]> Pileus Git - ~andy/linux/blobdiff - fs/jbd2/commit.c
jbd2: fix assertion failure in commit code due to lacking transaction credits
[~andy/linux] / fs / jbd2 / commit.c
index af5280fb579bf392f4f3ca58a4c021568655c104..3091d42992f0d934eb4355022efaa5c83ad1be0d 100644 (file)
@@ -1014,17 +1014,35 @@ restart_loop:
                 * there's no point in keeping a checkpoint record for
                 * it. */
 
-               /* A buffer which has been freed while still being
-                * journaled by a previous transaction may end up still
-                * being dirty here, but we want to avoid writing back
-                * that buffer in the future after the "add to orphan"
-                * operation been committed,  That's not only a performance
-                * gain, it also stops aliasing problems if the buffer is
-                * left behind for writeback and gets reallocated for another
-                * use in a different page. */
-               if (buffer_freed(bh) && !jh->b_next_transaction) {
-                       clear_buffer_freed(bh);
-                       clear_buffer_jbddirty(bh);
+               /*
+               * A buffer which has been freed while still being journaled by
+               * a previous transaction.
+               */
+               if (buffer_freed(bh)) {
+                       /*
+                        * If the running transaction is the one containing
+                        * "add to orphan" operation (b_next_transaction !=
+                        * NULL), we have to wait for that transaction to
+                        * commit before we can really get rid of the buffer.
+                        * So just clear b_modified to not confuse transaction
+                        * credit accounting and refile the buffer to
+                        * BJ_Forget of the running transaction. If the just
+                        * committed transaction contains "add to orphan"
+                        * operation, we can completely invalidate the buffer
+                        * now. We are rather through in that since the
+                        * buffer may be still accessible when blocksize <
+                        * pagesize and it is attached to the last partial
+                        * page.
+                        */
+                       jh->b_modified = 0;
+                       if (!jh->b_next_transaction) {
+                               clear_buffer_freed(bh);
+                               clear_buffer_jbddirty(bh);
+                               clear_buffer_mapped(bh);
+                               clear_buffer_new(bh);
+                               clear_buffer_req(bh);
+                               bh->b_bdev = NULL;
+                       }
                }
 
                if (buffer_jbddirty(bh)) {