diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ee4e436fcbc81b846fd2f2a05ace86a20315d451..c16aa1858514c84d03ae96cb773e3f01017b2d57 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", @@ -2843,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/fs/fuse/dir.c b/fs/fuse/dir.c index 5c4f6a1a6e7ac5931bb189add5a9a851ec37313d..5d91fc200bb3fec2d9ecee375dcadbd9cdd92806 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 294a58e4a4c351a6e635690d8d9317584e7c76b9..c561dab037279a84d1ca4bfbede73a41508453c3 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 c2603f6fd9ee676be3979a0790fa29e30c32aa4a..9acca79149ca4f5c132b31e9d9ef0f1d2627cab9 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 2bc6e6691b8ee45a018ccddce5c614753917c430..611afb5e8125be34a3c08c51f77d8b5a175c7dfa 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 3de28f382bd113618d793a976e1ef2ba11ef7caf..bb92b623fcbe256865bb92ec269bf222a3e3713e 100644 --- a/ipc/fast_ipc.c +++ b/ipc/fast_ipc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -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; } @@ -250,8 +257,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;