mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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: Daniel Rosenberg <drosen@google.com>
This commit is contained in:
parent
10db9d59bf
commit
f5fea6a938
4 changed files with 54 additions and 0 deletions
|
@ -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>
|
||||
|
@ -1779,6 +1780,10 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
|
|||
spin_unlock(&fc->lock);
|
||||
|
||||
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(&fc->lock);
|
||||
|
|
|
@ -222,6 +222,50 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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;
|
||||
|
@ -229,6 +273,7 @@ static int invalid_nodeid(u64 nodeid)
|
|||
|
||||
const struct dentry_operations fuse_dentry_operations = {
|
||||
.d_revalidate = fuse_dentry_revalidate,
|
||||
.d_canonical_path = fuse_dentry_canonical_path,
|
||||
};
|
||||
|
||||
int fuse_valid_type(int m)
|
||||
|
|
|
@ -302,6 +302,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;
|
||||
|
||||
/** Link on fi->writepages */
|
||||
struct list_head writepages_entry;
|
||||
|
||||
|
|
|
@ -278,6 +278,7 @@ enum fuse_opcode {
|
|||
FUSE_POLL = 40,
|
||||
FUSE_NOTIFY_REPLY = 41,
|
||||
FUSE_BATCH_FORGET = 42,
|
||||
FUSE_CANONICAL_PATH= 2016,
|
||||
|
||||
/* CUSE specific operations */
|
||||
CUSE_INIT = 4096,
|
||||
|
|
Loading…
Reference in a new issue