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.
Rolled in fix from
cad4f67e5b5b("ANDROID: fuse: Allocate zeroed memory for canonical path")
Note: I've changed the Change-Id since this was previously present, but
disappeared at some point.
Bug: 23904372
Bug: 171780975
Test: FileObserverTest and FileObserverTestLegacyPath on cuttlefish
Change-Id: I3d752756adb058ba32b47ec61887a2df98e862db
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Alessio Balsini <balsini@google.com>
This commit is contained in:
@@ -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>
|
||||
@@ -2040,6 +2041,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)
|
||||
|
||||
@@ -327,6 +327,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,
|
||||
@@ -335,6 +374,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 = {
|
||||
|
||||
@@ -312,6 +312,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 {
|
||||
|
||||
@@ -638,6 +638,7 @@ enum fuse_opcode {
|
||||
FUSE_SYNCFS = 50,
|
||||
FUSE_TMPFILE = 51,
|
||||
FUSE_STATX = 52,
|
||||
FUSE_CANONICAL_PATH = 2016,
|
||||
|
||||
/* CUSE specific operations */
|
||||
CUSE_INIT = 4096,
|
||||
|
||||
Reference in New Issue
Block a user