Loading fs/nfsd/nfs4xdr.c +55 −57 Original line number Diff line number Diff line Loading @@ -4452,84 +4452,82 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, return nfserr; } static __be32 nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) static __be32 nfsd4_encode_dirlist4(struct xdr_stream *xdr, struct nfsd4_readdir *readdir, u32 max_payload) { struct nfsd4_readdir *readdir = &u->readdir; int maxcount; int bytes_left; int bytes_left, maxcount, starting_len = xdr->buf->len; loff_t offset; struct xdr_stream *xdr = resp->xdr; int starting_len = xdr->buf->len; __be32 *p; nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf); if (nfserr != nfs_ok) return nfserr; __be32 status; /* * Number of bytes left for directory entries allowing for the * final 8 bytes of the readdir and a following failed op: * final 8 bytes of the readdir and a following failed op. */ bytes_left = xdr->buf->buflen - xdr->buf->len - COMPOUND_ERR_SLACK_SPACE - 8; if (bytes_left < 0) { nfserr = nfserr_resource; goto err_no_verf; } maxcount = svc_max_payload(resp->rqstp); maxcount = min_t(u32, readdir->rd_maxcount, maxcount); bytes_left = xdr->buf->buflen - xdr->buf->len - COMPOUND_ERR_SLACK_SPACE - XDR_UNIT * 2; if (bytes_left < 0) return nfserr_resource; maxcount = min_t(u32, readdir->rd_maxcount, max_payload); /* * Note the rfc defines rd_maxcount as the size of the * READDIR4resok structure, which includes the verifier above * and the 8 bytes encoded at the end of this function: * The RFC defines rd_maxcount as the size of the * READDIR4resok structure, which includes the verifier * and the 8 bytes encoded at the end of this function. */ if (maxcount < 16) { nfserr = nfserr_toosmall; goto err_no_verf; } maxcount = min_t(int, maxcount-16, bytes_left); if (maxcount < XDR_UNIT * 4) return nfserr_toosmall; maxcount = min_t(int, maxcount - XDR_UNIT * 4, bytes_left); /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0 */ if (!readdir->rd_dircount) readdir->rd_dircount = svc_max_payload(resp->rqstp); readdir->rd_dircount = max_payload; /* *entries */ readdir->xdr = xdr; readdir->rd_maxcount = maxcount; readdir->common.err = 0; readdir->cookie_offset = 0; offset = readdir->rd_cookie; nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, status = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, &readdir->common, nfsd4_encode_entry4); if (nfserr == nfs_ok && readdir->common.err == nfserr_toosmall && xdr->buf->len == starting_len + 8) { /* nothing encoded; which limit did we hit?: */ if (maxcount - 16 < bytes_left) /* It was the fault of rd_maxcount: */ nfserr = nfserr_toosmall; else /* We ran out of buffer space: */ nfserr = nfserr_resource; if (status) return status; if (readdir->common.err == nfserr_toosmall && xdr->buf->len == starting_len) { /* No entries were encoded. Which limit did we hit? */ if (maxcount - XDR_UNIT * 4 < bytes_left) /* It was the fault of rd_maxcount */ return nfserr_toosmall; /* We ran out of buffer space */ return nfserr_resource; } if (nfserr) goto err_no_verf; /* Encode the final entry's cookie value */ nfsd4_encode_entry4_nfs_cookie4(readdir, offset); /* No entries follow */ if (xdr_stream_encode_item_absent(xdr) != XDR_UNIT) return nfserr_resource; p = xdr_reserve_space(xdr, 8); if (!p) { WARN_ON_ONCE(1); goto err_no_verf; /* eof */ return nfsd4_encode_bool(xdr, readdir->common.err == nfserr_eof); } *p++ = 0; /* no more entries */ *p++ = htonl(readdir->common.err == nfserr_eof); return 0; err_no_verf: static __be32 nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_readdir *readdir = &u->readdir; struct xdr_stream *xdr = resp->xdr; int starting_len = xdr->buf->len; /* cookieverf */ nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf); if (nfserr != nfs_ok) return nfserr; /* reply */ nfserr = nfsd4_encode_dirlist4(xdr, readdir, svc_max_payload(resp->rqstp)); if (nfserr != nfs_ok) xdr_truncate_encode(xdr, starting_len); return nfserr; } Loading Loading
fs/nfsd/nfs4xdr.c +55 −57 Original line number Diff line number Diff line Loading @@ -4452,84 +4452,82 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, return nfserr; } static __be32 nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) static __be32 nfsd4_encode_dirlist4(struct xdr_stream *xdr, struct nfsd4_readdir *readdir, u32 max_payload) { struct nfsd4_readdir *readdir = &u->readdir; int maxcount; int bytes_left; int bytes_left, maxcount, starting_len = xdr->buf->len; loff_t offset; struct xdr_stream *xdr = resp->xdr; int starting_len = xdr->buf->len; __be32 *p; nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf); if (nfserr != nfs_ok) return nfserr; __be32 status; /* * Number of bytes left for directory entries allowing for the * final 8 bytes of the readdir and a following failed op: * final 8 bytes of the readdir and a following failed op. */ bytes_left = xdr->buf->buflen - xdr->buf->len - COMPOUND_ERR_SLACK_SPACE - 8; if (bytes_left < 0) { nfserr = nfserr_resource; goto err_no_verf; } maxcount = svc_max_payload(resp->rqstp); maxcount = min_t(u32, readdir->rd_maxcount, maxcount); bytes_left = xdr->buf->buflen - xdr->buf->len - COMPOUND_ERR_SLACK_SPACE - XDR_UNIT * 2; if (bytes_left < 0) return nfserr_resource; maxcount = min_t(u32, readdir->rd_maxcount, max_payload); /* * Note the rfc defines rd_maxcount as the size of the * READDIR4resok structure, which includes the verifier above * and the 8 bytes encoded at the end of this function: * The RFC defines rd_maxcount as the size of the * READDIR4resok structure, which includes the verifier * and the 8 bytes encoded at the end of this function. */ if (maxcount < 16) { nfserr = nfserr_toosmall; goto err_no_verf; } maxcount = min_t(int, maxcount-16, bytes_left); if (maxcount < XDR_UNIT * 4) return nfserr_toosmall; maxcount = min_t(int, maxcount - XDR_UNIT * 4, bytes_left); /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0 */ if (!readdir->rd_dircount) readdir->rd_dircount = svc_max_payload(resp->rqstp); readdir->rd_dircount = max_payload; /* *entries */ readdir->xdr = xdr; readdir->rd_maxcount = maxcount; readdir->common.err = 0; readdir->cookie_offset = 0; offset = readdir->rd_cookie; nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, status = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, &readdir->common, nfsd4_encode_entry4); if (nfserr == nfs_ok && readdir->common.err == nfserr_toosmall && xdr->buf->len == starting_len + 8) { /* nothing encoded; which limit did we hit?: */ if (maxcount - 16 < bytes_left) /* It was the fault of rd_maxcount: */ nfserr = nfserr_toosmall; else /* We ran out of buffer space: */ nfserr = nfserr_resource; if (status) return status; if (readdir->common.err == nfserr_toosmall && xdr->buf->len == starting_len) { /* No entries were encoded. Which limit did we hit? */ if (maxcount - XDR_UNIT * 4 < bytes_left) /* It was the fault of rd_maxcount */ return nfserr_toosmall; /* We ran out of buffer space */ return nfserr_resource; } if (nfserr) goto err_no_verf; /* Encode the final entry's cookie value */ nfsd4_encode_entry4_nfs_cookie4(readdir, offset); /* No entries follow */ if (xdr_stream_encode_item_absent(xdr) != XDR_UNIT) return nfserr_resource; p = xdr_reserve_space(xdr, 8); if (!p) { WARN_ON_ONCE(1); goto err_no_verf; /* eof */ return nfsd4_encode_bool(xdr, readdir->common.err == nfserr_eof); } *p++ = 0; /* no more entries */ *p++ = htonl(readdir->common.err == nfserr_eof); return 0; err_no_verf: static __be32 nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_readdir *readdir = &u->readdir; struct xdr_stream *xdr = resp->xdr; int starting_len = xdr->buf->len; /* cookieverf */ nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf); if (nfserr != nfs_ok) return nfserr; /* reply */ nfserr = nfsd4_encode_dirlist4(xdr, readdir, svc_max_payload(resp->rqstp)); if (nfserr != nfs_ok) xdr_truncate_encode(xdr, starting_len); return nfserr; } Loading