git: 2d90ef47141d - main - nfsd: Fix Verify for attributes like FilesAvail
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 04 Dec 2021 22:42:07 UTC
The branch main has been updated by rmacklem:
URL: https://cgit.FreeBSD.org/src/commit/?id=2d90ef47141d3ea0f88b43a1b6daf08d68ba8aba
commit 2d90ef47141d3ea0f88b43a1b6daf08d68ba8aba
Author: Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2021-12-04 22:38:55 +0000
Commit: Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2021-12-04 22:38:55 +0000
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
---
sys/fs/nfs/nfs_commonsubs.c | 91 ++++++++++++++++++++++++++++++---------------
1 file changed, 61 insertions(+), 30 deletions(-)
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 550dda43afa6..e61327075a87 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -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.