From 7cc2cbbff39932b0dc7ddc0416a10dccdd1823da Mon Sep 17 00:00:00 2001 From: adilger Date: Wed, 16 Jul 2003 15:01:38 +0000 Subject: [PATCH] Fix problems with new write_record() interface: - we were not incrementing the size properly - block > i_size >> blkbits was never true when it needed to be - new size was always 1 block too small - when size was set, it didn't make it to disk, because ext3_get_block_handle() updated size after marking the inode dirty Proper fix is to move i_disksize update into ext3_splice_branch(), so that it is done before inode is marked dirty. For now, we mark inode dirty again in fsfilt, so we don't need a new kernel for Wed LLNL debug shot. Make fsfilt_ext3 and fsfilt_extN identical again (cosmetic changes only). --- lustre/include/linux/lustre_fsfilt.h | 4 ++-- lustre/obdclass/fsfilt_ext3.c | 31 +++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lustre/include/linux/lustre_fsfilt.h b/lustre/include/linux/lustre_fsfilt.h index 17d5f76..97c7d2e 100644 --- a/lustre/include/linux/lustre_fsfilt.h +++ b/lustre/include/linux/lustre_fsfilt.h @@ -61,8 +61,8 @@ struct fsfilt_operations { int (* fs_sync)(struct super_block *sb); int (* fs_prep_san_write)(struct inode *inode, long *blocks, int nblocks, loff_t newsize); - int (* fs_write_record)(struct file *, char *, loff_t, loff_t *); - int (* fs_read_record)(struct file *, char *, loff_t, loff_t *); + int (* fs_write_record)(struct file *, char *, int size, loff_t *); + int (* fs_read_record)(struct file *, char *, int size, loff_t *); }; extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops); diff --git a/lustre/obdclass/fsfilt_ext3.c b/lustre/obdclass/fsfilt_ext3.c index 0a4cb1e..82c2f58 100644 --- a/lustre/obdclass/fsfilt_ext3.c +++ b/lustre/obdclass/fsfilt_ext3.c @@ -501,8 +501,8 @@ static int fsfilt_ext3_prep_san_write(struct inode *inode, long *blocks, return ext3_prep_san_write(inode, blocks, nblocks, newsize); } -static int fsfilt_ext3_read_record(struct file * file, char * buf, - loff_t size, loff_t *offs) +static int fsfilt_ext3_read_record(struct file * file, char *buf, + int size, loff_t *offs) { struct buffer_head *bh; unsigned long block, boffs; @@ -510,9 +510,10 @@ static int fsfilt_ext3_read_record(struct file * file, char * buf, int err; if (inode->i_size < *offs + size) { - CERROR("file is too short for this request\n"); + CERROR("file size %llu is too short for read %u@%llu\n", + inode->i_size, size, *offs); return -EIO; - } + } block = *offs >> inode->i_blkbits; bh = ext3_bread(NULL, inode, block, 0, &err); @@ -535,12 +536,13 @@ static int fsfilt_ext3_read_record(struct file * file, char * buf, return size; } -static int fsfilt_ext3_write_record(struct file * file, char * buf, - loff_t size, loff_t *offs) +static int fsfilt_ext3_write_record(struct file * file, char *buf, + int size, loff_t *offs) { struct buffer_head *bh; unsigned long block, boffs; struct inode *inode = file->f_dentry->d_inode; + loff_t old_size = inode->i_size; journal_t *journal; handle_t *handle; int err; @@ -553,18 +555,27 @@ static int fsfilt_ext3_write_record(struct file * file, char * buf, } block = *offs >> inode->i_blkbits; - if (block > inode->i_size >> inode->i_blkbits) { + if (*offs + size > inode->i_size) { down(&inode->i_sem); - if (block > inode->i_size >> inode->i_blkbits) - inode->i_size = block << inode->i_blkbits; + if (*offs + size > inode->i_size) + inode->i_size = ((loff_t)block + 1) << inode->i_blkbits; up(&inode->i_sem); } + bh = ext3_bread(handle, inode, block, 1, &err); if (!bh) { CERROR("can't read/create block: %d\n", err); goto out; } + /* This is a hack only needed because ext3_get_block_handle() updates + * i_disksize after marking the inode dirty in ext3_splice_branch(). + * We will fix that when we get a chance, as ext3_mark_inode_dirty() + * is not without cost, nor is it even exported. + */ + if (inode->i_size > old_size) + mark_inode_dirty(inode); + boffs = (unsigned)*offs % bh->b_size; if (boffs + size > bh->b_size) { CERROR("request crosses block's border. offset %lu, size %lu\n", @@ -582,7 +593,7 @@ static int fsfilt_ext3_write_record(struct file * file, char * buf, err = ext3_journal_dirty_metadata(handle, bh); if (err) { CERROR("journal_dirty_metadata() returned error %d\n", err); - goto out; + goto out; } err = size; out: -- 1.8.3.1