These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / nfs / nfs4xdr.c
index 0aea978..4e44412 100644 (file)
@@ -139,7 +139,8 @@ static int nfs4_stat_to_errno(int);
 #define encode_setclientid_maxsz \
                                (op_encode_hdr_maxsz + \
                                XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
-                               XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \
+                               /* client name */ \
+                               1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
                                1 /* sc_prog */ + \
                                1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
                                1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
@@ -288,7 +289,8 @@ static int nfs4_stat_to_errno(int);
 #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
                                encode_verifier_maxsz + \
                                1 /* co_ownerid.len */ + \
-                               XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
+                               /* eia_clientowner */ \
+                               1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
                                1 /* flags */ + \
                                1 /* spa_how */ + \
                                /* max is SP4_MACH_CRED (for now) */ + \
@@ -398,7 +400,8 @@ static int nfs4_stat_to_errno(int);
 #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
 #define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \
                                encode_stateid_maxsz + \
-                               1 /* FIXME: opaque lrf_body always empty at the moment */)
+                               1 + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
 #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
                                1 + decode_stateid_maxsz)
 #define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1)
@@ -999,7 +1002,8 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
 
 static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                                const struct nfs4_label *label,
-                               const struct nfs_server *server)
+                               const struct nfs_server *server,
+                               bool excl_check)
 {
        char owner_name[IDMAP_NAMESZ];
        char owner_group[IDMAP_NAMESZ];
@@ -1065,6 +1069,17 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
                len += 4;
        }
+
+       if (excl_check) {
+               const u32 *excl_bmval = server->exclcreat_bitmask;
+               bmval[0] &= excl_bmval[0];
+               bmval[1] &= excl_bmval[1];
+               bmval[2] &= excl_bmval[2];
+
+               if (!(excl_bmval[2] & FATTR4_WORD2_SECURITY_LABEL))
+                       label = NULL;
+       }
+
        if (label) {
                len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
                bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
@@ -1152,7 +1167,9 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
        case NF4LNK:
                p = reserve_space(xdr, 4);
                *p = cpu_to_be32(create->u.symlink.len);
-               xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
+               xdr_write_pages(xdr, create->u.symlink.pages, 0,
+                               create->u.symlink.len);
+               xdr->buf->flags |= XDRBUF_WRITE;
                break;
 
        case NF4BLK: case NF4CHR:
@@ -1166,7 +1183,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
        }
 
        encode_string(xdr, create->name->len, create->name->name);
-       encode_attrs(xdr, create->attrs, create->label, create->server);
+       encode_attrs(xdr, create->attrs, create->label, create->server, false);
 }
 
 static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
@@ -1380,18 +1397,17 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
 
 static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
 {
-       struct iattr dummy;
        __be32 *p;
 
        p = reserve_space(xdr, 4);
        switch(arg->createmode) {
        case NFS4_CREATE_UNCHECKED:
                *p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
-               encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
+               encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false);
                break;
        case NFS4_CREATE_GUARDED:
                *p = cpu_to_be32(NFS4_CREATE_GUARDED);
-               encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
+               encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false);
                break;
        case NFS4_CREATE_EXCLUSIVE:
                *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
@@ -1400,8 +1416,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
        case NFS4_CREATE_EXCLUSIVE4_1:
                *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
                encode_nfs4_verifier(xdr, &arg->u.verifier);
-               dummy.ia_valid = 0;
-               encode_attrs(xdr, &dummy, arg->label, arg->server);
+               encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true);
        }
 }
 
@@ -1644,7 +1659,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
        *p = cpu_to_be32(FATTR4_WORD0_ACL);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(arg->acl_len);
-       xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
+       xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len);
 }
 
 static void
@@ -1657,7 +1672,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
 {
        encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
        encode_nfs4_stateid(xdr, &arg->stateid);
-       encode_attrs(xdr, arg->iap, arg->label, server);
+       encode_attrs(xdr, arg->iap, arg->label, server, false);
 }
 
 static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
@@ -1667,13 +1682,14 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
        encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr);
        encode_nfs4_verifier(xdr, setclientid->sc_verifier);
 
-       encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
+       encode_string(xdr, strlen(setclientid->sc_clnt->cl_owner_id),
+                       setclientid->sc_clnt->cl_owner_id);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(setclientid->sc_prog);
        encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
        encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
        p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(setclientid->sc_cb_ident);
+       *p = cpu_to_be32(setclientid->sc_clnt->cl_cb_ident);
 }
 
 static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
@@ -1747,7 +1763,8 @@ static void encode_exchange_id(struct xdr_stream *xdr,
        encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
        encode_nfs4_verifier(xdr, args->verifier);
 
-       encode_string(xdr, args->id_len, args->id);
+       encode_string(xdr, strlen(args->client->cl_owner_id),
+                       args->client->cl_owner_id);
 
        encode_uint32(xdr, args->flags);
        encode_uint32(xdr, args->state_protect.how);
@@ -2474,7 +2491,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
-               args->acl_pages, args->acl_pgbase, args->acl_len);
+               args->acl_pages, 0, args->acl_len);
 
        encode_nops(&hdr);
 }
@@ -2576,6 +2593,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
                                     struct nfs4_server_caps_arg *args)
 {
+       const u32 *bitmask = args->bitmask;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2583,11 +2601,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fhandle, &hdr);
-       encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
-                          FATTR4_WORD0_FH_EXPIRE_TYPE|
-                          FATTR4_WORD0_LINK_SUPPORT|
-                          FATTR4_WORD0_SYMLINK_SUPPORT|
-                          FATTR4_WORD0_ACLSUPPORT, &hdr);
+       encode_getattr_three(xdr, bitmask[0], bitmask[1], bitmask[2], &hdr);
        encode_nops(&hdr);
 }
 
@@ -3364,6 +3378,22 @@ out_overflow:
        return -EIO;
 }
 
+static int decode_attr_exclcreat_supported(struct xdr_stream *xdr,
+                                uint32_t *bitmap, uint32_t *bitmask)
+{
+       if (likely(bitmap[2] & FATTR4_WORD2_SUPPATTR_EXCLCREAT)) {
+               int ret;
+               ret = decode_attr_bitmap(xdr, bitmask);
+               if (unlikely(ret < 0))
+                       return ret;
+               bitmap[2] &= ~FATTR4_WORD2_SUPPATTR_EXCLCREAT;
+       } else
+               bitmask[0] = bitmask[1] = bitmask[2] = 0;
+       dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__,
+               bitmask[0], bitmask[1], bitmask[2]);
+       return 0;
+}
+
 static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh)
 {
        __be32 *p;
@@ -3585,6 +3615,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
        status = 0;
        if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
                goto out;
+       bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS;
        status = -EIO;
        /* Ignore borken servers that return unrequested attrs */
        if (unlikely(res == NULL))
@@ -4317,6 +4348,9 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re
                goto xdr_error;
        if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
                goto xdr_error;
+       if ((status = decode_attr_exclcreat_supported(xdr, bitmap,
+                               res->exclcreat_bitmask)) != 0)
+               goto xdr_error;
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
        dprintk("%s: xdr returned %d!\n", __func__, -status);
@@ -4342,6 +4376,11 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
                goto xdr_error;
        if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
                goto xdr_error;
+
+       status = -EIO;
+       if (unlikely(bitmap[0]))
+               goto xdr_error;
+
        if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
                goto xdr_error;
        if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
@@ -4541,6 +4580,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
+       status = -EIO;
+       if (unlikely(bitmap[0]))
+               goto xdr_error;
+
        status = decode_attr_mode(xdr, bitmap, &fmode);
        if (status < 0)
                goto xdr_error;
@@ -4594,6 +4637,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
+       status = -EIO;
+       if (unlikely(bitmap[1]))
+               goto xdr_error;
+
        status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold);
        if (status < 0)
                goto xdr_error;
@@ -4731,6 +4778,28 @@ static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
        return 0;
 }
 
+/*
+ * The granularity of a CLONE operation.
+ */
+static int decode_attr_clone_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_CLONE_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_CLONE_BLKSIZE;
+       }
+       return 0;
+}
+
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
        unsigned int savep;
@@ -4756,13 +4825,26 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
        if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
                goto xdr_error;
        fsinfo->wtpref = fsinfo->wtmax;
+
+       status = -EIO;
+       if (unlikely(bitmap[0]))
+               goto xdr_error;
+
        status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
        if (status != 0)
                goto xdr_error;
        status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
        if (status != 0)
                goto xdr_error;
+
+       status = -EIO;
+       if (unlikely(bitmap[1]))
+               goto xdr_error;
+
        status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize);
+       if (status)
+               goto xdr_error;
+       status = decode_attr_clone_blksize(xdr, bitmap, &fsinfo->clone_blksize);
        if (status)
                goto xdr_error;
 
@@ -4899,24 +4981,28 @@ static int decode_lookup(struct xdr_stream *xdr)
 }
 
 /* This is too sick! */
-static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
+static int decode_space_limit(struct xdr_stream *xdr,
+               unsigned long *pagemod_limit)
 {
        __be32 *p;
        uint32_t limit_type, nblocks, blocksize;
+       u64 maxsize = 0;
 
        p = xdr_inline_decode(xdr, 12);
        if (unlikely(!p))
                goto out_overflow;
        limit_type = be32_to_cpup(p++);
        switch (limit_type) {
-       case 1:
-               xdr_decode_hyper(p, maxsize);
+       case NFS4_LIMIT_SIZE:
+               xdr_decode_hyper(p, &maxsize);
                break;
-       case 2:
+       case NFS4_LIMIT_BLOCKS:
                nblocks = be32_to_cpup(p++);
                blocksize = be32_to_cpup(p);
-               *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
+               maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
        }
+       maxsize >>= PAGE_CACHE_SHIFT;
+       *pagemod_limit = min_t(u64, maxsize, ULONG_MAX);
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -4944,7 +5030,7 @@ static int decode_rw_delegation(struct xdr_stream *xdr,
                break;
        case NFS4_OPEN_DELEGATE_WRITE:
                res->delegation_type = FMODE_WRITE|FMODE_READ;
-               if (decode_space_limit(xdr, &res->maxsize) < 0)
+               if (decode_space_limit(xdr, &res->pagemod_limit) < 0)
                                return -EIO;
        }
        return decode_ace(xdr, NULL, res->server->nfs_client);
@@ -7427,6 +7513,8 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(SEEK,              enc_seek,               dec_seek),
        PROC(ALLOCATE,          enc_allocate,           dec_allocate),
        PROC(DEALLOCATE,        enc_deallocate,         dec_deallocate),
+       PROC(LAYOUTSTATS,       enc_layoutstats,        dec_layoutstats),
+       PROC(CLONE,             enc_clone,              dec_clone),
 #endif /* CONFIG_NFS_V4_2 */
 };