[PATCH 4/4] NFSD: Encode a full READ_PLUS reply

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx>

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@xxxxxxxxxx>
---
 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




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux