Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSD: Add READ_PLUS hole segment encoding

However, we still only reply to the READ_PLUS call with a single segment
at this time.

Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

authored by

Anna Schumaker and committed by
J. Bruce Fields
2db27992 528b8493

+38 -1
+38 -1
fs/nfsd/nfs4xdr.c
··· 4608 4608 struct xdr_stream *xdr = &resp->xdr; 4609 4609 struct file *file = read->rd_nf->nf_file; 4610 4610 int starting_len = xdr->buf->len; 4611 + loff_t hole_pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE); 4611 4612 __be32 nfserr; 4612 4613 __be32 *p, tmp; 4613 4614 __be64 tmp64; 4614 4615 4616 + if (hole_pos > read->rd_offset) 4617 + maxcount = min_t(unsigned long, maxcount, hole_pos - read->rd_offset); 4615 4618 maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); 4616 4619 4617 4620 /* Content type, offset, byte count */ ··· 4641 4638 } 4642 4639 4643 4640 static __be32 4641 + nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, 4642 + struct nfsd4_read *read, 4643 + unsigned long maxcount, u32 *eof) 4644 + { 4645 + struct file *file = read->rd_nf->nf_file; 4646 + __be32 *p; 4647 + 4648 + /* Content type, offset, byte count */ 4649 + p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); 4650 + if (!p) 4651 + return nfserr_resource; 4652 + 4653 + *p++ = htonl(NFS4_CONTENT_HOLE); 4654 + p = xdr_encode_hyper(p, read->rd_offset); 4655 + p = xdr_encode_hyper(p, maxcount); 4656 + 4657 + *eof = (read->rd_offset + maxcount) >= i_size_read(file_inode(file)); 4658 + return nfs_ok; 4659 + } 4660 + 4661 + static __be32 4644 4662 nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, 4645 4663 struct nfsd4_read *read) 4646 4664 { ··· 4671 4647 int starting_len = xdr->buf->len; 4672 4648 int segments = 0; 4673 4649 __be32 *p, tmp; 4650 + loff_t pos; 4674 4651 u32 eof; 4675 4652 4676 4653 if (nfserr) ··· 4690 4665 maxcount = min_t(unsigned long, maxcount, read->rd_length); 4691 4666 4692 4667 eof = read->rd_offset >= i_size_read(file_inode(file)); 4693 - if (!eof) { 4668 + if (eof) 4669 + goto out; 4670 + 4671 + pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); 4672 + if (pos == -ENXIO) 4673 + pos = i_size_read(file_inode(file)); 4674 + 4675 + if (pos > read->rd_offset) { 4676 + maxcount = pos - read->rd_offset; 4677 + nfserr = nfsd4_encode_read_plus_hole(resp, read, maxcount, &eof); 4678 + segments++; 4679 + } else { 4694 4680 nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof); 4695 4681 segments++; 4696 4682 } 4697 4683 4684 + out: 4698 4685 if (nfserr) 4699 4686 xdr_truncate_encode(xdr, starting_len); 4700 4687 else {