Commit 40054463 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:
 "A batch of fixes to simple quotas:

   - add conditional rescheduling point not dependent on the lock during
     inode iterations to avoid delays with PREEMPT_NONE enabled

   - fix subvolume deletion so it does not break the squota invariants

   - properly handle enabling squota, tracking extents in the initial
     transaction

   - catch and warn about underflows, clamp to zero to avoid further
     problems

  And one fix to inode size handling:

   - fix handling of preallocated extents beyond i_size when not using
     the no-holes feature"

* tag 'for-7.1-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: swallow btrfs_record_squota_delta() ENOENT
  btrfs: clamp to avoid squota underflow
  btrfs: fix squota accounting during enable generation
  btrfs: check for subvolume before deleting squota qgroup
  btrfs: always drop root->inodes lock before cond_resched()
  btrfs: mark file extent range dirty after converting prealloc extents
parents f83ef5bc f13342e1
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1246,7 +1246,9 @@ static struct btrfs_inode *find_first_inode_to_shrink(struct btrfs_root *root,
		write_unlock(&tree->lock);
next:
		from = btrfs_ino(inode) + 1;
		cond_resched_lock(&root->inodes.xa_lock);
		xa_unlock(&root->inodes);
		cond_resched();
		xa_lock(&root->inodes);
	}
	xa_unlock(&root->inodes);

+8 −3
Original line number Diff line number Diff line
@@ -633,7 +633,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
							 trans->transid);
			btrfs_set_file_extent_num_bytes(leaf, fi,
							end - other_start);
			return 0;
			goto mark_dirty;
		}
	}

@@ -661,7 +661,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
							other_end - start);
			btrfs_set_file_extent_offset(leaf, fi,
						     start - orig_offset);
			return 0;
			goto mark_dirty;
		}
	}

@@ -788,7 +788,12 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
		}
	}

	return 0;
mark_dirty:
	ret = btrfs_inode_set_file_extent_range(inode, start, end - start);
	if (ret)
		btrfs_abort_transaction(trans, ret);

	return ret;
}

/*
+1 −0
Original line number Diff line number Diff line
@@ -155,6 +155,7 @@ enum {
	BTRFS_FS_LOG_RECOVERING,
	BTRFS_FS_OPEN,
	BTRFS_FS_QUOTA_ENABLED,
	BTRFS_FS_SQUOTA_ENABLING,
	BTRFS_FS_UPDATE_UUID_TREE_GEN,
	BTRFS_FS_CREATING_FREE_SPACE_TREE,
	BTRFS_FS_BTREE_ERR,
+3 −1
Original line number Diff line number Diff line
@@ -10699,7 +10699,9 @@ struct btrfs_inode *btrfs_find_first_inode(struct btrfs_root *root, u64 min_ino)
			break;

		from = btrfs_ino(inode) + 1;
		cond_resched_lock(&root->inodes.xa_lock);
		xa_unlock(&root->inodes);
		cond_resched();
		xa_lock(&root->inodes);
	}
	xa_unlock(&root->inodes);

+68 −33
Original line number Diff line number Diff line
@@ -1107,7 +1107,13 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
	if (simple) {
		fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
		btrfs_set_fs_incompat(fs_info, SIMPLE_QUOTA);
		btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid);
		/*
		 * Set the enable generation to the next transaction, as we cannot
		 * ensure that extents written during this transaction will see any
		 * state we have set here. So we should treat all extents of the
		 * transaction as coming in before squotas was enabled.
		 */
		btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid + 1);
	} else {
		fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
	}
@@ -1210,7 +1216,15 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
		goto out_free_path;
	}

	fs_info->qgroup_enable_gen = trans->transid;
	/*
	 * Set fs_info->qgroup_enable_gen and BTRFS_FS_SQUOTA_ENABLING
	 * under the transaction handle. We want to ensure that all extents in
	 * the next transaction definitely see them.
	 */
	if (simple) {
		fs_info->qgroup_enable_gen = trans->transid + 1;
		set_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
	}

	mutex_unlock(&fs_info->qgroup_ioctl_lock);
	/*
@@ -1224,9 +1238,15 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
	 */
	ret = btrfs_commit_transaction(trans);
	trans = NULL;

	mutex_lock(&fs_info->qgroup_ioctl_lock);
	if (ret)
	if (ret) {
		if (simple) {
			clear_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
			fs_info->qgroup_enable_gen = 0;
		}
		goto out_free_path;
	}

	/*
	 * Set quota enabled flag after committing the transaction, to avoid
@@ -1236,6 +1256,8 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
	spin_lock(&fs_info->qgroup_lock);
	fs_info->quota_root = quota_root;
	set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
	if (simple)
		clear_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
	spin_unlock(&fs_info->qgroup_lock);

	/* Skip rescan for simple qgroups. */
@@ -1715,32 +1737,24 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
	return ret;
}

static bool can_delete_parent_qgroup(struct btrfs_qgroup *qgroup)

static bool can_delete_parent_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup)
{
	ASSERT(btrfs_qgroup_level(qgroup->qgroupid));
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
		squota_check_parent_usage(fs_info, qgroup);
	return list_empty(&qgroup->members);
}

/*
 * Return true if we can delete the squota qgroup and false otherwise.
 *
 * Rules for whether we can delete:
 *
 * A subvolume qgroup can be removed iff the subvolume is fully deleted, which
 * is iff there is 0 usage in the qgroup.
 *
 * A higher level qgroup can be removed iff it has no members.
 * Note: We audit its usage to warn on inconsitencies without blocking deletion.
 * Because a shared extent can outlive its owning subvolume, we cannot delete a
 * subvol squota qgroup until all of the extents it owns are gone, even if the
 * subvolume itself has been deleted.
 */
static bool can_delete_squota_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup)
static bool can_delete_squota_subvol_qgroup(struct btrfs_fs_info *fs_info,
					    struct btrfs_qgroup *qgroup)
{
	ASSERT(btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE);

	if (btrfs_qgroup_level(qgroup->qgroupid) > 0) {
		squota_check_parent_usage(fs_info, qgroup);
		return can_delete_parent_qgroup(qgroup);
	}
	ASSERT(btrfs_qgroup_level(qgroup->qgroupid) == 0);

	return !(qgroup->rfer || qgroup->excl || qgroup->rfer_cmpr || qgroup->excl_cmpr);
}
@@ -1754,14 +1768,11 @@ static int can_delete_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup
{
	struct btrfs_key key;
	BTRFS_PATH_AUTO_FREE(path);

	/* Since squotas cannot be inconsistent, they have special rules for deletion. */
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
		return can_delete_squota_qgroup(fs_info, qgroup);
	int ret;

	/* For higher level qgroup, we can only delete it if it has no child. */
	if (btrfs_qgroup_level(qgroup->qgroupid))
		return can_delete_parent_qgroup(qgroup);
		return can_delete_parent_qgroup(fs_info, qgroup);

	/*
	 * For level-0 qgroups, we can only delete it if it has no subvolume
@@ -1777,10 +1788,21 @@ static int can_delete_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup
		return -ENOMEM;

	/*
	 * The @ret from btrfs_find_root() exactly matches our definition for
	 * the return value, thus can be returned directly.
	 * Any subvol qgroup, regardless of mode, cannot be deleted if the
	 * subvol still exists.
	 */
	ret = btrfs_find_root(fs_info->tree_root, &key, path, NULL, NULL);
	/*
	 * btrfs_find_root returns <0 on error, 0 if found, and >0 if not,
	 * so the "found" and "error" cases match our desired return values.
	 */
	return btrfs_find_root(fs_info->tree_root, &key, path, NULL, NULL);
	if (ret <= 0)
		return ret;

	/* Squotas require additional checks, even if the subvol is deleted. */
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
		return can_delete_squota_subvol_qgroup(fs_info, qgroup);
	return 1;
}

int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
@@ -4922,7 +4944,8 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
	u64 num_bytes = delta->num_bytes;
	const int sign = (delta->is_inc ? 1 : -1);

	if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE)
	if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE &&
	    !test_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags))
		return 0;

	if (!btrfs_is_fstree(root))
@@ -4934,8 +4957,9 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,

	spin_lock(&fs_info->qgroup_lock);
	qgroup = find_qgroup_rb(fs_info, root);
	if (!qgroup) {
		ret = -ENOENT;
	if (WARN_ON_ONCE(!qgroup)) {
		btrfs_warn(fs_info, "squota failed to find qgroup for root %llu", root);
		ret = 0;
		goto out;
	}

@@ -4944,8 +4968,19 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
	list_for_each_entry(qg, &qgroup_list, iterator) {
		struct btrfs_qgroup_list *glist;

		ASSERT(qg->excl == qg->rfer);
		if (WARN_ON_ONCE(sign < 0 && qg->excl < num_bytes)) {
			btrfs_warn(fs_info,
				   "squota underflow qg %hu/%llu excl %llu num_bytes %llu",
				   btrfs_qgroup_level(qg->qgroupid),
				   btrfs_qgroup_subvolid(qg->qgroupid),
				   qg->excl, num_bytes);
			qg->excl = 0;
			qg->rfer = 0;
		} else {
			qg->excl += num_bytes * sign;
			qg->rfer += num_bytes * sign;
		}
		qgroup_dirty(fs_info, qg);

		list_for_each_entry(glist, &qg->groups, next_group)