Snap for 7570015 from 7fdddf2190c5c3cc7c7d4ffd103199b4803fa028 to mainline-sdkext-release

Change-Id: Ia449a31f0fbcbfc8a31023ce9ba75d309b699699
diff --git a/Android.bp b/Android.bp
index 8bc193c..e43cdf7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,44 @@
+package {
+    default_applicable_licenses: ["external_libfuse_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+    name: "external_libfuse_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-GPL",
+        "SPDX-license-identifier-GPL-2.0",
+        "SPDX-license-identifier-LGPL",
+        "SPDX-license-identifier-LGPL-2.0",
+        "SPDX-license-identifier-LGPL-2.1",
+        "SPDX-license-identifier-LGPL-3.0",
+    ],
+    license_text: [
+        "LGPL2.txt",
+        "LICENSE",
+    ],
+}
+
 cc_defaults {
     name: "libfuse_default_flags",
     local_include_dirs: ["include/", "lib/"],
@@ -17,6 +58,7 @@
 
     clang: true,
     sdk_version: "current",
+    min_sdk_version: "30",
 
     ldflags: [
     ],
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..5ee6098
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+balsini@google.com
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 2d686b2..7ac28d7 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -92,6 +92,11 @@
 	 * same file handle. */
 	uint64_t fh;
 
+	/** Passthrough file handle id.  May be filled in by filesystem in
+	 * create and open.  It is used to create a passthrough connection
+	 * between FUSE file and lower file system file. */
+	uint32_t passthrough_fh;
+
 	/** Lock owner id.  Available in locking operations and flush */
 	uint64_t lock_owner;
 
@@ -359,6 +364,18 @@
 #define FUSE_CAP_NO_OPENDIR_SUPPORT    (1 << 24)
 
 /**
+ * Indicates support for passthrough mode access for read/write operations.
+ *
+ * If this flag is set in the `capable` field of the `fuse_conn_info`
+ * structure, then the FUSE kernel module supports redirecting read/write
+ * operations to the lower file system instead of letting them to be handled
+ * by the FUSE daemon.
+ *
+ * This feature is disabled by default.
+ */
+#define FUSE_CAP_PASSTHROUGH            (1 << 31)
+
+/**
  * Ioctl flags
  *
  * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h
index 8a45f42..bd8794e 100644
--- a/include/fuse_kernel.h
+++ b/include/fuse_kernel.h
@@ -301,6 +301,7 @@
 #define FUSE_CACHE_SYMLINKS	(1 << 23)
 #define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
 #define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
+#define FUSE_PASSTHROUGH	(1 << 31)
 
 /**
  * CUSE INIT request/reply flags
@@ -547,7 +548,7 @@
 struct fuse_open_out {
 	uint64_t	fh;
 	uint32_t	open_flags;
-	uint32_t	padding;
+	uint32_t	passthrough_fh;
 };
 
 struct fuse_release_in {
@@ -574,6 +575,13 @@
 	uint32_t	padding;
 };
 
+struct fuse_passthrough_out_v0 {
+	uint32_t	fd;
+	/* For future implementation */
+	uint32_t	len;
+	void *		vec;
+};
+
 #define FUSE_COMPAT_WRITE_IN_SIZE 24
 
 struct fuse_write_in {
@@ -825,7 +833,10 @@
 };
 
 /* Device ioctls: */
-#define FUSE_DEV_IOC_CLONE	_IOR(229, 0, uint32_t)
+#define FUSE_DEV_IOC_CLONE	      _IOR(229, 0, uint32_t)
+#define FUSE_DEV_IOC_PASSTHROUGH_OPEN_V0 _IOW(229, 1, struct fuse_passthrough_out_v0)
+#define FUSE_DEV_IOC_PASSTHROUGH_OPEN_V1 _IOW(229, 127, struct fuse_passthrough_out_v0)
+#define FUSE_DEV_IOC_PASSTHROUGH_OPEN_V2 _IOW(229, 126, uint32_t)
 
 struct fuse_lseek_in {
 	uint64_t	fh;
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index e81c282..e916112 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -1349,6 +1349,8 @@
  */
 int fuse_reply_readlink(fuse_req_t req, const char *link);
 
+int fuse_passthrough_enable(fuse_req_t req, unsigned int fd);
+
 /**
  * Reply with the canonical path for inotify
  *
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index fc76b7c..a4a4df0 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -27,6 +27,7 @@
 #include <errno.h>
 #include <assert.h>
 #include <sys/file.h>
+#include <sys/ioctl.h>
 
 #ifndef F_LINUX_SPECIFIC_BASE
 #define F_LINUX_SPECIFIC_BASE       1024
@@ -388,6 +389,7 @@
 		      const struct fuse_file_info *f)
 {
 	arg->fh = f->fh;
+	arg->passthrough_fh = f->passthrough_fh;
 	if (f->direct_io)
 		arg->open_flags |= FOPEN_DIRECT_IO;
 	if (f->keep_cache)
@@ -457,6 +459,77 @@
 	return send_reply_ok(req, path, strlen(path) + 1);
 }
 
+enum {
+	FUSE_PASSTHROUGH_API_UNAVAILABLE,
+	FUSE_PASSTHROUGH_API_V0,
+	FUSE_PASSTHROUGH_API_V1,
+	FUSE_PASSTHROUGH_API_V2,
+	FUSE_PASSTHROUGH_API_STABLE,
+};
+
+/*
+ * Requests the FUSE passthrough feature to be enabled on a specific file
+ * through the passed fd.
+ * This function returns an identifier that must be used as passthrough_fh
+ * when the open/create_open request reply is sent back to /dev/fuse.
+ * As for the current FUSE passthrough implementation, passthrough_fh values
+ * are only valid if > 0, so in case the FUSE passthrough open ioctl returns
+ * a value <= 0, this must be considered an error and is returned as-is by
+ * this function.
+ */
+int fuse_passthrough_enable(fuse_req_t req, unsigned int fd) {
+	static sig_atomic_t passthrough_version = FUSE_PASSTHROUGH_API_STABLE;
+	int ret = 0; /* values <= 0 represent errors in FUSE passthrough */
+
+	/*
+	 * The interface of FUSE passthrough is still unstable in the kernel,
+	 * so the following solution is to search for the most updated API
+	 * version and, if not found, fall back to an older one.
+	 * This happens when ioctl() returns -1 and errno is set to ENOTTY,
+	 * an error code that corresponds to the lack of a specific ioctl.
+	 */
+	switch (passthrough_version) {
+	case FUSE_PASSTHROUGH_API_STABLE:
+		/* There is not a stable API yet */
+		passthrough_version = FUSE_PASSTHROUGH_API_V2;
+	case FUSE_PASSTHROUGH_API_V2: {
+		ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V2, &fd);
+		if (ret == -1 && errno == ENOTTY)
+			passthrough_version = FUSE_PASSTHROUGH_API_V1;
+		else
+			break;
+	}
+	case FUSE_PASSTHROUGH_API_V1: {
+		struct fuse_passthrough_out_v0 out = {};
+		out.fd = fd;
+
+		ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V1, &out);
+		if (ret == -1 && errno == ENOTTY)
+			passthrough_version = FUSE_PASSTHROUGH_API_V0;
+		else
+			break;
+	}
+	case FUSE_PASSTHROUGH_API_V0: {
+		struct fuse_passthrough_out_v0 out = {};
+		out.fd = fd;
+
+		ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V0, &out);
+		if (ret == -1 && errno == ENOTTY)
+			passthrough_version = FUSE_PASSTHROUGH_API_UNAVAILABLE;
+		else
+			break;
+	}
+	default:
+		fuse_log(FUSE_LOG_ERR, "fuse: passthrough_enable no valid API\n");
+		return -ENOTTY;
+	}
+
+	if (ret <= 0)
+		fuse_log(FUSE_LOG_ERR, "fuse: passthrough_enable: %s\n", strerror(errno));
+
+	return ret;
+}
+
 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
 {
 	struct fuse_open_out arg;
@@ -1990,6 +2063,8 @@
 				bufsize = max_bufsize;
 			}
 		}
+		if (arg->flags & FUSE_PASSTHROUGH)
+			se->conn.capable |= FUSE_PASSTHROUGH;
 	} else {
 		se->conn.max_readahead = 0;
 	}
@@ -2102,6 +2177,8 @@
 		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;
 	outarg.max_readahead = se->conn.max_readahead;
 	outarg.max_write = se->conn.max_write;
 	if (se->conn.proto_minor >= 13) {
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 4c075a3..b01699a 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -163,6 +163,7 @@
 	global:
 		fuse_set_log_func;
 		fuse_log;
+		fuse_passthrough_enable;
 		fuse_reply_canonical_path;
 } FUSE_3.3;