ext4: fix a potential fiemap/page fault deadlock w/ inline_data
authorTheodore Ts'o <tytso@mit.edu>
Tue, 25 Dec 2018 05:56:33 +0000 (00:56 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Jan 2019 21:04:36 +0000 (22:04 +0100)
commit 2b08b1f12cd664dc7d5c84ead9ff25ae97ad5491 upstream.

The ext4_inline_data_fiemap() function calls fiemap_fill_next_extent()
while still holding the xattr semaphore.  This is not necessary and it
triggers a circular lockdep warning.  This is because
fiemap_fill_next_extent() could trigger a page fault when it writes
into page which triggers a page fault.  If that page is mmaped from
the inline file in question, this could very well result in a
deadlock.

This problem can be reproduced using generic/519 with a file system
configuration which has the inline_data feature enabled.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/inline.c

index 27373d8..56f6e17 100644 (file)
@@ -1890,12 +1890,12 @@ int ext4_inline_data_fiemap(struct inode *inode,
        physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data;
        physical += offsetof(struct ext4_inode, i_block);
 
-       if (physical)
-               error = fiemap_fill_next_extent(fieinfo, start, physical,
-                                               inline_len, flags);
        brelse(iloc.bh);
 out:
        up_read(&EXT4_I(inode)->xattr_sem);
+       if (physical)
+               error = fiemap_fill_next_extent(fieinfo, start, physical,
+                                               inline_len, flags);
        return (error < 0 ? error : 0);
 }