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