Merge to Fedora kernel-2.6.7-1.441
[linux-2.6.git] / fs / nfsd / nfs3xdr.c
index 1e3af06..f5df830 100644 (file)
@@ -847,8 +847,18 @@ encode_entry(struct readdir_cd *ccd, const char *name,
        int             elen;           /* estimated entry length in words */
        int             num_entry_words = 0;    /* actual number of words */
 
-       if (cd->offset)
-               xdr_encode_hyper(cd->offset, (u64) offset);
+       if (cd->offset) {
+               u64 offset64 = offset;
+
+               if (unlikely(cd->offset1)) {
+                       /* we ended up with offset on a page boundary */
+                       *cd->offset = htonl(offset64 >> 32);
+                       *cd->offset1 = htonl(offset64 & 0xffffffff);
+                       cd->offset1 = NULL;
+               } else {
+                       xdr_encode_hyper(cd->offset, (u64) offset);
+               }
+       }
 
        /*
        dprintk("encode_entry(%.*s @%ld%s)\n",
@@ -929,17 +939,32 @@ encode_entry(struct readdir_cd *ccd, const char *name,
                        /* update offset */
                        cd->offset = cd->buffer + (cd->offset - tmp);
                } else {
+                       unsigned int offset_r = (cd->offset - tmp) << 2;
+
+                       /* update pointer to offset location.
+                        * This is a 64bit quantity, so we need to
+                        * deal with 3 cases:
+                        *  -   entirely in first page
+                        *  -   entirely in second page
+                        *  -   4 bytes in each page
+                        */
+                       if (offset_r + 8 <= len1) {
+                               cd->offset = p + (cd->offset - tmp);
+                       } else if (offset_r >= len1) {
+                               cd->offset -= len1 >> 2;
+                       } else {
+                               /* sitting on the fence */
+                               BUG_ON(offset_r != len1 - 4);
+                               cd->offset = p + (cd->offset - tmp);
+                               cd->offset1 = tmp;
+                       }
+
                        len2 = (num_entry_words << 2) - len1;
 
                        /* move from temp page to current and next pages */
                        memmove(p, tmp, len1);
                        memmove(tmp, (caddr_t)tmp+len1, len2);
 
-                       /* update offset */
-                       if (((cd->offset - tmp) << 2) < len1)
-                               cd->offset = p + (cd->offset - tmp);
-                       else
-                               cd->offset -= len1 >> 2;
                        p = tmp + (len2 >> 2);
                }
        }