Merge branch 'slab/urgent' into slab/next
[pandora-kernel.git] / fs / nfs / nfs4xdr.c
index c191a9b..1dce12f 100644 (file)
@@ -113,7 +113,11 @@ static int nfs4_stat_to_errno(int);
 #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
 #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
 #define encode_fsinfo_maxsz    (encode_getattr_maxsz)
-#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + 15)
+/* The 5 accounts for the PNFS attributes, and assumes that at most three
+ * layout types will be returned.
+ */
+#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz + 4 + 8 + 5)
 #define encode_renew_maxsz     (op_encode_hdr_maxsz + 3)
 #define decode_renew_maxsz     (op_decode_hdr_maxsz)
 #define encode_setclientid_maxsz \
@@ -314,6 +318,17 @@ static int nfs4_stat_to_errno(int);
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
 #define encode_reclaim_complete_maxsz  (op_encode_hdr_maxsz + 4)
 #define decode_reclaim_complete_maxsz  (op_decode_hdr_maxsz + 4)
+#define encode_getdevicelist_maxsz (op_encode_hdr_maxsz + 4 + \
+                               encode_verifier_maxsz)
+#define decode_getdevicelist_maxsz (op_decode_hdr_maxsz + \
+                               2 /* nfs_cookie4 gdlr_cookie */ + \
+                               decode_verifier_maxsz \
+                                 /* verifier4 gdlr_verifier */ + \
+                               1 /* gdlr_deviceid_list count */ + \
+                               XDR_QUADLEN(NFS4_PNFS_GETDEVLIST_MAXNUM * \
+                                           NFS4_DEVICEID4_SIZE) \
+                                 /* gdlr_deviceid_list */ + \
+                               1 /* bool gdlr_eof */)
 #define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \
                                XDR_QUADLEN(NFS4_DEVICEID4_SIZE))
 #define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \
@@ -748,6 +763,14 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_dec_reclaim_complete_sz   (compound_decode_hdr_maxsz + \
                                         decode_sequence_maxsz + \
                                         decode_reclaim_complete_maxsz)
+#define NFS4_enc_getdevicelist_sz (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_getdevicelist_maxsz)
+#define NFS4_dec_getdevicelist_sz (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_getdevicelist_maxsz)
 #define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz +    \
                                encode_sequence_maxsz +\
                                encode_getdeviceinfo_maxsz)
@@ -1104,6 +1127,35 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm
        hdr->replen += decode_getattr_maxsz;
 }
 
+static void
+encode_getattr_three(struct xdr_stream *xdr,
+                    uint32_t bm0, uint32_t bm1, uint32_t bm2,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(OP_GETATTR);
+       if (bm2) {
+               p = reserve_space(xdr, 16);
+               *p++ = cpu_to_be32(3);
+               *p++ = cpu_to_be32(bm0);
+               *p++ = cpu_to_be32(bm1);
+               *p = cpu_to_be32(bm2);
+       } else if (bm1) {
+               p = reserve_space(xdr, 12);
+               *p++ = cpu_to_be32(2);
+               *p++ = cpu_to_be32(bm0);
+               *p = cpu_to_be32(bm1);
+       } else {
+               p = reserve_space(xdr, 8);
+               *p++ = cpu_to_be32(1);
+               *p = cpu_to_be32(bm0);
+       }
+       hdr->nops++;
+       hdr->replen += decode_getattr_maxsz;
+}
+
 static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
        encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
@@ -1112,8 +1164,11 @@ static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct c
 
 static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
-       encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
-                          bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
+       encode_getattr_three(xdr,
+                            bitmask[0] & nfs4_fsinfo_bitmap[0],
+                            bitmask[1] & nfs4_fsinfo_bitmap[1],
+                            bitmask[2] & nfs4_fsinfo_bitmap[2],
+                            hdr);
 }
 
 static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
@@ -1854,6 +1909,26 @@ static void encode_sequence(struct xdr_stream *xdr,
 }
 
 #ifdef CONFIG_NFS_V4_1
+static void
+encode_getdevicelist(struct xdr_stream *xdr,
+                    const struct nfs4_getdevicelist_args *args,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+       nfs4_verifier dummy = {
+               .data = "dummmmmy",
+       };
+
+       p = reserve_space(xdr, 20);
+       *p++ = cpu_to_be32(OP_GETDEVICELIST);
+       *p++ = cpu_to_be32(args->layoutclass);
+       *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM);
+       xdr_encode_hyper(p, 0ULL);                          /* cookie */
+       encode_nfs4_verifier(xdr, &dummy);
+       hdr->nops++;
+       hdr->replen += decode_getdevicelist_maxsz;
+}
+
 static void
 encode_getdeviceinfo(struct xdr_stream *xdr,
                     const struct nfs4_getdeviceinfo_args *args,
@@ -1916,7 +1991,7 @@ encode_layoutcommit(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
        /* Only whole file layouts */
        p = xdr_encode_hyper(p, 0); /* offset */
-       p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */
+       p = xdr_encode_hyper(p, args->lastbytewritten + 1);     /* length */
        *p++ = cpu_to_be32(0); /* reclaim */
        p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
        *p++ = cpu_to_be32(1); /* newoffset = TRUE */
@@ -2604,7 +2679,7 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .nops   = 0,
        };
-       const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
+       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_setclientid_confirm(xdr, arg, &hdr);
@@ -2748,7 +2823,7 @@ static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
        };
-       const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
+       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->la_seq_args, &hdr);
@@ -2774,6 +2849,24 @@ static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
        encode_nops(&hdr);
 }
 
+/*
+ * Encode GETDEVICELIST request
+ */
+static void nfs4_xdr_enc_getdevicelist(struct rpc_rqst *req,
+                                      struct xdr_stream *xdr,
+                                      struct nfs4_getdevicelist_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, args->fh, &hdr);
+       encode_getdevicelist(xdr, args, &hdr);
+       encode_nops(&hdr);
+}
+
 /*
  * Encode GETDEVICEINFO request
  */
@@ -3011,14 +3104,17 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
                goto out_overflow;
        bmlen = be32_to_cpup(p);
 
-       bitmap[0] = bitmap[1] = 0;
+       bitmap[0] = bitmap[1] = bitmap[2] = 0;
        p = xdr_inline_decode(xdr, (bmlen << 2));
        if (unlikely(!p))
                goto out_overflow;
        if (bmlen > 0) {
                bitmap[0] = be32_to_cpup(p++);
-               if (bmlen > 1)
-                       bitmap[1] = be32_to_cpup(p);
+               if (bmlen > 1) {
+                       bitmap[1] = be32_to_cpup(p++);
+                       if (bmlen > 2)
+                               bitmap[2] = be32_to_cpup(p);
+               }
        }
        return 0;
 out_overflow:
@@ -3050,8 +3146,9 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
                        return ret;
                bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
        } else
-               bitmask[0] = bitmask[1] = 0;
-       dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
+               bitmask[0] = bitmask[1] = bitmask[2] = 0;
+       dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__,
+               bitmask[0], bitmask[1], bitmask[2]);
        return 0;
 }
 
@@ -4105,7 +4202,7 @@ out_overflow:
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4131,7 +4228,7 @@ xdr_error:
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4163,7 +4260,7 @@ xdr_error:
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4303,7 +4400,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 {
        __be32 *savep;
        uint32_t attrlen,
-                bitmap[2] = {0};
+                bitmap[3] = {0};
        int status;
 
        status = decode_op_hdr(xdr, OP_GETATTR);
@@ -4389,10 +4486,32 @@ static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
        return status;
 }
 
+/*
+ * The prefered block size for layout directed io
+ */
+static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
+                                     uint32_t *res)
+{
+       __be32 *p;
+
+       dprintk("%s: bitmap is %x\n", __func__, bitmap[2]);
+       *res = 0;
+       if (bitmap[2] & FATTR4_WORD2_LAYOUT_BLKSIZE) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p)) {
+                       print_overflow_msg(__func__, xdr);
+                       return -EIO;
+               }
+               *res = be32_to_cpup(p);
+               bitmap[2] &= ~FATTR4_WORD2_LAYOUT_BLKSIZE;
+       }
+       return 0;
+}
+
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2];
+       uint32_t attrlen, bitmap[3];
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4420,6 +4539,9 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
        status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
        if (status != 0)
                goto xdr_error;
+       status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize);
+       if (status)
+               goto xdr_error;
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
@@ -4839,7 +4961,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 {
        __be32 *savep;
        uint32_t attrlen,
-                bitmap[2] = {0};
+                bitmap[3] = {0};
        struct kvec *iov = req->rq_rcv_buf.head;
        int status;
 
@@ -5268,6 +5390,53 @@ out_overflow:
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/*
+ * TODO: Need to handle case when EOF != true;
+ */
+static int decode_getdevicelist(struct xdr_stream *xdr,
+                               struct pnfs_devicelist *res)
+{
+       __be32 *p;
+       int status, i;
+       struct nfs_writeverf verftemp;
+
+       status = decode_op_hdr(xdr, OP_GETDEVICELIST);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 8 + 8 + 4);
+       if (unlikely(!p))
+               goto out_overflow;
+
+       /* TODO: Skip cookie for now */
+       p += 2;
+
+       /* Read verifier */
+       p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
+
+       res->num_devs = be32_to_cpup(p);
+
+       dprintk("%s: num_dev %d\n", __func__, res->num_devs);
+
+       if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) {
+               printk(KERN_ERR "%s too many result dev_num %u\n",
+                               __func__, res->num_devs);
+               return -EIO;
+       }
+
+       p = xdr_inline_decode(xdr,
+                             res->num_devs * NFS4_DEVICEID4_SIZE + 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       for (i = 0; i < res->num_devs; i++)
+               p = xdr_decode_opaque_fixed(p, res->dev_id[i].data,
+                                           NFS4_DEVICEID4_SIZE);
+       res->eof = be32_to_cpup(p);
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
 
 static int decode_getdeviceinfo(struct xdr_stream *xdr,
                                struct pnfs_device *pdev)
@@ -5430,6 +5599,7 @@ static int decode_layoutcommit(struct xdr_stream *xdr,
        int status;
 
        status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT);
+       res->status = status;
        if (status)
                return status;
 
@@ -6541,6 +6711,32 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
        return status;
 }
 
+/*
+ * Decode GETDEVICELIST response
+ */
+static int nfs4_xdr_dec_getdevicelist(struct rpc_rqst *rqstp,
+                                     struct xdr_stream *xdr,
+                                     struct nfs4_getdevicelist_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       dprintk("encoding getdevicelist!\n");
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status != 0)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status != 0)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status != 0)
+               goto out;
+       status = decode_getdevicelist(xdr, res->devlist);
+out:
+       return status;
+}
+
 /*
  * Decode GETDEVINFO response
  */
@@ -6722,7 +6918,7 @@ out:
 int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                       int plus)
 {
-       uint32_t bitmap[2] = {0};
+       uint32_t bitmap[3] = {0};
        uint32_t len;
        __be32 *p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
@@ -6908,6 +7104,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(SECINFO_NO_NAME,   enc_secinfo_no_name,    dec_secinfo_no_name),
        PROC(TEST_STATEID,      enc_test_stateid,       dec_test_stateid),
        PROC(FREE_STATEID,      enc_free_stateid,       dec_free_stateid),
+       PROC(GETDEVICELIST,     enc_getdevicelist,      dec_getdevicelist),
 #endif /* CONFIG_NFS_V4_1 */
 };