Merge branch 'for-3.18' of git://linux-nfs.org/~bfields/linux
[sfrench/cifs-2.6.git] / fs / nfsd / nfs4xdr.c
index 7ec646380005a1383cf1b1f1e97dfd3e21f6605b..eeea7a90eb873d6d4d8b606ddf2584a1c3a9f85c 100644 (file)
@@ -2688,6 +2688,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
        struct xdr_stream *xdr = cd->xdr;
        int start_offset = xdr->buf->len;
        int cookie_offset;
+       u32 name_and_cookie;
        int entry_bytes;
        __be32 nfserr = nfserr_toosmall;
        __be64 wire_offset;
@@ -2749,7 +2750,14 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
        cd->rd_maxcount -= entry_bytes;
        if (!cd->rd_dircount)
                goto fail;
-       cd->rd_dircount--;
+       /*
+        * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so
+        * let's always let through the first entry, at least:
+        */
+       name_and_cookie = 4 * XDR_QUADLEN(namlen) + 8;
+       if (name_and_cookie > cd->rd_dircount && cd->cookie_offset)
+               goto fail;
+       cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie);
        cd->cookie_offset = cookie_offset;
 skip_entry:
        cd->common.err = nfs_ok;
@@ -3127,7 +3135,8 @@ static __be32 nfsd4_encode_splice_read(
 
        buf->page_len = maxcount;
        buf->len += maxcount;
-       xdr->page_ptr += (maxcount + PAGE_SIZE - 1) / PAGE_SIZE;
+       xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
+                                                       / PAGE_SIZE;
 
        /* Use rest of head for padding and remaining ops: */
        buf->tail[0].iov_base = xdr->p;
@@ -3352,6 +3361,10 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
        }
        maxcount = min_t(int, maxcount-16, bytes_left);
 
+       /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */
+       if (!readdir->rd_dircount)
+               readdir->rd_dircount = INT_MAX;
+
        readdir->xdr = xdr;
        readdir->rd_maxcount = maxcount;
        readdir->common.err = 0;