diff options
Diffstat (limited to 'sys/fs/nfsclient/nfs_clvfsops.c')
-rw-r--r-- | sys/fs/nfsclient/nfs_clvfsops.c | 100 |
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); |