mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
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: Pixel 4.19 Change-Id: Iabdca0bbedfbff59e9c820c58636a68ef9683d9f Signed-off-by: Daniel Rosenberg <drosen@google.com> Signed-off-by: Alessio Balsini <balsini@google.com>
This commit is contained in:
committed by
Alessio Balsini
parent
54b41388f5
commit
fa199896a3
@@ -14,6 +14,7 @@
|
|||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@@ -573,6 +574,7 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
|
|||||||
req->out.numargs = args->out.numargs;
|
req->out.numargs = args->out.numargs;
|
||||||
memcpy(req->out.args, args->out.args,
|
memcpy(req->out.args, args->out.args,
|
||||||
args->out.numargs * sizeof(struct fuse_arg));
|
args->out.numargs * sizeof(struct fuse_arg));
|
||||||
|
req->out.canonical_path = args->out.canonical_path;
|
||||||
fuse_request_send(fc, req);
|
fuse_request_send(fc, req);
|
||||||
ret = req->out.h.error;
|
ret = req->out.h.error;
|
||||||
if (!ret && args->out.argvar) {
|
if (!ret && args->out.argvar) {
|
||||||
@@ -1932,6 +1934,13 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
|
|||||||
err = copy_out_args(cs, &req->out, nbytes);
|
err = copy_out_args(cs, &req->out, nbytes);
|
||||||
fuse_copy_finish(cs);
|
fuse_copy_finish(cs);
|
||||||
|
|
||||||
|
if (!err && req->in.h.opcode == FUSE_CANONICAL_PATH) {
|
||||||
|
char *path = (char *)req->out.args[0].value;
|
||||||
|
|
||||||
|
path[req->out.args[0].size - 1] = 0;
|
||||||
|
req->out.h.error = kern_path(path, 0, req->out.canonical_path);
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&fpq->lock);
|
spin_lock(&fpq->lock);
|
||||||
clear_bit(FR_LOCKED, &req->flags);
|
clear_bit(FR_LOCKED, &req->flags);
|
||||||
if (!fpq->connected)
|
if (!fpq->connected)
|
||||||
|
|||||||
@@ -281,10 +281,49 @@ static void fuse_dentry_release(struct dentry *dentry)
|
|||||||
kfree_rcu(fd, rcu);
|
kfree_rcu(fd, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.in.h.opcode = FUSE_CANONICAL_PATH;
|
||||||
|
args.in.h.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.out.argvar = 1;
|
||||||
|
args.out.canonical_path = canonical_path;
|
||||||
|
|
||||||
|
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 = {
|
const struct dentry_operations fuse_dentry_operations = {
|
||||||
.d_revalidate = fuse_dentry_revalidate,
|
.d_revalidate = fuse_dentry_revalidate,
|
||||||
.d_init = fuse_dentry_init,
|
.d_init = fuse_dentry_init,
|
||||||
.d_release = fuse_dentry_release,
|
.d_release = fuse_dentry_release,
|
||||||
|
.d_canonical_path = fuse_dentry_canonical_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct dentry_operations fuse_root_dentry_operations = {
|
const struct dentry_operations fuse_root_dentry_operations = {
|
||||||
|
|||||||
@@ -213,6 +213,9 @@ struct fuse_out {
|
|||||||
|
|
||||||
/** Array of arguments */
|
/** Array of arguments */
|
||||||
struct fuse_arg args[2];
|
struct fuse_arg args[2];
|
||||||
|
|
||||||
|
/* Path used for completing d_canonical_path */
|
||||||
|
struct path *canonical_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** FUSE page descriptor */
|
/** FUSE page descriptor */
|
||||||
@@ -235,6 +238,9 @@ struct fuse_args {
|
|||||||
unsigned argvar:1;
|
unsigned argvar:1;
|
||||||
unsigned numargs;
|
unsigned numargs;
|
||||||
struct fuse_arg args[2];
|
struct fuse_arg args[2];
|
||||||
|
|
||||||
|
/* Path used for completing d_canonical_path */
|
||||||
|
struct path *canonical_path;
|
||||||
} out;
|
} out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -383,6 +383,7 @@ enum fuse_opcode {
|
|||||||
FUSE_READDIRPLUS = 44,
|
FUSE_READDIRPLUS = 44,
|
||||||
FUSE_RENAME2 = 45,
|
FUSE_RENAME2 = 45,
|
||||||
FUSE_LSEEK = 46,
|
FUSE_LSEEK = 46,
|
||||||
|
FUSE_CANONICAL_PATH= 2016,
|
||||||
|
|
||||||
/* CUSE specific operations */
|
/* CUSE specific operations */
|
||||||
CUSE_INIT = 4096,
|
CUSE_INIT = 4096,
|
||||||
|
|||||||
Reference in New Issue
Block a user