]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ext4: remove extent cache entries when truncating inline data
authorEric Whitney <enwlinux@gmail.com>
Thu, 19 Aug 2021 14:49:26 +0000 (10:49 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 9 Sep 2021 14:52:05 +0000 (10:52 -0400)
Conditionally remove all cached extents belonging to an inode
when truncating its inline data.  It's only necessary to attempt to
remove cached extents when a conversion from inline to extent storage
has been initiated (!EXT4_STATE_MAY_INLINE_DATA).  This avoids
unnecessary es lock overhead in the more common inline case.

Signed-off-by: Eric Whitney <enwlinux@gmail.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Link: https://lore.kernel.org/r/20210819144927.25163-2-enwlinux@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/inline.c

index 50a3031bf466d3b3ba546f812915239ec643d2b6..39a1ab129fdc94b2caa18a7febe8a5b0f8ffa7b4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/iomap.h>
 #include <linux/fiemap.h>
 #include <linux/iversion.h>
+#include <linux/backing-dev.h>
 
 #include "ext4_jbd2.h"
 #include "ext4.h"
@@ -1918,6 +1919,24 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline)
        EXT4_I(inode)->i_disksize = i_size;
 
        if (i_size < inline_size) {
+               /*
+                * if there's inline data to truncate and this file was
+                * converted to extents after that inline data was written,
+                * the extent status cache must be cleared to avoid leaving
+                * behind stale delayed allocated extent entries
+                */
+               if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
+retry:
+                       err = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
+                       if (err == -ENOMEM) {
+                               cond_resched();
+                               congestion_wait(BLK_RW_ASYNC, HZ/50);
+                               goto retry;
+                       }
+                       if (err)
+                               goto out_error;
+               }
+
                /* Clear the content in the xattr space. */
                if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
                        if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0)