]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/btrfs/transaction.c
Merge branch 'for-5.4/ish' into for-linus
[linux.git] / fs / btrfs / transaction.c
index 3b8ae1a8f02df77769542a3c0a0782f452c8c791..e3adb714c04b364869e9da5c36e2f9fa0157b7fb 100644 (file)
@@ -28,15 +28,18 @@ static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
        [TRANS_STATE_COMMIT_START]      = (__TRANS_START | __TRANS_ATTACH),
        [TRANS_STATE_COMMIT_DOING]      = (__TRANS_START |
                                           __TRANS_ATTACH |
-                                          __TRANS_JOIN),
+                                          __TRANS_JOIN |
+                                          __TRANS_JOIN_NOSTART),
        [TRANS_STATE_UNBLOCKED]         = (__TRANS_START |
                                           __TRANS_ATTACH |
                                           __TRANS_JOIN |
-                                          __TRANS_JOIN_NOLOCK),
+                                          __TRANS_JOIN_NOLOCK |
+                                          __TRANS_JOIN_NOSTART),
        [TRANS_STATE_COMPLETED]         = (__TRANS_START |
                                           __TRANS_ATTACH |
                                           __TRANS_JOIN |
-                                          __TRANS_JOIN_NOLOCK),
+                                          __TRANS_JOIN_NOLOCK |
+                                          __TRANS_JOIN_NOSTART),
 };
 
 void btrfs_put_transaction(struct btrfs_transaction *transaction)
@@ -543,7 +546,8 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
                ret = join_transaction(fs_info, type);
                if (ret == -EBUSY) {
                        wait_current_trans(fs_info);
-                       if (unlikely(type == TRANS_ATTACH))
+                       if (unlikely(type == TRANS_ATTACH ||
+                                    type == TRANS_JOIN_NOSTART))
                                ret = -ENOENT;
                }
        } while (ret == -EBUSY);
@@ -659,6 +663,16 @@ struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root
                                 BTRFS_RESERVE_NO_FLUSH, true);
 }
 
+/*
+ * Similar to regular join but it never starts a transaction when none is
+ * running or after waiting for the current one to finish.
+ */
+struct btrfs_trans_handle *btrfs_join_transaction_nostart(struct btrfs_root *root)
+{
+       return start_transaction(root, 0, TRANS_JOIN_NOSTART,
+                                BTRFS_RESERVE_NO_FLUSH, true);
+}
+
 /*
  * btrfs_attach_transaction() - catch the running transaction
  *
@@ -2037,6 +2051,16 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
                }
        } else {
                spin_unlock(&fs_info->trans_lock);
+               /*
+                * The previous transaction was aborted and was already removed
+                * from the list of transactions at fs_info->trans_list. So we
+                * abort to prevent writing a new superblock that reflects a
+                * corrupt state (pointing to trees with unwritten nodes/leafs).
+                */
+               if (test_bit(BTRFS_FS_STATE_TRANS_ABORTED, &fs_info->fs_state)) {
+                       ret = -EROFS;
+                       goto cleanup_transaction;
+               }
        }
 
        extwriter_counter_dec(cur_trans, trans->type);