ext4: ensure enough credits in ext4_ext_shift_path_extents
authoryangerkun <yangerkun@huawei.com>
Fri, 3 Sep 2021 06:27:47 +0000 (14:27 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Nov 2021 18:15:56 +0000 (19:15 +0100)
commit 4268496e48dc681cfa53b92357314b5d7221e625 upstream.

Like ext4_ext_rm_leaf, we can ensure that there are enough credits
before every call that will consume credits.  As part of this fix we
fold the functionality of ext4_access_path() into
ext4_ext_shift_path_extents().  This change is needed as a preparation
for the next bugfix patch.

Cc: stable@kernel.org
Link: https://lore.kernel.org/r/20210903062748.4118886-3-yangerkun@huawei.com
Signed-off-by: yangerkun <yangerkun@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/extents.c

index 0e02571..434ecc7 100644 (file)
@@ -4978,36 +4978,6 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo,
 }
 
 /*
- * ext4_access_path:
- * Function to access the path buffer for marking it dirty.
- * It also checks if there are sufficient credits left in the journal handle
- * to update path.
- */
-static int
-ext4_access_path(handle_t *handle, struct inode *inode,
-               struct ext4_ext_path *path)
-{
-       int credits, err;
-
-       if (!ext4_handle_valid(handle))
-               return 0;
-
-       /*
-        * Check if need to extend journal credits
-        * 3 for leaf, sb, and inode plus 2 (bmap and group
-        * descriptor) for each block group; assume two block
-        * groups
-        */
-       credits = ext4_writepage_trans_blocks(inode);
-       err = ext4_datasem_ensure_credits(handle, inode, 7, credits, 0);
-       if (err < 0)
-               return err;
-
-       err = ext4_ext_get_access(handle, inode, path);
-       return err;
-}
-
-/*
  * ext4_ext_shift_path_extents:
  * Shift the extents of a path structure lying between path[depth].p_ext
  * and EXT_LAST_EXTENT(path[depth].p_hdr), by @shift blocks. @SHIFT tells
@@ -5021,6 +4991,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
        int depth, err = 0;
        struct ext4_extent *ex_start, *ex_last;
        bool update = false;
+       int credits, restart_credits;
        depth = path->p_depth;
 
        while (depth >= 0) {
@@ -5030,13 +5001,23 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
                                return -EFSCORRUPTED;
 
                        ex_last = EXT_LAST_EXTENT(path[depth].p_hdr);
+                       /* leaf + sb + inode */
+                       credits = 3;
+                       if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr)) {
+                               update = true;
+                               /* extent tree + sb + inode */
+                               credits = depth + 2;
+                       }
 
-                       err = ext4_access_path(handle, inode, path + depth);
+                       restart_credits = ext4_writepage_trans_blocks(inode);
+                       err = ext4_datasem_ensure_credits(handle, inode, credits,
+                                       restart_credits, 0);
                        if (err)
                                goto out;
 
-                       if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr))
-                               update = true;
+                       err = ext4_ext_get_access(handle, inode, path + depth);
+                       if (err)
+                               goto out;
 
                        while (ex_start <= ex_last) {
                                if (SHIFT == SHIFT_LEFT) {
@@ -5067,7 +5048,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
                }
 
                /* Update index too */
-               err = ext4_access_path(handle, inode, path + depth);
+               err = ext4_ext_get_access(handle, inode, path + depth);
                if (err)
                        goto out;