nfsd: Fix Verify for attributes like FilesAvail
When the Verify operation calls nfsv4_loadattr(), it provides the "struct statfs" information that can be used for doing a compare for FilesAvail, FilesFree, FilesTotal, SpaceAvail, SpaceFree and SpaceTotal. However, the code erroneously used the "struct nfsstatfs *" argument that is NULL. This patch fixes these cases to use the correct argument structure. For the case of FilesAvail, the code in nfsv4_fillattr() was factored out into a separate function called nfsv4_filesavail(), so that it can be called from nfsv4_loadattr() as well as nfsv4_fillattr(). In fact, most of the code in nfsv4_filesavail() is old OpenBSD code that does not build/run on FreeBSD, but I left it in place, in case it is of some use someday. I am not aware of any extant NFSv4 client that does Verify on these attributes. Reported by: rtm@lcs.mit.edu Tested by: rtm@lcs.mit.edu PR: 260176 MFC after: 2 weeks
This commit is contained in:
parent
480be96e1e
commit
2d90ef4714
@ -220,6 +220,7 @@ static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
|
||||
/* local functions */
|
||||
static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
|
||||
static void nfsv4_wanted(struct nfsv4lock *lp);
|
||||
static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
|
||||
static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
|
||||
static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
|
||||
static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
|
||||
@ -1629,8 +1630,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
case NFSATTRBIT_FILESAVAIL:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
|
||||
if (compare) {
|
||||
if (!(*retcmpp) &&
|
||||
sfp->sf_afiles != fxdr_hyper(tl))
|
||||
uquad = nfsv4_filesavail(sbp, vp->v_mount);
|
||||
if (!(*retcmpp) && uquad != fxdr_hyper(tl))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
} else if (sfp != NULL) {
|
||||
sfp->sf_afiles = fxdr_hyper(tl);
|
||||
@ -1640,8 +1641,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
case NFSATTRBIT_FILESFREE:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
|
||||
if (compare) {
|
||||
if (!(*retcmpp) &&
|
||||
sfp->sf_ffiles != fxdr_hyper(tl))
|
||||
uquad = (uint64_t)sbp->f_ffree;
|
||||
if (!(*retcmpp) && uquad != fxdr_hyper(tl))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
} else if (sfp != NULL) {
|
||||
sfp->sf_ffiles = fxdr_hyper(tl);
|
||||
@ -1651,8 +1652,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
case NFSATTRBIT_FILESTOTAL:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
|
||||
if (compare) {
|
||||
if (!(*retcmpp) &&
|
||||
sfp->sf_tfiles != fxdr_hyper(tl))
|
||||
uquad = sbp->f_files;
|
||||
if (!(*retcmpp) && uquad != fxdr_hyper(tl))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
} else if (sfp != NULL) {
|
||||
sfp->sf_tfiles = fxdr_hyper(tl);
|
||||
@ -2002,8 +2003,13 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
case NFSATTRBIT_SPACEAVAIL:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
|
||||
if (compare) {
|
||||
if (!(*retcmpp) &&
|
||||
sfp->sf_abytes != fxdr_hyper(tl))
|
||||
if (priv_check_cred(cred,
|
||||
PRIV_VFS_BLOCKRESERVE))
|
||||
uquad = sbp->f_bfree;
|
||||
else
|
||||
uquad = (uint64_t)sbp->f_bavail;
|
||||
uquad *= sbp->f_bsize;
|
||||
if (!(*retcmpp) && uquad != fxdr_hyper(tl))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
} else if (sfp != NULL) {
|
||||
sfp->sf_abytes = fxdr_hyper(tl);
|
||||
@ -2013,8 +2019,9 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
case NFSATTRBIT_SPACEFREE:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
|
||||
if (compare) {
|
||||
if (!(*retcmpp) &&
|
||||
sfp->sf_fbytes != fxdr_hyper(tl))
|
||||
uquad = sbp->f_bfree;
|
||||
uquad *= sbp->f_bsize;
|
||||
if (!(*retcmpp) && uquad != fxdr_hyper(tl))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
} else if (sfp != NULL) {
|
||||
sfp->sf_fbytes = fxdr_hyper(tl);
|
||||
@ -2024,8 +2031,9 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
case NFSATTRBIT_SPACETOTAL:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
|
||||
if (compare) {
|
||||
if (!(*retcmpp) &&
|
||||
sfp->sf_tbytes != fxdr_hyper(tl))
|
||||
uquad = sbp->f_blocks;
|
||||
uquad *= sbp->f_bsize;
|
||||
if (!(*retcmpp) && uquad != fxdr_hyper(tl))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
} else if (sfp != NULL) {
|
||||
sfp->sf_tbytes = fxdr_hyper(tl);
|
||||
@ -2723,24 +2731,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
|
||||
retnum += NFSX_HYPER;
|
||||
break;
|
||||
case NFSATTRBIT_FILESAVAIL:
|
||||
/*
|
||||
* Check quota and use min(quota, f_ffree).
|
||||
*/
|
||||
freenum = fs->f_ffree;
|
||||
#ifdef QUOTA
|
||||
/*
|
||||
* ufs_quotactl() insists that the uid argument
|
||||
* equal p_ruid for non-root quota access, so
|
||||
* we'll just make sure that's the case.
|
||||
*/
|
||||
savuid = p->p_cred->p_ruid;
|
||||
p->p_cred->p_ruid = cred->cr_uid;
|
||||
if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
|
||||
cred->cr_uid, &dqb))
|
||||
freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
|
||||
freenum);
|
||||
p->p_cred->p_ruid = savuid;
|
||||
#endif /* QUOTA */
|
||||
freenum = nfsv4_filesavail(fs, mp);
|
||||
NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
|
||||
*tl++ = 0;
|
||||
*tl = txdr_unsigned(freenum);
|
||||
@ -3066,6 +3057,46 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
|
||||
return (retnum + prefixnum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the files available attribute value.
|
||||
*/
|
||||
static uint32_t
|
||||
nfsv4_filesavail(struct statfs *fs, struct mount *mp)
|
||||
{
|
||||
uint32_t freenum;
|
||||
#ifdef QUOTA
|
||||
struct dqblk dqb;
|
||||
uid_t savuid;
|
||||
NFSPROC_T *p;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check quota and use min(quota, f_ffree).
|
||||
*/
|
||||
freenum = fs->f_ffree;
|
||||
#ifdef QUOTA
|
||||
/*
|
||||
* This is old OpenBSD code that does not build
|
||||
* for FreeBSD. I do not know if doing this is
|
||||
* useful, so I will just leave the code here.
|
||||
*/
|
||||
p = curthread();
|
||||
/*
|
||||
* ufs_quotactl() insists that the uid argument
|
||||
* equal p_ruid for non-root quota access, so
|
||||
* we'll just make sure that's the case.
|
||||
*/
|
||||
savuid = p->p_cred->p_ruid;
|
||||
p->p_cred->p_ruid = cred->cr_uid;
|
||||
if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
|
||||
cred->cr_uid, &dqb))
|
||||
freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
|
||||
freenum);
|
||||
p->p_cred->p_ruid = savuid;
|
||||
#endif /* QUOTA */
|
||||
return (freenum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the attribute bits onto an mbuf list.
|
||||
* Return the number of bytes of output generated.
|
||||
|
Loading…
Reference in New Issue
Block a user