Commit 02ef04e4 authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker

NFS: Account for XDR pad of buf->pages

Certain NFS results (eg. READLINK) might expect a data payload that
is not an exact multiple of 4 bytes. In this case, XDR encoding
is required to pad that payload so its length on the wire is a
multiple of 4 bytes. The constants that define the maximum size of
each NFS result do not appear to account for this extra word.

In each case where the data payload is to be received into pages:

- 1 word is added to the size of the receive buffer allocated by
  call_allocate

- rpc_inline_rcv_pages subtracts 1 word from @hdrsize so that the
  extra buffer space falls into the rcv_buf's tail iovec

- If buf->pagelen is word-aligned, an XDR pad is not needed and
  is thus removed from the tail
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent cf500bac
...@@ -56,11 +56,11 @@ ...@@ -56,11 +56,11 @@
#define NFS_attrstat_sz (1+NFS_fattr_sz) #define NFS_attrstat_sz (1+NFS_fattr_sz)
#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz) #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
#define NFS_readlinkres_sz (2) #define NFS_readlinkres_sz (2+1)
#define NFS_readres_sz (1+NFS_fattr_sz+1) #define NFS_readres_sz (1+NFS_fattr_sz+1+1)
#define NFS_writeres_sz (NFS_attrstat_sz) #define NFS_writeres_sz (NFS_attrstat_sz)
#define NFS_stat_sz (1) #define NFS_stat_sz (1)
#define NFS_readdirres_sz (1) #define NFS_readdirres_sz (1+1)
#define NFS_statfsres_sz (1+NFS_info_sz) #define NFS_statfsres_sz (1+NFS_info_sz)
static int nfs_stat_to_errno(enum nfs_stat); static int nfs_stat_to_errno(enum nfs_stat);
......
...@@ -69,13 +69,13 @@ ...@@ -69,13 +69,13 @@
#define NFS3_removeres_sz (NFS3_setattrres_sz) #define NFS3_removeres_sz (NFS3_setattrres_sz)
#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1+1)
#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3+1)
#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2+1)
#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)+1)
#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
static int nfs3_stat_to_errno(enum nfs_stat); static int nfs3_stat_to_errno(enum nfs_stat);
...@@ -1629,7 +1629,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1629,7 +1629,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
result->op_status = status; result->op_status = status;
if (status != NFS3_OK) if (status != NFS3_OK)
goto out_status; goto out_status;
result->replen = 3 + ((xdr_stream_pos(xdr) - pos) >> 2); result->replen = 4 + ((xdr_stream_pos(xdr) - pos) >> 2);
error = decode_read3resok(xdr, result); error = decode_read3resok(xdr, result);
out: out:
return error; return error;
......
...@@ -215,14 +215,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -215,14 +215,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
nfs4_fattr_bitmap_maxsz) nfs4_fattr_bitmap_maxsz)
#define encode_read_maxsz (op_encode_hdr_maxsz + \ #define encode_read_maxsz (op_encode_hdr_maxsz + \
encode_stateid_maxsz + 3) encode_stateid_maxsz + 3)
#define decode_read_maxsz (op_decode_hdr_maxsz + 2) #define decode_read_maxsz (op_decode_hdr_maxsz + 2 + 1)
#define encode_readdir_maxsz (op_encode_hdr_maxsz + \ #define encode_readdir_maxsz (op_encode_hdr_maxsz + \
2 + encode_verifier_maxsz + 5 + \ 2 + encode_verifier_maxsz + 5 + \
nfs4_label_maxsz) nfs4_label_maxsz)
#define decode_readdir_maxsz (op_decode_hdr_maxsz + \ #define decode_readdir_maxsz (op_decode_hdr_maxsz + \
decode_verifier_maxsz) decode_verifier_maxsz + 1)
#define encode_readlink_maxsz (op_encode_hdr_maxsz) #define encode_readlink_maxsz (op_encode_hdr_maxsz)
#define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1 + 1)
#define encode_write_maxsz (op_encode_hdr_maxsz + \ #define encode_write_maxsz (op_encode_hdr_maxsz + \
encode_stateid_maxsz + 4) encode_stateid_maxsz + 4)
#define decode_write_maxsz (op_decode_hdr_maxsz + \ #define decode_write_maxsz (op_decode_hdr_maxsz + \
...@@ -284,14 +284,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -284,14 +284,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
#define decode_delegreturn_maxsz (op_decode_hdr_maxsz) #define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
#define encode_getacl_maxsz (encode_getattr_maxsz) #define encode_getacl_maxsz (encode_getattr_maxsz)
#define decode_getacl_maxsz (op_decode_hdr_maxsz + \ #define decode_getacl_maxsz (op_decode_hdr_maxsz + \
nfs4_fattr_bitmap_maxsz + 1) nfs4_fattr_bitmap_maxsz + 1 + 1)
#define encode_setacl_maxsz (op_encode_hdr_maxsz + \ #define encode_setacl_maxsz (op_encode_hdr_maxsz + \
encode_stateid_maxsz + 3) encode_stateid_maxsz + 3)
#define decode_setacl_maxsz (decode_setattr_maxsz) #define decode_setacl_maxsz (decode_setattr_maxsz)
#define encode_fs_locations_maxsz \ #define encode_fs_locations_maxsz \
(encode_getattr_maxsz) (encode_getattr_maxsz)
#define decode_fs_locations_maxsz \ #define decode_fs_locations_maxsz \
(0) (1)
#define encode_secinfo_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) #define encode_secinfo_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz)
#define decode_secinfo_maxsz (op_decode_hdr_maxsz + 1 + ((NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)) / 4)) #define decode_secinfo_maxsz (op_decode_hdr_maxsz + 1 + ((NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)) / 4))
...@@ -392,12 +392,13 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -392,12 +392,13 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
1 /* opaque devaddr4 length */ + \ 1 /* opaque devaddr4 length */ + \
/* devaddr4 payload is read into page */ \ /* devaddr4 payload is read into page */ \
1 /* notification bitmap length */ + \ 1 /* notification bitmap length */ + \
1 /* notification bitmap, word 0 */) 1 /* notification bitmap, word 0 */ + \
1 /* possible XDR padding */)
#define encode_layoutget_maxsz (op_encode_hdr_maxsz + 10 + \ #define encode_layoutget_maxsz (op_encode_hdr_maxsz + 10 + \
encode_stateid_maxsz) encode_stateid_maxsz)
#define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \
decode_stateid_maxsz + \ decode_stateid_maxsz + \
XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE) + 1)
#define encode_layoutcommit_maxsz (op_encode_hdr_maxsz + \ #define encode_layoutcommit_maxsz (op_encode_hdr_maxsz + \
2 /* offset */ + \ 2 /* offset */ + \
2 /* length */ + \ 2 /* length */ + \
......
...@@ -1177,7 +1177,11 @@ void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages, ...@@ -1177,7 +1177,11 @@ void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
unsigned int base, unsigned int len, unsigned int base, unsigned int len,
unsigned int hdrsize) unsigned int hdrsize)
{ {
hdrsize += RPC_REPHDRSIZE + req->rq_cred->cr_auth->au_rslack; /* Subtract one to force an extra word of buffer space for the
* payload's XDR pad to fall into the rcv_buf's tail iovec.
*/
hdrsize += RPC_REPHDRSIZE + req->rq_cred->cr_auth->au_rslack - 1;
xdr_inline_pages(&req->rq_rcv_buf, hdrsize << 2, pages, base, len); xdr_inline_pages(&req->rq_rcv_buf, hdrsize << 2, pages, base, len);
trace_rpc_reply_pages(req); trace_rpc_reply_pages(req);
} }
......
...@@ -189,6 +189,8 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, ...@@ -189,6 +189,8 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
tail->iov_base = buf + offset; tail->iov_base = buf + offset;
tail->iov_len = buflen - offset; tail->iov_len = buflen - offset;
if ((xdr->page_len & 3) == 0)
tail->iov_len -= sizeof(__be32);
xdr->buflen += len; xdr->buflen += len;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment