perf parse-events: Reduce casts around bp_addr
[linux-2.6-microblaze.git] / fs / nfs / nfs42xdr.c
index c03f324..cc50085 100644 (file)
                                         decode_clone_maxsz + \
                                         decode_getattr_maxsz)
 
+/* Not limited by NFS itself, limited by the generic xattr code */
+#define nfs4_xattr_name_maxsz   XDR_QUADLEN(XATTR_NAME_MAX)
+
+#define encode_getxattr_maxsz   (op_encode_hdr_maxsz + 1 + \
+                                nfs4_xattr_name_maxsz)
+#define decode_getxattr_maxsz   (op_decode_hdr_maxsz + 1 + 1)
+#define encode_setxattr_maxsz   (op_encode_hdr_maxsz + \
+                                1 + nfs4_xattr_name_maxsz + 1)
+#define decode_setxattr_maxsz   (op_decode_hdr_maxsz + decode_change_info_maxsz)
+#define encode_listxattrs_maxsz  (op_encode_hdr_maxsz + 2 + 1)
+#define decode_listxattrs_maxsz  (op_decode_hdr_maxsz + 2 + 1 + 1)
+#define encode_removexattr_maxsz (op_encode_hdr_maxsz + 1 + \
+                                 nfs4_xattr_name_maxsz)
+#define decode_removexattr_maxsz (op_decode_hdr_maxsz + \
+                                 decode_change_info_maxsz)
+
+#define NFS4_enc_getxattr_sz   (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_getxattr_maxsz)
+#define NFS4_dec_getxattr_sz   (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_getxattr_maxsz)
+#define NFS4_enc_setxattr_sz   (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_setxattr_maxsz)
+#define NFS4_dec_setxattr_sz   (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_setxattr_maxsz)
+#define NFS4_enc_listxattrs_sz (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_listxattrs_maxsz)
+#define NFS4_dec_listxattrs_sz (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_listxattrs_maxsz)
+#define NFS4_enc_removexattr_sz        (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_removexattr_maxsz)
+#define NFS4_dec_removexattr_sz        (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_removexattr_maxsz)
+
+/*
+ * These values specify the maximum amount of data that is not
+ * associated with the extended attribute name or extended
+ * attribute list in the SETXATTR, GETXATTR and LISTXATTR
+ * respectively.
+ */
+const u32 nfs42_maxsetxattr_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
+                                       compound_encode_hdr_maxsz +
+                                       encode_sequence_maxsz +
+                                       encode_putfh_maxsz + 1 +
+                                       nfs4_xattr_name_maxsz)
+                                       * XDR_UNIT);
+
+const u32 nfs42_maxgetxattr_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
+                                       compound_decode_hdr_maxsz +
+                                       decode_sequence_maxsz +
+                                       decode_putfh_maxsz + 1) * XDR_UNIT);
+
+const u32 nfs42_maxlistxattrs_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
+                                       compound_decode_hdr_maxsz +
+                                       decode_sequence_maxsz +
+                                       decode_putfh_maxsz + 3) * XDR_UNIT);
+
 static void encode_fallocate(struct xdr_stream *xdr,
                             const struct nfs42_falloc_args *args)
 {
@@ -333,6 +405,210 @@ static void encode_layouterror(struct xdr_stream *xdr,
        encode_device_error(xdr, &args->errors[0]);
 }
 
+static void encode_setxattr(struct xdr_stream *xdr,
+                           const struct nfs42_setxattrargs *arg,
+                           struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       BUILD_BUG_ON(XATTR_CREATE != SETXATTR4_CREATE);
+       BUILD_BUG_ON(XATTR_REPLACE != SETXATTR4_REPLACE);
+
+       encode_op_hdr(xdr, OP_SETXATTR, decode_setxattr_maxsz, hdr);
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(arg->xattr_flags);
+       encode_string(xdr, strlen(arg->xattr_name), arg->xattr_name);
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(arg->xattr_len);
+       if (arg->xattr_len)
+               xdr_write_pages(xdr, arg->xattr_pages, 0, arg->xattr_len);
+}
+
+static int decode_setxattr(struct xdr_stream *xdr,
+                          struct nfs4_change_info *cinfo)
+{
+       int status;
+
+       status = decode_op_hdr(xdr, OP_SETXATTR);
+       if (status)
+               goto out;
+       status = decode_change_info(xdr, cinfo);
+out:
+       return status;
+}
+
+
+static void encode_getxattr(struct xdr_stream *xdr, const char *name,
+                           struct compound_hdr *hdr)
+{
+       encode_op_hdr(xdr, OP_GETXATTR, decode_getxattr_maxsz, hdr);
+       encode_string(xdr, strlen(name), name);
+}
+
+static int decode_getxattr(struct xdr_stream *xdr,
+                          struct nfs42_getxattrres *res,
+                          struct rpc_rqst *req)
+{
+       int status;
+       __be32 *p;
+       u32 len, rdlen;
+
+       status = decode_op_hdr(xdr, OP_GETXATTR);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               return -EIO;
+
+       len = be32_to_cpup(p);
+       if (len > req->rq_rcv_buf.page_len)
+               return -ERANGE;
+
+       res->xattr_len = len;
+
+       if (len > 0) {
+               rdlen = xdr_read_pages(xdr, len);
+               if (rdlen < len)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static void encode_removexattr(struct xdr_stream *xdr, const char *name,
+                              struct compound_hdr *hdr)
+{
+       encode_op_hdr(xdr, OP_REMOVEXATTR, decode_removexattr_maxsz, hdr);
+       encode_string(xdr, strlen(name), name);
+}
+
+
+static int decode_removexattr(struct xdr_stream *xdr,
+                          struct nfs4_change_info *cinfo)
+{
+       int status;
+
+       status = decode_op_hdr(xdr, OP_REMOVEXATTR);
+       if (status)
+               goto out;
+
+       status = decode_change_info(xdr, cinfo);
+out:
+       return status;
+}
+
+static void encode_listxattrs(struct xdr_stream *xdr,
+                            const struct nfs42_listxattrsargs *arg,
+                            struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       encode_op_hdr(xdr, OP_LISTXATTRS, decode_listxattrs_maxsz + 1, hdr);
+
+       p = reserve_space(xdr, 12);
+       if (unlikely(!p))
+               return;
+
+       p = xdr_encode_hyper(p, arg->cookie);
+       /*
+        * RFC 8276 says to specify the full max length of the LISTXATTRS
+        * XDR reply. Count is set to the XDR length of the names array
+        * plus the EOF marker. So, add the cookie and the names count.
+        */
+       *p = cpu_to_be32(arg->count + 8 + 4);
+}
+
+static int decode_listxattrs(struct xdr_stream *xdr,
+                           struct nfs42_listxattrsres *res)
+{
+       int status;
+       __be32 *p;
+       u32 count, len, ulen;
+       size_t left, copied;
+       char *buf;
+
+       status = decode_op_hdr(xdr, OP_LISTXATTRS);
+       if (status) {
+               /*
+                * Special case: for LISTXATTRS, NFS4ERR_TOOSMALL
+                * should be translated to ERANGE.
+                */
+               if (status == -ETOOSMALL)
+                       status = -ERANGE;
+               goto out;
+       }
+
+       p = xdr_inline_decode(xdr, 8);
+       if (unlikely(!p))
+               return -EIO;
+
+       xdr_decode_hyper(p, &res->cookie);
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               return -EIO;
+
+       left = res->xattr_len;
+       buf = res->xattr_buf;
+
+       count = be32_to_cpup(p);
+       copied = 0;
+
+       /*
+        * We have asked for enough room to encode the maximum number
+        * of possible attribute names, so everything should fit.
+        *
+        * But, don't rely on that assumption. Just decode entries
+        * until they don't fit anymore, just in case the server did
+        * something odd.
+        */
+       while (count--) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       return -EIO;
+
+               len = be32_to_cpup(p);
+               if (len > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) {
+                       status = -ERANGE;
+                       goto out;
+               }
+
+               p = xdr_inline_decode(xdr, len);
+               if (unlikely(!p))
+                       return -EIO;
+
+               ulen = len + XATTR_USER_PREFIX_LEN + 1;
+               if (buf) {
+                       if (ulen > left) {
+                               status = -ERANGE;
+                               goto out;
+                       }
+
+                       memcpy(buf, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+                       memcpy(buf + XATTR_USER_PREFIX_LEN, p, len);
+
+                       buf[ulen - 1] = 0;
+                       buf += ulen;
+                       left -= ulen;
+               }
+               copied += ulen;
+       }
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               return -EIO;
+
+       res->eof = be32_to_cpup(p);
+       res->copied = copied;
+
+out:
+       if (status == -ERANGE && res->xattr_len == XATTR_LIST_MAX)
+               status = -E2BIG;
+
+       return status;
+}
+
 /*
  * Encode ALLOCATE request
  */
@@ -988,4 +1264,166 @@ out:
        return status;
 }
 
+#ifdef CONFIG_NFS_V4_2
+static void nfs4_xdr_enc_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr,
+                                 const void *data)
+{
+       const struct nfs42_setxattrargs *args = data;
+       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_setxattr(xdr, args, &hdr);
+       encode_nops(&hdr);
+}
+
+static int nfs4_xdr_dec_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr,
+                                void *data)
+{
+       struct nfs42_setxattrres *res = data;
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, req);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+
+       status = decode_setxattr(xdr, &res->cinfo);
+out:
+       return status;
+}
+
+static void nfs4_xdr_enc_getxattr(struct rpc_rqst *req, struct xdr_stream *xdr,
+                                 const void *data)
+{
+       const struct nfs42_getxattrargs *args = data;
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+       size_t plen;
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, args->fh, &hdr);
+       encode_getxattr(xdr, args->xattr_name, &hdr);
+
+       plen = args->xattr_len ? args->xattr_len : XATTR_SIZE_MAX;
+
+       rpc_prepare_reply_pages(req, args->xattr_pages, 0, plen,
+           hdr.replen);
+       req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
+
+       encode_nops(&hdr);
+}
+
+static int nfs4_xdr_dec_getxattr(struct rpc_rqst *rqstp,
+                                struct xdr_stream *xdr, void *data)
+{
+       struct nfs42_getxattrres *res = data;
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+       status = decode_getxattr(xdr, res, rqstp);
+out:
+       return status;
+}
+
+static void nfs4_xdr_enc_listxattrs(struct rpc_rqst *req,
+                                   struct xdr_stream *xdr, const void *data)
+{
+       const struct nfs42_listxattrsargs *args = data;
+       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_listxattrs(xdr, args, &hdr);
+
+       rpc_prepare_reply_pages(req, args->xattr_pages, 0, args->count,
+           hdr.replen);
+       req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
+
+       encode_nops(&hdr);
+}
+
+static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp,
+                                  struct xdr_stream *xdr, void *data)
+{
+       struct nfs42_listxattrsres *res = data;
+       struct compound_hdr hdr;
+       int status;
+
+       xdr_set_scratch_buffer(xdr, page_address(res->scratch), PAGE_SIZE);
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+       status = decode_listxattrs(xdr, res);
+out:
+       return status;
+}
+
+static void nfs4_xdr_enc_removexattr(struct rpc_rqst *req,
+                                    struct xdr_stream *xdr, const void *data)
+{
+       const struct nfs42_removexattrargs *args = data;
+       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_removexattr(xdr, args->xattr_name, &hdr);
+       encode_nops(&hdr);
+}
+
+static int nfs4_xdr_dec_removexattr(struct rpc_rqst *req,
+                                   struct xdr_stream *xdr, void *data)
+{
+       struct nfs42_removexattrres *res = data;
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, req);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+
+       status = decode_removexattr(xdr, &res->cinfo);
+out:
+       return status;
+}
+#endif
 #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */