diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 76 | 
1 files changed, 64 insertions, 12 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a99a8d94872..635274140b1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3737,9 +3737,10 @@ out:  static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)  {  	struct nfs4_cached_acl *acl; +	size_t buflen = sizeof(*acl) + acl_len; -	if (pages && acl_len <= PAGE_SIZE) { -		acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); +	if (pages && buflen <= PAGE_SIZE) { +		acl = kmalloc(buflen, GFP_KERNEL);  		if (acl == NULL)  			goto out;  		acl->cached = 1; @@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu  	if (ret)  		goto out_free; -	acl_len = res.acl_len - res.acl_data_offset; +	acl_len = res.acl_len;  	if (acl_len > args.acl_len)  		nfs4_write_cached_acl(inode, NULL, 0, acl_len);  	else @@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)  	dprintk("<-- %s\n", __func__);  } +static size_t max_response_pages(struct nfs_server *server) +{ +	u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; +	return nfs_page_array_len(0, max_resp_sz); +} + +static void nfs4_free_pages(struct page **pages, size_t size) +{ +	int i; + +	if (!pages) +		return; + +	for (i = 0; i < size; i++) { +		if (!pages[i]) +			break; +		__free_page(pages[i]); +	} +	kfree(pages); +} + +static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) +{ +	struct page **pages; +	int i; + +	pages = kcalloc(size, sizeof(struct page *), gfp_flags); +	if (!pages) { +		dprintk("%s: can't alloc array of %zu pages\n", __func__, size); +		return NULL; +	} + +	for (i = 0; i < size; i++) { +		pages[i] = alloc_page(gfp_flags); +		if (!pages[i]) { +			dprintk("%s: failed to allocate page\n", __func__); +			nfs4_free_pages(pages, size); +			return NULL; +		} +	} + +	return pages; +} +  static void nfs4_layoutget_release(void *calldata)  {  	struct nfs4_layoutget *lgp = calldata; +	struct nfs_server *server = NFS_SERVER(lgp->args.inode); +	size_t max_pages = max_response_pages(server);  	dprintk("--> %s\n", __func__); +	nfs4_free_pages(lgp->args.layout.pages, max_pages);  	put_nfs_open_context(lgp->args.ctx);  	kfree(calldata);  	dprintk("<-- %s\n", __func__); @@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {  	.rpc_release = nfs4_layoutget_release,  }; -int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) +void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)  {  	struct nfs_server *server = NFS_SERVER(lgp->args.inode); +	size_t max_pages = max_response_pages(server);  	struct rpc_task *task;  	struct rpc_message msg = {  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], @@ -6259,12 +6308,19 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)  	dprintk("--> %s\n", __func__); +	lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags); +	if (!lgp->args.layout.pages) { +		nfs4_layoutget_release(lgp); +		return; +	} +	lgp->args.layout.pglen = max_pages * PAGE_SIZE; +  	lgp->res.layoutp = &lgp->args.layout;  	lgp->res.seq_res.sr_slot = NULL;  	nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);  	task = rpc_run_task(&task_setup_data);  	if (IS_ERR(task)) -		return PTR_ERR(task); +		return;  	status = nfs4_wait_for_completion_rpc_task(task);  	if (status == 0)  		status = task->tk_status; @@ -6272,7 +6328,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)  		status = pnfs_layout_process(lgp);  	rpc_put_task(task);  	dprintk("<-- %s status=%d\n", __func__, status); -	return status; +	return;  }  static void @@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)  		return;  	}  	spin_lock(&lo->plh_inode->i_lock); -	if (task->tk_status == 0) { -		if (lrp->res.lrs_present) { -			pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); -		} else -			BUG_ON(!list_empty(&lo->plh_segs)); -	} +	if (task->tk_status == 0 && lrp->res.lrs_present) +		pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);  	lo->plh_block_lgets--;  	spin_unlock(&lo->plh_inode->i_lock);  	dprintk("<-- %s\n", __func__);  |