diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 209 | 
1 files changed, 156 insertions, 53 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 79210d23f60..939ae606cfa 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -105,12 +105,8 @@ static int nfs4_stat_to_errno(int);  #ifdef CONFIG_NFS_V4_SECURITY_LABEL  /* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */  #define	nfs4_label_maxsz	(4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN)) -#define encode_readdir_space 24 -#define encode_readdir_bitmask_sz 3  #else  #define	nfs4_label_maxsz	0 -#define encode_readdir_space 20 -#define encode_readdir_bitmask_sz 2  #endif  /* We support only one layout type per file system */  #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) @@ -207,8 +203,7 @@ static int nfs4_stat_to_errno(int);  				 2 + encode_verifier_maxsz + 5 + \  				nfs4_label_maxsz)  #define decode_readdir_maxsz	(op_decode_hdr_maxsz + \ -				 decode_verifier_maxsz + \ -				nfs4_label_maxsz + nfs4_fattr_maxsz) +				 decode_verifier_maxsz)  #define encode_readlink_maxsz	(op_encode_hdr_maxsz)  #define decode_readlink_maxsz	(op_decode_hdr_maxsz + 1)  #define encode_write_maxsz	(op_encode_hdr_maxsz + \ @@ -595,11 +590,13 @@ static int nfs4_stat_to_errno(int);  #define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \  				encode_sequence_maxsz + \  				encode_putfh_maxsz + \ -				encode_getattr_maxsz) +				encode_getattr_maxsz + \ +				encode_renew_maxsz)  #define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \  				decode_sequence_maxsz + \  				decode_putfh_maxsz + \ -				decode_getattr_maxsz) +				decode_getattr_maxsz + \ +				decode_renew_maxsz)  #define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \  				encode_sequence_maxsz + \  				encode_putfh_maxsz + \ @@ -736,13 +733,15 @@ static int nfs4_stat_to_errno(int);  				 encode_sequence_maxsz + \  				 encode_putfh_maxsz + \  				 encode_lookup_maxsz + \ -				 encode_fs_locations_maxsz) +				 encode_fs_locations_maxsz + \ +				 encode_renew_maxsz)  #define NFS4_dec_fs_locations_sz \  				(compound_decode_hdr_maxsz + \  				 decode_sequence_maxsz + \  				 decode_putfh_maxsz + \  				 decode_lookup_maxsz + \ -				 decode_fs_locations_maxsz) +				 decode_fs_locations_maxsz + \ +				 decode_renew_maxsz)  #define NFS4_enc_secinfo_sz 	(compound_encode_hdr_maxsz + \  				encode_sequence_maxsz + \  				encode_putfh_maxsz + \ @@ -751,6 +750,18 @@ static int nfs4_stat_to_errno(int);  				decode_sequence_maxsz + \  				decode_putfh_maxsz + \  				decode_secinfo_maxsz) +#define NFS4_enc_fsid_present_sz \ +				(compound_encode_hdr_maxsz + \ +				 encode_sequence_maxsz + \ +				 encode_putfh_maxsz + \ +				 encode_getfh_maxsz + \ +				 encode_renew_maxsz) +#define NFS4_dec_fsid_present_sz \ +				(compound_decode_hdr_maxsz + \ +				 decode_sequence_maxsz + \ +				 decode_putfh_maxsz + \ +				 decode_getfh_maxsz + \ +				 decode_renew_maxsz)  #if defined(CONFIG_NFS_V4_1)  #define NFS4_enc_bind_conn_to_session_sz \  				(compound_encode_hdr_maxsz + \ @@ -1545,7 +1556,8 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)  	encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);  } -static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) +static void encode_read(struct xdr_stream *xdr, const struct nfs_pgio_args *args, +			struct compound_hdr *hdr)  {  	__be32 *p; @@ -1565,6 +1577,8 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg  	};  	uint32_t dircount = readdir->count >> 1;  	__be32 *p, verf[2]; +	uint32_t attrlen = 0; +	unsigned int i;  	if (readdir->plus) {  		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| @@ -1573,26 +1587,27 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg  			FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|  			FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|  			FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; +		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;  		dircount >>= 1;  	}  	/* Use mounted_on_fileid only if the server supports it */  	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))  		attrs[0] |= FATTR4_WORD0_FILEID; +	for (i = 0; i < ARRAY_SIZE(attrs); i++) { +		attrs[i] &= readdir->bitmask[i]; +		if (attrs[i] != 0) +			attrlen = i+1; +	}  	encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);  	encode_uint64(xdr, readdir->cookie);  	encode_nfs4_verifier(xdr, &readdir->verifier); -	p = reserve_space(xdr, encode_readdir_space); +	p = reserve_space(xdr, 12 + (attrlen << 2));  	*p++ = cpu_to_be32(dircount);  	*p++ = cpu_to_be32(readdir->count); -	*p++ = cpu_to_be32(encode_readdir_bitmask_sz); -	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); -	*p   = cpu_to_be32(attrs[1] & readdir->bitmask[1]); -	if (encode_readdir_bitmask_sz > 2) { -		if (hdr->minorversion > 1) -			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL; -		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]); -	} +	*p++ = cpu_to_be32(attrlen); +	for (i = 0; i < attrlen; i++) +		*p++ = cpu_to_be32(attrs[i]);  	memcpy(verf, readdir->verifier.data, sizeof(verf));  	dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n", @@ -1687,7 +1702,8 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4  	encode_nfs4_verifier(xdr, &arg->confirm);  } -static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) +static void encode_write(struct xdr_stream *xdr, const struct nfs_pgio_args *args, +			 struct compound_hdr *hdr)  {  	__be32 *p; @@ -2437,7 +2453,7 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,   * Encode a READ request   */  static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr, -			      struct nfs_readargs *args) +			      struct nfs_pgio_args *args)  {  	struct compound_hdr hdr = {  		.minorversion = nfs4_xdr_minorversion(&args->seq_args), @@ -2499,7 +2515,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,   * Encode a WRITE request   */  static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr, -			       struct nfs_writeargs *args) +			       struct nfs_pgio_args *args)  {  	struct compound_hdr hdr = {  		.minorversion = nfs4_xdr_minorversion(&args->seq_args), @@ -2687,11 +2703,20 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,  	encode_compound_hdr(xdr, req, &hdr);  	encode_sequence(xdr, &args->seq_args, &hdr); -	encode_putfh(xdr, args->dir_fh, &hdr); -	encode_lookup(xdr, args->name, &hdr); -	replen = hdr.replen;	/* get the attribute into args->page */ -	encode_fs_locations(xdr, args->bitmask, &hdr); +	if (args->migration) { +		encode_putfh(xdr, args->fh, &hdr); +		replen = hdr.replen; +		encode_fs_locations(xdr, args->bitmask, &hdr); +		if (args->renew) +			encode_renew(xdr, args->clientid, &hdr); +	} else { +		encode_putfh(xdr, args->dir_fh, &hdr); +		encode_lookup(xdr, args->name, &hdr); +		replen = hdr.replen; +		encode_fs_locations(xdr, args->bitmask, &hdr); +	} +	/* Set up reply kvec to capture returned fs_locations array. */  	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,  			0, PAGE_SIZE);  	encode_nops(&hdr); @@ -2715,6 +2740,26 @@ static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,  	encode_nops(&hdr);  } +/* + * Encode FSID_PRESENT request + */ +static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req, +				      struct xdr_stream *xdr, +				      struct nfs4_fsid_present_arg *args) +{ +	struct compound_hdr hdr = { +		.minorversion = nfs4_xdr_minorversion(&args->seq_args), +	}; + +	encode_compound_hdr(xdr, req, &hdr); +	encode_sequence(xdr, &args->seq_args, &hdr); +	encode_putfh(xdr, args->fh, &hdr); +	encode_getfh(xdr, &hdr); +	if (args->renew) +		encode_renew(xdr, args->clientid, &hdr); +	encode_nops(&hdr); +} +  #if defined(CONFIG_NFS_V4_1)  /*   * BIND_CONN_TO_SESSION request @@ -3053,7 +3098,8 @@ out_overflow:  	return -EIO;  } -static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected, +		int *nfs_retval)  {  	__be32 *p;  	uint32_t opnum; @@ -3063,19 +3109,32 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)  	if (unlikely(!p))  		goto out_overflow;  	opnum = be32_to_cpup(p++); -	if (opnum != expected) { -		dprintk("nfs: Server returned operation" -			" %d but we issued a request for %d\n", -				opnum, expected); -		return -EIO; -	} +	if (unlikely(opnum != expected)) +		goto out_bad_operation;  	nfserr = be32_to_cpup(p); -	if (nfserr != NFS_OK) -		return nfs4_stat_to_errno(nfserr); -	return 0; +	if (nfserr == NFS_OK) +		*nfs_retval = 0; +	else +		*nfs_retval = nfs4_stat_to_errno(nfserr); +	return true; +out_bad_operation: +	dprintk("nfs: Server returned operation" +		" %d but we issued a request for %d\n", +			opnum, expected); +	*nfs_retval = -EREMOTEIO; +	return false;  out_overflow:  	print_overflow_msg(__func__, xdr); -	return -EIO; +	*nfs_retval = -EIO; +	return false; +} + +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +{ +	int retval; + +	__decode_op_hdr(xdr, expected, &retval); +	return retval;  }  /* Dummy routine */ @@ -3391,7 +3450,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint  {  	__be32 *p; -	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL; +	*res = 0;  	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))  		return -EIO;  	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { @@ -4957,11 +5016,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)  	uint32_t savewords, bmlen, i;  	int status; -	status = decode_op_hdr(xdr, OP_OPEN); -	if (status != -EIO) -		nfs_increment_open_seqid(status, res->seqid); -	if (!status) -		status = decode_stateid(xdr, &res->stateid); +	if (!__decode_op_hdr(xdr, OP_OPEN, &status)) +		return status; +	nfs_increment_open_seqid(status, res->seqid); +	if (status) +		return status; +	status = decode_stateid(xdr, &res->stateid);  	if (unlikely(status))  		return status; @@ -5027,7 +5087,8 @@ static int decode_putrootfh(struct xdr_stream *xdr)  	return decode_op_hdr(xdr, OP_PUTROOTFH);  } -static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) +static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, +		       struct nfs_pgio_res *res)  {  	__be32 *p;  	uint32_t count, eof, recvd; @@ -5281,7 +5342,7 @@ static int decode_setclientid_confirm(struct xdr_stream *xdr)  	return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);  } -static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) +static int decode_write(struct xdr_stream *xdr, struct nfs_pgio_res *res)  {  	__be32 *p;  	int status; @@ -6578,7 +6639,7 @@ out:   * Decode Read response   */  static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr, -			     struct nfs_readres *res) +			     struct nfs_pgio_res *res)  {  	struct compound_hdr hdr;  	int status; @@ -6603,7 +6664,7 @@ out:   * Decode WRITE response   */  static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr, -			      struct nfs_writeres *res) +			      struct nfs_pgio_res *res)  {  	struct compound_hdr hdr;  	int status; @@ -6824,13 +6885,26 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,  	status = decode_putfh(xdr);  	if (status)  		goto out; -	status = decode_lookup(xdr); -	if (status) -		goto out; -	xdr_enter_page(xdr, PAGE_SIZE); -	status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, +	if (res->migration) { +		xdr_enter_page(xdr, PAGE_SIZE); +		status = decode_getfattr_generic(xdr, +					&res->fs_locations->fattr,  					 NULL, res->fs_locations,  					 NULL, res->fs_locations->server); +		if (status) +			goto out; +		if (res->renew) +			status = decode_renew(xdr); +	} else { +		status = decode_lookup(xdr); +		if (status) +			goto out; +		xdr_enter_page(xdr, PAGE_SIZE); +		status = decode_getfattr_generic(xdr, +					&res->fs_locations->fattr, +					 NULL, res->fs_locations, +					 NULL, res->fs_locations->server); +	}  out:  	return status;  } @@ -6859,6 +6933,34 @@ out:  	return status;  } +/* + * Decode FSID_PRESENT response + */ +static int nfs4_xdr_dec_fsid_present(struct rpc_rqst *rqstp, +				     struct xdr_stream *xdr, +				     struct nfs4_fsid_present_res *res) +{ +	struct compound_hdr hdr; +	int status; + +	status = decode_compound_hdr(xdr, &hdr); +	if (status) +		goto out; +	status = decode_sequence(xdr, &res->seq_res, rqstp); +	if (status) +		goto out; +	status = decode_putfh(xdr); +	if (status) +		goto out; +	status = decode_getfh(xdr, res->fh); +	if (status) +		goto out; +	if (res->renew) +		status = decode_renew(xdr); +out: +	return status; +} +  #if defined(CONFIG_NFS_V4_1)  /*   * Decode BIND_CONN_TO_SESSION response @@ -7373,6 +7475,7 @@ struct rpc_procinfo	nfs4_procedures[] = {  	PROC(FS_LOCATIONS,	enc_fs_locations,	dec_fs_locations),  	PROC(RELEASE_LOCKOWNER,	enc_release_lockowner,	dec_release_lockowner),  	PROC(SECINFO,		enc_secinfo,		dec_secinfo), +	PROC(FSID_PRESENT,	enc_fsid_present,	dec_fsid_present),  #if defined(CONFIG_NFS_V4_1)  	PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),  	PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),  | 
