vfs: add d_canonical_path for stacked filesystem support
authorDaniel Rosenberg <drosen@google.com>
Fri, 12 Feb 2016 00:44:15 +0000 (16:44 -0800)
committerDaniel Rosenberg <drosen@google.com>
Wed, 23 Mar 2016 03:27:13 +0000 (20:27 -0700)
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.

Change-Id: I09563baffad1711a045e45c1bd0bd8713c2cc0b6
Signed-off-by: Daniel Rosenberg <drosen@google.com>
fs/notify/inotify/inotify_user.c
include/linux/dcache.h

index b8d08d0d0a4dbe061b9336dd7f861d32e13c8618..9a0cd02cf3dc65e64cf60ab950b679a940c2550e 100644 (file)
@@ -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.dentry, &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;
@@ -814,7 +825,7 @@ static int __init inotify_user_setup(void)
        BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
        BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
 
-       BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
+       BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
 
        inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
 
index d67ae119cf4eb9d3143d5019108f1d7fbf252b88..ebad56e31a8c49963e35ea5cff90cab6d01d8b60 100644 (file)
@@ -161,6 +161,7 @@ struct dentry_operations {
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
        struct inode *(*d_select_inode)(struct dentry *, unsigned);
+       void (*d_canonical_path)(const struct dentry *, struct path *);
 } ____cacheline_aligned;
 
 /*