Commit eabcdba3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:

 - tree-checker catches invalid number of inline extent references

 - zoned mode fixes:
    - enhance zone append IO command so it also detects emulated writes
    - handle bio splitting at sectorsize boundary

 - when deleting a snapshot, fix a condition for visiting nodes in reloc
   trees

* tag 'for-6.13-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: tree-checker: reject inline extent items with 0 ref count
  btrfs: split bios to the fs sector size boundary
  btrfs: use bio_is_zone_append() in the completion handler
  btrfs: fix improper generation check in snapshot delete
parents b69810f3 dfb92681
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -358,7 +358,7 @@ static void btrfs_simple_end_io(struct bio *bio)
		INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
		queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work);
	} else {
		if (bio_op(bio) == REQ_OP_ZONE_APPEND && !bio->bi_status)
		if (bio_is_zone_append(bio) && !bio->bi_status)
			btrfs_record_physical_zoned(bbio);
		btrfs_bio_end_io(bbio, bbio->bio.bi_status);
	}
@@ -401,7 +401,7 @@ static void btrfs_orig_write_end_io(struct bio *bio)
	else
		bio->bi_status = BLK_STS_OK;

	if (bio_op(bio) == REQ_OP_ZONE_APPEND && !bio->bi_status)
	if (bio_is_zone_append(bio) && !bio->bi_status)
		stripe->physical = bio->bi_iter.bi_sector << SECTOR_SHIFT;

	btrfs_bio_end_io(bbio, bbio->bio.bi_status);
@@ -415,7 +415,7 @@ static void btrfs_clone_write_end_io(struct bio *bio)
	if (bio->bi_status) {
		atomic_inc(&stripe->bioc->error);
		btrfs_log_dev_io_error(bio, stripe->dev);
	} else if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
	} else if (bio_is_zone_append(bio)) {
		stripe->physical = bio->bi_iter.bi_sector << SECTOR_SHIFT;
	}

@@ -652,8 +652,14 @@ static u64 btrfs_append_map_length(struct btrfs_bio *bbio, u64 map_length)
	map_length = min(map_length, bbio->fs_info->max_zone_append_size);
	sector_offset = bio_split_rw_at(&bbio->bio, &bbio->fs_info->limits,
					&nr_segs, map_length);
	if (sector_offset)
		return sector_offset << SECTOR_SHIFT;
	if (sector_offset) {
		/*
		 * bio_split_rw_at() could split at a size smaller than our
		 * sectorsize and thus cause unaligned I/Os.  Fix that by
		 * always rounding down to the nearest boundary.
		 */
		return ALIGN_DOWN(sector_offset << SECTOR_SHIFT, bbio->fs_info->sectorsize);
	}
	return map_length;
}

+19 −0
Original line number Diff line number Diff line
@@ -370,6 +370,25 @@ static inline void btrfs_set_root_last_trans(struct btrfs_root *root, u64 transi
	WRITE_ONCE(root->last_trans, transid);
}

/*
 * Return the generation this root started with.
 *
 * Every normal root that is created with root->root_key.offset set to it's
 * originating generation.  If it is a snapshot it is the generation when the
 * snapshot was created.
 *
 * However for TREE_RELOC roots root_key.offset is the objectid of the owning
 * tree root.  Thankfully we copy the root item of the owning tree root, which
 * has it's last_snapshot set to what we would have root_key.offset set to, so
 * return that if this is a TREE_RELOC root.
 */
static inline u64 btrfs_root_origin_generation(const struct btrfs_root *root)
{
	if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID)
		return btrfs_root_last_snapshot(&root->root_item);
	return root->root_key.offset;
}

/*
 * Structure that conveys information about an extent that is going to replace
 * all the extents in a file range.
+3 −3
Original line number Diff line number Diff line
@@ -5285,7 +5285,7 @@ static bool visit_node_for_delete(struct btrfs_root *root, struct walk_control *
	 * reference to it.
	 */
	generation = btrfs_node_ptr_generation(eb, slot);
	if (!wc->update_ref || generation <= root->root_key.offset)
	if (!wc->update_ref || generation <= btrfs_root_origin_generation(root))
		return false;

	/*
@@ -5340,7 +5340,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
			goto reada;

		if (wc->stage == UPDATE_BACKREF &&
		    generation <= root->root_key.offset)
		    generation <= btrfs_root_origin_generation(root))
			continue;

		/* We don't lock the tree block, it's OK to be racy here */
@@ -5683,7 +5683,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
	 * for the subtree
	 */
	if (wc->stage == UPDATE_BACKREF &&
	    generation <= root->root_key.offset) {
	    generation <= btrfs_root_origin_generation(root)) {
		wc->lookup_info = 1;
		return 1;
	}
+26 −1
Original line number Diff line number Diff line
@@ -1527,6 +1527,11 @@ static int check_extent_item(struct extent_buffer *leaf,
					   dref_offset, fs_info->sectorsize);
				return -EUCLEAN;
			}
			if (unlikely(btrfs_extent_data_ref_count(leaf, dref) == 0)) {
				extent_err(leaf, slot,
			"invalid data ref count, should have non-zero value");
				return -EUCLEAN;
			}
			inline_refs += btrfs_extent_data_ref_count(leaf, dref);
			break;
		/* Contains parent bytenr and ref count */
@@ -1539,6 +1544,11 @@ static int check_extent_item(struct extent_buffer *leaf,
					   inline_offset, fs_info->sectorsize);
				return -EUCLEAN;
			}
			if (unlikely(btrfs_shared_data_ref_count(leaf, sref) == 0)) {
				extent_err(leaf, slot,
			"invalid shared data ref count, should have non-zero value");
				return -EUCLEAN;
			}
			inline_refs += btrfs_shared_data_ref_count(leaf, sref);
			break;
		case BTRFS_EXTENT_OWNER_REF_KEY:
@@ -1611,8 +1621,18 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf,
{
	u32 expect_item_size = 0;

	if (key->type == BTRFS_SHARED_DATA_REF_KEY)
	if (key->type == BTRFS_SHARED_DATA_REF_KEY) {
		struct btrfs_shared_data_ref *sref;

		sref = btrfs_item_ptr(leaf, slot, struct btrfs_shared_data_ref);
		if (unlikely(btrfs_shared_data_ref_count(leaf, sref) == 0)) {
			extent_err(leaf, slot,
		"invalid shared data backref count, should have non-zero value");
			return -EUCLEAN;
		}

		expect_item_size = sizeof(struct btrfs_shared_data_ref);
	}

	if (unlikely(btrfs_item_size(leaf, slot) != expect_item_size)) {
		generic_err(leaf, slot,
@@ -1689,6 +1709,11 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
				   offset, leaf->fs_info->sectorsize);
			return -EUCLEAN;
		}
		if (unlikely(btrfs_extent_data_ref_count(leaf, dref) == 0)) {
			extent_err(leaf, slot,
	"invalid extent data backref count, should have non-zero value");
			return -EUCLEAN;
		}
	}
	return 0;
}