aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Rosenberg <drosen@google.com>2016-02-11 16:44:15 -0800
committerMattias Nissler <mnissler@google.com>2016-07-20 16:18:27 +0200
commit45499ab41f7acf599a25f034a12c59f36219e0ab (patch)
tree841dbe4c7a93af67abd3f8125cdac4aa6cac894d
parent49f813ca0f7f33748ccea729f1f1f42fa04b417b (diff)
downloadv4.4-45499ab41f7acf599a25f034a12c59f36219e0ab.tar.gz
ANDROID: vfs: add d_canonical_path for stacked filesystem support
Inotify does not currently know when a filesystem is acting as a wrapper around another fs. This means that inotify watchers will miss any modifications to the base file, as well as any made in a separate stacked fs that points to the same file. d_canonical_path solves this problem by allowing the fs to map a dentry to a path in the lower fs. Inotify can use it to find the appropriate place to watch to be informed of all changes to a file. Includes subsequent work and fixes: Daniel Rosenberg <drosen@google.com>: inotify: Fix erroneous update of bit count Daniel Rosenberg <drosen@google.com>: inotify: Fix erroneous update of bit count Signed-off-by: Daniel Rosenberg <drosen@google.com> Bug: 23904372 Patchset: fs-dentry-canonical-path Signed-off-by: Mattias Nissler <mnissler@google.com> Change-Id: I3ed224cdcf589ac3b46fafd3d90b9775bf68f3cd
-rw-r--r--fs/notify/inotify/inotify_user.c15
-rw-r--r--include/linux/dcache.h1
2 files changed, 14 insertions, 2 deletions
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index b8d08d0d0a4d..e2893f17dde2 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -702,6 +702,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
struct fsnotify_group *group;
struct inode *inode;
struct path path;
+ struct path alteredpath;
+ struct path *canonical_path = &path;
struct fd f;
int ret;
unsigned flags = 0;
@@ -741,13 +743,22 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
if (ret)
goto fput_and_out;
+ /* support stacked filesystems */
+ if(path.dentry && path.dentry->d_op) {
+ if (path.dentry->d_op->d_canonical_path) {
+ path.dentry->d_op->d_canonical_path(&path, &alteredpath);
+ canonical_path = &alteredpath;
+ path_put(&path);
+ }
+ }
+
/* inode held in place by reference to path; group by fget on fd */
- inode = path.dentry->d_inode;
+ inode = canonical_path->dentry->d_inode;
group = f.file->private_data;
/* create/update an inode mark */
ret = inotify_update_watch(group, inode, mask);
- path_put(&path);
+ path_put(canonical_path);
fput_and_out:
fdput(f);
return ret;
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index f513dd855cb2..da48880a76c6 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -162,6 +162,7 @@ struct dentry_operations {
int (*d_manage)(struct dentry *, bool);
struct inode *(*d_select_inode)(struct dentry *, unsigned);
struct dentry *(*d_real)(struct dentry *, struct inode *);
+ void (*d_canonical_path)(const struct path *, struct path *);
} ____cacheline_aligned;
/*