From owner-svn-src-projects@freebsd.org Sat Aug 31 16:10:50 2019 Return-Path: Delivered-To: svn-src-projects@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id C03B8D58D0 for ; Sat, 31 Aug 2019 16:10:50 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46LLtL5TSLz4dNQ; Sat, 31 Aug 2019 16:10:50 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9C2241B545; Sat, 31 Aug 2019 16:10:50 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x7VGAo2b097206; Sat, 31 Aug 2019 16:10:50 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x7VGAmb9097196; Sat, 31 Aug 2019 16:10:48 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201908311610.x7VGAmb9097196@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Sat, 31 Aug 2019 16:10:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r351646 - in projects/nfsv42/sys/fs: nfs nfsclient nfsserver X-SVN-Group: projects X-SVN-Commit-Author: rmacklem X-SVN-Commit-Paths: in projects/nfsv42/sys/fs: nfs nfsclient nfsserver X-SVN-Commit-Revision: 351646 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 31 Aug 2019 16:10:50 -0000 Author: rmacklem Date: Sat Aug 31 16:10:48 2019 New Revision: 351646 URL: https://svnweb.freebsd.org/changeset/base/351646 Log: Add support for the Get extended attribute operation. RFC-8276 defines an optional extension to NFSv4.2 to handle extended attributes. This patch adds the first of the four of these operations. Modified: projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c projects/nfsv42/sys/fs/nfs/nfsport.h projects/nfsv42/sys/fs/nfs/nfsproto.h projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c projects/nfsv42/sys/fs/nfsclient/nfsmount.h projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Modified: projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Sat Aug 31 16:10:48 2019 (r351646) @@ -107,7 +107,7 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD, * non-idempotent Ops. * Define it here, since it is used by both the client and server. */ -struct nfsv4_opflag nfsv4_opflag[NFSV4N_NOPS] = { +struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ Modified: projects/nfsv42/sys/fs/nfs/nfsport.h ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfsport.h Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfs/nfsport.h Sat Aug 31 16:10:48 2019 (r351646) @@ -277,11 +277,6 @@ #define NFSV4OP_WRITESAME 70 #define NFSV4OP_CLONE 71 -/* - * Must be one more than the last NFSv4.2 op#. - */ -#define NFSV42_NOPS 72 - /* and the optional Extended attribute operations (RFC-8276). */ #define NFSV4OP_GETXATTR 72 #define NFSV4OP_SETXATTR 73 @@ -289,9 +284,9 @@ #define NFSV4OP_REMOVEXATTR 75 /* - * Must be one more that the last op#. + * Must be one more than the last NFSv4.2 op#. */ -#define NFSV4N_NOPS 76 +#define NFSV42_NOPS 76 /* Quirky case if the illegal op code */ #define NFSV4OP_OPILLEGAL 10044 Modified: projects/nfsv42/sys/fs/nfs/nfsproto.h ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfsproto.h Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfs/nfsproto.h Sat Aug 31 16:10:48 2019 (r351646) @@ -407,10 +407,10 @@ /* * 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 NFSV4N_NOPS, which + * or Operation#. Since the NFS V4 Op #s go higher, use NFSV42_NOPS, which * is one greater than the highest Op#. */ -#define NFSPROC_NOOP NFSV4N_NOPS +#define NFSPROC_NOOP NFSV42_NOPS /* Actual Version 2 procedure numbers */ #define NFSV2PROC_NULL 0 Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Sat Aug 31 16:10:48 2019 (r351646) @@ -8240,3 +8240,73 @@ nfsmout: return (error); } +/* + * The getextattr RPC. + */ +APPLESTATIC int +nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp, + struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) +{ + uint32_t *tl; + int error; + struct nfsrv_descript nfsd; + struct nfsrv_descript *nd = &nfsd; + nfsattrbit_t attrbits; + uint32_t len, len2; + + *attrflagp = 0; + NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp); + nfsm_strtom(nd, name, strlen(name)); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + nfsrv_putattrbit(nd, &attrbits); + error = nfscl_request(nd, vp, p, cred, NULL); + if (error != 0) + return (error); + if (nd->nd_repstat == 0) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + len = fxdr_unsigned(uint32_t, *tl); + /* Sanity check lengths. */ + if (uiop != NULL && len > 0 && len <= IOSIZE_MAX && + uiop->uio_resid <= UINT32_MAX) { + len2 = uiop->uio_resid; + if (len2 >= len) + error = nfsm_mbufuio(nd, uiop, len); + else { + error = nfsm_mbufuio(nd, uiop, len2); + if (error == 0) { + /* + * nfsm_mbufuio() advances to a multiple + * of 4, so advance len2 as well. Then + * we need to advance over the rest of + * the data. + */ + len2 = NFSM_RNDUP(len2); + len2 = NFSM_RNDUP(len - len2); + if (len2 > 0) + error = nfsm_advance(nd, len2, + -1); + } + } + } else if (uiop == NULL && len > 0) { + /* Just wants the length and not the data. */ + error = nfsm_advance(nd, len, -1); + } else + error = ENOATTR; + if (error != 0) + goto nfsmout; + *lenp = len; + /* Just skip over Getattr op status. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + error = nfsm_loadattr(nd, nap); + if (error == 0) + *attrflagp = 1; + } + if (error == 0) + error = nd->nd_repstat; +nfsmout: + mbuf_freem(nd->nd_mrep); + return (error); +} + Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Sat Aug 31 16:10:48 2019 (r351646) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -147,6 +148,7 @@ static vop_advise_t nfs_advise; static vop_allocate_t nfs_allocate; static vop_copy_file_range_t nfs_copy_file_range; static vop_ioctl_t nfs_ioctl; +static vop_getextattr_t nfs_getextattr; /* * Global vfs data structures for nfs @@ -188,6 +190,7 @@ static struct vop_vector newnfs_vnodeops_nosig = { .vop_allocate = nfs_allocate, .vop_copy_file_range = nfs_copy_file_range, .vop_ioctl = nfs_ioctl, + .vop_getextattr = nfs_getextattr, }; static int @@ -3742,6 +3745,65 @@ nfs_ioctl(struct vop_ioctl_args *ap) if (error != 0) error = ENXIO; + return (error); +} + +/* + * nfs getextattr call + */ +static int +nfs_getextattr(struct vop_getextattr_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct nfsmount *nmp; + struct ucred *cred; + struct thread *td = ap->a_td; + struct nfsvattr nfsva; + ssize_t len; + int attrflag, error, ret; + + nmp = VFSTONFS(vp->v_mount); + mtx_lock(&nmp->nm_mtx); + if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || + (nmp->nm_privflag & NFSMNTP_NOXATTR) != 0 || + ap->a_attrnamespace != EXTATTR_NAMESPACE_USER) { + mtx_unlock(&nmp->nm_mtx); + return (EOPNOTSUPP); + } + mtx_unlock(&nmp->nm_mtx); + + cred = ap->a_cred; + if (cred == NULL) + cred = td->td_ucred; + /* Do the actual NFSv4.2 Optional Extended Attribute (RFC-8276) RPC. */ + attrflag = 0; + error = nfsrpc_getextattr(vp, ap->a_name, ap->a_uio, &len, &nfsva, + &attrflag, cred, td); + if (attrflag != 0) { + ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); + if (error == 0 && ret != 0) + error = ret; + } + if (error == 0 && ap->a_size != NULL) + *ap->a_size = len; + + switch (error) { + case NFSERR_NOTSUPP: + case NFSERR_OPILLEGAL: + case NFSERR_MINORVERMISMATCH: + mtx_lock(&nmp->nm_mtx); + nmp->nm_privflag |= NFSMNTP_NOXATTR; + mtx_unlock(&nmp->nm_mtx); + error = EOPNOTSUPP; + break; + case NFSERR_NOXATTR: + case NFSERR_XATTR2BIG: + error = ENOATTR; + break; + default: + error = nfscl_maperr(td, error, 0, 0); + break; + } return (error); } Modified: projects/nfsv42/sys/fs/nfsclient/nfsmount.h ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfsmount.h Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfsclient/nfsmount.h Sat Aug 31 16:10:48 2019 (r351646) @@ -110,6 +110,7 @@ struct nfsmount { #define NFSMNTP_NOCONSECUTIVE 0x00000010 #define NFSMNTP_SEEK 0x00000020 #define NFSMNTP_SEEKTESTED 0x00000040 +#define NFSMNTP_NOXATTR 0x00000080 #define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1])) #define NFSMNT_SRVKRBNAME(m) \ Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c Sat Aug 31 16:10:48 2019 (r351646) @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); */ #include +#include #include #include #include @@ -5862,6 +5863,86 @@ nfsvno_seek(struct nfsrv_descript *nd, struct vnode *v if (ret != 0 && error == 0) error = ret; } + NFSEXITCODE(error); + return (error); +} + +/* + * Get Extended Atribute vnode op into an mbuf list. + */ +int +nfsvno_getxattr(struct vnode *vp, char *name, struct ucred *cred, + struct thread *p, struct mbuf **mpp, struct mbuf **mpendp, int *lenp) +{ + struct iovec *ivp, *ivp2; + struct uio io, *uiop = &io; + struct mbuf *mp, *mp2 = NULL, *mp3 = NULL; + int alen, error, i, len, maxiov, tlen; + size_t siz; + + maxiov = (NFS_SRVMAXIO + MCLBYTES - 1) / MCLBYTES; + if (maxiov < 1) + maxiov = 1; + ivp2 = ivp = mallocarray(maxiov, sizeof(*ivp), M_TEMP, M_WAITOK); + len = 0; + i = 0; + while (i < maxiov) { + NFSMGET(mp); + MCLGET(mp, M_WAITOK); + mp->m_len = M_SIZE(mp); + if (len == 0) { + mp3 = mp2 = mp; + } else { + mp2->m_next = mp; + mp2 = mp; + } + len += mp->m_len; + ivp->iov_base = mtod(mp, caddr_t); + ivp->iov_len = mp->m_len; + i++; + ivp++; + } + uiop->uio_iov = ivp2; + uiop->uio_iovcnt = i; + uiop->uio_offset = 0; + uiop->uio_resid = len; + uiop->uio_rw = UIO_READ; + uiop->uio_segflg = UIO_SYSSPACE; + uiop->uio_td = p; +#ifdef MAC + error = mac_vnode_check_getextattr(cred, vp, EXTATTR_NAMESPACE_USER, + name); + if (error != 0) + goto out; +#endif + + error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, uiop, NULL, + cred, p); + if (error != 0) + goto out; + if (uiop->uio_resid > 0) { + alen = len; + len -= uiop->uio_resid; + tlen = NFSM_RNDUP(len); + nfsrv_adj(mp3, alen - tlen, tlen - len); + } else { + error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, + &siz, cred, p); + if (error == 0 && len < siz) + error = NFSERR_XATTR2BIG; + } + if (error == 0) { + *lenp = len; + *mpp = mp3; + *mpendp = mp; + } + +out: + if (error != 0) { + m_freem(mp3); + *lenp = 0; + } + free(ivp2, M_TEMP); NFSEXITCODE(error); return (error); } Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Sat Aug 31 16:10:48 2019 (r351646) @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #ifndef APPLEKEXT #include +#include #include /* Global vars */ @@ -5472,6 +5473,60 @@ nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); +} + +/* + * nfs get extended attribute service + */ +APPLESTATIC int +nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, + vnode_t vp, __unused struct nfsexstuff *exp) +{ + uint32_t *tl; + mbuf_t mp = NULL, mpend = NULL; + int error, len; + char *name; + struct thread *p = curthread; + + error = 0; + if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { + nd->nd_repstat = NFSERR_WRONGSEC; + goto nfsmout; + } + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + len = fxdr_unsigned(int, *tl); + if (len <= 0) { + nd->nd_repstat = NFSERR_BADXDR; + goto nfsmout; + } + if (len > EXTATTR_MAXNAMELEN) { + nd->nd_repstat = NFSERR_NOXATTR; + goto nfsmout; + } + name = malloc(len + 1, M_TEMP, M_WAITOK); + nd->nd_repstat = nfsrv_mtostr(nd, name, len); + if (nd->nd_repstat == 0) + nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_cred, p, + &mp, &mpend, &len); + if (nd->nd_repstat == ENOATTR) + nd->nd_repstat = NFSERR_NOXATTR; + else if (nd->nd_repstat == EOPNOTSUPP) + nd->nd_repstat = NFSERR_NOTSUPP; + if (nd->nd_repstat == 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(len); + mbuf_setnext(nd->nd_mb, mp); + nd->nd_mb = mpend; + nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); + } + free(name, M_TEMP); + +nfsmout: + if (nd->nd_repstat == 0) + nd->nd_repstat = error; + vput(vp); + NFSEXITCODE2(0, nd); + return (0); } /* Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Aug 31 15:17:22 2019 (r351645) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Aug 31 16:10:48 2019 (r351646) @@ -209,6 +209,10 @@ int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript nfsrvd_seek, nfsrvd_notsupp, nfsrvd_notsupp, + nfsrvd_getxattr, + nfsrvd_notsupp, + nfsrvd_notsupp, + nfsrvd_notsupp, }; int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *, @@ -285,6 +289,10 @@ int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, }; int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *, @@ -350,6 +358,10 @@ int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, nfsrvd_copy_file_range, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,