btrfs: convert btrfs_transaction.use_count from atomic_t to refcount_t
authorElena Reshetova <elena.reshetova@intel.com>
Fri, 3 Mar 2017 08:55:11 +0000 (10:55 +0200)
committerDavid Sterba <dsterba@suse.com>
Tue, 18 Apr 2017 12:07:23 +0000 (14:07 +0200)
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: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/ordered-data.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h

index eb1ee7b6f532b74409a6bb50fdb204cb2c8332a1..e4aa64c263f918232d1553e410273c7a8326b367 100644 (file)
@@ -4615,7 +4615,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info)
                t = list_first_entry(&fs_info->trans_list,
                                     struct btrfs_transaction, list);
                if (t->state >= TRANS_STATE_COMMIT_START) {
-                       atomic_inc(&t->use_count);
+                       refcount_inc(&t->use_count);
                        spin_unlock(&fs_info->trans_lock);
                        btrfs_wait_for_commit(fs_info, t->transid);
                        btrfs_put_transaction(t);
index be5477676cc829e4efe89349fc9b7df540fd0dff..85e51f311b57528579a32a74f0bf92d4b8b760ec 100644 (file)
@@ -10850,7 +10850,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
                spin_lock(&fs_info->trans_lock);
                trans = fs_info->running_transaction;
                if (trans)
-                       atomic_inc(&trans->use_count);
+                       refcount_inc(&trans->use_count);
                spin_unlock(&fs_info->trans_lock);
 
                ret = find_free_dev_extent_start(trans, device, minlen, start,
index 9a46878ba60fa973562139f32629810b476ed453..da5399f9fb549fa3fcb5ce024fd73460dc45877e 100644 (file)
@@ -623,7 +623,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
                spin_lock(&fs_info->trans_lock);
                trans = fs_info->running_transaction;
                if (trans)
-                       atomic_inc(&trans->use_count);
+                       refcount_inc(&trans->use_count);
                spin_unlock(&fs_info->trans_lock);
 
                ASSERT(trans);
index 61b807de3e164e38877230cdfd1e9a545573f1be..a7d7a7d1d78a541713500b4e4252596cefea0816 100644 (file)
@@ -60,8 +60,8 @@ static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
 
 void btrfs_put_transaction(struct btrfs_transaction *transaction)
 {
-       WARN_ON(atomic_read(&transaction->use_count) == 0);
-       if (atomic_dec_and_test(&transaction->use_count)) {
+       WARN_ON(refcount_read(&transaction->use_count) == 0);
+       if (refcount_dec_and_test(&transaction->use_count)) {
                BUG_ON(!list_empty(&transaction->list));
                WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
                if (transaction->delayed_refs.pending_csums)
@@ -207,7 +207,7 @@ loop:
                        spin_unlock(&fs_info->trans_lock);
                        return -EBUSY;
                }
-               atomic_inc(&cur_trans->use_count);
+               refcount_inc(&cur_trans->use_count);
                atomic_inc(&cur_trans->num_writers);
                extwriter_counter_inc(cur_trans, type);
                spin_unlock(&fs_info->trans_lock);
@@ -257,7 +257,7 @@ loop:
         * One for this trans handle, one so it will live on until we
         * commit the transaction.
         */
-       atomic_set(&cur_trans->use_count, 2);
+       refcount_set(&cur_trans->use_count, 2);
        atomic_set(&cur_trans->pending_ordered, 0);
        cur_trans->flags = 0;
        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);
        cur_trans = fs_info->running_transaction;
        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);
 
                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) {
                        if (t->transid == transid) {
                                cur_trans = t;
-                               atomic_inc(&cur_trans->use_count);
+                               refcount_inc(&cur_trans->use_count);
                                ret = 0;
                                break;
                        }
@@ -773,7 +773,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
                                if (t->state == TRANS_STATE_COMPLETED)
                                        break;
                                cur_trans = t;
-                               atomic_inc(&cur_trans->use_count);
+                               refcount_inc(&cur_trans->use_count);
                                break;
                        }
                }
@@ -1839,7 +1839,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
 
        /* take transaction reference */
        cur_trans = trans->transaction;
-       atomic_inc(&cur_trans->use_count);
+       refcount_inc(&cur_trans->use_count);
 
        btrfs_end_transaction(trans);
 
@@ -2015,7 +2015,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
        spin_lock(&fs_info->trans_lock);
        if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
                spin_unlock(&fs_info->trans_lock);
-               atomic_inc(&cur_trans->use_count);
+               refcount_inc(&cur_trans->use_count);
                ret = btrfs_end_transaction(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,
                                        struct btrfs_transaction, list);
                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);
 
                        wait_for_commit(prev_trans);
index 5dfb5590fff654a077fd95704682293bfc948a8f..902619f83db650be5c3fafab1cec86d54709f52d 100644 (file)
@@ -18,6 +18,8 @@
 
 #ifndef __BTRFS_TRANSACTION__
 #define __BTRFS_TRANSACTION__
+
+#include <linux/refcount.h>
 #include "btrfs_inode.h"
 #include "delayed-ref.h"
 #include "ctree.h"
@@ -49,7 +51,7 @@ struct btrfs_transaction {
         * transaction can end
         */
        atomic_t num_writers;
-       atomic_t use_count;
+       refcount_t use_count;
        atomic_t pending_ordered;
 
        unsigned long flags;