All of lore.kernel.org
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Jan Kara <jack@suse.cz>
Cc: Matthew Bobrowski <mbobrowski@mbobrowski.org>,
	linux-fsdevel@vger.kernel.org
Subject: [PATCH v3 6/7] fsnotify: send event "on child" to sb/mount marks
Date: Tue,  5 May 2020 19:20:13 +0300	[thread overview]
Message-ID: <20200505162014.10352-7-amir73il@gmail.com> (raw)
In-Reply-To: <20200505162014.10352-1-amir73il@gmail.com>

Similar to events "on child" to watching directory, send event flavor
"on child" to sb/mount marks that specified interest in this flavor.
Event "on child" will not be sent on "orphan" children, that is, on
disconnected dentries and on a mount/sb root.

Currently, fanotify allows to set the FAN_EVENT_ON_CHILD flag on
sb/mount marks, but it was ignored.  Mask the flag explicitly until
fanotify implements support for events "on child" with name info
for sb/mount marks.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify_user.c |  7 ++++--
 fs/notify/fsnotify.c               | 38 ++++++++++++++++++++++++------
 include/linux/fsnotify_backend.h   | 23 ++++++++++++------
 3 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 030534da49e2..36c1327b32f4 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -1146,10 +1146,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	}
 
 	/* inode held in place by reference to path; group by fget on fd */
-	if (mark_type == FAN_MARK_INODE)
+	if (mark_type == FAN_MARK_INODE) {
 		inode = path.dentry->d_inode;
-	else
+	} else {
 		mnt = path.mnt;
+		/* Mask out FAN_EVENT_ON_CHILD flag for sb/mount marks */
+		mask &= ~FAN_EVENT_ON_CHILD;
+	}
 
 	/* create/update an inode mark */
 	switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 72d332ce8e12..f6da8f263bc0 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -142,23 +142,50 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
 	spin_unlock(&inode->i_lock);
 }
 
-/* Notify this dentry's parent about a child's events. */
+/*
+ * Notify this dentry's parent about a child's events if parent is watching
+ * children or if sb/mount marks are interested in events with file_name info.
+ */
 int fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
 		    int data_type)
 {
+	const struct path *path = fsnotify_data_path(data, data_type);
+	struct mount *mnt = NULL;
+	bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED;
+	__u32 test_mask = mask & FS_EVENTS_POSS_ON_CHILD;
+	__u32 p_mask, marks_mask = 0;
 	struct dentry *parent;
 	struct inode *p_inode;
 	int ret = 0;
 
-	if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
+	if (path && path->mnt->mnt_root != dentry)
+		mnt = real_mount(path->mnt);
+
+	/*
+	 * FS_EVENT_ON_CHILD on sb/mount mask implies reporting events as if all
+	 * directories are watched.
+	 */
+	if (!IS_ROOT(dentry))
+		marks_mask |= fsnotify_watches_children(
+						dentry->d_sb->s_fsnotify_mask);
+	if (mnt)
+		marks_mask |= fsnotify_watches_children(
+						mnt->mnt_fsnotify_mask);
+
+
+	if (!(marks_mask & test_mask) && !parent_watched)
 		return 0;
 
 	parent = dget_parent(dentry);
 	p_inode = parent->d_inode;
+	p_mask = fsnotify_inode_watches_children(p_inode);
 
-	if (unlikely(!fsnotify_inode_watches_children(p_inode))) {
+	if (p_mask)
+		marks_mask |= p_mask;
+	else if (unlikely(parent_watched))
 		__fsnotify_update_child_dentry_flags(p_inode);
-	} else if (p_inode->i_fsnotify_mask & mask & ALL_FSNOTIFY_EVENTS) {
+
+	if (marks_mask & test_mask) {
 		struct name_snapshot name;
 
 		/* we are notifying a parent so come up with the new mask which
@@ -323,9 +350,6 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
 		mnt = real_mount(path->mnt);
 		mnt_or_sb_mask |= mnt->mnt_fsnotify_mask;
 	}
-	/* An event "on child" is not intended for a mount/sb mark */
-	if (mask & FS_EVENT_ON_CHILD)
-		mnt_or_sb_mask = 0;
 
 	/*
 	 * Optimization: srcu_read_lock() has a memory barrier which can
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index f0c506405b54..ca461b95662a 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -50,8 +50,12 @@
 #define FS_DIR_MODIFY		0x00080000	/* Directory entry was modified */
 
 #define FS_EXCL_UNLINK		0x04000000	/* do not send events if object is unlinked */
-/* This inode cares about things that happen to its children.  Always set for
- * dnotify and inotify. */
+/*
+ * This inode cares about things that happen to its children.
+ * Always set for dnotify and inotify.
+ * Set on sb/mount marks mask to indicate interest in getting events with
+ * file_name information.
+ */
 #define FS_EVENT_ON_CHILD	0x08000000
 
 #define FS_DN_RENAME		0x10000000	/* file renamed */
@@ -386,14 +390,19 @@ extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
 extern void fsnotify_sb_delete(struct super_block *sb);
 extern u32 fsnotify_get_cookie(void);
 
-static inline int fsnotify_inode_watches_children(struct inode *inode)
+static inline __u32 fsnotify_watches_children(__u32 mask)
 {
-	/* FS_EVENT_ON_CHILD is set if the inode may care */
-	if (!(inode->i_fsnotify_mask & FS_EVENT_ON_CHILD))
+	/* FS_EVENT_ON_CHILD is set if the object may care */
+	if (!(mask & FS_EVENT_ON_CHILD))
 		return 0;
-	/* this inode might care about child events, does it care about the
+	/* This object might care about child events, does it care about the
 	 * specific set of events that can happen on a child? */
-	return inode->i_fsnotify_mask & FS_EVENTS_POSS_ON_CHILD;
+	return mask & FS_EVENTS_POSS_ON_CHILD;
+}
+
+static inline int fsnotify_inode_watches_children(struct inode *inode)
+{
+	return fsnotify_watches_children(inode->i_fsnotify_mask);
 }
 
 /*
-- 
2.17.1


  parent reply	other threads:[~2020-05-05 16:20 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-05 16:20 [PATCH v3 0/7] fanotify events on child with name info Amir Goldstein
2020-05-05 16:20 ` [PATCH v3 1/7] fanotify: create overflow event type Amir Goldstein
2020-05-05 16:20 ` [PATCH v3 2/7] fanotify: break up fanotify_alloc_event() Amir Goldstein
2020-05-05 16:20 ` [PATCH v3 3/7] fanotify: generalize the handling of extra event flags Amir Goldstein
2020-05-05 16:20 ` [PATCH v3 4/7] fanotify: distinguish between fid encode error and null fid Amir Goldstein
2020-05-05 16:20 ` [PATCH v3 5/7] fanotify: report parent fid + name for events on children Amir Goldstein
2020-05-05 16:20 ` Amir Goldstein [this message]
2020-05-05 16:20 ` [PATCH v3 7/7] fanotify: report events "on child" with name info to sb/mount marks Amir Goldstein
2020-05-18  9:40 ` [PATCH v3 0/7] fanotify events on child with name info Amir Goldstein

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200505162014.10352-7-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=mbobrowski@mbobrowski.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.