diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-31 19:25:39 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-31 19:25:39 -0700 | 
| commit | ac694dbdbc403c00e2c14d10bc7b8412cc378259 (patch) | |
| tree | e37328cfbeaf43716dd5914cad9179e57e84df76 /fs/nfs/write.c | |
| parent | a40a1d3d0a2fd613fdec6d89d3c053268ced76ed (diff) | |
| parent | 437ea90cc3afdca5229b41c6b1d38c4842756cb9 (diff) | |
| download | olio-linux-3.10-ac694dbdbc403c00e2c14d10bc7b8412cc378259.tar.xz olio-linux-3.10-ac694dbdbc403c00e2c14d10bc7b8412cc378259.zip  | |
Merge branch 'akpm' (Andrew's patch-bomb)
Merge Andrew's second set of patches:
 - MM
 - a few random fixes
 - a couple of RTC leftovers
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (120 commits)
  rtc/rtc-88pm80x: remove unneed devm_kfree
  rtc/rtc-88pm80x: assign ret only when rtc_register_driver fails
  mm: hugetlbfs: close race during teardown of hugetlbfs shared page tables
  tmpfs: distribute interleave better across nodes
  mm: remove redundant initialization
  mm: warn if pg_data_t isn't initialized with zero
  mips: zero out pg_data_t when it's allocated
  memcg: gix memory accounting scalability in shrink_page_list
  mm/sparse: remove index_init_lock
  mm/sparse: more checks on mem_section number
  mm/sparse: optimize sparse_index_alloc
  memcg: add mem_cgroup_from_css() helper
  memcg: further prevent OOM with too many dirty pages
  memcg: prevent OOM with too many dirty pages
  mm: mmu_notifier: fix freed page still mapped in secondary MMU
  mm: memcg: only check anon swapin page charges for swap cache
  mm: memcg: only check swap cache pages for repeated charging
  mm: memcg: split swapin charge function into private and public part
  mm: memcg: remove needless !mm fixup to init_mm when charging
  mm: memcg: remove unneeded shmem charge type
  ...
Diffstat (limited to 'fs/nfs/write.c')
| -rw-r--r-- | fs/nfs/write.c | 89 | 
1 files changed, 55 insertions, 34 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e4a2ad2059b..5829d0ce7cf 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -52,7 +52,7 @@ static mempool_t *nfs_commit_mempool;  struct nfs_commit_data *nfs_commitdata_alloc(void)  { -	struct nfs_commit_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); +	struct nfs_commit_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOIO);  	if (p) {  		memset(p, 0, sizeof(*p)); @@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(nfs_commit_free);  struct nfs_write_header *nfs_writehdr_alloc(void)  { -	struct nfs_write_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); +	struct nfs_write_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO);  	if (p) {  		struct nfs_pgio_header *hdr = &p->header; @@ -142,25 +142,38 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)  	set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);  } -static struct nfs_page *nfs_page_find_request_locked(struct page *page) +static struct nfs_page * +nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page)  {  	struct nfs_page *req = NULL; -	if (PagePrivate(page)) { +	if (PagePrivate(page))  		req = (struct nfs_page *)page_private(page); -		if (req != NULL) -			kref_get(&req->wb_kref); +	else if (unlikely(PageSwapCache(page))) { +		struct nfs_page *freq, *t; + +		/* Linearly search the commit list for the correct req */ +		list_for_each_entry_safe(freq, t, &nfsi->commit_info.list, wb_list) { +			if (freq->wb_page == page) { +				req = freq; +				break; +			} +		}  	} + +	if (req) +		kref_get(&req->wb_kref); +  	return req;  }  static struct nfs_page *nfs_page_find_request(struct page *page)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	struct nfs_page *req = NULL;  	spin_lock(&inode->i_lock); -	req = nfs_page_find_request_locked(page); +	req = nfs_page_find_request_locked(NFS_I(inode), page);  	spin_unlock(&inode->i_lock);  	return req;  } @@ -168,16 +181,16 @@ static struct nfs_page *nfs_page_find_request(struct page *page)  /* Adjust the file length if we're writing beyond the end */  static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	loff_t end, i_size;  	pgoff_t end_index;  	spin_lock(&inode->i_lock);  	i_size = i_size_read(inode);  	end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; -	if (i_size > 0 && page->index < end_index) +	if (i_size > 0 && page_file_index(page) < end_index)  		goto out; -	end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); +	end = page_file_offset(page) + ((loff_t)offset+count);  	if (i_size >= end)  		goto out;  	i_size_write(inode, end); @@ -190,7 +203,7 @@ out:  static void nfs_set_pageerror(struct page *page)  {  	SetPageError(page); -	nfs_zap_mapping(page->mapping->host, page->mapping); +	nfs_zap_mapping(page_file_mapping(page)->host, page_file_mapping(page));  }  /* We can set the PG_uptodate flag if we see that a write request @@ -231,7 +244,7 @@ static int nfs_set_page_writeback(struct page *page)  	int ret = test_set_page_writeback(page);  	if (!ret) { -		struct inode *inode = page->mapping->host; +		struct inode *inode = page_file_mapping(page)->host;  		struct nfs_server *nfss = NFS_SERVER(inode);  		if (atomic_long_inc_return(&nfss->writeback) > @@ -245,7 +258,7 @@ static int nfs_set_page_writeback(struct page *page)  static void nfs_end_page_writeback(struct page *page)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	struct nfs_server *nfss = NFS_SERVER(inode);  	end_page_writeback(page); @@ -255,13 +268,13 @@ static void nfs_end_page_writeback(struct page *page)  static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	struct nfs_page *req;  	int ret;  	spin_lock(&inode->i_lock);  	for (;;) { -		req = nfs_page_find_request_locked(page); +		req = nfs_page_find_request_locked(NFS_I(inode), page);  		if (req == NULL)  			break;  		if (nfs_lock_request(req)) @@ -316,13 +329,13 @@ out:  static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	int ret;  	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);  	nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); -	nfs_pageio_cond_complete(pgio, page->index); +	nfs_pageio_cond_complete(pgio, page_file_index(page));  	ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);  	if (ret == -EAGAIN) {  		redirty_page_for_writepage(wbc, page); @@ -339,7 +352,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc  	struct nfs_pageio_descriptor pgio;  	int err; -	NFS_PROTO(page->mapping->host)->write_pageio_init(&pgio, +	NFS_PROTO(page_file_mapping(page)->host)->write_pageio_init(&pgio,  							  page->mapping->host,  							  wb_priority(wbc),  							  &nfs_async_write_completion_ops); @@ -416,9 +429,15 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)  	spin_lock(&inode->i_lock);  	if (!nfsi->npages && NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))  		inode->i_version++; -	set_bit(PG_MAPPED, &req->wb_flags); -	SetPagePrivate(req->wb_page); -	set_page_private(req->wb_page, (unsigned long)req); +	/* +	 * Swap-space should not get truncated. Hence no need to plug the race +	 * with invalidate/truncate. +	 */ +	if (likely(!PageSwapCache(req->wb_page))) { +		set_bit(PG_MAPPED, &req->wb_flags); +		SetPagePrivate(req->wb_page); +		set_page_private(req->wb_page, (unsigned long)req); +	}  	nfsi->npages++;  	kref_get(&req->wb_kref);  	spin_unlock(&inode->i_lock); @@ -435,9 +454,11 @@ static void nfs_inode_remove_request(struct nfs_page *req)  	BUG_ON (!NFS_WBACK_BUSY(req));  	spin_lock(&inode->i_lock); -	set_page_private(req->wb_page, 0); -	ClearPagePrivate(req->wb_page); -	clear_bit(PG_MAPPED, &req->wb_flags); +	if (likely(!PageSwapCache(req->wb_page))) { +		set_page_private(req->wb_page, 0); +		ClearPagePrivate(req->wb_page); +		clear_bit(PG_MAPPED, &req->wb_flags); +	}  	nfsi->npages--;  	spin_unlock(&inode->i_lock);  	nfs_release_request(req); @@ -474,7 +495,7 @@ nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst,  	spin_unlock(cinfo->lock);  	if (!cinfo->dreq) {  		inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); -		inc_bdi_stat(req->wb_page->mapping->backing_dev_info, +		inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,  			     BDI_RECLAIMABLE);  		__mark_inode_dirty(req->wb_context->dentry->d_inode,  				   I_DIRTY_DATASYNC); @@ -541,7 +562,7 @@ static void  nfs_clear_page_commit(struct page *page)  {  	dec_zone_page_state(page, NR_UNSTABLE_NFS); -	dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE); +	dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE);  }  static void @@ -733,7 +754,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,  	spin_lock(&inode->i_lock);  	for (;;) { -		req = nfs_page_find_request_locked(page); +		req = nfs_page_find_request_locked(NFS_I(inode), page);  		if (req == NULL)  			goto out_unlock; @@ -792,7 +813,7 @@ out_err:  static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,  		struct page *page, unsigned int offset, unsigned int bytes)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	struct nfs_page	*req;  	req = nfs_try_to_update_request(inode, page, offset, bytes); @@ -845,7 +866,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)  		nfs_release_request(req);  		if (!do_flush)  			return 0; -		status = nfs_wb_page(page->mapping->host, page); +		status = nfs_wb_page(page_file_mapping(page)->host, page);  	} while (status == 0);  	return status;  } @@ -875,7 +896,7 @@ int nfs_updatepage(struct file *file, struct page *page,  		unsigned int offset, unsigned int count)  {  	struct nfs_open_context *ctx = nfs_file_open_context(file); -	struct inode	*inode = page->mapping->host; +	struct inode	*inode = page_file_mapping(page)->host;  	int		status = 0;  	nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); @@ -883,7 +904,7 @@ int nfs_updatepage(struct file *file, struct page *page,  	dprintk("NFS:       nfs_updatepage(%s/%s %d@%lld)\n",  		file->f_path.dentry->d_parent->d_name.name,  		file->f_path.dentry->d_name.name, count, -		(long long)(page_offset(page) + offset)); +		(long long)(page_file_offset(page) + offset));  	/* If we're not using byte range locks, and we know the page  	 * is up to date, it may be more efficient to extend the write @@ -1474,7 +1495,7 @@ void nfs_retry_commit(struct list_head *page_list,  		nfs_mark_request_commit(req, lseg, cinfo);  		if (!cinfo->dreq) {  			dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); -			dec_bdi_stat(req->wb_page->mapping->backing_dev_info, +			dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,  				     BDI_RECLAIMABLE);  		}  		nfs_unlock_and_release_request(req); @@ -1731,7 +1752,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)   */  int nfs_wb_page(struct inode *inode, struct page *page)  { -	loff_t range_start = page_offset(page); +	loff_t range_start = page_file_offset(page);  	loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);  	struct writeback_control wbc = {  		.sync_mode = WB_SYNC_ALL,  |