*/
        struct lockdep_map btrfs_trans_num_writers_map;
        struct lockdep_map btrfs_trans_num_extwriters_map;
+       struct lockdep_map btrfs_state_change_map[4];
 
 #ifdef CONFIG_BTRFS_FS_REF_VERIFY
        spinlock_t ref_verify_lock;
        BTRFS_ROOT_RESET_LOCKDEP_CLASS,
 };
 
+enum btrfs_lockdep_trans_states {
+       BTRFS_LOCKDEP_TRANS_COMMIT_START,
+       BTRFS_LOCKDEP_TRANS_UNBLOCKED,
+       BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED,
+       BTRFS_LOCKDEP_TRANS_COMPLETED,
+};
+
 /*
  * Lockdep annotation for wait events.
  *
 #define btrfs_lockdep_release(owner, lock)                                     \
        rwsem_release(&owner->lock##_map, _THIS_IP_)
 
+/*
+ * Macros for the transaction states wait events, similar to the generic wait
+ * event macros.
+ */
+#define btrfs_might_wait_for_state(owner, i)                                   \
+       do {                                                                    \
+               rwsem_acquire(&owner->btrfs_state_change_map[i], 0, 0, _THIS_IP_); \
+               rwsem_release(&owner->btrfs_state_change_map[i], _THIS_IP_);    \
+       } while (0)
+
+#define btrfs_trans_state_lockdep_acquire(owner, i)                            \
+       rwsem_acquire_read(&owner->btrfs_state_change_map[i], 0, 0, _THIS_IP_)
+
+#define btrfs_trans_state_lockdep_release(owner, i)                            \
+       rwsem_release(&owner->btrfs_state_change_map[i], _THIS_IP_)
+
 /* Initialization of the lockdep map */
 #define btrfs_lockdep_init_map(owner, lock)                                    \
        do {                                                                    \
                lockdep_init_map(&owner->lock##_map, #lock, &lock##_key, 0);    \
        } while (0)
 
+/* Initialization of the transaction states lockdep maps. */
+#define btrfs_state_lockdep_init_map(owner, lock, state)                       \
+       do {                                                                    \
+               static struct lock_class_key lock##_key;                        \
+               lockdep_init_map(&owner->btrfs_state_change_map[state], #lock,  \
+                                &lock##_key, 0);                               \
+       } while (0)
+
 static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
 {
        clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
 
                refcount_inc(&cur_trans->use_count);
                spin_unlock(&fs_info->trans_lock);
 
+               btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
                wait_event(fs_info->transaction_wait,
                           cur_trans->state >= TRANS_STATE_UNBLOCKED ||
                           TRANS_ABORTED(cur_trans));
        u64 transid = commit->transid;
        bool put = false;
 
+       /*
+        * At the moment this function is called with min_state either being
+        * TRANS_STATE_COMPLETED or TRANS_STATE_SUPER_COMMITTED.
+        */
+       if (min_state == TRANS_STATE_COMPLETED)
+               btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
+       else
+               btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
+
        while (1) {
                wait_event(commit->commit_wait, commit->state >= min_state);
                if (put)
         * Wait for the current transaction commit to start and block
         * subsequent transaction joins
         */
+       btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_START);
        wait_event(fs_info->transaction_blocked_wait,
                   cur_trans->state >= TRANS_STATE_COMMIT_START ||
                   TRANS_ABORTED(cur_trans));
        ktime_t interval;
 
        ASSERT(refcount_read(&trans->use_count) == 1);
+       btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_START);
 
        /* Stop the commit early if ->aborted is set */
        if (TRANS_ABORTED(cur_trans)) {
                ret = cur_trans->aborted;
-               btrfs_end_transaction(trans);
-               return ret;
+               goto lockdep_trans_commit_start_release;
        }
 
        btrfs_trans_release_metadata(trans);
                 * Any running threads may add more while we are here.
                 */
                ret = btrfs_run_delayed_refs(trans, 0);
-               if (ret) {
-                       btrfs_end_transaction(trans);
-                       return ret;
-               }
+               if (ret)
+                       goto lockdep_trans_commit_start_release;
        }
 
        btrfs_create_pending_block_groups(trans);
 
                if (run_it) {
                        ret = btrfs_start_dirty_block_groups(trans);
-                       if (ret) {
-                               btrfs_end_transaction(trans);
-                               return ret;
-                       }
+                       if (ret)
+                               goto lockdep_trans_commit_start_release;
                }
        }
 
 
                if (trans->in_fsync)
                        want_state = TRANS_STATE_SUPER_COMMITTED;
+
+               btrfs_trans_state_lockdep_release(fs_info,
+                                                 BTRFS_LOCKDEP_TRANS_COMMIT_START);
                ret = btrfs_end_transaction(trans);
                wait_for_commit(cur_trans, want_state);
 
 
        cur_trans->state = TRANS_STATE_COMMIT_START;
        wake_up(&fs_info->transaction_blocked_wait);
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_START);
 
        if (cur_trans->list.prev != &fs_info->trans_list) {
                enum btrfs_trans_state want_state = TRANS_STATE_COMPLETED;
        wait_event(cur_trans->writer_wait,
                   atomic_read(&cur_trans->num_writers) == 1);
 
+       /*
+        * Make lockdep happy by acquiring the state locks after
+        * btrfs_trans_num_writers is released. If we acquired the state locks
+        * before releasing the btrfs_trans_num_writers lock then lockdep would
+        * complain because we did not follow the reverse order unlocking rule.
+        */
+       btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
+       btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
+       btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
+
        /*
         * We've started the commit, clear the flag in case we were triggered to
         * do an async commit but somebody else started before the transaction
 
        if (TRANS_ABORTED(cur_trans)) {
                ret = cur_trans->aborted;
+               btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
                goto scrub_continue;
        }
        /*
        mutex_unlock(&fs_info->reloc_mutex);
 
        wake_up(&fs_info->transaction_wait);
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
 
        ret = btrfs_write_and_wait_transaction(trans);
        if (ret) {
         */
        cur_trans->state = TRANS_STATE_SUPER_COMMITTED;
        wake_up(&cur_trans->commit_wait);
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
 
        btrfs_finish_extent_commit(trans);
 
         */
        cur_trans->state = TRANS_STATE_COMPLETED;
        wake_up(&cur_trans->commit_wait);
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
 
        spin_lock(&fs_info->trans_lock);
        list_del_init(&cur_trans->list);
 
 unlock_reloc:
        mutex_unlock(&fs_info->reloc_mutex);
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
 scrub_continue:
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
        btrfs_scrub_continue(fs_info);
 cleanup_transaction:
        btrfs_trans_release_metadata(trans);
        btrfs_lockdep_release(fs_info, btrfs_trans_num_extwriters);
        btrfs_lockdep_release(fs_info, btrfs_trans_num_writers);
        goto cleanup_transaction;
+
+lockdep_trans_commit_start_release:
+       btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_START);
+       btrfs_end_transaction(trans);
+       return ret;
 }
 
 /*