[PATCH OLK-5.10 0/2] bugfixes for fuse fastpath and fast_ipc

bugfixes for fuse fastpath and fast_ipc chenrenhui (1): fuse: add fuse fastpath forget cmd support wuyifeng10 (1): ipc: fix error kill signal handle in fastpath fs/fuse/dev.c | 46 ++++++++++++++++++++++++++++++++++------ fs/fuse/dir.c | 16 ++++++++++++++ fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 5 +++++ include/linux/fast_ipc.h | 6 ++++++ ipc/fast_ipc.c | 25 ++++++++++++++++------ 6 files changed, 88 insertions(+), 13 deletions(-) -- 2.33.0

euleros inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KLD CVE: NA -------------------------------- fuse fastpath don't handle the forget queue, use fuse_fast_forget send cmd instead of fuse_queue_forget. Fixes: d738472f4834 ("fuse: support fastpath via fast_ipc") Signed-off-by: wuyifeng10 <wuyifeng10@huawei.com> --- fs/fuse/dev.c | 42 ++++++++++++++++++++++++++++++++++------ fs/fuse/dir.c | 16 +++++++++++++++ fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 5 +++++ include/linux/fast_ipc.h | 6 ++++++ ipc/fast_ipc.c | 10 ++++++++-- 6 files changed, 74 insertions(+), 8 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ee4e436fcbc8..c8df2357a5e7 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -352,6 +352,8 @@ ssize_t fuse_simple_request_fast(struct fuse_mount *fm, struct fuse_args *args) if (!args->noreply) __set_bit(FR_ISREPLY, &req->flags); + else + __clear_bit(FR_ISREPLY, &req->flags); __fuse_ipc_send(req, current, ipc_info); @@ -516,16 +518,42 @@ __releases(fiq->lock) fiq->ops->wake_pending_and_unlock(fiq); } -void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, - u64 nodeid, u64 nlookup) +#ifdef CONFIG_FUSE_FASTPATH +void fuse_fast_forget(struct fuse_mount *fm, struct fuse_forget_link *forget, + u64 nodeid, u64 nlookup) { - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_forget_in inarg; -#ifdef CONFIG_FUSE_FASTPATH - if (fc->no_forget) + FUSE_ARGS(args); + + if (fm->fc->no_forget) return; + + if (!fm->fc->use_fastpath) { + fuse_queue_forget(fm->fc, forget, nodeid, nlookup); + return; + } + + memset(&inarg, 0, sizeof(inarg)); + inarg.nlookup = nlookup; + args.opcode = FUSE_FORGET; + args.nodeid = nodeid; + args.in_numargs = 1; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + args.force = true; + args.noreply = true; + + fuse_simple_request(fm, &args); + /* ignore errors */ +} #endif +void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, + u64 nodeid, u64 nlookup) +{ + struct fuse_iqueue *fiq = &fc->iq; + forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; @@ -2698,7 +2726,6 @@ static ssize_t fuse_ipc_do_read(struct fuse_ipc_info *ipc_info, return reqsize; out_end: - fuse_drop_waiting(req->fm->fc); FUSE_DEBUG("[%s] error: %ld\n", __func__, err); return err; } @@ -2733,6 +2760,9 @@ static long fuse_ipc_wait_call(struct file *file, struct fuse_conn *fc, return ret; } + if (!test_bit(FR_ISREPLY, &ipc_info->req.flags)) + fast_ipc_set_call_no_reply(ipc_info->bind_info); + ret = fuse_ipc_read(ipc_info, ipc_in_data); FUSE_DEBUG("[cpu/%d][%s/%d] wait call slow end, ret = %ld\n", diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 5c4f6a1a6e7a..5d91fc200bb3 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -245,8 +245,12 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) fi = get_fuse_inode(inode); if (outarg.nodeid != get_node_id(inode) || (bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) { +#ifdef CONFIG_FUSE_FASTPATH + fuse_fast_forget(fm, forget, outarg.nodeid, 1); +#else fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); +#endif goto invalid; } #ifdef CONFIG_FUSE_FASTPATH @@ -478,7 +482,11 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name attr_version); err = -ENOMEM; if (!*inode) { +#ifdef CONFIG_FUSE_FASTPATH + fuse_fast_forget(fm, forget, outarg->nodeid, 1); +#else fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); +#endif goto out; } err = 0; @@ -625,7 +633,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); fuse_sync_release(NULL, ff, flags); +#ifdef CONFIG_FUSE_FASTPATH + fuse_fast_forget(fm, forget, outentry.nodeid, 1); +#else fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); +#endif err = -ENOMEM; goto out_err; } @@ -751,7 +763,11 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args, inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr, entry_attr_timeout(&outarg), 0); if (!inode) { +#ifdef CONFIG_FUSE_FASTPATH + fuse_fast_forget(fm, forget, outarg.nodeid, 1); +#else fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); +#endif return -ENOMEM; } #ifdef CONFIG_FUSE_FASTPATH diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 294a58e4a4c3..c561dab03727 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1290,6 +1290,9 @@ void fuse_dax_cancel_work(struct fuse_conn *fc); #define FUSE_DATA_PAGE_SIZE 4096 +void fuse_fast_forget(struct fuse_mount *fm, struct fuse_forget_link *forget, + u64 nodeid, u64 nlookup); + struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io, unsigned int npages); void fuse_io_free(struct fuse_io_args *ia); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index c2603f6fd9ee..9acca79149ca 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -133,8 +133,13 @@ static void fuse_evict_inode(struct inode *inode) if (FUSE_IS_DAX(inode)) fuse_dax_inode_cleanup(inode); if (fi->nlookup) { +#ifdef CONFIG_FUSE_FASTPATH + fuse_fast_forget(get_fuse_mount(inode), fi->forget, + fi->nodeid, fi->nlookup); +#else fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup); +#endif fi->forget = NULL; } } diff --git a/include/linux/fast_ipc.h b/include/linux/fast_ipc.h index 2bc6e6691b8e..611afb5e8125 100644 --- a/include/linux/fast_ipc.h +++ b/include/linux/fast_ipc.h @@ -15,6 +15,7 @@ struct fast_ipc_bind_info { struct task_struct *server_task; bool is_calling; + bool no_reply; bool client_need_exit; bool server_need_exit; @@ -42,4 +43,9 @@ long fast_ipc_wait_call(struct fast_ipc_bind_info *bind_info, void fast_ipc_release(struct fast_ipc_bind_info *bind_info); +static inline void fast_ipc_set_call_no_reply(struct fast_ipc_bind_info *bind_info) +{ + bind_info->no_reply = true; +}; + #endif diff --git a/ipc/fast_ipc.c b/ipc/fast_ipc.c index 3de28f382bd1..0bf761e117db 100644 --- a/ipc/fast_ipc.c +++ b/ipc/fast_ipc.c @@ -250,8 +250,14 @@ long fast_ipc_wait_call(struct fast_ipc_bind_info *bind_info, for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (bind_info->is_calling) - break; + if (bind_info->is_calling) { + /* client send a no reply request to userspace,we must handle it */ + if (bind_info->no_reply) { + bind_info->no_reply = false; + fast_ipc_ret_call(bind_info, tsk); + } else + break; + } if (bind_info->server_need_exit) { ret = -ENODEV; -- 2.33.0

From: wuyifeng10 <wuyifeng10@huawei.com> euleros inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KJ2 CVE: NA -------------------------------- When a kill signal recived by fusepath client, the server will abort, we need ignore the client action. Fixes: 1fc14d09b9f0 ("ipc: add fast_ipc module to enable fast process switching") Signed-off-by: wuyifeng10 <wuyifeng10@huawei.com> --- fs/fuse/dev.c | 4 +++- ipc/fast_ipc.c | 15 +++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index c8df2357a5e7..c16aa1858514 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2873,7 +2873,9 @@ static long fuse_ipc_ret_call(struct file *file, struct fuse_conn *fc, if (num_written < 0) { pr_err("[cpu/%d] [%s/%d]fuse_ipc_write failed %ld\n", smp_processor_id(), tsk->comm, tsk->pid, num_written); - return num_written; + /* no return, we report the error msg to client in + * fuse_ipc_write and continue handle the next request + */ } ret = fast_ipc_ret_call(ipc_info->bind_info, tsk); diff --git a/ipc/fast_ipc.c b/ipc/fast_ipc.c index 0bf761e117db..bb92b623fcbe 100644 --- a/ipc/fast_ipc.c +++ b/ipc/fast_ipc.c @@ -10,6 +10,7 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/sched.h> +#include <linux/delay.h> #include <linux/printk.h> #include <linux/preempt.h> #include <linux/sched/signal.h> @@ -185,11 +186,14 @@ ssize_t fast_ipc_do_call(struct fast_ipc_bind_info *bind_info, tsk->comm, tsk->pid); if (signal_pending(current)) { ret = -EINTR; - pr_err("[cpu/%d][%s/%d] client has signal pending break\n", + pr_err("[cpu/%d][%s/%d] client has signal, wait server finish\n", smp_processor_id(), tsk->comm, tsk->pid); - break; + msleep(10); + set_current_state(TASK_RUNNING); + /* for next loop, server change the is_calling flags */ + if (!bind_info->is_calling) + pr_err("server finish\n"); } - set_current_state(TASK_INTERRUPTIBLE); } set_current_state(TASK_RUNNING); @@ -216,12 +220,15 @@ long fast_ipc_ret_call(struct fast_ipc_bind_info *bind_info, { struct task_struct *client_task; - if (!bind_info->is_calling) + if (!bind_info->is_calling) { + pr_err("confusing bug is_no_calling\n"); return 0; + } bind_info_lock(bind_info); client_task = bind_info->client_task; if (!client_task) { + pr_err("confusing bug no_client\n"); bind_info_unlock(bind_info); return -ESRCH; } -- 2.33.0

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16355 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/ZG2... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/16355 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/ZG2...
participants (2)
-
chenrenhui
-
patchwork bot