Skip to content

Commit

Permalink
GFS2: Use kmalloc when possible for ->readdir()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Nick Piggin <[email protected]>
Cc: Prarit Bhargava <[email protected]>
Signed-off-by: Steven Whitehouse <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
swhiteho authored and torvalds committed Jul 28, 2010
1 parent fc0f5ac commit d2a97a4
Showing 1 changed file with 25 additions and 6 deletions.
31 changes: 25 additions & 6 deletions fs/gfs2/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,25 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
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,
filldir_t filldir, int *copied, unsigned *depth,
u64 leaf_no)
Expand Down Expand Up @@ -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
* leaf block.
*/
larr = vmalloc((leaves + entries + 99) * sizeof(void *));
larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *));
if (!larr)
goto out;
darr = (const struct gfs2_dirent **)(larr + leaves);
Expand All @@ -1282,7 +1301,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
do {
error = get_leaf(ip, lfn, &bh);
if (error)
goto out_kfree;
goto out_free;
lf = (struct gfs2_leaf *)bh->b_data;
lfn = be64_to_cpu(lf->lf_next);
if (lf->lf_entries) {
Expand All @@ -1291,7 +1310,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
gfs2_dirent_gather, NULL, &g);
error = PTR_ERR(dent);
if (IS_ERR(dent))
goto out_kfree;
goto out_free;
if (entries2 != g.offset) {
fs_warn(sdp, "Number of entries corrupt in dir "
"leaf %llu, entries2 (%u) != "
Expand All @@ -1300,7 +1319,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
entries2, g.offset);

error = -EIO;
goto out_kfree;
goto out_free;
}
error = 0;
larr[leaf++] = bh;
Expand All @@ -1312,10 +1331,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
BUG_ON(entries2 != entries);
error = do_filldir_main(ip, offset, opaque, filldir, darr,
entries, copied);
out_kfree:
out_free:
for(i = 0; i < leaf; i++)
brelse(larr[i]);
vfree(larr);
gfs2_free_sort_buffer(larr);
out:
return error;
}
Expand Down

0 comments on commit d2a97a4

Please sign in to comment.