From 426f86751b7ea842115051030464a53c8cab4f71 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 8 Apr 2022 19:08:53 -0700 Subject: [PATCH] UPSTREAM: ANDROID: fuse-bpf: Use cache and refcount Allocates the iocb we create for asynchronous IO from a cache instead of a regular kzalloc Test: generic/467 and fuse_test Bug: 217570523 Signed-off-by: Daniel Rosenberg Change-Id: I27dcec89cd585835f6a8e80e1ae30c503f4038c8 --- fs/fuse/backing.c | 38 +++++++++++++++++++++++++++++++++----- fs/fuse/control.c | 2 +- fs/fuse/fuse_i.h | 5 ++++- fs/fuse/inode.c | 7 +++++++ 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 6dd34a05a464..9bc1c51f8f9e 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -17,9 +17,12 @@ struct fuse_bpf_aio_req { struct kiocb iocb; + refcount_t ref; struct kiocb *iocb_orig; }; +static struct kmem_cache *fuse_bpf_aio_request_cachep; + static void fuse_file_accessed(struct file *dst_file, struct file *src_file) { struct inode *dst_inode; @@ -810,6 +813,12 @@ void *fuse_removexattr_finalize(struct fuse_args *fa, return NULL; } +static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req) +{ + if (refcount_dec_and_test(&aio_req->ref)) + kmem_cache_free(fuse_bpf_aio_request_cachep, aio_req); +} + static void fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req *aio_req) { struct kiocb *iocb = &aio_req->iocb; @@ -821,9 +830,8 @@ static void fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req *aio_req) file_end_write(iocb->ki_filp); fuse_copyattr(iocb_orig->ki_filp, iocb->ki_filp); } - iocb_orig->ki_pos = iocb->ki_pos; - kfree(aio_req); + fuse_bpf_aio_put(aio_req); } static void fuse_bpf_aio_rw_complete(struct kiocb *iocb, long res, long res2) @@ -896,13 +904,16 @@ int fuse_file_read_iter_backing(struct fuse_args *fa, struct fuse_bpf_aio_req *aio_req; ret = -ENOMEM; - aio_req = kzalloc(sizeof(struct fuse_bpf_aio_req), GFP_KERNEL); + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); if (!aio_req) goto out; + aio_req->iocb_orig = iocb; kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); ret = vfs_iocb_iter_read(ff->backing_file, &aio_req->iocb, to); + fuse_bpf_aio_put(aio_req); if (ret != -EIOCBQUEUED) fuse_bpf_aio_cleanup_handler(aio_req); } @@ -984,8 +995,7 @@ int fuse_file_write_iter_backing(struct fuse_args *fa, struct fuse_bpf_aio_req *aio_req; ret = -ENOMEM; - /* TODO get this from a cache? */ - aio_req = kzalloc(sizeof(struct fuse_bpf_aio_req), GFP_KERNEL); + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); if (!aio_req) goto out; @@ -994,7 +1004,9 @@ int fuse_file_write_iter_backing(struct fuse_args *fa, aio_req->iocb_orig = iocb; kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); ret = vfs_iocb_iter_write(ff->backing_file, &aio_req->iocb, from); + fuse_bpf_aio_put(aio_req); if (ret != -EIOCBQUEUED) fuse_bpf_aio_cleanup_handler(aio_req); } @@ -2369,3 +2381,19 @@ void *fuse_access_finalize(struct fuse_args *fa, struct inode *inode, int mask) { return NULL; } + +int __init fuse_bpf_init(void) +{ + fuse_bpf_aio_request_cachep = kmem_cache_create("fuse_bpf_aio_req", + sizeof(struct fuse_bpf_aio_req), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!fuse_bpf_aio_request_cachep) + return -ENOMEM; + + return 0; +} + +void __exit fuse_bpf_cleanup(void) +{ + kmem_cache_destroy(fuse_bpf_aio_request_cachep); +} diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 24b4d9db231d..9b46669f8f85 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -395,7 +395,7 @@ int __init fuse_ctl_init(void) return register_filesystem(&fuse_ctl_fs_type); } -void __exit fuse_ctl_cleanup(void) +void fuse_ctl_cleanup(void) { unregister_filesystem(&fuse_ctl_fs_type); } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 15c68072f90a..7d6b5ee9d1e5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1054,7 +1054,7 @@ int fuse_dev_init(void); void fuse_dev_cleanup(void); int fuse_ctl_init(void); -void __exit fuse_ctl_cleanup(void); +void fuse_ctl_cleanup(void); /** * Simple request sending that does request allocation and freeing @@ -1778,6 +1778,9 @@ struct fuse_err_ret { bool ret; }; +int __init fuse_bpf_init(void); +void __exit fuse_bpf_cleanup(void); + /* * expression statement to wrap the backing filter logic * struct inode *inode: inode with bpf and backing inode diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7142a25d974f..0e803d857f9f 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1911,11 +1911,17 @@ static int __init fuse_init(void) if (res) goto err_sysfs_cleanup; + res = fuse_bpf_init(); + if (res) + goto err_ctl_cleanup; + sanitize_global_limit(&max_user_bgreq); sanitize_global_limit(&max_user_congthresh); return 0; + err_ctl_cleanup: + fuse_ctl_cleanup(); err_sysfs_cleanup: fuse_sysfs_cleanup(); err_dev_cleanup: @@ -1933,6 +1939,7 @@ static void __exit fuse_exit(void) fuse_ctl_cleanup(); fuse_sysfs_cleanup(); fuse_fs_cleanup(); + fuse_bpf_cleanup(); fuse_dev_cleanup(); }