diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 74 | 
1 files changed, 52 insertions, 22 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9d992b0346e..1ff76acc7e9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -50,6 +50,8 @@  #include <linux/module.h>  #include <linux/sunrpc/bc_xprt.h>  #include <linux/xattr.h> +#include <linux/utsname.h> +#include <linux/mm.h>  #include "nfs4_fs.h"  #include "delegation.h" @@ -3251,6 +3253,35 @@ static void buf_to_pages(const void *buf, size_t buflen,  	}  } +static int buf_to_pages_noslab(const void *buf, size_t buflen, +		struct page **pages, unsigned int *pgbase) +{ +	struct page *newpage, **spages; +	int rc = 0; +	size_t len; +	spages = pages; + +	do { +		len = min(PAGE_CACHE_SIZE, buflen); +		newpage = alloc_page(GFP_KERNEL); + +		if (newpage == NULL) +			goto unwind; +		memcpy(page_address(newpage), buf, len); +                buf += len; +                buflen -= len; +		*pages++ = newpage; +		rc++; +	} while (buflen != 0); + +	return rc; + +unwind: +	for(; rc > 0; rc--) +		__free_page(spages[rc-1]); +	return -ENOMEM; +} +  struct nfs4_cached_acl {  	int cached;  	size_t len; @@ -3419,13 +3450,23 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl  		.rpc_argp	= &arg,  		.rpc_resp	= &res,  	}; -	int ret; +	int ret, i;  	if (!nfs4_server_supports_acls(server))  		return -EOPNOTSUPP; +	i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); +	if (i < 0) +		return i;  	nfs_inode_return_delegation(inode); -	buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);  	ret = nfs4_call_sync(server, &msg, &arg, &res, 1); + +	/* +	 * Free each page after tx, so the only ref left is +	 * held by the network stack +	 */ +	for (; i > 0; i--) +		put_page(pages[i-1]); +  	/*  	 * Acl update can result in inode attribute update.  	 * so mark the attribute cache invalid. @@ -4572,27 +4613,16 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)  	*p = htonl((u32)clp->cl_boot_time.tv_nsec);  	args.verifier = &verifier; -	while (1) { -		args.id_len = scnprintf(args.id, sizeof(args.id), -					"%s/%s %u", -					clp->cl_ipaddr, -					rpc_peeraddr2str(clp->cl_rpcclient, -							 RPC_DISPLAY_ADDR), -					clp->cl_id_uniquifier); - -		status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); - -		if (status != -NFS4ERR_CLID_INUSE) -			break; - -		if (signalled()) -			break; - -		if (++clp->cl_id_uniquifier == 0) -			break; -	} +	args.id_len = scnprintf(args.id, sizeof(args.id), +				"%s/%s.%s/%u", +				clp->cl_ipaddr, +				init_utsname()->nodename, +				init_utsname()->domainname, +				clp->cl_rpcclient->cl_auth->au_flavor); -	status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); +	status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); +	if (!status) +		status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);  	dprintk("<-- %s status= %d\n", __func__, status);  	return status;  }  |