patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / nfsd / nfs3xdr.c
index 8291752..a45bd68 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr3.h>
+#include <linux/vserver/xid.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -176,8 +177,10 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
        *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
        *p++ = htonl((u32) stat.mode);
        *p++ = htonl((u32) stat.nlink);
-       *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
-       *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
+       *p++ = htonl((u32) nfsd_ruid(rqstp,
+               XIDINO_UID(stat.uid, stat.xid)));
+       *p++ = htonl((u32) nfsd_rgid(rqstp,
+               XIDINO_GID(stat.gid, stat.xid)));
        if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
        } else {
@@ -799,6 +802,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
 {
        struct svc_export       *exp;
        struct dentry           *dparent, *dchild;
+       int rv = 0;
 
        dparent = cd->fh.fh_dentry;
        exp  = cd->fh.fh_export;
@@ -813,11 +817,12 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
                dchild = lookup_one_len(name, dparent, namlen);
        if (IS_ERR(dchild))
                return 1;
-       if (d_mountpoint(dchild))
-               return 1;
-       if (fh_compose(fhp, exp, dchild, &cd->fh) != 0 || !dchild->d_inode)
-               return 1;
-       return 0;
+       if (d_mountpoint(dchild) ||
+           fh_compose(fhp, exp, dchild, &cd->fh) != 0 ||
+           !dchild->d_inode)
+               rv = 1;
+       dput(dchild);
+       return rv;
 }
 
 /*
@@ -845,8 +850,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",
@@ -927,17 +942,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);
                }
        }