Re: [PATCH 6.0 134/190] nilfs2: fix deadlock in nilfs_count_free_blocks()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,
On Wed, Nov 16, 2022 at 7:20 PM Pavel Machek wrote:
>
> Hi!
>
> > From: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxx>
> >
> > commit 8ac932a4921a96ca52f61935dbba64ea87bbd5dc upstream.
> ...
> > However, there is actually no need to take rwsem A in
> > nilfs_count_free_blocks() because it, within the lock section, only reads
> > a single integer data on a shared struct with
> > nilfs_sufile_get_ncleansegs().  This has been the case after commit
> > aa474a220180 ("nilfs2: add local variable to cache the number of clean
> > segments"), that is, even before this bug was introduced.
>
> Ok, but these days we have checkers that don't like reading variables
> unlocked, and compiler theoretically could do something funny.
>
> So this should have READ/WRITE_ONCE annotations... this is incomplete,
> but should illustrate what is needed. Likely some helper for updating
> ncleansegs should be introduced.

If the compiler omits an update in the middle, it's okay for
nilfs_count_free_blocks() and other read-only callers.

In fact if I introduce such helper function like
nilfs_sufile_set_ncleansegs() with WRITE_ONCE, I use
nilfs_sufile_get_ncleansegs() first and nilfs_sufile_set_ncleansegs()
last within functions that update the counter, rather than each time
they increment or decrement it.  But, I didn't see any point in using
WRITE_ONCE/READ_ONCE like this.

Just be sure, the functions that update the counter are already
exclusive with another semaphore (sufile->mi_sem), so updating it
without the intermediate result won't break the counter.

If there's a real problem with some kind of checkers giving warnings
as you mentioned, that's probably the real reason to apply those
annotations.
I would like to deal with it for the mainline in that case.

Thanks,
Ryusuke Konishi

>
> Best regards,
>                                                                 Pavel
>
> diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
> index 63722475e17e..58dddc0b1d88 100644
> --- a/fs/nilfs2/sufile.c
> +++ b/fs/nilfs2/sufile.c
> @@ -122,7 +122,7 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
>   */
>  unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
>  {
> -       return NILFS_SUI(sufile)->ncleansegs;
> +       return READ_ONCE(NILFS_SUI(sufile)->ncleansegs);
>  }
>
>  /**
> @@ -418,7 +418,9 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
>         kunmap_atomic(kaddr);
>
>         nilfs_sufile_mod_counter(header_bh, -1, 1);
> -       NILFS_SUI(sufile)->ncleansegs--;
> +       /* nilfs_sufile_get_ncleansegs() leads this without taking lock */
> +       WRITE_ONCE(NILFS_SUI(sufile)->ncleansegs,
> +                  READ_ONCE(NILFS_SUI(sufile)->ncleansegs) - 1);
>
>         mark_buffer_dirty(su_bh);
>         nilfs_mdt_mark_dirty(sufile);
>
> --
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux