Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b64f57d authored by Elena Reshetova's avatar Elena Reshetova Committed by David Sterba
Browse files

btrfs: convert btrfs_transaction.use_count from atomic_t to refcount_t



refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.

Signed-off-by: default avatarElena Reshetova <elena.reshetova@intel.com>
Signed-off-by: default avatarHans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarDavid Windsor <dwindsor@gmail.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 140475ae
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -4615,7 +4615,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info)
		t = list_first_entry(&fs_info->trans_list,
		t = list_first_entry(&fs_info->trans_list,
				     struct btrfs_transaction, list);
				     struct btrfs_transaction, list);
		if (t->state >= TRANS_STATE_COMMIT_START) {
		if (t->state >= TRANS_STATE_COMMIT_START) {
			atomic_inc(&t->use_count);
			refcount_inc(&t->use_count);
			spin_unlock(&fs_info->trans_lock);
			spin_unlock(&fs_info->trans_lock);
			btrfs_wait_for_commit(fs_info, t->transid);
			btrfs_wait_for_commit(fs_info, t->transid);
			btrfs_put_transaction(t);
			btrfs_put_transaction(t);
+1 −1
Original line number Original line Diff line number Diff line
@@ -10850,7 +10850,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
		spin_lock(&fs_info->trans_lock);
		spin_lock(&fs_info->trans_lock);
		trans = fs_info->running_transaction;
		trans = fs_info->running_transaction;
		if (trans)
		if (trans)
			atomic_inc(&trans->use_count);
			refcount_inc(&trans->use_count);
		spin_unlock(&fs_info->trans_lock);
		spin_unlock(&fs_info->trans_lock);


		ret = find_free_dev_extent_start(trans, device, minlen, start,
		ret = find_free_dev_extent_start(trans, device, minlen, start,
+1 −1
Original line number Original line Diff line number Diff line
@@ -623,7 +623,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
		spin_lock(&fs_info->trans_lock);
		spin_lock(&fs_info->trans_lock);
		trans = fs_info->running_transaction;
		trans = fs_info->running_transaction;
		if (trans)
		if (trans)
			atomic_inc(&trans->use_count);
			refcount_inc(&trans->use_count);
		spin_unlock(&fs_info->trans_lock);
		spin_unlock(&fs_info->trans_lock);


		ASSERT(trans);
		ASSERT(trans);
+10 −10
Original line number Original line Diff line number Diff line
@@ -60,8 +60,8 @@ static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {


void btrfs_put_transaction(struct btrfs_transaction *transaction)
void btrfs_put_transaction(struct btrfs_transaction *transaction)
{
{
	WARN_ON(atomic_read(&transaction->use_count) == 0);
	WARN_ON(refcount_read(&transaction->use_count) == 0);
	if (atomic_dec_and_test(&transaction->use_count)) {
	if (refcount_dec_and_test(&transaction->use_count)) {
		BUG_ON(!list_empty(&transaction->list));
		BUG_ON(!list_empty(&transaction->list));
		WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
		WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
		if (transaction->delayed_refs.pending_csums)
		if (transaction->delayed_refs.pending_csums)
@@ -207,7 +207,7 @@ static noinline int join_transaction(struct btrfs_fs_info *fs_info,
			spin_unlock(&fs_info->trans_lock);
			spin_unlock(&fs_info->trans_lock);
			return -EBUSY;
			return -EBUSY;
		}
		}
		atomic_inc(&cur_trans->use_count);
		refcount_inc(&cur_trans->use_count);
		atomic_inc(&cur_trans->num_writers);
		atomic_inc(&cur_trans->num_writers);
		extwriter_counter_inc(cur_trans, type);
		extwriter_counter_inc(cur_trans, type);
		spin_unlock(&fs_info->trans_lock);
		spin_unlock(&fs_info->trans_lock);
@@ -257,7 +257,7 @@ static noinline int join_transaction(struct btrfs_fs_info *fs_info,
	 * One for this trans handle, one so it will live on until we
	 * One for this trans handle, one so it will live on until we
	 * commit the transaction.
	 * commit the transaction.
	 */
	 */
	atomic_set(&cur_trans->use_count, 2);
	refcount_set(&cur_trans->use_count, 2);
	atomic_set(&cur_trans->pending_ordered, 0);
	atomic_set(&cur_trans->pending_ordered, 0);
	cur_trans->flags = 0;
	cur_trans->flags = 0;
	cur_trans->start_time = get_seconds();
	cur_trans->start_time = get_seconds();
@@ -432,7 +432,7 @@ static void wait_current_trans(struct btrfs_fs_info *fs_info)
	spin_lock(&fs_info->trans_lock);
	spin_lock(&fs_info->trans_lock);
	cur_trans = fs_info->running_transaction;
	cur_trans = fs_info->running_transaction;
	if (cur_trans && is_transaction_blocked(cur_trans)) {
	if (cur_trans && is_transaction_blocked(cur_trans)) {
		atomic_inc(&cur_trans->use_count);
		refcount_inc(&cur_trans->use_count);
		spin_unlock(&fs_info->trans_lock);
		spin_unlock(&fs_info->trans_lock);


		wait_event(fs_info->transaction_wait,
		wait_event(fs_info->transaction_wait,
@@ -744,7 +744,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
		list_for_each_entry(t, &fs_info->trans_list, list) {
		list_for_each_entry(t, &fs_info->trans_list, list) {
			if (t->transid == transid) {
			if (t->transid == transid) {
				cur_trans = t;
				cur_trans = t;
				atomic_inc(&cur_trans->use_count);
				refcount_inc(&cur_trans->use_count);
				ret = 0;
				ret = 0;
				break;
				break;
			}
			}
@@ -773,7 +773,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
				if (t->state == TRANS_STATE_COMPLETED)
				if (t->state == TRANS_STATE_COMPLETED)
					break;
					break;
				cur_trans = t;
				cur_trans = t;
				atomic_inc(&cur_trans->use_count);
				refcount_inc(&cur_trans->use_count);
				break;
				break;
			}
			}
		}
		}
@@ -1839,7 +1839,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,


	/* take transaction reference */
	/* take transaction reference */
	cur_trans = trans->transaction;
	cur_trans = trans->transaction;
	atomic_inc(&cur_trans->use_count);
	refcount_inc(&cur_trans->use_count);


	btrfs_end_transaction(trans);
	btrfs_end_transaction(trans);


@@ -2015,7 +2015,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
	spin_lock(&fs_info->trans_lock);
	spin_lock(&fs_info->trans_lock);
	if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
	if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
		spin_unlock(&fs_info->trans_lock);
		spin_unlock(&fs_info->trans_lock);
		atomic_inc(&cur_trans->use_count);
		refcount_inc(&cur_trans->use_count);
		ret = btrfs_end_transaction(trans);
		ret = btrfs_end_transaction(trans);


		wait_for_commit(cur_trans);
		wait_for_commit(cur_trans);
@@ -2035,7 +2035,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
		prev_trans = list_entry(cur_trans->list.prev,
		prev_trans = list_entry(cur_trans->list.prev,
					struct btrfs_transaction, list);
					struct btrfs_transaction, list);
		if (prev_trans->state != TRANS_STATE_COMPLETED) {
		if (prev_trans->state != TRANS_STATE_COMPLETED) {
			atomic_inc(&prev_trans->use_count);
			refcount_inc(&prev_trans->use_count);
			spin_unlock(&fs_info->trans_lock);
			spin_unlock(&fs_info->trans_lock);


			wait_for_commit(prev_trans);
			wait_for_commit(prev_trans);
+3 −1
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@


#ifndef __BTRFS_TRANSACTION__
#ifndef __BTRFS_TRANSACTION__
#define __BTRFS_TRANSACTION__
#define __BTRFS_TRANSACTION__

#include <linux/refcount.h>
#include "btrfs_inode.h"
#include "btrfs_inode.h"
#include "delayed-ref.h"
#include "delayed-ref.h"
#include "ctree.h"
#include "ctree.h"
@@ -49,7 +51,7 @@ struct btrfs_transaction {
	 * transaction can end
	 * transaction can end
	 */
	 */
	atomic_t num_writers;
	atomic_t num_writers;
	atomic_t use_count;
	refcount_t use_count;
	atomic_t pending_ordered;
	atomic_t pending_ordered;


	unsigned long flags;
	unsigned long flags;