diff options
Diffstat (limited to 'mm/filemap.c')
| -rw-r--r-- | mm/filemap.c | 26 | 
1 files changed, 22 insertions, 4 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index d5e7c2029d16..0b2067b3c328 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1484,11 +1484,19 @@ void end_page_writeback(struct page *page)  		rotate_reclaimable_page(page);  	} +	/* +	 * Writeback does not hold a page reference of its own, relying +	 * on truncation to wait for the clearing of PG_writeback. +	 * But here we must make sure that the page is not freed and +	 * reused before the wake_up_page(). +	 */ +	get_page(page);  	if (!test_clear_page_writeback(page))  		BUG();  	smp_mb__after_atomic();  	wake_up_page(page, PG_writeback); +	put_page(page);  }  EXPORT_SYMBOL(end_page_writeback); @@ -2347,10 +2355,15 @@ page_ok:  page_not_up_to_date:  		/* Get exclusive access to the page ... */ -		if (iocb->ki_flags & IOCB_WAITQ) +		if (iocb->ki_flags & IOCB_WAITQ) { +			if (written) { +				put_page(page); +				goto out; +			}  			error = lock_page_async(page, iocb->ki_waitq); -		else +		} else {  			error = lock_page_killable(page); +		}  		if (unlikely(error))  			goto readpage_error; @@ -2393,10 +2406,15 @@ readpage:  		}  		if (!PageUptodate(page)) { -			if (iocb->ki_flags & IOCB_WAITQ) +			if (iocb->ki_flags & IOCB_WAITQ) { +				if (written) { +					put_page(page); +					goto out; +				}  				error = lock_page_async(page, iocb->ki_waitq); -			else +			} else {  				error = lock_page_killable(page); +			}  			if (unlikely(error))  				goto readpage_error;  | 
