diff options
| -rw-r--r-- | fs/notify/fsnotify.c | 41 | ||||
| -rw-r--r-- | include/linux/fsnotify.h | 33 | ||||
| -rw-r--r-- | include/linux/fsnotify_backend.h | 4 |
3 files changed, 45 insertions, 33 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index df06f3da166c..e8d3f349b7f2 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
| @@ -108,6 +108,47 @@ void fsnotify_sb_delete(struct super_block *sb) | |||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | /* | 110 | /* |
| 111 | * fsnotify_nameremove - a filename was removed from a directory | ||
| 112 | * | ||
| 113 | * This is mostly called under parent vfs inode lock so name and | ||
| 114 | * dentry->d_parent should be stable. However there are some corner cases where | ||
| 115 | * inode lock is not held. So to be on the safe side and be reselient to future | ||
| 116 | * callers and out of tree users of d_delete(), we do not assume that d_parent | ||
| 117 | * and d_name are stable and we use dget_parent() and | ||
| 118 | * take_dentry_name_snapshot() to grab stable references. | ||
| 119 | */ | ||
| 120 | void fsnotify_nameremove(struct dentry *dentry, int isdir) | ||
| 121 | { | ||
| 122 | struct dentry *parent; | ||
| 123 | struct name_snapshot name; | ||
| 124 | __u32 mask = FS_DELETE; | ||
| 125 | |||
| 126 | /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */ | ||
| 127 | if (IS_ROOT(dentry)) | ||
| 128 | return; | ||
| 129 | |||
| 130 | if (isdir) | ||
| 131 | mask |= FS_ISDIR; | ||
| 132 | |||
| 133 | parent = dget_parent(dentry); | ||
| 134 | /* Avoid unneeded take_dentry_name_snapshot() */ | ||
| 135 | if (!(d_inode(parent)->i_fsnotify_mask & FS_DELETE) && | ||
| 136 | !(dentry->d_sb->s_fsnotify_mask & FS_DELETE)) | ||
| 137 | goto out_dput; | ||
| 138 | |||
| 139 | take_dentry_name_snapshot(&name, dentry); | ||
| 140 | |||
| 141 | fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, | ||
| 142 | name.name, 0); | ||
| 143 | |||
| 144 | release_dentry_name_snapshot(&name); | ||
| 145 | |||
| 146 | out_dput: | ||
| 147 | dput(parent); | ||
| 148 | } | ||
| 149 | EXPORT_SYMBOL(fsnotify_nameremove); | ||
| 150 | |||
| 151 | /* | ||
| 111 | * Given an inode, first check if we care what happens to our children. Inotify | 152 | * Given an inode, first check if we care what happens to our children. Inotify |
| 112 | * and dnotify both tell their parents about events. If we care about any event | 153 | * and dnotify both tell their parents about events. If we care about any event |
| 113 | * on a child we run all of our children and set a dentry flag saying that the | 154 | * on a child we run all of our children and set a dentry flag saying that the |
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 09587e2860b5..e30d6132c633 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h | |||
| @@ -152,39 +152,6 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) | |||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | /* | 154 | /* |
| 155 | * fsnotify_nameremove - a filename was removed from a directory | ||
| 156 | * | ||
| 157 | * This is mostly called under parent vfs inode lock so name and | ||
| 158 | * dentry->d_parent should be stable. However there are some corner cases where | ||
| 159 | * inode lock is not held. So to be on the safe side and be reselient to future | ||
| 160 | * callers and out of tree users of d_delete(), we do not assume that d_parent | ||
| 161 | * and d_name are stable and we use dget_parent() and | ||
| 162 | * take_dentry_name_snapshot() to grab stable references. | ||
| 163 | */ | ||
| 164 | static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) | ||
| 165 | { | ||
| 166 | struct dentry *parent; | ||
| 167 | struct name_snapshot name; | ||
| 168 | __u32 mask = FS_DELETE; | ||
| 169 | |||
| 170 | /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */ | ||
| 171 | if (IS_ROOT(dentry)) | ||
| 172 | return; | ||
| 173 | |||
| 174 | if (isdir) | ||
| 175 | mask |= FS_ISDIR; | ||
| 176 | |||
| 177 | parent = dget_parent(dentry); | ||
| 178 | take_dentry_name_snapshot(&name, dentry); | ||
| 179 | |||
| 180 | fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, | ||
| 181 | name.name, 0); | ||
| 182 | |||
| 183 | release_dentry_name_snapshot(&name); | ||
| 184 | dput(parent); | ||
| 185 | } | ||
| 186 | |||
| 187 | /* | ||
| 188 | * fsnotify_inoderemove - an inode is going away | 155 | * fsnotify_inoderemove - an inode is going away |
| 189 | */ | 156 | */ |
| 190 | static inline void fsnotify_inoderemove(struct inode *inode) | 157 | static inline void fsnotify_inoderemove(struct inode *inode) |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index dfc28fcb4de8..094b38f2d9a1 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
| @@ -355,6 +355,7 @@ extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u | |||
| 355 | extern void __fsnotify_inode_delete(struct inode *inode); | 355 | extern void __fsnotify_inode_delete(struct inode *inode); |
| 356 | extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); | 356 | extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); |
| 357 | extern void fsnotify_sb_delete(struct super_block *sb); | 357 | extern void fsnotify_sb_delete(struct super_block *sb); |
| 358 | extern void fsnotify_nameremove(struct dentry *dentry, int isdir); | ||
| 358 | extern u32 fsnotify_get_cookie(void); | 359 | extern u32 fsnotify_get_cookie(void); |
| 359 | 360 | ||
| 360 | static inline int fsnotify_inode_watches_children(struct inode *inode) | 361 | static inline int fsnotify_inode_watches_children(struct inode *inode) |
| @@ -524,6 +525,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) | |||
| 524 | static inline void fsnotify_sb_delete(struct super_block *sb) | 525 | static inline void fsnotify_sb_delete(struct super_block *sb) |
| 525 | {} | 526 | {} |
| 526 | 527 | ||
| 528 | static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) | ||
| 529 | {} | ||
| 530 | |||
| 527 | static inline void fsnotify_update_flags(struct dentry *dentry) | 531 | static inline void fsnotify_update_flags(struct dentry *dentry) |
| 528 | {} | 532 | {} |
| 529 | 533 | ||
