Add support for the ModeSetMasked attribute to the NFSv4.1 server.

I do not know of an extant NFSv4.1 client that currently does a Setattr
operation for the ModeSetMasked, but it has been discussed on the linux-nfs
mailing list.
This patch adds support for doing a Setattr of ModeSetMasked, so that it
will work for any future NFSv4.1 client that chooses to do so.
Tested via a hacked FreeBSD NFSv4.1 client.

MFC after:	2 weeks
This commit is contained in:
rmacklem 2019-04-19 23:35:08 +00:00
parent a359c7f26f
commit 1422b10126
3 changed files with 42 additions and 6 deletions

View File

@ -1090,7 +1090,7 @@ struct nfsv3_sattr {
*/
#define NFSATTRBIT_SUPPSETONLY1 (NFSATTRBM_TIMEACCESSSET | \
NFSATTRBM_TIMEMODIFYSET)
#define NFSATTRBIT_SUPPSETONLY2 0
#define NFSATTRBIT_SUPPSETONLY2 (NFSATTRBM_MODESETMASKED)
/*
* NFSATTRBIT_SETABLE - SETABLE0 - bits 0<->31
@ -1106,7 +1106,8 @@ struct nfsv3_sattr {
NFSATTRBM_OWNERGROUP | \
NFSATTRBM_TIMEACCESSSET | \
NFSATTRBM_TIMEMODIFYSET)
#define NFSATTRBIT_SETABLE2 0
#define NFSATTRBIT_SETABLE2 \
(NFSATTRBM_MODESETMASKED)
/*
* NFSATTRBIT_NFSV41 - Attributes only supported by NFSv4.1.

View File

@ -2699,10 +2699,12 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
int attrsum = 0;
int i, j;
int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0;
int toclient = 0;
int moderet, toclient = 0;
u_char *cp, namestr[NFSV4_SMALLSTR + 1];
uid_t uid;
gid_t gid;
u_short mode, mask; /* Same type as va_mode. */
struct vattr va;
error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup);
if (error)
@ -2720,6 +2722,7 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
} else {
bitpos = 0;
}
moderet = 0;
for (; bitpos < NFSATTRBIT_MAX; bitpos++) {
if (attrsum > attrsize) {
error = NFSERR_BADXDR;
@ -2769,6 +2772,7 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
break;
case NFSATTRBIT_MODE:
moderet = NFSERR_INVAL; /* Can't do MODESETMASKED. */
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
nvap->na_mode = nfstov_mode(*tl);
attrsum += NFSX_UNSIGNED;
@ -2872,6 +2876,32 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
nvap->na_vaflags |= VA_UTIMES_NULL;
}
break;
case NFSATTRBIT_MODESETMASKED:
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
mode = fxdr_unsigned(u_short, *tl++);
mask = fxdr_unsigned(u_short, *tl);
/*
* vp == NULL implies an Open/Create operation.
* This attribute can only be used for Setattr and
* only for NFSv4.1 or higher.
* If moderet != 0, a mode attribute has also been
* specified and this attribute cannot be done in the
* same Setattr operation.
*/
if ((nd->nd_flag & ND_NFSV41) == 0)
nd->nd_repstat = NFSERR_ATTRNOTSUPP;
else if ((mode & ~07777) != 0 || (mask & ~07777) != 0 ||
vp == NULL)
nd->nd_repstat = NFSERR_INVAL;
else if (moderet == 0)
moderet = VOP_GETATTR(vp, &va, nd->nd_cred);
if (moderet == 0)
nvap->na_mode = (mode & mask) |
(va.va_mode & ~mask);
else
nd->nd_repstat = moderet;
attrsum += 2 * NFSX_UNSIGNED;
break;
default:
nd->nd_repstat = NFSERR_ATTRNOTSUPP;
/*

View File

@ -464,13 +464,18 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
}
}
if (!nd->nd_repstat &&
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
NFSVNO_ATTRINIT(&nva2);
NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
exp);
if (!nd->nd_repstat)
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
if (!nd->nd_repstat) {
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
}
}
#ifdef NFS4_ACL_EXTATTR_NAME