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:
commit
cad46744a3
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
302
fs/ocfs2/namei.c
302
fs/ocfs2/namei.c
|
@ -472,32 +472,23 @@ leave:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
struct inode *dir,
|
||||
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)
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Reference in New Issue