diff options
author | Amir Goldstein <amir73il@gmail.com> | 2019-01-10 19:04:40 +0200 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2019-02-07 16:38:35 +0100 |
commit | 0a20df7ed3349dfa3260ddee2efa919df44d0ad5 (patch) | |
tree | a67f25db1275679997c0d7348c0c25896e33dde7 | |
parent | 73072283a249c798838e09813760db8bcdd9cd3a (diff) | |
download | linux-stable-0a20df7ed3349dfa3260ddee2efa919df44d0ad5.tar.gz linux-stable-0a20df7ed3349dfa3260ddee2efa919df44d0ad5.tar.bz2 linux-stable-0a20df7ed3349dfa3260ddee2efa919df44d0ad5.zip |
fsnotify: report FS_ISDIR flag with MOVE_SELF and DELETE_SELF events
We need to report FS_ISDIR flag with MOVE_SELF and DELETE_SELF events
for fanotify, because fanotify API requires the user to explicitly
request events on directories by FAN_ONDIR flag.
inotify never reported IN_ISDIR with those events. It looks like an
oversight, but to avoid the risk of breaking existing inotify programs,
mask the FS_ISDIR flag out when reprting those events to inotify backend.
We also add the FS_ISDIR flag with FS_ATTRIB event in the case of rename
over an empty target directory. inotify did not report IN_ISDIR in this
case, but it normally does report IN_ISDIR along with IN_ATTRIB event,
so in this case, we do not mask out the FS_ISDIR flag.
[JK: Simplify the checks in fsnotify_move()]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 9 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 21 |
2 files changed, 26 insertions, 4 deletions
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index fe97299975f2..ff30abd6a49b 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -113,6 +113,15 @@ int inotify_handle_event(struct fsnotify_group *group, return -ENOMEM; } + /* + * We now report FS_ISDIR flag with MOVE_SELF and DELETE_SELF events + * for fanotify. inotify never reported IN_ISDIR with those events. + * It looks like an oversight, but to avoid the risk of breaking + * existing inotify programs, mask the flag out from those events. + */ + if (mask & (IN_MOVE_SELF | IN_DELETE_SELF)) + mask &= ~IN_ISDIR; + fsn_event = &event->fse; fsnotify_init_event(fsn_event, inode); event->mask = mask; diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 39b22e88423d..9becae610022 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -87,7 +87,12 @@ static inline int fsnotify_perm(struct file *file, int mask) */ static inline void fsnotify_link_count(struct inode *inode) { - fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0); + __u32 mask = FS_ATTRIB; + + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + + fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); } /* @@ -95,12 +100,14 @@ static inline void fsnotify_link_count(struct inode *inode) */ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, const unsigned char *old_name, - int isdir, struct inode *target, struct dentry *moved) + int isdir, struct inode *target, + struct dentry *moved) { struct inode *source = moved->d_inode; u32 fs_cookie = fsnotify_get_cookie(); __u32 old_dir_mask = FS_MOVED_FROM; __u32 new_dir_mask = FS_MOVED_TO; + __u32 mask = FS_MOVE_SELF; const unsigned char *new_name = moved->d_name.name; if (old_dir == new_dir) @@ -109,6 +116,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, if (isdir) { old_dir_mask |= FS_ISDIR; new_dir_mask |= FS_ISDIR; + mask |= FS_ISDIR; } fsnotify(old_dir, old_dir_mask, source, FSNOTIFY_EVENT_INODE, old_name, @@ -120,7 +128,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, fsnotify_link_count(target); if (source) - fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); + fsnotify(source, mask, source, FSNOTIFY_EVENT_INODE, NULL, 0); audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE); } @@ -178,7 +186,12 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) */ static inline void fsnotify_inoderemove(struct inode *inode) { - fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0); + __u32 mask = FS_DELETE_SELF; + + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + + fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); __fsnotify_inode_delete(inode); } |