Clean up and make try_to_free_buffers() not race with dirty pages
This is preparatory work in our continuing saga on some hard-to-trigger
file corruption with shared writable mmap() after the dirty page
tracking changes (commit d08b3851da etc)
were merged.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
	
	
This commit is contained in:
		
					parent
					
						
							
								9bfb18392e
							
						
					
				
			
			
				commit
				
					
						46d2277c79
					
				
			
		
					 1 changed files with 1 additions and 17 deletions
				
			
		
							
								
								
									
										18
									
								
								fs/buffer.c
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								fs/buffer.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2834,7 +2834,7 @@ int try_to_free_buffers(struct page *page)
 | 
			
		|||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!PageLocked(page));
 | 
			
		||||
	if (PageWriteback(page))
 | 
			
		||||
	if (PageDirty(page) || PageWriteback(page))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (mapping == NULL) {		/* can this still happen? */
 | 
			
		||||
| 
						 | 
				
			
			@ -2845,22 +2845,6 @@ int try_to_free_buffers(struct page *page)
 | 
			
		|||
	spin_lock(&mapping->private_lock);
 | 
			
		||||
	ret = drop_buffers(page, &buffers_to_free);
 | 
			
		||||
	spin_unlock(&mapping->private_lock);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the filesystem writes its buffers by hand (eg ext3)
 | 
			
		||||
		 * then we can have clean buffers against a dirty page.  We
 | 
			
		||||
		 * clean the page here; otherwise later reattachment of buffers
 | 
			
		||||
		 * could encounter a non-uptodate page, which is unresolvable.
 | 
			
		||||
		 * This only applies in the rare case where try_to_free_buffers
 | 
			
		||||
		 * succeeds but the page is not freed.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Also, during truncate, discard_buffer will have marked all
 | 
			
		||||
		 * the page's buffers clean.  We discover that here and clean
 | 
			
		||||
		 * the page also.
 | 
			
		||||
		 */
 | 
			
		||||
		if (test_clear_page_dirty(page))
 | 
			
		||||
			task_io_account_cancelled_write(PAGE_CACHE_SIZE);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	if (buffers_to_free) {
 | 
			
		||||
		struct buffer_head *bh = buffers_to_free;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue