All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Brennan <stephen.s.brennan@oracle.com>
To: Amir Goldstein <amir73il@gmail.com>
Cc: Jan Kara <jack@suse.cz>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	Al Viro <viro@zeniv.linux.org.uk>
Subject: Re: [PATCH v3 0/3] fsnotify: fix softlockups iterating over d_subdirs
Date: Thu, 10 Nov 2022 12:04:21 -0800	[thread overview]
Message-ID: <87h6z6fuey.fsf@oracle.com> (raw)
In-Reply-To: <CAOQ4uxgG=E+3CwpQAE__YGt7vdW77n0nTe6cExPTERBNUN0a0g@mail.gmail.com>

Amir Goldstein <amir73il@gmail.com> writes:
[...]
> IIUC, patches #1+#3 fix a reproducible softlock, so if Al approves them,
> I see no reason to withhold.
>
> With patches #1+#3 applied, the penalty is restricted to adding or
> removing/destroying multiple marks on very large dirs or dirs with
> many negative dentries.
>
> I think that fixing the synthetic test case of multiple added marks
> is rather easy even without DCACHE_FSNOTIFY_PARENT_WATCHED.
> Something like the attached patch is what Jan had suggested in the
> first place.
>
> The synthetic test case of concurrent add/remove watch on the same
> dir may still result in multiple children iterations, but that will usually
> not be avoided even with DCACHE_FSNOTIFY_PARENT_WATCHED
> and probably not worth optimizing for.
>
> Thoughts?

If I understand your train of thought, your below patch would take the
place of my patch #2, since #3 requires we not hold a spinlock during
fsnotify_update_children_dentry_flags().

And since you fully rely on dentry accessors to lazily clear flags, you
don't need to have the mutual exclusion provided by the inode lock.

I like that a lot.

However, the one thing I see here is that if we no longer hold the inode
lock, patch #3 needs to be re-examined: it assumes that dentries can't
be removed or moved around, and that assumption is only true with the
inode lock held.

I'll test things out with this patch replacing #2 and see how things
shake out. Maybe I can improve #3.

Thanks,
Stephen

>
> Thanks,
> Amir.
> From c8ea1d84397c26ce334bff9d9f721400cebb88dd Mon Sep 17 00:00:00 2001
> From: Amir Goldstein <amir73il@gmail.com>
> Date: Wed, 2 Nov 2022 10:28:01 +0200
> Subject: [PATCH] fsnotify: clear PARENT_WATCHED flags lazily
>
> Call fsnotify_update_children_dentry_flags() to set PARENT_WATCHED flags
> only when parent starts watching children.
>
> When parent stops watching children, clear false positive PARENT_WATCHED
> flags lazily in __fsnotify_parent() for each accessed child.
>
> Suggested-by: Jan Kara <jack@suse.cz>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  fs/notify/fsnotify.c             | 26 ++++++++++++++++++++------
>  fs/notify/fsnotify.h             |  3 ++-
>  fs/notify/mark.c                 | 32 +++++++++++++++++++++++++++++---
>  include/linux/fsnotify_backend.h |  8 +++++---
>  4 files changed, 56 insertions(+), 13 deletions(-)
>
> diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
> index 1e541a9bd12b..f60078d6bb97 100644
> --- a/fs/notify/fsnotify.c
> +++ b/fs/notify/fsnotify.c
> @@ -103,17 +103,13 @@ void fsnotify_sb_delete(struct super_block *sb)
>   * parent cares.  Thus when an event happens on a child it can quickly tell
>   * if there is a need to find a parent and send the event to the parent.
>   */
> -void __fsnotify_update_child_dentry_flags(struct inode *inode)
> +void fsnotify_update_children_dentry_flags(struct inode *inode, bool watched)
>  {
>  	struct dentry *alias;
> -	int watched;
>  
>  	if (!S_ISDIR(inode->i_mode))
>  		return;
>  
> -	/* determine if the children should tell inode about their events */
> -	watched = fsnotify_inode_watches_children(inode);
> -
>  	spin_lock(&inode->i_lock);
>  	/* run all of the dentries associated with this inode.  Since this is a
>  	 * directory, there damn well better only be one item on this list */
> @@ -140,6 +136,24 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
>  	spin_unlock(&inode->i_lock);
>  }
>  
> +/*
> + * Lazily clear false positive PARENT_WATCHED flag for child whose parent had
> + * stopped wacthing children.
> + */
> +static void fsnotify_update_child_dentry_flags(struct inode *inode,
> +					       struct dentry *dentry)
> +{
> +	spin_lock(&dentry->d_lock);
> +	/*
> +	 * d_lock is a sufficient barrier to prevent observing a non-watched
> +	 * parent state from before the fsnotify_update_children_dentry_flags()
> +	 * or fsnotify_update_flags() call that had set PARENT_WATCHED.
> +	 */
> +	if (!fsnotify_inode_watches_children(inode))
> +		dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
> +	spin_unlock(&dentry->d_lock);
> +}
> +
>  /* Are inode/sb/mount interested in parent and name info with this event? */
>  static bool fsnotify_event_needs_parent(struct inode *inode, struct mount *mnt,
>  					__u32 mask)
> @@ -208,7 +222,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
>  	p_inode = parent->d_inode;
>  	p_mask = fsnotify_inode_watches_children(p_inode);
>  	if (unlikely(parent_watched && !p_mask))
> -		__fsnotify_update_child_dentry_flags(p_inode);
> +		fsnotify_update_child_dentry_flags(p_inode, dentry);
>  
>  	/*
>  	 * Include parent/name in notification either if some notification
> diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h
> index fde74eb333cc..bce9be36d06b 100644
> --- a/fs/notify/fsnotify.h
> +++ b/fs/notify/fsnotify.h
> @@ -74,7 +74,8 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb)
>   * update the dentry->d_flags of all of inode's children to indicate if inode cares
>   * about events that happen to its children.
>   */
> -extern void __fsnotify_update_child_dentry_flags(struct inode *inode);
> +extern void fsnotify_update_children_dentry_flags(struct inode *inode,
> +						  bool watched);
>  
>  extern struct kmem_cache *fsnotify_mark_connector_cachep;
>  
> diff --git a/fs/notify/mark.c b/fs/notify/mark.c
> index fcc68b8a40fd..614bce0e7261 100644
> --- a/fs/notify/mark.c
> +++ b/fs/notify/mark.c
> @@ -176,6 +176,24 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
>  	return fsnotify_update_iref(conn, want_iref);
>  }
>  
> +static bool fsnotify_conn_watches_children(
> +					struct fsnotify_mark_connector *conn)
> +{
> +	if (conn->type != FSNOTIFY_OBJ_TYPE_INODE)
> +		return false;
> +
> +	return fsnotify_inode_watches_children(fsnotify_conn_inode(conn));
> +}
> +
> +static void fsnotify_conn_set_children_dentry_flags(
> +					struct fsnotify_mark_connector *conn)
> +{
> +	if (conn->type != FSNOTIFY_OBJ_TYPE_INODE)
> +		return;
> +
> +	fsnotify_update_children_dentry_flags(fsnotify_conn_inode(conn), true);
> +}
> +
>  /*
>   * Calculate mask of events for a list of marks. The caller must make sure
>   * connector and connector->obj cannot disappear under us.  Callers achieve
> @@ -184,15 +202,23 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
>   */
>  void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
>  {
> +	bool update_children;
> +
>  	if (!conn)
>  		return;
>  
>  	spin_lock(&conn->lock);
> +	update_children = !fsnotify_conn_watches_children(conn);
>  	__fsnotify_recalc_mask(conn);
> +	update_children &= fsnotify_conn_watches_children(conn);
>  	spin_unlock(&conn->lock);
> -	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
> -		__fsnotify_update_child_dentry_flags(
> -					fsnotify_conn_inode(conn));
> +	/*
> +	 * Set children's PARENT_WATCHED flags only if parent started watching.
> +	 * When parent stops watching, we clear false positive PARENT_WATCHED
> +	 * flags lazily in __fsnotify_parent().
> +	 */
> +	if (update_children)
> +		fsnotify_conn_set_children_dentry_flags(conn);
>  }
>  
>  /* Free all connectors queued for freeing once SRCU period ends */
> diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
> index a31423c376a7..bd90bcf6c3b0 100644
> --- a/include/linux/fsnotify_backend.h
> +++ b/include/linux/fsnotify_backend.h
> @@ -586,12 +586,14 @@ static inline __u32 fsnotify_parent_needed_mask(__u32 mask)
>  
>  static inline int fsnotify_inode_watches_children(struct inode *inode)
>  {
> +	__u32 parent_mask = READ_ONCE(inode->i_fsnotify_mask);
> +
>  	/* FS_EVENT_ON_CHILD is set if the inode may care */
> -	if (!(inode->i_fsnotify_mask & FS_EVENT_ON_CHILD))
> +	if (!(parent_mask & FS_EVENT_ON_CHILD))
>  		return 0;
>  	/* this inode 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 parent_mask & FS_EVENTS_POSS_ON_CHILD;
>  }
>  
>  /*
> @@ -605,7 +607,7 @@ static inline void fsnotify_update_flags(struct dentry *dentry)
>  	/*
>  	 * Serialisation of setting PARENT_WATCHED on the dentries is provided
>  	 * by d_lock. If inotify_inode_watched changes after we have taken
> -	 * d_lock, the following __fsnotify_update_child_dentry_flags call will
> +	 * d_lock, the following fsnotify_update_children_dentry_flags call will
>  	 * find our entry, so it will spin until we complete here, and update
>  	 * us with the new state.
>  	 */
> -- 
> 2.25.1

  reply	other threads:[~2022-11-10 20:25 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-13 22:27 [RFC] fsnotify: allow sleepable child dentry flag update Stephen Brennan
2022-10-13 23:51 ` Al Viro
2022-11-01 21:47   ` Stephen Brennan
2022-10-14  8:01 ` Amir Goldstein
2022-10-17  7:59   ` Stephen Brennan
2022-10-17 11:44     ` Amir Goldstein
2022-10-17 16:59       ` Stephen Brennan
2022-10-17 17:42         ` Amir Goldstein
2022-10-17  9:09   ` Jan Kara
2022-10-18  4:12 ` [PATCH 0/2] fsnotify: fix softlockups iterating over d_subdirs Stephen Brennan
2022-10-18  4:12   ` [PATCH 1/2] fsnotify: Protect i_fsnotify_mask and child flags with inode rwsem Stephen Brennan
2022-10-18  7:39     ` Amir Goldstein
2022-10-21  0:33       ` Stephen Brennan
2022-10-21  7:22         ` Amir Goldstein
2022-10-18  4:12   ` [PATCH 2/2] fsnotify: allow sleepable child flag update Stephen Brennan
2022-10-18  5:36     ` Amir Goldstein
2022-10-27  7:50     ` kernel test robot
2022-10-27  8:44       ` Yujie Liu
2022-10-27 22:12         ` Stephen Brennan
2022-10-18  8:07   ` [PATCH 0/2] fsnotify: fix softlockups iterating over d_subdirs Amir Goldstein
2022-10-18 23:52     ` Stephen Brennan
2022-10-19  5:33       ` Amir Goldstein
2022-10-27 22:06         ` Stephen Brennan
2022-10-28  8:58           ` Amir Goldstein
2022-10-21  1:03   ` [PATCH v2 0/3] " Stephen Brennan
2022-10-21  1:03     ` [PATCH v2 1/3] fsnotify: Use d_find_any_alias to get dentry associated with inode Stephen Brennan
2022-10-21  9:25       ` Amir Goldstein
2022-10-21  1:03     ` [PATCH v2 2/3] fsnotify: Protect i_fsnotify_mask and child flags with inode rwsem Stephen Brennan
2022-10-21  4:01       ` kernel test robot
2022-10-21  8:22       ` Amir Goldstein
2022-10-21  9:18         ` Amir Goldstein
2022-10-25 18:02           ` Stephen Brennan
2022-10-26  5:41             ` Amir Goldstein
2022-10-21  9:17       ` Christian Brauner
2022-10-21  9:21         ` Amir Goldstein
2022-10-21  1:03     ` [PATCH v2 3/3] fsnotify: allow sleepable child flag update Stephen Brennan
2022-10-28  0:10     ` [PATCH v3 0/3] fsnotify: fix softlockups iterating over d_subdirs Stephen Brennan
2022-10-28  0:10       ` [PATCH v3 1/3] fsnotify: Use d_find_any_alias to get dentry associated with inode Stephen Brennan
2022-11-10  1:12         ` Stephen Brennan
2022-10-28  0:10       ` [PATCH v3 2/3] fsnotify: Protect i_fsnotify_mask and child flags with inode rwsem Stephen Brennan
2022-10-28  9:11         ` Amir Goldstein
2022-11-10  0:03         ` kernel test robot
2022-11-10  1:06           ` Stephen Brennan
2022-10-28  0:10       ` [PATCH v3 3/3] fsnotify: allow sleepable child flag update Stephen Brennan
2022-10-28  9:32         ` Amir Goldstein
2022-11-01 21:25           ` Stephen Brennan
2022-11-01 17:51       ` [PATCH v3 0/3] fsnotify: fix softlockups iterating over d_subdirs Jan Kara
2022-11-01 20:48         ` Stephen Brennan
2022-11-02  8:55           ` Amir Goldstein
2022-11-10 20:04             ` Stephen Brennan [this message]
     [not found]               ` <CAOQ4uxjRVRjTNJ-2CSX9QwLVC9oQN9r4GHqCn=XZrisZo6DN2w@mail.gmail.com>
     [not found]                 ` <87eduafg6d.fsf@oracle.com>
2022-11-11  7:56                   ` Amir Goldstein
2022-11-02 17:52           ` Jan Kara
2022-11-04 23:33             ` Stephen Brennan
2022-11-07 11:56               ` Jan Kara
2022-11-11 22:06       ` [PATCH v4 0/5] " Stephen Brennan
2022-11-11 22:06         ` [PATCH v4 1/5] fsnotify: clear PARENT_WATCHED flags lazily Stephen Brennan
2022-11-11 22:06         ` [PATCH v4 2/5] fsnotify: Use d_find_any_alias to get dentry associated with inode Stephen Brennan
2022-11-12  8:53           ` Amir Goldstein
2022-11-11 22:06         ` [PATCH v4 3/5] dnotify: move fsnotify_recalc_mask() outside spinlock Stephen Brennan
2022-11-12  9:06           ` Amir Goldstein
2022-11-11 22:06         ` [PATCH v4 4/5] fsnotify: allow sleepable child flag update Stephen Brennan
2022-11-12 10:00           ` Amir Goldstein
2022-11-15  7:10           ` kernel test robot
2022-11-11 22:06         ` [PATCH v4 5/5] fsnotify: require inode lock held during " Stephen Brennan
2022-11-12  9:42           ` Amir Goldstein
2022-11-11 22:08         ` [PATCH v4 0/5] fsnotify: fix softlockups iterating over d_subdirs Stephen Brennan
2022-11-22 11:50         ` Jan Kara
2022-11-22 14:03           ` 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=87h6z6fuey.fsf@oracle.com \
    --to=stephen.s.brennan@oracle.com \
    --cc=amir73il@gmail.com \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /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.