Whamcloud - gitweb
LU-216 Protect extent tree during fsfilt_ldiskfs_ext_walk_space()
authorBobi Jam <bobijam@whamcloud.com>
Thu, 19 May 2011 12:20:53 +0000 (20:20 +0800)
committerJohann Lombardi <johann@whamcloud.com>
Fri, 20 May 2011 08:34:04 +0000 (01:34 -0700)
Guarantee the validity of the extent path passed in
ldiskfs_ext_new_extent_cb().

Change-Id: I3f80e1e935d8ce02233cbdbf5d0ebb60dc50d8b9
Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Reviewed-on: http://review.whamcloud.com/573
Tested-by: Hudson
Reviewed-by: Johann Lombardi <johann@whamcloud.com>
ldiskfs/kernel_patches/patches/ext4-walk-space.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5-ext4.series
ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series
lustre/lvfs/fsfilt_ext3.c

diff --git a/ldiskfs/kernel_patches/patches/ext4-walk-space.patch b/ldiskfs/kernel_patches/patches/ext4-walk-space.patch
new file mode 100644 (file)
index 0000000..73b6d05
--- /dev/null
@@ -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;
index 9a8f161..6ba92d3 100644 (file)
@@ -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
index 29733b7..9955f94 100644 (file)
@@ -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
index b221d2e..d867111 100644 (file)
@@ -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);