Skip to content

Commit

Permalink
udf: Allocate name buffer in directory iterator on heap
Browse files Browse the repository at this point in the history
commit 0aba486 upstream.

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/[email protected]
Reported-by: kernel test robot <[email protected]>
Signed-off-by: Jan Kara <[email protected]>
[Add extra include linux/slab.h]
Signed-off-by: Hauke Mehrtens <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
jankara authored and gregkh committed Nov 17, 2024
1 parent a5ee9fe commit 5ea4b73
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 9 deletions.
24 changes: 16 additions & 8 deletions fs/udf/directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/bio.h>
#include <linux/crc-itu-t.h>
#include <linux/iversion.h>
#include <linux/slab.h>

static int udf_verify_fi(struct udf_fileident_iter *iter)
{
Expand Down Expand Up @@ -248,9 +249,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) !=
Expand All @@ -260,17 +266,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)
Expand Down Expand Up @@ -307,6 +313,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,
Expand Down
2 changes: 1 addition & 1 deletion fs/udf/udfdecl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
};
Expand Down

0 comments on commit 5ea4b73

Please sign in to comment.