diff --git a/lustre/include/linux/lustre_fsfilt.h b/lustre/include/linux/lustre_fsfilt.h index 8446e5b12527dcdabd787072c7c64df30ed317e7..84c44ac1af7937bf132f6367eb2c74ceae0cbe9f 100644 --- a/lustre/include/linux/lustre_fsfilt.h +++ b/lustre/include/linux/lustre_fsfilt.h @@ -44,7 +44,8 @@ struct fsfilt_operations { char *fs_type; void *(* fs_start)(struct inode *inode, int op, void *desc_private); void *(* fs_brw_start)(int objcount, struct fsfilt_objinfo *fso, - int niocount, void *desc_private); + int niocount, struct niobuf_local *nb, + void *desc_private); int (* fs_commit)(struct inode *inode, void *handle,int force_sync); int (* fs_commit_async)(struct inode *inode, void *handle, void **wait_handle); @@ -115,13 +116,14 @@ static inline void *fsfilt_start(struct obd_device *obd, struct inode *inode, static inline void *fsfilt_brw_start(struct obd_device *obd, int objcount, struct fsfilt_objinfo *fso, int niocount, + struct niobuf_local *nb, struct obd_trans_info *oti) { unsigned long now = jiffies; void *parent_handle = oti ? oti->oti_handle : NULL; void *handle; - handle = obd->obd_fsops->fs_brw_start(objcount, fso, niocount, + handle = obd->obd_fsops->fs_brw_start(objcount, fso, niocount, nb, parent_handle); CDEBUG(D_HA, "started handle %p (%p)\n", handle, parent_handle); diff --git a/lustre/lvfs/fsfilt_ext3.c b/lustre/lvfs/fsfilt_ext3.c index 606a11ccdd931f4524d9b81a441e2e98b5cadfe5..5de8a9bb95f529127c97fd21147387188225db24 100644 --- a/lustre/lvfs/fsfilt_ext3.c +++ b/lustre/lvfs/fsfilt_ext3.c @@ -159,28 +159,44 @@ static void *fsfilt_ext3_start(struct inode *inode, int op, void *desc_private) * * 1 EXT3_DATA_TRANS_BLOCKS for the last_rcvd update. */ -static int fsfilt_ext3_credits_needed(int objcount, struct fsfilt_objinfo *fso) +static int fsfilt_ext3_credits_needed(int objcount, struct fsfilt_objinfo *fso, + int niocount, struct niobuf_local *nb) { struct super_block *sb = fso->fso_dentry->d_inode->i_sb; - int blockpp = 1 << (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); - int addrpp = EXT3_ADDR_PER_BLOCK(sb) * blockpp; - int nbitmaps = 0; - int ngdblocks = 0; - int needed = objcount + 1; - int i; - - for (i = 0; i < objcount; i++, fso++) { - int nblocks = fso->fso_bufcnt * blockpp; - int ndindirect = min(nblocks, addrpp + 1); - int nindir = nblocks + ndindirect + 1; - - nbitmaps += nindir + nblocks; - ngdblocks += nindir + nblocks; - - needed += nindir; + __u64 next_indir; + const int blockpp = 1 << (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); + int nbitmaps = 0, ngdblocks; + int needed = objcount + 1; /* inodes + superblock */ + int i, j; + + for (i = 0, j = 0; i < objcount; i++, fso++) { + /* two or more dindirect blocks in case we cross boundary */ + int ndind = (long)((nb[j + fso->fso_bufcnt - 1].offset - + nb[j].offset) >> + sb->s_blocksize_bits) / + (EXT3_ADDR_PER_BLOCK(sb) * EXT3_ADDR_PER_BLOCK(sb)); + nbitmaps += min(fso->fso_bufcnt, ndind > 0 ? ndind : 2); + + /* leaf, indirect, tindirect blocks for first block */ + nbitmaps += blockpp + 2; + + j += fso->fso_bufcnt; } - /* Assumes ext3 and ext3 have same sb_info layout at the start. */ + next_indir = nb[0].offset + + (EXT3_ADDR_PER_BLOCK(sb) << sb->s_blocksize_bits); + for (i = 1; i < niocount; i++) { + if (nb[i].offset >= next_indir) { + nbitmaps++; /* additional indirect */ + next_indir = nb[i].offset + + (EXT3_ADDR_PER_BLOCK(sb)<<sb->s_blocksize_bits); + } else if (nb[i].offset != nb[i - 1].offset + sb->s_blocksize) { + nbitmaps++; /* additional indirect */ + } + nbitmaps += blockpp; /* each leaf in different group? */ + } + + ngdblocks = nbitmaps; if (nbitmaps > EXT3_SB(sb)->s_groups_count) nbitmaps = EXT3_SB(sb)->s_groups_count; if (ngdblocks > EXT3_SB(sb)->s_gdb_count) @@ -217,7 +233,8 @@ static int fsfilt_ext3_credits_needed(int objcount, struct fsfilt_objinfo *fso) * the pages have been written. */ static void *fsfilt_ext3_brw_start(int objcount, struct fsfilt_objinfo *fso, - int niocount, void *desc_private) + int niocount, struct niobuf_local *nb, + void *desc_private) { journal_t *journal; handle_t *handle; @@ -226,7 +243,7 @@ static void *fsfilt_ext3_brw_start(int objcount, struct fsfilt_objinfo *fso, LASSERT(current->journal_info == desc_private); journal = EXT3_SB(fso->fso_dentry->d_inode->i_sb)->s_journal; - needed = fsfilt_ext3_credits_needed(objcount, fso); + needed = fsfilt_ext3_credits_needed(objcount, fso, niocount, nb); /* The number of blocks we could _possibly_ dirty can very large. * We reduce our request if it is absurd (and we couldn't get that diff --git a/lustre/lvfs/fsfilt_reiserfs.c b/lustre/lvfs/fsfilt_reiserfs.c index c8a5d47a5f50202291eba0d1cec59f1bbbf9f9b2..36af093c476023615c3148794fb83e8eb4841bef 100644 --- a/lustre/lvfs/fsfilt_reiserfs.c +++ b/lustre/lvfs/fsfilt_reiserfs.c @@ -56,7 +56,8 @@ static void *fsfilt_reiserfs_start(struct inode *inode, int op, } static void *fsfilt_reiserfs_brw_start(int objcount, struct fsfilt_objinfo *fso, - int niocount, void *desc_private) + int niocount, struct niobuf_local *nb, + void *desc_private) { return (void *)0xf00f00be; } diff --git a/lustre/obdfilter/filter_io_24.c b/lustre/obdfilter/filter_io_24.c index 4129a091132c37d7187c2ec0ef16df0aa3d8b655..84d536b480eea228627abad54fe20d7951a8dae2 100644 --- a/lustre/obdfilter/filter_io_24.c +++ b/lustre/obdfilter/filter_io_24.c @@ -249,7 +249,8 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount, cleanup_phase = 2; down(&inode->i_sem); - oti->oti_handle = fsfilt_brw_start(obd, objcount, &fso, niocount, oti); + oti->oti_handle = fsfilt_brw_start(obd, objcount, &fso, niocount, res, + oti); if (IS_ERR(oti->oti_handle)) { rc = PTR_ERR(oti->oti_handle); CDEBUG(rc == -ENOSPC ? D_INODE : D_ERROR,