Skip to content

Commit a999150

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: use kmem_cache pool during inline xattr lookups
It's been observed that kzalloc() on lookup_all_xattrs() are called millions of times on Android, quickly becoming the top abuser of slub memory allocator. Use a dedicated kmem cache pool for xattr lookups to mitigate this. Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com> Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent dabfbbc commit a999150

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

fs/f2fs/f2fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,9 @@ struct f2fs_sb_info {
14871487
__u32 s_chksum_seed;
14881488

14891489
struct workqueue_struct *post_read_wq; /* post read workqueue */
1490+
1491+
struct kmem_cache *inline_xattr_slab; /* inline xattr entry */
1492+
unsigned int inline_xattr_slab_size; /* default inline xattr slab size */
14901493
};
14911494

14921495
struct f2fs_private_dio {

fs/f2fs/super.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,7 @@ static void f2fs_put_super(struct super_block *sb)
12021202
kvfree(sbi->raw_super);
12031203

12041204
destroy_device_list(sbi);
1205+
f2fs_destroy_xattr_caches(sbi);
12051206
mempool_destroy(sbi->write_io_dummy);
12061207
#ifdef CONFIG_QUOTA
12071208
for (i = 0; i < MAXQUOTAS; i++)
@@ -3458,12 +3459,17 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
34583459
}
34593460
}
34603461

3462+
/* init per sbi slab cache */
3463+
err = f2fs_init_xattr_caches(sbi);
3464+
if (err)
3465+
goto free_io_dummy;
3466+
34613467
/* get an inode for meta space */
34623468
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
34633469
if (IS_ERR(sbi->meta_inode)) {
34643470
f2fs_err(sbi, "Failed to read F2FS meta data inode");
34653471
err = PTR_ERR(sbi->meta_inode);
3466-
goto free_io_dummy;
3472+
goto free_xattr_cache;
34673473
}
34683474

34693475
err = f2fs_get_valid_checkpoint(sbi);
@@ -3736,6 +3742,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
37363742
make_bad_inode(sbi->meta_inode);
37373743
iput(sbi->meta_inode);
37383744
sbi->meta_inode = NULL;
3745+
free_xattr_cache:
3746+
f2fs_destroy_xattr_caches(sbi);
37393747
free_io_dummy:
37403748
mempool_destroy(sbi->write_io_dummy);
37413749
free_percpu:

fs/f2fs/xattr.c

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@
2323
#include "xattr.h"
2424
#include "segment.h"
2525

26+
static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline)
27+
{
28+
if (likely(size == sbi->inline_xattr_slab_size)) {
29+
*is_inline = true;
30+
return kmem_cache_zalloc(sbi->inline_xattr_slab, GFP_NOFS);
31+
}
32+
*is_inline = false;
33+
return f2fs_kzalloc(sbi, size, GFP_NOFS);
34+
}
35+
36+
static void xattr_free(struct f2fs_sb_info *sbi, void *xattr_addr,
37+
bool is_inline)
38+
{
39+
if (is_inline)
40+
kmem_cache_free(sbi->inline_xattr_slab, xattr_addr);
41+
else
42+
kvfree(xattr_addr);
43+
}
44+
2645
static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
2746
struct dentry *unused, struct inode *inode,
2847
const char *name, void *buffer, size_t size)
@@ -301,7 +320,8 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr)
301320
static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
302321
unsigned int index, unsigned int len,
303322
const char *name, struct f2fs_xattr_entry **xe,
304-
void **base_addr, int *base_size)
323+
void **base_addr, int *base_size,
324+
bool *is_inline)
305325
{
306326
void *cur_addr, *txattr_addr, *last_txattr_addr;
307327
void *last_addr = NULL;
@@ -313,7 +333,7 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
313333
return -ENODATA;
314334

315335
*base_size = XATTR_SIZE(inode) + XATTR_PADDING_SIZE;
316-
txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS);
336+
txattr_addr = xattr_alloc(F2FS_I_SB(inode), *base_size, is_inline);
317337
if (!txattr_addr)
318338
return -ENOMEM;
319339

@@ -362,7 +382,7 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
362382
*base_addr = txattr_addr;
363383
return 0;
364384
out:
365-
kvfree(txattr_addr);
385+
xattr_free(F2FS_I_SB(inode), txattr_addr, *is_inline);
366386
return err;
367387
}
368388

@@ -499,6 +519,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
499519
unsigned int size, len;
500520
void *base_addr = NULL;
501521
int base_size;
522+
bool is_inline;
502523

503524
if (name == NULL)
504525
return -EINVAL;
@@ -509,7 +530,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
509530

510531
down_read(&F2FS_I(inode)->i_xattr_sem);
511532
error = lookup_all_xattrs(inode, ipage, index, len, name,
512-
&entry, &base_addr, &base_size);
533+
&entry, &base_addr, &base_size, &is_inline);
513534
up_read(&F2FS_I(inode)->i_xattr_sem);
514535
if (error)
515536
return error;
@@ -532,7 +553,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
532553
}
533554
error = size;
534555
out:
535-
kvfree(base_addr);
556+
xattr_free(F2FS_I_SB(inode), base_addr, is_inline);
536557
return error;
537558
}
538559

@@ -764,3 +785,26 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
764785
f2fs_update_time(sbi, REQ_TIME);
765786
return err;
766787
}
788+
789+
int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi)
790+
{
791+
dev_t dev = sbi->sb->s_bdev->bd_dev;
792+
char slab_name[32];
793+
794+
sprintf(slab_name, "f2fs_xattr_entry-%u:%u", MAJOR(dev), MINOR(dev));
795+
796+
sbi->inline_xattr_slab_size = F2FS_OPTION(sbi).inline_xattr_size *
797+
sizeof(__le32) + XATTR_PADDING_SIZE;
798+
799+
sbi->inline_xattr_slab = f2fs_kmem_cache_create(slab_name,
800+
sbi->inline_xattr_slab_size);
801+
if (!sbi->inline_xattr_slab)
802+
return -ENOMEM;
803+
804+
return 0;
805+
}
806+
807+
void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi)
808+
{
809+
kmem_cache_destroy(sbi->inline_xattr_slab);
810+
}

fs/f2fs/xattr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ extern int f2fs_setxattr(struct inode *, int, const char *,
131131
extern int f2fs_getxattr(struct inode *, int, const char *, void *,
132132
size_t, struct page *);
133133
extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
134+
extern int f2fs_init_xattr_caches(struct f2fs_sb_info *);
135+
extern void f2fs_destroy_xattr_caches(struct f2fs_sb_info *);
134136
#else
135137

136138
#define f2fs_xattr_handlers NULL
@@ -151,6 +153,8 @@ static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer,
151153
{
152154
return -EOPNOTSUPP;
153155
}
156+
static int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) { return 0; }
157+
static void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) { }
154158
#endif
155159

156160
#ifdef CONFIG_F2FS_FS_SECURITY

0 commit comments

Comments
 (0)