]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ext4: if zeroout fails fall back to splitting the extent node
authorTheodore Ts'o <tytso@mit.edu>
Fri, 13 Aug 2021 15:20:48 +0000 (11:20 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 31 Aug 2021 03:36:50 +0000 (23:36 -0400)
If the underlying storage device is using thin-provisioning, it's
possible for a zeroout operation to return ENOSPC.

Commit df22291ff0fd ("ext4: Retry block allocation if we have free blocks
left") added logic to retry block allocation since we might get free block
after we commit a transaction. But the ENOSPC from thin-provisioning
will confuse ext4, and lead to an infinite loop.

Since using zeroout instead of splitting the extent node is an
optimization, if it fails, we might as well fall back to splitting the
extent node.

Reported-by: yangerkun <yangerkun@huawei.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/extents.c

index 92ad64b89d9b52e14a7d1295d5c69a59773953de..501516cadc1b3277e720d6e9d26e9e8428292e8d 100644 (file)
@@ -3569,7 +3569,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                                split_map.m_len - ee_block);
                        err = ext4_ext_zeroout(inode, &zero_ex1);
                        if (err)
-                               goto out;
+                               goto fallback;
                        split_map.m_len = allocated;
                }
                if (split_map.m_lblk - ee_block + split_map.m_len <
@@ -3583,7 +3583,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                                                      ext4_ext_pblock(ex));
                                err = ext4_ext_zeroout(inode, &zero_ex2);
                                if (err)
-                                       goto out;
+                                       goto fallback;
                        }
 
                        split_map.m_len += split_map.m_lblk - ee_block;
@@ -3592,6 +3592,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                }
        }
 
+fallback:
        err = ext4_split_extent(handle, inode, ppath, &split_map, split_flag,
                                flags);
        if (err > 0)