btrfs_err(fs_info,
                        "COW'ing blocks on a fs root that's being dropped");
 
-       if (trans->transaction != fs_info->running_transaction)
-               WARN(1, KERN_CRIT "trans %llu running %llu\n",
-                      trans->transid,
-                      fs_info->running_transaction->transid);
-
-       if (trans->transid != fs_info->generation)
-               WARN(1, KERN_CRIT "trans %llu running %llu\n",
-                      trans->transid, fs_info->generation);
+       /*
+        * COWing must happen through a running transaction, which always
+        * matches the current fs generation (it's a transaction with a state
+        * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+        * into error state to prevent the commit of any transaction.
+        */
+       if (unlikely(trans->transaction != fs_info->running_transaction ||
+                    trans->transid != fs_info->generation)) {
+               btrfs_abort_transaction(trans, -EUCLEAN);
+               btrfs_crit(fs_info,
+"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
+                          buf->start, btrfs_root_id(root), trans->transid,
+                          fs_info->running_transaction->transid,
+                          fs_info->generation);
+               return -EUCLEAN;
+       }
 
        if (!should_cow_block(trans, root, buf)) {
                *cow_ret = buf;