Unverified Commit 406a4071 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!9772 btrfs: fix use-after-free after failure to create a snapshot

parents 1cc61a82 29da3310
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -868,10 +868,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
	btrfs_qgroup_convert_reserved_meta(root, qgroup_reserved);
	qgroup_reserved = 0;

	spin_lock(&fs_info->trans_lock);
	list_add(&pending_snapshot->list,
		 &trans->transaction->pending_snapshots);
	spin_unlock(&fs_info->trans_lock);
	trans->pending_snapshot = pending_snapshot;

	ret = btrfs_commit_transaction(trans);
	if (ret)
+24 −0
Original line number Diff line number Diff line
@@ -2038,6 +2038,27 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
		btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
}

/*
 * Add a pending snapshot associated with the given transaction handle to the
 * respective handle. This must be called after the transaction commit started
 * and while holding fs_info->trans_lock.
 * This serves to guarantee a caller of btrfs_commit_transaction() that it can
 * safely free the pending snapshot pointer in case btrfs_commit_transaction()
 * returns an error.
 */
static void add_pending_snapshot(struct btrfs_trans_handle *trans)
{
	struct btrfs_transaction *cur_trans = trans->transaction;

	if (!trans->pending_snapshot)
		return;

	lockdep_assert_held(&trans->fs_info->trans_lock);
	ASSERT(cur_trans->state >= TRANS_STATE_COMMIT_START);

	list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
}

int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
{
	struct btrfs_fs_info *fs_info = trans->fs_info;
@@ -2124,6 +2145,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)

	spin_lock(&fs_info->trans_lock);
	if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
		add_pending_snapshot(trans);

		spin_unlock(&fs_info->trans_lock);
		refcount_inc(&cur_trans->use_count);
		ret = btrfs_end_transaction(trans);
@@ -2206,6 +2229,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
	 * COMMIT_DOING so make sure to wait for num_writers to == 1 again.
	 */
	spin_lock(&fs_info->trans_lock);
	add_pending_snapshot(trans);
	cur_trans->state = TRANS_STATE_COMMIT_DOING;
	spin_unlock(&fs_info->trans_lock);
	wait_event(cur_trans->writer_wait,
+2 −0
Original line number Diff line number Diff line
@@ -122,6 +122,8 @@ struct btrfs_trans_handle {
	struct btrfs_transaction *transaction;
	struct btrfs_block_rsv *block_rsv;
	struct btrfs_block_rsv *orig_rsv;
	/* Set by a task that wants to create a snapshot. */
	struct btrfs_pending_snapshot *pending_snapshot;
	refcount_t use_count;
	unsigned int type;
	/*