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

 - protect reading super block vs setting block size externally (found
   by syzbot)

 - make sure no transaction is started in read-only mode even with some
   rescue mount option combinations

 - fix checksum calculation of backup super blocks when block-group-tree
   is enabled

 - more extensive mount-time checks of device items that could be left
   after device replace and attempting degraded mount

 - fix build warning with -Wmaybe-uninitialized on loongarch64-gcc 12

* tag 'for-6.19-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: add extra device item checks at mount
  btrfs: fix missing fields in superblock backup with BLOCK_GROUP_TREE
  btrfs: reject new transactions if the fs is fully read-only
  btrfs: sync read disk super and set block size
  btrfs: fix Wmaybe-uninitialized warning in replay_one_buffer()
parents 6c790212 34308187
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -1661,7 +1661,7 @@ static void backup_super_roots(struct btrfs_fs_info *info)
	btrfs_set_backup_chunk_root_level(root_backup,
			       btrfs_header_level(info->chunk_root->node));

	if (!btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE)) {
	if (!btrfs_fs_incompat(info, EXTENT_TREE_V2)) {
		struct btrfs_root *extent_root = btrfs_extent_root(info, 0);
		struct btrfs_root *csum_root = btrfs_csum_root(info, 0);

@@ -3255,6 +3255,15 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
	return 0;
}

static bool fs_is_full_ro(const struct btrfs_fs_info *fs_info)
{
	if (!sb_rdonly(fs_info->sb))
		return false;
	if (unlikely(fs_info->mount_opt & BTRFS_MOUNT_FULL_RO_MASK))
		return true;
	return false;
}

int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices)
{
	u32 sectorsize;
@@ -3363,6 +3372,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
	if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
		WRITE_ONCE(fs_info->fs_error, -EUCLEAN);

	/* If the fs has any rescue options, no transaction is allowed. */
	if (fs_is_full_ro(fs_info))
		WRITE_ONCE(fs_info->fs_error, -EROFS);

	/* Set up fs_info before parsing mount options */
	nodesize = btrfs_super_nodesize(disk_super);
	sectorsize = btrfs_super_sectorsize(disk_super);
@@ -3489,6 +3502,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
	    fs_info->generation == btrfs_super_uuid_tree_generation(disk_super))
		set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags);

	if (unlikely(btrfs_verify_dev_items(fs_info))) {
		ret = -EUCLEAN;
		goto fail_block_groups;
	}
	ret = btrfs_verify_dev_extents(fs_info);
	if (ret) {
		btrfs_err(fs_info,
+8 −0
Original line number Diff line number Diff line
@@ -264,6 +264,14 @@ enum {
	BTRFS_MOUNT_REF_TRACKER			= (1ULL << 33),
};

/* These mount options require a full read-only fs, no new transaction is allowed. */
#define BTRFS_MOUNT_FULL_RO_MASK		\
	(BTRFS_MOUNT_NOLOGREPLAY |		\
	 BTRFS_MOUNT_IGNOREBADROOTS |		\
	 BTRFS_MOUNT_IGNOREDATACSUMS |		\
	 BTRFS_MOUNT_IGNOREMETACSUMS |		\
	 BTRFS_MOUNT_IGNORESUPERFLAGS)

/*
 * Compat flags that we support.  If any incompat flags are set other than the
 * ones specified below then we will fail to mount
+1 −1
Original line number Diff line number Diff line
@@ -2798,7 +2798,7 @@ static int replay_one_buffer(struct extent_buffer *eb,

	nritems = btrfs_header_nritems(eb);
	for (wc->log_slot = 0; wc->log_slot < nritems; wc->log_slot++) {
		struct btrfs_inode_item *inode_item;
		struct btrfs_inode_item *inode_item = NULL;

		btrfs_item_key_to_cpu(eb, &wc->log_key, wc->log_slot);

+42 −0
Original line number Diff line number Diff line
@@ -1364,7 +1364,9 @@ struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev,
				      (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT);
	}

	filemap_invalidate_lock(mapping);
	page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS);
	filemap_invalidate_unlock(mapping);
	if (IS_ERR(page))
		return ERR_CAST(page);

@@ -7257,6 +7259,7 @@ static int read_one_dev(struct extent_buffer *leaf,
			return -EINVAL;
		}
	}
	set_bit(BTRFS_DEV_STATE_ITEM_FOUND, &device->dev_state);
	set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
	if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
	   !test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
@@ -8082,6 +8085,45 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info)
	return verify_chunk_dev_extent_mapping(fs_info);
}

/*
 * Ensure that all devices registered in the fs have their device items in the
 * chunk tree.
 *
 * Return true if unexpected device is found.
 * Return false otherwise.
 */
bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info)
{
	struct btrfs_fs_devices *seed_devs;
	struct btrfs_device *dev;
	bool ret = false;

	mutex_lock(&uuid_mutex);
	list_for_each_entry(dev, &fs_info->fs_devices->devices, dev_list) {
		if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) {
			btrfs_err(fs_info,
			"devid %llu path %s is registered but not found in chunk tree",
				  dev->devid, btrfs_dev_name(dev));
			ret = true;
		}
	}
	list_for_each_entry(seed_devs, &fs_info->fs_devices->seed_list, seed_list) {
		list_for_each_entry(dev, &seed_devs->devices, dev_list) {
			if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) {
				btrfs_err(fs_info,
			"devid %llu path %s is registered but not found in chunk tree",
					  dev->devid, btrfs_dev_name(dev));
				ret = true;
			}
		}
	}
	mutex_unlock(&uuid_mutex);
	if (ret)
		btrfs_err(fs_info,
"remove the above devices or use 'btrfs device scan --forget <dev>' to unregister them before mount");
	return ret;
}

/*
 * Check whether the given block group or device is pinned by any inode being
 * used as a swapfile.
+4 −0
Original line number Diff line number Diff line
@@ -100,6 +100,9 @@ enum btrfs_raid_types {
#define BTRFS_DEV_STATE_FLUSH_SENT	(4)
#define BTRFS_DEV_STATE_NO_READA	(5)

/* Set when the device item is found in chunk tree, used to catch unexpected registered device. */
#define BTRFS_DEV_STATE_ITEM_FOUND	(7)

/* Special value encoding failure to write primary super block. */
#define BTRFS_SUPER_PRIMARY_WRITE_ERROR		(INT_MAX / 2)

@@ -893,6 +896,7 @@ enum btrfs_raid_types __attribute_const__ btrfs_bg_flags_to_raid_index(u64 flags
int btrfs_bg_type_to_factor(u64 flags);
const char *btrfs_bg_type_to_raid_name(u64 flags);
int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info);
bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info);
bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical);

bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr);