diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index a3374c1a3d411a79ec78e0d76c9df51a1529aed0..a9d3a2208506a2e568f8270397c7c26db754160f 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -63,14 +63,25 @@ void jbd2_journal_free_transaction(transaction_t *transaction)
 }
 
 /*
- * We reserve t_outstanding_credits >> JBD2_CONTROL_BLOCKS_SHIFT for
- * transaction descriptor blocks.
+ * Base amount of descriptor blocks we reserve for each transaction.
  */
-#define JBD2_CONTROL_BLOCKS_SHIFT 5
-
 static int jbd2_descriptor_blocks_per_trans(journal_t *journal)
 {
-	return journal->j_max_transaction_buffers >> JBD2_CONTROL_BLOCKS_SHIFT;
+	int tag_space = journal->j_blocksize - sizeof(journal_header_t);
+	int tags_per_block;
+
+	/* Subtract UUID */
+	tag_space -= 16;
+	if (jbd2_journal_has_csum_v2or3(journal))
+		tag_space -= sizeof(struct jbd2_journal_block_tail);
+	/* Commit code leaves a slack space of 16 bytes at the end of block */
+	tags_per_block = (tag_space - 16) / journal_tag_bytes(journal);
+	/*
+	 * Revoke descriptors are accounted separately so we need to reserve
+	 * space for commit block and normal transaction descriptor blocks.
+	 */
+	return 1 + DIV_ROUND_UP(journal->j_max_transaction_buffers,
+				tags_per_block);
 }
 
 /*