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

 - revert device path canonicalization, this does not work as intended
   with namespaces and is not reliable in all setups

 - fix crash in scrub when checksum tree is not valid, e.g. when mounted
   with rescue=ignoredatacsums

 - fix crash when tracepoint btrfs_prelim_ref_insert is enabled

 - other minor fixups:
     - open code folio_index(), meant to be used in MM code
     - use matching type for sizeof in compression allocation

* tag 'for-6.15-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: open code folio_index() in btree_clear_folio_dirty_tag()
  Revert "btrfs: canonicalize the device path before adding it"
  btrfs: avoid NULL pointer dereference if no valid csum tree
  btrfs: handle empty eb->folios in num_extent_folios()
  btrfs: correct the order of prelim_ref arguments in btrfs__prelim_ref
  btrfs: compression: adjust cb->compressed_folios allocation type
parents cccd0337 38e54105
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -606,7 +606,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
	free_extent_map(em);

	cb->nr_folios = DIV_ROUND_UP(compressed_len, PAGE_SIZE);
	cb->compressed_folios = kcalloc(cb->nr_folios, sizeof(struct page *), GFP_NOFS);
	cb->compressed_folios = kcalloc(cb->nr_folios, sizeof(struct folio *), GFP_NOFS);
	if (!cb->compressed_folios) {
		ret = BLK_STS_RESOURCE;
		goto out_free_bio;
+2 −2
Original line number Diff line number Diff line
@@ -3508,8 +3508,8 @@ static void btree_clear_folio_dirty_tag(struct folio *folio)
	ASSERT(folio_test_locked(folio));
	xa_lock_irq(&folio->mapping->i_pages);
	if (!folio_test_dirty(folio))
		__xa_clear_mark(&folio->mapping->i_pages,
				folio_index(folio), PAGECACHE_TAG_DIRTY);
		__xa_clear_mark(&folio->mapping->i_pages, folio->index,
				PAGECACHE_TAG_DIRTY);
	xa_unlock_irq(&folio->mapping->i_pages);
}

+2 −0
Original line number Diff line number Diff line
@@ -298,6 +298,8 @@ static inline int __pure num_extent_pages(const struct extent_buffer *eb)
 */
static inline int __pure num_extent_folios(const struct extent_buffer *eb)
{
	if (!eb->folios[0])
		return 0;
	if (folio_order(eb->folios[0]))
		return 1;
	return num_extent_pages(eb);
+2 −2
Original line number Diff line number Diff line
@@ -1541,8 +1541,8 @@ static int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
	u64 extent_gen;
	int ret;

	if (unlikely(!extent_root)) {
		btrfs_err(fs_info, "no valid extent root for scrub");
	if (unlikely(!extent_root || !csum_root)) {
		btrfs_err(fs_info, "no valid extent or csum root for scrub");
		return -EUCLEAN;
	}
	memset(stripe->sectors, 0, sizeof(struct scrub_sector_verification) *
+1 −90
Original line number Diff line number Diff line
@@ -733,82 +733,6 @@ const u8 *btrfs_sb_fsid_ptr(const struct btrfs_super_block *sb)
	return has_metadata_uuid ? sb->metadata_uuid : sb->fsid;
}

/*
 * We can have very weird soft links passed in.
 * One example is "/proc/self/fd/<fd>", which can be a soft link to
 * a block device.
 *
 * But it's never a good idea to use those weird names.
 * Here we check if the path (not following symlinks) is a good one inside
 * "/dev/".
 */
static bool is_good_dev_path(const char *dev_path)
{
	struct path path = { .mnt = NULL, .dentry = NULL };
	char *path_buf = NULL;
	char *resolved_path;
	bool is_good = false;
	int ret;

	if (!dev_path)
		goto out;

	path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
	if (!path_buf)
		goto out;

	/*
	 * Do not follow soft link, just check if the original path is inside
	 * "/dev/".
	 */
	ret = kern_path(dev_path, 0, &path);
	if (ret)
		goto out;
	resolved_path = d_path(&path, path_buf, PATH_MAX);
	if (IS_ERR(resolved_path))
		goto out;
	if (strncmp(resolved_path, "/dev/", strlen("/dev/")))
		goto out;
	is_good = true;
out:
	kfree(path_buf);
	path_put(&path);
	return is_good;
}

static int get_canonical_dev_path(const char *dev_path, char *canonical)
{
	struct path path = { .mnt = NULL, .dentry = NULL };
	char *path_buf = NULL;
	char *resolved_path;
	int ret;

	if (!dev_path) {
		ret = -EINVAL;
		goto out;
	}

	path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
	if (!path_buf) {
		ret = -ENOMEM;
		goto out;
	}

	ret = kern_path(dev_path, LOOKUP_FOLLOW, &path);
	if (ret)
		goto out;
	resolved_path = d_path(&path, path_buf, PATH_MAX);
	if (IS_ERR(resolved_path)) {
		ret = PTR_ERR(resolved_path);
		goto out;
	}
	ret = strscpy(canonical, resolved_path, PATH_MAX);
out:
	kfree(path_buf);
	path_put(&path);
	return ret;
}

static bool is_same_device(struct btrfs_device *device, const char *new_path)
{
	struct path old = { .mnt = NULL, .dentry = NULL };
@@ -1513,23 +1437,12 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
	bool new_device_added = false;
	struct btrfs_device *device = NULL;
	struct file *bdev_file;
	char *canonical_path = NULL;
	u64 bytenr;
	dev_t devt;
	int ret;

	lockdep_assert_held(&uuid_mutex);

	if (!is_good_dev_path(path)) {
		canonical_path = kmalloc(PATH_MAX, GFP_KERNEL);
		if (canonical_path) {
			ret = get_canonical_dev_path(path, canonical_path);
			if (ret < 0) {
				kfree(canonical_path);
				canonical_path = NULL;
			}
		}
	}
	/*
	 * Avoid an exclusive open here, as the systemd-udev may initiate the
	 * device scan which may race with the user's mount or mkfs command,
@@ -1574,8 +1487,7 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
		goto free_disk_super;
	}

	device = device_list_add(canonical_path ? : path, disk_super,
				 &new_device_added);
	device = device_list_add(path, disk_super, &new_device_added);
	if (!IS_ERR(device) && new_device_added)
		btrfs_free_stale_devices(device->devt, device);

@@ -1584,7 +1496,6 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,

error_bdev_put:
	fput(bdev_file);
	kfree(canonical_path);

	return device;
}
Loading