blob: fd82e920a75410a2227c460b47b51ae6d9687853 [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Rosenberg <drosen@google.com>
Date: Fri, 22 Apr 2016 00:00:48 -0700
Subject: ANDROID: fuse: Add support for d_canonical_path
Allows FUSE to report to inotify that it is acting as a layered filesystem.
The userspace component returns a string representing the location of the
underlying file. If the string cannot be resolved into a path, the top
level path is returned instead.
[CPNOTE: 20/07/21] Lee: Pinged Alessio for an update via the bug
Bug: 23904372
Bug: 171780975
Test: FileObserverTest and FileObserverTestLegacyPath on cuttlefish
Change-Id: Iabdca0bbedfbff59e9c820c58636a68ef9683d9f
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Alessio Balsini <balsini@google.com>
---
fs/fuse/dev.c | 10 +++++++++-
fs/fuse/dir.c | 40 +++++++++++++++++++++++++++++++++++++++
fs/fuse/fuse_i.h | 6 ++++--
fs/fuse/passthrough.c | 9 ++-------
include/uapi/linux/fuse.h | 14 ++++----------
5 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -14,6 +14,7 @@
#include <linux/sched/signal.h>
#include <linux/uio.h>
#include <linux/miscdevice.h>
+#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/file.h>
#include <linux/slab.h>
@@ -1920,6 +1921,14 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
err = copy_out_args(cs, req->args, nbytes);
fuse_copy_finish(cs);
+ if (!err && req->in.h.opcode == FUSE_CANONICAL_PATH) {
+ char *path = (char *)req->args->out_args[0].value;
+
+ path[req->args->out_args[0].size - 1] = 0;
+ req->out.h.error =
+ kern_path(path, 0, req->args->canonical_path);
+ }
+
spin_lock(&fpq->lock);
clear_bit(FR_LOCKED, &req->flags);
if (!fpq->connected)
@@ -2252,7 +2261,6 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
int res;
int oldfd;
struct fuse_dev *fud = NULL;
- struct fuse_passthrough_out pto;
switch (cmd) {
case FUSE_DEV_IOC_CLONE:
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -328,6 +328,45 @@ static struct vfsmount *fuse_dentry_automount(struct path *path)
return mnt;
}
+/*
+ * Get the canonical path. Since we must translate to a path, this must be done
+ * in the context of the userspace daemon, however, the userspace daemon cannot
+ * look up paths on its own. Instead, we handle the lookup as a special case
+ * inside of the write request.
+ */
+static void fuse_dentry_canonical_path(const struct path *path,
+ struct path *canonical_path)
+{
+ struct inode *inode = d_inode(path->dentry);
+ //struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_mount *fm = get_fuse_mount_super(path->mnt->mnt_sb);
+ FUSE_ARGS(args);
+ char *path_name;
+ int err;
+
+ path_name = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!path_name)
+ goto default_path;
+
+ args.opcode = FUSE_CANONICAL_PATH;
+ args.nodeid = get_node_id(inode);
+ args.in_numargs = 0;
+ args.out_numargs = 1;
+ args.out_args[0].size = PATH_MAX;
+ args.out_args[0].value = path_name;
+ args.canonical_path = canonical_path;
+ args.out_argvar = 1;
+
+ err = fuse_simple_request(fm, &args);
+ free_page((unsigned long)path_name);
+ if (err > 0)
+ return;
+default_path:
+ canonical_path->dentry = path->dentry;
+ canonical_path->mnt = path->mnt;
+ path_get(canonical_path);
+}
+
const struct dentry_operations fuse_dentry_operations = {
.d_revalidate = fuse_dentry_revalidate,
.d_delete = fuse_dentry_delete,
@@ -336,6 +375,7 @@ const struct dentry_operations fuse_dentry_operations = {
.d_release = fuse_dentry_release,
#endif
.d_automount = fuse_dentry_automount,
+ .d_canonical_path = fuse_dentry_canonical_path,
};
const struct dentry_operations fuse_root_dentry_operations = {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -277,6 +277,9 @@ struct fuse_args {
struct fuse_in_arg in_args[3];
struct fuse_arg out_args[2];
void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);
+
+ /* Path used for completing d_canonical_path */
+ struct path *canonical_path;
};
struct fuse_args_pages {
@@ -1314,8 +1317,7 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff,
unsigned int open_flags, fl_owner_t id, bool isdir);
/* passthrough.c */
-int fuse_passthrough_open(struct fuse_dev *fud,
- struct fuse_passthrough_out *pto);
+int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd);
int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff,
struct fuse_open_out *openarg);
void fuse_passthrough_release(struct fuse_passthrough *passthrough);
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -180,8 +180,7 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
return ret;
}
-int fuse_passthrough_open(struct fuse_dev *fud,
- struct fuse_passthrough_out *pto)
+int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd)
{
int res;
struct file *passthrough_filp;
@@ -193,11 +192,7 @@ int fuse_passthrough_open(struct fuse_dev *fud,
if (!fc->passthrough)
return -EPERM;
- /* This field is reserved for future implementation */
- if (pto->len != 0)
- return -EINVAL;
-
- passthrough_filp = fget(pto->fd);
+ passthrough_filp = fget(lower_fd);
if (!passthrough_filp) {
pr_err("FUSE: invalid file descriptor for passthrough.\n");
return -EBADF;
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -519,6 +519,7 @@ enum fuse_opcode {
FUSE_SETUPMAPPING = 48,
FUSE_REMOVEMAPPING = 49,
FUSE_SYNCFS = 50,
+ FUSE_CANONICAL_PATH = 2016,
/* CUSE specific operations */
CUSE_INIT = 4096,
@@ -852,14 +853,6 @@ struct fuse_in_header {
uint32_t padding;
};
-/* fuse_passthrough_out for passthrough V1 */
-struct fuse_passthrough_out {
- uint32_t fd;
- /* For future implementation */
- uint32_t len;
- void *vec;
-};
-
struct fuse_out_header {
uint32_t len;
int32_t error;
@@ -937,8 +930,9 @@ struct fuse_notify_retrieve_in {
/* Device ioctls: */
#define FUSE_DEV_IOC_MAGIC 229
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
-/* 127 is reserved for the V1 interface implementation in Android */
-#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 127, struct fuse_passthrough_out)
+/* 127 is reserved for the V1 interface implementation in Android (deprecated) */
+/* 126 is reserved for the V2 interface implementation in Android */
+#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 126, __u32)
struct fuse_lseek_in {
uint64_t fh;