From: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx> Decode multiple hole and data segments sent by the server, placing everything directly where they need to go in the xdr pages. Signed-off-by: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx> --- fs/nfs/nfs42xdr.c | 50 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index 791e90353bc2..c31c6fadee19 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c @@ -756,16 +756,15 @@ static int decode_read_plus_data(struct xdr_stream *xdr, struct nfs_pgio_res *re p = xdr_decode_hyper(p, &offset); count = be32_to_cpup(p); - recvd = xdr_read_pages(xdr, count); + recvd = xdr_align_data(xdr, res->count, count); if (count > recvd) { dprintk("NFS: server cheating in read reply: " "count %u > recvd %u\n", count, recvd); - count = recvd; *eof = 0; } - res->count += count; - return 0; + res->count += recvd; + return count - recvd; } static int decode_read_plus_hole(struct xdr_stream *xdr, struct nfs_pgio_res *res, @@ -780,21 +779,18 @@ static int decode_read_plus_hole(struct xdr_stream *xdr, struct nfs_pgio_res *re p = xdr_decode_hyper(p, &offset); p = xdr_decode_hyper(p, &length); - - recvd = xdr_expand_hole(xdr, 0, length); - if (recvd < length) { + recvd = xdr_expand_hole(xdr, res->count, length); + if (recvd < length) *eof = 0; - length = recvd; - } - res->count += length; - return 0; + res->count += recvd; + return length - recvd; } static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res) { uint32_t eof, segments, type; - int status; + int status, i; __be32 *p; status = decode_op_hdr(xdr, OP_READ_PLUS); @@ -810,22 +806,24 @@ static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res) if (segments == 0) goto out; - p = xdr_inline_decode(xdr, 4); - if (unlikely(!p)) - return -EIO; + for (i = 0; i < segments; i++) { + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + return -EIO; - type = be32_to_cpup(p++); - if (type == NFS4_CONTENT_DATA) - status = decode_read_plus_data(xdr, res, &eof); - else if (type == NFS4_CONTENT_HOLE) - status = decode_read_plus_hole(xdr, res, &eof); - else - return -EINVAL; + type = be32_to_cpup(p++); + if (type == NFS4_CONTENT_DATA) + status = decode_read_plus_data(xdr, res, &eof); + else if (type == NFS4_CONTENT_HOLE) + status = decode_read_plus_hole(xdr, res, &eof); + else + return -EINVAL; - if (status) - return status; - if (segments > 1) - eof = 0; + if (status < 0) + return status; + if (status > 0) + break; + } out: res->eof = eof; -- 2.27.0