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

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
...@@ -4615,7 +4615,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info) ...@@ -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);
......
...@@ -10850,7 +10850,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, ...@@ -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,
......
...@@ -623,7 +623,7 @@ void btrfs_remove_ordered_extent(struct inode *inode, ...@@ -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);
......
...@@ -60,8 +60,8 @@ static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -18,6 +18,8 @@ ...@@ -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 { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment