svn commit: r319831 - projects/pnfs-planb-server-stable11/sys/fs/nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Sun Jun 11 20:07:14 UTC 2017
Author: rmacklem
Date: Sun Jun 11 20:07:12 2017
New Revision: 319831
URL: https://svnweb.freebsd.org/changeset/base/319831
Log:
Update some nfs files for the pNFS server.
Modified:
projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdkrpc.c
projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdport.c
Modified: projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdkrpc.c Sun Jun 11 19:31:42 2017 (r319830)
+++ projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdkrpc.c Sun Jun 11 20:07:12 2017 (r319831)
@@ -103,6 +103,7 @@ static int nfs_proc(struct nfsrv_descript *, u_int32_t
extern u_long sb_max_adj;
extern int newnfs_numnfsd;
extern struct proc *nfsd_master_proc;
+extern time_t nfsdev_time;
/*
* NFS server system calls
@@ -493,6 +494,7 @@ nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *
*/
NFSD_LOCK();
if (newnfs_numnfsd == 0) {
+ nfsdev_time = time_second;
p = td->td_proc;
PROC_LOCK(p);
p->p_flag2 |= P2_AST_SU;
@@ -500,6 +502,7 @@ nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *
newnfs_numnfsd++;
NFSD_UNLOCK();
+ nfsrv_createdevids(args, td);
/* An empty string implies AUTH_SYS only. */
if (principal[0] != '\0') {
@@ -553,6 +556,7 @@ nfsrvd_init(int terminating)
if (terminating) {
nfsd_master_proc = NULL;
NFSD_UNLOCK();
+ nfsrv_freealllayoutsanddevids();
nfsrv_freeallbackchannel_xprts();
svcpool_close(nfsrvd_pool);
NFSD_LOCK();
Modified: projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdport.c Sun Jun 11 19:31:42 2017 (r319830)
+++ projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdport.c Sun Jun 11 20:07:12 2017 (r319831)
@@ -35,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include <sys/capsicum.h>
+#include <sys/extattr.h>
/*
* Functions that perform the vfs operations required by the routines in
@@ -63,8 +64,12 @@ extern struct nfslockhashhead *nfslockhash;
extern struct nfssessionhash *nfssessionhash;
extern int nfsrv_sessionhashsize;
extern struct nfsstatsv1 nfsstatsv1;
+extern struct nfslayouthash *nfslayouthash;
+extern int nfsrv_layouthashsize;
+extern struct mtx nfsrv_dslock_mtx;
struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
NFSDLOCKMUTEX;
+NFSSTATESPINLOCK;
struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE];
struct nfsrchash_bucket nfsrcahash_table[NFSRVCACHE_HASHSIZE];
struct mtx nfsrc_udpmtx;
@@ -87,7 +92,31 @@ static int nfs_commit_miss;
extern int nfsrv_issuedelegs;
extern int nfsrv_dolocallocks;
extern int nfsd_enable_stringtouid;
+extern struct nfsdevicehead nfsrv_devidhead;
+static void nfsrv_pnfscreate(struct vnode *, struct vattr *, struct ucred *,
+ NFSPROC_T *);
+static void nfsrv_pnfsremovesetup(struct vnode *, NFSPROC_T *, struct vnode **,
+ fhandle_t *);
+static void nfsrv_pnfsremove(struct vnode *, fhandle_t *, NFSPROC_T *);
+static int nfsrv_proxyds(struct nfsrv_descript *, struct vnode *, off_t, int,
+ struct ucred *, struct thread *, int, struct mbuf **, char *,
+ struct mbuf **, struct nfsvattr *, struct acl *);
+static int nfsrv_dsgetsockmnt(struct vnode *, int, char *, int,
+ NFSPROC_T *, struct vnode **, struct nfsmount **, fhandle_t *, char *);
+static int nfsrv_setextattr(struct vnode *, struct nfsvattr *, NFSPROC_T *);
+static int nfsrv_readdsrpc(fhandle_t *, off_t, int, struct ucred *,
+ NFSPROC_T *, struct nfsmount *, struct mbuf **, struct mbuf **);
+static int nfsrv_writedsrpc(fhandle_t *, off_t, int, struct ucred *,
+ NFSPROC_T *, struct vnode *, struct nfsmount *, struct mbuf **, char *);
+static int nfsrv_setacldsrpc(fhandle_t *, struct ucred *, NFSPROC_T *,
+ struct vnode *, struct nfsmount *, struct acl *);
+static int nfsrv_setattrdsrpc(fhandle_t *, struct ucred *, NFSPROC_T *,
+ struct vnode *, struct nfsmount *, struct nfsvattr *);
+static int nfsrv_getattrdsrpc(fhandle_t *, struct ucred *, NFSPROC_T *,
+ struct vnode *, struct nfsmount *, struct nfsvattr *);
+static int nfsrv_putfhname(fhandle_t *, char *);
+
SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW, 0, "NFS server");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW,
&nfsrv_enable_crossmntpt, 0, "Enable nfsd to cross mount points");
@@ -103,7 +132,36 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW
0, "Debug level for NFS server");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW,
&nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names");
+static int nfsrv_pnfsgetdsattr = 1;
+SYSCTL_INT(_vfs_nfsd, OID_AUTO, pnfsgetdsattr, CTLFLAG_RW,
+ &nfsrv_pnfsgetdsattr, 0, "When set getattr gets DS attributes via RPC");
+/*
+ * nfsrv_dsdirsize can only be increased and only when the nfsd threads are
+ * not running.
+ * The dsN subdirectories for the increased values must have been created
+ * on all DS servers before this increase is done.
+ */
+u_int nfsrv_dsdirsize = 20;
+static int
+sysctl_dsdirsize(SYSCTL_HANDLER_ARGS)
+{
+ int error, newdsdirsize;
+
+ newdsdirsize = nfsrv_dsdirsize;
+ error = sysctl_handle_int(oidp, &newdsdirsize, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (newdsdirsize <= nfsrv_dsdirsize || newdsdirsize > 10000 ||
+ newnfs_numnfsd != 0)
+ return (EINVAL);
+ nfsrv_dsdirsize = newdsdirsize;
+ return (0);
+}
+SYSCTL_PROC(_vfs_nfsd, OID_AUTO, dsdirsize, CTLTYPE_UINT | CTLFLAG_RW, 0,
+ sizeof(nfsrv_dsdirsize), sysctl_dsdirsize, "IU",
+ "Number of dsN subdirs on the DS servers");
+
#define MAX_REORDERED_RPC 16
#define NUM_HEURISTIC 1031
#define NHUSE_INIT 64
@@ -179,10 +237,12 @@ nfsrv_sequential_heuristic(struct uio *uio, struct vno
* Get attributes into nfsvattr structure.
*/
int
-nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred,
- struct thread *p, int vpislocked)
+nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap,
+ struct nfsrv_descript *nd, struct thread *p, int vpislocked,
+ nfsattrbit_t *attrbitp)
{
- int error, lockedit = 0;
+ int error, gotattr, lockedit = 0;
+ struct nfsvattr na;
if (vpislocked == 0) {
/*
@@ -195,10 +255,45 @@ nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap
NFSVOPLOCK(vp, LK_SHARED | LK_RETRY);
}
}
- error = VOP_GETATTR(vp, &nvap->na_vattr, cred);
+
+ /*
+ * Acquire the Change, Size and TimeModify attributes, as required.
+ * This needs to be done for regular files if:
+ * - non-NFSv4 RPCs or
+ * - when attrbitp == NULL or
+ * - an NFSv4 RPC with any of the above attributes in attrbitp.
+ * A return of 0 for nfsrv_proxyds() indicates that it has acquired
+ * these attributes. nfsrv_proxyds() will return an error if the
+ * server is not a pNFS one.
+ */
+ gotattr = 0;
+ if (vp->v_type == VREG && (attrbitp == NULL ||
+ (nd->nd_flag & ND_NFSV4) == 0 ||
+ NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_CHANGE) ||
+ NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) ||
+ NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFY))) {
+ error = nfsrv_proxyds(nd, vp, 0, 0, nd->nd_cred, p,
+ NFSPROC_GETATTR, NULL, NULL, NULL, &na, NULL);
+ if (error == 0)
+ gotattr = 1;
+ }
+
+ error = VOP_GETATTR(vp, &nvap->na_vattr, nd->nd_cred);
if (lockedit != 0)
NFSVOPUNLOCK(vp, 0);
+ /*
+ * If we got the Change, Size and Modify Time from the DS,
+ * replace them.
+ */
+ if (gotattr != 0) {
+ nvap->na_mtime = na.na_mtime;
+ nvap->na_filerev = na.na_filerev;
+ nvap->na_size = na.na_size;
+ }
+ NFSD_DEBUG(4, "nfsvno_getattr: gotattr=%d err=%d chg=%ju\n", gotattr,
+ error, (uintmax_t)na.na_filerev);
+
NFSEXITCODE(error);
return (error);
}
@@ -328,6 +423,17 @@ nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap
int error;
error = VOP_SETATTR(vp, &nvap->na_vattr, cred);
+ if (error == 0 && (nvap->na_vattr.va_uid != (uid_t)VNOVAL ||
+ nvap->na_vattr.va_gid != (gid_t)VNOVAL ||
+ nvap->na_vattr.va_size != VNOVAL ||
+ nvap->na_vattr.va_mode != (mode_t)VNOVAL ||
+ nvap->na_vattr.va_mtime.tv_sec != VNOVAL)) {
+ /* For a pNFS server, set the attributes on the DS file. */
+ error = nfsrv_proxyds(NULL, vp, 0, 0, cred, p, NFSPROC_SETATTR,
+ NULL, NULL, NULL, nvap, NULL);
+ if (error == ENOENT)
+ error = 0;
+ }
NFSEXITCODE(error);
return (error);
}
@@ -640,6 +746,15 @@ nfsvno_read(struct vnode *vp, off_t off, int cnt, stru
struct uio io, *uiop = &io;
struct nfsheur *nh;
+ /*
+ * Attempt to read from a DS file. A return of ENOENT implies
+ * there is no DS file to read.
+ */
+ error = nfsrv_proxyds(NULL, vp, off, cnt, cred, p, NFSPROC_READDS, mpp,
+ NULL, mpendp, NULL, NULL);
+ if (error != ENOENT)
+ return (error);
+
len = left = NFSM_RNDUP(cnt);
m3 = NULL;
/*
@@ -717,7 +832,7 @@ out:
* Write vnode op from an mbuf list.
*/
int
-nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int stable,
+nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int *stable,
struct mbuf *mp, char *cp, struct ucred *cred, struct thread *p)
{
struct iovec *ivp;
@@ -727,6 +842,17 @@ nfsvno_write(struct vnode *vp, off_t off, int retlen,
struct uio io, *uiop = &io;
struct nfsheur *nh;
+ /*
+ * Attempt to write to a DS file. A return of ENOENT implies
+ * there is no DS file to write.
+ */
+ error = nfsrv_proxyds(NULL, vp, off, retlen, cred, p, NFSPROC_WRITEDS,
+ &mp, cp, NULL, NULL, NULL);
+ if (error != ENOENT) {
+ *stable = NFSWRITE_FILESYNC;
+ return (error);
+ }
+
MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
M_WAITOK);
uiop->uio_iov = iv = ivp;
@@ -750,7 +876,7 @@ nfsvno_write(struct vnode *vp, off_t off, int retlen,
}
}
- if (stable == NFSWRITE_UNSTABLE)
+ if (*stable == NFSWRITE_UNSTABLE)
ioflags = IO_NODELOCKED;
else
ioflags = (IO_SYNC | IO_NODELOCKED);
@@ -789,6 +915,16 @@ nfsvno_createsub(struct nfsrv_descript *nd, struct nam
vrele(ndp->ni_startdir);
error = VOP_CREATE(ndp->ni_dvp,
&ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
+ /* For a pNFS server, create the data file on a DS. */
+ if (error == 0 && nvap->na_type == VREG) {
+ /*
+ * Create a data file on a DS for a pNFS server.
+ * This function just returns if not
+ * running a pNFS DS or the creation fails.
+ */
+ nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr,
+ nd->nd_cred, p);
+ }
vput(ndp->ni_dvp);
nfsvno_relpathbuf(ndp);
if (!error) {
@@ -1055,16 +1191,25 @@ int
nfsvno_removesub(struct nameidata *ndp, int is_v4, struct ucred *cred,
struct thread *p, struct nfsexstuff *exp)
{
- struct vnode *vp;
+ struct vnode *vp, *dsdvp;
+ fhandle_t fh;
int error = 0;
vp = ndp->ni_vp;
+ dsdvp = NULL;
if (vp->v_type == VDIR)
error = NFSERR_ISDIR;
else if (is_v4)
error = nfsrv_checkremove(vp, 1, p);
+ if (error == 0)
+ nfsrv_pnfsremovesetup(vp, p, &dsdvp, &fh);
if (!error)
error = VOP_REMOVE(ndp->ni_dvp, vp, &ndp->ni_cnd);
+ if (dsdvp != NULL) {
+ if (error == 0)
+ nfsrv_pnfsremove(dsdvp, &fh, p);
+ NFSVOPUNLOCK(dsdvp, 0);
+ }
if (ndp->ni_dvp == vp)
vrele(ndp->ni_dvp);
else
@@ -1124,9 +1269,11 @@ int
nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
u_int32_t ndstat, u_int32_t ndflag, struct ucred *cred, struct thread *p)
{
- struct vnode *fvp, *tvp, *tdvp;
+ struct vnode *fvp, *tvp, *tdvp, *dsdvp;
+ fhandle_t fh;
int error = 0;
+ dsdvp = NULL;
fvp = fromndp->ni_vp;
if (ndstat) {
vrele(fromndp->ni_dvp);
@@ -1201,6 +1348,11 @@ nfsvno_rename(struct nameidata *fromndp, struct nameid
*/
nfsd_recalldelegation(fvp, p);
}
+ if (error == 0 && tvp != NULL) {
+ nfsrv_pnfsremovesetup(tvp, p, &dsdvp, &fh);
+ NFSD_DEBUG(4, "nfsvno_rename: pnfsremovesetup"
+ " dsdvp=%p\n", dsdvp);
+ }
out:
if (!error) {
error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
@@ -1218,6 +1370,20 @@ out:
if (error == -1)
error = 0;
}
+
+ /*
+ * If dsdvp != NULL, it was set up by nfsrv_pnfsremovesetup() and
+ * if the rename succeeded, the DS file for the tvp needs to be
+ * removed.
+ */
+ if (dsdvp != NULL) {
+ if (error == 0) {
+ nfsrv_pnfsremove(dsdvp, &fh, p);
+ NFSD_DEBUG(4, "nfsvno_rename: pnfsremove\n");
+ }
+ NFSVOPUNLOCK(dsdvp, 0);
+ }
+
vrele(tondp->ni_startdir);
nfsvno_relpathbuf(tondp);
out1:
@@ -1422,6 +1588,16 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidat
vrele(ndp->ni_startdir);
nd->nd_repstat = VOP_CREATE(ndp->ni_dvp,
&ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
+ /* For a pNFS server, create the data file on a DS. */
+ if (nd->nd_repstat == 0) {
+ /*
+ * Create a data file on a DS for a pNFS server.
+ * This function just returns if not
+ * running a pNFS DS or the creation fails.
+ */
+ nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr,
+ cred, p);
+ }
vput(ndp->ni_dvp);
nfsvno_relpathbuf(ndp);
if (!nd->nd_repstat) {
@@ -1505,7 +1681,7 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidat
*/
int
nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *nvap,
- struct ucred *cred, struct thread *p)
+ struct nfsrv_descript *nd, struct thread *p)
{
struct vattr va;
@@ -1516,8 +1692,8 @@ nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *n
if ((vp->v_iflag & VI_DOOMED) != 0)
return (ESTALE);
}
- (void) VOP_SETATTR(vp, &va, cred);
- (void) nfsvno_getattr(vp, nvap, cred, p, 1);
+ (void) VOP_SETATTR(vp, &va, nd->nd_cred);
+ (void) nfsvno_getattr(vp, nvap, nd, p, 1, NULL);
return (0);
}
@@ -1601,8 +1777,8 @@ nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram,
siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
fullsiz = siz;
if (nd->nd_flag & ND_NFSV3) {
- nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred,
- p, 1);
+ nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd, p, 1,
+ NULL);
#if 0
/*
* va_filerev is not sufficient as a cookie verifier,
@@ -1660,7 +1836,7 @@ again:
if (!cookies && !nd->nd_repstat)
nd->nd_repstat = NFSERR_PERM;
if (nd->nd_flag & ND_NFSV3) {
- getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
+ getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
if (!nd->nd_repstat)
nd->nd_repstat = getret;
}
@@ -1875,7 +2051,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdg
NFSZERO_ATTRBIT(&attrbits);
}
fullsiz = siz;
- nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
+ nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
if (!nd->nd_repstat) {
if (off && verf != at.na_filerev) {
/*
@@ -1935,7 +2111,7 @@ again:
if (io.uio_resid)
siz -= io.uio_resid;
- getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
+ getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
if (!cookies && !nd->nd_repstat)
nd->nd_repstat = NFSERR_PERM;
@@ -2158,8 +2334,8 @@ again:
NFSNONZERO_ATTRBIT(&attrbits))) {
r = nfsvno_getfh(nvp, &nfh, p);
if (!r)
- r = nfsvno_getattr(nvp, nvap,
- nd->nd_cred, p, 1);
+ r = nfsvno_getattr(nvp, nvap, nd, p,
+ 1, &attrbits);
if (r == 0 && is_zfs == 1 &&
nfsrv_enable_crossmntpt != 0 &&
(nd->nd_flag & ND_NFSV4) != 0 &&
@@ -3067,8 +3243,10 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap
struct file *fp;
struct nfsd_addsock_args sockarg;
struct nfsd_nfsd_args nfsdarg;
+ struct nfsd_nfsd_oargs onfsdarg;
cap_rights_t rights;
int error;
+ char *cp;
if (uap->flag & NFSSVC_NFSDADDSOCK) {
error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg));
@@ -3095,11 +3273,69 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap
error = EINVAL;
goto out;
}
- error = copyin(uap->argp, (caddr_t)&nfsdarg,
- sizeof (nfsdarg));
+ if ((uap->flag & NFSSVC_NEWSTRUCT) == 0) {
+ error = copyin(uap->argp, &onfsdarg, sizeof(onfsdarg));
+ if (error == 0) {
+ nfsdarg.principal = onfsdarg.principal;
+ nfsdarg.minthreads = onfsdarg.minthreads;
+ nfsdarg.maxthreads = onfsdarg.maxthreads;
+ nfsdarg.version = 1;
+ nfsdarg.addr = NULL;
+ nfsdarg.addrlen = 0;
+ nfsdarg.dnshost = NULL;
+ nfsdarg.dnshostlen = 0;
+ }
+ } else
+ error = copyin(uap->argp, &nfsdarg, sizeof(nfsdarg));
if (error)
goto out;
+ if (nfsdarg.addrlen > 0 && nfsdarg.addrlen < 10000 &&
+ nfsdarg.dnshostlen > 0 && nfsdarg.dnshostlen < 10000 &&
+ nfsdarg.dspathlen > 0 && nfsdarg.dspathlen < 10000 &&
+ nfsdarg.addr != NULL && nfsdarg.dnshost != NULL &&
+ nfsdarg.dspath != NULL) {
+ NFSD_DEBUG(1, "addrlen=%d dspathlen=%d dnslen=%d\n",
+ nfsdarg.addrlen, nfsdarg.dspathlen,
+ nfsdarg.dnshostlen);
+ cp = malloc(nfsdarg.addrlen + 1, M_TEMP, M_WAITOK);
+ error = copyin(nfsdarg.addr, cp, nfsdarg.addrlen);
+ if (error != 0) {
+ free(cp, M_TEMP);
+ goto out;
+ }
+ cp[nfsdarg.addrlen] = '\0'; /* Ensure nul term. */
+ nfsdarg.addr = cp;
+ cp = malloc(nfsdarg.dnshostlen + 1, M_TEMP, M_WAITOK);
+ error = copyin(nfsdarg.dnshost, cp, nfsdarg.dnshostlen);
+ if (error != 0) {
+ free(nfsdarg.addr, M_TEMP);
+ free(cp, M_TEMP);
+ goto out;
+ }
+ cp[nfsdarg.dnshostlen] = '\0'; /* Ensure nul term. */
+ nfsdarg.dnshost = cp;
+ cp = malloc(nfsdarg.dspathlen + 1, M_TEMP, M_WAITOK);
+ error = copyin(nfsdarg.dspath, cp, nfsdarg.dspathlen);
+ if (error != 0) {
+ free(nfsdarg.addr, M_TEMP);
+ free(nfsdarg.dnshost, M_TEMP);
+ free(cp, M_TEMP);
+ goto out;
+ }
+ cp[nfsdarg.dspathlen] = '\0'; /* Ensure nul term. */
+ nfsdarg.dspath = cp;
+ } else {
+ nfsdarg.addr = NULL;
+ nfsdarg.addrlen = 0;
+ nfsdarg.dnshost = NULL;
+ nfsdarg.dnshostlen = 0;
+ nfsdarg.dspath = NULL;
+ nfsdarg.dspathlen = 0;
+ }
error = nfsrvd_nfsd(td, &nfsdarg);
+ free(nfsdarg.addr, M_TEMP);
+ free(nfsdarg.dnshost, M_TEMP);
+ free(nfsdarg.dspath, M_TEMP);
} else {
error = nfssvc_srvcall(td, uap, td->td_ucred);
}
@@ -3318,6 +3554,886 @@ nfsrv_backupstable(void)
}
}
+/*
+ * Create a pNFS data file on a Data Server.
+ */
+static void
+nfsrv_pnfscreate(struct vnode *vp, struct vattr *vap, struct ucred *cred,
+ NFSPROC_T *p)
+{
+ struct vnode *dvp, *nvp;
+ struct nfsdevice *ds;
+ fhandle_t fh;
+ struct nameidata named;
+ char *bufp;
+ u_long *hashp;
+ struct mount *mp;
+ struct nfsnode *np;
+ struct nfsmount *nmp;
+ struct pnfsdsfile *pf;
+ struct pnfsdsattr dsattr;
+ struct vattr va;
+ uid_t vauid;
+ gid_t vagid;
+ u_short vamode;
+ struct ucred *tcred;
+ int error;
+ uint32_t dsdir;
+
+ /* Get a DS server directory in a round-robin order. */
+ NFSDDSLOCK();
+ ds = TAILQ_FIRST(&nfsrv_devidhead);
+ if (ds == NULL) {
+ NFSDDSUNLOCK();
+ NFSD_DEBUG(4, "nfsrv_pnfscreate: no srv\n");
+ return;
+ }
+ /* Put at end of list to implement round-robin usage. */
+ TAILQ_REMOVE(&nfsrv_devidhead, ds, nfsdev_list);
+ TAILQ_INSERT_TAIL(&nfsrv_devidhead, ds, nfsdev_list);
+ dsdir = ds->nfsdev_nextdir;
+ ds->nfsdev_nextdir = (ds->nfsdev_nextdir + 1) % nfsrv_dsdirsize;
+ dvp = ds->nfsdev_dsdir[dsdir];
+ NFSDDSUNLOCK();
+
+ error = nfsvno_getfh(vp, &fh, p);
+ if (error == 0)
+ error = VOP_GETATTR(vp, &va, cred);
+ if (error != 0) {
+ printf("pNFS: pnfscreate getfh+attr=%d\n", error);
+ return;
+ }
+
+ NFSD_DEBUG(4, "nfsrv_pnfscreate: cruid=%d crgid=%d uid=%d gid=%d\n",
+ cred->cr_uid, cred->cr_gid, va.va_uid, va.va_gid);
+ /* Make date file name based on FH. */
+ tcred = newnfs_getcred();
+ NFSNAMEICNDSET(&named.ni_cnd, tcred, CREATE,
+ LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
+ nfsvno_setpathbuf(&named, &bufp, &hashp);
+ named.ni_cnd.cn_lkflags = LK_EXCLUSIVE;
+ named.ni_cnd.cn_thread = p;
+ named.ni_cnd.cn_nameptr = bufp;
+ named.ni_cnd.cn_namelen = nfsrv_putfhname(&fh, bufp);
+
+ /* Create the date file in the DS mount. */
+ error = NFSVOPLOCK(dvp, LK_EXCLUSIVE);
+ if (error == 0) {
+ error = VOP_CREATE(dvp, &nvp, &named.ni_cnd, vap);
+ NFSVOPUNLOCK(dvp, 0);
+ if (error == 0) {
+ /* Set the ownership of the file. */
+ vauid = va.va_uid;
+ vagid = va.va_gid;
+ vamode = va.va_mode;
+ VATTR_NULL(&va);
+ va.va_uid = vauid;
+ va.va_gid = vagid;
+ va.va_mode = vamode;
+ error = VOP_SETATTR(nvp, &va, tcred);
+ NFSD_DEBUG(4, "nfsrv_pnfscreate: setattr-uid=%d\n",
+ error);
+ if (error != 0)
+ vput(nvp);
+ }
+ if (error != 0)
+ printf("pNFS: pnfscreate failed=%d\n", error);
+ } else
+ printf("pNFS: pnfscreate vnlock=%d\n", error);
+ NFSFREECRED(tcred);
+ nfsvno_relpathbuf(&named);
+ if (error == 0) {
+ pf = NULL;
+ np = VTONFS(nvp);
+ nmp = VFSTONFS(nvp->v_mount);
+ if (strcmp(nvp->v_mount->mnt_vfc->vfc_name, "nfs") != 0 ||
+ nmp->nm_nam->sa_len > sizeof(struct sockaddr_in6) ||
+ np->n_fhp->nfh_len != NFSX_MYFH) {
+ printf("Bad DS file: fstype=%s salen=%d fhlen=%d\n",
+ nvp->v_mount->mnt_vfc->vfc_name,
+ nmp->nm_nam->sa_len, np->n_fhp->nfh_len);
+ error = ENOENT;
+ }
+
+ /* Get the attributes of the DS file. */
+ error = VOP_GETATTR(nvp, &va, cred);
+ /* Set extattrs for the DS on the MDS file. */
+ if (error == 0) {
+ dsattr.dsa_filerev = va.va_filerev;
+ dsattr.dsa_size = va.va_size;
+ dsattr.dsa_mtime = va.va_mtime;
+ pf = malloc(sizeof(*pf), M_TEMP, M_WAITOK | M_ZERO);
+ pf->dsf_dir = dsdir;
+ NFSBCOPY(np->n_fhp->nfh_fh, &pf->dsf_fh, NFSX_MYFH);
+ NFSBCOPY(nmp->nm_nam, &pf->dsf_sin,
+ nmp->nm_nam->sa_len);
+ error = vn_start_write(vp, &mp, V_WAIT);
+ } else
+ printf("pNFS: pnfscreate can't get DS attr=%d\n",
+ error);
+ if (error == 0) {
+ error = vn_extattr_set(vp, IO_NODELOCKED,
+ EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile",
+ sizeof(*pf), (char *)pf, p);
+ if (error == 0)
+ error = vn_extattr_set(vp, IO_NODELOCKED,
+ EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr",
+ sizeof(dsattr), (char *)&dsattr, p);
+ vn_finished_write(mp);
+ if (error != 0)
+ printf("pNFS: pnfscreate setextattr=%d\n",
+ error);
+ } else
+ printf("pNFS: pnfscreate startwrite=%d\n", error);
+ vput(nvp);
+ free(pf, M_TEMP);
+ } else
+ printf("pNFS: pnfscreate=%d\n", error);
+}
+
+/*
+ * Get the information needed to remove the pNFS Data Server file from the
+ * Metadata file. Upon success, ddvp is set non-NULL to the locked
+ * DS directory vnode. The caller must unlock *ddvp when done with it.
+ */
+static void
+nfsrv_pnfsremovesetup(struct vnode *vp, NFSPROC_T *p, struct vnode **dvpp,
+ fhandle_t *fhp)
+{
+ struct vnode *dvp;
+ struct nfsmount *nmp;
+ struct vattr va;
+ struct ucred *tcred;
+ char *buf;
+ int buflen, error;
+
+ *dvpp = NULL;
+ /* If not an exported regular file or not a pNFS server, just return. */
+ NFSDDSLOCK();
+ if (vp->v_type != VREG || (vp->v_mount->mnt_flag & MNT_EXPORTED) == 0 ||
+ TAILQ_EMPTY(&nfsrv_devidhead)) {
+ NFSDDSUNLOCK();
+ return;
+ }
+ NFSDDSUNLOCK();
+
+ /* Check to see if this is the last hard link. */
+ tcred = newnfs_getcred();
+ error = VOP_GETATTR(vp, &va, tcred);
+ NFSFREECRED(tcred);
+ if (error != 0) {
+ printf("pNFS: nfsrv_pnfsremovesetup getattr=%d\n", error);
+ return;
+ }
+ if (va.va_nlink > 1)
+ return;
+
+ buflen = 1024;
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+ /* Get the directory vnode for the DS mount and the file handle. */
+ error = nfsrv_dsgetsockmnt(vp, LK_EXCLUSIVE, buf, buflen, p, &dvp,
+ &nmp, NULL, NULL);
+ if (error == 0) {
+ error = nfsvno_getfh(vp, fhp, p);
+ if (error != 0) {
+ NFSVOPUNLOCK(dvp, 0);
+ printf("pNFS: nfsrv_pnfsremovesetup getfh=%d\n", error);
+ }
+ } else
+ printf("pNFS: nfsrv_pnfsremovesetup getsockmnt=%d\n", error);
+ free(buf, M_TEMP);
+ if (error == 0)
+ *dvpp = dvp;
+}
+
+/*
+ * Remove a pNFS data file from a Data Server.
+ * nfsrv_pnfsremovesetup() must have been called before the MDS file was
+ * removed to set up the dvp and fill in the FH.
+ */
+static void
+nfsrv_pnfsremove(struct vnode *dvp, fhandle_t *fhp, NFSPROC_T *p)
+{
+ struct vnode *nvp;
+ struct nameidata named;
+ struct ucred *tcred;
+ char *bufp;
+ u_long *hashp;
+ int error;
+
+ /* Look up the data file and remove it. */
+ tcred = newnfs_getcred();
+ named.ni_cnd.cn_nameiop = DELETE;
+ named.ni_cnd.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
+ named.ni_cnd.cn_cred = tcred;
+ named.ni_cnd.cn_thread = p;
+ named.ni_cnd.cn_flags = ISLASTCN | LOCKPARENT | LOCKLEAF | SAVENAME;
+ nfsvno_setpathbuf(&named, &bufp, &hashp);
+ named.ni_cnd.cn_nameptr = bufp;
+ named.ni_cnd.cn_namelen = nfsrv_putfhname(fhp, bufp);
+ NFSD_DEBUG(4, "nfsrv_pnfsremove: filename=%s\n", bufp);
+ error = VOP_LOOKUP(dvp, &nvp, &named.ni_cnd);
+ NFSD_DEBUG(4, "nfsrv_pnfsremove: aft LOOKUP=%d\n", error);
+ if (error == 0) {
+ error = VOP_REMOVE(dvp, nvp, &named.ni_cnd);
+ vput(nvp);
+ }
+ NFSFREECRED(tcred);
+ nfsvno_relpathbuf(&named);
+ if (error != 0)
+ printf("pNFS: nfsrv_pnfsremove failed=%d\n", error);
+}
+
+/*
+ * Generate a file name based on the file handle and put it in *bufp.
+ * Return the number of bytes generated.
+ */
+static int
+nfsrv_putfhname(fhandle_t *fhp, char *bufp)
+{
+ int i;
+ uint8_t *cp;
+ const uint8_t *hexdigits = "0123456789abcdef";
+
+ cp = (uint8_t *)fhp;
+ for (i = 0; i < sizeof(*fhp); i++) {
+ bufp[2 * i] = hexdigits[(*cp >> 4) & 0xf];
+ bufp[2 * i + 1] = hexdigits[*cp++ & 0xf];
+ }
+ bufp[2 * i] = '\0';
+ return (2 * i);
+}
+
+/*
+ * Update the Metadata file's attributes from the DS file when a Read/Write
+ * layout is returned.
+ * Basically just call nfsrv_proxyds() with procedure == NFSPROC_LAYOUTRETURN
+ * so that it does a nfsrv_getattrdsrpc() and nfsrv_setextattr() on the DS file.
+ */
+int
+nfsrv_updatemdsattr(struct vnode *vp, struct nfsvattr *nap, NFSPROC_T *p)
+{
+ struct ucred *tcred;
+ int error;
+
+ /* Do this as root so that it won't fail with EACCES. */
+ tcred = newnfs_getcred();
+ error = nfsrv_proxyds(NULL, vp, 0, 0, tcred, p, NFSPROC_LAYOUTRETURN,
+ NULL, NULL, NULL, nap, NULL);
+ NFSFREECRED(tcred);
+ return (error);
+}
+
+/*
+ * Set the NFSv4 ACL on the DS file to the same ACL as the MDS file.
+ */
+int
+nfsrv_dssetacl(struct vnode *vp, struct acl *aclp, struct ucred *cred,
+ NFSPROC_T *p)
+{
+ int error;
+
+ error = nfsrv_proxyds(NULL, vp, 0, 0, cred, p, NFSPROC_SETACL,
+ NULL, NULL, NULL, NULL, aclp);
+ return (error);
+}
+
+static int
+nfsrv_proxyds(struct nfsrv_descript *nd, struct vnode *vp, off_t off, int cnt,
+ struct ucred *cred, struct thread *p, int ioproc, struct mbuf **mpp,
+ char *cp, struct mbuf **mpp2, struct nfsvattr *nap, struct acl *aclp)
+{
+ struct nfsmount *nmp;
+ fhandle_t fh;
+ struct vnode *dvp;
+ struct pnfsdsattr dsattr;
+ char *buf;
+ int buflen, error;
+
+ NFSD_DEBUG(4, "in nfsrv_proxyds\n");
+ /*
+ * If not a regular file, not exported or not a pNFS server,
+ * just return ENOENT.
+ */
+ NFSDDSLOCK();
+ if (vp->v_type != VREG || (vp->v_mount->mnt_flag & MNT_EXPORTED) == 0 ||
+ TAILQ_EMPTY(&nfsrv_devidhead)) {
+ NFSDDSUNLOCK();
+ return (ENOENT);
+ }
+ NFSDDSUNLOCK();
+
+ buflen = 1024;
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+ error = 0;
+
+ /*
+ * For Getattr, get the Change attribute (va_filerev) and size (va_size)
+ * from the MetaData file's extended attribute.
+ */
+ if (ioproc == NFSPROC_GETATTR) {
+ error = vn_extattr_get(vp, IO_NODELOCKED,
+ EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr", &buflen, buf,
+ p);
+ if (error == 0 && buflen != sizeof(dsattr))
+ error = ENXIO;
+ if (error == 0) {
+ NFSBCOPY(buf, &dsattr, buflen);
+ nap->na_filerev = dsattr.dsa_filerev;
+ nap->na_size = dsattr.dsa_size;
+ nap->na_mtime = dsattr.dsa_mtime;
+ }
+
+ /*
+ * If nfsrv_pnfsgetdsattr is 0 or nfsrv_checkdsattr() returns
+ * 0, just return now. nfsrv_checkdsattr() returns 0 if there
+ * is no Read/Write layout + either an Open/Write_access or
+ * Write delegation issued to a client for the file.
+ */
+ if (nfsrv_pnfsgetdsattr == 0 || nfsrv_checkdsattr(nd, vp, p) ==
+ 0) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+ }
+
+ if (error == 0) {
+ buflen = 1024;
+ error = nfsrv_dsgetsockmnt(vp, LK_SHARED, buf, buflen, p,
+ &dvp, &nmp, &fh, NULL);
+ if (error != 0)
+ printf("pNFS: proxy getextattr sockaddr=%d\n", error);
+ } else
+ printf("pNFS: nfsrv_dsgetsockmnt=%d\n", error);
+ if (error == 0) {
+ if (ioproc == NFSPROC_READDS)
+ error = nfsrv_readdsrpc(&fh, off, cnt, cred, p, nmp,
+ mpp, mpp2);
+ else if (ioproc == NFSPROC_WRITEDS)
+ error = nfsrv_writedsrpc(&fh, off, cnt, cred, p, vp,
+ nmp, mpp, cp);
+ else if (ioproc == NFSPROC_SETATTR)
+ error = nfsrv_setattrdsrpc(&fh, cred, p, vp, nmp,
+ nap);
+ else if (ioproc == NFSPROC_SETACL)
+ error = nfsrv_setacldsrpc(&fh, cred, p, vp, nmp,
+ aclp);
+ else
+ error = nfsrv_getattrdsrpc(&fh, cred, p, vp, nmp,
+ nap);
+ NFSVOPUNLOCK(dvp, 0);
+ NFSD_DEBUG(4, "nfsrv_proxyds: aft RPC=%d\n", error);
+ } else {
+ /* Return ENOENT for any Extended Attribute error. */
+ error = ENOENT;
+ }
+ free(buf, M_TEMP);
+ NFSD_DEBUG(4, "nfsrv_proxyds: error=%d\n", error);
+ return (error);
+}
+
+/*
+ * Get the DS mount point, fh and directory from the "pnfsd.dsfile" extended
+ * attribute.
+ */
+static int
+nfsrv_dsgetsockmnt(struct vnode *vp, int lktype, char *buf, int buflen,
+ NFSPROC_T *p, struct vnode **dvpp, struct nfsmount **nmpp, fhandle_t *fhp,
+ char *devid)
+{
+ struct vnode *dvp;
+ struct nfsmount *nmp;
+ struct sockaddr *sad;
+ struct nfsdevice *ds;
+ struct pnfsdsfile *pf;
+ uint32_t dsdir;
+ int error;
+
+ if (dvpp != NULL) {
+ *dvpp = NULL;
+ *nmpp = NULL;
+ }
+ error = vn_extattr_get(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM,
+ "pnfsd.dsfile", &buflen, buf, p);
+ if (error == 0 && buflen != sizeof(*pf))
+ error = ENOATTR;
+ if (error == 0) {
+ pf = (struct pnfsdsfile *)buf;
+ sad = (struct sockaddr *)&pf->dsf_sin;
+ dsdir = pf->dsf_dir;
+ if (dsdir >= nfsrv_dsdirsize) {
+ printf("nfsrv_dsgetsockmnt: dsdir=%d\n", dsdir);
+ error = ENOATTR;
+ }
+ }
+ if (error == 0) {
+ /* Use the socket address to find the mount point. */
+ NFSDDSLOCK();
+ TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
+ dvp = ds->nfsdev_dvp;
+ nmp = VFSTONFS(dvp->v_mount);
+ if (nfsaddr2_match(sad, nmp->nm_nam))
+ break;
+ }
+ NFSDDSUNLOCK();
+ if (ds != NULL) {
+ if (dvpp != NULL) {
+ dvp = ds->nfsdev_dsdir[dsdir];
+ if (error == 0)
+ error = vn_lock(dvp, lktype);
+ }
+ if (devid != NULL)
+ NFSBCOPY(ds->nfsdev_deviceid, devid,
+ NFSX_V4DEVICEID);
+ } else
+ error = ENOENT;
+ }
+ if (error == 0) {
+ if (dvpp != NULL) {
+ *dvpp = dvp;
+ *nmpp = nmp;
+ }
+ if (fhp != NULL)
+ NFSBCOPY(&pf->dsf_fh, fhp, NFSX_MYFH);
+ } else
+ NFSD_DEBUG(4, "nfsrv_dsgetsockmnt err=%d\n", error);
+ return (error);
+}
+
+/*
+ * Set the extended attribute for the Change attribute.
+ */
+static int
+nfsrv_setextattr(struct vnode *vp, struct nfsvattr *nap, NFSPROC_T *p)
+{
+ struct pnfsdsattr dsattr;
+ struct mount *mp;
+ int error;
+
+ error = vn_start_write(vp, &mp, V_WAIT);
+ if (error == 0) {
+ dsattr.dsa_filerev = nap->na_filerev;
+ dsattr.dsa_size = nap->na_size;
+ dsattr.dsa_mtime = nap->na_mtime;
+ error = vn_extattr_set(vp, IO_NODELOCKED,
+ EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr",
+ sizeof(dsattr), (char *)&dsattr, p);
+ vn_finished_write(mp);
+ }
+ if (error != 0)
+ printf("pNFS: setextattr=%d\n", error);
+ return (error);
+}
+
+static int
+nfsrv_readdsrpc(fhandle_t *fhp, off_t off, int len, struct ucred *cred,
+ NFSPROC_T *p, struct nfsmount *nmp, struct mbuf **mpp, struct mbuf **mpendp)
+{
+ uint32_t *tl;
+ struct nfsrv_descript nfsd, *nd = &nfsd;
+ nfsv4stateid_t st;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list