18cda8fd12f691b3adc04a7034e66345ee0dc1db
[openafs.git] / src / afs / afs_daemons.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "../afs/param.h"
12
13 RCSID("$Header$");
14
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h"   /* statistics gathering code */
18 #include "../afs/afs_cbqueue.h" 
19 #ifdef AFS_AIX_ENV
20 #include <sys/adspace.h>        /* for vm_att(), vm_det() */
21 #endif
22
23
24 /* background request queue size */
25 afs_lock_t afs_xbrs;            /* lock for brs */
26 static int brsInit = 0;
27 short afs_brsWaiters = 0;       /* number of users waiting for brs buffers */
28 short afs_brsDaemons = 0;       /* number of daemons waiting for brs requests */
29 struct brequest afs_brs[NBRS];  /* request structures */
30 struct afs_osi_WaitHandle AFS_WaitHandler, AFS_CSWaitHandler;
31
32 static int rxepoch_checked=0;
33 #define afs_CheckRXEpoch() {if (rxepoch_checked == 0 && rxkad_EpochWasSet) { \
34         rxepoch_checked = 1; afs_GCUserData(/* force flag */ 1);  } }
35
36 extern char afs_rootVolumeName[];
37 extern struct vcache *afs_globalVp;
38 extern struct VenusFid afs_rootFid;
39 extern struct osi_dev cacheDev;
40 extern char *afs_indexFlags;
41 extern afs_rwlock_t afs_xvcache;
42 extern struct afs_exporter *afs_nfsexporter;
43 extern int cacheDiskType;
44 extern int afs_BumpBase();
45 extern void afs_CheckCallbacks();
46
47 /* PAG garbage collection */
48 /* We induce a compile error if param.h does not define AFS_GCPAGS */
49 afs_int32 afs_gcpags=AFS_GCPAGS;
50 afs_int32 afs_gcpags_procsize;
51
52 afs_int32 afs_CheckServerDaemonStarted = 0;
53 afs_int32 PROBE_INTERVAL=180;   /* default to 3 min */
54
55 #define PROBE_WAIT() (1000 * (PROBE_INTERVAL - ((afs_random() & 0x7fffffff) \
56                       % (PROBE_INTERVAL/2))))
57
58 afs_CheckServerDaemon()
59 {
60     afs_int32 now, delay, lastCheck, last10MinCheck;
61
62     afs_CheckServerDaemonStarted = 1;
63
64     while (afs_initState < 101) afs_osi_Sleep(&afs_initState);
65     afs_osi_Wait(PROBE_WAIT(), &AFS_CSWaitHandler, 0);  
66     
67     last10MinCheck = lastCheck = osi_Time();
68     while ( 1 ) {
69         if (afs_termState == AFSOP_STOP_CS) {
70             afs_termState = AFSOP_STOP_BKG;
71             afs_osi_Wakeup(&afs_termState);
72             break;
73         }
74
75         now = osi_Time();
76         if (PROBE_INTERVAL + lastCheck <= now) {
77             afs_CheckServers(1, (struct cell *) 0); /* check down servers */
78             lastCheck = now = osi_Time();
79         }
80
81         if (600 + last10MinCheck <= now) {
82             afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP, ICL_TYPE_INT32, 600);
83             afs_CheckServers(0, (struct cell *) 0);
84             last10MinCheck = now = osi_Time();
85         }
86         /* shutdown check. */
87         if (afs_termState == AFSOP_STOP_CS) {
88             afs_termState = AFSOP_STOP_BKG;
89             afs_osi_Wakeup(&afs_termState);
90             break;
91         }
92
93         /* Compute time to next probe. */
94         delay = PROBE_INTERVAL + lastCheck;
95         if (delay > 600 + last10MinCheck)
96             delay = 600 + last10MinCheck;
97         delay -= now;
98         if (delay < 1)
99             delay = 1;
100         afs_osi_Wait(delay * 1000,  &AFS_CSWaitHandler, 0);  
101     }
102     afs_CheckServerDaemonStarted = 0;
103 }
104
105 void afs_Daemon() {
106     afs_int32 code;
107     extern struct afs_exporter *root_exported;
108     struct afs_exporter *exporter;
109     afs_int32 now;
110     afs_int32 last3MinCheck, last10MinCheck, last60MinCheck, lastNMinCheck;
111     afs_int32 last1MinCheck;
112     afs_uint32 lastCBSlotBump;
113     char cs_warned = 0;
114
115     AFS_STATCNT(afs_Daemon);
116     last1MinCheck = last3MinCheck = last60MinCheck = last10MinCheck = lastNMinCheck = 0;
117
118     afs_rootFid.Fid.Volume = 0;
119     while (afs_initState < 101) afs_osi_Sleep(&afs_initState);
120
121     now = osi_Time();
122     lastCBSlotBump = now;
123
124     /* when a lot of clients are booted simultaneously, they develop
125      * annoying synchronous VL server bashing behaviors.  So we stagger them.
126      */
127     last1MinCheck = now + ((afs_random() & 0x7fffffff) % 60); /* an extra 30 */
128     last3MinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180);
129     last60MinCheck = now - 1800 + ((afs_random() & 0x7fffffff) % 3600);
130     last10MinCheck = now - 300 + ((afs_random() & 0x7fffffff) % 600);
131     lastNMinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180);
132
133     /* start off with afs_initState >= 101 (basic init done) */
134     while(1) {
135         afs_CheckCallbacks(20);  /* unstat anything which will expire soon */
136         
137         /* things to do every 20 seconds or less - required by protocol spec */
138         if (afs_nfsexporter) 
139             afs_FlushActiveVcaches(0);  /* flush NFS writes */
140         afs_FlushVCBs(1);               /* flush queued callbacks */
141         afs_MaybeWakeupTruncateDaemon();        /* free cache space if have too */
142         rx_CheckPackets();              /* Does RX need more packets? */
143 #if     defined(AFS_AIX32_ENV) || defined(AFS_HPUX_ENV)
144         /* 
145          * Hack: We always want to make sure there are plenty free
146          * entries in the small free pool so that we don't have to
147          * worry about rx (with disabled interrupts) to have to call
148          * malloc). So we do the dummy call below...
149          */
150         if (((afs_stats_cmperf.SmallBlocksAlloced - afs_stats_cmperf.SmallBlocksActive) 
151              <= AFS_SALLOC_LOW_WATER))
152             osi_FreeSmallSpace(osi_AllocSmallSpace(AFS_SMALLOCSIZ));
153         if (((afs_stats_cmperf.MediumBlocksAlloced - afs_stats_cmperf.MediumBlocksActive) 
154              <= AFS_MALLOC_LOW_WATER+50)) 
155             osi_AllocMoreMSpace(AFS_MALLOC_LOW_WATER * 2); 
156 #endif
157         
158         now = osi_Time();
159         if (lastCBSlotBump + CBHTSLOTLEN < now) {  /* pretty time-dependant */
160             lastCBSlotBump = now;
161             if (afs_BumpBase()) {
162                 afs_CheckCallbacks(20);  /* unstat anything which will expire soon */
163             }
164         }
165         
166         if (last1MinCheck + 60 < now) {
167             /* things to do every minute */
168             DFlush();                   /* write out dir buffers */
169             afs_WriteThroughDSlots();   /* write through cacheinfo entries */
170             afs_FlushActiveVcaches(1);/* keep flocks held & flush nfs writes */
171             afs_CheckRXEpoch();
172             last1MinCheck = now;
173         }
174         
175         if (last3MinCheck + 180 < now) {
176             afs_CheckTokenCache();      /* check for access cache resets due to expired
177                                            tickets */
178             last3MinCheck = now;
179         }
180         if (!afs_CheckServerDaemonStarted) {
181             /* Do the check here if the correct afsd is not installed. */
182             if (!cs_warned) {
183                 cs_warned = 1;
184                 printf("Please install afsd with check server daemon.\n");
185             }
186             if (lastNMinCheck + PROBE_INTERVAL < now) {
187                 /* only check down servers */
188                 afs_CheckServers(1, (struct cell *) 0);
189                 lastNMinCheck = now;
190             }
191         }
192         if (last10MinCheck + 600 < now) {
193 #ifdef AFS_USERSPACE_IP_ADDR    
194             extern int rxi_GetcbiInfo(void);
195 #endif
196             afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP,
197                        ICL_TYPE_INT32, 600);
198 #ifdef AFS_USERSPACE_IP_ADDR    
199             if (rxi_GetcbiInfo()) { /* addresses changed from last time */
200                 afs_FlushCBs();
201             }
202 #else  /* AFS_USERSPACE_IP_ADDR */
203             if (rxi_GetIFInfo()) { /* addresses changed from last time */
204                 afs_FlushCBs();
205             }
206 #endif /* else AFS_USERSPACE_IP_ADDR */
207             if (!afs_CheckServerDaemonStarted)
208                 afs_CheckServers(0, (struct cell *) 0);
209             afs_GCUserData(0);      /* gc old conns */
210             /* This is probably the wrong way of doing GC for the various exporters but it will suffice for a while */
211             for (exporter = root_exported; exporter; exporter = exporter->exp_next) {
212                 (void) EXP_GC(exporter, 0);     /* Generalize params */
213             }
214             {
215                 static int cnt=0;
216                 if (++cnt < 12) {
217                     afs_CheckVolumeNames(AFS_VOLCHECK_EXPIRED |
218                                          AFS_VOLCHECK_BUSY);
219                 } else {
220                     cnt = 0;
221                     afs_CheckVolumeNames(AFS_VOLCHECK_EXPIRED |
222                                          AFS_VOLCHECK_BUSY |
223                                          AFS_VOLCHECK_MTPTS);
224                 }
225             }
226             last10MinCheck = now;
227         }
228         if (last60MinCheck + 3600 < now) {
229             afs_Trace1(afs_iclSetp, CM_TRACE_PROBEVOLUME,
230                        ICL_TYPE_INT32, 3600);
231             afs_CheckRootVolume();
232 #if AFS_GCPAGS
233             if (afs_gcpags == AFS_GCPAGS_OK) {
234                 afs_int32 didany;
235                 afs_GCPAGs(&didany);
236             }
237 #endif
238             last60MinCheck = now;
239         }
240         if (afs_initState < 300) {      /* while things ain't rosy */
241             code = afs_CheckRootVolume();
242             if (code == 0) afs_initState = 300;             /* succeeded */
243             if (afs_initState < 200) afs_initState = 200;   /* tried once */
244             afs_osi_Wakeup(&afs_initState);
245         }
246         
247         /* 18285 is because we're trying to divide evenly into 128, that is,
248          * CBSlotLen, while staying just under 20 seconds.  If CBSlotLen
249          * changes, should probably change this interval, too. 
250          * Some of the preceding actions may take quite some time, so we
251          * might not want to wait the entire interval */
252         now = 18285 - (osi_Time() - now);
253         if (now > 0) {
254             afs_osi_Wait(now, &AFS_WaitHandler, 0);  
255         }
256         
257         if (afs_termState == AFSOP_STOP_AFS) {
258             if (afs_CheckServerDaemonStarted)
259                 afs_termState = AFSOP_STOP_CS;
260             else
261                 afs_termState = AFSOP_STOP_BKG;
262             afs_osi_Wakeup(&afs_termState);
263             return;
264         }
265     }
266 }
267
268 afs_CheckRootVolume () {
269     char rootVolName[32];
270     register struct volume *tvp;
271
272     AFS_STATCNT(afs_CheckRootVolume);
273     if (*afs_rootVolumeName == 0) {
274         strcpy(rootVolName, "root.afs");
275     }
276     else {
277         strcpy(rootVolName, afs_rootVolumeName);
278     }
279     tvp = afs_GetVolumeByName(rootVolName, LOCALCELL, 1, (struct vrequest *) 0, READ_LOCK);
280     if (!tvp) {
281         char buf[128];
282         int len = strlen(rootVolName);
283
284         if ((len < 9) || strcmp(&rootVolName[len - 9], ".readonly")) {
285             strcpy(buf, rootVolName);
286             afs_strcat(buf, ".readonly");
287             tvp = afs_GetVolumeByName(buf, LOCALCELL, 1, (struct vrequest *) 0, READ_LOCK);
288         }
289     }
290     if (tvp) {
291         int volid = (tvp->roVol? tvp->roVol : tvp->volume);
292         afs_rootFid.Cell = LOCALCELL;
293         if (afs_rootFid.Fid.Volume && afs_rootFid.Fid.Volume != volid
294             && afs_globalVp) {
295             /* If we had a root fid before and it changed location we reset
296              * the afs_globalVp so that it will be reevaluated.
297              * Just decrement the reference count. This only occurs during
298              * initial cell setup and can panic the machine if we set the
299              * count to zero and fs checkv is executed when the current
300              * directory is /afs.
301              */
302             AFS_FAST_RELE(afs_globalVp);
303             afs_globalVp = 0;
304         }
305         afs_rootFid.Fid.Volume = volid;
306         afs_rootFid.Fid.Vnode = 1;
307         afs_rootFid.Fid.Unique = 1;
308         afs_initState = 300;    /* won */
309         afs_osi_Wakeup(&afs_initState);
310         afs_PutVolume(tvp, READ_LOCK);
311     }
312 #ifdef AFS_DEC_ENV
313 /* This is to make sure that we update the root gnode */
314 /* every time root volume gets released */
315     {
316         extern struct vfs *afs_globalVFS;
317         extern int afs_root();
318         struct gnode *rootgp;
319         struct mount *mp;
320         int code;
321
322         /* Only do this if afs_globalVFS is properly set due to race conditions
323            this routine could be called before the gfs_mount is performed!
324            Furthermore, afs_root (called below) *waits* until
325            initState >= 200, so we don't try this until we've gotten
326            at least that far */
327         if (afs_globalVFS && afs_initState >= 200) {
328             if (code = afs_root(afs_globalVFS, &rootgp))
329                 return code;
330             mp = (struct mount *) afs_globalVFS->vfs_data ;
331             mp->m_rootgp = gget(mp, 0, 0, (char *)rootgp);
332             afs_unlock(mp->m_rootgp);   /* unlock basic gnode */
333             afs_vrele((struct vcache *) rootgp);  /* zap afs_root's vnode hold */
334         }
335     }
336 #endif
337     if (afs_rootFid.Fid.Volume) return 0;
338     else return ENOENT;
339 }
340
341 /* parm 0 is the pathname, parm 1 to the fetch is the chunk number */
342 void BPath(ab)
343     register struct brequest *ab; {
344     register struct dcache *tdc;
345     struct vcache *tvc;
346     struct vnode *tvn;
347 #ifdef AFS_LINUX22_ENV
348     struct dentry *dp = NULL;
349 #endif
350     afs_int32 offset, len;
351     struct vrequest treq;
352     afs_int32 code;
353
354     AFS_STATCNT(BPath);
355     if (code = afs_InitReq(&treq, ab->cred)) return;
356     AFS_GUNLOCK();
357 #ifdef AFS_LINUX22_ENV
358     code = gop_lookupname((char *)ab->parm[0], AFS_UIOSYS, 1,  (struct vnode **) 0, &dp);
359     if (dp)
360         tvn = (struct vnode*)dp->d_inode;
361 #else
362     code = gop_lookupname((char *)ab->parm[0], AFS_UIOSYS, 1,  (struct vnode **) 0, (struct vnode **)&tvn);
363 #endif
364     AFS_GLOCK();
365     osi_FreeLargeSpace((char *)ab->parm[0]); /* free path name buffer here */
366     if (code) return;
367     /* now path may not have been in afs, so check that before calling our cache manager */
368     if (!tvn || !IsAfsVnode((struct vnode *) tvn)) {
369         /* release it and give up */
370         if (tvn) {
371 #ifdef AFS_DEC_ENV
372             grele(tvn);
373 #else
374 #ifdef AFS_LINUX22_ENV
375             dput(dp);
376 #else
377             AFS_RELE((struct vnode *) tvn);
378 #endif
379 #endif
380         }
381         return;
382     }
383 #ifdef AFS_DEC_ENV
384     tvc = (struct vcache *) afs_gntovn(tvn);
385 #else
386     tvc = (struct vcache *) tvn;
387 #endif
388     /* here we know its an afs vnode, so we can get the data for the chunk */
389     tdc = afs_GetDCache(tvc, ab->parm[1], &treq, &offset, &len, 1);
390     if (tdc) {
391         afs_PutDCache(tdc);
392     }
393 #ifdef AFS_DEC_ENV
394     grele(tvn);
395 #else
396 #ifdef AFS_LINUX22_ENV
397     dput(dp);
398 #else
399     AFS_RELE((struct vnode *) tvn);
400 #endif
401 #endif
402 }
403
404 /* parm 0 to the fetch is the chunk number; parm 1 is the dcache entry to wakeup,
405  * parm 2 is true iff we should release the dcache entry here.
406  */
407 void BPrefetch(ab)
408     register struct brequest *ab; {
409     register struct dcache *tdc;
410     register struct vcache *tvc;
411     afs_int32 offset, len;
412     struct vrequest treq;
413
414     AFS_STATCNT(BPrefetch);
415     if (len = afs_InitReq(&treq, ab->cred)) return;
416     tvc = ab->vnode;
417     tdc = afs_GetDCache(tvc, (afs_int32)ab->parm[0], &treq, &offset, &len, 1);
418     if (tdc) {
419         afs_PutDCache(tdc);
420     }
421     /* now, dude may be waiting for us to clear DFFetchReq bit; do so.  Can't
422      * use tdc from GetDCache since afs_GetDCache may fail, but someone may
423      * be waiting for our wakeup anyway.
424      */
425     tdc = (struct dcache *) (ab->parm[1]);
426     tdc->flags &= ~DFFetchReq;
427     afs_osi_Wakeup(&tdc->validPos);
428     if (ab->parm[2]) {
429 #ifdef  AFS_SUN5_ENVX
430         mutex_enter(&tdc->lock);
431         tdc->refCount--;
432         mutex_exit(&tdc->lock);
433 #else
434         afs_PutDCache(tdc);     /* put this one back, too */
435 #endif
436     }
437 }
438
439
440 void BStore(ab)
441     register struct brequest *ab; {
442     register struct vcache *tvc;
443     register afs_int32 code;
444     struct vrequest treq;
445 #if defined(AFS_SGI_ENV)
446     struct cred *tmpcred;
447 #endif
448
449     AFS_STATCNT(BStore);
450     if (code = afs_InitReq(&treq, ab->cred)) return;
451     code = 0;
452     tvc = ab->vnode;
453 #if defined(AFS_SGI_ENV)
454     /*
455      * Since StoreOnLastReference can end up calling osi_SyncVM which
456      * calls into VM code that assumes that u.u_cred has the
457      * correct credentials, we set our to theirs for this xaction
458      */
459     tmpcred = OSI_GET_CURRENT_CRED();
460     OSI_SET_CURRENT_CRED(ab->cred);
461
462     /*
463      * To avoid recursion since the WriteLock may be released during VM
464      * operations, we hold the VOP_RWLOCK across this transaction as
465      * do the other callers of StoreOnLastReference
466      */
467     AFS_RWLOCK((vnode_t *)tvc, 1);
468 #endif
469     ObtainWriteLock(&tvc->lock,209);
470     code = afs_StoreOnLastReference(tvc, &treq);
471     ReleaseWriteLock(&tvc->lock);
472 #if defined(AFS_SGI_ENV)
473     OSI_SET_CURRENT_CRED(tmpcred);
474     AFS_RWUNLOCK((vnode_t *)tvc, 1);
475 #endif
476     /* now set final return code, and wakeup anyone waiting */
477     if ((ab->flags & BUVALID) == 0) {
478         ab->code = afs_CheckCode(code, &treq, 43);    /* set final code, since treq doesn't go across processes */
479         ab->flags |= BUVALID;
480         if (ab->flags & BUWAIT) {
481             ab->flags &= ~BUWAIT;
482             afs_osi_Wakeup(ab);
483         }
484     }
485 }
486
487 /* release a held request buffer */
488 void afs_BRelease(ab)
489     register struct brequest *ab; {
490
491     AFS_STATCNT(afs_BRelease);
492     MObtainWriteLock(&afs_xbrs,294);
493     if (--ab->refCount <= 0) {
494         ab->flags = 0;
495     }
496     if (afs_brsWaiters) afs_osi_Wakeup(&afs_brsWaiters);
497     MReleaseWriteLock(&afs_xbrs);
498 }
499
500 /* return true if bkg fetch daemons are all busy */
501 int afs_BBusy() {
502     AFS_STATCNT(afs_BBusy);
503     if (afs_brsDaemons > 0) return 0;
504     return 1;
505 }
506
507 struct brequest *afs_BQueue(aopcode, avc, dontwait, ause, acred, aparm0, aparm1, aparm2, aparm3)
508     register short aopcode;
509     afs_int32 ause, dontwait;
510     register struct vcache *avc;
511     struct AFS_UCRED *acred;
512     /* On 64 bit platforms, "long" does the right thing. */
513     long aparm0, aparm1, aparm2, aparm3;
514 {
515     register int i;
516     register struct brequest *tb;
517
518     AFS_STATCNT(afs_BQueue);
519     MObtainWriteLock(&afs_xbrs,296);
520     while (1) {
521         tb = afs_brs;
522         for(i=0;i<NBRS;i++,tb++) {
523             if (tb->refCount == 0) break;
524         }
525         if (i < NBRS) {
526             /* found a buffer */
527             tb->opcode = aopcode;
528             tb->vnode = avc;
529             tb->cred = acred;
530             crhold(tb->cred);
531             if (avc) {
532 #ifdef  AFS_DEC_ENV
533                 avc->vrefCount++;
534 #else
535                 VN_HOLD((struct vnode *)avc);
536 #endif
537             }
538             tb->refCount = ause+1;
539             tb->parm[0] = aparm0;
540             tb->parm[1] = aparm1;
541             tb->parm[2] = aparm2;
542             tb->parm[3] = aparm3;
543             tb->flags = 0;
544             tb->code = 0;
545             /* if daemons are waiting for work, wake them up */
546             if (afs_brsDaemons > 0) {
547                 afs_osi_Wakeup(&afs_brsDaemons);
548             }
549             MReleaseWriteLock(&afs_xbrs);
550             return tb;
551         }
552         if (dontwait) {
553             MReleaseWriteLock(&afs_xbrs);
554             return (struct brequest *)0;
555         }
556         /* no free buffers, sleep a while */
557         afs_brsWaiters++;
558         MReleaseWriteLock(&afs_xbrs);
559         afs_osi_Sleep(&afs_brsWaiters);
560         MObtainWriteLock(&afs_xbrs,301);
561         afs_brsWaiters--;
562     }
563 }
564
565 #ifdef  AFS_AIX32_ENV
566 #ifdef AFS_AIX41_ENV
567 /* AIX 4.1 has a much different sleep/wakeup mechanism available for use. 
568  * The modifications here will work for either a UP or MP machine.
569  */
570 struct buf *afs_asyncbuf = (struct buf*)0;
571 afs_int32 afs_asyncbuf_cv = EVENT_NULL;
572 afs_int32 afs_biodcnt = 0;
573
574 /* in implementing this, I assumed that all external linked lists were
575  * null-terminated.  
576  *
577  * Several places in this code traverse a linked list.  The algorithm
578  * used here is probably unfamiliar to most people.  Careful examination
579  * will show that it eliminates an assignment inside the loop, as compared
580  * to the standard algorithm, at the cost of occasionally using an extra
581  * variable.
582  */
583
584 /* get_bioreq()
585  *
586  * This function obtains, and returns, a pointer to a buffer for
587  * processing by a daemon.  It sleeps until such a buffer is available.
588  * The source of buffers for it is the list afs_asyncbuf (see also 
589  * naix_vm_strategy).  This function may be invoked concurrently by
590  * several processes, that is, several instances of the same daemon.
591  * naix_vm_strategy, which adds buffers to the list, runs at interrupt
592  * level, while get_bioreq runs at process level.
593  *
594  * Since AIX 4.1 can wake just one process at a time, the separate sleep
595  * addresses have been removed.
596  * Note that the kernel_lock is held until the e_sleep_thread() occurs. 
597  * The afs_asyncbuf_lock is primarily used to serialize access between
598  * process and interrupts.
599  */
600 Simple_lock afs_asyncbuf_lock;
601 /*static*/ struct buf *afs_get_bioreq()
602 {
603     struct buf *bp = (struct buf *) 0;
604     struct buf *bestbp;
605     struct buf **bestlbpP, **lbpP;
606     int bestage, stop;
607     struct buf *t1P, *t2P;      /* temp pointers for list manipulation */
608     int oldPriority;
609     afs_uint32 wait_ret;
610     struct afs_bioqueue *s;
611
612     /* ??? Does the forward pointer of the returned buffer need to be NULL?
613     */
614     
615     /* Disable interrupts from the strategy function, and save the 
616      * prior priority level and lock access to the afs_asyncbuf.
617      */
618     AFS_GUNLOCK();
619     oldPriority = disable_lock(INTMAX, &afs_asyncbuf_lock) ;
620
621     while(1) {
622         if (afs_asyncbuf) {
623             /* look for oldest buffer */
624             bp = bestbp = afs_asyncbuf;
625             bestage = (int) bestbp->av_back;
626             bestlbpP = &afs_asyncbuf;
627             while (1) {
628                 lbpP = &bp->av_forw;
629                 bp = *lbpP;
630                 if (!bp) break;
631                 if ((int) bp->av_back - bestage < 0) {
632                     bestbp = bp;
633                     bestlbpP = lbpP;
634                     bestage = (int) bp->av_back;
635                 }
636             }
637             bp = bestbp;
638             *bestlbpP = bp->av_forw;
639             break;
640         }
641         else {
642             /* If afs_asyncbuf is null, it is necessary to go to sleep.
643              * e_wakeup_one() ensures that only one thread wakes.
644              */
645             int interrupted;
646             /* The LOCK_HANDLER indicates to e_sleep_thread to only drop the
647              * lock on an MP machine.
648              */
649             interrupted = e_sleep_thread(&afs_asyncbuf_cv,
650                                          &afs_asyncbuf_lock,
651                                          LOCK_HANDLER|INTERRUPTIBLE);
652             if (interrupted==THREAD_INTERRUPTED) {
653                 /* re-enable interrupts from strategy */
654                 unlock_enable(oldPriority, &afs_asyncbuf_lock);
655                 AFS_GLOCK();
656                 return(NULL);
657             }
658         }  /* end of "else asyncbuf is empty" */
659     } /* end of "inner loop" */
660     
661     /*assert (bp);*/
662     
663     unlock_enable(oldPriority, &afs_asyncbuf_lock);
664     AFS_GLOCK();
665
666     /* For the convenience of other code, replace the gnodes in
667      * the b_vp field of bp and the other buffers on the b_work
668      * chain with the corresponding vnodes.   
669      *
670      * ??? what happens to the gnodes?  They're not just cut loose,
671      * are they?
672      */
673     for(t1P=bp;;) {
674         t2P = (struct buf *) t1P->b_work;
675         t1P->b_vp = ((struct gnode *) t1P->b_vp)->gn_vnode;
676         if (!t2P) 
677             break;
678
679         t1P = (struct buf *) t2P->b_work;
680         t2P->b_vp = ((struct gnode *) t2P->b_vp)->gn_vnode;
681         if (!t1P)
682             break;
683     }
684
685     /* If the buffer does not specify I/O, it may immediately
686      * be returned to the caller.  This condition is detected
687      * by examining the buffer's flags (the b_flags field).  If
688      * the B_PFPROT bit is set, the buffer represents a protection
689      * violation, rather than a request for I/O.  The remainder
690      * of the outer loop handles the case where the B_PFPROT bit is clear.
691      */
692     if (bp->b_flags & B_PFPROT)  {
693         return (bp);
694     }
695     return (bp);
696
697 } /* end of function get_bioreq() */
698
699
700 /* afs_BioDaemon
701  *
702  * This function is the daemon.  It is called from the syscall
703  * interface.  Ordinarily, a script or an administrator will run a
704  * daemon startup utility, specifying the number of I/O daemons to
705  * run.  The utility will fork off that number of processes,
706  * each making the appropriate syscall, which will cause this
707  * function to be invoked.
708  */
709 static int afs_initbiod = 0;            /* this is self-initializing code */
710 int DOvmlock = 0;
711 afs_BioDaemon (nbiods)
712     afs_int32 nbiods;
713 {
714     afs_int32 code, s, pflg = 0;
715     label_t jmpbuf;
716     struct buf *bp, *bp1, *tbp1, *tbp2;         /* temp pointers only */
717     caddr_t tmpaddr;
718     struct vnode *vp;
719     struct vcache *vcp;
720     char tmperr;
721     if (!afs_initbiod) {
722         /* XXX ###1 XXX */
723         afs_initbiod = 1;
724         /* pin lock, since we'll be using it in an interrupt. */
725         lock_alloc(&afs_asyncbuf_lock, LOCK_ALLOC_PIN, 2, 1);
726         simple_lock_init(&afs_asyncbuf_lock);
727         pin (&afs_asyncbuf, sizeof(struct buf*));
728         pin (&afs_asyncbuf_cv, sizeof(afs_int32));
729     }
730
731     /* Ignore HUP signals... */
732 #ifdef AFS_AIX41_ENV
733     {
734         sigset_t sigbits, osigbits;
735         /*
736          * add SIGHUP to the set of already masked signals
737          */
738         SIGFILLSET(sigbits);                    /* allow all signals    */
739         SIGDELSET(sigbits, SIGHUP);             /*   except SIGHUP      */
740         limit_sigs(&sigbits, &osigbits);        /*   and already masked */
741     }
742 #else
743     SIGDELSET(u.u_procp->p_sig, SIGHUP);
744     SIGADDSET(u.u_procp->p_sigignore, SIGHUP);
745     SIGDELSET(u.u_procp->p_sigcatch, SIGHUP);
746 #endif
747     /* Main body starts here -- this is an intentional infinite loop, and
748      * should NEVER exit 
749      *
750      * Now, the loop will exit if get_bioreq() returns NULL, indicating 
751      * that we've been interrupted.
752      */
753     while (1) {
754         bp = afs_get_bioreq();
755         if (!bp)
756             break;      /* we were interrupted */
757         if (code = setjmpx(&jmpbuf)) {
758             /* This should not have happend, maybe a lack of resources  */
759             AFS_GUNLOCK();
760             s = disable_lock(INTMAX, &afs_asyncbuf_lock);
761             for (bp1 = bp; bp ; bp = bp1) {
762                 if (bp1)
763                     bp1 = (struct buf *) bp1->b_work;
764                 bp->b_actf = 0;
765                 bp->b_error = code;
766                 bp->b_flags |= B_ERROR;
767                 iodone(bp);
768             }
769             unlock_enable(s, &afs_asyncbuf_lock);
770             AFS_GLOCK();
771             continue;
772         }
773         vcp = (struct vcache *)bp->b_vp;
774         if (bp->b_flags & B_PFSTORE) {  /* XXXX */
775             ObtainWriteLock(&vcp->lock,404);        
776             if (vcp->v.v_gnode->gn_mwrcnt) {
777                 if (vcp->m.Length < bp->b_bcount + (u_int)dbtob(bp->b_blkno))
778                     vcp->m.Length = bp->b_bcount + (u_int)dbtob(bp->b_blkno);
779             }
780             ReleaseWriteLock(&vcp->lock);
781         }
782         /* If the buffer represents a protection violation, rather than
783          * an actual request for I/O, no special action need be taken.  
784          */
785         if ( bp->b_flags & B_PFPROT ) {   
786             iodone (bp);    /* Notify all users of the buffer that we're done */
787             clrjmpx(&jmpbuf);
788             continue;
789         }
790 if (DOvmlock)
791         ObtainWriteLock(&vcp->pvmlock,211);     
792         /*
793          * First map its data area to a region in the current address space
794          * by calling vm_att with the subspace identifier, and a pointer to
795          * the data area.  vm_att returns  a new data area pointer, but we
796          * also want to hang onto the old one.
797          */
798         tmpaddr = bp->b_baddr;
799         bp->b_baddr = vm_att (bp->b_xmemd.subspace_id, tmpaddr);
800         tmperr = afs_ustrategy(bp);     /* temp variable saves offset calculation */
801         if (tmperr) {                   /* in non-error case */
802             bp->b_flags |= B_ERROR;             /* should other flags remain set ??? */
803             bp->b_error = tmperr;
804         }
805
806         /* Unmap the buffer's data area by calling vm_det.  Reset data area
807          * to the value that we saved above.
808          */
809         vm_det(bp->b_un.b_addr);
810         bp->b_baddr = tmpaddr;
811
812         /*
813          * buffer may be linked with other buffers via the b_work field.
814          * See also naix_vm_strategy.  For each buffer in the chain (including
815          * bp) notify all users of the buffer that the daemon is finished
816          * using it by calling iodone.  
817          * assumes iodone can modify the b_work field.
818          */
819         for(tbp1=bp;;) {
820             tbp2 = (struct buf *) tbp1->b_work;
821             iodone(tbp1);
822             if (!tbp2) 
823                 break;
824
825             tbp1 = (struct buf *) tbp2->b_work;
826             iodone(tbp2);
827             if (!tbp1)
828                 break;
829         }
830 if (DOvmlock)
831         ReleaseWriteLock(&vcp->pvmlock);     /* Unlock the vnode.  */
832         clrjmpx(&jmpbuf);
833     } /* infinite loop (unless we're interrupted) */
834 } /* end of afs_BioDaemon() */
835
836 #else /* AFS_AIX41_ENV */
837
838
839 #define squeue afs_q
840 struct afs_bioqueue {
841     struct squeue lruq;
842     int sleeper;
843     int cnt;
844 };
845 struct afs_bioqueue afs_bioqueue;
846 struct buf *afs_busyq = NULL;
847 struct buf *afs_asyncbuf;
848 afs_int32 afs_biodcnt = 0;
849
850 /* in implementing this, I assumed that all external linked lists were
851  * null-terminated.  
852  *
853  * Several places in this code traverse a linked list.  The algorithm
854  * used here is probably unfamiliar to most people.  Careful examination
855  * will show that it eliminates an assignment inside the loop, as compared
856  * to the standard algorithm, at the cost of occasionally using an extra
857  * variable.
858  */
859
860 /* get_bioreq()
861  *
862  * This function obtains, and returns, a pointer to a buffer for
863  * processing by a daemon.  It sleeps until such a buffer is available.
864  * The source of buffers for it is the list afs_asyncbuf (see also 
865  * naix_vm_strategy).  This function may be invoked concurrently by
866  * several processes, that is, several instances of the same daemon.
867  * naix_vm_strategy, which adds buffers to the list, runs at interrupt
868  * level, while get_bioreq runs at process level.
869  *
870  * The common kernel paradigm of sleeping and waking up, in which all the
871  * competing processes sleep waiting for wakeups on one address, is not
872  * followed here.  Instead, the following paradigm is used:  when a daemon
873  * goes to sleep, it checks for other sleeping daemons.  If there aren't any,
874  * it sleeps on the address of variable afs_asyncbuf.  But if there is
875  * already a daemon sleeping on that address, it threads its own unique
876  * address onto a list, and sleeps on that address.  This way, every 
877  * sleeper is sleeping on a different address, and every wakeup wakes up
878  * exactly one daemon.  This prevents a whole bunch of daemons from waking
879  * up and then immediately having to go back to sleep.  This provides a
880  * performance gain and makes the I/O scheduling a bit more deterministic.
881  * The list of sleepers is variable afs_bioqueue.  The unique address
882  * on which to sleep is passed to get_bioreq as its parameter.
883  */
884 /*static*/ struct buf *afs_get_bioreq(self)
885     struct afs_bioqueue *self;      /* address on which to sleep */
886
887 {
888     struct buf *bp = (struct buf *) 0;
889     struct buf *bestbp;
890     struct buf **bestlbpP, **lbpP;
891     int bestage, stop;
892     struct buf *t1P, *t2P;      /* temp pointers for list manipulation */
893     int oldPriority;
894     afs_uint32 wait_ret;
895 struct afs_bioqueue *s;
896
897     /* ??? Does the forward pointer of the returned buffer need to be NULL?
898     */
899     
900         /* Disable interrupts from the strategy function, and save the 
901          * prior priority level
902          */
903         oldPriority = i_disable ( INTMAX ) ;
904
905         /* Each iteration of following loop either pulls
906          * a buffer off afs_asyncbuf, or sleeps.  
907          */
908         while (1) {   /* inner loop */
909                 if (afs_asyncbuf) {
910                         /* look for oldest buffer */
911                         bp = bestbp = afs_asyncbuf;
912                         bestage = (int) bestbp->av_back;
913                         bestlbpP = &afs_asyncbuf;
914                         while (1) {
915                                 lbpP = &bp->av_forw;
916                                 bp = *lbpP;
917                                 if (!bp) break;
918                                 if ((int) bp->av_back - bestage < 0) {
919                                         bestbp = bp;
920                                         bestlbpP = lbpP;
921                                         bestage = (int) bp->av_back;
922                                 }
923                         }
924                         bp = bestbp;
925                         *bestlbpP = bp->av_forw;
926                         break;  
927                         }
928                 else {
929                         int interrupted;
930
931                 /* If afs_asyncbuf is null, it is necessary to go to sleep.
932                  * There are two possibilities:  either there is already a
933                  * daemon that is sleeping on the address of afs_asyncbuf,
934                  * or there isn't. 
935                  */
936                         if (afs_bioqueue.sleeper) {
937                                 /* enqueue */
938                                 QAdd (&(afs_bioqueue.lruq), &(self->lruq));
939                                 interrupted = sleep ((caddr_t) self, PCATCH|(PZERO + 1));
940                                 if (self->lruq.next != &self->lruq) {   /* XXX ##3 XXX */
941                                     QRemove (&(self->lruq));            /* dequeue */
942                                 }
943 self->cnt++;
944                                 afs_bioqueue.sleeper = FALSE;
945                                 if (interrupted) {
946                                     /* re-enable interrupts from strategy */
947                                     i_enable (oldPriority);
948                                     return(NULL);
949                                 }
950                                 continue;
951                         } else {
952                                 afs_bioqueue.sleeper = TRUE;
953                                 interrupted = sleep ((caddr_t) &afs_asyncbuf, PCATCH|(PZERO + 1));
954                                 afs_bioqueue.sleeper = FALSE;
955                                 if (interrupted)
956                                 {
957                                     /*
958                                      * We need to wakeup another daemon if present
959                                      * since we were waiting on afs_asyncbuf.
960                                      */
961 #ifdef  notdef  /* The following doesn't work as advertised */                              
962                                      if (afs_bioqueue.lruq.next != &afs_bioqueue.lruq)
963                                      {
964                                          struct squeue *bq = afs_bioqueue.lruq.next;
965                                          QRemove (bq);
966                                          wakeup (bq);
967                                      }
968 #endif
969                                     /* re-enable interrupts from strategy */
970                                      i_enable (oldPriority);
971                                      return(NULL);
972                                  }
973                                 continue;
974                                 }
975
976                         }  /* end of "else asyncbuf is empty" */
977                 } /* end of "inner loop" */
978
979         /*assert (bp);*/
980
981         i_enable (oldPriority);     /* re-enable interrupts from strategy */
982
983         /* For the convenience of other code, replace the gnodes in
984          * the b_vp field of bp and the other buffers on the b_work
985          * chain with the corresponding vnodes.   
986          *
987          * ??? what happens to the gnodes?  They're not just cut loose,
988          * are they?
989          */
990         for(t1P=bp;;) {
991                 t2P = (struct buf *) t1P->b_work;
992                 t1P->b_vp = ((struct gnode *) t1P->b_vp)->gn_vnode;
993                 if (!t2P) 
994                         break;
995
996                 t1P = (struct buf *) t2P->b_work;
997                 t2P->b_vp = ((struct gnode *) t2P->b_vp)->gn_vnode;
998                 if (!t1P)
999                         break;
1000                 }
1001
1002         /* If the buffer does not specify I/O, it may immediately
1003          * be returned to the caller.  This condition is detected
1004          * by examining the buffer's flags (the b_flags field).  If
1005          * the B_PFPROT bit is set, the buffer represents a protection
1006          * violation, rather than a request for I/O.  The remainder
1007          * of the outer loop handles the case where the B_PFPROT bit is clear.
1008          */
1009          if (bp->b_flags & B_PFPROT)  {
1010                 return (bp);
1011             }
1012
1013         /* wake up another process to handle the next buffer, and return
1014          * bp to the caller.
1015          */
1016         oldPriority = i_disable ( INTMAX ) ;
1017
1018         /* determine where to find the sleeping process. 
1019          * There are two cases: either it is sleeping on
1020          * afs_asyncbuf, or it is sleeping on its own unique
1021          * address.  These cases are distinguished by examining
1022          * the sleeper field of afs_bioqueue.
1023          */
1024         if (afs_bioqueue.sleeper) {
1025                 wakeup (&afs_asyncbuf);
1026                 }
1027         else {
1028                 if (afs_bioqueue.lruq.next == &afs_bioqueue.lruq) {
1029                         /* queue is empty, what now? ???*/
1030                         /* Should this be impossible, or does    */
1031                         /* it just mean that nobody is sleeping? */;
1032                         }
1033                 else {
1034                         struct squeue *bq = afs_bioqueue.lruq.next;
1035                         QRemove (bq);
1036                         QInit (bq);
1037                         wakeup (bq);
1038                         afs_bioqueue.sleeper = TRUE; 
1039                         }
1040                 }
1041         i_enable (oldPriority);     /* re-enable interrupts from strategy */
1042         return (bp);
1043
1044 } /* end of function get_bioreq() */
1045
1046
1047 /* afs_BioDaemon
1048  *
1049  * This function is the daemon.  It is called from the syscall
1050  * interface.  Ordinarily, a script or an administrator will run a
1051  * daemon startup utility, specifying the number of I/O daemons to
1052  * run.  The utility will fork off that number of processes,
1053  * each making the appropriate syscall, which will cause this
1054  * function to be invoked.
1055  */
1056 static int afs_initbiod = 0;            /* this is self-initializing code */
1057 int DOvmlock = 0;
1058 afs_BioDaemon (nbiods)
1059     afs_int32 nbiods;
1060 {
1061     struct afs_bioqueue *self;
1062     afs_int32 code, s, pflg = 0;
1063     label_t jmpbuf;
1064     struct buf *bp, *bp1, *tbp1, *tbp2;         /* temp pointers only */
1065     caddr_t tmpaddr;
1066     struct vnode *vp;
1067     struct vcache *vcp;
1068     char tmperr;
1069     if (!afs_initbiod) {
1070         /* XXX ###1 XXX */
1071         afs_initbiod = 1;
1072         /* Initialize the queue of waiting processes, afs_bioqueue.  */
1073         QInit (&(afs_bioqueue.lruq));           
1074     }
1075
1076     /* establish ourself as a kernel process so shutdown won't kill us */
1077 /*    u.u_procp->p_flag |= SKPROC;*/
1078
1079     /* Initialize a token (self) to use in the queue of sleeping processes.   */
1080     self = (struct afs_bioqueue *) afs_osi_Alloc (sizeof (struct afs_bioqueue));
1081     pin (self, sizeof (struct afs_bioqueue)); /* fix in memory */
1082     memset(self, 0, sizeof(*self));
1083     QInit (&(self->lruq));              /* initialize queue entry pointers */
1084
1085
1086     /* Ignore HUP signals... */
1087 #ifdef AFS_AIX41_ENV
1088     {
1089         sigset_t sigbits, osigbits;
1090         /*
1091          * add SIGHUP to the set of already masked signals
1092          */
1093         SIGFILLSET(sigbits);                    /* allow all signals    */
1094         SIGDELSET(sigbits, SIGHUP);             /*   except SIGHUP      */
1095         limit_sigs(&sigbits, &osigbits);        /*   and already masked */
1096     }
1097 #else
1098     SIGDELSET(u.u_procp->p_sig, SIGHUP);
1099     SIGADDSET(u.u_procp->p_sigignore, SIGHUP);
1100     SIGDELSET(u.u_procp->p_sigcatch, SIGHUP);
1101 #endif
1102     /* Main body starts here -- this is an intentional infinite loop, and
1103      * should NEVER exit 
1104      *
1105      * Now, the loop will exit if get_bioreq() returns NULL, indicating 
1106      * that we've been interrupted.
1107      */
1108     while (1) {
1109         bp = afs_get_bioreq(self);
1110         if (!bp)
1111             break;      /* we were interrupted */
1112         if (code = setjmpx(&jmpbuf)) {
1113             /* This should not have happend, maybe a lack of resources  */
1114             s = splimp();
1115             for (bp1 = bp; bp ; bp = bp1) {
1116                 if (bp1)
1117                     bp1 = bp1->b_work;
1118                 bp->b_actf = 0;
1119                 bp->b_error = code;
1120                 bp->b_flags |= B_ERROR;
1121                 iodone(bp);
1122             }
1123             splx(s);
1124             continue;
1125         }
1126         vcp = (struct vcache *)bp->b_vp;
1127         if (bp->b_flags & B_PFSTORE) {
1128             ObtainWriteLock(&vcp->lock,210);        
1129             if (vcp->v.v_gnode->gn_mwrcnt) {
1130                 if (vcp->m.Length < bp->b_bcount + (u_int)dbtob(bp->b_blkno))
1131                     vcp->m.Length = bp->b_bcount + (u_int)dbtob(bp->b_blkno);
1132             }
1133             ReleaseWriteLock(&vcp->lock);
1134         }
1135         /* If the buffer represents a protection violation, rather than
1136          * an actual request for I/O, no special action need be taken.  
1137          */
1138         if ( bp->b_flags & B_PFPROT ) {   
1139             iodone (bp);    /* Notify all users of the buffer that we're done */
1140             continue;
1141         }
1142 if (DOvmlock)
1143         ObtainWriteLock(&vcp->pvmlock,558);     
1144         /*
1145          * First map its data area to a region in the current address space
1146          * by calling vm_att with the subspace identifier, and a pointer to
1147          * the data area.  vm_att returns  a new data area pointer, but we
1148          * also want to hang onto the old one.
1149          */
1150         tmpaddr = bp->b_baddr;
1151         bp->b_baddr = vm_att (bp->b_xmemd.subspace_id, tmpaddr);
1152         tmperr = afs_ustrategy(bp);     /* temp variable saves offset calculation */
1153         if (tmperr) {                   /* in non-error case */
1154             bp->b_flags |= B_ERROR;             /* should other flags remain set ??? */
1155             bp->b_error = tmperr;
1156         }
1157
1158         /* Unmap the buffer's data area by calling vm_det.  Reset data area
1159          * to the value that we saved above.
1160          */
1161         vm_det(bp->b_un.b_addr);
1162         bp->b_baddr = tmpaddr;
1163
1164         /*
1165          * buffer may be linked with other buffers via the b_work field.
1166          * See also naix_vm_strategy.  For each buffer in the chain (including
1167          * bp) notify all users of the buffer that the daemon is finished
1168          * using it by calling iodone.  
1169          * assumes iodone can modify the b_work field.
1170          */
1171         for(tbp1=bp;;) {
1172             tbp2 = (struct buf *) tbp1->b_work;
1173             iodone(tbp1);
1174             if (!tbp2) 
1175                 break;
1176
1177             tbp1 = (struct buf *) tbp2->b_work;
1178             iodone(tbp2);
1179             if (!tbp1)
1180                 break;
1181         }
1182 if (DOvmlock)
1183         ReleaseWriteLock(&vcp->pvmlock);     /* Unlock the vnode.  */
1184         clrjmpx(&jmpbuf);
1185     } /* infinite loop (unless we're interrupted) */
1186     unpin (self, sizeof (struct afs_bioqueue));
1187     afs_osi_Free (self, sizeof (struct afs_bioqueue));
1188 } /* end of afs_BioDaemon() */
1189 #endif /* AFS_AIX41_ENV */ 
1190 #endif /* AFS_AIX32_ENV */
1191
1192
1193 int afs_nbrs = 0;
1194 void afs_BackgroundDaemon() {
1195     struct brequest *tb;
1196     int i, foundAny;
1197     afs_int32 pid;
1198
1199     AFS_STATCNT(afs_BackgroundDaemon);
1200     /* initialize subsystem */
1201     if (brsInit == 0) {
1202         LOCK_INIT(&afs_xbrs, "afs_xbrs");
1203         memset((char *)afs_brs, 0, sizeof(afs_brs));
1204         brsInit = 1;
1205 #if defined (AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
1206         /*
1207          * steal the first daemon for doing delayed DSlot flushing
1208          * (see afs_GetDownDSlot)
1209          */
1210         AFS_GUNLOCK();
1211         afs_sgidaemon();
1212         return;
1213 #endif
1214     }
1215     afs_nbrs++;
1216
1217     MObtainWriteLock(&afs_xbrs,302);
1218     while (1) {
1219         if (afs_termState == AFSOP_STOP_BKG) {
1220             if (--afs_nbrs <= 0)
1221                 afs_termState = AFSOP_STOP_TRUNCDAEMON;
1222             MReleaseWriteLock(&afs_xbrs);
1223             afs_osi_Wakeup(&afs_termState);
1224             return;
1225         }
1226         
1227         /* find a request */
1228         tb = afs_brs;
1229         foundAny = 0;
1230         for(i=0;i<NBRS;i++,tb++) {
1231             /* look for request */
1232             if ((tb->refCount > 0) && !(tb->flags & BSTARTED)) {
1233                 /* new request, not yet picked up */
1234                 tb->flags |= BSTARTED;
1235                 MReleaseWriteLock(&afs_xbrs);
1236                 foundAny = 1;
1237                 afs_Trace1(afs_iclSetp, CM_TRACE_BKG1,
1238                            ICL_TYPE_INT32, tb->opcode);
1239                 if (tb->opcode == BOP_FETCH)
1240                     BPrefetch(tb);
1241                 else if (tb->opcode == BOP_STORE)
1242                     BStore(tb);
1243                 else if (tb->opcode == BOP_PATH)
1244                     BPath(tb);
1245                 else panic("background bop");
1246                 if (tb->vnode) {
1247 #ifdef  AFS_DEC_ENV
1248                     tb->vnode->vrefCount--;         /* fix up reference count */
1249 #else
1250                     AFS_RELE((struct vnode *)(tb->vnode));      /* MUST call vnode layer or could lose vnodes */
1251 #endif
1252                     tb->vnode = (struct vcache *) 0;
1253                 }
1254                 if (tb->cred) {
1255                     crfree(tb->cred);
1256                     tb->cred = (struct AFS_UCRED *) 0;
1257                 }
1258                 afs_BRelease(tb);   /* this grabs and releases afs_xbrs lock */
1259                 MObtainWriteLock(&afs_xbrs,305);
1260             }
1261         }
1262         if (!foundAny) {
1263             /* wait for new request */
1264             afs_brsDaemons++;
1265             MReleaseWriteLock(&afs_xbrs);
1266             afs_osi_Sleep(&afs_brsDaemons);
1267             MObtainWriteLock(&afs_xbrs,307);
1268             afs_brsDaemons--;
1269         }
1270     }
1271 }
1272
1273
1274 void shutdown_daemons()
1275 {
1276   extern int afs_cold_shutdown;
1277   register int i;
1278   register struct brequest *tb;
1279
1280   AFS_STATCNT(shutdown_daemons);
1281   if (afs_cold_shutdown) {
1282       afs_brsDaemons = brsInit = 0;
1283       rxepoch_checked = afs_nbrs = 0;
1284       memset((char *)afs_brs, 0, sizeof(afs_brs));
1285       memset((char *)&afs_xbrs, 0, sizeof(afs_lock_t));
1286       afs_brsWaiters = 0;
1287 #ifdef AFS_AIX32_ENV
1288 #ifdef AFS_AIX41_ENV
1289       lock_free(&afs_asyncbuf_lock);
1290       unpin(&afs_asyncbuf, sizeof(struct buf*));
1291       pin (&afs_asyncbuf_cv, sizeof(afs_int32));
1292 #else /* AFS_AIX41_ENV */
1293       afs_busyq = NULL;
1294       afs_biodcnt = 0;
1295       memset((char *)&afs_bioqueue, 0, sizeof(struct afs_bioqueue));
1296 #endif
1297       afs_initbiod = 0;
1298 #endif
1299   }
1300 }
1301
1302 #if defined(AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
1303 /*
1304  * sgi - daemon - handles certain operations that otherwise
1305  * would use up too much kernel stack space
1306  *
1307  * This all assumes that since the caller must have the xdcache lock
1308  * exclusively that the list will never be more than one long
1309  * and noone else can attempt to add anything until we're done.
1310  */
1311 SV_TYPE afs_sgibksync;
1312 SV_TYPE afs_sgibkwait;
1313 lock_t afs_sgibklock;
1314 struct dcache *afs_sgibklist;
1315
1316 int
1317 afs_sgidaemon(void)
1318 {
1319         int s;
1320         struct dcache *tdc;
1321
1322         if (afs_sgibklock == NULL) {
1323                 SV_INIT(&afs_sgibksync, "bksync", 0, 0);
1324                 SV_INIT(&afs_sgibkwait, "bkwait", 0, 0);
1325                 SPINLOCK_INIT(&afs_sgibklock, "bklock");
1326         }
1327         s = SPLOCK(afs_sgibklock);
1328         for (;;) {
1329                 /* wait for something to do */
1330                 SP_WAIT(afs_sgibklock, s, &afs_sgibksync, PINOD);
1331                 osi_Assert(afs_sgibklist);
1332
1333                 /* XX will probably need to generalize to real list someday */
1334                 s = SPLOCK(afs_sgibklock);
1335                 while (afs_sgibklist) {
1336                         tdc = afs_sgibklist;
1337                         afs_sgibklist = NULL;
1338                         SPUNLOCK(afs_sgibklock, s);
1339                         AFS_GLOCK();
1340                         tdc->flags &= ~DFEntryMod;
1341                         afs_WriteDCache(tdc, 1);
1342                         AFS_GUNLOCK();
1343                         s = SPLOCK(afs_sgibklock);
1344                 }
1345
1346                 /* done all the work - wake everyone up */
1347                 while (SV_SIGNAL(&afs_sgibkwait))
1348                         ;
1349         }
1350 }
1351 #endif