forked from mirrors/linux
		
	nfsd4: allow exotic read compounds
I'm not sure why a client would want to stuff multiple reads in a single compound rpc, but it's legal for them to do it, and we should really support it. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
		
							parent
							
								
									fec25fa4ad
								
							
						
					
					
						commit
						b042098063
					
				
					 2 changed files with 25 additions and 38 deletions
				
			
		| 
						 | 
					@ -176,7 +176,5 @@ Nonstandard compound limitations:
 | 
				
			||||||
  ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
 | 
					  ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
 | 
				
			||||||
  fail to live up to the promise we made in CREATE_SESSION fore channel
 | 
					  fail to live up to the promise we made in CREATE_SESSION fore channel
 | 
				
			||||||
  negotiation.
 | 
					  negotiation.
 | 
				
			||||||
* No more than one read-like operation allowed per compound; encoding
 | 
					 | 
				
			||||||
  replies that cross page boundaries (except for read data) not handled.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
 | 
					See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3139,28 +3139,34 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 | 
				
			||||||
	struct xdr_stream *xdr = &resp->xdr;
 | 
						struct xdr_stream *xdr = &resp->xdr;
 | 
				
			||||||
	u32 eof;
 | 
						u32 eof;
 | 
				
			||||||
	int v;
 | 
						int v;
 | 
				
			||||||
	struct page *page;
 | 
					 | 
				
			||||||
	int starting_len = xdr->buf->len - 8;
 | 
						int starting_len = xdr->buf->len - 8;
 | 
				
			||||||
	int space_left;
 | 
					 | 
				
			||||||
	long len;
 | 
						long len;
 | 
				
			||||||
 | 
						int thislen;
 | 
				
			||||||
	__be32 nfserr;
 | 
						__be32 nfserr;
 | 
				
			||||||
	__be32 tmp;
 | 
						__be32 tmp;
 | 
				
			||||||
	__be32 *p;
 | 
						__be32 *p;
 | 
				
			||||||
 | 
						u32 zzz = 0;
 | 
				
			||||||
 | 
						int pad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = maxcount;
 | 
						len = maxcount;
 | 
				
			||||||
	v = 0;
 | 
						v = 0;
 | 
				
			||||||
	while (len) {
 | 
					 | 
				
			||||||
		int thislen;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		page = *(resp->rqstp->rq_next_page);
 | 
						thislen = (void *)xdr->end - (void *)xdr->p;
 | 
				
			||||||
		if (!page) { /* ran out of pages */
 | 
						if (len < thislen)
 | 
				
			||||||
			maxcount -= len;
 | 
							thislen = len;
 | 
				
			||||||
			break;
 | 
						p = xdr_reserve_space(xdr, (thislen+3)&~3);
 | 
				
			||||||
		}
 | 
						WARN_ON_ONCE(!p);
 | 
				
			||||||
 | 
						resp->rqstp->rq_vec[v].iov_base = p;
 | 
				
			||||||
 | 
						resp->rqstp->rq_vec[v].iov_len = thislen;
 | 
				
			||||||
 | 
						v++;
 | 
				
			||||||
 | 
						len -= thislen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (len) {
 | 
				
			||||||
		thislen = min_t(long, len, PAGE_SIZE);
 | 
							thislen = min_t(long, len, PAGE_SIZE);
 | 
				
			||||||
		resp->rqstp->rq_vec[v].iov_base = page_address(page);
 | 
							p = xdr_reserve_space(xdr, (thislen+3)&~3);
 | 
				
			||||||
 | 
							WARN_ON_ONCE(!p);
 | 
				
			||||||
 | 
							resp->rqstp->rq_vec[v].iov_base = p;
 | 
				
			||||||
		resp->rqstp->rq_vec[v].iov_len = thislen;
 | 
							resp->rqstp->rq_vec[v].iov_len = thislen;
 | 
				
			||||||
		resp->rqstp->rq_next_page++;
 | 
					 | 
				
			||||||
		v++;
 | 
							v++;
 | 
				
			||||||
		len -= thislen;
 | 
							len -= thislen;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -3170,6 +3176,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 | 
				
			||||||
			read->rd_vlen, &maxcount);
 | 
								read->rd_vlen, &maxcount);
 | 
				
			||||||
	if (nfserr)
 | 
						if (nfserr)
 | 
				
			||||||
		return nfserr;
 | 
							return nfserr;
 | 
				
			||||||
 | 
						xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eof = (read->rd_offset + maxcount >=
 | 
						eof = (read->rd_offset + maxcount >=
 | 
				
			||||||
	       read->rd_fhp->fh_dentry->d_inode->i_size);
 | 
						       read->rd_fhp->fh_dentry->d_inode->i_size);
 | 
				
			||||||
| 
						 | 
					@ -3179,27 +3186,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 | 
				
			||||||
	tmp = htonl(maxcount);
 | 
						tmp = htonl(maxcount);
 | 
				
			||||||
	write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
 | 
						write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp->xdr.buf->page_len = maxcount;
 | 
						pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
 | 
				
			||||||
	xdr->buf->len += maxcount;
 | 
						write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
 | 
				
			||||||
	xdr->page_ptr += v;
 | 
													&zzz, pad);
 | 
				
			||||||
	xdr->iov = xdr->buf->tail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Use rest of head for padding and remaining ops: */
 | 
					 | 
				
			||||||
	resp->xdr.buf->tail[0].iov_base = xdr->p;
 | 
					 | 
				
			||||||
	resp->xdr.buf->tail[0].iov_len = 0;
 | 
					 | 
				
			||||||
	if (maxcount&3) {
 | 
					 | 
				
			||||||
		p = xdr_reserve_space(xdr, 4);
 | 
					 | 
				
			||||||
		WRITE32(0);
 | 
					 | 
				
			||||||
		resp->xdr.buf->tail[0].iov_base += maxcount&3;
 | 
					 | 
				
			||||||
		resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
 | 
					 | 
				
			||||||
		xdr->buf->len -= (maxcount&3);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
 | 
					 | 
				
			||||||
				xdr->buf->buflen - xdr->buf->len);
 | 
					 | 
				
			||||||
	xdr->buf->buflen = xdr->buf->len + space_left;
 | 
					 | 
				
			||||||
	xdr->end = (__be32 *)((void *)xdr->end + space_left);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3224,15 +3213,15 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 | 
				
			||||||
		WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
 | 
							WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
 | 
				
			||||||
		return nfserr_resource;
 | 
							return nfserr_resource;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (resp->xdr.buf->page_len && resp->rqstp->rq_splice_ok) {
 | 
				
			||||||
	if (resp->xdr.buf->page_len) {
 | 
							WARN_ON_ONCE(1);
 | 
				
			||||||
		WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
 | 
					 | 
				
			||||||
		return nfserr_resource;
 | 
							return nfserr_resource;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	xdr_commit_encode(xdr);
 | 
						xdr_commit_encode(xdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	maxcount = svc_max_payload(resp->rqstp);
 | 
						maxcount = svc_max_payload(resp->rqstp);
 | 
				
			||||||
 | 
						if (maxcount > xdr->buf->buflen - xdr->buf->len)
 | 
				
			||||||
 | 
							maxcount = xdr->buf->buflen - xdr->buf->len;
 | 
				
			||||||
	if (maxcount > read->rd_length)
 | 
						if (maxcount > read->rd_length)
 | 
				
			||||||
		maxcount = read->rd_length;
 | 
							maxcount = read->rd_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue