nfsv4: Add support to NFSv4 for named attributes
NFSv4 supports a feature called named attributes, that are
essentially Solaris style extended attributes.
Commits starting with 2ec2ba7e23 added Solaris style extended
attribute support.
This patch uses the Solaris style extended attribute
support to provide support for NFSv4.
Since nfsv4_loadattr() needed an additional argument,
many file are affected, although many in a trivial way.
For the NFSv4 server to support named attributes, ZFS must
be patched and only ZFS file systems support these Solaris
style extended attributes.
This commit is contained in:
+27
-73
@@ -223,7 +223,6 @@ 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 bool nfs_test_namedattr(struct nfsrv_descript *nd, struct vnode *vp);
|
||||
static void nfsv4_wanted(struct nfsv4lock *lp);
|
||||
static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
|
||||
static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
|
||||
@@ -1282,70 +1281,6 @@ nfsrv_getopbits(struct nfsrv_descript *nd, nfsopbit_t *opbitp, int *cntp)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if a named attribute exists for this file.
|
||||
*/
|
||||
static bool
|
||||
nfs_test_namedattr(struct nfsrv_descript *nd, struct vnode *vp)
|
||||
{
|
||||
struct uio io;
|
||||
struct iovec iv;
|
||||
struct componentname cn;
|
||||
struct vnode *dvp;
|
||||
struct dirent *dp;
|
||||
int eofflag, error;
|
||||
char *buf, *cp, *endcp;
|
||||
bool ret;
|
||||
|
||||
if (vp == NULL || (vp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0)
|
||||
return (false);
|
||||
NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
|
||||
NOFOLLOW | LOCKLEAF);
|
||||
cn.cn_lkflags = LK_SHARED;
|
||||
cn.cn_nameptr = ".";
|
||||
cn.cn_namelen = 1;
|
||||
error = VOP_LOOKUP(vp, &dvp, &cn);
|
||||
if (error != 0)
|
||||
return (false);
|
||||
|
||||
/* Now we have to read the directory, looking for a valid entry. */
|
||||
buf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK);
|
||||
ret = false;
|
||||
io.uio_offset = 0;
|
||||
io.uio_segflg = UIO_SYSSPACE;
|
||||
io.uio_rw = UIO_READ;
|
||||
io.uio_td = NULL;
|
||||
do {
|
||||
iv.iov_base = buf;
|
||||
iv.iov_len = DIRBLKSIZ;
|
||||
io.uio_iov = &iv;
|
||||
io.uio_iovcnt = 1;
|
||||
io.uio_resid = DIRBLKSIZ;
|
||||
error = VOP_READDIR(dvp, &io, nd->nd_cred, &eofflag, NULL,
|
||||
NULL);
|
||||
if (error != 0 || io.uio_resid == DIRBLKSIZ)
|
||||
break;
|
||||
cp = buf;
|
||||
endcp = &buf[DIRBLKSIZ - io.uio_resid];
|
||||
while (cp < endcp) {
|
||||
dp = (struct dirent *)cp;
|
||||
if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
|
||||
((dp->d_namlen == 1 && dp->d_name[0] != '.') ||
|
||||
(dp->d_namlen == 2 && (dp->d_name[0] != '.' ||
|
||||
dp->d_name[1] != '.')) || dp->d_namlen > 2)) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
cp += dp->d_reclen;
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
} while (eofflag == 0);
|
||||
vput(dvp);
|
||||
free(buf, M_TEMP);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the attributes for V4.
|
||||
* If the compare flag is true, test for any attribute changes,
|
||||
@@ -1361,7 +1296,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
|
||||
struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
|
||||
struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
|
||||
u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
|
||||
u_int32_t *leasep, u_int32_t *rderrp, bool *has_namedattrp,
|
||||
NFSPROC_T *p, struct ucred *cred)
|
||||
{
|
||||
u_int32_t *tl;
|
||||
int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
|
||||
@@ -1451,6 +1387,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
sfp->sf_tbytes = UINT64_MAX;
|
||||
sfp->sf_abytes = UINT64_MAX;
|
||||
}
|
||||
if (has_namedattrp != NULL)
|
||||
*has_namedattrp = false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1581,13 +1519,25 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
|
||||
break;
|
||||
case NFSATTRBIT_NAMEDATTR:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
|
||||
if (compare && !(*retcmpp)) {
|
||||
bool named_attr;
|
||||
if (compare) {
|
||||
if (!(*retcmpp)) {
|
||||
long has_named_attr;
|
||||
|
||||
named_attr = nfs_test_namedattr(nd, vp);
|
||||
if ((named_attr && *tl != newnfs_true) ||
|
||||
(!named_attr && *tl != newnfs_false))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
if (vp == NULL || VOP_PATHCONF(vp,
|
||||
_PC_HAS_NAMEDATTR, &has_named_attr)
|
||||
!= 0)
|
||||
has_named_attr = 0;
|
||||
if ((has_named_attr != 0 &&
|
||||
*tl != newnfs_true) ||
|
||||
(has_named_attr == 0 &&
|
||||
*tl != newnfs_false))
|
||||
*retcmpp = NFSERR_NOTSAME;
|
||||
}
|
||||
} else if (has_namedattrp != NULL) {
|
||||
if (*tl == newnfs_true)
|
||||
*has_namedattrp = true;
|
||||
else
|
||||
*has_namedattrp = false;
|
||||
}
|
||||
attrsum += NFSX_UNSIGNED;
|
||||
break;
|
||||
@@ -2684,6 +2634,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
|
||||
size_t atsiz;
|
||||
bool xattrsupp;
|
||||
short irflag;
|
||||
long has_named_attr;
|
||||
#ifdef QUOTA
|
||||
struct dqblk dqb;
|
||||
uid_t savuid;
|
||||
@@ -2840,7 +2791,10 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
|
||||
break;
|
||||
case NFSATTRBIT_NAMEDATTR:
|
||||
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
|
||||
if (nfs_test_namedattr(nd, vp))
|
||||
if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, &has_named_attr)
|
||||
!= 0)
|
||||
has_named_attr = 0;
|
||||
if (has_named_attr != 0)
|
||||
*tl = newnfs_true;
|
||||
else
|
||||
*tl = newnfs_false;
|
||||
|
||||
@@ -340,7 +340,7 @@ int nfsv4_loadattr(struct nfsrv_descript *, vnode_t,
|
||||
struct nfsvattr *, struct nfsfh **, fhandle_t *, int,
|
||||
struct nfsv3_pathconf *, struct statfs *, struct nfsstatfs *,
|
||||
struct nfsfsinfo *, NFSACL_T *,
|
||||
int, int *, u_int32_t *, u_int32_t *, NFSPROC_T *, struct ucred *);
|
||||
int, int *, u_int32_t *, u_int32_t *, bool *, NFSPROC_T *, struct ucred *);
|
||||
int nfsv4_lock(struct nfsv4lock *, int, int *, struct mtx *, struct mount *);
|
||||
void nfsv4_unlock(struct nfsv4lock *, int);
|
||||
void nfsv4_relref(struct nfsv4lock *);
|
||||
@@ -515,7 +515,7 @@ int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *, uint32_t *,
|
||||
struct ucred *, NFSPROC_T *, struct nfsvattr *, int *);
|
||||
int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *,
|
||||
NFSPROC_T *, struct nfsvattr *, int *);
|
||||
int nfsrpc_pathconf(vnode_t, struct nfsv3_pathconf *,
|
||||
int nfsrpc_pathconf(vnode_t, struct nfsv3_pathconf *, bool *,
|
||||
struct ucred *, NFSPROC_T *, struct nfsvattr *, int *);
|
||||
int nfsrpc_renew(struct nfsclclient *, struct nfsclds *, struct ucred *,
|
||||
NFSPROC_T *);
|
||||
@@ -568,6 +568,9 @@ int nfsrpc_listextattr(vnode_t, uint64_t *, struct uio *, size_t *, bool *,
|
||||
int nfsrpc_rmextattr(vnode_t, const char *, struct nfsvattr *, int *,
|
||||
struct ucred *, NFSPROC_T *);
|
||||
void nfsrpc_bindconnsess(CLIENT *, void *, struct ucred *);
|
||||
int nfsrpc_openattr(struct nfsmount *, struct vnode *, uint8_t *, int,
|
||||
bool, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsfh **,
|
||||
int *);
|
||||
|
||||
/* nfs_clstate.c */
|
||||
int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int,
|
||||
|
||||
@@ -1414,6 +1414,7 @@ struct nfsv3_sattr {
|
||||
* NFSGETATTRBIT_PATHCONF0 - bits 0<->31
|
||||
*/
|
||||
#define NFSGETATTRBIT_PATHCONF0 (NFSATTRBIT_GETATTR0 | \
|
||||
NFSATTRBM_NAMEDATTR | \
|
||||
NFSATTRBM_CASEINSENSITIVE | \
|
||||
NFSATTRBM_CASEPRESERVING | \
|
||||
NFSATTRBM_CHOWNRESTRICTED | \
|
||||
|
||||
@@ -271,7 +271,8 @@ nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
|
||||
|
||||
if (nd->nd_flag & ND_NFSV4) {
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
} else if (nd->nd_flag & ND_NFSV3) {
|
||||
NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
|
||||
nap->na_type = nfsv34tov_type(fp->fa_type);
|
||||
|
||||
@@ -828,7 +828,7 @@ nfscl_wcc_data(struct nfsrv_descript *nd, struct vnode *vp,
|
||||
== (ND_NFSV4 | ND_V4WCCATTR)) {
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
/*
|
||||
|
||||
@@ -392,7 +392,8 @@ nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
|
||||
mode |= NFSV4OPEN_ACCESSWRITE;
|
||||
if (NFSHASNFSV4N(nmp)) {
|
||||
if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
|
||||
nfs_numnfscbd > 0) {
|
||||
nfs_numnfscbd > 0 &&
|
||||
(vn_irflag_read(vp) & VIRF_NAMEDATTR) == 0) {
|
||||
if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
|
||||
mode |= NFSV4OPEN_WANTWRITEDELEG;
|
||||
else
|
||||
@@ -695,7 +696,7 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
|
||||
("nfsrpc_openrpc: Getattr repstat"));
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, p, cred);
|
||||
NULL, NULL, NULL, NULL, p, cred);
|
||||
if (error)
|
||||
goto nfsmout;
|
||||
}
|
||||
@@ -1354,7 +1355,7 @@ nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
|
||||
if ((nd->nd_flag & ND_NFSV4) != 0)
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
else
|
||||
error = nfsm_loadattr(nd, nap);
|
||||
} else
|
||||
@@ -3478,7 +3479,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
nfsva.na_mntonfileno = UINT64_MAX;
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, p, cred);
|
||||
NULL, NULL, NULL, NULL, p, cred);
|
||||
if (error) {
|
||||
dotdotfileid = dotfileid;
|
||||
} else if (gotmnton) {
|
||||
@@ -3728,7 +3729,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
nfsva.na_mntonfileno = UINT64_MAX;
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, &rderr, p, cred);
|
||||
NULL, NULL, &rderr, NULL, p, cred);
|
||||
if (error)
|
||||
goto nfsmout;
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
|
||||
@@ -3878,13 +3879,16 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
size_t tresid;
|
||||
u_int32_t *tl2 = NULL, rderr;
|
||||
struct timespec dctime, ts;
|
||||
bool attr_ok, validentry;
|
||||
bool attr_ok, named_dir, validentry;
|
||||
|
||||
KASSERT(uiop->uio_iovcnt == 1 &&
|
||||
(uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
|
||||
("nfs readdirplusrpc bad uio"));
|
||||
KASSERT(uiop->uio_segflg == UIO_SYSSPACE,
|
||||
("nfsrpc_readdirplus: uio userspace"));
|
||||
named_dir = false;
|
||||
if ((vp->v_irflag & VIRF_NAMEDDIR) != 0)
|
||||
named_dir = true;
|
||||
ncookie.lval[0] = ncookie.lval[1] = 0;
|
||||
timespecclear(&dctime);
|
||||
*attrflagp = 0;
|
||||
@@ -3950,7 +3954,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
nfsva.na_mntonfileno = UINT64_MAX;
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, p, cred);
|
||||
NULL, NULL, NULL, NULL, p, cred);
|
||||
if (error) {
|
||||
dotdotfileid = dotfileid;
|
||||
} else if (gotmnton) {
|
||||
@@ -4217,7 +4221,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
nfsva.na_mntonfileno = 0xffffffff;
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, &rderr, p, cred);
|
||||
NULL, NULL, &rderr, NULL, p, cred);
|
||||
if (error)
|
||||
goto nfsmout;
|
||||
}
|
||||
@@ -4322,7 +4326,8 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
if (cnp->cn_namelen <= NCHNAMLEN &&
|
||||
ndp->ni_dvp != ndp->ni_vp &&
|
||||
(newvp->v_type != VDIR ||
|
||||
dctime.tv_sec != 0)) {
|
||||
dctime.tv_sec != 0) &&
|
||||
!named_dir) {
|
||||
cache_enter_time_flags(ndp->ni_dvp,
|
||||
ndp->ni_vp, cnp,
|
||||
&nfsva.na_ctime,
|
||||
@@ -4879,7 +4884,7 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
|
||||
if (nd->nd_repstat == 0) {
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
|
||||
NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL,
|
||||
p, cred);
|
||||
NULL, p, cred);
|
||||
if (!error) {
|
||||
nmp->nm_fsid[0] = nap->na_filesid[0];
|
||||
nmp->nm_fsid[1] = nap->na_filesid[1];
|
||||
@@ -4932,7 +4937,7 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
|
||||
* nfs pathconf rpc
|
||||
*/
|
||||
int
|
||||
nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
|
||||
nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp,
|
||||
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
|
||||
{
|
||||
struct nfsrv_descript nfsd, *nd = &nfsd;
|
||||
@@ -4942,6 +4947,7 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
|
||||
int error;
|
||||
struct nfsnode *np;
|
||||
|
||||
*has_namedattrp = false;
|
||||
*attrflagp = 0;
|
||||
nmp = VFSTONFS(vp->v_mount);
|
||||
if (NFSHASNFSV4(nmp)) {
|
||||
@@ -4968,8 +4974,8 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
|
||||
return (error);
|
||||
if (nd->nd_repstat == 0) {
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
|
||||
pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
|
||||
cred);
|
||||
pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
|
||||
has_namedattrp, p, cred);
|
||||
if (!error)
|
||||
*attrflagp = 1;
|
||||
} else {
|
||||
@@ -5264,7 +5270,7 @@ nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp)
|
||||
return (error);
|
||||
if (!nd->nd_repstat)
|
||||
error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
|
||||
NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
|
||||
NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, p, cred);
|
||||
else
|
||||
error = nd->nd_repstat;
|
||||
m_freem(nd->nd_mrep);
|
||||
@@ -8364,7 +8370,7 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
|
||||
if (*++tl == 0) {
|
||||
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, p, cred);
|
||||
NULL, NULL, NULL, NULL, p, cred);
|
||||
if (error != 0)
|
||||
goto nfsmout;
|
||||
if (ndp != NULL) {
|
||||
@@ -9529,6 +9535,50 @@ nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr)
|
||||
m_freem(nd->nd_mrep);
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs opeattr rpc
|
||||
*/
|
||||
int
|
||||
nfsrpc_openattr(struct nfsmount *nmp, struct vnode *vp, uint8_t *fhp, int fhlen,
|
||||
bool createit, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap,
|
||||
struct nfsfh **nfhpp, int *attrflagp)
|
||||
{
|
||||
uint32_t *tl;
|
||||
struct nfsrv_descript nfsd, *nd = &nfsd;
|
||||
nfsattrbit_t attrbits;
|
||||
int error = 0;
|
||||
|
||||
*attrflagp = 0;
|
||||
nfscl_reqstart(nd, NFSPROC_OPENATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0,
|
||||
cred);
|
||||
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
|
||||
if (createit)
|
||||
*tl = newnfs_true;
|
||||
else
|
||||
*tl = newnfs_false;
|
||||
NFSGETATTR_ATTRBIT(&attrbits);
|
||||
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
|
||||
*tl = txdr_unsigned(NFSV4OP_GETATTR);
|
||||
(void)nfsrv_putattrbit(nd, &attrbits);
|
||||
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
|
||||
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (nd->nd_repstat == 0) {
|
||||
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
error = nfsm_getfh(nd, nfhpp);
|
||||
if (error != 0)
|
||||
goto nfsmout;
|
||||
error = nfscl_postop_attr(nd, nap, attrflagp);
|
||||
}
|
||||
nfsmout:
|
||||
m_freem(nd->nd_mrep);
|
||||
if (error == 0 && nd->nd_repstat != 0)
|
||||
error = nd->nd_repstat;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do roughly what nfs_statfs() does for NFSv4, but when called with a shared
|
||||
* locked vnode.
|
||||
|
||||
@@ -1801,12 +1801,18 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
|
||||
if (argp->flags & NFSMNT_NFSV3)
|
||||
ncl_fsinfo(nmp, *vpp, cred, td);
|
||||
|
||||
/* Mark if the mount point supports NFSv4 ACLs. */
|
||||
if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
|
||||
ret == 0 &&
|
||||
NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
|
||||
/*
|
||||
* Mark if the mount point supports NFSv4 ACLs and
|
||||
* named attributes.
|
||||
*/
|
||||
if ((argp->flags & NFSMNT_NFSV4) != 0) {
|
||||
MNT_ILOCK(mp);
|
||||
mp->mnt_flag |= MNT_NFS4ACLS;
|
||||
if (ret == 0 && nfsrv_useacl != 0 &&
|
||||
NFSISSET_ATTRBIT(&nfsva.na_suppattr,
|
||||
NFSATTRBIT_ACL))
|
||||
mp->mnt_flag |= MNT_NFS4ACLS;
|
||||
if (nmp->nm_minorvers > 0)
|
||||
mp->mnt_flag |= MNT_NAMEDATTR;
|
||||
MNT_IUNLOCK(mp);
|
||||
}
|
||||
|
||||
|
||||
+249
-89
@@ -113,6 +113,8 @@ static vop_write_t nfsfifo_write;
|
||||
static vop_close_t nfsfifo_close;
|
||||
static int nfs_setattrrpc(struct vnode *, struct vattr *, struct ucred *,
|
||||
struct thread *);
|
||||
static int nfs_get_namedattrdir(struct vnode *, struct componentname *,
|
||||
struct vnode **);
|
||||
static vop_lookup_t nfs_lookup;
|
||||
static vop_create_t nfs_create;
|
||||
static vop_mknod_t nfs_mknod;
|
||||
@@ -1193,6 +1195,40 @@ nfs_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a named attribute directory for the vnode.
|
||||
*/
|
||||
static int
|
||||
nfs_get_namedattrdir(struct vnode *vp, struct componentname *cnp,
|
||||
struct vnode **vpp)
|
||||
{
|
||||
struct nfsfh *nfhp;
|
||||
struct nfsnode *np;
|
||||
struct vnode *newvp;
|
||||
struct nfsvattr nfsva;
|
||||
int attrflag, error;
|
||||
|
||||
attrflag = 0;
|
||||
*vpp = NULL;
|
||||
np = VTONFS(vp);
|
||||
error = nfsrpc_openattr(VFSTONFS(vp->v_mount), vp, np->n_fhp->nfh_fh,
|
||||
np->n_fhp->nfh_len, (cnp->cn_flags & CREATENAMED),
|
||||
cnp->cn_cred, curthread, &nfsva, &nfhp, &attrflag);
|
||||
if (error == NFSERR_NOTSUPP)
|
||||
error = ENOATTR;
|
||||
if (error == 0)
|
||||
error = nfscl_nget(vp->v_mount, vp, nfhp, cnp, curthread, &np,
|
||||
cnp->cn_lkflags);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
newvp = NFSTOV(np);
|
||||
vn_irflag_set_cond(newvp, VIRF_NAMEDDIR);
|
||||
if (attrflag != 0)
|
||||
(void)nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1);
|
||||
*vpp = newvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs lookup call, one step at a time...
|
||||
* First look in cache
|
||||
@@ -1205,7 +1241,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct mount *mp = dvp->v_mount;
|
||||
int flags = cnp->cn_flags;
|
||||
uint64_t flags = cnp->cn_flags;
|
||||
struct vnode *newvp;
|
||||
struct nfsmount *nmp;
|
||||
struct nfsnode *np, *newnp;
|
||||
@@ -1216,15 +1252,57 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
struct vattr vattr;
|
||||
struct timespec nctime, ts;
|
||||
uint32_t openmode;
|
||||
bool is_nameddir, needs_nameddir, opennamed;
|
||||
|
||||
dattrflag = 0;
|
||||
*vpp = NULLVP;
|
||||
nmp = VFSTONFS(mp);
|
||||
opennamed = (flags & (OPENNAMED | ISLASTCN)) == (OPENNAMED | ISLASTCN);
|
||||
if (opennamed && (!NFSHASNFSV4(nmp) || !NFSHASNFSV4N(nmp)))
|
||||
return (ENOATTR);
|
||||
is_nameddir = (vn_irflag_read(dvp) & VIRF_NAMEDDIR) != 0;
|
||||
if ((is_nameddir && (flags & ISLASTCN) == 0 && (cnp->cn_namelen > 1 ||
|
||||
*cnp->cn_nameptr != '.')) ||
|
||||
(opennamed && !is_nameddir && (flags & ISDOTDOT) != 0))
|
||||
return (ENOATTR);
|
||||
if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
|
||||
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
|
||||
return (EROFS);
|
||||
np = VTONFS(dvp);
|
||||
|
||||
needs_nameddir = false;
|
||||
if (opennamed || is_nameddir) {
|
||||
cnp->cn_flags &= ~MAKEENTRY;
|
||||
if (!is_nameddir)
|
||||
needs_nameddir = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the named attribute directory is needed, acquire it now.
|
||||
*/
|
||||
newvp = NULLVP;
|
||||
if (needs_nameddir) {
|
||||
KASSERT(np->n_v4 == NULL, ("nfs_lookup: O_NAMEDATTR when"
|
||||
" n_v4 not NULL"));
|
||||
error = nfs_get_namedattrdir(dvp, cnp, &newvp);
|
||||
if (error != 0)
|
||||
goto handle_error;
|
||||
if (cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.') {
|
||||
*vpp = newvp;
|
||||
return (0);
|
||||
}
|
||||
dvp = newvp;
|
||||
np = VTONFS(dvp);
|
||||
newvp = NULLVP;
|
||||
} else if (opennamed && cnp->cn_namelen == 1 &&
|
||||
*cnp->cn_nameptr == '.') {
|
||||
VREF(dvp);
|
||||
*vpp = dvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (dvp->v_type != VDIR)
|
||||
return (ENOTDIR);
|
||||
nmp = VFSTONFS(mp);
|
||||
np = VTONFS(dvp);
|
||||
|
||||
/* For NFSv4, wait until any remove is done. */
|
||||
NFSLOCKNODE(np);
|
||||
@@ -1237,77 +1315,83 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
error = vn_dir_check_exec(dvp, cnp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
error = cache_lookup(dvp, vpp, cnp, &nctime, &ncticks);
|
||||
if (error > 0 && error != ENOENT)
|
||||
return (error);
|
||||
if (error == -1) {
|
||||
/*
|
||||
* Lookups of "." are special and always return the
|
||||
* current directory. cache_lookup() already handles
|
||||
* associated locking bookkeeping, etc.
|
||||
*/
|
||||
if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We only accept a positive hit in the cache if the
|
||||
* change time of the file matches our cached copy.
|
||||
* Otherwise, we discard the cache entry and fallback
|
||||
* to doing a lookup RPC. We also only trust cache
|
||||
* entries for less than nm_nametimeo seconds.
|
||||
*
|
||||
* To better handle stale file handles and attributes,
|
||||
* clear the attribute cache of this node if it is a
|
||||
* leaf component, part of an open() call, and not
|
||||
* locally modified before fetching the attributes.
|
||||
* This should allow stale file handles to be detected
|
||||
* here where we can fall back to a LOOKUP RPC to
|
||||
* recover rather than having nfs_open() detect the
|
||||
* stale file handle and failing open(2) with ESTALE.
|
||||
*/
|
||||
newvp = *vpp;
|
||||
newnp = VTONFS(newvp);
|
||||
if (!(nmp->nm_flag & NFSMNT_NOCTO) &&
|
||||
(flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) &&
|
||||
!(newnp->n_flag & NMODIFIED)) {
|
||||
NFSLOCKNODE(newnp);
|
||||
newnp->n_attrstamp = 0;
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
|
||||
NFSUNLOCKNODE(newnp);
|
||||
if (!opennamed && !is_nameddir) {
|
||||
error = cache_lookup(dvp, vpp, cnp, &nctime, &ncticks);
|
||||
if (error > 0 && error != ENOENT)
|
||||
return (error);
|
||||
if (error == -1) {
|
||||
/*
|
||||
* Lookups of "." are special and always return the
|
||||
* current directory. cache_lookup() already handles
|
||||
* associated locking bookkeeping, etc.
|
||||
*/
|
||||
if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We only accept a positive hit in the cache if the
|
||||
* change time of the file matches our cached copy.
|
||||
* Otherwise, we discard the cache entry and fallback
|
||||
* to doing a lookup RPC. We also only trust cache
|
||||
* entries for less than nm_nametimeo seconds.
|
||||
*
|
||||
* To better handle stale file handles and attributes,
|
||||
* clear the attribute cache of this node if it is a
|
||||
* leaf component, part of an open() call, and not
|
||||
* locally modified before fetching the attributes.
|
||||
* This should allow stale file handles to be detected
|
||||
* here where we can fall back to a LOOKUP RPC to
|
||||
* recover rather than having nfs_open() detect the
|
||||
* stale file handle and failing open(2) with ESTALE.
|
||||
*/
|
||||
newvp = *vpp;
|
||||
newnp = VTONFS(newvp);
|
||||
if (!(nmp->nm_flag & NFSMNT_NOCTO) &&
|
||||
(flags & (ISLASTCN | ISOPEN)) ==
|
||||
(ISLASTCN | ISOPEN) &&
|
||||
!(newnp->n_flag & NMODIFIED)) {
|
||||
NFSLOCKNODE(newnp);
|
||||
newnp->n_attrstamp = 0;
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
|
||||
NFSUNLOCKNODE(newnp);
|
||||
}
|
||||
if (nfscl_nodeleg(newvp, 0) == 0 ||
|
||||
((u_int)(ticks - ncticks) <
|
||||
(nmp->nm_nametimeo * hz) &&
|
||||
VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
timespeccmp(&vattr.va_ctime, &nctime, ==))) {
|
||||
NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits);
|
||||
return (0);
|
||||
}
|
||||
cache_purge(newvp);
|
||||
if (dvp != newvp)
|
||||
vput(newvp);
|
||||
else
|
||||
vrele(newvp);
|
||||
*vpp = NULLVP;
|
||||
} else if (error == ENOENT) {
|
||||
if (VN_IS_DOOMED(dvp))
|
||||
return (ENOENT);
|
||||
/*
|
||||
* We only accept a negative hit in the cache if the
|
||||
* modification time of the parent directory matches
|
||||
* the cached copy in the name cache entry.
|
||||
* Otherwise, we discard all of the negative cache
|
||||
* entries for this directory. We also only trust
|
||||
* negative cache entries for up to nm_negnametimeo
|
||||
* seconds.
|
||||
*/
|
||||
if ((u_int)(ticks - ncticks) <
|
||||
(nmp->nm_negnametimeo * hz) &&
|
||||
VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
timespeccmp(&vattr.va_mtime, &nctime, ==)) {
|
||||
NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits);
|
||||
return (ENOENT);
|
||||
}
|
||||
cache_purge_negative(dvp);
|
||||
}
|
||||
if (nfscl_nodeleg(newvp, 0) == 0 ||
|
||||
((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) &&
|
||||
VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
timespeccmp(&vattr.va_ctime, &nctime, ==))) {
|
||||
NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits);
|
||||
return (0);
|
||||
}
|
||||
cache_purge(newvp);
|
||||
if (dvp != newvp)
|
||||
vput(newvp);
|
||||
else
|
||||
vrele(newvp);
|
||||
*vpp = NULLVP;
|
||||
} else if (error == ENOENT) {
|
||||
if (VN_IS_DOOMED(dvp))
|
||||
return (ENOENT);
|
||||
/*
|
||||
* We only accept a negative hit in the cache if the
|
||||
* modification time of the parent directory matches
|
||||
* the cached copy in the name cache entry.
|
||||
* Otherwise, we discard all of the negative cache
|
||||
* entries for this directory. We also only trust
|
||||
* negative cache entries for up to nm_negnametimeo
|
||||
* seconds.
|
||||
*/
|
||||
if ((u_int)(ticks - ncticks) < (nmp->nm_negnametimeo * hz) &&
|
||||
VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
timespeccmp(&vattr.va_mtime, &nctime, ==)) {
|
||||
NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits);
|
||||
return (ENOENT);
|
||||
}
|
||||
cache_purge_negative(dvp);
|
||||
}
|
||||
|
||||
openmode = 0;
|
||||
@@ -1328,7 +1412,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp) && !NFSHASPNFS(nmp) &&
|
||||
(nmp->nm_privflag & NFSMNTP_DELEGISSUED) == 0 &&
|
||||
(!NFSMNT_RDONLY(mp) || (flags & OPENWRITE) == 0) &&
|
||||
(flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN)) {
|
||||
(flags & (ISLASTCN | ISOPEN | OPENNAMED))) == (ISLASTCN | ISOPEN)) {
|
||||
if ((flags & OPENREAD) != 0)
|
||||
openmode |= NFSV4OPEN_ACCESSREAD;
|
||||
if ((flags & OPENWRITE) != 0)
|
||||
@@ -1337,7 +1421,6 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
NFSUNLOCKMNT(nmp);
|
||||
#endif
|
||||
|
||||
newvp = NULLVP;
|
||||
NFSINCRGLOBAL(nfsstatsv1.lookupcache_misses);
|
||||
nanouptime(&ts);
|
||||
error = nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
|
||||
@@ -1345,6 +1428,11 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
openmode);
|
||||
if (dattrflag)
|
||||
(void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1);
|
||||
if (needs_nameddir) {
|
||||
vput(dvp);
|
||||
dvp = ap->a_dvp;
|
||||
}
|
||||
handle_error:
|
||||
if (error) {
|
||||
if (newvp != NULLVP) {
|
||||
vput(newvp);
|
||||
@@ -1353,13 +1441,14 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
|
||||
if (error != ENOENT) {
|
||||
if (NFS_ISV4(dvp))
|
||||
error = nfscl_maperr(td, error, (uid_t)0,
|
||||
(gid_t)0);
|
||||
error = nfscl_maperr(td, error,
|
||||
(uid_t)0, (gid_t)0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* The requested file was not found. */
|
||||
if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
|
||||
if ((cnp->cn_nameiop == CREATE ||
|
||||
cnp->cn_nameiop == RENAME) &&
|
||||
(flags & ISLASTCN)) {
|
||||
/*
|
||||
* XXX: UFS does a full VOP_ACCESS(dvp,
|
||||
@@ -1400,7 +1489,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
free(nfhp, M_NFSFH);
|
||||
return (EISDIR);
|
||||
}
|
||||
error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, LK_EXCLUSIVE);
|
||||
error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np,
|
||||
LK_EXCLUSIVE);
|
||||
if (error)
|
||||
return (error);
|
||||
newvp = NFSTOV(np);
|
||||
@@ -1421,7 +1511,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
}
|
||||
NFSUNLOCKNODE(np);
|
||||
if (attrflag)
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1);
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL,
|
||||
0, 1);
|
||||
*vpp = newvp;
|
||||
return (0);
|
||||
}
|
||||
@@ -1462,19 +1553,23 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (attrflag)
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1);
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL,
|
||||
0, 1);
|
||||
} else if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) {
|
||||
free(nfhp, M_NFSFH);
|
||||
VREF(dvp);
|
||||
newvp = dvp;
|
||||
if (attrflag)
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1);
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL,
|
||||
0, 1);
|
||||
} else {
|
||||
error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np,
|
||||
cnp->cn_lkflags);
|
||||
if (error)
|
||||
return (error);
|
||||
newvp = NFSTOV(np);
|
||||
if (opennamed)
|
||||
vn_irflag_set_cond(newvp, VIRF_NAMEDATTR);
|
||||
/*
|
||||
* If n_localmodtime >= time before RPC, then
|
||||
* a file modification operation, such as
|
||||
@@ -1492,8 +1587,10 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
}
|
||||
NFSUNLOCKNODE(np);
|
||||
if (attrflag)
|
||||
(void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1);
|
||||
else if ((flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) &&
|
||||
(void)nfscl_loadattrcache(&newvp, &nfsva, NULL,
|
||||
0, 1);
|
||||
else if ((flags & (ISLASTCN | ISOPEN)) ==
|
||||
(ISLASTCN | ISOPEN) &&
|
||||
!(np->n_flag & NMODIFIED)) {
|
||||
/*
|
||||
* Flush the attribute cache when opening a
|
||||
@@ -1754,6 +1851,7 @@ nfs_create(struct vop_create_args *ap)
|
||||
nfsquad_t cverf;
|
||||
int error = 0, attrflag, dattrflag, fmode = 0;
|
||||
struct vattr vattr;
|
||||
bool is_nameddir, needs_nameddir, opennamed;
|
||||
|
||||
/*
|
||||
* Oops, not for me..
|
||||
@@ -1767,6 +1865,32 @@ nfs_create(struct vop_create_args *ap)
|
||||
fmode |= O_EXCL;
|
||||
dnp = VTONFS(dvp);
|
||||
nmp = VFSTONFS(dvp->v_mount);
|
||||
needs_nameddir = false;
|
||||
if (NFSHASNFSV4(nmp) && NFSHASNFSV4N(nmp)) {
|
||||
opennamed = (cnp->cn_flags & (OPENNAMED | ISLASTCN)) ==
|
||||
(OPENNAMED | ISLASTCN);
|
||||
is_nameddir = (vn_irflag_read(dvp) & VIRF_NAMEDDIR) != 0;
|
||||
if (opennamed || is_nameddir) {
|
||||
cnp->cn_flags &= ~MAKEENTRY;
|
||||
if (!is_nameddir)
|
||||
needs_nameddir = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the named attribute directory is needed, acquire it now.
|
||||
*/
|
||||
if (needs_nameddir) {
|
||||
KASSERT(dnp->n_v4 == NULL, ("nfs_create: O_NAMEDATTR when"
|
||||
" n_v4 not NULL"));
|
||||
error = nfs_get_namedattrdir(dvp, cnp, &newvp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
dvp = newvp;
|
||||
dnp = VTONFS(dvp);
|
||||
newvp = NULL;
|
||||
}
|
||||
|
||||
again:
|
||||
/* For NFSv4, wait until any remove is done. */
|
||||
NFSLOCKNODE(dnp);
|
||||
@@ -1849,6 +1973,8 @@ nfs_create(struct vop_create_args *ap)
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
|
||||
}
|
||||
NFSUNLOCKNODE(dnp);
|
||||
if (needs_nameddir)
|
||||
vput(dvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@@ -4375,25 +4501,48 @@ nfs_pathconf(struct vop_pathconf_args *ap)
|
||||
struct nfsmount *nmp;
|
||||
struct thread *td = curthread;
|
||||
off_t off;
|
||||
bool eof;
|
||||
bool eof, has_namedattr, named_enabled;
|
||||
int attrflag, error;
|
||||
struct nfsnode *np;
|
||||
|
||||
nmp = VFSTONFS(vp->v_mount);
|
||||
np = VTONFS(vp);
|
||||
named_enabled = false;
|
||||
has_namedattr = false;
|
||||
if ((NFS_ISV34(vp) && (ap->a_name == _PC_LINK_MAX ||
|
||||
ap->a_name == _PC_NAME_MAX || ap->a_name == _PC_CHOWN_RESTRICTED ||
|
||||
ap->a_name == _PC_NO_TRUNC)) ||
|
||||
(NFS_ISV4(vp) && ap->a_name == _PC_ACL_NFS4)) {
|
||||
(NFS_ISV4(vp) && (ap->a_name == _PC_ACL_NFS4 ||
|
||||
ap->a_name == _PC_HAS_NAMEDATTR))) {
|
||||
/*
|
||||
* Since only the above 4 a_names are returned by the NFSv3
|
||||
* Pathconf RPC, there is no point in doing it for others.
|
||||
* For NFSv4, the Pathconf RPC (actually a Getattr Op.) can
|
||||
* be used for _PC_NFS4_ACL as well.
|
||||
* be used for _PC_ACL_NFS4 and _PC_HAS_NAMEDATTR as well.
|
||||
*/
|
||||
error = nfsrpc_pathconf(vp, &pc, td->td_ucred, td, &nfsva,
|
||||
&attrflag);
|
||||
error = nfsrpc_pathconf(vp, &pc, &has_namedattr, td->td_ucred,
|
||||
td, &nfsva, &attrflag);
|
||||
if (attrflag != 0)
|
||||
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
} else if (NFS_ISV4(vp) && ap->a_name == _PC_NAMEDATTR_ENABLED &&
|
||||
(np->n_flag & NNAMEDNOTSUPP) == 0) {
|
||||
struct nfsfh *nfhp;
|
||||
|
||||
error = nfsrpc_openattr(nmp, vp, np->n_fhp->nfh_fh,
|
||||
np->n_fhp->nfh_len, false, td->td_ucred, td, &nfsva, &nfhp,
|
||||
&attrflag);
|
||||
named_enabled = true;
|
||||
if (error == 0) {
|
||||
free(nfhp, M_NFSFH);
|
||||
} else if (error == NFSERR_NOTSUPP) {
|
||||
named_enabled = false;
|
||||
NFSLOCKNODE(np);
|
||||
np->n_flag |= NNAMEDNOTSUPP;
|
||||
NFSUNLOCKNODE(np);
|
||||
}
|
||||
error = 0;
|
||||
} else {
|
||||
/*
|
||||
* For NFSv2 (or NFSv3 when not one of the above 4 a_names),
|
||||
@@ -4476,7 +4625,6 @@ nfs_pathconf(struct vop_pathconf_args *ap)
|
||||
case _PC_MIN_HOLE_SIZE:
|
||||
/* Only some NFSv4.2 servers support Seek for Holes. */
|
||||
*ap->a_retval = 0;
|
||||
nmp = VFSTONFS(vp->v_mount);
|
||||
if (NFS_ISV4(vp) && nmp->nm_minorvers == NFSV42_MINORVERSION) {
|
||||
/*
|
||||
* NFSv4.2 doesn't have an attribute for hole size,
|
||||
@@ -4507,6 +4655,18 @@ nfs_pathconf(struct vop_pathconf_args *ap)
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
}
|
||||
break;
|
||||
case _PC_NAMEDATTR_ENABLED:
|
||||
if (named_enabled)
|
||||
*ap->a_retval = 1;
|
||||
else
|
||||
*ap->a_retval = 0;
|
||||
break;
|
||||
case _PC_HAS_NAMEDATTR:
|
||||
if (has_namedattr)
|
||||
*ap->a_retval = 1;
|
||||
else
|
||||
*ap->a_retval = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
error = vop_stdpathconf(ap);
|
||||
|
||||
@@ -162,6 +162,7 @@ struct nfsnode {
|
||||
#define NDSCOMMIT 0x00100000 /* Commit is done via the DS. */
|
||||
#define NVNSETSZSKIP 0x00200000 /* Skipped vnode_pager_setsize() */
|
||||
#define NMIGHTBELOCKED 0x00400000 /* Might be file locked. */
|
||||
#define NNAMEDNOTSUPP 0x00800000 /* Openattr is not supported. */
|
||||
|
||||
/*
|
||||
* Convert between nfsnode pointers and vnode pointers
|
||||
|
||||
@@ -122,7 +122,6 @@ extern struct nfsdevicehead nfsrv_devidhead;
|
||||
/* Map d_type to vnode type. */
|
||||
static uint8_t dtype_to_vnode[DT_WHT + 1] = { VNON, VFIFO, VCHR, VNON, VDIR,
|
||||
VNON, VBLK, VNON, VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON };
|
||||
#define NFS_DTYPETOVTYPE(t) ((t) <= DT_WHT ? dtype_to_vnode[(t)] : VNON)
|
||||
|
||||
static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **,
|
||||
struct iovec **);
|
||||
@@ -130,6 +129,7 @@ static int nfsrv_createiovec_extpgs(int, int, struct mbuf **,
|
||||
struct mbuf **, struct iovec **);
|
||||
static int nfsrv_createiovecw(int, struct mbuf *, char *, struct iovec **,
|
||||
int *);
|
||||
static void nfs_dtypetovtype(struct nfsvattr *, struct vnode *, uint8_t);
|
||||
static void nfsrv_pnfscreate(struct vnode *, struct vattr *, struct ucred *,
|
||||
NFSPROC_T *);
|
||||
static void nfsrv_pnfsremovesetup(struct vnode *, NFSPROC_T *, struct vnode **,
|
||||
@@ -444,6 +444,7 @@ nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap,
|
||||
gotattr = 1;
|
||||
}
|
||||
|
||||
nvap->na_bsdflags = 0;
|
||||
error = VOP_GETATTR(vp, &nvap->na_vattr, nd->nd_cred);
|
||||
if (lockedit != 0)
|
||||
NFSVOPUNLOCK(vp);
|
||||
@@ -2046,6 +2047,23 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a dirent d_type to a vnode type.
|
||||
*/
|
||||
static void nfs_dtypetovtype(struct nfsvattr *nvap, struct vnode *vp,
|
||||
uint8_t dtype)
|
||||
{
|
||||
|
||||
if ((vn_irflag_read(vp) & VIRF_NAMEDDIR) != 0) {
|
||||
nvap->na_type = VREG;
|
||||
nvap->na_bsdflags |= SFBSD_NAMEDATTR;
|
||||
} else if (dtype <= DT_WHT) {
|
||||
nvap->na_type = dtype_to_vnode[dtype];
|
||||
} else {
|
||||
nvap->na_type = VNON;
|
||||
}
|
||||
}
|
||||
|
||||
/* Since the Readdir vnode ops vary, put the entire functions in here. */
|
||||
/*
|
||||
* nfs readdir service
|
||||
@@ -2665,6 +2683,10 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
|
||||
LK_SHARED, &nvp);
|
||||
else
|
||||
r = EOPNOTSUPP;
|
||||
if (r == 0 && (vn_irflag_read(vp) &
|
||||
VIRF_NAMEDDIR) != 0)
|
||||
vn_irflag_set_cond(nvp,
|
||||
VIRF_NAMEDATTR);
|
||||
if (r == EOPNOTSUPP) {
|
||||
if (usevget) {
|
||||
usevget = 0;
|
||||
@@ -2679,6 +2701,10 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
|
||||
cn.cn_namelen = nlen;
|
||||
cn.cn_flags = ISLASTCN |
|
||||
NOFOLLOW | LOCKLEAF;
|
||||
if ((vn_irflag_read(vp) &
|
||||
VIRF_NAMEDDIR) != 0)
|
||||
cn.cn_flags |=
|
||||
OPENNAMED;
|
||||
if (nlen == 2 &&
|
||||
dp->d_name[0] == '.' &&
|
||||
dp->d_name[1] == '.')
|
||||
@@ -2796,7 +2822,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
|
||||
/* Only need Type and/or Fileid. */
|
||||
VATTR_NULL(&nvap->na_vattr);
|
||||
nvap->na_fileid = dp->d_fileno;
|
||||
nvap->na_type = NFS_DTYPETOVTYPE(dp->d_type);
|
||||
nfs_dtypetovtype(nvap, vp, dp->d_type);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3462,6 +3488,15 @@ nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype,
|
||||
&credanon);
|
||||
vfs_unbusy(mp);
|
||||
|
||||
if (nd->nd_repstat == 0 &&
|
||||
nfp->nfsrvfh_len >= NFSX_MYFH + NFSX_V4NAMEDDIRFH &&
|
||||
nfp->nfsrvfh_len <= NFSX_MYFH + NFSX_V4NAMEDATTRFH) {
|
||||
if (nfp->nfsrvfh_len == NFSX_MYFH + NFSX_V4NAMEDDIRFH)
|
||||
vn_irflag_set_cond(*vpp, VIRF_NAMEDDIR);
|
||||
else
|
||||
vn_irflag_set_cond(*vpp, VIRF_NAMEDATTR);
|
||||
}
|
||||
|
||||
/*
|
||||
* For NFSv4 without a pseudo root fs, unexported file handles
|
||||
* can be returned, so that Lookup works everywhere.
|
||||
@@ -5528,7 +5563,7 @@ nfsrv_writedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, int len,
|
||||
if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) ==
|
||||
(ND_NFSV4 | ND_V4WCCATTR)) {
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
NFSD_DEBUG(4, "nfsrv_writedsdorpc: wcc attr=%d\n", error);
|
||||
if (error != 0)
|
||||
goto nfsmout;
|
||||
@@ -5559,7 +5594,7 @@ nfsrv_writedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, int len,
|
||||
if (error == 0) {
|
||||
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
NFSD_DEBUG(4, "nfsrv_writedsdorpc: aft loadattr=%d\n", error);
|
||||
nfsmout:
|
||||
@@ -5725,7 +5760,7 @@ nfsrv_allocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off,
|
||||
if (nd->nd_repstat == 0) {
|
||||
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
} else
|
||||
error = nd->nd_repstat;
|
||||
NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: aft loadattr=%d\n", error);
|
||||
@@ -5892,7 +5927,7 @@ nfsrv_deallocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off,
|
||||
if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) ==
|
||||
(ND_NFSV4 | ND_V4WCCATTR)) {
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: wcc attr=%d\n", error);
|
||||
if (error != 0)
|
||||
goto nfsmout;
|
||||
@@ -5906,7 +5941,7 @@ nfsrv_deallocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off,
|
||||
if (nd->nd_repstat == 0) {
|
||||
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
} else
|
||||
error = nd->nd_repstat;
|
||||
NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: aft loadattr=%d\n", error);
|
||||
@@ -6054,7 +6089,7 @@ nfsrv_setattrdsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
|
||||
if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) ==
|
||||
(ND_NFSV4 | ND_V4WCCATTR)) {
|
||||
error = nfsv4_loadattr(nd, NULL, dsnap, NULL, NULL, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: wcc attr=%d\n", error);
|
||||
if (error != 0)
|
||||
goto nfsmout;
|
||||
@@ -6078,7 +6113,8 @@ nfsrv_setattrdsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
|
||||
if (error == 0) {
|
||||
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
error = nfsv4_loadattr(nd, NULL, dsnap, NULL, NULL, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: aft setattr loadattr=%d\n", error);
|
||||
nfsmout:
|
||||
@@ -6367,7 +6403,7 @@ nfsrv_getattrdsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
|
||||
if (nd->nd_repstat == 0) {
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
/*
|
||||
* We can only save the updated values in the extended
|
||||
* attribute if the vp is exclusively locked.
|
||||
|
||||
@@ -595,6 +595,8 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
char *bufp;
|
||||
u_long *hashp;
|
||||
struct thread *p = curthread;
|
||||
struct componentname *cnp;
|
||||
short irflag;
|
||||
|
||||
if (nd->nd_repstat) {
|
||||
nfsrv_postopattr(nd, dattr_ret, &dattr);
|
||||
@@ -611,8 +613,12 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
goto out;
|
||||
}
|
||||
|
||||
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
|
||||
LOCKLEAF);
|
||||
cnp = &named.ni_cnd;
|
||||
irflag = vn_irflag_read(dp);
|
||||
if ((irflag & VIRF_NAMEDDIR) != 0)
|
||||
NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF | OPENNAMED);
|
||||
else
|
||||
NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF);
|
||||
nfsvno_setpathbuf(&named, &bufp, &hashp);
|
||||
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
|
||||
if (error) {
|
||||
@@ -621,6 +627,10 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
goto out;
|
||||
}
|
||||
if (!nd->nd_repstat) {
|
||||
/* Don't set OPENNAMED for Lookupp (".."). */
|
||||
if (cnp->cn_namelen == 2 && *cnp->cn_nameptr == '.' &&
|
||||
*(cnp->cn_nameptr + 1) == '.')
|
||||
cnp->cn_flags &= ~OPENNAMED;
|
||||
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
|
||||
} else {
|
||||
vrele(dp);
|
||||
@@ -1348,6 +1358,18 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
|
||||
vtyp = nfsv34tov_type(*tl);
|
||||
nfs4type = fxdr_unsigned(nfstype, *tl);
|
||||
if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) {
|
||||
/*
|
||||
* Don't allow creation of non-regular file objects
|
||||
* in a named attribute directory.
|
||||
*/
|
||||
nd->nd_repstat = NFSERR_INVAL;
|
||||
vrele(dp);
|
||||
#ifdef NFS4_ACL_EXTATTR_NAME
|
||||
acl_free(aclp);
|
||||
#endif
|
||||
goto out;
|
||||
}
|
||||
switch (nfs4type) {
|
||||
case NFLNK:
|
||||
error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
|
||||
@@ -1680,8 +1702,7 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
|
||||
}
|
||||
|
||||
/* If this is the same file handle, just VREF() the vnode. */
|
||||
if (tfh.nfsrvfh_len == NFSX_MYFH &&
|
||||
!NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
|
||||
if (!NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
|
||||
VREF(dp);
|
||||
tdp = dp;
|
||||
tnes = *exp;
|
||||
@@ -1804,8 +1825,15 @@ nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
|
||||
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
|
||||
goto out;
|
||||
}
|
||||
if ((vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0 ||
|
||||
(tovp != NULL &&
|
||||
(vn_irflag_read(tovp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0)) {
|
||||
nd->nd_repstat = NFSERR_INVAL;
|
||||
if (tovp != NULL)
|
||||
vrele(tovp);
|
||||
}
|
||||
NFSVOPUNLOCK(vp);
|
||||
if (vp->v_type == VDIR) {
|
||||
if (!nd->nd_repstat && vp->v_type == VDIR) {
|
||||
if (nd->nd_flag & ND_NFSV4)
|
||||
nd->nd_repstat = NFSERR_ISDIR;
|
||||
else
|
||||
@@ -2971,6 +2999,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
|
||||
cverf[0] = *tl++;
|
||||
cverf[1] = *tl;
|
||||
if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0)
|
||||
nd->nd_repstat = NFSERR_INVAL;
|
||||
break;
|
||||
case NFSCREATE_EXCLUSIVE41:
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
|
||||
@@ -2979,7 +3009,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
|
||||
if (error != 0)
|
||||
goto nfsmout;
|
||||
if (NFSISSET_ATTRBIT(&attrbits,
|
||||
if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0 ||
|
||||
NFSISSET_ATTRBIT(&attrbits,
|
||||
NFSATTRBIT_TIMEACCESSSET))
|
||||
nd->nd_repstat = NFSERR_INVAL;
|
||||
/*
|
||||
@@ -3473,11 +3504,20 @@ nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
{
|
||||
fhandle_t fh;
|
||||
struct thread *p = curthread;
|
||||
int siz;
|
||||
short irflag;
|
||||
|
||||
nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
|
||||
irflag = vn_irflag_read(vp);
|
||||
vput(vp);
|
||||
if (!nd->nd_repstat)
|
||||
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
|
||||
if (nd->nd_repstat == 0) {
|
||||
siz = 0;
|
||||
if ((irflag & VIRF_NAMEDDIR) != 0)
|
||||
siz = NFSX_FHMAX + NFSX_V4NAMEDDIRFH;
|
||||
else if ((irflag & VIRF_NAMEDATTR) != 0)
|
||||
siz = NFSX_FHMAX + NFSX_V4NAMEDATTRFH;
|
||||
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, siz, 0);
|
||||
}
|
||||
NFSEXITCODE2(0, nd);
|
||||
return (0);
|
||||
}
|
||||
@@ -4187,7 +4227,8 @@ nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
|
||||
if (!nd->nd_repstat) {
|
||||
nfsvno_getfs(&fs, isdgram);
|
||||
error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
|
||||
sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
|
||||
sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, p,
|
||||
nd->nd_cred);
|
||||
if (!error) {
|
||||
if (nd->nd_procnum == NFSV4OP_NVERIFY) {
|
||||
if (ret == 0)
|
||||
@@ -4209,15 +4250,39 @@ nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
|
||||
*/
|
||||
int
|
||||
nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
|
||||
struct vnode *dp, struct vnode **vpp, __unused fhandle_t *fhp,
|
||||
__unused struct nfsexstuff *exp)
|
||||
{
|
||||
u_int32_t *tl;
|
||||
int error = 0, createdir __unused;
|
||||
uint32_t *tl;
|
||||
struct componentname cn;
|
||||
int error = 0;
|
||||
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
|
||||
createdir = fxdr_unsigned(int, *tl);
|
||||
nd->nd_repstat = NFSERR_NOTSUPP;
|
||||
NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
|
||||
NOFOLLOW);
|
||||
cn.cn_nameptr = ".";
|
||||
cn.cn_namelen = 1;
|
||||
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
|
||||
if (*tl == newnfs_true)
|
||||
cn.cn_flags |= CREATENAMED;
|
||||
|
||||
nd->nd_repstat = vn_lock(dp, LK_SHARED);
|
||||
if (nd->nd_repstat != 0)
|
||||
goto nfsmout;
|
||||
|
||||
if ((dp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0)
|
||||
nd->nd_repstat = NFSERR_NOTSUPP;
|
||||
if (nd->nd_repstat == 0 && (vn_irflag_read(dp) & (VIRF_NAMEDDIR |
|
||||
VIRF_NAMEDATTR)) != 0)
|
||||
nd->nd_repstat = NFSERR_WRONGTYPE;
|
||||
if (nd->nd_repstat == 0) {
|
||||
nd->nd_repstat = VOP_LOOKUP(dp, vpp, &cn);
|
||||
if (nd->nd_repstat == ENOATTR)
|
||||
nd->nd_repstat = NFSERR_NOENT;
|
||||
}
|
||||
|
||||
vput(dp);
|
||||
NFSEXITCODE2(0, nd);
|
||||
return (0);
|
||||
nfsmout:
|
||||
vrele(dp);
|
||||
NFSEXITCODE2(error, nd);
|
||||
|
||||
@@ -4675,7 +4675,7 @@ nfsrv_docallback(struct nfsclient *clp, int procnum, nfsv4stateid_t *stateidp,
|
||||
} else if (error == 0 && procnum == NFSV4OP_CBGETATTR)
|
||||
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
|
||||
p, NULL);
|
||||
NULL, p, NULL);
|
||||
m_freem(nd->nd_mrep);
|
||||
}
|
||||
NFSLOCKSTATE();
|
||||
|
||||
@@ -1473,8 +1473,9 @@ int
|
||||
nfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
|
||||
{
|
||||
u_int32_t *tl;
|
||||
int error = 0, len, copylen;
|
||||
int error = 0, len, copylen, namedlen;
|
||||
|
||||
namedlen = 0;
|
||||
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
|
||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
|
||||
len = fxdr_unsigned(int, *tl);
|
||||
@@ -1490,6 +1491,11 @@ nfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
|
||||
copylen = NFSX_MYFH;
|
||||
len = NFSM_RNDUP(len);
|
||||
nd->nd_flag |= ND_DSSERVER;
|
||||
} else if (len >= NFSX_MYFH + NFSX_V4NAMEDDIRFH &&
|
||||
len <= NFSX_MYFH + NFSX_V4NAMEDATTRFH) {
|
||||
copylen = NFSX_MYFH;
|
||||
namedlen = len;
|
||||
len = NFSM_RNDUP(len);
|
||||
} else if (len < NFSRV_MINFH || len > NFSRV_MAXFH) {
|
||||
if (nd->nd_flag & ND_NFSV4) {
|
||||
if (len > 0 && len <= NFSX_V4FHMAX) {
|
||||
@@ -1524,7 +1530,10 @@ nfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
|
||||
goto nfsmout;
|
||||
}
|
||||
NFSBCOPY(tl, (caddr_t)fhp->nfsrvfh_data, copylen);
|
||||
fhp->nfsrvfh_len = copylen;
|
||||
if (namedlen > 0)
|
||||
fhp->nfsrvfh_len = namedlen;
|
||||
else
|
||||
fhp->nfsrvfh_len = copylen;
|
||||
nfsmout:
|
||||
NFSEXITCODE2(error, nd);
|
||||
return (error);
|
||||
|
||||
Reference in New Issue
Block a user