@@ -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;
@@ -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
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@gmail.com> --- fs/notify/fanotify/fanotify.c | 39 +++++++++++++++++++++++++++++++------- fs/notify/fanotify/fanotify_user.c | 9 +++++++-- 2 files changed, 39 insertions(+), 9 deletions(-)