All of lore.kernel.org
 help / color / mirror / Atom feed
From: Baokun Li <libaokun@linux.alibaba.com>
To: fuse-devel@lists.linux.dev
Cc: bernd@bsbernd.com, miklos@szeredi.hu
Subject: [PATCH 1/2] fuse_lowlevel: add support for FUSE_NOTIFY_RESEND
Date: Fri,  9 Oct 2026 15:54:15 +0800	[thread overview]
Message-ID: <20261009075417.2521879-2-libaokun@linux.alibaba.com> (raw)
In-Reply-To: <20261009075417.2521879-1-libaokun@linux.alibaba.com>

The kernel supports resending pending requests since protocol 7.40
(FUSE_NOTIFY_RESEND / FUSE_HAS_RESEND), added in Linux 6.9 by commits
760eac73f9f6 ("fuse: Introduce a new notification type for resend
pending requests") and 9e7f5296f475 ("fuse: Use the high bit of request
ID for indicating resend requests"). A daemon can ask the kernel to
requeue requests that were already sent to the daemon but never
answered, e.g. to recover in-flight requests after a daemon takeover.

Add fuse_lowlevel_notify_resend() to send the notification, expose
kernel support through the new FUSE_CAP_HAS_RESEND capability, and add
fuse_req_is_resend() so file systems can detect resent requests via the
FUSE_UNIQUE_RESEND bit in the request ID and handle them idempotently.

Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
---
 ChangeLog.rst            |  7 +++++++
 doc/README.notifications |  2 +-
 include/fuse_common.h    | 13 +++++++++++++
 include/fuse_lowlevel.h  | 28 ++++++++++++++++++++++++++++
 lib/fuse_cap_names_i.h   |  1 +
 lib/fuse_lowlevel.c      | 23 +++++++++++++++++++++++
 lib/fuse_versionscript   |  2 ++
 7 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/ChangeLog.rst b/ChangeLog.rst
index d5392b251929..ec8cbc3dd1d5 100644
--- a/ChangeLog.rst
+++ b/ChangeLog.rst
@@ -1,6 +1,13 @@
 Unreleased Changes
 ==================
 
+* ``fuse_lowlevel_notify_resend()`` lets a filesystem ask the kernel to
+  re-queue requests that were already sent to the daemon but never
+  answered, for example to recover in-flight requests after a daemon
+  takeover. Support is reported through the new ``FUSE_CAP_HAS_RESEND``
+  capability, and ``fuse_req_is_resend()`` tells whether a request was
+  redelivered this way. Requires protocol 7.40 (Linux 6.9) or newer.
+
 * ``fuse_session_custom_io()`` is disabled unless libfuse is built with
   ``-Denable-custom-io=true``, and returns ``-ENOTSUP`` otherwise. The
   ``hello_ll_uds`` example is built only with that option, and enabling it
diff --git a/doc/README.notifications b/doc/README.notifications
index 149e47e19c9f..30051ed87b51 100644
--- a/doc/README.notifications
+++ b/doc/README.notifications
@@ -26,7 +26,7 @@ notifications:
 | STORE       | fuse_lowlevel_notify_store       |
 | RETRIEVE    | fuse_lowlevel_notify_retrieve    |
 | DELETE      | fuse_lowlevel_notify_delete      |
-| RESEND      | -                                |
+| RESEND      | fuse_lowlevel_notify_resend      |
 | PRUNE       | fuse_lowlevel_notify_prune       |
 |-------------+----------------------------------|
 
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 7533626175db..c2a7211e2f53 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -551,6 +551,19 @@ struct fuse_loop_config_v1 {
  */
 #define FUSE_CAP_IO_URING_BUFPOOL (1ULL << 34)
 
+/**
+ * Indicates that the kernel supports resending pending requests
+ *
+ * The file system can ask the kernel to re-queue requests that were
+ * already sent to the daemon but never answered, by sending the
+ * FUSE_NOTIFY_RESEND notification (see fuse_lowlevel_notify_resend()).
+ * Resent requests carry the FUSE_UNIQUE_RESEND bit in the request ID,
+ * which can be queried with fuse_req_is_resend().
+ *
+ * This feature is enabled by default when supported by the kernel.
+ */
+#define FUSE_CAP_HAS_RESEND (1ULL << 35)
+
 /**
  * Ioctl flags
  *
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index f228bdfd951f..a6313e24a5a8 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -1977,6 +1977,23 @@ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
 int fuse_lowlevel_notify_prune(struct fuse_session *se,
 			       fuse_ino_t *nodeids, uint32_t count);
 
+/**
+ * Notify the kernel to resend pending requests
+ *
+ * Ask the kernel to re-queue requests that were already sent to the file
+ * system but not yet answered, e.g. to recover in-flight requests after
+ * a daemon takeover.
+ *
+ * Resent requests carry the FUSE_UNIQUE_RESEND bit in the request ID; use
+ * fuse_req_is_resend() to detect them. Since they may have been partially
+ * processed before, they should be handled idempotently or duplicates
+ * should be detected.
+ *
+ * @param se the session object
+ * @return zero for success, -errno for failure
+ */
+int fuse_lowlevel_notify_resend(struct fuse_session *se);
+
 /* ----------------------------------------------------------- *
  * Utility functions					       *
  * ----------------------------------------------------------- */
@@ -2100,6 +2117,17 @@ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
  */
 int fuse_req_interrupted(fuse_req_t req);
 
+/**
+ * Check if a request is a resent request
+ *
+ * A resent request was already sent to the file system, but was never
+ * answered (see fuse_lowlevel_notify_resend()).
+ *
+ * @param req request handle
+ * @return 1 if the request is a resend request, 0 otherwise
+ */
+int fuse_req_is_resend(fuse_req_t req);
+
 
 /* ----------------------------------------------------------- *
  * Inquiry functions                                           *
diff --git a/lib/fuse_cap_names_i.h b/lib/fuse_cap_names_i.h
index aa85b910200d..36e99147dd89 100644
--- a/lib/fuse_cap_names_i.h
+++ b/lib/fuse_cap_names_i.h
@@ -63,6 +63,7 @@ static const struct fuse_cap_name fuse_cap_names[] = {
 	{ FUSE_CAP_ALLOW_IDMAP,			"FUSE_CAP_ALLOW_IDMAP"},
 	{ FUSE_CAP_SECURITY_CTX,		"FUSE_CAP_SECURITY_CTX"},
 	{ FUSE_CAP_IO_URING_BUFPOOL,		"FUSE_CAP_IO_URING_BUFPOOL"},
+	{ FUSE_CAP_HAS_RESEND,			"FUSE_CAP_HAS_RESEND"},
 	// Add any new capabilities here
 	{ 0, NULL} // Sentinel to mark the end of the array
 };
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 3951bbb6dd09..bbc58523b033 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -2960,6 +2960,8 @@ _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
 			se->conn.capable_ext |= FUSE_CAP_ALLOW_IDMAP;
 		if (inargflags & FUSE_SECURITY_CTX)
 			se->conn.capable_ext |= FUSE_CAP_SECURITY_CTX;
+		if (inargflags & FUSE_HAS_RESEND)
+			se->conn.capable_ext |= FUSE_CAP_HAS_RESEND;
 	} else {
 		se->conn.max_readahead = 0;
 	}
@@ -3005,6 +3007,7 @@ _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
 		       FUSE_CAP_READDIRPLUS_AUTO);
 	LL_SET_DEFAULT(1, FUSE_CAP_OVER_IO_URING);
 	LL_SET_DEFAULT(se->uring.bufpool, FUSE_CAP_IO_URING_BUFPOOL);
+	LL_SET_DEFAULT(1, FUSE_CAP_HAS_RESEND);
 
 	/* This could safely become default, but libfuse needs an API extension
 	 * to support it
@@ -3133,6 +3136,8 @@ _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
 		outargflags |= FUSE_SECURITY_CTX;
 	if (se->conn.want_ext & FUSE_CAP_ALLOW_IDMAP)
 		outargflags |= FUSE_ALLOW_IDMAP;
+	if (se->conn.want_ext & FUSE_CAP_HAS_RESEND)
+		outargflags |= FUSE_HAS_RESEND;
 
 	if ((inargflags & FUSE_REQUEST_TIMEOUT) && se->conn.request_timeout) {
 		outargflags |= FUSE_REQUEST_TIMEOUT;
@@ -3644,6 +3649,19 @@ int fuse_lowlevel_notify_prune(struct fuse_session *se,
 	return send_notify_iov(se, FUSE_NOTIFY_PRUNE, iov, 3);
 }
 
+int fuse_lowlevel_notify_resend(struct fuse_session *se)
+{
+	struct iovec iov[1];
+
+	if (!se)
+		return -EINVAL;
+
+	if (!(se->conn.capable_ext & FUSE_CAP_HAS_RESEND))
+		return -ENOSYS;
+
+	return send_notify_iov(se, FUSE_NOTIFY_RESEND, iov, 1);
+}
+
 void *fuse_req_userdata(fuse_req_t req)
 {
 	return req->se->userdata;
@@ -3768,6 +3786,11 @@ int fuse_req_interrupted(fuse_req_t req)
 	return interrupted;
 }
 
+int fuse_req_is_resend(fuse_req_t req)
+{
+	return !!(req->unique & FUSE_UNIQUE_RESEND);
+}
+
 bool fuse_req_is_uring(fuse_req_t req)
 {
 	return req->flags.is_uring;
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index b40f141f7eb9..e074cd4a0831 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -228,6 +228,8 @@ FUSE_3.19 {
 		fuse_session_start_teardown_watchdog;
 		fuse_session_stop_teardown_watchdog;
 		fuse_lowlevel_notify_prune;
+		fuse_lowlevel_notify_resend;
+		fuse_req_is_resend;
 		fuse_daemonize_early_start;
 		fuse_daemonize_early_success;
 		fuse_daemonize_early_fail;
-- 
2.43.7


  reply	other threads:[~2026-10-09  8:00 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-09  7:54 [PATCH 0/2] libfuse: add support for FUSE_NOTIFY_RESEND Baokun Li
2026-10-09  7:54 ` Baokun Li [this message]
2026-10-09  7:54 ` [PATCH 2/2] test: exercise FUSE_NOTIFY_RESEND Baokun Li
2026-10-09  8:19   ` Bernd Schubert
2026-10-09  9:31     ` Baokun Li
2026-10-09 13:51       ` Luis Henriques
2026-10-10  2:33         ` Baokun Li
2026-10-13  8:32           ` Luis Henriques

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261009075417.2521879-2-libaokun@linux.alibaba.com \
    --to=libaokun@linux.alibaba.com \
    --cc=bernd@bsbernd.com \
    --cc=fuse-devel@lists.linux.dev \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.