Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 24ab59f

Browse files
drosen-googlegregkh
authored andcommitted
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: Daniel Rosenberg <[email protected]> Signed-off-by: Alessio Balsini <[email protected]>
1 parent 854f380 commit 24ab59f

File tree

4 files changed

+48
-0
lines changed

4 files changed

+48
-0
lines changed

fs/fuse/dev.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/sched/signal.h>
1515
#include <linux/uio.h>
1616
#include <linux/miscdevice.h>
17+
#include <linux/namei.h>
1718
#include <linux/pagemap.h>
1819
#include <linux/file.h>
1920
#include <linux/slab.h>
@@ -1899,6 +1900,12 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
18991900
err = copy_out_args(cs, req->args, nbytes);
19001901
fuse_copy_finish(cs);
19011902

1903+
if (!err && req->in.h.opcode == FUSE_CANONICAL_PATH) {
1904+
char *path = (char *)req->args->out_args[0].value;
1905+
path[req->args->out_args[0].size - 1] = 0;
1906+
req->out.h.error = kern_path(path, 0, req->args->canonical_path);
1907+
}
1908+
19021909
spin_lock(&fpq->lock);
19031910
clear_bit(FR_LOCKED, &req->flags);
19041911
if (!fpq->connected)

fs/fuse/dir.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,13 +298,50 @@ static int fuse_dentry_delete(const struct dentry *dentry)
298298
return time_before64(fuse_dentry_time(dentry), get_jiffies_64());
299299
}
300300

301+
/*
302+
* Get the canonical path. Since we must translate to a path, this must be done
303+
* in the context of the userspace daemon, however, the userspace daemon cannot
304+
* look up paths on its own. Instead, we handle the lookup as a special case
305+
* inside of the write request.
306+
*/
307+
static void fuse_dentry_canonical_path(const struct path *path, struct path *canonical_path) {
308+
struct inode *inode = d_inode(path->dentry);
309+
struct fuse_conn *fc = get_fuse_conn(inode);
310+
FUSE_ARGS(args);
311+
char *path_name;
312+
int err;
313+
314+
path_name = (char*)__get_free_page(GFP_KERNEL);
315+
if (!path_name)
316+
goto default_path;
317+
318+
args.opcode = FUSE_CANONICAL_PATH;
319+
args.nodeid = get_node_id(inode);
320+
args.in_numargs = 0;
321+
args.out_numargs = 1;
322+
args.out_args[0].size = PATH_MAX;
323+
args.out_args[0].value = path_name;
324+
args.canonical_path = canonical_path;
325+
args.out_argvar = 1;
326+
327+
err = fuse_simple_request(fc, &args);
328+
free_page((unsigned long)path_name);
329+
if (err > 0)
330+
return;
331+
default_path:
332+
canonical_path->dentry = path->dentry;
333+
canonical_path->mnt = path->mnt;
334+
path_get(canonical_path);
335+
}
336+
301337
const struct dentry_operations fuse_dentry_operations = {
302338
.d_revalidate = fuse_dentry_revalidate,
303339
.d_delete = fuse_dentry_delete,
304340
#if BITS_PER_LONG < 64
305341
.d_init = fuse_dentry_init,
306342
.d_release = fuse_dentry_release,
307343
#endif
344+
.d_canonical_path = fuse_dentry_canonical_path,
308345
};
309346

310347
const struct dentry_operations fuse_root_dentry_operations = {

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ struct fuse_args {
253253
struct fuse_in_arg in_args[3];
254254
struct fuse_arg out_args[2];
255255
void (*end)(struct fuse_conn *fc, struct fuse_args *args, int error);
256+
257+
/* Path used for completing d_canonical_path */
258+
struct path *canonical_path;
256259
};
257260

258261
struct fuse_args_pages {

include/uapi/linux/fuse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ enum fuse_opcode {
465465
FUSE_COPY_FILE_RANGE = 47,
466466
FUSE_SETUPMAPPING = 48,
467467
FUSE_REMOVEMAPPING = 49,
468+
FUSE_CANONICAL_PATH = 2016,
468469

469470
/* CUSE specific operations */
470471
CUSE_INIT = 4096,

0 commit comments

Comments
 (0)