Merge tag 'netfs-lib-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowe...
[linux-2.6-microblaze.git] / fs / nfsd / nfs3proc.c
index 8675851..17715a6 100644 (file)
@@ -126,14 +126,15 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp)
 {
        struct nfsd_fhandle *argp = rqstp->rq_argp;
        struct nfsd3_readlinkres *resp = rqstp->rq_resp;
-       char *buffer = page_address(*(rqstp->rq_next_page++));
 
        dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
 
        /* Read the symlink. */
        fh_copy(&resp->fh, &argp->fh);
        resp->len = NFS3_MAXPATHLEN;
-       resp->status = nfsd_readlink(rqstp, &resp->fh, buffer, &resp->len);
+       resp->pages = rqstp->rq_next_page++;
+       resp->status = nfsd_readlink(rqstp, &resp->fh,
+                                    page_address(*resp->pages), &resp->len);
        return rpc_success;
 }
 
@@ -158,6 +159,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
 
        v = 0;
        len = argp->count;
+       resp->pages = rqstp->rq_next_page;
        while (len > 0) {
                struct page *page = *(rqstp->rq_next_page++);
 
@@ -439,17 +441,30 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
                                     struct nfsd3_readdirres *resp,
                                     int count)
 {
+       struct xdr_buf *buf = &resp->dirlist;
+       struct xdr_stream *xdr = &resp->xdr;
+
        count = min_t(u32, count, svc_max_payload(rqstp));
 
-       /* Convert byte count to number of words (i.e. >> 2),
-        * and reserve room for the NULL ptr & eof flag (-2 words) */
-       resp->buflen = (count >> 2) - 2;
+       memset(buf, 0, sizeof(*buf));
 
-       resp->buffer = page_address(*rqstp->rq_next_page);
+       /* Reserve room for the NULL ptr & eof flag (-2 words) */
+       buf->buflen = count - XDR_UNIT * 2;
+       buf->pages = rqstp->rq_next_page;
        while (count > 0) {
                rqstp->rq_next_page++;
                count -= PAGE_SIZE;
        }
+
+       /* This is xdr_init_encode(), but it assumes that
+        * the head kvec has already been consumed. */
+       xdr_set_scratch_buffer(xdr, NULL, 0);
+       xdr->buf = buf;
+       xdr->page_ptr = buf->pages;
+       xdr->iov = NULL;
+       xdr->p = page_address(*buf->pages);
+       xdr->end = xdr->p + (PAGE_SIZE >> 2);
+       xdr->rqst = NULL;
 }
 
 /*
@@ -460,10 +475,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 {
        struct nfsd3_readdirargs *argp = rqstp->rq_argp;
        struct nfsd3_readdirres  *resp = rqstp->rq_resp;
-       int             count = 0;
        loff_t          offset;
-       struct page     **p;
-       caddr_t         page_addr = NULL;
 
        dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
                                SVCFH_fmt(&argp->fh),
@@ -471,39 +483,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 
        nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
 
-       /* Read directory and encode entries on the fly */
        fh_copy(&resp->fh, &argp->fh);
-
        resp->common.err = nfs_ok;
+       resp->cookie_offset = 0;
        resp->rqstp = rqstp;
        offset = argp->cookie;
-
        resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
-                                   &resp->common, nfs3svc_encode_entry);
+                                   &resp->common, nfs3svc_encode_entry3);
        memcpy(resp->verf, argp->verf, 8);
-       count = 0;
-       for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
-               page_addr = page_address(*p);
+       nfs3svc_encode_cookie3(resp, offset);
 
-               if (((caddr_t)resp->buffer >= page_addr) &&
-                   ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
-                       count += (caddr_t)resp->buffer - page_addr;
-                       break;
-               }
-               count += PAGE_SIZE;
-       }
-       resp->count = count >> 2;
-       if (resp->offset) {
-               if (unlikely(resp->offset1)) {
-                       /* we ended up with offset on a page boundary */
-                       *resp->offset = htonl(offset >> 32);
-                       *resp->offset1 = htonl(offset & 0xffffffff);
-                       resp->offset1 = NULL;
-               } else {
-                       xdr_encode_hyper(resp->offset, offset);
-               }
-               resp->offset = NULL;
-       }
+       /* Recycle only pages that were part of the reply */
+       rqstp->rq_next_page = resp->xdr.page_ptr + 1;
 
        return rpc_success;
 }
@@ -517,10 +508,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 {
        struct nfsd3_readdirargs *argp = rqstp->rq_argp;
        struct nfsd3_readdirres  *resp = rqstp->rq_resp;
-       int     count = 0;
        loff_t  offset;
-       struct page **p;
-       caddr_t page_addr = NULL;
 
        dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
                                SVCFH_fmt(&argp->fh),
@@ -528,10 +516,9 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 
        nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
 
-       /* Read directory and encode entries on the fly */
        fh_copy(&resp->fh, &argp->fh);
-
        resp->common.err = nfs_ok;
+       resp->cookie_offset = 0;
        resp->rqstp = rqstp;
        offset = argp->cookie;
 
@@ -545,30 +532,12 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
        }
 
        resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
-                                   &resp->common, nfs3svc_encode_entry_plus);
+                                   &resp->common, nfs3svc_encode_entryplus3);
        memcpy(resp->verf, argp->verf, 8);
-       for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
-               page_addr = page_address(*p);
+       nfs3svc_encode_cookie3(resp, offset);
 
-               if (((caddr_t)resp->buffer >= page_addr) &&
-                   ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
-                       count += (caddr_t)resp->buffer - page_addr;
-                       break;
-               }
-               count += PAGE_SIZE;
-       }
-       resp->count = count >> 2;
-       if (resp->offset) {
-               if (unlikely(resp->offset1)) {
-                       /* we ended up with offset on a page boundary */
-                       *resp->offset = htonl(offset >> 32);
-                       *resp->offset1 = htonl(offset & 0xffffffff);
-                       resp->offset1 = NULL;
-               } else {
-                       xdr_encode_hyper(resp->offset, offset);
-               }
-               resp->offset = NULL;
-       }
+       /* Recycle only pages that were part of the reply */
+       rqstp->rq_next_page = resp->xdr.page_ptr + 1;
 
 out:
        return rpc_success;
@@ -736,7 +705,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
        [NFS3PROC_GETATTR] = {
                .pc_func = nfsd3_proc_getattr,
                .pc_decode = nfs3svc_decode_fhandleargs,
-               .pc_encode = nfs3svc_encode_attrstatres,
+               .pc_encode = nfs3svc_encode_getattrres,
                .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_fhandle),
                .pc_ressize = sizeof(struct nfsd3_attrstatres),
@@ -758,7 +727,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
        [NFS3PROC_LOOKUP] = {
                .pc_func = nfsd3_proc_lookup,
                .pc_decode = nfs3svc_decode_diropargs,
-               .pc_encode = nfs3svc_encode_diropres,
+               .pc_encode = nfs3svc_encode_lookupres,
                .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_diropargs),
                .pc_ressize = sizeof(struct nfsd3_diropres),