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

 - fix quota root leak after quota disable failure

 - fix condition when checking if a zone can be added as free

 - allocate inode in NOFS context during logging or tree-log replay

 - handle raid-stripe-tree lookup correctly during scrub

* tag 'for-6.10-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: qgroup: fix quota root leak after quota disable failure
  btrfs: scrub: handle RST lookup error correctly
  btrfs: zoned: fix initial free space detection
  btrfs: use NOFS context when getting inodes during logging and log replay
parents fd19d4a4 a7e4c6a3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2697,7 +2697,7 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
	u64 offset = bytenr - block_group->start;
	u64 to_free, to_unusable;
	int bg_reclaim_threshold = 0;
	bool initial = (size == block_group->length);
	bool initial = ((size == block_group->length) && (block_group->alloc_offset == 0));
	u64 reclaimable_unusable;

	WARN_ON(!initial && offset + size > block_group->zone_capacity);
+2 −2
Original line number Diff line number Diff line
@@ -1351,7 +1351,7 @@ static int flush_reservations(struct btrfs_fs_info *fs_info)

int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
{
	struct btrfs_root *quota_root;
	struct btrfs_root *quota_root = NULL;
	struct btrfs_trans_handle *trans = NULL;
	int ret = 0;

@@ -1449,9 +1449,9 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
	btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
			      quota_root->node, 0, 1);

	btrfs_put_root(quota_root);

out:
	btrfs_put_root(quota_root);
	mutex_unlock(&fs_info->qgroup_ioctl_lock);
	if (ret && trans)
		btrfs_end_transaction(trans);
+14 −10
Original line number Diff line number Diff line
@@ -1688,20 +1688,24 @@ static void scrub_submit_extent_sector_read(struct scrub_ctx *sctx,
					    (i << fs_info->sectorsize_bits);
			int err;

			bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ,
					       fs_info, scrub_read_endio, stripe);
			bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;

			io_stripe.is_scrub = true;
			stripe_len = (nr_sectors - i) << fs_info->sectorsize_bits;
			/*
			 * For RST cases, we need to manually split the bbio to
			 * follow the RST boundary.
			 */
			err = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical,
					      &stripe_len, &bioc, &io_stripe,
					      &mirror);
					      &stripe_len, &bioc, &io_stripe, &mirror);
			btrfs_put_bioc(bioc);
			if (err) {
				btrfs_bio_end_io(bbio,
						 errno_to_blk_status(err));
				return;
			if (err < 0) {
				set_bit(i, &stripe->io_error_bitmap);
				set_bit(i, &stripe->error_bitmap);
				continue;
			}

			bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ,
					       fs_info, scrub_read_endio, stripe);
			bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;
		}

		__bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
+28 −15
Original line number Diff line number Diff line
@@ -138,6 +138,25 @@ static void wait_log_commit(struct btrfs_root *root, int transid);
 * and once to do all the other items.
 */

static struct inode *btrfs_iget_logging(u64 objectid, struct btrfs_root *root)
{
	unsigned int nofs_flag;
	struct inode *inode;

	/*
	 * We're holding a transaction handle whether we are logging or
	 * replaying a log tree, so we must make sure NOFS semantics apply
	 * because btrfs_alloc_inode() may be triggered and it uses GFP_KERNEL
	 * to allocate an inode, which can recurse back into the filesystem and
	 * attempt a transaction commit, resulting in a deadlock.
	 */
	nofs_flag = memalloc_nofs_save();
	inode = btrfs_iget(root->fs_info->sb, objectid, root);
	memalloc_nofs_restore(nofs_flag);

	return inode;
}

/*
 * start a sub transaction and setup the log tree
 * this increments the log tree writer count to make the people
@@ -600,7 +619,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root,
{
	struct inode *inode;

	inode = btrfs_iget(root->fs_info->sb, objectid, root);
	inode = btrfs_iget_logging(objectid, root);
	if (IS_ERR(inode))
		inode = NULL;
	return inode;
@@ -5438,7 +5457,6 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
				struct btrfs_log_ctx *ctx)
{
	struct btrfs_root *root = start_inode->root;
	struct btrfs_fs_info *fs_info = root->fs_info;
	struct btrfs_path *path;
	LIST_HEAD(dir_list);
	struct btrfs_dir_list *dir_elem;
@@ -5499,7 +5517,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
				continue;

			btrfs_release_path(path);
			di_inode = btrfs_iget(fs_info->sb, di_key.objectid, root);
			di_inode = btrfs_iget_logging(di_key.objectid, root);
			if (IS_ERR(di_inode)) {
				ret = PTR_ERR(di_inode);
				goto out;
@@ -5559,7 +5577,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
		btrfs_add_delayed_iput(curr_inode);
		curr_inode = NULL;

		vfs_inode = btrfs_iget(fs_info->sb, ino, root);
		vfs_inode = btrfs_iget_logging(ino, root);
		if (IS_ERR(vfs_inode)) {
			ret = PTR_ERR(vfs_inode);
			break;
@@ -5654,7 +5672,7 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
	if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES)
		return BTRFS_LOG_FORCE_COMMIT;

	inode = btrfs_iget(root->fs_info->sb, ino, root);
	inode = btrfs_iget_logging(ino, root);
	/*
	 * If the other inode that had a conflicting dir entry was deleted in
	 * the current transaction then we either:
@@ -5755,7 +5773,6 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
				  struct btrfs_root *root,
				  struct btrfs_log_ctx *ctx)
{
	struct btrfs_fs_info *fs_info = root->fs_info;
	int ret = 0;

	/*
@@ -5786,7 +5803,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
		list_del(&curr->list);
		kfree(curr);

		inode = btrfs_iget(fs_info->sb, ino, root);
		inode = btrfs_iget_logging(ino, root);
		/*
		 * If the other inode that had a conflicting dir entry was
		 * deleted in the current transaction, we need to log its parent
@@ -5797,7 +5814,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
			if (ret != -ENOENT)
				break;

			inode = btrfs_iget(fs_info->sb, parent, root);
			inode = btrfs_iget_logging(parent, root);
			if (IS_ERR(inode)) {
				ret = PTR_ERR(inode);
				break;
@@ -6319,7 +6336,6 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
				    struct btrfs_log_ctx *ctx)
{
	const bool orig_log_new_dentries = ctx->log_new_dentries;
	struct btrfs_fs_info *fs_info = trans->fs_info;
	struct btrfs_delayed_item *item;
	int ret = 0;

@@ -6345,7 +6361,7 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
		if (key.type == BTRFS_ROOT_ITEM_KEY)
			continue;

		di_inode = btrfs_iget(fs_info->sb, key.objectid, inode->root);
		di_inode = btrfs_iget_logging(key.objectid, inode->root);
		if (IS_ERR(di_inode)) {
			ret = PTR_ERR(di_inode);
			break;
@@ -6729,7 +6745,6 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
				 struct btrfs_inode *inode,
				 struct btrfs_log_ctx *ctx)
{
	struct btrfs_fs_info *fs_info = trans->fs_info;
	int ret;
	struct btrfs_path *path;
	struct btrfs_key key;
@@ -6794,8 +6809,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
				cur_offset = item_size;
			}

			dir_inode = btrfs_iget(fs_info->sb, inode_key.objectid,
					       root);
			dir_inode = btrfs_iget_logging(inode_key.objectid, root);
			/*
			 * If the parent inode was deleted, return an error to
			 * fallback to a transaction commit. This is to prevent
@@ -6857,7 +6871,6 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
	btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);

	while (true) {
		struct btrfs_fs_info *fs_info = root->fs_info;
		struct extent_buffer *leaf;
		int slot;
		struct btrfs_key search_key;
@@ -6872,7 +6885,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
		search_key.objectid = found_key.offset;
		search_key.type = BTRFS_INODE_ITEM_KEY;
		search_key.offset = 0;
		inode = btrfs_iget(fs_info->sb, ino, root);
		inode = btrfs_iget_logging(ino, root);
		if (IS_ERR(inode))
			return PTR_ERR(inode);