VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / nfsd / nfs4xdr.c
index b98b5fe..e95b02a 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/nfsd_idmap.h>
+#include <linux/vserver/xid.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -287,27 +288,40 @@ u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
        return p;
 }
 
-char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
+static int
+defer_free(struct nfsd4_compoundargs *argp,
+               void (*release)(const void *), void *p)
 {
        struct tmpbuf *tb;
+
+       tb = kmalloc(sizeof(*tb), GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+       tb->buf = p;
+       tb->release = release;
+       tb->next = argp->to_free;
+       argp->to_free = tb;
+       return 0;
+}
+
+char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
+{
+       void *new = NULL;
        if (p == argp->tmp) {
-               p = kmalloc(nbytes, GFP_KERNEL);
-               if (!p) return NULL;
+               new = kmalloc(nbytes, GFP_KERNEL);
+               if (!new) return NULL;
+               p = new;
                memcpy(p, argp->tmp, nbytes);
        } else {
                if (p != argp->tmpp)
                        BUG();
                argp->tmpp = NULL;
        }
-       tb = kmalloc(sizeof(*tb), GFP_KERNEL);
-       if (!tb) {
-               kfree(p);
+       if (defer_free(argp, kfree, p)) {
+               kfree(new);
                return NULL;
-       }
-       tb->buf = p;
-       tb->next = argp->to_free;
-       argp->to_free = tb;
-       return (char*)p;
+       } else
+               return (char *)p;
 }
 
 
@@ -538,9 +552,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
        case NF4SOCK:
        case NF4FIFO:
        case NF4DIR:
-               break;
        default:
-               goto xdr_error;
+               break;
        }
 
        READ_BUF(4);
@@ -1289,6 +1302,39 @@ static u32 nfs4_ftypes[16] = {
         NF4SOCK, NF4BAD,  NF4LNK, NF4BAD,
 };
 
+static int
+nfsd4_encode_name(struct svc_rqst *rqstp, int group, uid_t id,
+                       u32 **p, int *buflen)
+{
+       int status;
+
+       if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
+               return nfserr_resource;
+       if (group)
+               status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));
+       else
+               status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));
+       if (status < 0)
+               return nfserrno(status);
+       *p = xdr_encode_opaque(*p, NULL, status);
+       *buflen -= (XDR_QUADLEN(status) << 2) + 4;
+       BUG_ON(*buflen < 0);
+       return 0;
+}
+
+static inline int
+nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen)
+{
+       return nfsd4_encode_name(rqstp, uid, 0, p, buflen);
+}
+
+static inline int
+nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen)
+{
+       return nfsd4_encode_name(rqstp, gid, 1, p, buflen);
+}
+
+
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
  * ourselves.
@@ -1304,10 +1350,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        u32 bmval0 = bmval[0];
        u32 bmval1 = bmval[1];
        struct kstat stat;
-       char owner[IDMAP_NAMESZ];
-       u32 ownerlen = 0;
-       char group[IDMAP_NAMESZ];
-       u32 grouplen = 0;
        struct svc_fh tempfh;
        struct kstatfs statfs;
        int buflen = *countp << 2;
@@ -1338,23 +1380,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                        goto out;
                fhp = &tempfh;
        }
-       if (bmval1 & FATTR4_WORD1_OWNER) {
-               int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner);
-               if (temp < 0) {
-                       status = temp;
-                       goto out_nfserr;
-               }
-               ownerlen = (unsigned) temp;
-       }
-       if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-               int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group);
-               if (temp < 0) {
-                       status = temp;
-                       goto out_nfserr;
-               }
-               grouplen = (unsigned) temp;
-       }
-
        if ((buflen -= 16) < 0)
                goto out_resource;
 
@@ -1536,18 +1561,22 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                WRITE32(stat.nlink);
        }
        if (bmval1 & FATTR4_WORD1_OWNER) {
-               buflen -= (XDR_QUADLEN(ownerlen) << 2) + 4;
-               if (buflen < 0)
+               status = nfsd4_encode_user(rqstp,
+                       XIDINO_UID(XID_TAG(dentry->d_inode),
+                       stat.uid, stat.xid), &p, &buflen);
+               if (status == nfserr_resource)
                        goto out_resource;
-               WRITE32(ownerlen);
-               WRITEMEM(owner, ownerlen);
+               if (status)
+                       goto out;
        }
        if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-               buflen -= (XDR_QUADLEN(grouplen) << 2) + 4;
-               if (buflen < 0)
+               status = nfsd4_encode_group(rqstp,
+                       XIDINO_GID(XID_TAG(dentry->d_inode),
+                       stat.gid, stat.xid), &p, &buflen);
+               if (status == nfserr_resource)
                        goto out_resource;
-               WRITE32(grouplen);
-               WRITEMEM(group, grouplen);
+               if (status)
+                       goto out;
        }
        if (bmval1 & FATTR4_WORD1_RAWDEV) {
                if ((buflen -= 8) < 0)
@@ -1686,6 +1715,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
                        goto error;
                }
 
+               exp_get(exp);
                if (d_mountpoint(dentry)) {
                        if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, 
                                         &exp))) {      
@@ -1697,6 +1727,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
                         * this call will be retried.
                         */
                                dput(dentry);
+                               exp_put(exp);
                                nfserr = nfserr_dropit;
                                goto error;
                        }
@@ -1706,6 +1737,8 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
                nfserr = nfsd4_encode_fattr(NULL, exp,
                                dentry, p, &buflen, cd->rd_bmval,
                                cd->rd_rqstp);
+               dput(dentry);
+               exp_put(exp);
                if (!nfserr) {
                        p += buflen;
                        goto out;
@@ -2446,6 +2479,24 @@ nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
         return xdr_ressize_check(rqstp, p);
 }
 
+void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
+{
+       if (args->ops != args->iops) {
+               kfree(args->ops);
+               args->ops = args->iops;
+       }
+       if (args->tmpp) {
+               kfree(args->tmpp);
+               args->tmpp = NULL;
+       }
+       while (args->to_free) {
+               struct tmpbuf *tb = args->to_free;
+               args->to_free = tb->next;
+               tb->release(tb->buf);
+               kfree(tb);
+       }
+}
+
 int
 nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
 {
@@ -2462,20 +2513,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun
 
        status = nfsd4_decode_compound(args);
        if (status) {
-               if (args->ops != args->iops) {
-                       kfree(args->ops);
-                       args->ops = args->iops;
-               }
-               if (args->tmpp) {
-                       kfree(args->tmpp);
-                       args->tmpp = NULL;
-               }
-               while (args->to_free) {
-                       struct tmpbuf *tb = args->to_free;
-                       args->to_free = tb->next;
-                       kfree(tb->buf);
-                       kfree(tb);
-               }
+               nfsd4_release_compoundargs(args);
        }
        return !status;
 }
@@ -2486,7 +2524,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compound
        /*
         * All that remains is to write the tag and operation count...
         */
-       struct iovec *iov;
+       struct kvec *iov;
        p = resp->tagp;
        *p++ = htonl(resp->taglen);
        memcpy(p, resp->tag, resp->taglen);