From 4c2ea168bb65cb0abe1182e319e650ea3a58da10 Mon Sep 17 00:00:00 2001 From: Bobi Jam Date: Thu, 19 May 2011 20:20:53 +0800 Subject: [PATCH] LU-216 Protect extent tree during fsfilt_ldiskfs_ext_walk_space() Guarantee the validity of the extent path passed in ldiskfs_ext_new_extent_cb(). Change-Id: I3f80e1e935d8ce02233cbdbf5d0ebb60dc50d8b9 Signed-off-by: Bobi Jam Reviewed-on: http://review.whamcloud.com/573 Tested-by: Hudson Reviewed-by: Johann Lombardi --- .../kernel_patches/patches/ext4-walk-space.patch | 49 ++++++++++++++++++++++ .../series/ldiskfs-2.6-rhel5-ext4.series | 1 + .../series/ldiskfs-2.6-sles11.series | 1 + lustre/lvfs/fsfilt_ext3.c | 32 +++++--------- 4 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 ldiskfs/kernel_patches/patches/ext4-walk-space.patch diff --git a/ldiskfs/kernel_patches/patches/ext4-walk-space.patch b/ldiskfs/kernel_patches/patches/ext4-walk-space.patch new file mode 100644 index 0000000..73b6d05 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/ext4-walk-space.patch @@ -0,0 +1,49 @@ +Index: linux-stage/fs/ext4/ext4_extents.h +=================================================================== +--- linux-stage.orig/fs/ext4/ext4_extents.h ++++ linux-stage/fs/ext4/ext4_extents.h +@@ -258,7 +258,7 @@ extern int ext4_ext_try_to_merge(struct + extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *); + extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *, int); + extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t, +- ext_prepare_callback, void *); ++ ext_prepare_callback, void *, int); + extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, + struct ext4_ext_path *); + extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *, +Index: linux-stage/fs/ext4/extents.c +=================================================================== +--- linux-stage.orig/fs/ext4/extents.c ++++ linux-stage/fs/ext4/extents.c +@@ -1851,7 +1851,7 @@ cleanup: + + int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block, + ext4_lblk_t num, ext_prepare_callback func, +- void *cbdata) ++ void *cbdata, int locked) + { + struct ext4_ext_path *path = NULL; + struct ext4_ext_cache cbex; +@@ -1866,9 +1866,11 @@ int ext4_ext_walk_space(struct inode *in + while (block < last && block != EXT_MAX_BLOCK) { + num = last - block; + /* find extent for this block */ +- down_read(&EXT4_I(inode)->i_data_sem); ++ if (!locked) ++ down_read(&EXT4_I(inode)->i_data_sem); + path = ext4_ext_find_extent(inode, block, path); +- up_read(&EXT4_I(inode)->i_data_sem); ++ if (!locked) ++ up_read(&EXT4_I(inode)->i_data_sem); + if (IS_ERR(path)) { + err = PTR_ERR(path); + path = NULL; +@@ -3987,7 +3989,7 @@ int ext4_fiemap(struct inode *inode, str + * ext4_ext_fiemap_cb will push extents back to user. + */ + error = ext4_ext_walk_space(inode, start_blk, len_blks, +- ext4_ext_fiemap_cb, fieinfo); ++ ext4_ext_fiemap_cb, fieinfo, 0); + } + + return error; diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5-ext4.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5-ext4.series index 9a8f161..6ba92d3 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5-ext4.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5-ext4.series @@ -34,3 +34,4 @@ ext4-remove-extents-warning-rhel5.patch ext4-disable-delalloc-rhel5.patch ext4-failed-mount-b23368.patch ext4-mballoc-group_check-rhel5.patch +ext4-walk-space.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series index 29733b7..9955f94 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series @@ -27,4 +27,5 @@ ext4-hash-indexed-dir-dotdot-update.patch ext4-disable-write-bar-by-default.patch ext4-mballoc-skip-grps.patch ext4-disable-mb-cache-sles11.patch +ext4-walk-space.patch ext4-fiemap-2.6-rhel5.patch diff --git a/lustre/lvfs/fsfilt_ext3.c b/lustre/lvfs/fsfilt_ext3.c index b221d2e..d867111 100644 --- a/lustre/lvfs/fsfilt_ext3.c +++ b/lustre/lvfs/fsfilt_ext3.c @@ -855,26 +855,13 @@ static int fsfilt_ext3_sync(struct super_block *sb) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)) # define fsfilt_up_truncate_sem(inode) up(&LDISKFS_I(inode)->truncate_sem); # define fsfilt_down_truncate_sem(inode) down(&LDISKFS_I(inode)->truncate_sem); -# define fsfilt_up_truncate_sem_in_cb(inode) do { } while (0) -# define fsfilt_down_truncate_sem_in_cb(inode) do { } while (0) #else # ifdef HAVE_EXT4_LDISKFS -# ifdef WALK_SPACE_HAS_DATA_SEM /* We only use it in fsfilt_map_nblocks() for now */ -# define fsfilt_up_truncate_sem(inode) do{ }while(0) -# define fsfilt_down_truncate_sem(inode) do{ }while(0) -# define fsfilt_up_truncate_sem_in_cb(inode) up_write((&EXT4_I(inode)->i_data_sem)) -# define fsfilt_down_truncate_sem_in_cb(inode) down_write((&EXT4_I(inode)->i_data_sem)) -# else # define fsfilt_up_truncate_sem(inode) up_write((&LDISKFS_I(inode)->i_data_sem)); # define fsfilt_down_truncate_sem(inode) down_write((&LDISKFS_I(inode)->i_data_sem)); -# define fsfilt_up_truncate_sem_in_cb(inode) do { } while (0) -# define fsfilt_down_truncate_sem_in_cb(inode) do { } while (0) -# endif # else # define fsfilt_up_truncate_sem(inode) mutex_unlock(&LDISKFS_I(inode)->truncate_mutex); # define fsfilt_down_truncate_sem(inode) mutex_lock(&LDISKFS_I(inode)->truncate_mutex); -# define fsfilt_up_truncate_sem_in_cb(inode) do { } while (0) -# define fsfilt_down_truncate_sem_in_cb(inode) do { } while (0) # endif #endif @@ -892,12 +879,18 @@ static int fsfilt_ext3_sync(struct super_block *sb) #define ext3_ext_base inode #define ext3_ext_base2inode(inode) (inode) #define EXT_DEPTH(inode) ext_depth(inode) -#define fsfilt_ext3_ext_walk_space(inode, block, num, cb, cbdata) \ +# if defined(HAVE_EXT4_LDISKFS) && defined(WALK_SPACE_HAS_DATA_SEM) +/* for kernels 2.6.18-238 and later */ +# define fsfilt_ext3_ext_walk_space(inode, block, num, cb, cbdata, locked) \ + ext3_ext_walk_space(inode, block, num, cb, cbdata, locked); +# else +# define fsfilt_ext3_ext_walk_space(inode, block, num, cb, cbdata, locked) \ ext3_ext_walk_space(inode, block, num, cb, cbdata); +# endif #else #define ext3_ext_base ext3_extents_tree #define ext3_ext_base2inode(tree) (tree->inode) -#define fsfilt_ext3_ext_walk_space(tree, block, num, cb, cbdata) \ +#define fsfilt_ext3_ext_walk_space(tree, block, num, cb, cbdata, locked) \ ext3_ext_walk_space(tree, block, num, cb); #endif @@ -1073,11 +1066,6 @@ static int ext3_ext_new_extent_cb(struct ext3_ext_base *base, return EXT_REPEAT; } - /* In 2.6.32 kernel, ext4_ext_walk_space()'s callback func is not - * protected by i_data_sem, we need do it ourselves, since we create - * file system blocks */ - fsfilt_down_truncate_sem_in_cb(inode); - count = cex->ec_len; pblock = new_blocks(handle, base, path, cex->ec_block, &count, &err); if (!pblock) @@ -1112,7 +1100,6 @@ static int ext3_ext_new_extent_cb(struct ext3_ext_base *base, BUG_ON(le32_to_cpu(nex.ee_block) != cex->ec_block); out: - fsfilt_up_truncate_sem_in_cb(inode); ext3_journal_stop(handle); map: if (err >= 0) { @@ -1179,7 +1166,8 @@ int fsfilt_map_nblocks(struct inode *inode, unsigned long block, bp.create = create; fsfilt_down_truncate_sem(inode); - err = fsfilt_ext3_ext_walk_space(base, block, num, ext3_ext_new_extent_cb, &bp); + err = fsfilt_ext3_ext_walk_space(base, block, num, + ext3_ext_new_extent_cb, &bp, 1); ext3_ext_invalidate_cache(base); fsfilt_up_truncate_sem(inode); -- 1.8.3.1