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

Commit 24ab59f6 authored by Daniel Rosenberg's avatar Daniel Rosenberg Committed by Greg Kroah-Hartman
Browse files

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.

Bug: 23904372
Bug: 171780975
Test: inotify on cuttlefish
Change-Id: Iabdca0bbedfbff59e9c820c58636a68ef9683d9f
Signed-off-by: default avatarDaniel Rosenberg <drosen@google.com>
Signed-off-by: default avatarAlessio Balsini <balsini@google.com>
parent 854f3806
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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>
@@ -1899,6 +1900,12 @@ 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)
+37 −0
Original line number Diff line number Diff line
@@ -298,6 +298,42 @@ static int fuse_dentry_delete(const struct dentry *dentry)
	return time_before64(fuse_dentry_time(dentry), get_jiffies_64());
}

/*
 * 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);
	FUSE_ARGS(args);
	char *path_name;
	int err;

	path_name = (char*)__get_free_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(fc, &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,
@@ -305,6 +341,7 @@ const struct dentry_operations fuse_dentry_operations = {
	.d_init		= fuse_dentry_init,
	.d_release	= fuse_dentry_release,
#endif
	.d_canonical_path = fuse_dentry_canonical_path,
};

const struct dentry_operations fuse_root_dentry_operations = {
+3 −0
Original line number Diff line number Diff line
@@ -253,6 +253,9 @@ struct fuse_args {
	struct fuse_in_arg in_args[3];
	struct fuse_arg out_args[2];
	void (*end)(struct fuse_conn *fc, struct fuse_args *args, int error);

	/* Path used for completing d_canonical_path */
	struct path *canonical_path;
};

struct fuse_args_pages {
+1 −0
Original line number Diff line number Diff line
@@ -465,6 +465,7 @@ enum fuse_opcode {
	FUSE_COPY_FILE_RANGE	= 47,
	FUSE_SETUPMAPPING	= 48,
	FUSE_REMOVEMAPPING	= 49,
	FUSE_CANONICAL_PATH	= 2016,

	/* CUSE specific operations */
	CUSE_INIT		= 4096,