Extend initialization flags and FUSE_PASSTHROUGH to 64 bits

With the latest kernel version the FUSE_PASSTHROUGH flag now conflicts
with another flag.
As the flag bits in the original "flags" field are all covered, the
developer allocated another "flags2" field in the userspace <->
kernelspace communication.
While FUSE_PASSTHROUGH is kept as the last bit of either field, it's
userspace that needs to decide if it should be the last bit of "flags"
or "flags2" based on the FUSE version.

Test: launch_cvd (both android-mainline and android13-5.10) \
  `logcat FuseDaemon:V \*:S` shows no FUSE passthrough errors
Bug: 215310351
Signed-off-by: Alessio Balsini <balsini@google.com>
Change-Id: Ib35e5e162b57a49fde1c36154adafb51172fc2bd
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 3f836d7..d6fa3e2 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -409,7 +409,7 @@
  *
  * This feature is disabled by default.
  */
-#define FUSE_CAP_PASSTHROUGH            (1 << 31)
+#define FUSE_CAP_PASSTHROUGH            (1LL << 63)
 
 /**
  * Ioctl flags
@@ -473,7 +473,7 @@
 	/**
 	 * Capability flags that the kernel supports (read-only)
 	 */
-	unsigned capable;
+	uint64_t capable;
 
 	/**
 	 * Capability flags that the filesystem wants to enable.
@@ -481,7 +481,7 @@
 	 * libfuse attempts to initialize this field with
 	 * reasonable default values before calling the init() handler.
 	 */
-	unsigned want;
+	uint64_t want;
 
 	/**
 	 * Maximum number of pending "background" requests. A
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index aee22b4..2ede5f3 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -2013,6 +2013,7 @@
 	struct fuse_session *se = req->se;
 	size_t bufsize = se->bufsize;
 	size_t outargsize = sizeof(outarg);
+	int extended_flags;
 
 	(void) nodeid;
 	if (se->debug) {
@@ -2032,6 +2033,10 @@
 	outarg.major = FUSE_KERNEL_VERSION;
 	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
 
+	extended_flags = arg->major > 7 || (arg->major == 7 && arg->minor >= 36);
+	fuse_log(FUSE_LOG_DEBUG, "fuse: protocol version: %u.%u, extended flags: %d\n",
+		arg->major, arg->minor, extended_flags);
+
 	if (arg->major < 7) {
 		fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
 			arg->major, arg->minor);
@@ -2092,8 +2097,13 @@
 				bufsize = max_bufsize;
 			}
 		}
-		if (arg->flags & FUSE_PASSTHROUGH)
-			se->conn.capable |= FUSE_PASSTHROUGH;
+		if (extended_flags) {
+			if (arg->flags2 & (1 << 31))
+				se->conn.capable |= FUSE_CAP_PASSTHROUGH;
+		} else {
+			if (arg->flags & (1 << 31))
+				se->conn.capable |= FUSE_CAP_PASSTHROUGH;
+		}
 	} else {
 		se->conn.max_readahead = 0;
 	}
@@ -2206,8 +2216,12 @@
 		outarg.flags |= FUSE_WRITEBACK_CACHE;
 	if (se->conn.want & FUSE_CAP_POSIX_ACL)
 		outarg.flags |= FUSE_POSIX_ACL;
-	if (se->conn.want & FUSE_CAP_PASSTHROUGH)
-		outarg.flags |= FUSE_PASSTHROUGH;
+	if (se->conn.want & FUSE_CAP_PASSTHROUGH) {
+		if (extended_flags)
+			outarg.flags2 |= (1 << 31);
+		else
+			outarg.flags |= (1 << 31);
+	}
 	if (se->conn.want & FUSE_CAP_CACHE_SYMLINKS)
 		outarg.flags |= FUSE_CACHE_SYMLINKS;
 	if (se->conn.want & FUSE_CAP_EXPLICIT_INVAL_DATA)