diff options
Diffstat (limited to 'fs/jbd2/commit.c')
| -rw-r--r-- | fs/jbd2/commit.c | 46 | 
1 files changed, 25 insertions, 21 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 2494095e0340..27373f5792a4 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -976,29 +976,33 @@ restart_loop:  		 * it. */  		/* -		* A buffer which has been freed while still being journaled by -		* a previous transaction. -		*/ -		if (buffer_freed(bh)) { +		 * A buffer which has been freed while still being journaled +		 * by a previous transaction, 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. +		 */ +		if (buffer_freed(bh) && !jh->b_next_transaction) { +			struct address_space *mapping; + +			clear_buffer_freed(bh); +			clear_buffer_jbddirty(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. +			 * Block device buffers need to stay mapped all the +			 * time, so it is enough to clear buffer_jbddirty and +			 * buffer_freed bits. For the file mapping buffers (i.e. +			 * journalled data) we need to unmap buffer and clear +			 * more bits. We also need to be careful about the check +			 * because the data page mapping can get cleared under +			 * out hands, which alse need not to clear more bits +			 * because the page and buffers will be freed and can +			 * never be reused once we are done with them.  			 */ -			jh->b_modified = 0; -			if (!jh->b_next_transaction) { -				clear_buffer_freed(bh); -				clear_buffer_jbddirty(bh); +			mapping = READ_ONCE(bh->b_page->mapping); +			if (mapping && !sb_is_blkdev_sb(mapping->host->i_sb)) {  				clear_buffer_mapped(bh);  				clear_buffer_new(bh);  				clear_buffer_req(bh);  | 
