Merge branch 'fixes' of git://oss.oracle.com/git/tma/linux-2.6

* 'fixes' of git://oss.oracle.com/git/tma/linux-2.6:
  ocfs2: Fix orphan add in ocfs2_create_inode_in_orphan
  ocfs2: split out ocfs2_prepare_orphan_dir() into locking and prep functions
  ocfs2: allow return of new inode block location before allocation of the inode
  ocfs2: use ocfs2_alloc_dinode_update_counts() instead of open coding
  ocfs2: split out inode alloc code from ocfs2_mknod_locked
  Ocfs2: Fix a regression bug from mainline commit(6b933c8e6f).
  ocfs2: Fix deadlock when allocating page
  ocfs2: properly set and use inode group alloc hint
  ocfs2: Use the right group in nfs sync check.
  ocfs2: Flush drive's caches on fdatasync
  ocfs2: make __ocfs2_page_mkwrite handle file end properly.
  ocfs2: Fix incorrect checksum validation error
  ocfs2: Fix metaecc error messages
This commit is contained in:
Linus Torvalds 2010-09-09 08:57:02 -07:00
commit cad46744a3
9 changed files with 480 additions and 112 deletions

View File

@ -6672,7 +6672,7 @@ int ocfs2_grab_pages(struct inode *inode, loff_t start, loff_t end,
last_page_bytes = PAGE_ALIGN(end);
index = start >> PAGE_CACHE_SHIFT;
do {
pages[numpages] = grab_cache_page(mapping, index);
pages[numpages] = find_or_create_page(mapping, index, GFP_NOFS);
if (!pages[numpages]) {
ret = -ENOMEM;
mlog_errno(ret);

View File

@ -439,7 +439,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
ocfs2_blockcheck_inc_failure(stats);
mlog(ML_ERROR,
"CRC32 failed: stored: %u, computed %u. Applying ECC.\n",
"CRC32 failed: stored: 0x%x, computed 0x%x. Applying ECC.\n",
(unsigned int)check.bc_crc32e, (unsigned int)crc);
/* Ok, try ECC fixups */
@ -453,7 +453,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
goto out;
}
mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
mlog(ML_ERROR, "Fixed CRC32 failed: stored: 0x%x, computed 0x%x\n",
(unsigned int)check.bc_crc32e, (unsigned int)crc);
rc = -EIO;

View File

@ -36,6 +36,7 @@
#include <linux/writeback.h>
#include <linux/falloc.h>
#include <linux/quotaops.h>
#include <linux/blkdev.h>
#define MLOG_MASK_PREFIX ML_INODE
#include <cluster/masklog.h>
@ -190,8 +191,16 @@ static int ocfs2_sync_file(struct file *file, int datasync)
if (err)
goto bail;
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) {
/*
* We still have to flush drive's caches to get data to the
* platter
*/
if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL,
NULL, BLKDEV_IFL_WAIT);
goto bail;
}
journal = osb->journal->j_journal;
err = jbd2_journal_force_commit(journal);
@ -774,7 +783,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT));
BUG_ON(abs_from & (inode->i_blkbits - 1));
page = grab_cache_page(mapping, index);
page = find_or_create_page(mapping, index, GFP_NOFS);
if (!page) {
ret = -ENOMEM;
mlog_errno(ret);
@ -2329,7 +2338,7 @@ out_dio:
BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
((file->f_flags & O_DIRECT) && has_refcount)) {
((file->f_flags & O_DIRECT) && !direct_io)) {
ret = filemap_fdatawrite_range(file->f_mapping, pos,
pos + count - 1);
if (ret < 0)

View File

@ -488,7 +488,11 @@ static int ocfs2_read_locked_inode(struct inode *inode,
OCFS2_BH_IGNORE_CACHE);
} else {
status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
if (!status)
/*
* If buffer is in jbd, then its checksum may not have been
* computed as yet.
*/
if (!status && !buffer_jbd(bh))
status = ocfs2_validate_inode_block(osb->sb, bh);
}
if (status < 0) {

View File

@ -74,9 +74,11 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
/*
* Another node might have truncated while we were waiting on
* cluster locks.
* We don't check size == 0 before the shift. This is borrowed
* from do_generic_file_read.
*/
last_index = size >> PAGE_CACHE_SHIFT;
if (page->index > last_index) {
last_index = (size - 1) >> PAGE_CACHE_SHIFT;
if (unlikely(!size || page->index > last_index)) {
ret = -EINVAL;
goto out;
}
@ -107,7 +109,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
* because the "write" would invalidate their data.
*/
if (page->index == last_index)
len = size & ~PAGE_CACHE_MASK;
len = ((size - 1) & ~PAGE_CACHE_MASK) + 1;
ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page,
&fsdata, di_bh, page);

View File

@ -472,32 +472,23 @@ leave:
return status;
}
static int ocfs2_mknod_locked(struct ocfs2_super *osb,
struct inode *dir,
struct inode *inode,
dev_t dev,
struct buffer_head **new_fe_bh,
struct buffer_head *parent_fe_bh,
handle_t *handle,
struct ocfs2_alloc_context *inode_ac)
static int __ocfs2_mknod_locked(struct inode *dir,
struct inode *inode,
dev_t dev,
struct buffer_head **new_fe_bh,
struct buffer_head *parent_fe_bh,
handle_t *handle,
struct ocfs2_alloc_context *inode_ac,
u64 fe_blkno, u64 suballoc_loc, u16 suballoc_bit)
{
int status = 0;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
struct ocfs2_dinode *fe = NULL;
struct ocfs2_extent_list *fel;
u64 suballoc_loc, fe_blkno = 0;
u16 suballoc_bit;
u16 feat;
*new_fe_bh = NULL;
status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh,
inode_ac, &suballoc_loc,
&suballoc_bit, &fe_blkno);
if (status < 0) {
mlog_errno(status);
goto leave;
}
/* populate as many fields early on as possible - many of
* these are used by the support functions here and in
* callers. */
@ -591,6 +582,34 @@ leave:
return status;
}
static int ocfs2_mknod_locked(struct ocfs2_super *osb,
struct inode *dir,
struct inode *inode,
dev_t dev,
struct buffer_head **new_fe_bh,
struct buffer_head *parent_fe_bh,
handle_t *handle,
struct ocfs2_alloc_context *inode_ac)
{
int status = 0;
u64 suballoc_loc, fe_blkno = 0;
u16 suballoc_bit;
*new_fe_bh = NULL;
status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh,
inode_ac, &suballoc_loc,
&suballoc_bit, &fe_blkno);
if (status < 0) {
mlog_errno(status);
return status;
}
return __ocfs2_mknod_locked(dir, inode, dev, new_fe_bh,
parent_fe_bh, handle, inode_ac,
fe_blkno, suballoc_loc, suballoc_bit);
}
static int ocfs2_mkdir(struct inode *dir,
struct dentry *dentry,
int mode)
@ -1852,61 +1871,117 @@ bail:
return status;
}
static int ocfs2_lookup_lock_orphan_dir(struct ocfs2_super *osb,
struct inode **ret_orphan_dir,
struct buffer_head **ret_orphan_dir_bh)
{
struct inode *orphan_dir_inode;
struct buffer_head *orphan_dir_bh = NULL;
int ret = 0;
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
osb->slot_num);
if (!orphan_dir_inode) {
ret = -ENOENT;
mlog_errno(ret);
return ret;
}
mutex_lock(&orphan_dir_inode->i_mutex);
ret = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
if (ret < 0) {
mutex_unlock(&orphan_dir_inode->i_mutex);
iput(orphan_dir_inode);
mlog_errno(ret);
return ret;
}
*ret_orphan_dir = orphan_dir_inode;
*ret_orphan_dir_bh = orphan_dir_bh;
return 0;
}
static int __ocfs2_prepare_orphan_dir(struct inode *orphan_dir_inode,
struct buffer_head *orphan_dir_bh,
u64 blkno,
char *name,
struct ocfs2_dir_lookup_result *lookup)
{
int ret;
struct ocfs2_super *osb = OCFS2_SB(orphan_dir_inode->i_sb);
ret = ocfs2_blkno_stringify(blkno, name);
if (ret < 0) {
mlog_errno(ret);
return ret;
}
ret = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode,
orphan_dir_bh, name,
OCFS2_ORPHAN_NAMELEN, lookup);
if (ret < 0) {
mlog_errno(ret);
return ret;
}
return 0;
}
/**
* ocfs2_prepare_orphan_dir() - Prepare an orphan directory for
* insertion of an orphan.
* @osb: ocfs2 file system
* @ret_orphan_dir: Orphan dir inode - returned locked!
* @blkno: Actual block number of the inode to be inserted into orphan dir.
* @lookup: dir lookup result, to be passed back into functions like
* ocfs2_orphan_add
*
* Returns zero on success and the ret_orphan_dir, name and lookup
* fields will be populated.
*
* Returns non-zero on failure.
*/
static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
struct inode **ret_orphan_dir,
u64 blkno,
char *name,
struct ocfs2_dir_lookup_result *lookup)
{
struct inode *orphan_dir_inode;
struct inode *orphan_dir_inode = NULL;
struct buffer_head *orphan_dir_bh = NULL;
int status = 0;
int ret = 0;
status = ocfs2_blkno_stringify(blkno, name);
if (status < 0) {
mlog_errno(status);
return status;
ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir_inode,
&orphan_dir_bh);
if (ret < 0) {
mlog_errno(ret);
return ret;
}
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
osb->slot_num);
if (!orphan_dir_inode) {
status = -ENOENT;
mlog_errno(status);
return status;
}
mutex_lock(&orphan_dir_inode->i_mutex);
status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
if (status < 0) {
mlog_errno(status);
goto leave;
}
status = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode,
orphan_dir_bh, name,
OCFS2_ORPHAN_NAMELEN, lookup);
if (status < 0) {
ocfs2_inode_unlock(orphan_dir_inode, 1);
mlog_errno(status);
goto leave;
ret = __ocfs2_prepare_orphan_dir(orphan_dir_inode, orphan_dir_bh,
blkno, name, lookup);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
*ret_orphan_dir = orphan_dir_inode;
leave:
if (status) {
out:
brelse(orphan_dir_bh);
if (ret) {
ocfs2_inode_unlock(orphan_dir_inode, 1);
mutex_unlock(&orphan_dir_inode->i_mutex);
iput(orphan_dir_inode);
}
brelse(orphan_dir_bh);
mlog_exit(status);
return status;
mlog_exit(ret);
return ret;
}
static int ocfs2_orphan_add(struct ocfs2_super *osb,
@ -2053,6 +2128,99 @@ leave:
return status;
}
/**
* ocfs2_prep_new_orphaned_file() - Prepare the orphan dir to recieve a newly
* allocated file. This is different from the typical 'add to orphan dir'
* operation in that the inode does not yet exist. This is a problem because
* the orphan dir stringifies the inode block number to come up with it's
* dirent. Obviously if the inode does not yet exist we have a chicken and egg
* problem. This function works around it by calling deeper into the orphan
* and suballoc code than other callers. Use this only by necessity.
* @dir: The directory which this inode will ultimately wind up under - not the
* orphan dir!
* @dir_bh: buffer_head the @dir inode block
* @orphan_name: string of length (CFS2_ORPHAN_NAMELEN + 1). Will be filled
* with the string to be used for orphan dirent. Pass back to the orphan dir
* code.
* @ret_orphan_dir: orphan dir inode returned to be passed back into orphan
* dir code.
* @ret_di_blkno: block number where the new inode will be allocated.
* @orphan_insert: Dir insert context to be passed back into orphan dir code.
* @ret_inode_ac: Inode alloc context to be passed back to the allocator.
*
* Returns zero on success and the ret_orphan_dir, name and lookup
* fields will be populated.
*
* Returns non-zero on failure.
*/
static int ocfs2_prep_new_orphaned_file(struct inode *dir,
struct buffer_head *dir_bh,
char *orphan_name,
struct inode **ret_orphan_dir,
u64 *ret_di_blkno,
struct ocfs2_dir_lookup_result *orphan_insert,
struct ocfs2_alloc_context **ret_inode_ac)
{
int ret;
u64 di_blkno;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
struct inode *orphan_dir = NULL;
struct buffer_head *orphan_dir_bh = NULL;
struct ocfs2_alloc_context *inode_ac = NULL;
ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir, &orphan_dir_bh);
if (ret < 0) {
mlog_errno(ret);
return ret;
}
/* reserve an inode spot */
ret = ocfs2_reserve_new_inode(osb, &inode_ac);
if (ret < 0) {
if (ret != -ENOSPC)
mlog_errno(ret);
goto out;
}
ret = ocfs2_find_new_inode_loc(dir, dir_bh, inode_ac,
&di_blkno);
if (ret) {
mlog_errno(ret);
goto out;
}
ret = __ocfs2_prepare_orphan_dir(orphan_dir, orphan_dir_bh,
di_blkno, orphan_name, orphan_insert);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
out:
if (ret == 0) {
*ret_orphan_dir = orphan_dir;
*ret_di_blkno = di_blkno;
*ret_inode_ac = inode_ac;
/*
* orphan_name and orphan_insert are already up to
* date via prepare_orphan_dir
*/
} else {
/* Unroll reserve_new_inode* */
if (inode_ac)
ocfs2_free_alloc_context(inode_ac);
/* Unroll orphan dir locking */
mutex_unlock(&orphan_dir->i_mutex);
ocfs2_inode_unlock(orphan_dir, 1);
iput(orphan_dir);
}
brelse(orphan_dir_bh);
return 0;
}
int ocfs2_create_inode_in_orphan(struct inode *dir,
int mode,
struct inode **new_inode)
@ -2068,6 +2236,8 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
struct buffer_head *new_di_bh = NULL;
struct ocfs2_alloc_context *inode_ac = NULL;
struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
u64 uninitialized_var(di_blkno), suballoc_loc;
u16 suballoc_bit;
status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
if (status < 0) {
@ -2076,20 +2246,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
return status;
}
/*
* We give the orphan dir the root blkno to fake an orphan name,
* and allocate enough space for our insertion.
*/
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
osb->root_blkno,
orphan_name, &orphan_insert);
if (status < 0) {
mlog_errno(status);
goto leave;
}
/* reserve an inode spot */
status = ocfs2_reserve_new_inode(osb, &inode_ac);
status = ocfs2_prep_new_orphaned_file(dir, parent_di_bh,
orphan_name, &orphan_dir,
&di_blkno, &orphan_insert, &inode_ac);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@ -2116,17 +2275,20 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
goto leave;
did_quota_inode = 1;
inode->i_nlink = 0;
/* do the real work now. */
status = ocfs2_mknod_locked(osb, dir, inode,
0, &new_di_bh, parent_di_bh, handle,
inode_ac);
status = ocfs2_claim_new_inode_at_loc(handle, dir, inode_ac,
&suballoc_loc,
&suballoc_bit, di_blkno);
if (status < 0) {
mlog_errno(status);
goto leave;
}
status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name);
inode->i_nlink = 0;
/* do the real work now. */
status = __ocfs2_mknod_locked(dir, inode,
0, &new_di_bh, parent_di_bh, handle,
inode_ac, di_blkno, suballoc_loc,
suballoc_bit);
if (status < 0) {
mlog_errno(status);
goto leave;

View File

@ -2960,7 +2960,7 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
if (map_end & (PAGE_CACHE_SIZE - 1))
to = map_end & (PAGE_CACHE_SIZE - 1);
page = grab_cache_page(mapping, page_index);
page = find_or_create_page(mapping, page_index, GFP_NOFS);
/*
* In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page
@ -3179,7 +3179,8 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb,
if (map_end > end)
map_end = end;
page = grab_cache_page(context->inode->i_mapping, page_index);
page = find_or_create_page(context->inode->i_mapping,
page_index, GFP_NOFS);
BUG_ON(!page);
wait_on_page_writeback(page);

View File

@ -57,11 +57,28 @@ struct ocfs2_suballoc_result {
u64 sr_bg_blkno; /* The bg we allocated from. Set
to 0 when a block group is
contiguous. */
u64 sr_bg_stable_blkno; /*
* Doesn't change, always
* set to target block
* group descriptor
* block.
*/
u64 sr_blkno; /* The first allocated block */
unsigned int sr_bit_offset; /* The bit in the bg */
unsigned int sr_bits; /* How many bits we claimed */
};
static u64 ocfs2_group_from_res(struct ocfs2_suballoc_result *res)
{
if (res->sr_blkno == 0)
return 0;
if (res->sr_bg_blkno)
return res->sr_bg_blkno;
return ocfs2_which_suballoc_group(res->sr_blkno, res->sr_bit_offset);
}
static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg);
static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe);
static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl);
@ -138,6 +155,10 @@ void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
brelse(ac->ac_bh);
ac->ac_bh = NULL;
ac->ac_resv = NULL;
if (ac->ac_find_loc_priv) {
kfree(ac->ac_find_loc_priv);
ac->ac_find_loc_priv = NULL;
}
}
void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
@ -1678,6 +1699,15 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
if (!ret)
ocfs2_bg_discontig_fix_result(ac, gd, res);
/*
* sr_bg_blkno might have been changed by
* ocfs2_bg_discontig_fix_result
*/
res->sr_bg_stable_blkno = group_bh->b_blocknr;
if (ac->ac_find_loc_only)
goto out_loc_only;
ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh,
res->sr_bits,
le16_to_cpu(gd->bg_chain));
@ -1691,6 +1721,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
if (ret < 0)
mlog_errno(ret);
out_loc_only:
*bits_left = le16_to_cpu(gd->bg_free_bits_count);
out:
@ -1708,7 +1739,6 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
{
int status;
u16 chain;
u32 tmp_used;
u64 next_group;
struct inode *alloc_inode = ac->ac_inode;
struct buffer_head *group_bh = NULL;
@ -1770,6 +1800,11 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
if (!status)
ocfs2_bg_discontig_fix_result(ac, bg, res);
/*
* sr_bg_blkno might have been changed by
* ocfs2_bg_discontig_fix_result
*/
res->sr_bg_stable_blkno = group_bh->b_blocknr;
/*
* Keep track of previous block descriptor read. When
@ -1796,22 +1831,17 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
}
}
/* Ok, claim our bits now: set the info on dinode, chainlist
* and then the group */
status = ocfs2_journal_access_di(handle,
INODE_CACHE(alloc_inode),
ac->ac_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
if (ac->ac_find_loc_only)
goto out_loc_only;
status = ocfs2_alloc_dinode_update_counts(alloc_inode, handle,
ac->ac_bh, res->sr_bits,
chain);
if (status) {
mlog_errno(status);
goto bail;
}
tmp_used = le32_to_cpu(fe->id1.bitmap1.i_used);
fe->id1.bitmap1.i_used = cpu_to_le32(res->sr_bits + tmp_used);
le32_add_cpu(&cl->cl_recs[chain].c_free, -res->sr_bits);
ocfs2_journal_dirty(handle, ac->ac_bh);
status = ocfs2_block_group_set_bits(handle,
alloc_inode,
bg,
@ -1826,6 +1856,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits,
(unsigned long long)le64_to_cpu(fe->i_blkno));
out_loc_only:
*bits_left = le16_to_cpu(bg->bg_free_bits_count);
bail:
brelse(group_bh);
@ -1845,6 +1876,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
int status;
u16 victim, i;
u16 bits_left = 0;
u64 hint = ac->ac_last_group;
struct ocfs2_chain_list *cl;
struct ocfs2_dinode *fe;
@ -1872,7 +1904,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
goto bail;
}
res->sr_bg_blkno = ac->ac_last_group;
res->sr_bg_blkno = hint;
if (res->sr_bg_blkno) {
/* Attempt to short-circuit the usual search mechanism
* by jumping straight to the most recently used
@ -1896,8 +1928,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits,
res, &bits_left);
if (!status)
if (!status) {
hint = ocfs2_group_from_res(res);
goto set_hint;
}
if (status < 0 && status != -ENOSPC) {
mlog_errno(status);
goto bail;
@ -1920,8 +1954,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
ac->ac_chain = i;
status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits,
res, &bits_left);
if (!status)
if (!status) {
hint = ocfs2_group_from_res(res);
break;
}
if (status < 0 && status != -ENOSPC) {
mlog_errno(status);
goto bail;
@ -1936,7 +1972,7 @@ set_hint:
if (bits_left < min_bits)
ac->ac_last_group = 0;
else
ac->ac_last_group = res->sr_bg_blkno;
ac->ac_last_group = hint;
}
bail:
@ -2016,6 +2052,136 @@ static inline void ocfs2_save_inode_ac_group(struct inode *dir,
OCFS2_I(dir)->ip_last_used_slot = ac->ac_alloc_slot;
}
int ocfs2_find_new_inode_loc(struct inode *dir,
struct buffer_head *parent_fe_bh,
struct ocfs2_alloc_context *ac,
u64 *fe_blkno)
{
int ret;
handle_t *handle = NULL;
struct ocfs2_suballoc_result *res;
BUG_ON(!ac);
BUG_ON(ac->ac_bits_given != 0);
BUG_ON(ac->ac_bits_wanted != 1);
BUG_ON(ac->ac_which != OCFS2_AC_USE_INODE);
res = kzalloc(sizeof(*res), GFP_NOFS);
if (res == NULL) {
ret = -ENOMEM;
mlog_errno(ret);
goto out;
}
ocfs2_init_inode_ac_group(dir, parent_fe_bh, ac);
/*
* The handle started here is for chain relink. Alternatively,
* we could just disable relink for these calls.
*/
handle = ocfs2_start_trans(OCFS2_SB(dir->i_sb), OCFS2_SUBALLOC_ALLOC);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
handle = NULL;
mlog_errno(ret);
goto out;
}
/*
* This will instruct ocfs2_claim_suballoc_bits and
* ocfs2_search_one_group to search but save actual allocation
* for later.
*/
ac->ac_find_loc_only = 1;
ret = ocfs2_claim_suballoc_bits(ac, handle, 1, 1, res);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
ac->ac_find_loc_priv = res;
*fe_blkno = res->sr_blkno;
out:
if (handle)
ocfs2_commit_trans(OCFS2_SB(dir->i_sb), handle);
if (ret)
kfree(res);
return ret;
}
int ocfs2_claim_new_inode_at_loc(handle_t *handle,
struct inode *dir,
struct ocfs2_alloc_context *ac,
u64 *suballoc_loc,
u16 *suballoc_bit,
u64 di_blkno)
{
int ret;
u16 chain;
struct ocfs2_suballoc_result *res = ac->ac_find_loc_priv;
struct buffer_head *bg_bh = NULL;
struct ocfs2_group_desc *bg;
struct ocfs2_dinode *di = (struct ocfs2_dinode *) ac->ac_bh->b_data;
/*
* Since di_blkno is being passed back in, we check for any
* inconsistencies which may have happened between
* calls. These are code bugs as di_blkno is not expected to
* change once returned from ocfs2_find_new_inode_loc()
*/
BUG_ON(res->sr_blkno != di_blkno);
ret = ocfs2_read_group_descriptor(ac->ac_inode, di,
res->sr_bg_stable_blkno, &bg_bh);
if (ret) {
mlog_errno(ret);
goto out;
}
bg = (struct ocfs2_group_desc *) bg_bh->b_data;
chain = le16_to_cpu(bg->bg_chain);
ret = ocfs2_alloc_dinode_update_counts(ac->ac_inode, handle,
ac->ac_bh, res->sr_bits,
chain);
if (ret) {
mlog_errno(ret);
goto out;
}
ret = ocfs2_block_group_set_bits(handle,
ac->ac_inode,
bg,
bg_bh,
res->sr_bit_offset,
res->sr_bits);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits,
(unsigned long long)di_blkno);
atomic_inc(&OCFS2_SB(ac->ac_inode->i_sb)->alloc_stats.bg_allocs);
BUG_ON(res->sr_bits != 1);
*suballoc_loc = res->sr_bg_blkno;
*suballoc_bit = res->sr_bit_offset;
ac->ac_bits_given++;
ocfs2_save_inode_ac_group(dir, ac);
out:
brelse(bg_bh);
return ret;
}
int ocfs2_claim_new_inode(handle_t *handle,
struct inode *dir,
struct buffer_head *parent_fe_bh,
@ -2567,7 +2733,8 @@ out:
* suballoc_bit.
*/
static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno,
u16 *suballoc_slot, u16 *suballoc_bit)
u16 *suballoc_slot, u64 *group_blkno,
u16 *suballoc_bit)
{
int status;
struct buffer_head *inode_bh = NULL;
@ -2604,6 +2771,8 @@ static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno,
*suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot);
if (suballoc_bit)
*suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit);
if (group_blkno)
*group_blkno = le64_to_cpu(inode_fe->i_suballoc_loc);
bail:
brelse(inode_bh);
@ -2621,7 +2790,8 @@ bail:
*/
static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb,
struct inode *suballoc,
struct buffer_head *alloc_bh, u64 blkno,
struct buffer_head *alloc_bh,
u64 group_blkno, u64 blkno,
u16 bit, int *res)
{
struct ocfs2_dinode *alloc_di;
@ -2642,10 +2812,8 @@ static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb,
goto bail;
}
if (alloc_di->i_suballoc_loc)
bg_blkno = le64_to_cpu(alloc_di->i_suballoc_loc);
else
bg_blkno = ocfs2_which_suballoc_group(blkno, bit);
bg_blkno = group_blkno ? group_blkno :
ocfs2_which_suballoc_group(blkno, bit);
status = ocfs2_read_group_descriptor(suballoc, alloc_di, bg_blkno,
&group_bh);
if (status < 0) {
@ -2680,6 +2848,7 @@ bail:
int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res)
{
int status;
u64 group_blkno = 0;
u16 suballoc_bit = 0, suballoc_slot = 0;
struct inode *inode_alloc_inode;
struct buffer_head *alloc_bh = NULL;
@ -2687,7 +2856,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res)
mlog_entry("blkno: %llu", (unsigned long long)blkno);
status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot,
&suballoc_bit);
&group_blkno, &suballoc_bit);
if (status < 0) {
mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status);
goto bail;
@ -2715,7 +2884,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res)
}
status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh,
blkno, suballoc_bit, res);
group_blkno, blkno, suballoc_bit, res);
if (status < 0)
mlog(ML_ERROR, "test suballoc bit failed %d\n", status);

View File

@ -56,6 +56,9 @@ struct ocfs2_alloc_context {
u64 ac_max_block; /* Highest block number to allocate. 0 is
is the same as ~0 - unlimited */
int ac_find_loc_only; /* hack for reflink operation ordering */
struct ocfs2_suballoc_result *ac_find_loc_priv; /* */
struct ocfs2_alloc_reservation *ac_resv;
};
@ -197,4 +200,22 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et,
struct ocfs2_alloc_context **meta_ac);
int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res);
/*
* The following two interfaces are for ocfs2_create_inode_in_orphan().
*/
int ocfs2_find_new_inode_loc(struct inode *dir,
struct buffer_head *parent_fe_bh,
struct ocfs2_alloc_context *ac,
u64 *fe_blkno);
int ocfs2_claim_new_inode_at_loc(handle_t *handle,
struct inode *dir,
struct ocfs2_alloc_context *ac,
u64 *suballoc_loc,
u16 *suballoc_bit,
u64 di_blkno);
#endif /* _CHAINALLOC_H_ */