Commit d2a97a4e authored by Steven Whitehouse's avatar Steven Whitehouse Committed by Linus Torvalds

GFS2: Use kmalloc when possible for ->readdir()

If we don't need a huge amount of memory in ->readdir() then
we can use kmalloc rather than vmalloc to allocate it. This
should cut down on the greater overheads associated with
vmalloc for smaller directories.

We may be able to eliminate vmalloc entirely at some stage,
but this is easy to do right away.

Also using GFP_NOFS to avoid any issues wrt to deleting inodes
while under a glock, and suggestion from Linus to factor out
the alloc/dealloc.

I've given this a test with a variety of different sized
directories and it seems to work ok.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Nick Piggin <npiggin@suse.de>
Cc: Prarit Bhargava <prarit@redhat.com>
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fc0f5ac8
...@@ -1231,6 +1231,25 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, ...@@ -1231,6 +1231,25 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
return 0; return 0;
} }
static void *gfs2_alloc_sort_buffer(unsigned size)
{
void *ptr = NULL;
if (size < KMALLOC_MAX_SIZE)
ptr = kmalloc(size, GFP_NOFS | __GFP_NOWARN);
if (!ptr)
ptr = __vmalloc(size, GFP_NOFS, PAGE_KERNEL);
return ptr;
}
static void gfs2_free_sort_buffer(void *ptr)
{
if (is_vmalloc_addr(ptr))
vfree(ptr);
else
kfree(ptr);
}
static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
filldir_t filldir, int *copied, unsigned *depth, filldir_t filldir, int *copied, unsigned *depth,
u64 leaf_no) u64 leaf_no)
...@@ -1271,7 +1290,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, ...@@ -1271,7 +1290,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
* 99 is the maximum number of entries that can fit in a single * 99 is the maximum number of entries that can fit in a single
* leaf block. * leaf block.
*/ */
larr = vmalloc((leaves + entries + 99) * sizeof(void *)); larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *));
if (!larr) if (!larr)
goto out; goto out;
darr = (const struct gfs2_dirent **)(larr + leaves); darr = (const struct gfs2_dirent **)(larr + leaves);
...@@ -1282,7 +1301,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, ...@@ -1282,7 +1301,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
do { do {
error = get_leaf(ip, lfn, &bh); error = get_leaf(ip, lfn, &bh);
if (error) if (error)
goto out_kfree; goto out_free;
lf = (struct gfs2_leaf *)bh->b_data; lf = (struct gfs2_leaf *)bh->b_data;
lfn = be64_to_cpu(lf->lf_next); lfn = be64_to_cpu(lf->lf_next);
if (lf->lf_entries) { if (lf->lf_entries) {
...@@ -1291,7 +1310,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, ...@@ -1291,7 +1310,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
gfs2_dirent_gather, NULL, &g); gfs2_dirent_gather, NULL, &g);
error = PTR_ERR(dent); error = PTR_ERR(dent);
if (IS_ERR(dent)) if (IS_ERR(dent))
goto out_kfree; goto out_free;
if (entries2 != g.offset) { if (entries2 != g.offset) {
fs_warn(sdp, "Number of entries corrupt in dir " fs_warn(sdp, "Number of entries corrupt in dir "
"leaf %llu, entries2 (%u) != " "leaf %llu, entries2 (%u) != "
...@@ -1300,7 +1319,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, ...@@ -1300,7 +1319,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
entries2, g.offset); entries2, g.offset);
error = -EIO; error = -EIO;
goto out_kfree; goto out_free;
} }
error = 0; error = 0;
larr[leaf++] = bh; larr[leaf++] = bh;
...@@ -1312,10 +1331,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, ...@@ -1312,10 +1331,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
BUG_ON(entries2 != entries); BUG_ON(entries2 != entries);
error = do_filldir_main(ip, offset, opaque, filldir, darr, error = do_filldir_main(ip, offset, opaque, filldir, darr,
entries, copied); entries, copied);
out_kfree: out_free:
for(i = 0; i < leaf; i++) for(i = 0; i < leaf; i++)
brelse(larr[i]); brelse(larr[i]);
vfree(larr); gfs2_free_sort_buffer(larr);
out: out:
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment