From: Dave Chinner <david@fromorbit.com>
To: Jan Kara <jack@suse.cz>
Cc: Christian Brauner <brauner@kernel.org>,
linux-fsdevel@vger.kernel.org, Al Viro <viro@zeniv.linux.org.uk>,
David Howells <dhowells@redhat.com>
Subject: Re: [PATCH] fs: Provide helpers for manipulating sb->s_readonly_remount
Date: Sat, 17 Jun 2023 09:33:42 +1000 [thread overview]
Message-ID: <ZIzxVvLgukjBOBBW@dread.disaster.area> (raw)
In-Reply-To: <20230616163827.19377-1-jack@suse.cz>
On Fri, Jun 16, 2023 at 06:38:27PM +0200, Jan Kara wrote:
> Provide helpers to set and clear sb->s_readonly_remount including
> appropriate memory barriers. Also use this opportunity to document what
> the barriers pair with and why they are needed.
>
> Suggested-by: Dave Chinner <david@fromorbit.com>
> Signed-off-by: Jan Kara <jack@suse.cz>
The helper conversion looks fine so from that perspective the patch
looks good.
However, I'm not sure the use of memory barriers is correct, though.
IIUC, we want mnt_is_readonly() to return true when ever
s_readonly_remount is set. Is that the behaviour we are trying to
acheive for both ro->rw and rw->ro transactions?
> ---
> fs/internal.h | 26 ++++++++++++++++++++++++++
> fs/namespace.c | 10 ++++------
> fs/super.c | 17 ++++++-----------
> include/linux/fs.h | 2 +-
> 4 files changed, 37 insertions(+), 18 deletions(-)
>
> diff --git a/fs/internal.h b/fs/internal.h
> index bd3b2810a36b..01bff3f6db79 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -120,6 +120,32 @@ void put_super(struct super_block *sb);
> extern bool mount_capable(struct fs_context *);
> int sb_init_dio_done_wq(struct super_block *sb);
>
> +/*
> + * Prepare superblock for changing its read-only state (i.e., either remount
> + * read-write superblock read-only or vice versa). After this function returns
> + * mnt_is_readonly() will return true for any mount of the superblock if its
> + * caller is able to observe any changes done by the remount. This holds until
> + * sb_end_ro_state_change() is called.
> + */
> +static inline void sb_start_ro_state_change(struct super_block *sb)
> +{
> + WRITE_ONCE(sb->s_readonly_remount, 1);
> + /* The barrier pairs with the barrier in mnt_is_readonly() */
> + smp_wmb();
> +}
I'm not sure how this wmb pairs with the memory barrier in
mnt_is_readonly() to provide the correct behavior. The barrier in
mnt_is_readonly() happens after it checks s_readonly_remount, so
the s_readonly_remount in mnt_is_readonly is not ordered in any way
against this barrier.
The barrier in mnt_is_readonly() ensures that the loads of SB_RDONLY
and MNT_READONLY are ordered after s_readonly_remount(), but we
don't change those flags until a long way after s_readonly_remount
is set.
Hence if this is a ro->rw transistion, then I can see that racing on
s_readonly_remount being isn't an issue, because the mount/sb
flags will have SB_RDONLY/MNT_READONLY set and the correct thing
will be done (i.e. consider code between sb_start_ro_state_change()
and sb_end_ro_state_change() is RO).
However, it's not obvious (to me, anyway) how this works at all for
a rw->ro transition - if we race on s_readonly_remount being set
then we'll consider the fs to still be read-write regardless of the
smp_rmb() in mnt_is_readonly() because neither SB_RDONLY or
MNT_READONLY are set at this point.
So I can't see what the memory barrier is actually doing for
us here...
What am I missing?
> +/*
> + * Ends section changing read-only state of the superblock. After this function
> + * returns if mnt_is_readonly() returns false, the caller will be able to
> + * observe all the changes remount did to the superblock.
> + */
> +static inline void sb_end_ro_state_change(struct super_block *sb)
> +{
> + /* The barrier pairs with the barrier in mnt_is_readonly() */
> + smp_wmb();
> + WRITE_ONCE(sb->s_readonly_remount, 0);
> +}
This one looks fine - it is providing release semantics,
ensuring that if s_readonly_remount is seen as zero, then the prior
sb/mnt flag changes will be seen by __mnt_is_readonly(mnt). i.e the
smp_rmb() in mnt_is_readonly() is providing acquire side
semantics on the s_readonly_remount access if it returns 0....
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
next prev parent reply other threads:[~2023-06-16 23:33 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-16 16:38 [PATCH] fs: Provide helpers for manipulating sb->s_readonly_remount Jan Kara
2023-06-16 23:33 ` Dave Chinner [this message]
2023-06-17 15:05 ` Christian Brauner
2023-06-19 23:11 ` Dave Chinner
2023-06-19 11:05 ` Jan Kara
2023-06-19 23:16 ` Dave Chinner
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=ZIzxVvLgukjBOBBW@dread.disaster.area \
--to=david@fromorbit.com \
--cc=brauner@kernel.org \
--cc=dhowells@redhat.com \
--cc=jack@suse.cz \
--cc=linux-fsdevel@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.