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

 - detect possible file name hash collision earlier so it does not lead
   to transaction abort

 - handle b-tree leaf overflows when snapshotting a subvolume with set
   received UUID, leading to transaction abort

 - in zoned mode, reorder relocation block group initialization after
   the transaction kthread start

 - fix orphan cleanup state tracking of subvolume, this could lead to
   invalid dentries under some conditions

 - add locking around updates of dynamic reclain state update

 - in subpage mode, add missing RCU unlock when trying to releae extent
   buffer

 - remap tree fixes:
     - add missing description strings for the newly added remap tree
     - properly update search key when iterating backrefs

* tag 'for-7.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: remove duplicated definition of btrfs_printk_in_rcu()
  btrfs: remove unnecessary transaction abort in the received subvol ioctl
  btrfs: abort transaction on failure to update root in the received subvol ioctl
  btrfs: fix transaction abort on set received ioctl due to item overflow
  btrfs: fix transaction abort when snapshotting received subvolumes
  btrfs: fix transaction abort on file creation due to name hash collision
  btrfs: read key again after incrementing slot in move_existing_remaps()
  btrfs: add missing RCU unlock in error path in try_release_subpage_extent_buffer()
  btrfs: set BTRFS_ROOT_ORPHAN_CLEANUP during subvol create
  btrfs: zoned: move btrfs_zoned_reserve_data_reloc_bg() after kthread start
  btrfs: hold space_info->lock when clearing periodic reclaim ready
  btrfs: print-tree: add remap tree definitions
parents 2c7e63d7 0749cab6
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -3594,7 +3594,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
		}
	}

	btrfs_zoned_reserve_data_reloc_bg(fs_info);
	btrfs_free_zone_cache(fs_info);

	btrfs_check_active_zone_reservation(fs_info);
@@ -3622,6 +3621,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
		goto fail_cleaner;
	}

	/*
	 * Starts a transaction, must be called after the transaction kthread
	 * is initialized.
	 */
	btrfs_zoned_reserve_data_reloc_bg(fs_info);

	ret = btrfs_read_qgroup_config(fs_info);
	if (ret)
		goto fail_trans_kthread;
+1 −0
Original line number Diff line number Diff line
@@ -4507,6 +4507,7 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
		 */
		if (!test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
			spin_unlock(&eb->refs_lock);
			rcu_read_lock();
			break;
		}

+19 −0
Original line number Diff line number Diff line
@@ -6612,6 +6612,25 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
	int ret;
	bool xa_reserved = false;

	if (!args->orphan && !args->subvol) {
		/*
		 * Before anything else, check if we can add the name to the
		 * parent directory. We want to avoid a dir item overflow in
		 * case we have an existing dir item due to existing name
		 * hash collisions. We do this check here before we call
		 * btrfs_add_link() down below so that we can avoid a
		 * transaction abort (which could be exploited by malicious
		 * users).
		 *
		 * For subvolumes we already do this in btrfs_mksubvol().
		 */
		ret = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
						     btrfs_ino(BTRFS_I(dir)),
						     name);
		if (ret < 0)
			return ret;
	}

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
+28 −4
Original line number Diff line number Diff line
@@ -672,6 +672,13 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
		goto out;
	}

	/*
	 * Subvolumes have orphans cleaned on first dentry lookup. A new
	 * subvolume cannot have any orphans, so we should set the bit before we
	 * add the subvolume dentry to the dentry cache, so that it is in the
	 * same state as a subvolume after first lookup.
	 */
	set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &new_root->state);
	d_instantiate_new(dentry, new_inode_args.inode);
	new_inode_args.inode = NULL;

@@ -3852,6 +3859,25 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
		goto out;
	}

	received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
				       BTRFS_UUID_SIZE);

	/*
	 * Before we attempt to add the new received uuid, check if we have room
	 * for it in case there's already an item. If the size of the existing
	 * item plus this root's ID (u64) exceeds the maximum item size, we can
	 * return here without the need to abort a transaction. If we don't do
	 * this check, the btrfs_uuid_tree_add() call below would fail with
	 * -EOVERFLOW and result in a transaction abort. Malicious users could
	 * exploit this to turn the fs into RO mode.
	 */
	if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
		ret = btrfs_uuid_tree_check_overflow(fs_info, sa->uuid,
						     BTRFS_UUID_KEY_RECEIVED_SUBVOL);
		if (ret < 0)
			goto out;
	}

	/*
	 * 1 - root item
	 * 2 - uuid items (received uuid + subvol uuid)
@@ -3867,15 +3893,12 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
	sa->rtime.sec = ct.tv_sec;
	sa->rtime.nsec = ct.tv_nsec;

	received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
				       BTRFS_UUID_SIZE);
	if (received_uuid_changed &&
	    !btrfs_is_empty_uuid(root_item->received_uuid)) {
		ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
					  BTRFS_UUID_KEY_RECEIVED_SUBVOL,
					  btrfs_root_id(root));
		if (unlikely(ret && ret != -ENOENT)) {
		        btrfs_abort_transaction(trans, ret);
		        btrfs_end_transaction(trans);
		        goto out;
		}
@@ -3890,7 +3913,8 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,

	ret = btrfs_update_root(trans, fs_info->tree_root,
				&root->root_key, &root->root_item);
	if (ret < 0) {
	if (unlikely(ret < 0)) {
		btrfs_abort_transaction(trans, ret);
		btrfs_end_transaction(trans);
		goto out;
	}
+0 −3
Original line number Diff line number Diff line
@@ -28,9 +28,6 @@ void _btrfs_printk(const struct btrfs_fs_info *fs_info, unsigned int level, cons

#else

#define btrfs_printk_in_rcu(fs_info, level, fmt, args...)		\
	btrfs_no_printk(fs_info, fmt, ##args)

#define btrfs_printk_in_rcu(fs_info, level, fmt, args...)		\
	btrfs_no_printk(fs_info, fmt, ##args)

Loading