When event data type is FSNOTIFY_EVENT_DENTRY, store the provided dentry in the event queue along with the mount point that was used to setup the watch. This will enable the watcher to read the path of the passed dentry from /proc/self/fd/X, for example on FAN_ATTRIB events. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/notify/fanotify/fanotify.c | 39 +++++++++++++++++++++++++++++++------- fs/notify/fanotify/fanotify_user.c | 9 +++++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index d2f97ec..fb2b852 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -105,18 +105,28 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, { __u32 marks_mask, marks_ignored_mask; struct path *path = data; + struct dentry *dentry; pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p" " data_type=%d\n", __func__, inode_mark, vfsmnt_mark, event_mask, data, data_type); /* if we don't have enough info to send an event to userspace say no */ - if (data_type != FSNOTIFY_EVENT_PATH) + if (data_type != FSNOTIFY_EVENT_PATH && + data_type != FSNOTIFY_EVENT_DENTRY) return false; - /* sorry, fanotify only gives a damn about files and dirs */ - if (!d_is_reg(path->dentry) && - !d_can_lookup(path->dentry)) + dentry = path->dentry; + pr_debug("%s: dentry=%p d_flags=%x inode=%p\n", __func__, + dentry, dentry->d_flags, dentry->d_inode); + + if (d_is_negative(dentry) || d_really_is_negative(dentry)) + return false; + + /* sorry, fanotify only gives a damn about files and dirs + * FIXME: can this be removed? */ + if (data_type == FSNOTIFY_EVENT_PATH && + !d_is_reg(dentry) && !d_can_lookup(dentry)) return false; if (inode_mark && vfsmnt_mark) { @@ -139,7 +149,7 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, BUG(); } - if (d_is_dir(path->dentry) && + if (d_is_dir(dentry) && !(marks_mask & FS_ISDIR & ~marks_ignored_mask)) return false; @@ -177,6 +187,10 @@ init: __maybe_unused if (path) { event->path = *path; path_get(&event->path); + pr_debug("%s: mnt=%p, dentry=%p parent=%p d_flags=%x\n", + __func__, event->path.mnt, event->path.dentry, + event->path.dentry->d_parent, + event->path.dentry->d_flags); } else { event->path.mnt = NULL; event->path.dentry = NULL; @@ -194,6 +208,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, int ret = 0; struct fanotify_event_info *event; struct fsnotify_event *fsn_event; + struct path path; BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); @@ -206,14 +221,24 @@ static int fanotify_handle_event(struct fsnotify_group *group, BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM); BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR); - if (!fanotify_should_send_event(inode_mark, fanotify_mark, mask, data, + if (data_type == FSNOTIFY_EVENT_PATH) { + path = *(struct path *)data; + } else if (data_type == FSNOTIFY_EVENT_DENTRY) { + path.dentry = (struct dentry *)data; + path.mnt = (inode_mark ? inode_mark->mnt : fanotify_mark->mnt); + } else { + path.mnt = NULL; + path.dentry = NULL; + } + + if (!fanotify_should_send_event(inode_mark, fanotify_mark, mask, &path, data_type)) return 0; pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, mask); - event = fanotify_alloc_event(inode, mask, data); + event = fanotify_alloc_event(inode, mask, &path); if (unlikely(!event)) return -ENOMEM; diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 0696d46..789962c 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -88,12 +88,17 @@ static int create_fd(struct fsnotify_group *group, */ /* it's possible this event was an overflow event. in that case dentry and mnt * are NULL; That's fine, just don't call dentry open */ - if (event->path.dentry && event->path.mnt) + if (event->path.dentry && event->path.mnt) { + pr_debug("%s: mnt=%p, dentry=%p parent=%p d_flags=%x\n", + __func__, event->path.mnt, event->path.dentry, + event->path.dentry->d_parent, + event->path.dentry->d_flags); new_file = dentry_open(&event->path, group->fanotify_data.f_flags | FMODE_NONOTIFY, current_cred()); - else + } else { new_file = ERR_PTR(-EOVERFLOW); + } if (IS_ERR(new_file)) { /* * we still send an event even if we can't open the file. this -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html