ANDROID: fuse: Add support for d_canonical_path
authorDaniel Rosenberg <drosen@google.com>
Fri, 22 Apr 2016 07:00:48 +0000 (00:00 -0700)
committerDaniel Rosenberg <drosen@google.com>
Tue, 30 Jan 2018 03:39:58 +0000 (19:39 -0800)
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.

bug: 23904372
Change-Id: Iabdca0bbedfbff59e9c820c58636a68ef9683d9f
Signed-off-by: Daniel Rosenberg <drosen@google.com>
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
include/uapi/linux/fuse.h

index 9b35551d9986254be207405388eda97282eb0dc8..032485010a05ac672c13ac15340e1d0c21a38b98 100644 (file)
@@ -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>
@@ -1890,6 +1891,10 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
                cs->move_pages = 0;
 
        err = copy_out_args(cs, &req->out, nbytes);
+       if (req->in.h.opcode == FUSE_CANONICAL_PATH) {
+               req->out.h.error = kern_path((char *)req->out.args[0].value, 0,
+                                                       req->canonical_path);
+       }
        fuse_copy_finish(cs);
 
        spin_lock(&fpq->lock);
index 24967382a7b15271ae0646c3cb5522b3e58c37d0..cebd108dc3ce21ce62fd57dd8dddb9a9a551136c 100644 (file)
@@ -262,6 +262,50 @@ invalid:
        goto out;
 }
 
+/*
+ * 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 = path->dentry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_req *req;
+       int err;
+       char *path_name;
+
+       req = fuse_get_req(fc, 1);
+       err = PTR_ERR(req);
+       if (IS_ERR(req))
+               goto default_path;
+
+       path_name = (char*)__get_free_page(GFP_KERNEL);
+       if (!path_name) {
+               fuse_put_request(fc, req);
+               goto default_path;
+       }
+
+       req->in.h.opcode = FUSE_CANONICAL_PATH;
+       req->in.h.nodeid = get_node_id(inode);
+       req->in.numargs = 0;
+       req->out.numargs = 1;
+       req->out.args[0].size = PATH_MAX;
+       req->out.args[0].value = path_name;
+       req->canonical_path = canonical_path;
+       req->out.argvar = 1;
+       fuse_request_send(fc, req);
+       err = req->out.h.error;
+       fuse_put_request(fc, req);
+       free_page((unsigned long)path_name);
+       if (!err)
+               return;
+default_path:
+       canonical_path->dentry = path->dentry;
+       canonical_path->mnt = path->mnt;
+       path_get(canonical_path);
+}
+
 static int invalid_nodeid(u64 nodeid)
 {
        return !nodeid || nodeid == FUSE_ROOT_ID;
@@ -284,11 +328,13 @@ const struct dentry_operations fuse_dentry_operations = {
        .d_revalidate   = fuse_dentry_revalidate,
        .d_init         = fuse_dentry_init,
        .d_release      = fuse_dentry_release,
+       .d_canonical_path = fuse_dentry_canonical_path,
 };
 
 const struct dentry_operations fuse_root_dentry_operations = {
        .d_init         = fuse_dentry_init,
        .d_release      = fuse_dentry_release,
+       .d_canonical_path = fuse_dentry_canonical_path,
 };
 
 int fuse_valid_type(int m)
index d5773ca67ad2bbc36155a30fafa596dd7e44502a..61581f54a482ba5cda0c2a4f221dd84ac8dd9cf0 100644 (file)
@@ -370,6 +370,9 @@ struct fuse_req {
        /** Inode used in the request or NULL */
        struct inode *inode;
 
+       /** Path used for completing d_canonical_path */
+       struct path *canonical_path;
+
        /** AIO control block */
        struct fuse_io_priv *io;
 
index 4b5001c57f4642d57559607e1398492f78bf998b..d5ac0ebd82c5ed368af439b282ec098fcd29d418 100644 (file)
@@ -376,6 +376,7 @@ enum fuse_opcode {
        FUSE_READDIRPLUS   = 44,
        FUSE_RENAME2       = 45,
        FUSE_LSEEK         = 46,
+       FUSE_CANONICAL_PATH= 2016,
 
        /* CUSE specific operations */
        CUSE_INIT          = 4096,