BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / nfs / nfs_node.c
index 7c28b29..810378e 100644 (file)
@@ -5,36 +5,50 @@
  * This code is derived from software contributed to Berkeley by
  * Rick Macklem at The University of Guelph.
  *
  * 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 are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 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.
  *
  *
- *     @(#)nfs_node.c  7.5 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)nfs_node.c  7.34 (Berkeley) 5/15/91
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "user.h"
 #include "proc.h"
 #include "mount.h"
 #include "proc.h"
 #include "mount.h"
-#include "vnode.h"
-#include "../ufs/dir.h"
 #include "namei.h"
 #include "namei.h"
-#include "errno.h"
+#include "vnode.h"
+#include "kernel.h"
+#include "malloc.h"
+
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsnode.h"
 #include "nfsmount.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "nfsnode.h"
 #include "nfsmount.h"
-#include "kernel.h"
-#include "malloc.h"
 
 /* The request list head */
 extern struct nfsreq nfsreqh;
 
 /* The request list head */
 extern struct nfsreq nfsreqh;
@@ -46,13 +60,11 @@ extern struct nfsreq nfsreqh;
 #define        NFSNOHASH(fhsum)        (((unsigned)(fhsum))%NFSNOHSZ)
 #endif
 
 #define        NFSNOHASH(fhsum)        (((unsigned)(fhsum))%NFSNOHSZ)
 #endif
 
-union nhead {                          /* inode LRU cache, Chris Maltby */
+union nhead {
        union  nhead *nh_head[2];
        struct nfsnode *nh_chain[2];
 } nhead[NFSNOHSZ];
 
        union  nhead *nh_head[2];
        struct nfsnode *nh_chain[2];
 } nhead[NFSNOHSZ];
 
-struct nfsnode *nfreeh, **nfreet;
-
 #define TRUE   1
 #define        FALSE   0
 
 #define TRUE   1
 #define        FALSE   0
 
@@ -63,35 +75,38 @@ struct nfsnode *nfreeh, **nfreet;
 nfs_nhinit()
 {
        register int i;
 nfs_nhinit()
 {
        register int i;
-       register struct nfsnode *np = nfsnode;
        register union  nhead *nh = nhead;
 
        register union  nhead *nh = nhead;
 
+#ifndef lint
+       if (VN_MAXPRIVATE < sizeof(struct nfsnode))
+               panic("nfs_nhinit: too small");
+#endif /* not lint */
        for (i = NFSNOHSZ; --i >= 0; nh++) {
                nh->nh_head[0] = nh;
                nh->nh_head[1] = nh;
        }
        for (i = NFSNOHSZ; --i >= 0; nh++) {
                nh->nh_head[0] = nh;
                nh->nh_head[1] = nh;
        }
-       nfreeh = np;
-       nfreet = &np->n_freef;
-       np->n_freeb = &nfreeh;
-       np->n_forw = np;
-       np->n_back = np;
-       NFSTOV(np)->v_data = (qaddr_t)np;
-       NFSTOV(np)->v_type = VNON;
-       for (i = nnfsnode; --i > 0; ) {
-               ++np;
-               np->n_forw = np;
-               np->n_back = np;
-               NFSTOV(np)->v_data = (qaddr_t)np;
-               NFSTOV(np)->v_type = VNON;
-               *nfreet = np;
-               np->n_freeb = nfreet;
-               nfreet = &np->n_freef;
-       }
-       np->n_freef = NULL;
 }
 
 /*
 }
 
 /*
- * Look up an vnode/nfsnode by file handle.
+ * Compute an entry in the NFS hash table structure
+ */
+union nhead *
+nfs_hash(fhp)
+       register nfsv2fh_t *fhp;
+{
+       register u_char *fhpp;
+       register u_long fhsum;
+       int i;
+
+       fhpp = &fhp->fh_bytes[0];
+       fhsum = 0;
+       for (i = 0; i < NFSX_FH; i++)
+               fhsum += *fhpp++;
+       return (&nhead[NFSNOHASH(fhsum)]);
+}
+
+/*
+ * 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.
  * Callers must check for mount points!!
  * In all cases, a pointer to a
  * nfsnode structure is returned.
@@ -103,251 +118,152 @@ nfs_nget(mntp, fhp, npp)
 {
        register struct nfsnode *np;
        register struct vnode *vp;
 {
        register struct nfsnode *np;
        register struct vnode *vp;
-       register struct nfsnode *nq;
-       register u_char *fhpp;
-       register u_long fhsum;
-       register int i;
-       union  nhead *nh;
+       extern struct vnodeops nfsv2_vnodeops;
+       struct vnode *nvp;
+       union nhead *nh;
        int error;
 
        int error;
 
-       fhpp = &fhp->fh_bytes[0];
-       fhsum = 0;
-       for (i = 0; i < NFSX_FH; i++)
-               fhsum += *fhpp++;
+       nh = nfs_hash(fhp);
 loop:
 loop:
-       nh = &nhead[NFSNOHASH(fhsum)];
        for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
        for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
-               if (mntp == NFSTOV(np)->v_mount &&
-                   !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) {
-                       /*
-                        * Following is essentially an inline expanded
-                        * copy of ngrab(), expanded inline for speed,
-                        * and so that the test for a mounted on nfsnode
-                        * can be deferred until after we are sure that
-                        * the nfsnode isn't busy.
-                        */
-                       if ((np->n_flag & NLOCKED) != 0) {
-                               np->n_flag |= NWANT;
-                               sleep((caddr_t)np, PINOD);
-                               goto loop;
-                       }
-                       vp = NFSTOV(np);
-                       if (vp->v_count == 0) {         /* nfsno on free list */
-                               if (nq = np->n_freef)
-                                       nq->n_freeb = np->n_freeb;
-                               else
-                                       nfreet = np->n_freeb;
-                               *np->n_freeb = nq;
-                               np->n_freef = NULL;
-                               np->n_freeb = NULL;
-                       }
-                       np->n_flag |= NLOCKED;
-                       VREF(vp);
-                       *npp = np;
-                       return(0);
+               if (mntp != NFSTOV(np)->v_mount ||
+                   bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
+                       continue;
+               if ((np->n_flag & NLOCKED) != 0) {
+                       np->n_flag |= NWANT;
+                       (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
+                       goto loop;
                }
                }
-
+               vp = NFSTOV(np);
+               if (vget(vp))
+                       goto loop;
+               *npp = np;
+               return(0);
        }
        }
-       if ((np = nfreeh) == NULL) {
-               tablefull("nfsnode");
+       if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
                *npp = 0;
                *npp = 0;
-               return(ENFILE);
-       }
-       vp = NFSTOV(np);
-       if (vp->v_count)
-               panic("free nfsnode isn't");
-       if (nq = np->n_freef)
-               nq->n_freeb = &nfreeh;
-       nfreeh = nq;
-       np->n_freef = NULL;
-       np->n_freeb = NULL;
-       /*
-        * Now to take nfsnode off the hash chain it was on
-        * (initially, or after an nflush, it is on a "hash chain"
-        * consisting entirely of itself, and pointed to by no-one,
-        * but that doesn't matter)
-        */
-       remque(np);
-       /*
-        * Flush out any associated bio buffers that might be lying about
-        */
-       if (vp->v_type == VREG && (np->n_flag & NBUFFERED)) {
-               np->n_flag |= NLOCKED;
-               nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
+               return (error);
        }
        }
+       vp = nvp;
+       np = VTONFS(vp);
+       np->n_vnode = vp;
        /*
         * Insert the nfsnode in the hash queue for its new file handle
         */
        /*
         * Insert the nfsnode in the hash queue for its new file handle
         */
-       np->n_flag = NLOCKED;
+       np->n_flag = 0;
        insque(np, nh);
        insque(np, nh);
+       nfs_lock(vp);
        bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
        bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
-#ifndef notyet
-       cache_purge(vp);
-#endif
        np->n_attrstamp = 0;
        np->n_attrstamp = 0;
+       np->n_direofoffset = 0;
        np->n_sillyrename = (struct sillyrename *)0;
        np->n_sillyrename = (struct sillyrename *)0;
-       np->n_id = ++nextnfsnodeid;
        np->n_size = 0;
        np->n_mtime = 0;
        np->n_size = 0;
        np->n_mtime = 0;
-       /*
-        * Initialize the associated vnode
-        */
-       vinit(vp, mntp, VNON, &nfsv2_vnodeops);
        *npp = np;
        return (0);
 }
 
        *npp = np;
        return (0);
 }
 
-/*
- * Convert a pointer to an nfsnode into a reference to an nfsnode.
- *
- * This is basically the internal piece of nget (after the
- * nfsnode pointer is located) but without the test for mounted
- * filesystems.  It is caller's responsibility to check that
- * the nfsnode pointer is valid.
- */
-nfs_ngrab(np)
-       register struct nfsnode *np;
-{
-       register struct vnode *vp = NFSTOV(np);
-
-       while ((np->n_flag & NLOCKED) != 0) {
-               np->n_flag |= NWANT;
-               sleep((caddr_t)np, PINOD);
-       }
-       if (vp->v_count == 0) {         /* ino on free list */
-               register struct nfsnode *nq;
-
-               if (nq = np->n_freef)
-                       nq->n_freeb = np->n_freeb;
-               else
-                       nfreet = np->n_freeb;
-               *np->n_freeb = nq;
-               np->n_freef = NULL;
-               np->n_freeb = NULL;
-       }
-       VREF(vp);
-       np->n_flag |= NLOCKED;
-}
-
-nfs_inactive(vp)
+nfs_inactive(vp, p)
        struct vnode *vp;
        struct vnode *vp;
+       struct proc *p;
 {
        register struct nfsnode *np;
 {
        register struct nfsnode *np;
-       register struct nameidata *ndp;
        register struct sillyrename *sp;
        register struct sillyrename *sp;
-       register struct nfsreq *rep;
-       struct nfsreq *rep2;
        struct nfsnode *dnp;
        struct nfsnode *dnp;
-       int s;
+       extern int prtactive;
 
 
-       if (vp == NULL)
-               panic("nfs_inactive NULL vp");
-       if (vp->v_count == 0) {
-               np = VTONFS(vp);
-               nfs_lock(vp);
-               sp = np->n_sillyrename;
-               np->n_sillyrename = (struct sillyrename *)0;
-               if (sp) {
-                       /*
-                        * Remove the silly file that was rename'd earlier
-                        */
-                       ndp = &sp->s_namei;
-                       if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
-                               ndp->ni_dvp = NFSTOV(dnp);
-                               nfs_removeit(ndp);
-                               nfs_nput(ndp->ni_dvp);
-                       }
-                       crfree(ndp->ni_cred);
-                       free((caddr_t)sp, M_TEMP);
-               }
-               nfs_unlock(vp);
-               np->n_flag = 0;
-#ifdef notdef
-               /*
-                * Scan the request list for any requests left hanging about
-                */
-               s = splnet();
-               rep = nfsreqh.r_next;
-               while (rep && rep != &nfsreqh) {
-                       if (rep->r_vp == vp) {
-                               rep->r_prev->r_next = rep2 = rep->r_next;
-                               rep->r_next->r_prev = rep->r_prev;
-                               m_freem(rep->r_mreq);
-                               if (rep->r_mrep != NULL)
-                                       m_freem(rep->r_mrep);
-                               free((caddr_t)rep, M_NFSREQ);
-                               rep = rep2;
-                       } else
-                               rep = rep->r_next;
-               }
-               splx(s);
-#endif
+       np = VTONFS(vp);
+       if (prtactive && vp->v_usecount != 0)
+               vprint("nfs_inactive: pushing active", vp);
+       nfs_lock(vp);
+       sp = np->n_sillyrename;
+       np->n_sillyrename = (struct sillyrename *)0;
+       if (sp) {
                /*
                /*
-                * Put the nfsnode on the end of the free list.
+                * Remove the silly file that was rename'd earlier
                 */
                 */
-               if (nfreeh) {
-                       *nfreet = np;
-                       np->n_freeb = nfreet;
-               } else {
-                       nfreeh = np;
-                       np->n_freeb = &nfreeh;
+               if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
+                       sp->s_dvp = NFSTOV(dnp);
+                       nfs_removeit(sp, p);
+                       nfs_nput(sp->s_dvp);
                }
                }
-               np->n_freef = NULL;
-               nfreet = &np->n_freef;
+               crfree(sp->s_cred);
+               vrele(sp->s_dvp);
+               free((caddr_t)sp, M_NFSREQ);
        }
        }
+       nfs_unlock(vp);
+       np->n_flag &= NMODIFIED;
+#ifdef notdef
+       /*
+        * Scan the request list for any requests left hanging about
+        */
+       s = splnet();
+       rep = nfsreqh.r_next;
+       while (rep && rep != &nfsreqh) {
+               if (rep->r_vp == vp) {
+                       rep->r_prev->r_next = rep2 = rep->r_next;
+                       rep->r_next->r_prev = rep->r_prev;
+                       m_freem(rep->r_mreq);
+                       if (rep->r_mrep != NULL)
+                               m_freem(rep->r_mrep);
+                       free((caddr_t)rep, M_NFSREQ);
+                       rep = rep2;
+               } else
+                       rep = rep->r_next;
+       }
+       splx(s);
+#endif
        return (0);
 }
 
 /*
        return (0);
 }
 
 /*
- * Remove any nfsnodes in the nfsnode cache belonging to mount.
- *
- * There should not be any active ones, return error if any are found
- * (nb: this is a user error, not a system err).
+ * Reclaim an nfsnode so that it can be used for other purposes.
  */
  */
-nfs_nflush(mntp)
-       struct mount *mntp;
-{
-       register struct nfsnode *np;
+nfs_reclaim(vp)
        register struct vnode *vp;
        register struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+       extern int prtactive;
 
 
-       for (np = nfsnode; np < nfsnodeNNFSNODE; np++) {
-               vp = NFSTOV(np);
-               if (vp->v_mount == mntp)
-                       if (vp->v_count)
-                               return (EBUSY);
-                       else {
-                               remque(np);
-                               np->n_forw = np;
-                               np->n_back = np;
-                               /*
-                                * as v_count == 0, the inode was on the free
-                                * list already, just leave it there, it will
-                                * fall off the bottom eventually. We could
-                                * perhaps move it to the head of the free
-                                * list, but as umounts are done so
-                                * infrequently, we would gain very little,
-                                * while making the code bigger.
-                                */
-                       }
-       }
+       if (prtactive && vp->v_usecount != 0)
+               vprint("nfs_reclaim: pushing active", vp);
+       /*
+        * Remove the nfsnode from its hash chain.
+        */
+       remque(np);
+       np->n_forw = np;
+       np->n_back = np;
+       cache_purge(vp);
+       np->n_flag = 0;
+       np->n_direofoffset = 0;
        return (0);
 }
 
        return (0);
 }
 
+/*
+ * In theory, NFS does not need locking, but we make provision
+ * for doing it just in case it is needed.
+ */
+int donfslocking = 0;
 /*
  * Lock an nfsnode
  */
 /*
  * Lock an nfsnode
  */
+
 nfs_lock(vp)
        struct vnode *vp;
 {
        register struct nfsnode *np = VTONFS(vp);
 
 nfs_lock(vp)
        struct vnode *vp;
 {
        register struct nfsnode *np = VTONFS(vp);
 
-       if (np->n_flag & NLOCKED)
-               printf("pid %d hit locked nfsnode=0x%x\n",
-                   u.u_procp->p_pid, np);
+       if (!donfslocking)
+               return;
        while (np->n_flag & NLOCKED) {
                np->n_flag |= NWANT;
        while (np->n_flag & NLOCKED) {
                np->n_flag |= NWANT;
-               sleep((caddr_t)np, PINOD);
+               if (np->n_lockholder == curproc->p_pid)
+                       panic("locking against myself");
+               np->n_lockwaiter = curproc->p_pid;
+               (void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
        }
        }
+       np->n_lockwaiter = 0;
+       np->n_lockholder = curproc->p_pid;
        np->n_flag |= NLOCKED;
 }
 
        np->n_flag |= NLOCKED;
 }
 
@@ -359,15 +275,7 @@ nfs_unlock(vp)
 {
        register struct nfsnode *np = VTONFS(vp);
 
 {
        register struct nfsnode *np = VTONFS(vp);
 
-       if ((np->n_flag & NLOCKED) == 0) {
-               printf("pid %d unlocking unlocked nfsnode=0x%x ",
-                   u.u_procp->p_pid, np);
-               printf("fh0=0x%x fh1=0x%x fh2=0x%x fh3=0x%x fh4=0x%x fh5=0x%x fh6=0x%x fh7=0x%x\n",
-                       np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1],
-                       np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3],
-                       np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5],
-                       np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]);
-       }
+       np->n_lockholder = 0;
        np->n_flag &= ~NLOCKED;
        if (np->n_flag & NWANT) {
                np->n_flag &= ~NWANT;
        np->n_flag &= ~NLOCKED;
        if (np->n_flag & NWANT) {
                np->n_flag &= ~NWANT;
@@ -375,6 +283,18 @@ nfs_unlock(vp)
        }
 }
 
        }
 }
 
+/*
+ * Check for a locked nfsnode
+ */
+nfs_islocked(vp)
+       struct vnode *vp;
+{
+
+       if (VTONFS(vp)->n_flag & NLOCKED)
+               return (1);
+       return (0);
+}
+
 /*
  * Unlock and vrele()
  * since I can't decide if dirs. should be locked, I will check for
 /*
  * Unlock and vrele()
  * since I can't decide if dirs. should be locked, I will check for
@@ -390,32 +310,16 @@ nfs_nput(vp)
        vrele(vp);
 }
 
        vrele(vp);
 }
 
-nfs_abortop(ndp)
-       register struct nameidata *ndp;
-{
-       register struct nfsnode *np;
-
-       if (ndp->ni_vp != NULL) {
-               np = VTONFS(ndp->ni_vp);
-               if (np->n_flag & NLOCKED)
-                       nfs_unlock(ndp->ni_vp);
-               vrele(ndp->ni_vp);
-       }
-       if (ndp->ni_dvp != NULL) {
-               np = VTONFS(ndp->ni_dvp);
-               if (np->n_flag & NLOCKED)
-                       nfs_unlock(ndp->ni_dvp);
-               vrele(ndp->ni_dvp);
-       }
-}
-
 /*
 /*
- * This is silly, but if you use a macro and try and use it in a file
- * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not
- * a good thing
+ * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Currently nothing to do.
  */
  */
-struct nfsmount *vfs_to_nfs(mp)
-       struct mount *mp;
+/* ARGSUSED */
+nfs_abortop(ndp)
+       struct nameidata *ndp;
 {
 {
-       return ((struct nfsmount *)mp->m_data);
+
+       if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
+               FREE(ndp->ni_pnbuf, M_NAMEI);
+       return (0);
 }
 }