]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: add extra sanity checks for create_io_em()
authorQu Wenruo <wqu@suse.com>
Wed, 3 Apr 2024 00:00:06 +0000 (10:30 +1030)
committerDavid Sterba <dsterba@suse.com>
Tue, 7 May 2024 19:31:08 +0000 (21:31 +0200)
The function create_io_em() is called before we submit an IO, to update
the in-memory extent map for the involved range.

This patch changes the following aspects:

- Does not allow BTRFS_ORDERED_NOCOW type
  For real NOCOW (excluding NOCOW writes into preallocated ranges)
  writes, we never call create_io_em(), as we does not need to update
  the extent map at all.

  So remove the sanity check allowing BTRFS_ORDERED_NOCOW type.

- Add extra sanity checks
  * PREALLOC
    - @block_len == len
      For uncompressed writes.

  * REGULAR
    - @block_len == @orig_block_len == @ram_bytes == @len
      We're creating a new uncompressed extent, and referring all of it.

    - @orig_start == @start
      We haven no offset inside the extent.

  * COMPRESSED
    - valid @compress_type
    - @len <= @ram_bytes
      This is to co-operate with encoded writes, which can cause a new
      file extent referring only part of a uncompressed extent.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index eb0dc913c33bca4dc1655e7028301c73ae079fc5..3d587b517809314da88aead01b49a8fe0fc75a5f 100644 (file)
@@ -7258,11 +7258,49 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
        struct extent_map *em;
        int ret;
 
+       /*
+        * Note the missing NOCOW type.
+        *
+        * For pure NOCOW writes, we should not create an io extent map, but
+        * just reusing the existing one.
+        * Only PREALLOC writes (NOCOW write into preallocated range) can
+        * create an io extent map.
+        */
        ASSERT(type == BTRFS_ORDERED_PREALLOC ||
               type == BTRFS_ORDERED_COMPRESSED ||
-              type == BTRFS_ORDERED_NOCOW ||
               type == BTRFS_ORDERED_REGULAR);
 
+       switch (type) {
+       case BTRFS_ORDERED_PREALLOC:
+               /* Uncompressed extents. */
+               ASSERT(block_len == len);
+
+               /* We're only referring part of a larger preallocated extent. */
+               ASSERT(block_len <= ram_bytes);
+               break;
+       case BTRFS_ORDERED_REGULAR:
+               /* Uncompressed extents. */
+               ASSERT(block_len == len);
+
+               /* COW results a new extent matching our file extent size. */
+               ASSERT(orig_block_len == len);
+               ASSERT(ram_bytes == len);
+
+               /* Since it's a new extent, we should not have any offset. */
+               ASSERT(orig_start == start);
+               break;
+       case BTRFS_ORDERED_COMPRESSED:
+               /* Must be compressed. */
+               ASSERT(compress_type != BTRFS_COMPRESS_NONE);
+
+               /*
+                * Encoded write can make us to refer to part of the
+                * uncompressed extent.
+                */
+               ASSERT(len <= ram_bytes);
+               break;
+       }
+
        em = alloc_extent_map();
        if (!em)
                return ERR_PTR(-ENOMEM);