summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsclient/nfs_clvfsops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clvfsops.c')
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c100
1 files changed, 84 insertions, 16 deletions
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index 41a6b78..00dbf90 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -80,6 +80,8 @@ extern int nfscl_ticks;
extern struct timeval nfsboottime;
extern struct nfsstats newnfsstats;
extern int nfsrv_useacl;
+extern int nfscl_debuglevel;
+NFSCLSTATEMUTEX;
MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
@@ -104,7 +106,7 @@ static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
static int mountnfs(struct nfs_args *, struct mount *,
struct sockaddr *, char *, u_char *, int, u_char *, int,
u_char *, int, struct vnode **, struct ucred *,
- struct thread *, int, int);
+ struct thread *, int, int, int);
static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
struct sockaddr_storage *, int *, off_t *,
struct timeval *);
@@ -296,9 +298,11 @@ nfs_statfs(struct mount *mp, struct statfs *sbp)
if (!error)
error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
&attrflag, NULL);
+ if (error != 0)
+ NFSCL_DEBUG(2, "statfs=%d\n", error);
if (attrflag == 0) {
ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
- td->td_ucred, td, &nfsva, NULL);
+ td->td_ucred, td, &nfsva, NULL, NULL);
if (ret) {
/*
* Just set default values to get things going.
@@ -521,7 +525,7 @@ nfs_mountdiskless(char *path,
nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
- NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
+ NFS_DEFAULT_NEGNAMETIMEO, 0)) != 0) {
printf("nfs_mountroot: mount %s on /: %d\n", path, error);
return (error);
}
@@ -715,8 +719,8 @@ static const char *nfs_opts[] = { "from", "nfs_args",
"readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
"retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
"readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
- "principal", "nfsv4", "gssname", "allgssname", "dirpath",
- "nametimeo", "negnametimeo", "nocto", "wcommitsize",
+ "principal", "nfsv4", "gssname", "allgssname", "dirpath", "minorversion",
+ "nametimeo", "negnametimeo", "nocto", "pnfs", "wcommitsize",
NULL };
/*
@@ -763,6 +767,7 @@ nfs_mount(struct mount *mp)
char *opt, *name, *secname;
int nametimeo = NFS_DEFAULT_NAMETIMEO;
int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
+ int minvers = 0;
int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen;
size_t hstlen;
@@ -836,6 +841,8 @@ nfs_mount(struct mount *mp)
args.flags |= NFSMNT_ALLGSSNAME;
if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
args.flags |= NFSMNT_NOCTO;
+ if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0)
+ args.flags |= NFSMNT_PNFS;
if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
if (opt == NULL) {
vfs_mount_error(mp, "illegal readdirsize");
@@ -988,6 +995,16 @@ nfs_mount(struct mount *mp)
goto out;
}
}
+ if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
+ 0) {
+ ret = sscanf(opt, "%d", &minvers);
+ if (ret != 1 || minvers < 0 || minvers > 1 ||
+ (args.flags & NFSMNT_NFSV4) == 0) {
+ vfs_mount_error(mp, "illegal minorversion: %s", opt);
+ error = EINVAL;
+ goto out;
+ }
+ }
if (vfs_getopt(mp->mnt_optnew, "sec",
(void **) &secname, NULL) == 0)
nfs_sec_name(secname, &args.flags);
@@ -1132,7 +1149,7 @@ nfs_mount(struct mount *mp)
args.fh = nfh;
error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
- nametimeo, negnametimeo);
+ nametimeo, negnametimeo, minvers);
out:
if (!error) {
MNT_ILOCK(mp);
@@ -1176,14 +1193,20 @@ static int
mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
- struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo)
+ struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
+ int minvers)
{
struct nfsmount *nmp;
struct nfsnode *np;
int error, trycnt, ret;
struct nfsvattr nfsva;
+ struct nfsclclient *clp;
+ struct nfsclds *dsp, *tdsp;
+ uint32_t lease;
static u_int64_t clval = 0;
+ NFSCL_DEBUG(3, "in mnt\n");
+ clp = NULL;
if (mp->mnt_flag & MNT_UPDATE) {
nmp = VFSTONFS(mp);
printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
@@ -1259,6 +1282,10 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
else
nmp->nm_wcommitsize = hibufspace / 10;
+ if ((argp->flags & NFSMNT_NFSV4) != 0)
+ nmp->nm_minorvers = minvers;
+ else
+ nmp->nm_minorvers = 0;
nfs_decode_args(mp, nmp, argp, hst, cred, td);
@@ -1306,17 +1333,18 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
goto bad;
+ /* For NFSv4.1, get the clientid now. */
+ if (nmp->nm_minorvers > 0) {
+ NFSCL_DEBUG(3, "at getcl\n");
+ error = nfscl_getcl(mp, cred, td, 0, &clp);
+ NFSCL_DEBUG(3, "aft getcl=%d\n", error);
+ if (error != 0)
+ goto bad;
+ }
- /*
- * A reference count is needed on the nfsnode representing the
- * remote root. If this object is not persistent, then backward
- * traversals of the mount point (i.e. "..") will not work if
- * the nfsnode gets flushed out of the cache. Ufs does not have
- * this problem, because one can identify root inodes by their
- * number == ROOTINO (2).
- */
if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
nmp->nm_dirpathlen > 0) {
+ NFSCL_DEBUG(3, "in dirp\n");
/*
* If the fhsize on the mount point == 0 for V4, the mount
* path needs to be looked up.
@@ -1325,6 +1353,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
do {
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
cred, td);
+ NFSCL_DEBUG(3, "aft dirp=%d\n", error);
if (error)
(void) nfs_catnap(PZERO, error, "nfsgetdirp");
} while (error && --trycnt > 0);
@@ -1333,6 +1362,15 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
goto bad;
}
}
+
+ /*
+ * A reference count is needed on the nfsnode representing the
+ * remote root. If this object is not persistent, then backward
+ * traversals of the mount point (i.e. "..") will not work if
+ * the nfsnode gets flushed out of the cache. Ufs does not have
+ * this problem, because one can identify root inodes by their
+ * number == ROOTINO (2).
+ */
if (nmp->nm_fhsize > 0) {
/*
* Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
@@ -1352,7 +1390,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
* (*vpp)->v_type with the correct value.
*/
ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
- cred, td, &nfsva, NULL);
+ cred, td, &nfsva, NULL, &lease);
if (ret) {
/*
* Just set default values to get things going.
@@ -1367,8 +1405,25 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
nfsva.na_vattr.va_gen = 1;
nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
nfsva.na_vattr.va_size = 512 * 1024;
+ lease = 60;
}
(void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
+ if (nmp->nm_minorvers > 0) {
+ NFSCL_DEBUG(3, "lease=%d\n", (int)lease);
+ NFSLOCKCLSTATE();
+ clp->nfsc_renew = NFSCL_RENEW(lease);
+ clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
+ clp->nfsc_clientidrev++;
+ if (clp->nfsc_clientidrev == 0)
+ clp->nfsc_clientidrev++;
+ NFSUNLOCKCLSTATE();
+ /*
+ * Mount will succeed, so the renew thread can be
+ * started now.
+ */
+ nfscl_start_renewthread(clp);
+ nfscl_clientrelease(clp);
+ }
if (argp->flags & NFSMNT_NFSV3)
ncl_fsinfo(nmp, *vpp, cred, td);
@@ -1390,10 +1445,20 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
error = EIO;
bad:
+ if (clp != NULL)
+ nfscl_clientrelease(clp);
newnfs_disconnect(&nmp->nm_sockreq);
crfree(nmp->nm_sockreq.nr_cred);
mtx_destroy(&nmp->nm_sockreq.nr_mtx);
mtx_destroy(&nmp->nm_mtx);
+ if (nmp->nm_clp != NULL) {
+ NFSLOCKCLSTATE();
+ LIST_REMOVE(nmp->nm_clp, nfsc_list);
+ NFSUNLOCKCLSTATE();
+ free(nmp->nm_clp, M_NFSCLCLIENT);
+ }
+ TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp)
+ nfscl_freenfsclds(dsp);
FREE(nmp, M_NEWNFSMNT);
FREE(nam, M_SONAME);
return (error);
@@ -1408,6 +1473,7 @@ nfs_unmount(struct mount *mp, int mntflags)
struct thread *td;
struct nfsmount *nmp;
int error, flags = 0, trycnt = 0;
+ struct nfsclds *dsp, *tdsp;
td = curthread;
@@ -1448,6 +1514,8 @@ nfs_unmount(struct mount *mp, int mntflags)
mtx_destroy(&nmp->nm_sockreq.nr_mtx);
mtx_destroy(&nmp->nm_mtx);
+ TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp)
+ nfscl_freenfsclds(dsp);
FREE(nmp, M_NEWNFSMNT);
out:
return (error);
OpenPOWER on IntegriCloud