]> www.infradead.org Git - users/jedix/linux-maple.git/commit
gfs2: Fix mmap + page fault deadlocks (part 2)
authorAndreas Gruenbacher <agruenba@redhat.com>
Thu, 13 May 2021 08:47:59 +0000 (10:47 +0200)
committerAndreas Gruenbacher <agruenba@redhat.com>
Wed, 2 Jun 2021 09:47:04 +0000 (11:47 +0200)
commitb8182f91d5dd9a91c939c8b336ad2c0ca76f13e4
tree2004119a64a8c489f1cc3396e303980974b157aa
parenta06cf5b66b4492ad64b44ebea0524e73eefbe248
gfs2: Fix mmap + page fault deadlocks (part 2)

Now that we handle self-recursion on the inode glock in gfs2_fault and
gfs2_page_mkwrite, we need to take care of more complex deadlock
scenarios like the following (example by Jan Kara):

Two independent processes P1, P2. Two files F1, F2, and two mappings M1,
M2 where M1 is a mapping of F1, M2 is a mapping of F2. Now P1 does DIO
to F1 with M2 as a buffer, P2 does DIO to F2 with M1 as a buffer. They
can race like:

P1                                      P2
read()                                  read()
  gfs2_file_read_iter()                   gfs2_file_read_iter()
    gfs2_file_direct_read()                 gfs2_file_direct_read()
      locks glock of F1                       locks glock of F2
      iomap_dio_rw()                          iomap_dio_rw()
        bio_iov_iter_get_pages()                bio_iov_iter_get_pages()
          <fault in M2>                           <fault in M1>
            gfs2_fault()                            gfs2_fault()
              tries to grab glock of F2               tries to grab glock of F1

Those kinds of scenarios are much harder to reproduce than
self-recursion.

We deal with such situations by using the LM_FLAG_OUTER flag to mark
"outer" glock taking.  Then, when taking an "inner" glock, we use the
LM_FLAG_TRY flag so that locking attempts that don't immediately succeed
will be aborted.  In case of a failed locking attempt, we "unroll" to
where the "outer" glock was taken, drop the "outer" glock, and fault in
the first offending user page.  This will re-trigger the "inner" locking
attempt but without the LM_FLAG_TRY flag.  Once that has happened, we
re-acquire the "outer" glock and retry the original operation.

Reported-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/bmap.c
fs/gfs2/file.c