NFSv4: Fix exclusive create attributes encoding
When using NFS4_CREATE_EXCLUSIVE4_1 mode, the client will overestimate the amount of space that it needs for the attributes because it does so before checking whether or not the server supports a given attribute. Fix by checking the attribute mask earlier. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
parent
2e84611b3f
commit
28cf22d0ba
@ -1000,8 +1000,9 @@ 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,
|
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
|
||||||
const struct nfs4_label *label,
|
const struct nfs4_label *label,
|
||||||
|
const umode_t *umask,
|
||||||
const struct nfs_server *server,
|
const struct nfs_server *server,
|
||||||
bool excl_check, const umode_t *umask)
|
const uint32_t attrmask[])
|
||||||
{
|
{
|
||||||
char owner_name[IDMAP_NAMESZ];
|
char owner_name[IDMAP_NAMESZ];
|
||||||
char owner_group[IDMAP_NAMESZ];
|
char owner_group[IDMAP_NAMESZ];
|
||||||
@ -1016,22 +1017,20 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
|
|||||||
/*
|
/*
|
||||||
* We reserve enough space to write the entire attribute buffer at once.
|
* We reserve enough space to write the entire attribute buffer at once.
|
||||||
*/
|
*/
|
||||||
if (iap->ia_valid & ATTR_SIZE) {
|
if ((iap->ia_valid & ATTR_SIZE) && (attrmask[0] & FATTR4_WORD0_SIZE)) {
|
||||||
bmval[0] |= FATTR4_WORD0_SIZE;
|
bmval[0] |= FATTR4_WORD0_SIZE;
|
||||||
len += 8;
|
len += 8;
|
||||||
}
|
}
|
||||||
if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
|
|
||||||
umask = NULL;
|
|
||||||
if (iap->ia_valid & ATTR_MODE) {
|
if (iap->ia_valid & ATTR_MODE) {
|
||||||
if (umask) {
|
if (umask && (attrmask[2] & FATTR4_WORD2_MODE_UMASK)) {
|
||||||
bmval[2] |= FATTR4_WORD2_MODE_UMASK;
|
bmval[2] |= FATTR4_WORD2_MODE_UMASK;
|
||||||
len += 8;
|
len += 8;
|
||||||
} else {
|
} else if (attrmask[1] & FATTR4_WORD1_MODE) {
|
||||||
bmval[1] |= FATTR4_WORD1_MODE;
|
bmval[1] |= FATTR4_WORD1_MODE;
|
||||||
len += 4;
|
len += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (iap->ia_valid & ATTR_UID) {
|
if ((iap->ia_valid & ATTR_UID) && (attrmask[1] & FATTR4_WORD1_OWNER)) {
|
||||||
owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
|
owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
|
||||||
if (owner_namelen < 0) {
|
if (owner_namelen < 0) {
|
||||||
dprintk("nfs: couldn't resolve uid %d to string\n",
|
dprintk("nfs: couldn't resolve uid %d to string\n",
|
||||||
@ -1044,7 +1043,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
|
|||||||
bmval[1] |= FATTR4_WORD1_OWNER;
|
bmval[1] |= FATTR4_WORD1_OWNER;
|
||||||
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
|
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
|
||||||
}
|
}
|
||||||
if (iap->ia_valid & ATTR_GID) {
|
if ((iap->ia_valid & ATTR_GID) &&
|
||||||
|
(attrmask[1] & FATTR4_WORD1_OWNER_GROUP)) {
|
||||||
owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
|
owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
|
||||||
if (owner_grouplen < 0) {
|
if (owner_grouplen < 0) {
|
||||||
dprintk("nfs: couldn't resolve gid %d to string\n",
|
dprintk("nfs: couldn't resolve gid %d to string\n",
|
||||||
@ -1056,6 +1056,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
|
|||||||
bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
|
bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
|
||||||
len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
|
len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
|
||||||
}
|
}
|
||||||
|
if (attrmask[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
|
||||||
if (iap->ia_valid & ATTR_ATIME_SET) {
|
if (iap->ia_valid & ATTR_ATIME_SET) {
|
||||||
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
|
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
|
||||||
len += 16;
|
len += 16;
|
||||||
@ -1063,6 +1064,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
|
|||||||
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
|
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
|
||||||
len += 4;
|
len += 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (attrmask[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
|
||||||
if (iap->ia_valid & ATTR_MTIME_SET) {
|
if (iap->ia_valid & ATTR_MTIME_SET) {
|
||||||
bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
|
bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
|
||||||
len += 16;
|
len += 16;
|
||||||
@ -1070,18 +1073,9 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
|
|||||||
bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
|
bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
|
||||||
len += 4;
|
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) {
|
if (label && (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL)) {
|
||||||
len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
|
len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
|
||||||
bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
|
bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
|
||||||
}
|
}
|
||||||
@ -1188,8 +1182,8 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
|
|||||||
}
|
}
|
||||||
|
|
||||||
encode_string(xdr, create->name->len, create->name->name);
|
encode_string(xdr, create->name->len, create->name->name);
|
||||||
encode_attrs(xdr, create->attrs, create->label, create->server, false,
|
encode_attrs(xdr, create->attrs, create->label, &create->umask,
|
||||||
&create->umask);
|
create->server, create->server->attr_bitmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
|
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
|
||||||
@ -1409,13 +1403,13 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
|
|||||||
switch(arg->createmode) {
|
switch(arg->createmode) {
|
||||||
case NFS4_CREATE_UNCHECKED:
|
case NFS4_CREATE_UNCHECKED:
|
||||||
*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
|
*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
|
||||||
encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
|
encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
|
||||||
&arg->umask);
|
arg->server, arg->server->attr_bitmask);
|
||||||
break;
|
break;
|
||||||
case NFS4_CREATE_GUARDED:
|
case NFS4_CREATE_GUARDED:
|
||||||
*p = cpu_to_be32(NFS4_CREATE_GUARDED);
|
*p = cpu_to_be32(NFS4_CREATE_GUARDED);
|
||||||
encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
|
encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
|
||||||
&arg->umask);
|
arg->server, arg->server->attr_bitmask);
|
||||||
break;
|
break;
|
||||||
case NFS4_CREATE_EXCLUSIVE:
|
case NFS4_CREATE_EXCLUSIVE:
|
||||||
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
|
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
|
||||||
@ -1424,8 +1418,8 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
|
|||||||
case NFS4_CREATE_EXCLUSIVE4_1:
|
case NFS4_CREATE_EXCLUSIVE4_1:
|
||||||
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
|
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
|
||||||
encode_nfs4_verifier(xdr, &arg->u.verifier);
|
encode_nfs4_verifier(xdr, &arg->u.verifier);
|
||||||
encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true,
|
encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
|
||||||
&arg->umask);
|
arg->server, arg->server->exclcreat_bitmask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1681,7 +1675,8 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
|
|||||||
{
|
{
|
||||||
encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
|
encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
|
||||||
encode_nfs4_stateid(xdr, &arg->stateid);
|
encode_nfs4_stateid(xdr, &arg->stateid);
|
||||||
encode_attrs(xdr, arg->iap, arg->label, server, false, NULL);
|
encode_attrs(xdr, arg->iap, arg->label, NULL, server,
|
||||||
|
server->attr_bitmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
|
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
|
||||||
|
Loading…
Reference in New Issue
Block a user