Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / fs / nfs / nfs3xdr.c
index 640316a..8849694 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfsacl.h>
 #include <linux/vserver/xid.h>
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
@@ -80,6 +81,11 @@ extern int                   nfs_stat_to_errno(int);
 #define NFS3_pathconfres_sz    (1+NFS3_post_op_attr_sz+6)
 #define NFS3_commitres_sz      (1+NFS3_wcc_data_sz+2)
 
+#define ACL3_getaclargs_sz     (NFS3_fh_sz+1)
+#define ACL3_setaclargs_sz     (NFS3_fh_sz+1+2*(2+5*3))
+#define ACL3_getaclres_sz      (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
+#define ACL3_setaclres_sz      (1+NFS3_post_op_attr_sz)
+
 /*
  * Map file type to S_IFMT bits
  */
@@ -169,7 +175,6 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 
        /* Update the mode bits */
        fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
-       fattr->timestamp = jiffies;
        return p;
 }
 
@@ -178,7 +183,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr, int tagxid)
 {
        if (attr->ia_valid & ATTR_MODE) {
                *p++ = xdr_one;
-               *p++ = htonl(attr->ia_mode);
+               *p++ = htonl(attr->ia_mode & S_IALLUGO);
        } else {
                *p++ = xdr_zero;
        }
@@ -635,6 +640,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
        return 0;
 }
 
+#ifdef CONFIG_NFS_V3_ACL
+/*
+ * Encode GETACL arguments
+ */
+static int
+nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
+                   struct nfs3_getaclargs *args)
+{
+       struct rpc_auth *auth = req->rq_task->tk_auth;
+       unsigned int replen;
+
+       p = xdr_encode_fhandle(p, args->fh);
+       *p++ = htonl(args->mask);
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+       if (args->mask & (NFS_ACL | NFS_DFACL)) {
+               /* Inline the page array */
+               replen = (RPC_REPHDRSIZE + auth->au_rslack +
+                         ACL3_getaclres_sz) << 2;
+               xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
+                                NFSACL_MAXPAGES << PAGE_SHIFT);
+       }
+       return 0;
+}
+
+/*
+ * Encode SETACL arguments
+ */
+static int
+nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
+                   struct nfs3_setaclargs *args)
+{
+       struct xdr_buf *buf = &req->rq_snd_buf;
+       unsigned int base, len_in_head, len = nfsacl_size(
+               (args->mask & NFS_ACL)   ? args->acl_access  : NULL,
+               (args->mask & NFS_DFACL) ? args->acl_default : NULL);
+       int count, err;
+
+       p = xdr_encode_fhandle(p, NFS_FH(args->inode));
+       *p++ = htonl(args->mask);
+       base = (char *)p - (char *)buf->head->iov_base;
+       /* put as much of the acls into head as possible. */
+       len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
+       len -= len_in_head;
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
+
+       for (count = 0; (count << PAGE_SHIFT) < len; count++) {
+               args->pages[count] = alloc_page(GFP_KERNEL);
+               if (!args->pages[count]) {
+                       while (count)
+                               __free_page(args->pages[--count]);
+                       return -ENOMEM;
+               }
+       }
+       xdr_encode_pages(buf, args->pages, 0, len);
+
+       err = nfsacl_encode(buf, base, args->inode,
+                           (args->mask & NFS_ACL) ?
+                           args->acl_access : NULL, 1, 0);
+       if (err > 0)
+               err = nfsacl_encode(buf, base + err, args->inode,
+                                   (args->mask & NFS_DFACL) ?
+                                   args->acl_default : NULL, 1,
+                                   NFS_ACL_DEFAULT);
+       return (err > 0) ? 0 : err;
+}
+#endif  /* CONFIG_NFS_V3_ACL */
+
 /*
  * NFS XDR decode functions
  */
@@ -986,6 +1059,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
        return 0;
 }
 
+#ifdef CONFIG_NFS_V3_ACL
+/*
+ * Decode GETACL reply
+ */
+static int
+nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
+                  struct nfs3_getaclres *res)
+{
+       struct xdr_buf *buf = &req->rq_rcv_buf;
+       int status = ntohl(*p++);
+       struct posix_acl **acl;
+       unsigned int *aclcnt;
+       int err, base;
+
+       if (status != 0)
+               return -nfs_stat_to_errno(status);
+       p = xdr_decode_post_op_attr(p, res->fattr);
+       res->mask = ntohl(*p++);
+       if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
+               return -EINVAL;
+       base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
+
+       acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
+       aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
+       err = nfsacl_decode(buf, base, aclcnt, acl);
+
+       acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
+       aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
+       if (err > 0)
+               err = nfsacl_decode(buf, base + err, aclcnt, acl);
+       return (err > 0) ? 0 : err;
+}
+
+/*
+ * Decode setacl reply.
+ */
+static int
+nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+{
+       int status = ntohl(*p++);
+
+       if (status)
+               return -nfs_stat_to_errno(status);
+       xdr_decode_post_op_attr(p, fattr);
+       return 0;
+}
+#endif  /* CONFIG_NFS_V3_ACL */
+
 #ifndef MAX
 # define MAX(a, b)     (((a) > (b))? (a) : (b))
 #endif
@@ -996,7 +1117,9 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
        .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,                 \
        .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,                 \
        .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,       \
-       .p_timer     = timer                                            \
+       .p_timer     = timer,                                           \
+       .p_statidx   = NFS3PROC_##proc,                                 \
+       .p_name      = #proc,                                           \
        }
 
 struct rpc_procinfo    nfs3_procedures[] = {
@@ -1025,7 +1148,34 @@ struct rpc_procinfo      nfs3_procedures[] = {
 
 struct rpc_version             nfs_version3 = {
        .number                 = 3,
-       .nrprocs                = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
+       .nrprocs                = ARRAY_SIZE(nfs3_procedures),
        .procs                  = nfs3_procedures
 };
 
+#ifdef CONFIG_NFS_V3_ACL
+static struct rpc_procinfo     nfs3_acl_procedures[] = {
+       [ACLPROC3_GETACL] = {
+               .p_proc = ACLPROC3_GETACL,
+               .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
+               .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
+               .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
+               .p_timer = 1,
+               .p_name = "GETACL",
+       },
+       [ACLPROC3_SETACL] = {
+               .p_proc = ACLPROC3_SETACL,
+               .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
+               .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
+               .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
+               .p_timer = 0,
+               .p_name = "SETACL",
+       },
+};
+
+struct rpc_version             nfsacl_version3 = {
+       .number                 = 3,
+       .nrprocs                = sizeof(nfs3_acl_procedures)/
+                                 sizeof(nfs3_acl_procedures[0]),
+       .procs                  = nfs3_acl_procedures,
+};
+#endif  /* CONFIG_NFS_V3_ACL */