summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsclient/nfs_clnode.c
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2009-05-04 15:23:58 +0000
committerrmacklem <rmacklem@FreeBSD.org>2009-05-04 15:23:58 +0000
commite3d34903b6fb9cb09f7e616bde59d97341958fa2 (patch)
tree0246ff14527b554e60f1c9212be00ee8c1128197 /sys/fs/nfsclient/nfs_clnode.c
parentfb2908c8ff440e0985013b83071bd8dfecb11371 (diff)
downloadFreeBSD-src-e3d34903b6fb9cb09f7e616bde59d97341958fa2.zip
FreeBSD-src-e3d34903b6fb9cb09f7e616bde59d97341958fa2.tar.gz
Add the experimental nfs subtree to the kernel, that includes
support for NFSv4 as well as NFSv2 and 3. It lives in 3 subdirs under sys/fs: nfs - functions that are common to the client and server nfsclient - a mutation of sys/nfsclient that call generic functions to do RPCs and handle state. As such, it retains the buffer cache handling characteristics and vnode semantics that are found in sys/nfsclient, for the most part. nfsserver - the server. It includes a DRC designed specifically for NFSv4, that is used instead of the generic DRC in sys/rpc. The build glue will be checked in later, so at this point, it consists of 3 new subdirs that should not affect kernel building. Approved by: kib (mentor)
Diffstat (limited to 'sys/fs/nfsclient/nfs_clnode.c')
-rw-r--r--sys/fs/nfsclient/nfs_clnode.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c
new file mode 100644
index 0000000..188b72b
--- /dev/null
+++ b/sys/fs/nfsclient/nfs_clnode.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from nfs_node.c 8.6 (Berkeley) 5/22/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <vm/uma.h>
+
+#include <fs/nfs/nfsport.h>
+#include <fs/nfsclient/nfsnode.h>
+#include <fs/nfsclient/nfsmount.h>
+#include <fs/nfsclient/nfs.h>
+
+extern struct vop_vector newnfs_vnodeops;
+extern struct buf_ops buf_ops_newnfs;
+MALLOC_DECLARE(M_NEWNFSREQ);
+
+uma_zone_t newnfsnode_zone;
+vop_reclaim_t *ncl_reclaim_p = NULL;
+
+void
+ncl_nhinit(void)
+{
+
+ newnfsnode_zone = uma_zcreate("NCLNODE", sizeof(struct nfsnode), NULL,
+ NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+}
+
+void
+ncl_nhuninit(void)
+{
+ uma_zdestroy(newnfsnode_zone);
+}
+
+/*
+ * ONLY USED FOR THE ROOT DIRECTORY. nfscl_nget() does the rest. If this
+ * function is going to be used to get Regular Files, code must be added
+ * to fill in the "struct nfsv4node".
+ * Look up a vnode/nfsnode by file handle.
+ * Callers must check for mount points!!
+ * In all cases, a pointer to a
+ * nfsnode structure is returned.
+ */
+int
+ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp)
+{
+ struct thread *td = curthread; /* XXX */
+ struct nfsnode *np;
+ struct vnode *vp;
+ struct vnode *nvp;
+ int error;
+ u_int hash;
+ struct nfsmount *nmp;
+ struct nfsfh *nfhp;
+
+ nmp = VFSTONFS(mntp);
+ *npp = NULL;
+
+ hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT);
+
+ MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
+ M_NFSFH, M_WAITOK);
+ bcopy(fhp, &nfhp->nfh_fh[0], fhsize);
+ nfhp->nfh_len = fhsize;
+ error = vfs_hash_get(mntp, hash, LK_EXCLUSIVE,
+ td, &nvp, newnfs_vncmpf, nfhp);
+ FREE(nfhp, M_NFSFH);
+ if (error)
+ return (error);
+ if (nvp != NULL) {
+ *npp = VTONFS(nvp);
+ return (0);
+ }
+
+ /*
+ * Allocate before getnewvnode since doing so afterward
+ * might cause a bogus v_data pointer to get dereferenced
+ * elsewhere if zalloc should block.
+ */
+ np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
+
+ error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
+ if (error) {
+ uma_zfree(newnfsnode_zone, np);
+ return (error);
+ }
+ vp = nvp;
+ vp->v_bufobj.bo_ops = &buf_ops_newnfs;
+ vp->v_data = np;
+ np->n_vnode = vp;
+ /*
+ * Initialize the mutex even if the vnode is going to be a loser.
+ * This simplifies the logic in reclaim, which can then unconditionally
+ * destroy the mutex (in the case of the loser, or if hash_insert
+ * happened to return an error no special casing is needed).
+ */
+ mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK);
+ /*
+ * NFS supports recursive and shared locking.
+ */
+ VN_LOCK_AREC(vp);
+ VN_LOCK_ASHARE(vp);
+ /*
+ * Are we getting the root? If so, make sure the vnode flags
+ * are correct
+ */
+ if ((fhsize == nmp->nm_fhsize) &&
+ !bcmp(fhp, nmp->nm_fh, fhsize)) {
+ if (vp->v_type == VNON)
+ vp->v_type = VDIR;
+ vp->v_vflag |= VV_ROOT;
+ }
+
+ MALLOC(np->n_fhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
+ M_NFSFH, M_WAITOK);
+ bcopy(fhp, np->n_fhp->nfh_fh, fhsize);
+ np->n_fhp->nfh_len = fhsize;
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
+ error = insmntque(vp, mntp);
+ if (error != 0) {
+ *npp = NULL;
+ FREE((caddr_t)np->n_fhp, M_NFSFH);
+ mtx_destroy(&np->n_mtx);
+ uma_zfree(newnfsnode_zone, np);
+ return (error);
+ }
+ error = vfs_hash_insert(vp, hash, LK_EXCLUSIVE,
+ td, &nvp, newnfs_vncmpf, np->n_fhp);
+ if (error)
+ return (error);
+ if (nvp != NULL) {
+ *npp = VTONFS(nvp);
+ /* vfs_hash_insert() vput()'s the losing vnode */
+ return (0);
+ }
+ *npp = np;
+
+ return (0);
+}
+
+int
+ncl_inactive(struct vop_inactive_args *ap)
+{
+ struct nfsnode *np;
+ struct sillyrename *sp;
+ struct thread *td = curthread; /* XXX */
+
+ np = VTONFS(ap->a_vp);
+ if (prtactive && vrefcnt(ap->a_vp) != 0)
+ vprint("ncl_inactive: pushing active", ap->a_vp);
+ if (ap->a_vp->v_type != VDIR) {
+ sp = np->n_sillyrename;
+ np->n_sillyrename = NULL;
+ } else
+ sp = NULL;
+ if (sp) {
+ (void)ncl_vinvalbuf(ap->a_vp, 0, td, 1);
+ /*
+ * Remove the silly file that was rename'd earlier
+ */
+ ncl_removeit(sp, ap->a_vp);
+ crfree(sp->s_cred);
+ vrele(sp->s_dvp);
+ FREE((caddr_t)sp, M_NEWNFSREQ);
+ }
+ np->n_flag &= NMODIFIED;
+ return (0);
+}
+
+/*
+ * Reclaim an nfsnode so that it can be used for other purposes.
+ */
+int
+ncl_reclaim(struct vop_reclaim_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct nfsnode *np = VTONFS(vp);
+ struct nfsdmap *dp, *dp2;
+
+ if (prtactive && vrefcnt(vp) != 0)
+ vprint("ncl_reclaim: pushing active", vp);
+
+ /*
+ * If the NLM is running, give it a chance to abort pending
+ * locks.
+ */
+ if (ncl_reclaim_p)
+ ncl_reclaim_p(ap);
+
+ /*
+ * Destroy the vm object and flush associated pages.
+ */
+ vnode_destroy_vobject(vp);
+
+ vfs_hash_remove(vp);
+
+ /*
+ * Call nfscl_reclaimnode() to save attributes in the delegation,
+ * as required.
+ */
+ if (vp->v_type == VREG)
+ nfscl_reclaimnode(vp);
+
+ /*
+ * Free up any directory cookie structures and
+ * large file handle structures that might be associated with
+ * this nfs node.
+ */
+ if (vp->v_type == VDIR) {
+ dp = LIST_FIRST(&np->n_cookies);
+ while (dp) {
+ dp2 = dp;
+ dp = LIST_NEXT(dp, ndm_list);
+ FREE((caddr_t)dp2, M_NFSDIROFF);
+ }
+ }
+ FREE((caddr_t)np->n_fhp, M_NFSFH);
+ if (np->n_v4 != NULL)
+ FREE((caddr_t)np->n_v4, M_NFSV4NODE);
+ mtx_destroy(&np->n_mtx);
+ uma_zfree(newnfsnode_zone, vp->v_data);
+ vp->v_data = NULL;
+ return (0);
+}
+
+/*
+ * Invalidate both the access and attribute caches for this vnode.
+ */
+void
+ncl_invalcaches(struct vnode *vp)
+{
+ struct nfsnode *np = VTONFS(vp);
+ int i;
+
+ mtx_lock(&np->n_mtx);
+ for (i = 0; i < NFS_ACCESSCACHESIZE; i++)
+ np->n_accesscache[i].stamp = 0;
+ np->n_attrstamp = 0;
+ mtx_unlock(&np->n_mtx);
+}
+
OpenPOWER on IntegriCloud