Add support for no_interrupt (#956)
authoryangyun50 <149988609+yangyun50@users.noreply.github.com>
Tue, 4 Jun 2024 11:50:48 +0000 (19:50 +0800)
committerGitHub <noreply@github.com>
Tue, 4 Jun 2024 11:50:48 +0000 (13:50 +0200)
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.

example/cuse.c
example/hello_ll.c
example/hello_ll_uds.c
example/notify_inval_entry.c
example/notify_inval_inode.c
example/notify_store_retrieve.c
example/passthrough_hp.cc
example/passthrough_ll.c
include/fuse_common.h
lib/fuse.c
lib/fuse_lowlevel.c

index 0c0e7bce75e98fd3f86b6b137d645bb1a84c9f40..6b333029fd4a5c154041ac628adedfe12ad4a037 100644 (file)
@@ -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,
index 10f4b4ac243e2ebfa17985504c1222bb6c66c715..28bd1c4a9abcf0686014daa01974e7a0d917ab19 100644 (file)
@@ -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,
index f291fed99e18e5bd4a524c61f4ca74bc0c2539b0..a566155dc1c71671fa89179db56290dd2e764328 100644 (file)
@@ -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,
index 83b24d27cb1aecb4ef0f4d9cbfc0f7caa5d9c70a..c30789970646bd255d3f1199aa291d122f66948c 100644 (file)
@@ -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,
index c0b1112a061e266fe8065110dedca241a937e90f..de88c87e71a51e674eefbdc1bfd5c74e2c8038e1 100644 (file)
@@ -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,
index 1298591f5011f2145c58703b2b720a9261c7883c..7145bf49a10907bc5ab8be8e7a5f132e99fbe26d 100644 (file)
@@ -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,
index 7b8febeb70bee79b3d61f4923b9681121adbca23..e780f2387e48a3bf5529359ac53c441c2f8dfa85 100644 (file)
@@ -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;
 }
 
 
index da9de53d14568057e7ec51a9fcb1a8075dde66a1..87c18a28ebd7342bc8031806b2a84cc22ae85249 100644 (file)
@@ -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)
index ba4b127f6320b6a49601fec0c1dd494995fc78a3..c583af399bf1f53cd8fa375195c02a185ca6959a 100644 (file)
@@ -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;
index 861716890a582b61e267ccc50d43929f4c2d407d..4f06da78903b8dfe356a167f895820f39a5089a9 100644 (file)
@@ -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)
index dc1b7a653ed91368aacd4e654e3bae8157d153b4..92f7a9977a0e799b8b71e83022e5b30523fe56e5 100644 (file)
@@ -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);