Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e4aa2a5 authored by Daniel Rosenberg's avatar Daniel Rosenberg Committed by Amit Pundir
Browse files

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.

bug: 23904372
Change-Id: Iabdca0bbedfbff59e9c820c58636a68ef9683d9f
Signed-off-by: default avatarDaniel Rosenberg <drosen@google.com>
parent 7a9d2174
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/poll.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>
@@ -1878,6 +1879,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);
+45 −0
Original line number Diff line number Diff line
@@ -262,6 +262,50 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
	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,6 +328,7 @@ 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,
};

int fuse_valid_type(int m)
+3 −0
Original line number Diff line number Diff line
@@ -368,6 +368,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;

+1 −0
Original line number Diff line number Diff line
@@ -375,6 +375,7 @@ enum fuse_opcode {
	FUSE_READDIRPLUS   = 44,
	FUSE_RENAME2       = 45,
	FUSE_LSEEK         = 46,
	FUSE_CANONICAL_PATH= 2016,

	/* CUSE specific operations */
	CUSE_INIT          = 4096,