diff options
| -rw-r--r-- | fs/fscache/internal.h | 1 | ||||
| -rw-r--r-- | fs/fscache/page.c | 19 | ||||
| -rw-r--r-- | fs/fscache/stats.c | 6 | ||||
| -rw-r--r-- | fs/nfs/write.c | 3 | 
4 files changed, 21 insertions, 8 deletions
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index dcb3e1d5dbf..88a48ccb7d9 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h @@ -200,6 +200,7 @@ extern atomic_t fscache_n_store_vmscan_not_storing;  extern atomic_t fscache_n_store_vmscan_gone;  extern atomic_t fscache_n_store_vmscan_busy;  extern atomic_t fscache_n_store_vmscan_cancelled; +extern atomic_t fscache_n_store_vmscan_wait;  extern atomic_t fscache_n_marks;  extern atomic_t fscache_n_uncaches; diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 4dbbca16262..f9b2fb3ae49 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -56,6 +56,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie,  	_enter("%p,%p,%x", cookie, page, gfp); +try_again:  	rcu_read_lock();  	val = radix_tree_lookup(&cookie->stores, page->index);  	if (!val) { @@ -104,11 +105,19 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie,  	return true;  page_busy: -	/* we might want to wait here, but that could deadlock the allocator as -	 * the work threads writing to the cache may all end up sleeping -	 * on memory allocation */ -	fscache_stat(&fscache_n_store_vmscan_busy); -	return false; +	/* We will wait here if we're allowed to, but that could deadlock the +	 * allocator as the work threads writing to the cache may all end up +	 * sleeping on memory allocation, so we may need to impose a timeout +	 * too. */ +	if (!(gfp & __GFP_WAIT)) { +		fscache_stat(&fscache_n_store_vmscan_busy); +		return false; +	} + +	fscache_stat(&fscache_n_store_vmscan_wait); +	__fscache_wait_on_page_write(cookie, page); +	gfp &= ~__GFP_WAIT; +	goto try_again;  }  EXPORT_SYMBOL(__fscache_maybe_release_page); diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 51cdaee1410..8179e8bc4a3 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c @@ -69,6 +69,7 @@ atomic_t fscache_n_store_vmscan_not_storing;  atomic_t fscache_n_store_vmscan_gone;  atomic_t fscache_n_store_vmscan_busy;  atomic_t fscache_n_store_vmscan_cancelled; +atomic_t fscache_n_store_vmscan_wait;  atomic_t fscache_n_marks;  atomic_t fscache_n_uncaches; @@ -232,11 +233,12 @@ static int fscache_stats_show(struct seq_file *m, void *v)  		   atomic_read(&fscache_n_store_radix_deletes),  		   atomic_read(&fscache_n_store_pages_over_limit)); -	seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n", +	seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u wt=%u\n",  		   atomic_read(&fscache_n_store_vmscan_not_storing),  		   atomic_read(&fscache_n_store_vmscan_gone),  		   atomic_read(&fscache_n_store_vmscan_busy), -		   atomic_read(&fscache_n_store_vmscan_cancelled)); +		   atomic_read(&fscache_n_store_vmscan_cancelled), +		   atomic_read(&fscache_n_store_vmscan_wait));  	seq_printf(m, "Ops    : pend=%u run=%u enq=%u can=%u rej=%u\n",  		   atomic_read(&fscache_n_op_pend), diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5209916e122..b673be31590 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1794,7 +1794,8 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,  	if (PagePrivate(page))  		return -EBUSY; -	nfs_fscache_release_page(page, GFP_KERNEL); +	if (!nfs_fscache_release_page(page, GFP_KERNEL)) +		return -EBUSY;  	return migrate_page(mapping, newpage, page, mode);  }  |