From: yangyun50 <149988609+yangyun50@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:50:48 +0000 (+0800) Subject: Add support for no_interrupt (#956) X-Git-Tag: fuse-3.17.1-rc0~113 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=cef8c8b249023fb8129ae791e0998cbca771f96a;p=qemu-gpiodev%2Flibfuse.git Add support for no_interrupt (#956) The function fuse_session_process_buf_int() would do much things for FUSE_INTERRUPT requests, even there are no FUSE_INTERRUPT requests: 1. check every non-FUSE_INTERRUPT request and add these requests to the linked list(se->list) under a big lock(se->lock). 2. the function fuse_free_req() frees every request and remove them from the linked list(se->list) under a bing lock(se->lock). These operations are not meaningful when there are no FUSE_INTERRUPT requests, and have a great impact on the performance of fuse filesystem because the big lock for each request. In some cases, FUSE_INTERRUPT requests are infrequent, even none at all. Besides, the user-defined filesystem may do nothing for FUSE_INTERRUPT requests. And the kernel side has the option "no_interrupt" in struct fuse_conn. This kernel option can be enabled by return ENOSYS in libfuse for the reply of FUSE_INTERRUPT request. But I don't find the code to enable the "no_interrupt" kernel option in libfuse. So add the no_interrupt support, and when this operaion is enabled: 1. remove the useless locking operaions and list operations. 2. return ENOSYS for the reply of FUSE_INTERRUPT request to inform the kernel to disable FUSE_INTERRUPT request. --- diff --git a/example/cuse.c b/example/cuse.c index 0c0e7bc..6b33302 100644 --- a/example/cuse.c +++ b/example/cuse.c @@ -87,6 +87,14 @@ static int cusexmp_expand(size_t new_size) return 0; } +static void cusexmp_init(void *userdata, struct fuse_conn_info *conn) +{ + (void)userdata; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; +} + static void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi) { fuse_reply_open(req, fi); @@ -281,6 +289,7 @@ static int cusexmp_process_arg(void *data, const char *arg, int key, } static const struct cuse_lowlevel_ops cusexmp_clop = { + .init = cusexmp_init, .open = cusexmp_open, .read = cusexmp_read, .write = cusexmp_write, diff --git a/example/hello_ll.c b/example/hello_ll.c index 10f4b4a..28bd1c4 100644 --- a/example/hello_ll.c +++ b/example/hello_ll.c @@ -53,6 +53,14 @@ static int hello_stat(fuse_ino_t ino, struct stat *stbuf) return 0; } +static void hello_ll_init(void *userdata, struct fuse_conn_info *conn) +{ + (void)userdata; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; +} + static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { @@ -202,6 +210,7 @@ static void hello_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *nam } static const struct fuse_lowlevel_ops hello_ll_oper = { + .init = hello_ll_init, .lookup = hello_ll_lookup, .getattr = hello_ll_getattr, .readdir = hello_ll_readdir, diff --git a/example/hello_ll_uds.c b/example/hello_ll_uds.c index f291fed..a566155 100644 --- a/example/hello_ll_uds.c +++ b/example/hello_ll_uds.c @@ -77,6 +77,14 @@ static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino, fuse_reply_attr(req, &stbuf, 1.0); } +static void hello_ll_init(void *userdata, struct fuse_conn_info *conn) +{ + (void)userdata; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; +} + static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse_entry_param e; @@ -164,6 +172,7 @@ static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, } static const struct fuse_lowlevel_ops hello_ll_oper = { + .init = hello_ll_init, .lookup = hello_ll_lookup, .getattr = hello_ll_getattr, .readdir = hello_ll_readdir, diff --git a/example/notify_inval_entry.c b/example/notify_inval_entry.c index 83b24d2..c307899 100644 --- a/example/notify_inval_entry.c +++ b/example/notify_inval_entry.c @@ -140,6 +140,13 @@ static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) { return 0; } +static void tfs_init(void *userdata, struct fuse_conn_info *conn) { + (void)userdata; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; +} + static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse_entry_param e; @@ -232,6 +239,7 @@ static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, } static const struct fuse_lowlevel_ops tfs_oper = { + .init = tfs_init, .lookup = tfs_lookup, .getattr = tfs_getattr, .readdir = tfs_readdir, diff --git a/example/notify_inval_inode.c b/example/notify_inval_inode.c index c0b1112..de88c87 100644 --- a/example/notify_inval_inode.c +++ b/example/notify_inval_inode.c @@ -123,6 +123,13 @@ static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) { return 0; } +static void tfs_init(void *userdata, struct fuse_conn_info *conn) { + (void)userdata; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; +} + static void tfs_destroy(void *userarg) { (void)userarg; @@ -250,6 +257,7 @@ static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, } static const struct fuse_lowlevel_ops tfs_oper = { + .init = tfs_init, .destroy = tfs_destroy, .lookup = tfs_lookup, .getattr = tfs_getattr, diff --git a/example/notify_store_retrieve.c b/example/notify_store_retrieve.c index 1298591..7145bf4 100644 --- a/example/notify_store_retrieve.c +++ b/example/notify_store_retrieve.c @@ -132,6 +132,13 @@ static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) { return 0; } +static void tfs_init(void *userdata, struct fuse_conn_info *conn) { + (void)userdata; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; +} + static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse_entry_param e; @@ -304,6 +311,7 @@ static void tfs_destroy(void *userdata) static const struct fuse_lowlevel_ops tfs_oper = { + .init = tfs_init, .lookup = tfs_lookup, .getattr = tfs_getattr, .readdir = tfs_readdir, diff --git a/example/passthrough_hp.cc b/example/passthrough_hp.cc index 7b8febe..e780f23 100644 --- a/example/passthrough_hp.cc +++ b/example/passthrough_hp.cc @@ -223,6 +223,9 @@ static void sfs_init(void *userdata, fuse_conn_info *conn) { /* This is a local file system - no network coherency needed */ if (conn->capable & FUSE_CAP_DIRECT_IO_ALLOW_MMAP) conn->want |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP; + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; } diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c index da9de53..87c18a2 100644 --- a/example/passthrough_ll.c +++ b/example/passthrough_ll.c @@ -181,6 +181,9 @@ static void lo_init(void *userdata, fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n"); conn->want |= FUSE_CAP_FLOCK_LOCKS; } + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + conn->no_interrupt = 1; } static void lo_destroy(void *userdata) diff --git a/include/fuse_common.h b/include/fuse_common.h index ba4b127..c583af3 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -634,10 +634,20 @@ struct fuse_conn_info { #define FUSE_BACKING_STACKED_OVER (1) unsigned max_backing_stack_depth; + /** + * Disable FUSE_INTERRUPT requests. + * + * Enable `no_interrupt` option to: + * 1) Avoid unnecessary locking operations and list operations, + * 2) Return ENOSYS for the reply of FUSE_INTERRUPT request to + * inform the kernel not to send the FUSE_INTERRUPT request. + */ + unsigned no_interrupt; + /** * For future use. */ - unsigned reserved[21]; + unsigned reserved[20]; }; struct fuse_session; diff --git a/lib/fuse.c b/lib/fuse.c index 8617168..4f06da7 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -2612,6 +2612,10 @@ static void fuse_lib_init(void *data, struct fuse_conn_info *conn) if(conn->capable & FUSE_CAP_EXPORT_SUPPORT) conn->want |= FUSE_CAP_EXPORT_SUPPORT; fuse_fs_init(f->fs, conn, &f->conf); + + /* Disable the receiving and processing of FUSE_INTERRUPT requests */ + if (!f->conf.intr) + conn->no_interrupt = 1; } void fuse_fs_destroy(struct fuse_fs *fs) diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index dc1b7a6..92f7a99 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -134,14 +134,20 @@ void fuse_free_req(fuse_req_t req) int ctr; struct fuse_session *se = req->se; - pthread_mutex_lock(&se->lock); - req->u.ni.func = NULL; - req->u.ni.data = NULL; - list_del_req(req); - ctr = --req->ctr; - fuse_chan_put(req->ch); - req->ch = NULL; - pthread_mutex_unlock(&se->lock); + if (se->conn.no_interrupt) { + ctr = --req->ctr; + fuse_chan_put(req->ch); + req->ch = NULL; + } else { + pthread_mutex_lock(&se->lock); + req->u.ni.func = NULL; + req->u.ni.data = NULL; + list_del_req(req); + ctr = --req->ctr; + fuse_chan_put(req->ch); + req->ch = NULL; + pthread_mutex_unlock(&se->lock); + } if (!ctr) destroy_req(req); } @@ -2786,7 +2792,13 @@ void fuse_session_process_buf_int(struct fuse_session *se, err = ENOSYS; if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) goto reply_err; - if (in->opcode != FUSE_INTERRUPT) { + /* Do not process interrupt request */ + if (se->conn.no_interrupt && in->opcode == FUSE_INTERRUPT) { + if (se->debug) + fuse_log(FUSE_LOG_DEBUG, "FUSE_INTERRUPT: reply to kernel to disable interrupt\n"); + goto reply_err; + } + if (!se->conn.no_interrupt && in->opcode != FUSE_INTERRUPT) { struct fuse_req *intr; pthread_mutex_lock(&se->lock); intr = check_interrupt(se, req);