* [PATCH 1/4] NFSD: Return eof and maxcount to nfsd4_encode_read()
2020-01-10 22:35 [PATCH 0/4] NFSD: Add support for the v4.2 READ_PLUS operation schumaker.anna
@ 2020-01-10 22:35 ` schumaker.anna
2020-01-10 22:35 ` [PATCH 2/4] NFSD: Add READ_PLUS data support schumaker.anna
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: schumaker.anna @ 2020-01-10 22:35 UTC (permalink / raw)
To: bfields, linux-nfs; +Cc: Anna.Schumaker
From: Anna Schumaker <Anna.Schumaker@Netapp.com>
I want to reuse nfsd4_encode_readv() and nfsd4_encode_splice_read() in
READ_PLUS rather than reimplementing them. READ_PLUS returns a single
eof flag for the entire call and a separate maxcount for each data
segment, so we need to have the READ call encode these values in a
different place.
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
---
fs/nfsd/nfs4xdr.c | 60 ++++++++++++++++++++---------------------------
1 file changed, 26 insertions(+), 34 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index d2dc4c0e22e8..812e82097879 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3446,23 +3446,22 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
static __be32 nfsd4_encode_splice_read(
struct nfsd4_compoundres *resp,
- struct nfsd4_read *read,
- struct file *file, unsigned long maxcount)
+ struct nfsd4_read *read, struct file *file,
+ unsigned long *maxcount, u32 *eof)
{
struct xdr_stream *xdr = &resp->xdr;
struct xdr_buf *buf = xdr->buf;
- u32 eof;
+ long len;
int space_left;
__be32 nfserr;
- __be32 *p = xdr->p - 2;
/* Make sure there will be room for padding if needed */
if (xdr->end - xdr->p < 1)
return nfserr_resource;
+ len = *maxcount;
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
- file, read->rd_offset, &maxcount, &eof);
- read->rd_length = maxcount;
+ file, read->rd_offset, maxcount, eof);
if (nfserr) {
/*
* nfsd_splice_actor may have already messed with the
@@ -3473,24 +3472,21 @@ static __be32 nfsd4_encode_splice_read(
return nfserr;
}
- *(p++) = htonl(eof);
- *(p++) = htonl(maxcount);
-
- buf->page_len = maxcount;
- buf->len += maxcount;
- xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
+ buf->page_len = *maxcount;
+ buf->len += *maxcount;
+ xdr->page_ptr += (buf->page_base + *maxcount + PAGE_SIZE - 1)
/ PAGE_SIZE;
/* Use rest of head for padding and remaining ops: */
buf->tail[0].iov_base = xdr->p;
buf->tail[0].iov_len = 0;
xdr->iov = buf->tail;
- if (maxcount&3) {
- int pad = 4 - (maxcount&3);
+ if (*maxcount&3) {
+ int pad = 4 - (*maxcount&3);
*(xdr->p++) = 0;
- buf->tail[0].iov_base += maxcount&3;
+ buf->tail[0].iov_base += *maxcount&3;
buf->tail[0].iov_len = pad;
buf->len += pad;
}
@@ -3504,22 +3500,20 @@ static __be32 nfsd4_encode_splice_read(
}
static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
- struct nfsd4_read *read,
- struct file *file, unsigned long maxcount)
+ struct nfsd4_read *read, struct file *file,
+ unsigned long *maxcount, u32 *eof)
{
struct xdr_stream *xdr = &resp->xdr;
- u32 eof;
int v;
int starting_len = xdr->buf->len - 8;
long len;
int thislen;
__be32 nfserr;
- __be32 tmp;
__be32 *p;
u32 zzz = 0;
int pad;
- len = maxcount;
+ len = *maxcount;
v = 0;
thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p));
@@ -3541,22 +3535,15 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
}
read->rd_vlen = v;
- len = maxcount;
+ len = *maxcount;
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
- resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
- &eof);
- read->rd_length = maxcount;
+ resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
if (nfserr)
return nfserr;
- xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
-
- tmp = htonl(eof);
- write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
- tmp = htonl(maxcount);
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
+ xdr_truncate_encode(xdr, starting_len + 8 + ((*maxcount+3)&~3));
- pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
+ pad = (*maxcount&3) ? 4 - (*maxcount&3) : 0;
+ write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + *maxcount,
&zzz, pad);
return 0;
@@ -3567,6 +3554,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_read *read)
{
unsigned long maxcount;
+ u32 eof;
struct xdr_stream *xdr = &resp->xdr;
struct file *file;
int starting_len = xdr->buf->len;
@@ -3595,13 +3583,17 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
if (file->f_op->splice_read &&
test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
- nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
+ nfserr = nfsd4_encode_splice_read(resp, read, file, &maxcount, &eof);
else
- nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
+ nfserr = nfsd4_encode_readv(resp, read, file, &maxcount, &eof);
if (nfserr)
xdr_truncate_encode(xdr, starting_len);
+ read->rd_length = maxcount;
+ *p++ = htonl(eof);
+ *p++ = htonl(maxcount);
+
return nfserr;
}
--
2.24.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4] NFSD: Add READ_PLUS data support
2020-01-10 22:35 [PATCH 0/4] NFSD: Add support for the v4.2 READ_PLUS operation schumaker.anna
2020-01-10 22:35 ` [PATCH 1/4] NFSD: Return eof and maxcount to nfsd4_encode_read() schumaker.anna
@ 2020-01-10 22:35 ` schumaker.anna
2020-01-10 22:35 ` [PATCH 3/4] NFSD: Add READ_PLUS hole segment encoding schumaker.anna
2020-01-10 22:35 ` [PATCH 4/4] NFSD: Encode a full READ_PLUS reply schumaker.anna
3 siblings, 0 replies; 5+ messages in thread
From: schumaker.anna @ 2020-01-10 22:35 UTC (permalink / raw)
To: bfields, linux-nfs; +Cc: Anna.Schumaker
From: Anna Schumaker <Anna.Schumaker@Netapp.com>
This patch adds READ_PLUS support for returning a single
NFS4_CONTENT_DATA segment to the client. This is basically the same as
the READ operation, only with the extra information about data segments.
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
---
fs/nfsd/nfs4proc.c | 17 +++++++++
fs/nfsd/nfs4xdr.c | 90 ++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 101 insertions(+), 6 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 4798667af647..3c11ca9bd5d7 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2179,6 +2179,16 @@ static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
}
+static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ u32 maxcount = svc_max_payload(rqstp);
+ u32 rlen = min(op->u.read.rd_length, maxcount);
+ /* enough extra xdr space for encoding either a hole or data segment. */
+ u32 segments = 1 + 2 + 2;
+
+ return (op_encode_hdr_size + 2 + segments + XDR_QUADLEN(rlen)) * sizeof(__be32);
+}
+
static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
{
u32 maxcount = 0, rlen = 0;
@@ -2700,6 +2710,13 @@ static const struct nfsd4_operation nfsd4_ops[] = {
.op_name = "OP_COPY",
.op_rsize_bop = nfsd4_copy_rsize,
},
+ [OP_READ_PLUS] = {
+ .op_func = nfsd4_read,
+ .op_release = nfsd4_read_release,
+ .op_name = "OP_READ_PLUS",
+ .op_rsize_bop = nfsd4_read_plus_rsize,
+ .op_get_currentstateid = nfsd4_get_readstateid,
+ },
[OP_SEEK] = {
.op_func = nfsd4_seek,
.op_name = "OP_SEEK",
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 812e82097879..014e05365c17 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1882,7 +1882,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
[OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status,
[OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status,
- [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read,
[OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
[OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
@@ -3589,10 +3589,11 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
if (nfserr)
xdr_truncate_encode(xdr, starting_len);
-
- read->rd_length = maxcount;
- *p++ = htonl(eof);
- *p++ = htonl(maxcount);
+ else {
+ read->rd_length = maxcount;
+ *p++ = htonl(eof);
+ *p++ = htonl(maxcount);
+ }
return nfserr;
}
@@ -4264,6 +4265,83 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
return nfserr_resource;
p = xdr_encode_hyper(p, os->count);
*p++ = cpu_to_be32(0);
+ return nfserr;
+}
+
+static __be32
+nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
+ struct nfsd4_read *read,
+ unsigned long maxcount, u32 *eof)
+{
+ struct xdr_stream *xdr = &resp->xdr;
+ struct file *file = read->rd_nf->nf_file;
+ __be32 nfserr;
+ __be32 *p;
+
+ /* Content type, offset, byte count */
+ p = xdr_reserve_space(xdr, 4 + 8 + 4);
+ if (!p)
+ return nfserr_resource;
+ xdr_commit_encode(xdr);
+
+ if (file->f_op->splice_read &&
+ test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
+ nfserr = nfsd4_encode_splice_read(resp, read, file, &maxcount, eof);
+ else
+ nfserr = nfsd4_encode_readv(resp, read, file, &maxcount, eof);
+
+ if (nfserr)
+ return nfserr;
+
+ *p++ = htonl(NFS4_CONTENT_DATA);
+ p = xdr_encode_hyper(p, read->rd_offset);
+ *p++ = htonl(maxcount);
+
+ read->rd_offset += maxcount;
+ read->rd_length = (maxcount > 0) ? read->rd_length - maxcount : 0;
+ return nfserr;
+}
+
+static __be32
+nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_read *read)
+{
+ unsigned long maxcount;
+ u32 eof;
+ struct xdr_stream *xdr = &resp->xdr;
+ struct file *file;
+ int starting_len = xdr->buf->len;
+ __be32 *p;
+
+ if (nfserr)
+ return nfserr;
+ file = read->rd_nf->nf_file;
+
+ /* eof flag, segment count */
+ p = xdr_reserve_space(xdr, 4 + 4);
+ if (!p) {
+ WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
+ return nfserr_resource;
+ }
+ if (resp->xdr.buf->page_len &&
+ test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
+ WARN_ON_ONCE(1);
+ return nfserr_resource;
+ }
+ xdr_commit_encode(xdr);
+
+ maxcount = svc_max_payload(resp->rqstp);
+ maxcount = min_t(unsigned long, maxcount,
+ (xdr->buf->buflen - xdr->buf->len));
+ maxcount = min_t(unsigned long, maxcount, read->rd_length);
+
+ nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof);
+ if (nfserr)
+ xdr_truncate_encode(xdr, starting_len);
+ else {
+ *p++ = htonl(eof);
+ *p++ = htonl(1);
+ }
return nfserr;
}
@@ -4372,7 +4450,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = {
[OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
[OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
[OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status,
- [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus,
[OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
[OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
[OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
--
2.24.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] NFSD: Add READ_PLUS hole segment encoding
2020-01-10 22:35 [PATCH 0/4] NFSD: Add support for the v4.2 READ_PLUS operation schumaker.anna
2020-01-10 22:35 ` [PATCH 1/4] NFSD: Return eof and maxcount to nfsd4_encode_read() schumaker.anna
2020-01-10 22:35 ` [PATCH 2/4] NFSD: Add READ_PLUS data support schumaker.anna
@ 2020-01-10 22:35 ` schumaker.anna
2020-01-10 22:35 ` [PATCH 4/4] NFSD: Encode a full READ_PLUS reply schumaker.anna
3 siblings, 0 replies; 5+ messages in thread
From: schumaker.anna @ 2020-01-10 22:35 UTC (permalink / raw)
To: bfields, linux-nfs; +Cc: Anna.Schumaker
From: Anna Schumaker <Anna.Schumaker@Netapp.com>
However, we only encode the hole if it is at the beginning of the range
and treat everything else as data to keep things simple.
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
---
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/nfs4xdr.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3c11ca9bd5d7..fc8c821eda8b 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2184,7 +2184,7 @@ static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op
u32 maxcount = svc_max_payload(rqstp);
u32 rlen = min(op->u.read.rd_length, maxcount);
/* enough extra xdr space for encoding either a hole or data segment. */
- u32 segments = 1 + 2 + 2;
+ u32 segments = 2 * (1 + 2 + 2);
return (op_encode_hdr_size + 2 + segments + XDR_QUADLEN(rlen)) * sizeof(__be32);
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 014e05365c17..552972b35547 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -4302,6 +4302,31 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
return nfserr;
}
+static __be32
+nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, struct nfsd4_read *read,
+ unsigned long maxcount, u32 *eof)
+{
+ struct file *file = read->rd_nf->nf_file;
+ __be32 *p;
+
+ /* Content type, offset, byte count */
+ p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
+ if (!p)
+ return nfserr_resource;
+
+ maxcount = min_t(unsigned long, maxcount, read->rd_length);
+
+ *p++ = cpu_to_be32(NFS4_CONTENT_HOLE);
+ p = xdr_encode_hyper(p, read->rd_offset);
+ p = xdr_encode_hyper(p, maxcount);
+
+ *eof = (read->rd_offset + maxcount) >= i_size_read(file_inode(file));
+
+ read->rd_offset += maxcount;
+ read->rd_length = (maxcount > 0) ? read->rd_length - maxcount : 0;
+ return nfs_ok;
+}
+
static __be32
nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_read *read)
@@ -4311,6 +4336,8 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
struct xdr_stream *xdr = &resp->xdr;
struct file *file;
int starting_len = xdr->buf->len;
+ unsigned int segments = 0;
+ loff_t data_pos;
__be32 *p;
if (nfserr)
@@ -4335,12 +4362,28 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
(xdr->buf->buflen - xdr->buf->len));
maxcount = min_t(unsigned long, maxcount, read->rd_length);
- nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof);
+ data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
+ if (data_pos == -ENXIO)
+ data_pos = i_size_read(file_inode(file));
+ else if (data_pos < 0)
+ data_pos = read->rd_offset;
+
+ if (data_pos > read->rd_offset) {
+ nfserr = nfsd4_encode_read_plus_hole(resp, read,
+ data_pos - read->rd_offset, &eof);
+ segments++;
+ }
+
+ if (!nfserr && !eof && read->rd_length > 0) {
+ nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof);
+ segments++;
+ }
+
if (nfserr)
xdr_truncate_encode(xdr, starting_len);
else {
*p++ = htonl(eof);
- *p++ = htonl(1);
+ *p++ = htonl(segments);
}
return nfserr;
--
2.24.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4] NFSD: Encode a full READ_PLUS reply
2020-01-10 22:35 [PATCH 0/4] NFSD: Add support for the v4.2 READ_PLUS operation schumaker.anna
` (2 preceding siblings ...)
2020-01-10 22:35 ` [PATCH 3/4] NFSD: Add READ_PLUS hole segment encoding schumaker.anna
@ 2020-01-10 22:35 ` schumaker.anna
3 siblings, 0 replies; 5+ messages in thread
From: schumaker.anna @ 2020-01-10 22:35 UTC (permalink / raw)
To: bfields, linux-nfs; +Cc: Anna.Schumaker
From: Anna Schumaker <Anna.Schumaker@Netapp.com>
Reply to the client with multiple hole and data segments. This might
have performance issues due to the number of calls to vfs_llseek(),
depending on the underlying filesystem used on the server.
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
---
fs/nfsd/nfs4xdr.c | 41 +++++++++++++++++++++++++++++------------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 552972b35547..c63846729d0b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -4270,14 +4270,18 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
- struct nfsd4_read *read,
- unsigned long maxcount, u32 *eof)
+ struct nfsd4_read *read, u32 *eof)
{
struct xdr_stream *xdr = &resp->xdr;
struct file *file = read->rd_nf->nf_file;
+ unsigned long maxcount = read->rd_length;
+ loff_t hole_pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE);
__be32 nfserr;
__be32 *p;
+ if (hole_pos > read->rd_offset)
+ maxcount = min_t(unsigned long, maxcount, hole_pos - read->rd_offset);
+
/* Content type, offset, byte count */
p = xdr_reserve_space(xdr, 4 + 8 + 4);
if (!p)
@@ -4289,6 +4293,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
nfserr = nfsd4_encode_splice_read(resp, read, file, &maxcount, eof);
else
nfserr = nfsd4_encode_readv(resp, read, file, &maxcount, eof);
+ clear_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
if (nfserr)
return nfserr;
@@ -4303,18 +4308,24 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
}
static __be32
-nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, struct nfsd4_read *read,
- unsigned long maxcount, u32 *eof)
+nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
+ struct nfsd4_read *read, u32 *eof, loff_t data_pos)
{
struct file *file = read->rd_nf->nf_file;
+ unsigned long maxcount = read->rd_length;
__be32 *p;
+ if (data_pos == 0)
+ data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
+ if (data_pos == -ENXIO)
+ data_pos = i_size_read(file_inode(file));
+
/* Content type, offset, byte count */
p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
if (!p)
return nfserr_resource;
- maxcount = min_t(unsigned long, maxcount, read->rd_length);
+ maxcount = min_t(unsigned long, maxcount, data_pos - read->rd_offset);
*p++ = cpu_to_be32(NFS4_CONTENT_HOLE);
p = xdr_encode_hyper(p, read->rd_offset);
@@ -4338,6 +4349,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
int starting_len = xdr->buf->len;
unsigned int segments = 0;
loff_t data_pos;
+ bool is_data;
__be32 *p;
if (nfserr)
@@ -4361,21 +4373,26 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
maxcount = min_t(unsigned long, maxcount,
(xdr->buf->buflen - xdr->buf->len));
maxcount = min_t(unsigned long, maxcount, read->rd_length);
+ read->rd_length = maxcount;
data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
if (data_pos == -ENXIO)
data_pos = i_size_read(file_inode(file));
else if (data_pos < 0)
data_pos = read->rd_offset;
+ is_data = (data_pos == read->rd_offset);
+ eof = read->rd_offset > i_size_read(file_inode(file));
- if (data_pos > read->rd_offset) {
- nfserr = nfsd4_encode_read_plus_hole(resp, read,
- data_pos - read->rd_offset, &eof);
- segments++;
- }
+ while (read->rd_length > 0 && !eof) {
+ if (is_data)
+ nfserr = nfsd4_encode_read_plus_data(resp, read, &eof);
+ else
+ nfserr = nfsd4_encode_read_plus_hole(resp, read, &eof, data_pos);
- if (!nfserr && !eof && read->rd_length > 0) {
- nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof);
+ if (nfserr)
+ break;
+ is_data = !is_data;
+ data_pos = 0;
segments++;
}
--
2.24.1
^ permalink raw reply related [flat|nested] 5+ messages in thread