Hi Edwin,

On Wed, 6 Mar 2019 at 12:08, Edwin Török <[email protected]> wrote:
> Hello,
>
> I've been trying to debug a GFS2 deadlock that we see in our lab quite 
> frequently with a 4.19 kernel. With 4.4 and older kernels we were not able to 
> reproduce this.
> See below for lockdep dumps and stacktraces.

thanks for the thorough bug report.  Does the below fix work for you?

Thanks,
Andreas

--

Prevent page reclaim on the backing device of the filesystem in
gfs2_file_write_iter:

 - In gfs2_file_write_iter, iomap_file_buffered_write grabs the log
   flush lock (via iomap_apply -> iomap_begin -> gfs2_iomap_begin_write
   -> gfs2_trans_begin) and holds it for the duration of the write.

 - It then calls iomap_write_actor -> balance_dirty_pages.

 - If that triggers writeback on the same filesystem, we would try
   to grab the log flush lock again (via writeback_sb_inodes ->
   gfs2_write_inode -> gfs2_log_flush) and deadlock.

Prevent that by not setting backing_dev_info in gfs2_file_write_iter.

Reported-by: Edwin Török <[email protected]>
Fixes: 64bc06bb32ee ("gfs2: iomap buffered write support")
Signed-off-by: Andreas Gruenbacher <[email protected]>
---
 fs/gfs2/file.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index a2dea5bc04276..8c7d296d58608 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -816,16 +816,13 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, 
struct iov_iter *from)
        if (ret <= 0)
                goto out;
 
-       /* We can write back this queue in page reclaim */
-       current->backing_dev_info = inode_to_bdi(inode);
-
        ret = file_remove_privs(file);
        if (ret)
-               goto out2;
+               goto out;
 
        ret = file_update_time(file);
        if (ret)
-               goto out2;
+               goto out;
 
        if (iocb->ki_flags & IOCB_DIRECT) {
                struct address_space *mapping = file->f_mapping;
@@ -834,11 +831,11 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, 
struct iov_iter *from)
 
                written = gfs2_file_direct_write(iocb, from);
                if (written < 0 || !iov_iter_count(from))
-                       goto out2;
+                       goto out;
 
                ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
                if (unlikely(ret < 0))
-                       goto out2;
+                       goto out;
                buffered = ret;
 
                /*
@@ -867,8 +864,6 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, 
struct iov_iter *from)
                        iocb->ki_pos += ret;
        }
 
-out2:
-       current->backing_dev_info = NULL;
 out:
        inode_unlock(inode);
        if (likely(ret > 0)) {
-- 
2.20.1

Reply via email to