Commit e98bf64f authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: add extra sanity checks for create_io_em()



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: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 4bdc558b
Loading
Loading
Loading
Loading
+39 −1
Original line number Diff line number Diff line
@@ -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);