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

NFSD: Return both a hole and a data segment

But only one of each right now. We'll expand on this in the next patch.

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
278765ea 2db27992

+40 -16
+40 -16
fs/nfsd/nfs4xdr.c
··· 4603 4603 static __be32 4604 4604 nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, 4605 4605 struct nfsd4_read *read, 4606 - unsigned long maxcount, u32 *eof) 4606 + unsigned long *maxcount, u32 *eof) 4607 4607 { 4608 4608 struct xdr_stream *xdr = &resp->xdr; 4609 4609 struct file *file = read->rd_nf->nf_file; ··· 4614 4614 __be64 tmp64; 4615 4615 4616 4616 if (hole_pos > read->rd_offset) 4617 - maxcount = min_t(unsigned long, maxcount, hole_pos - read->rd_offset); 4618 - maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); 4617 + *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset); 4618 + *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len)); 4619 4619 4620 4620 /* Content type, offset, byte count */ 4621 4621 p = xdr_reserve_space(xdr, 4 + 8 + 4); 4622 4622 if (!p) 4623 4623 return nfserr_resource; 4624 4624 4625 - read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); 4625 + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount); 4626 4626 if (read->rd_vlen < 0) 4627 4627 return nfserr_resource; 4628 4628 4629 4629 nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, 4630 - resp->rqstp->rq_vec, read->rd_vlen, &maxcount, eof); 4630 + resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof); 4631 4631 if (nfserr) 4632 4632 return nfserr; 4633 4633 ··· 4635 4635 write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); 4636 4636 tmp64 = cpu_to_be64(read->rd_offset); 4637 4637 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8); 4638 - tmp = htonl(maxcount); 4638 + tmp = htonl(*maxcount); 4639 4639 write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4); 4640 4640 return nfs_ok; 4641 4641 } ··· 4643 4643 static __be32 4644 4644 nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, 4645 4645 struct nfsd4_read *read, 4646 - unsigned long maxcount, u32 *eof) 4646 + unsigned long *maxcount, u32 *eof) 4647 4647 { 4648 4648 struct file *file = read->rd_nf->nf_file; 4649 + loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); 4650 + unsigned long count; 4649 4651 __be32 *p; 4652 + 4653 + if (data_pos == -ENXIO) 4654 + data_pos = i_size_read(file_inode(file)); 4655 + else if (data_pos <= read->rd_offset) 4656 + return nfserr_resource; 4657 + count = data_pos - read->rd_offset; 4650 4658 4651 4659 /* Content type, offset, byte count */ 4652 4660 p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); ··· 4663 4655 4664 4656 *p++ = htonl(NFS4_CONTENT_HOLE); 4665 4657 p = xdr_encode_hyper(p, read->rd_offset); 4666 - p = xdr_encode_hyper(p, maxcount); 4658 + p = xdr_encode_hyper(p, count); 4667 4659 4668 - *eof = (read->rd_offset + maxcount) >= i_size_read(file_inode(file)); 4660 + *eof = (read->rd_offset + count) >= i_size_read(file_inode(file)); 4661 + *maxcount = min_t(unsigned long, count, *maxcount); 4669 4662 return nfs_ok; 4670 4663 } 4671 4664 ··· 4674 4665 nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, 4675 4666 struct nfsd4_read *read) 4676 4667 { 4677 - unsigned long maxcount; 4668 + unsigned long maxcount, count; 4678 4669 struct xdr_stream *xdr = &resp->xdr; 4679 4670 struct file *file; 4680 4671 int starting_len = xdr->buf->len; ··· 4697 4688 maxcount = min_t(unsigned long, maxcount, 4698 4689 (xdr->buf->buflen - xdr->buf->len)); 4699 4690 maxcount = min_t(unsigned long, maxcount, read->rd_length); 4691 + count = maxcount; 4700 4692 4701 4693 eof = read->rd_offset >= i_size_read(file_inode(file)); 4702 4694 if (eof) ··· 4706 4696 pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); 4707 4697 if (pos == -ENXIO) 4708 4698 pos = i_size_read(file_inode(file)); 4699 + else if (pos < 0) 4700 + pos = read->rd_offset; 4709 4701 4710 - if (pos > read->rd_offset) { 4711 - maxcount = pos - read->rd_offset; 4712 - nfserr = nfsd4_encode_read_plus_hole(resp, read, maxcount, &eof); 4702 + if (pos == read->rd_offset) { 4703 + maxcount = count; 4704 + nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof); 4705 + if (nfserr) 4706 + goto out; 4707 + count -= maxcount; 4708 + read->rd_offset += maxcount; 4713 4709 segments++; 4714 - } else { 4715 - nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof); 4710 + } 4711 + 4712 + if (count > 0 && !eof) { 4713 + maxcount = count; 4714 + nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof); 4715 + if (nfserr) 4716 + goto out; 4717 + count -= maxcount; 4718 + read->rd_offset += maxcount; 4716 4719 segments++; 4717 4720 } 4718 4721 4719 4722 out: 4720 - if (nfserr) 4723 + if (nfserr && segments == 0) 4721 4724 xdr_truncate_encode(xdr, starting_len); 4722 4725 else { 4723 4726 tmp = htonl(eof); 4724 4727 write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); 4725 4728 tmp = htonl(segments); 4726 4729 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); 4730 + nfserr = nfs_ok; 4727 4731 } 4728 4732 4729 4733 return nfserr;