diff options
Diffstat (limited to 'sys/fs/nfs')
-rw-r--r-- | sys/fs/nfs/nfs_commonacl.c | 38 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonkrpc.c | 112 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonport.c | 59 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonsubs.c | 246 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_var.h | 5 | ||||
-rw-r--r-- | sys/fs/nfs/nfsdport.h | 16 | ||||
-rw-r--r-- | sys/fs/nfs/nfsport.h | 13 | ||||
-rw-r--r-- | sys/fs/nfs/nfsproto.h | 57 |
8 files changed, 415 insertions, 131 deletions
diff --git a/sys/fs/nfs/nfs_commonacl.c b/sys/fs/nfs/nfs_commonacl.c index c4875d8..1d731c5 100644 --- a/sys/fs/nfs/nfs_commonacl.c +++ b/sys/fs/nfs/nfs_commonacl.c @@ -59,7 +59,8 @@ nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, mask = fxdr_unsigned(u_int32_t, *tl++); len = fxdr_unsigned(int, *tl); if (len < 0) { - return (NFSERR_BADXDR); + error = NFSERR_BADXDR; + goto nfsmout; } else if (len == 0) { /* Netapp filers return a 0 length who for nil users */ acep->ae_tag = ACL_UNDEFINED_TAG; @@ -68,7 +69,8 @@ nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, acep->ae_entry_type = ACL_ENTRY_TYPE_DENY; if (acesizep) *acesizep = 4 * NFSX_UNSIGNED; - return (0); + error = 0; + goto nfsmout; } if (len > NFSV4_SMALLSTR) name = malloc(len + 1, M_NFSSTRING, M_WAITOK); @@ -78,7 +80,7 @@ nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, if (error) { if (len > NFSV4_SMALLSTR) free(name, M_NFSSTRING); - return (error); + goto nfsmout; } if (len == 6) { if (!NFSBCMP(name, "OWNER@", 6)) { @@ -171,8 +173,9 @@ nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, *aceerrp = aceerr; if (acesizep) *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); - return (0); + error = 0; nfsmout: + NFSEXITCODE(error); return (error); } @@ -184,6 +187,7 @@ nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, enum vtype type, acl_perm_t *permp) { acl_perm_t perm = 0x0; + int error = 0; if (mask & NFSV4ACE_READDATA) { mask &= ~NFSV4ACE_READDATA; @@ -257,10 +261,15 @@ nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, mask &= ~NFSV4ACE_SYNCHRONIZE; perm |= ACL_SYNCHRONIZE; } - if (mask != 0) - return (NFSERR_ATTRNOTSUPP); + if (mask != 0) { + error = NFSERR_ATTRNOTSUPP; + goto out; + } *permp = perm; - return (0); + +out: + NFSEXITCODE(error); + return (error); } /* local functions */ @@ -445,19 +454,26 @@ nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred, { int error; - if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) - return (NFSERR_ATTRNOTSUPP); + if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) { + error = NFSERR_ATTRNOTSUPP; + goto out; + } /* * With NFSv4 ACLs, chmod(2) may need to add additional entries. * Make sure it has enough room for that - splitting every entry * into two and appending "canonical six" entries at the end. * Cribbed out of kern/vfs_acl.c - Rick M. */ - if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) - return (NFSERR_ATTRNOTSUPP); + if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) { + error = NFSERR_ATTRNOTSUPP; + goto out; + } error = VOP_ACLCHECK(vp, ACL_TYPE_NFS4, aclp, cred, p); if (!error) error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p); + +out: + NFSEXITCODE(error); return (error); } diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c index ba1ac4e..1f65380 100644 --- a/sys/fs/nfs/nfs_commonkrpc.c +++ b/sys/fs/nfs/nfs_commonkrpc.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); */ #include "opt_inet6.h" +#include "opt_kdtrace.h" #include "opt_kgssapi.h" #include "opt_nfs.h" @@ -64,6 +65,28 @@ __FBSDID("$FreeBSD$"); #include <fs/nfs/nfsport.h> +#ifdef KDTRACE_HOOKS +#include <sys/dtrace_bsd.h> + +dtrace_nfsclient_nfs23_start_probe_func_t + dtrace_nfscl_nfs234_start_probe; + +dtrace_nfsclient_nfs23_done_probe_func_t + dtrace_nfscl_nfs234_done_probe; + +/* + * Registered probes by RPC type. + */ +uint32_t nfscl_nfs2_start_probes[NFS_NPROCS + 1]; +uint32_t nfscl_nfs2_done_probes[NFS_NPROCS + 1]; + +uint32_t nfscl_nfs3_start_probes[NFS_NPROCS + 1]; +uint32_t nfscl_nfs3_done_probes[NFS_NPROCS + 1]; + +uint32_t nfscl_nfs4_start_probes[NFS_NPROCS + 1]; +uint32_t nfscl_nfs4_done_probes[NFS_NPROCS + 1]; +#endif + NFSSTATESPINLOCK; NFSREQSPINLOCK; extern struct nfsstats newnfsstats; @@ -143,7 +166,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, CLIENT *client; struct netconfig *nconf; struct socket *so; - int one = 1, retries, error; + int one = 1, retries, error = 0; struct thread *td = curthread; /* @@ -199,7 +222,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, nrp->nr_soproto, td->td_ucred, td); if (error) { td->td_ucred = origcred; - return (error); + goto out; } do { if (error != 0 && pktscale > 2) @@ -230,7 +253,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, soclose(so); if (error) { td->td_ucred = origcred; - return (error); + goto out; } client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog, @@ -284,7 +307,10 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, /* Restore current thread's credentials. */ td->td_ucred = origcred; - return (0); + +out: + NFSEXITCODE(error); + return (error); } /* @@ -300,9 +326,7 @@ newnfs_disconnect(struct nfssockreq *nrp) client = nrp->nr_client; nrp->nr_client = NULL; mtx_unlock(&nrp->nr_mtx); -#ifdef KGSSAPI - rpc_gss_secpurge(client); -#endif + rpc_gss_secpurge_call(client); CLNT_CLOSE(client); CLNT_RELEASE(client); } else { @@ -314,21 +338,18 @@ static AUTH * nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, char *srv_principal, gss_OID mech_oid, struct ucred *cred) { -#ifdef KGSSAPI rpc_gss_service_t svc; AUTH *auth; #ifdef notyet rpc_gss_options_req_t req_options; #endif -#endif switch (secflavour) { -#ifdef KGSSAPI case RPCSEC_GSS_KRB5: case RPCSEC_GSS_KRB5I: case RPCSEC_GSS_KRB5P: if (!mech_oid) { - if (!rpc_gss_mech_to_oid("kerberosv5", &mech_oid)) + if (!rpc_gss_mech_to_oid_call("kerberosv5", &mech_oid)) return (NULL); } if (secflavour == RPCSEC_GSS_KRB5) @@ -344,7 +365,7 @@ nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, req_options.input_channel_bindings = NULL; req_options.enc_type = nfs_keytab_enctype; - auth = rpc_gss_secfind(nrp->nr_client, cred, + auth = rpc_gss_secfind_call(nrp->nr_client, cred, clnt_principal, srv_principal, mech_oid, svc, &req_options); #else @@ -354,7 +375,7 @@ nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, * principals. As such, that case cannot yet be handled. */ if (clnt_principal == NULL) - auth = rpc_gss_secfind(nrp->nr_client, cred, + auth = rpc_gss_secfind_call(nrp->nr_client, cred, srv_principal, mech_oid, svc); else auth = NULL; @@ -362,7 +383,6 @@ nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, if (auth != NULL) return (auth); /* fallthrough */ -#endif /* KGSSAPI */ case AUTH_SYS: default: return (authunix_create(cred)); @@ -509,6 +529,20 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, else secflavour = RPCSEC_GSS_KRB5; srv_principal = NFSMNT_SRVKRBNAME(nmp); + } else if (nmp != NULL && !NFSHASKERB(nmp) && + nd->nd_procnum != NFSPROC_NULL && + (nd->nd_flag & ND_USEGSSNAME) != 0) { + /* + * Use the uid that did the mount when the RPC is doing + * NFSv4 system operations, as indicated by the + * ND_USEGSSNAME flag, for the AUTH_SYS case. + */ + saved_uid = cred->cr_uid; + if (nmp->nm_uid != (uid_t)-1) + cred->cr_uid = nmp->nm_uid; + else + cred->cr_uid = 0; + set_uid = 1; } if (nmp != NULL) { @@ -568,6 +602,29 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND) MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSDREQ, M_WAITOK); +#ifdef KDTRACE_HOOKS + if (dtrace_nfscl_nfs234_start_probe != NULL) { + uint32_t probe_id; + int probe_procnum; + + if (nd->nd_flag & ND_NFSV4) { + probe_id = + nfscl_nfs4_start_probes[nd->nd_procnum]; + probe_procnum = nd->nd_procnum; + } else if (nd->nd_flag & ND_NFSV3) { + probe_id = nfscl_nfs3_start_probes[procnum]; + probe_procnum = procnum; + } else { + probe_id = + nfscl_nfs2_start_probes[nd->nd_procnum]; + probe_procnum = procnum; + } + if (probe_id != 0) + (dtrace_nfscl_nfs234_start_probe) + (probe_id, vp, nd->nd_mreq, cred, + probe_procnum); + } +#endif } trycnt = 0; tryagain: @@ -658,8 +715,10 @@ tryagain: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl); if (nd->nd_repstat != 0) { - if ((nd->nd_repstat == NFSERR_DELAY && + if (((nd->nd_repstat == NFSERR_DELAY || + nd->nd_repstat == NFSERR_GRACE) && (nd->nd_flag & ND_NFSV4) && + nd->nd_procnum != NFSPROC_DELEGRETURN && nd->nd_procnum != NFSPROC_SETATTR && nd->nd_procnum != NFSPROC_READ && nd->nd_procnum != NFSPROC_WRITE && @@ -679,6 +738,8 @@ tryagain: while (NFSD_MONOSEC < waituntil) (void) nfs_catnap(PZERO, 0, "nfstry"); trylater_delay *= 2; + m_freem(nd->nd_mrep); + nd->nd_mrep = NULL; goto tryagain; } @@ -762,6 +823,27 @@ tryagain: } } +#ifdef KDTRACE_HOOKS + if (nmp != NULL && dtrace_nfscl_nfs234_done_probe != NULL) { + uint32_t probe_id; + int probe_procnum; + + if (nd->nd_flag & ND_NFSV4) { + probe_id = nfscl_nfs4_done_probes[nd->nd_procnum]; + probe_procnum = nd->nd_procnum; + } else if (nd->nd_flag & ND_NFSV3) { + probe_id = nfscl_nfs3_done_probes[procnum]; + probe_procnum = procnum; + } else { + probe_id = nfscl_nfs2_done_probes[nd->nd_procnum]; + probe_procnum = procnum; + } + if (probe_id != 0) + (dtrace_nfscl_nfs234_done_probe)(probe_id, vp, + nd->nd_mreq, cred, probe_procnum, 0); + } +#endif + m_freem(nd->nd_mreq); AUTH_DESTROY(auth); if (rep != NULL) diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c index 6254915..0320f47 100644 --- a/sys/fs/nfs/nfs_commonport.c +++ b/sys/fs/nfs/nfs_commonport.c @@ -289,6 +289,50 @@ nfsvno_getfs(struct nfsfsinfo *sip, int isdgram) NFSV3FSINFO_CANSETTIME); } +/* + * Do the pathconf vnode op. + */ +int +nfsvno_pathconf(struct vnode *vp, int flag, register_t *retf, + struct ucred *cred, struct thread *p) +{ + int error; + + error = VOP_PATHCONF(vp, flag, retf); + if (error == EOPNOTSUPP || error == EINVAL) { + /* + * Some file systems return EINVAL for name arguments not + * supported and some return EOPNOTSUPP for this case. + * So the NFSv3 Pathconf RPC doesn't fail for these cases, + * just fake them. + */ + switch (flag) { + case _PC_LINK_MAX: + *retf = LINK_MAX; + break; + case _PC_NAME_MAX: + *retf = NAME_MAX; + break; + case _PC_CHOWN_RESTRICTED: + *retf = 1; + break; + case _PC_NO_TRUNC: + *retf = 1; + break; + default: + /* + * Only happens if a _PC_xxx is added to the server, + * but this isn't updated. + */ + *retf = 0; + printf("nfsrvd pathconf flag=%d not supp\n", flag); + }; + error = 0; + } + NFSEXITCODE(error); + return (error); +} + /* Fake nfsrv_atroot. Just return 0 */ int nfsrv_atroot(struct vnode *vp, long *retp) @@ -384,6 +428,7 @@ nfssvc_nfscommon(struct thread *td, struct nfssvc_args *uap) int error; error = nfssvc_call(td, uap, td->td_ucred); + NFSEXITCODE(error); return (error); } @@ -396,9 +441,9 @@ nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) if (uap->flag & NFSSVC_IDNAME) { error = copyin(uap->argp, (caddr_t)&nid, sizeof (nid)); if (error) - return (error); + goto out; error = nfssvc_idname(&nid); - return (error); + goto out; } else if (uap->flag & NFSSVC_GETSTATS) { error = copyout(&newnfsstats, CAST_USER_ADDR_T(uap->argp), sizeof (newnfsstats)); @@ -460,7 +505,7 @@ nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) sizeof(newnfsstats.cbrpccnt)); } } - return (error); + goto out; } else if (uap->flag & NFSSVC_NFSUSERDPORT) { u_short sockport; @@ -472,6 +517,9 @@ nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) nfsrv_nfsuserddelport(); error = 0; } + +out: + NFSEXITCODE(error); return (error); } @@ -526,7 +574,7 @@ nfscommon_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: if (loaded) - return (0); + goto out; newnfs_portinit(); mtx_init(&nfs_nameid_mutex, "nfs_nameid_mutex", NULL, MTX_DEF); mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF); @@ -563,6 +611,9 @@ nfscommon_modevent(module_t mod, int type, void *data) error = EOPNOTSUPP; break; } + +out: + NFSEXITCODE(error); return error; } static moduledata_t nfscommon_mod = { diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 03b5786..168018c 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -179,8 +179,10 @@ nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; rem = NFSM_RNDUP(siz) - siz; while (siz > 0) { - if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) - return (EBADRPC); + if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { + error = EBADRPC; + goto out; + } left = uiop->uio_iov->iov_len; uiocp = uiop->uio_iov->iov_base; if (left > siz) @@ -189,8 +191,10 @@ nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) while (left > 0) { while (len == 0) { mp = mbuf_next(mp); - if (mp == NULL) - return (EBADRPC); + if (mp == NULL) { + error = EBADRPC; + goto out; + } mbufcp = NFSMTOD(mp, caddr_t); len = mbuf_len(mp); } @@ -231,6 +235,9 @@ nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) else nd->nd_dpos += rem; } + +out: + NFSEXITCODE2(error, nd); return (error); } #endif /* !APPLE */ @@ -308,9 +315,10 @@ nfsm_dissct(struct nfsrv_descript *nd, int siz) APPLESTATIC int nfsm_advance(struct nfsrv_descript *nd, int offs, int left) { + int error = 0; if (offs == 0) - return (0); + goto out; /* * A negative offs should be considered a serious problem. */ @@ -330,13 +338,18 @@ nfsm_advance(struct nfsrv_descript *nd, int offs, int left) while (offs > left) { offs -= left; nd->nd_md = mbuf_next(nd->nd_md); - if (nd->nd_md == NULL) - return (EBADRPC); + if (nd->nd_md == NULL) { + error = EBADRPC; + goto out; + } left = mbuf_len(nd->nd_md); nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); } nd->nd_dpos += offs; - return (0); + +out: + NFSEXITCODE(error); + return (error); } /* @@ -620,8 +633,10 @@ nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if ((len = fxdr_unsigned(int, *tl)) <= 0 || - len > NFSX_FHMAX) - return (EBADRPC); + len > NFSX_FHMAX) { + error = EBADRPC; + goto nfsmout; + } } else len = NFSX_V2FH; MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, @@ -629,11 +644,12 @@ nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); if (error) { FREE((caddr_t)nfhp, M_NFSFH); - return (error); + goto nfsmout; } nfhp->nfh_len = len; *nfhpp = nfhp; nfsmout: + NFSEXITCODE2(error, nd); return (error); } @@ -660,9 +676,9 @@ nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, aclsize = NFSX_UNSIGNED; acecnt = fxdr_unsigned(int, *tl); if (acecnt > ACL_MAX_ENTRIES) - aceerr = 1; + aceerr = NFSERR_ATTRNOTSUPP; if (nfsrv_useacl == 0) - aceerr = 1; + aceerr = NFSERR_ATTRNOTSUPP; for (i = 0; i < acecnt; i++) { if (aclp && !aceerr) error = nfsrv_dissectace(nd, &aclp->acl_entry[i], @@ -670,7 +686,7 @@ nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, else error = nfsrv_skipace(nd, &acesize); if (error) - return (error); + goto nfsmout; aclsize += acesize; } if (aclp && !aceerr) @@ -680,6 +696,7 @@ nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, if (aclsizep) *aclsizep = aclsize; nfsmout: + NFSEXITCODE2(error, nd); return (error); } @@ -697,6 +714,7 @@ nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) error = nfsm_advance(nd, NFSM_RNDUP(len), -1); nfsmout: *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); + NFSEXITCODE2(error, nd); return (error); } @@ -715,8 +733,10 @@ nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); cnt = fxdr_unsigned(int, *tl); - if (cnt < 0) - return (NFSERR_BADXDR); + if (cnt < 0) { + error = NFSERR_BADXDR; + goto nfsmout; + } if (cnt > NFSATTRBIT_MAXWORDS) { outcnt = NFSATTRBIT_MAXWORDS; if (retnotsupp) @@ -735,6 +755,7 @@ nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, if (cntp) *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); nfsmout: + NFSEXITCODE2(error, nd); return (error); } @@ -756,7 +777,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) { u_int32_t *tl; - int i = 0, j, k, l, m, bitpos, attrsum = 0; + int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; int error, tfhsize, aceerr, attrsize, cnt, retnotsup; u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; nfsattrbit_t attrbits, retattrbits, checkattrbits; @@ -782,7 +803,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); } if (error) - return (error); + goto nfsmout; if (compare) { *retcmpp = retnotsup; @@ -853,7 +874,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, error = nfsrv_getattrbits(nd, &nap->na_suppattr, &cnt, &retnotsup); if (error) - return (error); + goto nfsmout; if (compare && !(*retcmpp)) { NFSSETSUPP_ATTRBIT(&checkattrbits); if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) @@ -1014,9 +1035,10 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, &cnt, p); if (error) { acl_free(naclp); - return (error); + goto nfsmout; } - if (aceerr || nfsrv_compareacl(aclp, naclp)) + if (aceerr || aclp == NULL || + nfsrv_compareacl(aclp, naclp)) *retcmpp = NFSERR_NOTSAME; acl_free(naclp); } else { @@ -1033,7 +1055,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, error = nfsrv_dissectacl(nd, NULL, &aceerr, &cnt, p); if (error) - return (error); + goto nfsmout; } attrsum += cnt; break; @@ -1118,7 +1140,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, case NFSATTRBIT_FILEHANDLE: error = nfsm_getfh(nd, &tnfhp); if (error) - return (error); + goto nfsmout; tfhsize = tnfhp->nfh_len; if (compare) { if (!(*retcmpp) && @@ -1184,7 +1206,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, case NFSATTRBIT_FSLOCATIONS: error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); if (error) - return (error); + goto nfsmout; attrsum += l; if (compare && !(*retcmpp)) { refp = nfsv4root_getreferral(vp, NULL, 0); @@ -1360,8 +1382,10 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, case NFSATTRBIT_OWNER: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); j = fxdr_unsigned(int, *tl); - if (j < 0) - return (NFSERR_BADXDR); + if (j < 0) { + error = NFSERR_BADXDR; + goto nfsmout; + } attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); if (j > NFSV4_SMALLSTR) cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); @@ -1371,7 +1395,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, if (error) { if (j > NFSV4_SMALLSTR) free(cp, M_NFSSTRING); - return (error); + goto nfsmout; } if (compare) { if (!(*retcmpp)) { @@ -1391,8 +1415,10 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, case NFSATTRBIT_OWNERGROUP: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); j = fxdr_unsigned(int, *tl); - if (j < 0) - return (NFSERR_BADXDR); + if (j < 0) { + error = NFSERR_BADXDR; + goto nfsmout; + } attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); if (j > NFSV4_SMALLSTR) cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); @@ -1402,7 +1428,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, if (error) { if (j > NFSV4_SMALLSTR) free(cp, M_NFSSTRING); - return (error); + goto nfsmout; } if (compare) { if (!(*retcmpp)) { @@ -1708,6 +1734,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, error = nfsm_advance(nd, attrsize - attrsum, -1); } nfsmout: + NFSEXITCODE2(error, nd); return (error); } @@ -1904,8 +1931,10 @@ nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) siz -= xfer; if (siz > 0) { mp = mbuf_next(mp); - if (mp == NULL) - return (EBADRPC); + if (mp == NULL) { + error = EBADRPC; + goto out; + } cp = NFSMTOD(mp, caddr_t); len = mbuf_len(mp); } else { @@ -1922,6 +1951,9 @@ nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) else nd->nd_dpos += rem; } + +out: + NFSEXITCODE2(error, nd); return (error); } @@ -1995,12 +2027,12 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, supports_nfsv4acls == 0)) { NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); } else if (naclp != NULL) { - if (vn_lock(vp, LK_SHARED) == 0) { + if (NFSVOPLOCK(vp, LK_SHARED) == 0) { error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); if (error == 0) error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp, cred, p); - VOP_UNLOCK(vp, 0); + NFSVOPUNLOCK(vp, 0); } else error = NFSERR_PERM; if (error != 0) { @@ -2568,9 +2600,12 @@ nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p) u_char *cp; struct nfsusrgrp *usrp; int cnt, ret; + int error = 0; - if (len == 0) - return (NFSERR_BADOWNER); + if (len == 0) { + error = NFSERR_BADOWNER; + goto out; + } /* * Look for an '@'. */ @@ -2601,7 +2636,8 @@ tryagain: if (len == 6 && !NFSBCMP(str, "nobody", 6)) { *uidp = nfsrv_defaultuid; NFSUNLOCKNAMEID(); - return (0); + error = 0; + goto out; } LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { @@ -2613,7 +2649,8 @@ tryagain: TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); NFSUNLOCKNAMEID(); - return (0); + error = 0; + goto out; } } NFSUNLOCKNAMEID(); @@ -2622,7 +2659,11 @@ tryagain: str, p); if (ret == 0 && cnt < 2) goto tryagain; - return (NFSERR_BADOWNER); + error = NFSERR_BADOWNER; + +out: + NFSEXITCODE(error); + return (error); } /* @@ -2748,9 +2789,12 @@ nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p) u_char *cp; struct nfsusrgrp *usrp; int cnt, ret; + int error = 0; - if (len == 0) - return (NFSERR_BADOWNER); + if (len == 0) { + error = NFSERR_BADOWNER; + goto out; + } /* * Look for an '@'. */ @@ -2779,7 +2823,8 @@ tryagain: if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { *gidp = nfsrv_defaultgid; NFSUNLOCKNAMEID(); - return (0); + error = 0; + goto out; } LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { @@ -2791,7 +2836,8 @@ tryagain: TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); NFSUNLOCKNAMEID(); - return (0); + error = 0; + goto out; } } NFSUNLOCKNAMEID(); @@ -2800,7 +2846,11 @@ tryagain: str, p); if (ret == 0 && cnt < 2) goto tryagain; - return (NFSERR_BADOWNER); + error = NFSERR_BADOWNER; + +out: + NFSEXITCODE(error); + return (error); } /* @@ -2845,7 +2895,8 @@ nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) NFSLOCKNAMEID(); if (nfsrv_nfsuserd) { NFSUNLOCKNAMEID(); - return (EPERM); + error = EPERM; + goto out; } nfsrv_nfsuserd = 1; NFSUNLOCKNAMEID(); @@ -2871,6 +2922,8 @@ nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) NFSSOCKADDRFREE(rp->nr_nam); nfsrv_nfsuserd = 0; } +out: + NFSEXITCODE(error); return (error); } @@ -2910,7 +2963,8 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) NFSLOCKNAMEID(); if (nfsrv_nfsuserd == 0) { NFSUNLOCKNAMEID(); - return (EPERM); + error = EPERM; + goto out; } NFSUNLOCKNAMEID(); nd = &nfsd; @@ -2936,6 +2990,8 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) mbuf_freem(nd->nd_mrep); error = nd->nd_repstat; } +out: + NFSEXITCODE(error); return (error); } @@ -2992,7 +3048,7 @@ nfssvc_idname(struct nfsd_idargs *nidp) NFSUNLOCKNAMEID(); if (error) free(cp, M_NFSSTRING); - return (error); + goto out; } /* @@ -3005,7 +3061,7 @@ nfssvc_idname(struct nfsd_idargs *nidp) nidp->nid_namelen); if (error) { free((caddr_t)newusrp, M_NFSUSERGROUP); - return (error); + goto out; } newusrp->lug_namelen = nidp->nid_namelen; @@ -3080,6 +3136,8 @@ nfssvc_idname(struct nfsd_idargs *nidp) } else FREE((caddr_t)newusrp, M_NFSUSERGROUP); NFSUNLOCKNAMEID(); +out: + NFSEXITCODE(error); return (error); } @@ -3109,6 +3167,7 @@ nfsrv_checkutf8(u_int8_t *cp, int len) int cnt = 0, gotd = 0, shift = 0; u_int8_t byte; static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; + int error = 0; /* * Here are what the variables are used for: @@ -3125,14 +3184,18 @@ nfsrv_checkutf8(u_int8_t *cp, int len) if (cnt > 0) { /* This handles the 10xxxxxx bytes */ if ((*cp & 0xc0) != 0x80 || - (gotd && (*cp & 0x20))) - return (NFSERR_INVAL); + (gotd && (*cp & 0x20))) { + error = NFSERR_INVAL; + goto out; + } gotd = 0; val <<= 6; val |= (*cp & 0x3f); cnt--; - if (cnt == 0 && (val >> shift) == 0x0) - return (NFSERR_INVAL); + if (cnt == 0 && (val >> shift) == 0x0) { + error = NFSERR_INVAL; + goto out; + } } else if (*cp & 0x80) { /* first byte of multi byte char */ byte = *cp; @@ -3140,8 +3203,10 @@ nfsrv_checkutf8(u_int8_t *cp, int len) cnt++; byte <<= 1; } - if (cnt == 0 || cnt == 6) - return (NFSERR_INVAL); + if (cnt == 0 || cnt == 6) { + error = NFSERR_INVAL; + goto out; + } val = (*cp & (0x3f >> cnt)); shift = utf8_shift[cnt - 1]; if (cnt == 2 && val == 0xd) @@ -3152,8 +3217,11 @@ nfsrv_checkutf8(u_int8_t *cp, int len) len--; } if (cnt > 0) - return (NFSERR_INVAL); - return (0); + error = NFSERR_INVAL; + +out: + NFSEXITCODE(error); + return (error); } /* @@ -3174,7 +3242,7 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, { u_int32_t *tl; u_char *cp = NULL, *cp2 = NULL, *cp3, *str; - int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv; + int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; struct list { SLIST_ENTRY(list) next; int len; @@ -3192,15 +3260,20 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, */ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); - if (len < 0 || len > 10240) - return (NFSERR_BADXDR); + if (len < 0 || len > 10240) { + error = NFSERR_BADXDR; + goto nfsmout; + } if (len == 0) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); - if (*tl != 0) - return (NFSERR_BADXDR); + if (*tl != 0) { + error = NFSERR_BADXDR; + goto nfsmout; + } *nilp = 1; *sump = 2 * NFSX_UNSIGNED; - return (0); + error = 0; + goto nfsmout; } cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); error = nfsrv_mtostr(nd, cp, len); @@ -3210,10 +3283,8 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, if (cnt <= 0) error = NFSERR_BADXDR; } - if (error) { - free(cp, M_NFSSTRING); - return (error); - } + if (error) + goto nfsmout; /* * Now, loop through the location list and make up the srvlist. @@ -3227,9 +3298,8 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nsrv = fxdr_unsigned(int, *tl); if (nsrv <= 0) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (NFSERR_BADXDR); + error = NFSERR_BADXDR; + goto nfsmout; } /* @@ -3238,9 +3308,8 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len <= 0 || len > 1024) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (NFSERR_BADXDR); + error = NFSERR_BADXDR; + goto nfsmout; } nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); if (cp3 != cp2) { @@ -3248,11 +3317,8 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, siz++; } error = nfsrv_mtostr(nd, cp3, len); - if (error) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (error); - } + if (error) + goto nfsmout; cp3 += len; *cp3++ = ':'; siz += (len + 1); @@ -3264,18 +3330,14 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len <= 0 || len > 1024) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (NFSERR_BADXDR); + error = NFSERR_BADXDR; + goto nfsmout; } lsp = (struct list *)malloc(sizeof (struct list) + len, M_TEMP, M_WAITOK); error = nfsrv_mtostr(nd, lsp->host, len); - if (error) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (error); - } + if (error) + goto nfsmout; xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); lsp->len = len; SLIST_INSERT_HEAD(&head, lsp, next); @@ -3287,17 +3349,13 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len <= 0 || len > 1024) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (NFSERR_BADXDR); + error = NFSERR_BADXDR; + goto nfsmout; } nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); error = nfsrv_mtostr(nd, cp3, len); - if (error) { - free(cp, M_NFSSTRING); - free(cp2, M_NFSSTRING); - return (error); - } + if (error) + goto nfsmout; xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); str = cp3; stringlen = len; @@ -3320,12 +3378,14 @@ nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, *fsrootp = cp; *srvp = cp2; *sump = xdrsum; + NFSEXITCODE2(0, nd); return (0); nfsmout: if (cp != NULL) free(cp, M_NFSSTRING); if (cp2 != NULL) free(cp2, M_NFSSTRING); + NFSEXITCODE2(error, nd); return (error); } diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 5f944b5..f095641 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -325,6 +325,8 @@ struct ucred *newnfs_getcred(void); void newnfs_setroot(struct ucred *); int nfs_catnap(int, int, const char *); struct nfsreferral *nfsv4root_getreferral(vnode_t, vnode_t, u_int32_t); +int nfsvno_pathconf(vnode_t, int, register_t *, struct ucred *, + NFSPROC_T *); int nfsrv_atroot(vnode_t, long *); void newnfs_timer(void *); int nfs_supportsnfsv4acls(vnode_t); @@ -438,6 +440,7 @@ int nfscl_getcl(vnode_t, struct ucred *, NFSPROC_T *, struct nfsclclient *nfscl_findcl(struct nfsmount *); void nfscl_clientrelease(struct nfsclclient *); void nfscl_freelock(struct nfscllock *, int); +void nfscl_freelockowner(struct nfscllockowner *, int); int nfscl_getbytelock(vnode_t, u_int64_t, u_int64_t, short, struct ucred *, NFSPROC_T *, struct nfsclclient *, int, void *, int, u_int8_t *, u_int8_t *, struct nfscllockowner **, int *, int *); @@ -568,8 +571,6 @@ int nfsvno_checkexp(mount_t, NFSSOCKADDR_T, struct nfsexstuff *, struct ucred **); int nfsvno_fhtovp(mount_t, fhandle_t *, NFSSOCKADDR_T, int, vnode_t *, struct nfsexstuff *, struct ucred **); -int nfsvno_pathconf(vnode_t, int, register_t *, struct ucred *, - NFSPROC_T *); vnode_t nfsvno_getvp(fhandle_t *); int nfsvno_advlock(vnode_t, int, u_int64_t, u_int64_t, NFSPROC_T *); int nfsrv_v4rootexport(void *, struct ucred *, NFSPROC_T *); diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h index a3f05db..529ada2 100644 --- a/sys/fs/nfs/nfsdport.h +++ b/sys/fs/nfs/nfsdport.h @@ -57,6 +57,22 @@ struct nfsexstuff { int nes_secflavors[MAXSECFLAVORS]; /* and the flavors */ }; +/* + * These are NO-OPS for BSD until Isilon upstreams EXITCODE support. + * EXITCODE is an in-memory ring buffer that holds the routines failing status. + * This is a valuable tool to use when debugging and analyzing issues. + * In addition to recording a routine's failing status, it offers + * logging of routines for call stack tracing. + * EXITCODE should be used only in routines that return a true errno value, as + * that value will be formatted to a displayable errno string. Routines that + * return regular int status that are not true errno should not set EXITCODE. + * If you want to log routine tracing, you can add EXITCODE(0) to any routine. + * NFS extended the EXITCODE with EXITCODE2 to record either the routine's + * exit errno status or the nd_repstat. + */ +#define NFSEXITCODE(error) +#define NFSEXITCODE2(error, nd) + #define NFSVNO_EXINIT(e) ((e)->nes_exflag = 0) #define NFSVNO_EXPORTED(e) ((e)->nes_exflag & MNT_EXPORTED) #define NFSVNO_EXRDONLY(e) ((e)->nes_exflag & MNT_EXRDONLY) diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index c21482d..726d3b5 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -267,6 +267,7 @@ * NFS_V3NPROCS is one greater than the last V3 op and NFS_NPROCS is * one greater than the last number. */ +#ifndef NFS_V3NPROCS #define NFS_V3NPROCS 22 #define NFSPROC_LOOKUPP 22 @@ -293,6 +294,7 @@ * Must be defined as one higher than the last Proc# above. */ #define NFSV4_NPROCS 41 +#endif /* NFS_V3NPROCS */ /* * Stats structure @@ -358,7 +360,9 @@ struct ext_nfsstats { /* * Define NFS_NPROCS as NFSV4_NPROCS for the experimental kernel code. */ +#ifndef NFS_NPROCS #define NFS_NPROCS NFSV4_NPROCS +#endif #include <fs/nfs/nfskpiport.h> #include <fs/nfs/nfsdport.h> @@ -832,10 +836,13 @@ void nfsd_mntinit(void); /* * Define these for vnode lock/unlock ops. + * + * These are good abstractions to macro out, so that they can be added to + * later, for debugging or stats, etc. */ -#define NFSVOPLOCK(v, f, p) vn_lock((v), (f)) -#define NFSVOPUNLOCK(v, f, p) VOP_UNLOCK((v), (f)) -#define NFSVOPISLOCKED(v, p) VOP_ISLOCKED((v)) +#define NFSVOPLOCK(v, f) vn_lock((v), (f)) +#define NFSVOPUNLOCK(v, f) VOP_UNLOCK((v), (f)) +#define NFSVOPISLOCKED(v) VOP_ISLOCKED((v)) /* * Define ncl_hash(). diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index 6b66c1f..5ae2e3d 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -226,6 +226,48 @@ #define NFSPROC_COMMIT 21 /* + * The lower numbers -> 21 are used by NFSv2 and v3. These define higher + * numbers used by NFSv4. + * NFS_V3NPROCS is one greater than the last V3 op and NFS_NPROCS is + * one greater than the last number. + */ +#ifndef NFS_V3NPROCS +#define NFS_V3NPROCS 22 + +#define NFSPROC_LOOKUPP 22 +#define NFSPROC_SETCLIENTID 23 +#define NFSPROC_SETCLIENTIDCFRM 24 +#define NFSPROC_LOCK 25 +#define NFSPROC_LOCKU 26 +#define NFSPROC_OPEN 27 +#define NFSPROC_CLOSE 28 +#define NFSPROC_OPENCONFIRM 29 +#define NFSPROC_LOCKT 30 +#define NFSPROC_OPENDOWNGRADE 31 +#define NFSPROC_RENEW 32 +#define NFSPROC_PUTROOTFH 33 +#define NFSPROC_RELEASELCKOWN 34 +#define NFSPROC_DELEGRETURN 35 +#define NFSPROC_RETDELEGREMOVE 36 +#define NFSPROC_RETDELEGRENAME1 37 +#define NFSPROC_RETDELEGRENAME2 38 +#define NFSPROC_GETACL 39 +#define NFSPROC_SETACL 40 + +/* + * Must be defined as one higher than the last Proc# above. + */ +#define NFSV4_NPROCS 41 +#endif /* NFS_V3NPROCS */ + +/* + * Define NFS_NPROCS as NFSV4_NPROCS for the experimental kernel code. + */ +#ifndef NFS_NPROCS +#define NFS_NPROCS NFSV4_NPROCS +#endif + +/* * NFSPROC_NOOP is a fake op# that can't be the same as any V2/3/4 Procedure * or Operation#. Since the NFS V4 Op #s go higher, use NFSV4OP_NOPS, which * is one greater than the highest Op#. @@ -826,15 +868,24 @@ struct nfsv3_sattr { * NFSATTRBIT_WRITEGETATTR0 - bits 0<->31 */ #define NFSATTRBIT_WRITEGETATTR0 \ - (NFSATTRBM_CHANGE | \ + (NFSATTRBM_SUPPORTEDATTRS | \ + NFSATTRBM_TYPE | \ + NFSATTRBM_CHANGE | \ NFSATTRBM_SIZE | \ - NFSATTRBM_FSID) + NFSATTRBM_FSID | \ + NFSATTRBM_FILEID | \ + NFSATTRBM_MAXREAD) /* * NFSATTRBIT_WRITEGETATTR1 - bits 32<->63 */ #define NFSATTRBIT_WRITEGETATTR1 \ - (NFSATTRBM_TIMEMETADATA | \ + (NFSATTRBM_MODE | \ + NFSATTRBM_NUMLINKS | \ + NFSATTRBM_RAWDEV | \ + NFSATTRBM_SPACEUSED | \ + NFSATTRBM_TIMEACCESS | \ + NFSATTRBM_TIMEMETADATA | \ NFSATTRBM_TIMEMODIFY) /* |