diff options
Diffstat (limited to 'fs/nfs/write.c')
| -rw-r--r-- | fs/nfs/write.c | 104 | 
1 files changed, 58 insertions, 46 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 76735dd8c9a..dbb5c0a613b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -69,19 +69,24 @@ void nfs_commit_free(struct nfs_commit_data *p)  }  EXPORT_SYMBOL_GPL(nfs_commit_free); -struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) +struct nfs_write_header *nfs_writehdr_alloc(unsigned int pagecount)  { -	struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); +	struct nfs_write_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);  	if (p) { +		struct nfs_pgio_header *hdr = &p->header; +		struct nfs_write_data *data = &p->rpc_data; +  		memset(p, 0, sizeof(*p)); -		INIT_LIST_HEAD(&p->pages); -		p->npages = pagecount; -		if (pagecount <= ARRAY_SIZE(p->page_array)) -			p->pagevec = p->page_array; +		INIT_LIST_HEAD(&hdr->pages); +		INIT_LIST_HEAD(&data->list); +		data->npages = pagecount; +		data->header = hdr; +		if (pagecount <= ARRAY_SIZE(data->page_array)) +			data->pagevec = data->page_array;  		else { -			p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); -			if (!p->pagevec) { +			data->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); +			if (!data->pagevec) {  				mempool_free(p, nfs_wdata_mempool);  				p = NULL;  			} @@ -90,17 +95,18 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)  	return p;  } -void nfs_writedata_free(struct nfs_write_data *p) +void nfs_writehdr_free(struct nfs_pgio_header *hdr)  { -	if (p && (p->pagevec != &p->page_array[0])) -		kfree(p->pagevec); -	mempool_free(p, nfs_wdata_mempool); +	struct nfs_write_header *whdr = container_of(hdr, struct nfs_write_header, header); +	mempool_free(whdr, nfs_wdata_mempool);  }  void nfs_writedata_release(struct nfs_write_data *wdata)  {  	put_nfs_open_context(wdata->args.context); -	nfs_writedata_free(wdata); +	if (wdata->pagevec != wdata->page_array) +		kfree(wdata->pagevec); +	nfs_writehdr_free(wdata->header);  }  static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) @@ -507,9 +513,8 @@ static inline  int nfs_write_need_commit(struct nfs_write_data *data)  {  	if (data->verf.committed == NFS_DATA_SYNC) -		return data->lseg == NULL; -	else -		return data->verf.committed != NFS_FILE_SYNC; +		return data->header->lseg == NULL; +	return data->verf.committed != NFS_FILE_SYNC;  }  static inline @@ -517,7 +522,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,  				  struct nfs_write_data *data)  {  	if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { -		nfs_mark_request_commit(req, data->lseg); +		nfs_mark_request_commit(req, data->header->lseg);  		return 1;  	}  	if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { @@ -841,13 +846,13 @@ int nfs_initiate_write(struct rpc_clnt *clnt,  		       const struct rpc_call_ops *call_ops,  		       int how)  { -	struct inode *inode = data->inode; +	struct inode *inode = data->header->inode;  	int priority = flush_task_priority(how);  	struct rpc_task *task;  	struct rpc_message msg = {  		.rpc_argp = &data->args,  		.rpc_resp = &data->res, -		.rpc_cred = data->cred, +		.rpc_cred = data->header->cred,  	};  	struct rpc_task_setup task_setup_data = {  		.rpc_client = clnt, @@ -896,14 +901,15 @@ static void nfs_write_rpcsetup(struct nfs_page *req,  		unsigned int count, unsigned int offset,  		int how)  { +	struct nfs_pgio_header *hdr = data->header;  	struct inode *inode = req->wb_context->dentry->d_inode;  	/* Set up the RPC argument and reply structs  	 * NB: take care not to mess about with data->commit et al. */ -	data->req = req; -	data->inode = inode = req->wb_context->dentry->d_inode; -	data->cred = req->wb_context->cred; +	hdr->req = req; +	hdr->inode = inode = req->wb_context->dentry->d_inode; +	hdr->cred = req->wb_context->cred;  	data->args.fh     = NFS_FH(inode);  	data->args.offset = req_offset(req) + offset; @@ -935,7 +941,7 @@ static int nfs_do_write(struct nfs_write_data *data,  		const struct rpc_call_ops *call_ops,  		int how)  { -	struct inode *inode = data->args.context->dentry->d_inode; +	struct inode *inode = data->header->inode;  	return nfs_initiate_write(NFS_CLIENT(inode), data, call_ops, how);  } @@ -981,6 +987,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head  {  	struct nfs_page *req = nfs_list_entry(desc->pg_list.next);  	struct page *page = req->wb_page; +	struct nfs_write_header *whdr;  	struct nfs_write_data *data;  	size_t wsize = desc->pg_bsize, nbytes;  	unsigned int offset; @@ -1000,9 +1007,10 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head  	do {  		size_t len = min(nbytes, wsize); -		data = nfs_writedata_alloc(1); -		if (!data) +		whdr = nfs_writehdr_alloc(1); +		if (!whdr)  			goto out_bad; +		data = &whdr->rpc_data;  		data->pagevec[0] = page;  		nfs_write_rpcsetup(req, data, len, offset, desc->pg_ioflags);  		list_add(&data->list, res); @@ -1036,13 +1044,14 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r  {  	struct nfs_page		*req;  	struct page		**pages; +	struct nfs_write_header	*whdr;  	struct nfs_write_data	*data;  	struct list_head *head = &desc->pg_list;  	int ret = 0; -	data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, -						      desc->pg_count)); -	if (!data) { +	whdr = nfs_writehdr_alloc(nfs_page_array_len(desc->pg_base, +						     desc->pg_count)); +	if (!whdr) {  		while (!list_empty(head)) {  			req = nfs_list_entry(head->next);  			nfs_list_remove_request(req); @@ -1051,14 +1060,15 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r  		ret = -ENOMEM;  		goto out;  	} +	data = &whdr->rpc_data;  	pages = data->pagevec;  	while (!list_empty(head)) {  		req = nfs_list_entry(head->next);  		nfs_list_remove_request(req); -		nfs_list_add_request(req, &data->pages); +		nfs_list_add_request(req, &whdr->header.pages);  		*pages++ = req->wb_page;  	} -	req = nfs_list_entry(data->pages.next); +	req = nfs_list_entry(whdr->header.pages.next);  	if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&  	    (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) @@ -1126,10 +1136,11 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)  	dprintk("NFS: %5u write(%s/%lld %d@%lld)",  		task->tk_pid, -		data->req->wb_context->dentry->d_inode->i_sb->s_id, +		data->header->inode->i_sb->s_id,  		(long long) -		  NFS_FILEID(data->req->wb_context->dentry->d_inode), -		data->req->wb_bytes, (long long)req_offset(data->req)); +		  NFS_FILEID(data->header->inode), +		data->header->req->wb_bytes, +		(long long)req_offset(data->header->req));  	nfs_writeback_done(task, data);  } @@ -1137,7 +1148,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)  static void nfs_writeback_release_partial(void *calldata)  {  	struct nfs_write_data	*data = calldata; -	struct nfs_page		*req = data->req; +	struct nfs_page		*req = data->header->req;  	struct page		*page = req->wb_page;  	int status = data->task.tk_status; @@ -1169,13 +1180,13 @@ static void nfs_writeback_release_partial(void *calldata)  out:  	if (atomic_dec_and_test(&req->wb_complete))  		nfs_writepage_release(req, data); -	nfs_writedata_release(calldata); +	nfs_writedata_release(data);  }  void nfs_write_prepare(struct rpc_task *task, void *calldata)  {  	struct nfs_write_data *data = calldata; -	NFS_PROTO(data->inode)->write_rpc_prepare(task, data); +	NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data);  }  void nfs_commit_prepare(struct rpc_task *task, void *calldata) @@ -1208,11 +1219,12 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)  static void nfs_writeback_release_full(void *calldata)  {  	struct nfs_write_data	*data = calldata; +	struct nfs_pgio_header *hdr = data->header;  	int status = data->task.tk_status;  	/* Update attributes as result of writeback. */ -	while (!list_empty(&data->pages)) { -		struct nfs_page *req = nfs_list_entry(data->pages.next); +	while (!list_empty(&hdr->pages)) { +		struct nfs_page *req = nfs_list_entry(hdr->pages.next);  		struct page *page = req->wb_page;  		nfs_list_remove_request(req); @@ -1233,7 +1245,7 @@ static void nfs_writeback_release_full(void *calldata)  		if (nfs_write_need_commit(data)) {  			memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); -			nfs_mark_request_commit(req, data->lseg); +			nfs_mark_request_commit(req, hdr->lseg);  			dprintk(" marked for commit\n");  			goto next;  		} @@ -1244,7 +1256,7 @@ remove_request:  		nfs_unlock_request(req);  		nfs_end_page_writeback(page);  	} -	nfs_writedata_release(calldata); +	nfs_writedata_release(data);  }  static const struct rpc_call_ops nfs_write_full_ops = { @@ -1261,6 +1273,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)  {  	struct nfs_writeargs	*argp = &data->args;  	struct nfs_writeres	*resp = &data->res; +	struct inode		*inode = data->header->inode;  	int status;  	dprintk("NFS: %5u nfs_writeback_done (status %d)\n", @@ -1273,10 +1286,10 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)  	 * another writer had changed the file, but some applications  	 * depend on tighter cache coherency when writing.  	 */ -	status = NFS_PROTO(data->inode)->write_done(task, data); +	status = NFS_PROTO(inode)->write_done(task, data);  	if (status != 0)  		return; -	nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); +	nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, resp->count);  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)  	if (resp->verf->committed < argp->stable && task->tk_status >= 0) { @@ -1294,7 +1307,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)  		if (time_before(complain, jiffies)) {  			dprintk("NFS:       faulty NFS server %s:"  				" (committed = %d) != (stable = %d)\n", -				NFS_SERVER(data->inode)->nfs_client->cl_hostname, +				NFS_SERVER(inode)->nfs_client->cl_hostname,  				resp->verf->committed, argp->stable);  			complain = jiffies + 300 * HZ;  		} @@ -1304,7 +1317,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)  	if (task->tk_status >= 0 && resp->count < argp->count) {  		static unsigned long    complain; -		nfs_inc_stats(data->inode, NFSIOS_SHORTWRITE); +		nfs_inc_stats(inode, NFSIOS_SHORTWRITE);  		/* Has the server at least made some progress? */  		if (resp->count != 0) { @@ -1333,7 +1346,6 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)  		/* Can't do anything about it except throw an error. */  		task->tk_status = -EIO;  	} -	return;  } @@ -1745,7 +1757,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,  int __init nfs_init_writepagecache(void)  {  	nfs_wdata_cachep = kmem_cache_create("nfs_write_data", -					     sizeof(struct nfs_write_data), +					     sizeof(struct nfs_write_header),  					     0, SLAB_HWCACHE_ALIGN,  					     NULL);  	if (nfs_wdata_cachep == NULL)  |