Linux: Add autoconf macro for structure checks
[openafs.git] / src / afs / afs_vcache.c
index 899cdf8..51566e7 100644 (file)
 #include "afs/afs_cbqueue.h"
 #include "afs/afs_osidnlc.h"
 
-#if defined(AFS_LINUX22_ENV)
 afs_int32 afs_maxvcount = 0;   /* max number of vcache entries */
 afs_int32 afs_vcount = 0;      /* number of vcache in use now */
-#endif /* AFS_LINUX22_ENV */
 
 #ifdef AFS_SGI_ENV
 int afsvnumbers = 0;
@@ -212,14 +210,7 @@ afs_FlushVCache(struct vcache *avc, int *slept)
     vn_reinit(AFSTOV(avc));
 #endif
     afs_FreeAllAxs(&(avc->Access));
-
-    /* we can't really give back callbacks on RO files, since the
-     * server only tracks them on a per-volume basis, and we don't
-     * know whether we still have some other files from the same
-     * volume. */
-    if ((avc->f.states & CRO) == 0 && avc->callback) {
-       afs_QueueVCB(avc);
-    }
+    afs_QueueVCB(avc);
     ObtainWriteLock(&afs_xcbhash, 460);
     afs_DequeueCallback(avc);  /* remove it from queued callbacks list */
     avc->f.states &= ~(CStatd | CUnique);
@@ -256,7 +247,7 @@ afs_FlushVCache(struct vcache *avc, int *slept)
        afs_stats_cmperf.vcacheXAllocs--;
     } else {
        if (afs_norefpanic) {
-           printf("flush vc refcnt < 1");
+           afs_warn("flush vc refcnt < 1");
            afs_norefpanic++;
        } else
            osi_Panic("flush vc refcnt < 1");
@@ -393,7 +384,7 @@ afs_FlushVCBs(afs_int32 lockit)
     tfids = afs_osi_Alloc(sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
 
     if (lockit)
-       MObtainWriteLock(&afs_xvcb, 273);
+       ObtainWriteLock(&afs_xvcb, 273);
     ObtainReadLock(&afs_xserver);
     for (i = 0; i < NSERVERS; i++) {
        for (safety1 = 0, tsp = afs_servers[i];
@@ -419,7 +410,7 @@ afs_FlushVCBs(afs_int32 lockit)
                    cbArray.AFSCBs_val = callBacks;
                    memset(&callBacks[0], 0, sizeof(callBacks[0]));
                    callBacks[0].CallBackType = CB_EXCLUSIVE;
-                   for (safety3 = 0; safety3 < MAXHOSTS * 2; safety3++) {
+                   for (safety3 = 0; safety3 < AFS_MAXHOSTS * 2; safety3++) {
                        tc = afs_ConnByHost(tsp, tsp->cell->fsport,
                                            tsp->cell->cellNum, &treq, 0,
                                            SHARED_LOCK);
@@ -478,7 +469,7 @@ afs_FlushVCBs(afs_int32 lockit)
 
     ReleaseReadLock(&afs_xserver);
     if (lockit)
-       MReleaseWriteLock(&afs_xvcb);
+       ReleaseWriteLock(&afs_xvcb);
     afs_osi_Free(tfids, sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
     return 0;
 }
@@ -491,23 +482,34 @@ afs_FlushVCBs(afs_int32 lockit)
  *     Called when the xvcache lock is already held.
  *
  * \param avc vcache entry
- * \return 0 for success < 0 otherwise.
+ * \return 1 if queued, 0 otherwise
  */
 
 static afs_int32
 afs_QueueVCB(struct vcache *avc)
 {
+    int queued = 0;
     struct server *tsp;
     struct afs_cbr *tcbp;
 
     AFS_STATCNT(afs_QueueVCB);
+
+    ObtainWriteLock(&afs_xvcb, 274);
+
+    /* we can't really give back callbacks on RO files, since the
+     * server only tracks them on a per-volume basis, and we don't
+     * know whether we still have some other files from the same
+     * volume. */
+    if (!((avc->f.states & CRO) == 0 && avc->callback)) {
+        goto done;
+    }
+
     /* The callback is really just a struct server ptr. */
     tsp = (struct server *)(avc->callback);
 
     /* we now have a pointer to the server, so we just allocate
      * a queue entry and queue it.
      */
-    MObtainWriteLock(&afs_xvcb, 274);
     tcbp = afs_AllocCBR();
     tcbp->fid = avc->f.fid.Fid;
 
@@ -519,10 +521,12 @@ afs_QueueVCB(struct vcache *avc)
     tcbp->pprev = &tsp->cbrs;
 
     afs_InsertHashCBR(tcbp);
+    queued = 1;
 
+ done:
     /* now release locks and return */
-    MReleaseWriteLock(&afs_xvcb);
-    return 0;
+    ReleaseWriteLock(&afs_xvcb);
+    return queued;
 }
 
 
@@ -545,7 +549,7 @@ afs_RemoveVCB(struct VenusFid *afid)
     struct afs_cbr *cbr, *ncbr;
 
     AFS_STATCNT(afs_RemoveVCB);
-    MObtainWriteLock(&afs_xvcb, 275);
+    ObtainWriteLock(&afs_xvcb, 275);
 
     slot = afs_HashCBRFid(&afid->Fid);
     ncbr = afs_cbrHashT[slot];
@@ -561,7 +565,7 @@ afs_RemoveVCB(struct VenusFid *afid)
        }
     }
 
-    MReleaseWriteLock(&afs_xvcb);
+    ReleaseWriteLock(&afs_xvcb);
 }
 
 void 
@@ -586,7 +590,7 @@ afs_FlushReclaimedVcaches(void)
               We probably need a way to be smarter about this. */
            tvc->nextfree = tmpReclaimedVCList;
            tmpReclaimedVCList = tvc;
-           printf("Reclaim list flush %lx failed: %d\n", (unsigned long) tvc, code);
+           /* printf("Reclaim list flush %lx failed: %d\n", (unsigned long) tvc, code); */
        }
         if (tvc->f.states & (CVInit
 #ifdef AFS_DARWIN80_ENV
@@ -692,7 +696,7 @@ restart:
                break;
        }
        if (!afsd_dynamic_vcaches && anumber == target) {
-           printf("afs_ShakeLooseVCaches: warning none freed, using %d of %d\n",
+           afs_warn("afs_ShakeLooseVCaches: warning none freed, using %d of %d\n",
                   afs_vcount, afs_maxvcount);
        }
     } /* finished freeing up space */
@@ -717,7 +721,7 @@ afs_AllocVCache(void)
     if (!ip)
        osi_Panic("afs_AllocVCache: no more inodes");
     AFS_GLOCK();
-#if defined(STRUCT_SUPER_HAS_ALLOC_INODE)
+#if defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
     tvc = VTOAFS(ip);
 #else
     tvc = afs_osi_Alloc(sizeof(struct vcache));
@@ -738,9 +742,9 @@ afs_AllocVCache(void)
     /* none free, making one is better than a panic */
     afs_stats_cmperf.vcacheXAllocs++;  /* count in case we have a leak */
     tvc = (struct vcache *)afs_osi_Alloc(sizeof(struct vcache));
-#if defined(AFS_DARWIN_ENV) && !defined(UKERNEL)
+#if (defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)) && !defined(UKERNEL)
     tvc->v = NULL; /* important to clean this, or use memset 0 */
-#endif
+#endif /* DARWIN || XBSD && !UKERNEL */
 #ifdef KERNEL_HAVE_PIN
     pin((char *)tvc, sizeof(struct vcache));   /* XXX */
 #endif
@@ -795,8 +799,9 @@ afs_AllocVCache(void)
  *
  * \return The new vcache struct.
  */
-struct vcache *
-afs_NewVCache(struct VenusFid *afid, struct server *serverp)
+
+static_inline struct vcache *
+afs_NewVCache_int(struct VenusFid *afid, struct server *serverp, int seq)
 {
     struct vcache *tvc;
     afs_int32 i, j;
@@ -817,7 +822,7 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
     if(!afsd_dynamic_vcaches) {
        afs_ShakeLooseVCaches(anumber);
        if (afs_vcount >= afs_maxvcount) {
-           printf("afs_NewVCache - none freed\n");
+           afs_warn("afs_NewVCache - none freed\n");
            return NULL;
        }
     }
@@ -885,7 +890,19 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
                  * XXX assume FreeBSD is the same for now.
                  */
                 AFS_GUNLOCK();
+#if defined(AFS_FBSD80_ENV)
+                /* vgone() is correct, but v_usecount is assumed not
+                 * to be 0, and I suspect that currently our usage ensures that
+                 * in fact it will */
+                if (vrefcnt(AFSTOV(tvc)) < 1) {
+                   vref(AFSTOV(tvc));
+                }
+                vn_lock(AFSTOV(tvc), LK_EXCLUSIVE | LK_RETRY); /* !glocked */
+#endif
                 vgone(AFSTOV(tvc));
+#if defined(AFS_FBSD80_ENV)
+                VOP_UNLOCK(AFSTOV(tvc), 0);
+#endif
                 fv_slept = 0;
                 code = 0;
                 AFS_GLOCK();
@@ -1001,7 +1018,7 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
 #ifdef AFS_OBSD_ENV
     ReleaseWriteLock(&afs_xvcache);
     AFS_GUNLOCK();
-    afs_nbsd_getnewvnode(tvc); /* includes one refcount */
+    afs_obsd_getnewvnode(tvc); /* includes one refcount */
     AFS_GLOCK();
     ObtainWriteLock(&afs_xvcache,337);
     lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
@@ -1009,7 +1026,7 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
 #ifdef AFS_DARWIN_ENV
     ReleaseWriteLock(&afs_xvcache);
     AFS_GUNLOCK();
-    afs_darwin_getnewvnode(tvc);       /* includes one refcount */
+    afs_darwin_getnewvnode(tvc, seq ? 0 : 1);  /* includes one refcount */
     AFS_GLOCK();
     ObtainWriteLock(&afs_xvcache,338);
 #ifdef AFS_DARWIN80_ENV
@@ -1032,6 +1049,14 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
        if (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
 #endif
            panic("afs getnewvnode");   /* can't happen */
+#ifdef AFS_FBSD70_ENV
+       /* XXX verified on 80--TODO check on 7x */
+       if (!vp->v_mount) {
+           vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* !glocked */
+           insmntque(vp, afs_globalVFS);
+           VOP_UNLOCK(vp, 0);
+       }
+#endif
        AFS_GLOCK();
        ObtainWriteLock(&afs_xvcache,339);
        if (tvc->v != NULL) {
@@ -1044,7 +1069,7 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
             * then there probably needs to be some sort of additional
             * mutual exclusion (an Embryonic flag would suffice).
             * -GAW */
-           printf("afs_NewVCache: lost the race\n");
+           afs_warn("afs_NewVCache: lost the race\n");
            return (tvc);
        }
        tvc->v = vp;
@@ -1122,11 +1147,11 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
 #endif
     vnode_pcache_init(&tvc->v);
 #if defined(DEBUG) && defined(VNODE_INIT_BITLOCK)
-    /* Above define is never true execpt in SGI test kernels. */
-    init_bitlock(&(tvc->v.v_flag, VLOCK, "vnode", tvc->v.v_number);
+    /* Above define is never true except in SGI test kernels. */
+    init_bitlock(&(tvc->v.v_flag, VLOCK, "vnode", tvc->v.v_number));
 #endif
 #ifdef INTR_KTHREADS
-                AFS_VN_INIT_BUF_LOCK(&(tvc->v));
+    AFS_VN_INIT_BUF_LOCK(&(tvc->v));
 #endif
 #else
     SetAfsVnode(AFSTOV(tvc));
@@ -1152,11 +1177,6 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
     tvc->v.v_next = gnodepnt->gn_vnode;        /*Single vnode per gnode for us! */
     gnodepnt->gn_vnode = &tvc->v;
 #endif
-#ifdef AFS_FBSD70_ENV
-#ifndef AFS_FBSD80_ENV /* yup.  they put it back. */
-    insmntque(AFSTOV(tvc), afs_globalVFS);
-#endif
-#endif
 #if defined(AFS_SGI_ENV)
     VN_SET_DPAGES(&(tvc->v), (struct pfdat *)NULL);
     osi_Assert((tvc->v.v_flag & VINACT) == 0);
@@ -1181,13 +1201,28 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
     memset(&(tvc->callsort), 0, sizeof(struct afs_q));
     tvc->slocks = NULL;
     tvc->f.states &=~ CVInit;
+    if (seq) {
+       tvc->f.states |= CBulkFetching;
+       tvc->f.m.Length = seq;
+    }
     afs_osi_Wakeup(&tvc->f.states);
 
     return tvc;
-
 }                              /*afs_NewVCache */
 
 
+struct vcache *
+afs_NewVCache(struct VenusFid *afid, struct server *serverp)
+{
+    return afs_NewVCache_int(afid, serverp, 0);
+}
+
+struct vcache *
+afs_NewBulkVCache(struct VenusFid *afid, struct server *serverp, int seq)
+{
+    return afs_NewVCache_int(afid, serverp, seq);
+}
+
 /*!
  * ???
  *
@@ -1579,9 +1614,10 @@ afs_WriteVCache(register struct vcache *avc,
  *
  * \note Must be called with a shared lock on the vnode
  */
-int afs_WriteVCacheDiscon(register struct vcache *avc,
-                               register struct AFSStoreStatus *astatus,
-                               struct vattr *attrs)
+int
+afs_WriteVCacheDiscon(register struct vcache *avc,
+                     register struct AFSStoreStatus *astatus,
+                     struct vattr *attrs)
 {
     afs_int32 code = 0;
     afs_int32 flags = 0;
@@ -1601,13 +1637,13 @@ int afs_WriteVCacheDiscon(register struct vcache *avc,
        }
 
        if (astatus->Mask & AFS_SETOWNER) {
-               printf("Not allowed yet. \n");
-               /*avc->f.m.Owner = astatus->Owner;*/
+           /* printf("Not allowed yet. \n"); */
+           /*avc->f.m.Owner = astatus->Owner;*/
        }
 
        if (astatus->Mask & AFS_SETGROUP) {
-               printf("Not allowed yet. \n");
-               /*avc->f.m.Group =  astatus->Group;*/
+           /* printf("Not allowed yet. \n"); */
+           /*avc->f.m.Group =  astatus->Group;*/
        }
 
        if (astatus->Mask & AFS_SETMODE) {
@@ -1939,7 +1975,7 @@ afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq,
            if (glocked)
                AFS_GLOCK();
        }
-       vinvalbuf(vp, V_SAVE, curthread, PINOD, 0);
+       vinvalbuf(vp, V_SAVE, PINOD, 0); /* changed late in 8.0-CURRENT */
        if (!iheldthelock)
            VOP_UNLOCK(vp, 0);
 #elif defined(AFS_FBSD60_ENV)
@@ -2023,7 +2059,7 @@ afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq,
            if (AFS_IS_DISCONNECTED) {
                /* Nothing to do otherwise...*/
                code = ENETDOWN;
-               printf("Network is down in afs_GetCache");
+               /* printf("Network is down in afs_GetCache"); */
            } else
                code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
 
@@ -2132,7 +2168,7 @@ afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
     origCBs = afs_allCBs;      /* if anything changes, we don't have a cb */
     
     if (AFS_IS_DISCONNECTED) {
-       printf("Network is down in afs_LookupVcache\n");
+       /* printf("Network is down in afs_LookupVcache\n"); */
         code = ENETDOWN;
     } else 
         code =
@@ -2302,11 +2338,13 @@ afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq,
                goto rootvc_loop;
             }
 #ifdef AFS_DARWIN80_ENV
-            if (tvc->f.states & CDeadVnode) {
-               ReleaseSharedLock(&afs_xvcache);
-               afs_osi_Sleep(&tvc->f.states);
-               goto rootvc_loop;
-            }
+           if (tvc->f.states & CDeadVnode) {
+               if (!(tvc->f.states & CBulkFetching)) {
+                   ReleaseSharedLock(&afs_xvcache);
+                   afs_osi_Sleep(&tvc->f.states);
+                   goto rootvc_loop;
+               }
+           }
            tvp = AFSTOV(tvc);
            if (vnode_get(tvp))       /* this bumps ref count */
                continue;
@@ -2317,6 +2355,11 @@ afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq,
                AFS_GLOCK();
                continue;
            }
+           if (tvc->f.states & (CBulkFetching|CDeadVnode)) {
+               AFS_GUNLOCK();
+               vnode_recycle(AFSTOV(tvc));
+               AFS_GLOCK();
+           }
 #endif
            break;
        }
@@ -2489,12 +2532,9 @@ afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq,
  * \note The vcache must be write locked.
  */
 void
-afs_UpdateStatus(struct vcache *avc,
-                       struct VenusFid *afid,
-                       struct vrequest *areq,
-                       struct AFSFetchStatus *Outsp,
-                       struct AFSCallBack *acb,
-                       afs_uint32 start)
+afs_UpdateStatus(struct vcache *avc, struct VenusFid *afid,
+                struct vrequest *areq, struct AFSFetchStatus *Outsp,
+                struct AFSCallBack *acb, afs_uint32 start)
 {
     struct volume *volp;
 
@@ -2771,7 +2811,8 @@ afs_PutVCache(register struct vcache *avc)
  * \note avc must be write locked on entry
  */
 void
-afs_ResetVCache(struct vcache *avc, afs_ucred_t *acred) {
+afs_ResetVCache(struct vcache *avc, afs_ucred_t *acred)
+{
     ObtainWriteLock(&afs_xcbhash, 456);
     afs_DequeueCallback(avc);
     avc->f.states &= ~(CStatd | CDirty);    /* next reference will re-stat */
@@ -2794,7 +2835,10 @@ afs_ResetVCache(struct vcache *avc, afs_ucred_t *acred) {
  *
  * \return 
  */
-static void findvc_sleep(struct vcache *avc, int flag) {
+static void
+findvc_sleep(struct vcache *avc, int flag)
+{
+    int fstates = avc->f.states;
     if (flag & IS_SLOCK) {
            ReleaseSharedLock(&afs_xvcache);
     } else {
@@ -2804,7 +2848,16 @@ static void findvc_sleep(struct vcache *avc, int flag) {
            ReleaseReadLock(&afs_xvcache);
        }
     }
-    afs_osi_Sleep(&avc->f.states);
+    if (flag & FIND_CDEAD) {
+       ObtainWriteLock(&afs_xvcache, 342);
+       afs_FlushReclaimedVcaches();
+       if (fstates == avc->f.states) {
+           ReleaseWriteLock(&afs_xvcache);
+           afs_osi_Sleep(&avc->f.states);
+       } else
+           ReleaseWriteLock(&afs_xvcache);
+    } else
+       afs_osi_Sleep(&avc->f.states);
     if (flag & IS_SLOCK) {
            ObtainSharedLock(&afs_xvcache, 341);
     } else {
@@ -2850,10 +2903,12 @@ afs_FindVCache(struct VenusFid *afid, afs_int32 * retry, afs_int32 flag)
                goto findloop;
             }
 #ifdef  AFS_DARWIN80_ENV
-            if (tvc->f.states & CDeadVnode) {
-                findvc_sleep(tvc, flag);
-               goto findloop;
-            }
+           if (tvc->f.states & CDeadVnode) {
+               if (!(flag & FIND_CDEAD)) {
+                   findvc_sleep(tvc, flag);
+                   goto findloop;
+               }
+           }
            tvp = AFSTOV(tvc);
            if (vnode_get(tvp))
                continue;
@@ -2864,6 +2919,11 @@ afs_FindVCache(struct VenusFid *afid, afs_int32 * retry, afs_int32 flag)
                AFS_GLOCK();
                continue;
            }
+           if (tvc->f.states & (CBulkFetching|CDeadVnode)) {
+               AFS_GUNLOCK();
+               vnode_recycle(AFSTOV(tvc));
+               AFS_GLOCK();
+           }
 #endif
            break;
        }
@@ -2981,11 +3041,13 @@ afs_NFSFindVCache(struct vcache **avcp, struct VenusFid *afid)
                goto loop;
             }
 #ifdef  AFS_DARWIN80_ENV
-            if (tvc->f.states & CDeadVnode) {
-               ReleaseSharedLock(&afs_xvcache);
-               afs_osi_Sleep(&tvc->f.states);
-               goto loop;
-            }
+           if (tvc->f.states & CDeadVnode) {
+               if (!(tvc->f.states & CBulkFetching)) {
+                   ReleaseSharedLock(&afs_xvcache);
+                   afs_osi_Sleep(&tvc->f.states);
+                   goto loop;
+               }
+           }
            tvp = AFSTOV(tvc);
            if (vnode_get(tvp)) {
                /* This vnode no longer exists. */
@@ -2999,6 +3061,11 @@ afs_NFSFindVCache(struct vcache **avcp, struct VenusFid *afid)
                AFS_GLOCK();
                continue;
            }
+           if (tvc->f.states & (CBulkFetching|CDeadVnode)) {
+               AFS_GUNLOCK();
+               vnode_recycle(AFSTOV(tvc));
+               AFS_GLOCK();
+           }
 #endif /* AFS_DARWIN80_ENV */
            count++;
            if (found_tvc) {
@@ -3248,7 +3315,8 @@ shutdown_vcache(void)
 }
 
 void
-afs_DisconGiveUpCallbacks(void) {
+afs_DisconGiveUpCallbacks(void)
+{
     int i;
     struct vcache *tvc;
     int nq=0;
@@ -3258,18 +3326,16 @@ afs_DisconGiveUpCallbacks(void) {
     /* Somehow, walk the set of vcaches, with each one coming out as tvc */
     for (i = 0; i < VCSIZE; i++) {
         for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
-            if ((tvc->f.states & CRO) == 0 && tvc->callback) {
-                afs_QueueVCB(tvc);
+            if (afs_QueueVCB(tvc)) {
                 tvc->callback = NULL;
                 nq++;
             }
         }
     }
-    /*printf("%d callbacks to be discarded. queued ... ", nq);*/
-    afs_FlushVCBs(0);
-    
+
     ReleaseWriteLock(&afs_xvcache);
-    /*printf("gone\n");*/
+
+    afs_FlushVCBs(1);
 }
 
 /*!
@@ -3281,7 +3347,8 @@ afs_DisconGiveUpCallbacks(void) {
  *
  */
 void
-afs_ClearAllStatdFlag(void) {
+afs_ClearAllStatdFlag(void)
+{
     int i;
     struct vcache *tvc;