more-64bit-client-fixes-20011110
[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     tdc->flags &= ~DFFetchReq;
437     afs_osi_Wakeup(&tdc->validPos);
438     if (ab->size_parm[1]) {
439 #ifdef  AFS_SUN5_ENVX
440         mutex_enter(&tdc->lock);
441         tdc->refCount--;
442         mutex_exit(&tdc->lock);
443 #else
444         afs_PutDCache(tdc);     /* put this one back, too */
445 #endif
446     }
447 }
448
449
450 void BStore(ab)
451     register struct brequest *ab; {
452     register struct vcache *tvc;
453     register afs_int32 code;
454     struct vrequest treq;
455 #if defined(AFS_SGI_ENV)
456     struct cred *tmpcred;
457 #endif
458
459     AFS_STATCNT(BStore);
460     if (code = afs_InitReq(&treq, ab->cred)) return;
461     code = 0;
462     tvc = ab->vnode;
463 #if defined(AFS_SGI_ENV)
464     /*
465      * Since StoreOnLastReference can end up calling osi_SyncVM which
466      * calls into VM code that assumes that u.u_cred has the
467      * correct credentials, we set our to theirs for this xaction
468      */
469     tmpcred = OSI_GET_CURRENT_CRED();
470     OSI_SET_CURRENT_CRED(ab->cred);
471
472     /*
473      * To avoid recursion since the WriteLock may be released during VM
474      * operations, we hold the VOP_RWLOCK across this transaction as
475      * do the other callers of StoreOnLastReference
476      */
477     AFS_RWLOCK((vnode_t *)tvc, 1);
478 #endif
479     ObtainWriteLock(&tvc->lock,209);
480     code = afs_StoreOnLastReference(tvc, &treq);
481     ReleaseWriteLock(&tvc->lock);
482 #if defined(AFS_SGI_ENV)
483     OSI_SET_CURRENT_CRED(tmpcred);
484     AFS_RWUNLOCK((vnode_t *)tvc, 1);
485 #endif
486     /* now set final return code, and wakeup anyone waiting */
487     if ((ab->flags & BUVALID) == 0) {
488         ab->code = afs_CheckCode(code, &treq, 43);    /* set final code, since treq doesn't go across processes */
489         ab->flags |= BUVALID;
490         if (ab->flags & BUWAIT) {
491             ab->flags &= ~BUWAIT;
492             afs_osi_Wakeup(ab);
493         }
494     }
495 }
496
497 /* release a held request buffer */
498 void afs_BRelease(ab)
499     register struct brequest *ab; {
500
501     AFS_STATCNT(afs_BRelease);
502     MObtainWriteLock(&afs_xbrs,294);
503     if (--ab->refCount <= 0) {
504         ab->flags = 0;
505     }
506     if (afs_brsWaiters) afs_osi_Wakeup(&afs_brsWaiters);
507     MReleaseWriteLock(&afs_xbrs);
508 }
509
510 /* return true if bkg fetch daemons are all busy */
511 int afs_BBusy() {
512     AFS_STATCNT(afs_BBusy);
513     if (afs_brsDaemons > 0) return 0;
514     return 1;
515 }
516
517 struct brequest *afs_BQueue(aopcode, avc, dontwait, ause, acred, asparm0, asparm1, apparm0)
518     register short aopcode;
519     afs_int32 ause, dontwait;
520     register struct vcache *avc;
521     struct AFS_UCRED *acred;
522     afs_size_t asparm0, asparm1;
523     void *apparm0;
524 {
525     register int i;
526     register struct brequest *tb;
527
528     AFS_STATCNT(afs_BQueue);
529     MObtainWriteLock(&afs_xbrs,296);
530     while (1) {
531         tb = afs_brs;
532         for(i=0;i<NBRS;i++,tb++) {
533             if (tb->refCount == 0) break;
534         }
535         if (i < NBRS) {
536             /* found a buffer */
537             tb->opcode = aopcode;
538             tb->vnode = avc;
539             tb->cred = acred;
540             crhold(tb->cred);
541             if (avc) {
542 #ifdef  AFS_DEC_ENV
543                 avc->vrefCount++;
544 #else
545                 VN_HOLD((struct vnode *)avc);
546 #endif
547             }
548             tb->refCount = ause+1;
549             tb->size_parm[0] = asparm0;
550             tb->size_parm[1] = asparm1;
551             tb->ptr_parm[0]  = apparm0;
552             tb->flags = 0;
553             tb->code = 0;
554             tb->ts = afs_brs_count++;
555             /* if daemons are waiting for work, wake them up */
556             if (afs_brsDaemons > 0) {
557                 afs_osi_Wakeup(&afs_brsDaemons);
558             }
559             MReleaseWriteLock(&afs_xbrs);
560             return tb;
561         }
562         if (dontwait) {
563             MReleaseWriteLock(&afs_xbrs);
564             return (struct brequest *)0;
565         }
566         /* no free buffers, sleep a while */
567         afs_brsWaiters++;
568         MReleaseWriteLock(&afs_xbrs);
569         afs_osi_Sleep(&afs_brsWaiters);
570         MObtainWriteLock(&afs_xbrs,301);
571         afs_brsWaiters--;
572     }
573 }
574
575 #ifdef  AFS_AIX32_ENV
576 #ifdef AFS_AIX41_ENV
577 /* AIX 4.1 has a much different sleep/wakeup mechanism available for use. 
578  * The modifications here will work for either a UP or MP machine.
579  */
580 struct buf *afs_asyncbuf = (struct buf*)0;
581 afs_int32 afs_asyncbuf_cv = EVENT_NULL;
582 afs_int32 afs_biodcnt = 0;
583
584 /* in implementing this, I assumed that all external linked lists were
585  * null-terminated.  
586  *
587  * Several places in this code traverse a linked list.  The algorithm
588  * used here is probably unfamiliar to most people.  Careful examination
589  * will show that it eliminates an assignment inside the loop, as compared
590  * to the standard algorithm, at the cost of occasionally using an extra
591  * variable.
592  */
593
594 /* get_bioreq()
595  *
596  * This function obtains, and returns, a pointer to a buffer for
597  * processing by a daemon.  It sleeps until such a buffer is available.
598  * The source of buffers for it is the list afs_asyncbuf (see also 
599  * naix_vm_strategy).  This function may be invoked concurrently by
600  * several processes, that is, several instances of the same daemon.
601  * naix_vm_strategy, which adds buffers to the list, runs at interrupt
602  * level, while get_bioreq runs at process level.
603  *
604  * Since AIX 4.1 can wake just one process at a time, the separate sleep
605  * addresses have been removed.
606  * Note that the kernel_lock is held until the e_sleep_thread() occurs. 
607  * The afs_asyncbuf_lock is primarily used to serialize access between
608  * process and interrupts.
609  */
610 Simple_lock afs_asyncbuf_lock;
611 /*static*/ struct buf *afs_get_bioreq()
612 {
613     struct buf *bp = (struct buf *) 0;
614     struct buf *bestbp;
615     struct buf **bestlbpP, **lbpP;
616     int bestage, stop;
617     struct buf *t1P, *t2P;      /* temp pointers for list manipulation */
618     int oldPriority;
619     afs_uint32 wait_ret;
620     struct afs_bioqueue *s;
621
622     /* ??? Does the forward pointer of the returned buffer need to be NULL?
623     */
624     
625     /* Disable interrupts from the strategy function, and save the 
626      * prior priority level and lock access to the afs_asyncbuf.
627      */
628     AFS_GUNLOCK();
629     oldPriority = disable_lock(INTMAX, &afs_asyncbuf_lock) ;
630
631     while(1) {
632         if (afs_asyncbuf) {
633             /* look for oldest buffer */
634             bp = bestbp = afs_asyncbuf;
635             bestage = (int) bestbp->av_back;
636             bestlbpP = &afs_asyncbuf;
637             while (1) {
638                 lbpP = &bp->av_forw;
639                 bp = *lbpP;
640                 if (!bp) break;
641                 if ((int) bp->av_back - bestage < 0) {
642                     bestbp = bp;
643                     bestlbpP = lbpP;
644                     bestage = (int) bp->av_back;
645                 }
646             }
647             bp = bestbp;
648             *bestlbpP = bp->av_forw;
649             break;
650         }
651         else {
652             /* If afs_asyncbuf is null, it is necessary to go to sleep.
653              * e_wakeup_one() ensures that only one thread wakes.
654              */
655             int interrupted;
656             /* The LOCK_HANDLER indicates to e_sleep_thread to only drop the
657              * lock on an MP machine.
658              */
659             interrupted = e_sleep_thread(&afs_asyncbuf_cv,
660                                          &afs_asyncbuf_lock,
661                                          LOCK_HANDLER|INTERRUPTIBLE);
662             if (interrupted==THREAD_INTERRUPTED) {
663                 /* re-enable interrupts from strategy */
664                 unlock_enable(oldPriority, &afs_asyncbuf_lock);
665                 AFS_GLOCK();
666                 return(NULL);
667             }
668         }  /* end of "else asyncbuf is empty" */
669     } /* end of "inner loop" */
670     
671     /*assert (bp);*/
672     
673     unlock_enable(oldPriority, &afs_asyncbuf_lock);
674     AFS_GLOCK();
675
676     /* For the convenience of other code, replace the gnodes in
677      * the b_vp field of bp and the other buffers on the b_work
678      * chain with the corresponding vnodes.   
679      *
680      * ??? what happens to the gnodes?  They're not just cut loose,
681      * are they?
682      */
683     for(t1P=bp;;) {
684         t2P = (struct buf *) t1P->b_work;
685         t1P->b_vp = ((struct gnode *) t1P->b_vp)->gn_vnode;
686         if (!t2P) 
687             break;
688
689         t1P = (struct buf *) t2P->b_work;
690         t2P->b_vp = ((struct gnode *) t2P->b_vp)->gn_vnode;
691         if (!t1P)
692             break;
693     }
694
695     /* If the buffer does not specify I/O, it may immediately
696      * be returned to the caller.  This condition is detected
697      * by examining the buffer's flags (the b_flags field).  If
698      * the B_PFPROT bit is set, the buffer represents a protection
699      * violation, rather than a request for I/O.  The remainder
700      * of the outer loop handles the case where the B_PFPROT bit is clear.
701      */
702     if (bp->b_flags & B_PFPROT)  {
703         return (bp);
704     }
705     return (bp);
706
707 } /* end of function get_bioreq() */
708
709
710 /* afs_BioDaemon
711  *
712  * This function is the daemon.  It is called from the syscall
713  * interface.  Ordinarily, a script or an administrator will run a
714  * daemon startup utility, specifying the number of I/O daemons to
715  * run.  The utility will fork off that number of processes,
716  * each making the appropriate syscall, which will cause this
717  * function to be invoked.
718  */
719 static int afs_initbiod = 0;            /* this is self-initializing code */
720 int DOvmlock = 0;
721 afs_BioDaemon (nbiods)
722     afs_int32 nbiods;
723 {
724     afs_int32 code, s, pflg = 0;
725     label_t jmpbuf;
726     struct buf *bp, *bp1, *tbp1, *tbp2;         /* temp pointers only */
727     caddr_t tmpaddr;
728     struct vnode *vp;
729     struct vcache *vcp;
730     char tmperr;
731     if (!afs_initbiod) {
732         /* XXX ###1 XXX */
733         afs_initbiod = 1;
734         /* pin lock, since we'll be using it in an interrupt. */
735         lock_alloc(&afs_asyncbuf_lock, LOCK_ALLOC_PIN, 2, 1);
736         simple_lock_init(&afs_asyncbuf_lock);
737         pin (&afs_asyncbuf, sizeof(struct buf*));
738         pin (&afs_asyncbuf_cv, sizeof(afs_int32));
739     }
740
741     /* Ignore HUP signals... */
742     {
743         sigset_t sigbits, osigbits;
744         /*
745          * add SIGHUP to the set of already masked signals
746          */
747         SIGFILLSET(sigbits);                    /* allow all signals    */
748         SIGDELSET(sigbits, SIGHUP);             /*   except SIGHUP      */
749         limit_sigs(&sigbits, &osigbits);        /*   and already masked */
750     }
751     /* Main body starts here -- this is an intentional infinite loop, and
752      * should NEVER exit 
753      *
754      * Now, the loop will exit if get_bioreq() returns NULL, indicating 
755      * that we've been interrupted.
756      */
757     while (1) {
758         bp = afs_get_bioreq();
759         if (!bp)
760             break;      /* we were interrupted */
761         if (code = setjmpx(&jmpbuf)) {
762             /* This should not have happend, maybe a lack of resources  */
763             AFS_GUNLOCK();
764             s = disable_lock(INTMAX, &afs_asyncbuf_lock);
765             for (bp1 = bp; bp ; bp = bp1) {
766                 if (bp1)
767                     bp1 = (struct buf *) bp1->b_work;
768                 bp->b_actf = 0;
769                 bp->b_error = code;
770                 bp->b_flags |= B_ERROR;
771                 iodone(bp);
772             }
773             unlock_enable(s, &afs_asyncbuf_lock);
774             AFS_GLOCK();
775             continue;
776         }
777         vcp = (struct vcache *)bp->b_vp;
778         if (bp->b_flags & B_PFSTORE) {  /* XXXX */
779             ObtainWriteLock(&vcp->lock,404);        
780             if (vcp->v.v_gnode->gn_mwrcnt) {
781                 afs_offs_t newlength = 
782                         (afs_offs_t) dbtob(bp->b_blkno) + bp->b_bcount;
783                 if (vcp->m.Length < newlength) {
784                     afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
785                         ICL_TYPE_STRING, __FILE__,
786                         ICL_TYPE_LONG, __LINE__,
787                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(vcp->m.Length),
788                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(newlength));
789                     vcp->m.Length = newlength;
790                 }
791             }
792             ReleaseWriteLock(&vcp->lock);
793         }
794         /* If the buffer represents a protection violation, rather than
795          * an actual request for I/O, no special action need be taken.  
796          */
797         if ( bp->b_flags & B_PFPROT ) {   
798             iodone (bp);    /* Notify all users of the buffer that we're done */
799             clrjmpx(&jmpbuf);
800             continue;
801         }
802 if (DOvmlock)
803         ObtainWriteLock(&vcp->pvmlock,211);     
804         /*
805          * First map its data area to a region in the current address space
806          * by calling vm_att with the subspace identifier, and a pointer to
807          * the data area.  vm_att returns  a new data area pointer, but we
808          * also want to hang onto the old one.
809          */
810         tmpaddr = bp->b_baddr;
811         bp->b_baddr = vm_att (bp->b_xmemd.subspace_id, tmpaddr);
812         tmperr = afs_ustrategy(bp);     /* temp variable saves offset calculation */
813         if (tmperr) {                   /* in non-error case */
814             bp->b_flags |= B_ERROR;             /* should other flags remain set ??? */
815             bp->b_error = tmperr;
816         }
817
818         /* Unmap the buffer's data area by calling vm_det.  Reset data area
819          * to the value that we saved above.
820          */
821         vm_det(bp->b_un.b_addr);
822         bp->b_baddr = tmpaddr;
823
824         /*
825          * buffer may be linked with other buffers via the b_work field.
826          * See also naix_vm_strategy.  For each buffer in the chain (including
827          * bp) notify all users of the buffer that the daemon is finished
828          * using it by calling iodone.  
829          * assumes iodone can modify the b_work field.
830          */
831         for(tbp1=bp;;) {
832             tbp2 = (struct buf *) tbp1->b_work;
833             iodone(tbp1);
834             if (!tbp2) 
835                 break;
836
837             tbp1 = (struct buf *) tbp2->b_work;
838             iodone(tbp2);
839             if (!tbp1)
840                 break;
841         }
842 if (DOvmlock)
843         ReleaseWriteLock(&vcp->pvmlock);     /* Unlock the vnode.  */
844         clrjmpx(&jmpbuf);
845     } /* infinite loop (unless we're interrupted) */
846 } /* end of afs_BioDaemon() */
847
848 #else /* AFS_AIX41_ENV */
849
850
851 #define squeue afs_q
852 struct afs_bioqueue {
853     struct squeue lruq;
854     int sleeper;
855     int cnt;
856 };
857 struct afs_bioqueue afs_bioqueue;
858 struct buf *afs_busyq = NULL;
859 struct buf *afs_asyncbuf;
860 afs_int32 afs_biodcnt = 0;
861
862 /* in implementing this, I assumed that all external linked lists were
863  * null-terminated.  
864  *
865  * Several places in this code traverse a linked list.  The algorithm
866  * used here is probably unfamiliar to most people.  Careful examination
867  * will show that it eliminates an assignment inside the loop, as compared
868  * to the standard algorithm, at the cost of occasionally using an extra
869  * variable.
870  */
871
872 /* get_bioreq()
873  *
874  * This function obtains, and returns, a pointer to a buffer for
875  * processing by a daemon.  It sleeps until such a buffer is available.
876  * The source of buffers for it is the list afs_asyncbuf (see also 
877  * naix_vm_strategy).  This function may be invoked concurrently by
878  * several processes, that is, several instances of the same daemon.
879  * naix_vm_strategy, which adds buffers to the list, runs at interrupt
880  * level, while get_bioreq runs at process level.
881  *
882  * The common kernel paradigm of sleeping and waking up, in which all the
883  * competing processes sleep waiting for wakeups on one address, is not
884  * followed here.  Instead, the following paradigm is used:  when a daemon
885  * goes to sleep, it checks for other sleeping daemons.  If there aren't any,
886  * it sleeps on the address of variable afs_asyncbuf.  But if there is
887  * already a daemon sleeping on that address, it threads its own unique
888  * address onto a list, and sleeps on that address.  This way, every 
889  * sleeper is sleeping on a different address, and every wakeup wakes up
890  * exactly one daemon.  This prevents a whole bunch of daemons from waking
891  * up and then immediately having to go back to sleep.  This provides a
892  * performance gain and makes the I/O scheduling a bit more deterministic.
893  * The list of sleepers is variable afs_bioqueue.  The unique address
894  * on which to sleep is passed to get_bioreq as its parameter.
895  */
896 /*static*/ struct buf *afs_get_bioreq(self)
897     struct afs_bioqueue *self;      /* address on which to sleep */
898
899 {
900     struct buf *bp = (struct buf *) 0;
901     struct buf *bestbp;
902     struct buf **bestlbpP, **lbpP;
903     int bestage, stop;
904     struct buf *t1P, *t2P;      /* temp pointers for list manipulation */
905     int oldPriority;
906     afs_uint32 wait_ret;
907 struct afs_bioqueue *s;
908
909     /* ??? Does the forward pointer of the returned buffer need to be NULL?
910     */
911     
912         /* Disable interrupts from the strategy function, and save the 
913          * prior priority level
914          */
915         oldPriority = i_disable ( INTMAX ) ;
916
917         /* Each iteration of following loop either pulls
918          * a buffer off afs_asyncbuf, or sleeps.  
919          */
920         while (1) {   /* inner loop */
921                 if (afs_asyncbuf) {
922                         /* look for oldest buffer */
923                         bp = bestbp = afs_asyncbuf;
924                         bestage = (int) bestbp->av_back;
925                         bestlbpP = &afs_asyncbuf;
926                         while (1) {
927                                 lbpP = &bp->av_forw;
928                                 bp = *lbpP;
929                                 if (!bp) break;
930                                 if ((int) bp->av_back - bestage < 0) {
931                                         bestbp = bp;
932                                         bestlbpP = lbpP;
933                                         bestage = (int) bp->av_back;
934                                 }
935                         }
936                         bp = bestbp;
937                         *bestlbpP = bp->av_forw;
938                         break;  
939                         }
940                 else {
941                         int interrupted;
942
943                 /* If afs_asyncbuf is null, it is necessary to go to sleep.
944                  * There are two possibilities:  either there is already a
945                  * daemon that is sleeping on the address of afs_asyncbuf,
946                  * or there isn't. 
947                  */
948                         if (afs_bioqueue.sleeper) {
949                                 /* enqueue */
950                                 QAdd (&(afs_bioqueue.lruq), &(self->lruq));
951                                 interrupted = sleep ((caddr_t) self, PCATCH|(PZERO + 1));
952                                 if (self->lruq.next != &self->lruq) {   /* XXX ##3 XXX */
953                                     QRemove (&(self->lruq));            /* dequeue */
954                                 }
955 self->cnt++;
956                                 afs_bioqueue.sleeper = FALSE;
957                                 if (interrupted) {
958                                     /* re-enable interrupts from strategy */
959                                     i_enable (oldPriority);
960                                     return(NULL);
961                                 }
962                                 continue;
963                         } else {
964                                 afs_bioqueue.sleeper = TRUE;
965                                 interrupted = sleep ((caddr_t) &afs_asyncbuf, PCATCH|(PZERO + 1));
966                                 afs_bioqueue.sleeper = FALSE;
967                                 if (interrupted)
968                                 {
969                                     /*
970                                      * We need to wakeup another daemon if present
971                                      * since we were waiting on afs_asyncbuf.
972                                      */
973 #ifdef  notdef  /* The following doesn't work as advertised */                              
974                                      if (afs_bioqueue.lruq.next != &afs_bioqueue.lruq)
975                                      {
976                                          struct squeue *bq = afs_bioqueue.lruq.next;
977                                          QRemove (bq);
978                                          wakeup (bq);
979                                      }
980 #endif
981                                     /* re-enable interrupts from strategy */
982                                      i_enable (oldPriority);
983                                      return(NULL);
984                                  }
985                                 continue;
986                                 }
987
988                         }  /* end of "else asyncbuf is empty" */
989                 } /* end of "inner loop" */
990
991         /*assert (bp);*/
992
993         i_enable (oldPriority);     /* re-enable interrupts from strategy */
994
995         /* For the convenience of other code, replace the gnodes in
996          * the b_vp field of bp and the other buffers on the b_work
997          * chain with the corresponding vnodes.   
998          *
999          * ??? what happens to the gnodes?  They're not just cut loose,
1000          * are they?
1001          */
1002         for(t1P=bp;;) {
1003                 t2P = (struct buf *) t1P->b_work;
1004                 t1P->b_vp = ((struct gnode *) t1P->b_vp)->gn_vnode;
1005                 if (!t2P) 
1006                         break;
1007
1008                 t1P = (struct buf *) t2P->b_work;
1009                 t2P->b_vp = ((struct gnode *) t2P->b_vp)->gn_vnode;
1010                 if (!t1P)
1011                         break;
1012                 }
1013
1014         /* If the buffer does not specify I/O, it may immediately
1015          * be returned to the caller.  This condition is detected
1016          * by examining the buffer's flags (the b_flags field).  If
1017          * the B_PFPROT bit is set, the buffer represents a protection
1018          * violation, rather than a request for I/O.  The remainder
1019          * of the outer loop handles the case where the B_PFPROT bit is clear.
1020          */
1021          if (bp->b_flags & B_PFPROT)  {
1022                 return (bp);
1023             }
1024
1025         /* wake up another process to handle the next buffer, and return
1026          * bp to the caller.
1027          */
1028         oldPriority = i_disable ( INTMAX ) ;
1029
1030         /* determine where to find the sleeping process. 
1031          * There are two cases: either it is sleeping on
1032          * afs_asyncbuf, or it is sleeping on its own unique
1033          * address.  These cases are distinguished by examining
1034          * the sleeper field of afs_bioqueue.
1035          */
1036         if (afs_bioqueue.sleeper) {
1037                 wakeup (&afs_asyncbuf);
1038                 }
1039         else {
1040                 if (afs_bioqueue.lruq.next == &afs_bioqueue.lruq) {
1041                         /* queue is empty, what now? ???*/
1042                         /* Should this be impossible, or does    */
1043                         /* it just mean that nobody is sleeping? */;
1044                         }
1045                 else {
1046                         struct squeue *bq = afs_bioqueue.lruq.next;
1047                         QRemove (bq);
1048                         QInit (bq);
1049                         wakeup (bq);
1050                         afs_bioqueue.sleeper = TRUE; 
1051                         }
1052                 }
1053         i_enable (oldPriority);     /* re-enable interrupts from strategy */
1054         return (bp);
1055
1056 } /* end of function get_bioreq() */
1057
1058
1059 /* afs_BioDaemon
1060  *
1061  * This function is the daemon.  It is called from the syscall
1062  * interface.  Ordinarily, a script or an administrator will run a
1063  * daemon startup utility, specifying the number of I/O daemons to
1064  * run.  The utility will fork off that number of processes,
1065  * each making the appropriate syscall, which will cause this
1066  * function to be invoked.
1067  */
1068 static int afs_initbiod = 0;            /* this is self-initializing code */
1069 int DOvmlock = 0;
1070 afs_BioDaemon (nbiods)
1071     afs_int32 nbiods;
1072 {
1073     struct afs_bioqueue *self;
1074     afs_int32 code, s, pflg = 0;
1075     label_t jmpbuf;
1076     struct buf *bp, *bp1, *tbp1, *tbp2;         /* temp pointers only */
1077     caddr_t tmpaddr;
1078     struct vnode *vp;
1079     struct vcache *vcp;
1080     char tmperr;
1081     if (!afs_initbiod) {
1082         /* XXX ###1 XXX */
1083         afs_initbiod = 1;
1084         /* Initialize the queue of waiting processes, afs_bioqueue.  */
1085         QInit (&(afs_bioqueue.lruq));           
1086     }
1087
1088     /* establish ourself as a kernel process so shutdown won't kill us */
1089 /*    u.u_procp->p_flag |= SKPROC;*/
1090
1091     /* Initialize a token (self) to use in the queue of sleeping processes.   */
1092     self = (struct afs_bioqueue *) afs_osi_Alloc (sizeof (struct afs_bioqueue));
1093     pin (self, sizeof (struct afs_bioqueue)); /* fix in memory */
1094     memset(self, 0, sizeof(*self));
1095     QInit (&(self->lruq));              /* initialize queue entry pointers */
1096
1097
1098     /* Ignore HUP signals... */
1099     SIGDELSET(u.u_procp->p_sig, SIGHUP);
1100     SIGADDSET(u.u_procp->p_sigignore, SIGHUP);
1101     SIGDELSET(u.u_procp->p_sigcatch, SIGHUP);
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         int min_ts;
1220         struct brequest *min_tb;
1221
1222         if (afs_termState == AFSOP_STOP_BKG) {
1223             if (--afs_nbrs <= 0)
1224                 afs_termState = AFSOP_STOP_TRUNCDAEMON;
1225             MReleaseWriteLock(&afs_xbrs);
1226             afs_osi_Wakeup(&afs_termState);
1227             return;
1228         }
1229
1230         /* find a request */
1231         tb = afs_brs;
1232         foundAny = 0;
1233         min_tb = NULL;
1234         for(i=0; i<NBRS; i++, tb++) {
1235             /* look for request with smallest ts */
1236             if ((tb->refCount > 0) && !(tb->flags & BSTARTED)) {
1237                 /* new request, not yet picked up */
1238                 if ((min_tb && (min_ts - tb->ts > 0)) || !min_tb) {
1239                     min_tb = tb;
1240                     min_ts = tb->ts;
1241                 }
1242             }
1243         }
1244         if (tb = min_tb) {
1245             /* claim and process this request */
1246             tb->flags |= BSTARTED;
1247             MReleaseWriteLock(&afs_xbrs);
1248             foundAny = 1;
1249             afs_Trace1(afs_iclSetp, CM_TRACE_BKG1,
1250                        ICL_TYPE_INT32, tb->opcode);
1251             if (tb->opcode == BOP_FETCH)
1252                 BPrefetch(tb);
1253             else if (tb->opcode == BOP_STORE)
1254                 BStore(tb);
1255             else if (tb->opcode == BOP_PATH)
1256                 BPath(tb);
1257             else panic("background bop");
1258             if (tb->vnode) {
1259 #ifdef  AFS_DEC_ENV
1260                 tb->vnode->vrefCount--;     /* fix up reference count */
1261 #else
1262                 AFS_RELE((struct vnode *)(tb->vnode));  /* MUST call vnode layer or could lose vnodes */
1263 #endif
1264                 tb->vnode = (struct vcache *) 0;
1265             }
1266             if (tb->cred) {
1267                 crfree(tb->cred);
1268                 tb->cred = (struct AFS_UCRED *) 0;
1269             }
1270             afs_BRelease(tb);   /* this grabs and releases afs_xbrs lock */
1271             MObtainWriteLock(&afs_xbrs,305);
1272         }
1273         if (!foundAny) {
1274             /* wait for new request */
1275             afs_brsDaemons++;
1276             MReleaseWriteLock(&afs_xbrs);
1277             afs_osi_Sleep(&afs_brsDaemons);
1278             MObtainWriteLock(&afs_xbrs,307);
1279             afs_brsDaemons--;
1280         }
1281     }
1282 }
1283
1284
1285 void shutdown_daemons()
1286 {
1287   extern int afs_cold_shutdown;
1288   register int i;
1289   register struct brequest *tb;
1290
1291   AFS_STATCNT(shutdown_daemons);
1292   if (afs_cold_shutdown) {
1293       afs_brsDaemons = brsInit = 0;
1294       rxepoch_checked = afs_nbrs = 0;
1295       memset((char *)afs_brs, 0, sizeof(afs_brs));
1296       memset((char *)&afs_xbrs, 0, sizeof(afs_lock_t));
1297       afs_brsWaiters = 0;
1298 #ifdef AFS_AIX32_ENV
1299 #ifdef AFS_AIX41_ENV
1300       lock_free(&afs_asyncbuf_lock);
1301       unpin(&afs_asyncbuf, sizeof(struct buf*));
1302       pin (&afs_asyncbuf_cv, sizeof(afs_int32));
1303 #else /* AFS_AIX41_ENV */
1304       afs_busyq = NULL;
1305       afs_biodcnt = 0;
1306       memset((char *)&afs_bioqueue, 0, sizeof(struct afs_bioqueue));
1307 #endif
1308       afs_initbiod = 0;
1309 #endif
1310   }
1311 }
1312
1313 #if defined(AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
1314 /*
1315  * sgi - daemon - handles certain operations that otherwise
1316  * would use up too much kernel stack space
1317  *
1318  * This all assumes that since the caller must have the xdcache lock
1319  * exclusively that the list will never be more than one long
1320  * and noone else can attempt to add anything until we're done.
1321  */
1322 SV_TYPE afs_sgibksync;
1323 SV_TYPE afs_sgibkwait;
1324 lock_t afs_sgibklock;
1325 struct dcache *afs_sgibklist;
1326
1327 int
1328 afs_sgidaemon(void)
1329 {
1330         int s;
1331         struct dcache *tdc;
1332
1333         if (afs_sgibklock == NULL) {
1334                 SV_INIT(&afs_sgibksync, "bksync", 0, 0);
1335                 SV_INIT(&afs_sgibkwait, "bkwait", 0, 0);
1336                 SPINLOCK_INIT(&afs_sgibklock, "bklock");
1337         }
1338         s = SPLOCK(afs_sgibklock);
1339         for (;;) {
1340                 /* wait for something to do */
1341                 SP_WAIT(afs_sgibklock, s, &afs_sgibksync, PINOD);
1342                 osi_Assert(afs_sgibklist);
1343
1344                 /* XX will probably need to generalize to real list someday */
1345                 s = SPLOCK(afs_sgibklock);
1346                 while (afs_sgibklist) {
1347                         tdc = afs_sgibklist;
1348                         afs_sgibklist = NULL;
1349                         SPUNLOCK(afs_sgibklock, s);
1350                         AFS_GLOCK();
1351                         tdc->flags &= ~DFEntryMod;
1352                         afs_WriteDCache(tdc, 1);
1353                         AFS_GUNLOCK();
1354                         s = SPLOCK(afs_sgibklock);
1355                 }
1356
1357                 /* done all the work - wake everyone up */
1358                 while (SV_SIGNAL(&afs_sgibkwait))
1359                         ;
1360         }
1361 }
1362 #endif