udf: Allocate name buffer in directory iterator on heap
authorJan Kara <jack@suse.cz>
Tue, 20 Dec 2022 11:38:45 +0000 (12:38 +0100)
committerJan Kara <jack@suse.cz>
Mon, 9 Jan 2023 09:39:53 +0000 (10:39 +0100)
Currently we allocate name buffer in directory iterators (struct
udf_fileident_iter) on stack. These structures are relatively large
(some 360 bytes on 64-bit architectures). For udf_rename() which needs
to keep three of these structures in parallel the stack usage becomes
rather heavy - 1536 bytes in total. Allocate the name buffer in the
iterator from heap to avoid excessive stack usage.

Link: https://lore.kernel.org/all/202212200558.lK9x1KW0-lkp@intel.com
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/directory.c
fs/udf/udfdecl.h

index e7e8b30..a4c9190 100644 (file)
@@ -248,9 +248,14 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
        iter->elen = 0;
        iter->epos.bh = NULL;
        iter->name = NULL;
+       iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL);
+       if (!iter->namebuf)
+               return -ENOMEM;
 
-       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-               return udf_copy_fi(iter);
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               err = udf_copy_fi(iter);
+               goto out;
+       }
 
        if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
                       &iter->eloc, &iter->elen, &iter->loffset) !=
@@ -260,17 +265,17 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
                udf_err(dir->i_sb,
                        "position %llu not allocated in directory (ino %lu)\n",
                        (unsigned long long)pos, dir->i_ino);
-               return -EFSCORRUPTED;
+               err = -EFSCORRUPTED;
+               goto out;
        }
        err = udf_fiiter_load_bhs(iter);
        if (err < 0)
-               return err;
+               goto out;
        err = udf_copy_fi(iter);
-       if (err < 0) {
+out:
+       if (err < 0)
                udf_fiiter_release(iter);
-               return err;
-       }
-       return 0;
+       return err;
 }
 
 int udf_fiiter_advance(struct udf_fileident_iter *iter)
@@ -307,6 +312,8 @@ void udf_fiiter_release(struct udf_fileident_iter *iter)
        brelse(iter->bh[0]);
        brelse(iter->bh[1]);
        iter->bh[0] = iter->bh[1] = NULL;
+       kfree(iter->namebuf);
+       iter->namebuf = NULL;
 }
 
 static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2,
index f764b4d..d35aa42 100644 (file)
@@ -99,7 +99,7 @@ struct udf_fileident_iter {
        struct extent_position epos;    /* Position after the above extent */
        struct fileIdentDesc fi;        /* Copied directory entry */
        uint8_t *name;                  /* Pointer to entry name */
-       uint8_t namebuf[UDF_NAME_LEN_CS0]; /* Storage for entry name in case
+       uint8_t *namebuf;               /* Storage for entry name in case
                                         * the name is split between two blocks
                                         */
 };