bkg-disable-var-20060202
[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
14     ("$Header$");
15
16 #ifdef AFS_AIX51_ENV
17 #define __FULL_PROTO
18 #include <sys/sleep.h>
19 #endif
20
21 #include "afs/sysincludes.h"    /* Standard vendor system headers */
22 #include "afsincludes.h"        /* Afs-based standard headers */
23 #include "afs/afs_stats.h"      /* statistics gathering code */
24 #include "afs/afs_cbqueue.h"
25 #ifdef AFS_AIX_ENV
26 #include <sys/adspace.h>        /* for vm_att(), vm_det() */
27 #endif
28
29
30 /* background request queue size */
31 afs_lock_t afs_xbrs;            /* lock for brs */
32 static int brsInit = 0;
33 short afs_brsWaiters = 0;       /* number of users waiting for brs buffers */
34 short afs_brsDaemons = 0;       /* number of daemons waiting for brs requests */
35 struct brequest afs_brs[NBRS];  /* request structures */
36 struct afs_osi_WaitHandle AFS_WaitHandler, AFS_CSWaitHandler;
37 static int afs_brs_count = 0;   /* request counter, to service reqs in order */
38 #ifdef AFS_DISABLE_BKG
39 int disable_bkg = AFS_DISABLE_BKG;
40 #endif
41
42 static int rxepoch_checked = 0;
43 #define afs_CheckRXEpoch() {if (rxepoch_checked == 0 && rxkad_EpochWasSet) { \
44         rxepoch_checked = 1; afs_GCUserData(/* force flag */ 1);  } }
45
46 /* PAG garbage collection */
47 /* We induce a compile error if param.h does not define AFS_GCPAGS */
48 afs_int32 afs_gcpags = AFS_GCPAGS;
49 afs_int32 afs_gcpags_procsize = 0;
50
51 afs_int32 afs_CheckServerDaemonStarted = 0;
52 #ifdef DEFAULT_PROBE_INTERVAL
53 afs_int32 PROBE_INTERVAL = DEFAULT_PROBE_INTERVAL;      /* overridding during compile */
54 #else
55 afs_int32 PROBE_INTERVAL = 180; /* default to 3 min */
56 #endif
57
58 #define PROBE_WAIT() (1000 * (PROBE_INTERVAL - ((afs_random() & 0x7fffffff) \
59                       % (PROBE_INTERVAL/2))))
60
61 void
62 afs_CheckServerDaemon(void)
63 {
64     afs_int32 now, delay, lastCheck, last10MinCheck;
65
66     afs_CheckServerDaemonStarted = 1;
67
68     while (afs_initState < 101)
69         afs_osi_Sleep(&afs_initState);
70     afs_osi_Wait(PROBE_WAIT(), &AFS_CSWaitHandler, 0);
71
72     last10MinCheck = lastCheck = osi_Time();
73     while (1) {
74         if (afs_termState == AFSOP_STOP_CS) {
75             afs_termState = AFSOP_STOP_BKG;
76             afs_osi_Wakeup(&afs_termState);
77             break;
78         }
79
80         now = osi_Time();
81         if (PROBE_INTERVAL + lastCheck <= now) {
82             afs_CheckServers(1, NULL);  /* check down servers */
83             lastCheck = now = osi_Time();
84         }
85
86         if (600 + last10MinCheck <= now) {
87             afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP, ICL_TYPE_INT32, 600);
88             afs_CheckServers(0, NULL);
89             last10MinCheck = now = osi_Time();
90         }
91         /* shutdown check. */
92         if (afs_termState == AFSOP_STOP_CS) {
93             afs_termState = AFSOP_STOP_BKG;
94             afs_osi_Wakeup(&afs_termState);
95             break;
96         }
97
98         /* Compute time to next probe. */
99         delay = PROBE_INTERVAL + lastCheck;
100         if (delay > 600 + last10MinCheck)
101             delay = 600 + last10MinCheck;
102         delay -= now;
103         if (delay < 1)
104             delay = 1;
105         afs_osi_Wait(delay * 1000, &AFS_CSWaitHandler, 0);
106     }
107     afs_CheckServerDaemonStarted = 0;
108 }
109 #define RECURSIVE_VFS_CONTEXT 1
110 #if RECURSIVE_VFS_CONTEXT
111 extern int vfs_context_ref;
112 #else
113 #define vfs_context_ref 1
114 #endif
115 void
116 afs_Daemon(void)
117 {
118     afs_int32 code;
119     struct afs_exporter *exporter;
120     afs_int32 now;
121     afs_int32 last3MinCheck, last10MinCheck, last60MinCheck, lastNMinCheck;
122     afs_int32 last1MinCheck;
123     afs_uint32 lastCBSlotBump;
124     char cs_warned = 0;
125
126     AFS_STATCNT(afs_Daemon);
127     last1MinCheck = last3MinCheck = last60MinCheck = last10MinCheck =
128         lastNMinCheck = 0;
129
130     afs_rootFid.Fid.Volume = 0;
131     while (afs_initState < 101)
132         afs_osi_Sleep(&afs_initState);
133
134 #ifdef AFS_DARWIN80_ENV
135     if (afs_osi_ctxtp_initialized)
136         osi_Panic("vfs context already initialized");
137     while (afs_osi_ctxtp && vfs_context_ref)
138         afs_osi_Sleep(&afs_osi_ctxtp);
139 #if RECURSIVE_VFS_CONTEXT
140     if (afs_osi_ctxtp && !vfs_context_ref)
141        vfs_context_rele(afs_osi_ctxtp);
142 #endif
143     afs_osi_ctxtp = vfs_context_create(NULL);
144     afs_osi_ctxtp_initialized = 1;
145 #endif
146     now = osi_Time();
147     lastCBSlotBump = now;
148
149     /* when a lot of clients are booted simultaneously, they develop
150      * annoying synchronous VL server bashing behaviors.  So we stagger them.
151      */
152     last1MinCheck = now + ((afs_random() & 0x7fffffff) % 60);   /* an extra 30 */
153     last3MinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180);
154     last60MinCheck = now - 1800 + ((afs_random() & 0x7fffffff) % 3600);
155     last10MinCheck = now - 300 + ((afs_random() & 0x7fffffff) % 600);
156     lastNMinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180);
157
158     /* start off with afs_initState >= 101 (basic init done) */
159     while (1) {
160         afs_CheckCallbacks(20); /* unstat anything which will expire soon */
161
162         /* things to do every 20 seconds or less - required by protocol spec */
163         if (afs_nfsexporter)
164             afs_FlushActiveVcaches(0);  /* flush NFS writes */
165         afs_FlushVCBs(1);       /* flush queued callbacks */
166         afs_MaybeWakeupTruncateDaemon();        /* free cache space if have too */
167         rx_CheckPackets();      /* Does RX need more packets? */
168
169         now = osi_Time();
170         if (lastCBSlotBump + CBHTSLOTLEN < now) {       /* pretty time-dependant */
171             lastCBSlotBump = now;
172             if (afs_BumpBase()) {
173                 afs_CheckCallbacks(20); /* unstat anything which will expire soon */
174             }
175         }
176
177         if (last1MinCheck + 60 < now) {
178             /* things to do every minute */
179             DFlush();           /* write out dir buffers */
180             afs_WriteThroughDSlots();   /* write through cacheinfo entries */
181             ObtainWriteLock(&afs_xvcache, 736);
182             afs_FlushReclaimedVcaches();
183             ReleaseWriteLock(&afs_xvcache);
184             afs_FlushActiveVcaches(1);  /* keep flocks held & flush nfs writes */
185 #ifdef AFS_DISCON_ENV
186             afs_StoreDirtyVcaches();
187 #endif
188             afs_CheckRXEpoch();
189             last1MinCheck = now;
190         }
191
192         if (last3MinCheck + 180 < now) {
193             afs_CheckTokenCache();      /* check for access cache resets due to expired
194                                          * tickets */
195             last3MinCheck = now;
196         }
197         if (!afs_CheckServerDaemonStarted) {
198             /* Do the check here if the correct afsd is not installed. */
199             if (!cs_warned) {
200                 cs_warned = 1;
201                 printf("Please install afsd with check server daemon.\n");
202             }
203             if (lastNMinCheck + PROBE_INTERVAL < now) {
204                 /* only check down servers */
205                 afs_CheckServers(1, NULL);
206                 lastNMinCheck = now;
207             }
208         }
209         if (last10MinCheck + 600 < now) {
210 #ifdef AFS_USERSPACE_IP_ADDR
211             extern int rxi_GetcbiInfo(void);
212 #endif
213             afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP, ICL_TYPE_INT32, 600);
214 #ifdef AFS_USERSPACE_IP_ADDR
215             if (rxi_GetcbiInfo()) {     /* addresses changed from last time */
216                 afs_FlushCBs();
217             }
218 #else /* AFS_USERSPACE_IP_ADDR */
219             if (rxi_GetIFInfo()) {      /* addresses changed from last time */
220                 afs_FlushCBs();
221             }
222 #endif /* else AFS_USERSPACE_IP_ADDR */
223             if (!afs_CheckServerDaemonStarted)
224                 afs_CheckServers(0, NULL);
225             afs_GCUserData(0);  /* gc old conns */
226             /* This is probably the wrong way of doing GC for the various exporters but it will suffice for a while */
227             for (exporter = root_exported; exporter;
228                  exporter = exporter->exp_next) {
229                 (void)EXP_GC(exporter, 0);      /* Generalize params */
230             }
231             {
232                 static int cnt = 0;
233                 if (++cnt < 12) {
234                     afs_CheckVolumeNames(AFS_VOLCHECK_EXPIRED |
235                                          AFS_VOLCHECK_BUSY);
236                 } else {
237                     cnt = 0;
238                     afs_CheckVolumeNames(AFS_VOLCHECK_EXPIRED |
239                                          AFS_VOLCHECK_BUSY |
240                                          AFS_VOLCHECK_MTPTS);
241                 }
242             }
243             last10MinCheck = now;
244         }
245         if (last60MinCheck + 3600 < now) {
246             afs_Trace1(afs_iclSetp, CM_TRACE_PROBEVOLUME, ICL_TYPE_INT32,
247                        3600);
248             afs_CheckRootVolume();
249 #if AFS_GCPAGS
250             if (afs_gcpags == AFS_GCPAGS_OK) {
251                 afs_int32 didany;
252                 afs_GCPAGs(&didany);
253             }
254 #endif
255             last60MinCheck = now;
256         }
257         if (afs_initState < 300) {      /* while things ain't rosy */
258             code = afs_CheckRootVolume();
259             if (code == 0)
260                 afs_initState = 300;    /* succeeded */
261             if (afs_initState < 200)
262                 afs_initState = 200;    /* tried once */
263             afs_osi_Wakeup(&afs_initState);
264         }
265
266         /* 18285 is because we're trying to divide evenly into 128, that is,
267          * CBSlotLen, while staying just under 20 seconds.  If CBSlotLen
268          * changes, should probably change this interval, too. 
269          * Some of the preceding actions may take quite some time, so we
270          * might not want to wait the entire interval */
271         now = 18285 - (osi_Time() - now);
272         if (now > 0) {
273             afs_osi_Wait(now, &AFS_WaitHandler, 0);
274         }
275
276         if (afs_termState == AFSOP_STOP_AFS) {
277             if (afs_CheckServerDaemonStarted)
278                 afs_termState = AFSOP_STOP_CS;
279             else
280                 afs_termState = AFSOP_STOP_BKG;
281             afs_osi_Wakeup(&afs_termState);
282             return;
283         }
284     }
285 }
286
287 int
288 afs_CheckRootVolume(void)
289 {
290     char rootVolName[32];
291     struct volume *tvp = NULL;
292     int usingDynroot = afs_GetDynrootEnable();
293     int localcell;
294
295     AFS_STATCNT(afs_CheckRootVolume);
296     if (*afs_rootVolumeName == 0) {
297         strcpy(rootVolName, "root.afs");
298     } else {
299         strcpy(rootVolName, afs_rootVolumeName);
300     }
301
302     if (usingDynroot) {
303         afs_GetDynrootFid(&afs_rootFid);
304         tvp = afs_GetVolume(&afs_rootFid, NULL, READ_LOCK);
305     } else {
306         struct cell *lc = afs_GetPrimaryCell(READ_LOCK);
307
308         if (!lc)
309             return ENOENT;
310         localcell = lc->cellNum;
311         afs_PutCell(lc, READ_LOCK);
312         tvp = afs_GetVolumeByName(rootVolName, localcell, 1, NULL, READ_LOCK);
313         if (!tvp) {
314             char buf[128];
315             int len = strlen(rootVolName);
316
317             if ((len < 9) || strcmp(&rootVolName[len - 9], ".readonly")) {
318                 strcpy(buf, rootVolName);
319                 afs_strcat(buf, ".readonly");
320                 tvp = afs_GetVolumeByName(buf, localcell, 1, NULL, READ_LOCK);
321             }
322         }
323         if (tvp) {
324             int volid = (tvp->roVol ? tvp->roVol : tvp->volume);
325             afs_rootFid.Cell = localcell;
326             if (afs_rootFid.Fid.Volume && afs_rootFid.Fid.Volume != volid
327                 && afs_globalVp) {
328                 struct vcache *tvc = afs_globalVp;
329                 /* If we had a root fid before and it changed location we reset
330                  * the afs_globalVp so that it will be reevaluated.
331                  * Just decrement the reference count. This only occurs during
332                  * initial cell setup and can panic the machine if we set the
333                  * count to zero and fs checkv is executed when the current
334                  * directory is /afs.
335                  */
336 #ifdef AFS_LINUX20_ENV
337                 {
338                     struct vrequest treq;
339                     struct vattr vattr;
340                     cred_t *credp;
341                     struct dentry *dp;
342                     struct vcache *vcp;
343                     
344                     afs_rootFid.Fid.Volume = volid;
345                     afs_rootFid.Fid.Vnode = 1;
346                     afs_rootFid.Fid.Unique = 1;
347                     
348                     credp = crref();
349                     if (afs_InitReq(&treq, credp))
350                         goto out;
351                     vcp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
352                     if (!vcp)
353                         goto out;
354                     afs_getattr(vcp, &vattr, credp);
355                     afs_fill_inode(AFSTOV(vcp), &vattr);
356                     
357                     dp = d_find_alias(AFSTOV(afs_globalVp));
358                     
359 #if defined(AFS_LINUX24_ENV)
360                     spin_lock(&dcache_lock);
361 #if defined(AFS_LINUX26_ENV)
362                     spin_lock(&dp->d_lock);
363 #endif
364 #endif
365                     list_del_init(&dp->d_alias);
366                     list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
367                     dp->d_inode = AFSTOV(vcp);
368 #if defined(AFS_LINUX24_ENV)
369 #if defined(AFS_LINUX26_ENV)
370                     spin_unlock(&dp->d_lock);
371 #endif
372                     spin_unlock(&dcache_lock);
373 #endif
374                     dput(dp);
375                     
376                     AFS_FAST_RELE(afs_globalVp);
377                     afs_globalVp = vcp;
378                 out:
379                     crfree(credp);
380                 }
381 #else
382 #ifdef AFS_DARWIN80_ENV
383                 afs_PutVCache(afs_globalVp);
384 #else
385                 AFS_FAST_RELE(afs_globalVp);
386 #endif
387                 afs_globalVp = 0;
388 #endif
389             }
390             afs_rootFid.Fid.Volume = volid;
391             afs_rootFid.Fid.Vnode = 1;
392             afs_rootFid.Fid.Unique = 1;
393         }
394     }
395     if (tvp) {
396         afs_initState = 300;    /* won */
397         afs_osi_Wakeup(&afs_initState);
398         afs_PutVolume(tvp, READ_LOCK);
399     }
400     if (afs_rootFid.Fid.Volume)
401         return 0;
402     else
403         return ENOENT;
404 }
405
406 /* ptr_parm 0 is the pathname, size_parm 0 to the fetch is the chunk number */
407 static void
408 BPath(register struct brequest *ab)
409 {
410     register struct dcache *tdc = NULL;
411     struct vcache *tvc = NULL;
412     struct vnode *tvn = NULL;
413 #ifdef AFS_LINUX22_ENV
414     struct dentry *dp = NULL;
415 #endif
416     afs_size_t offset, len;
417     struct vrequest treq;
418     afs_int32 code;
419
420     AFS_STATCNT(BPath);
421     if ((code = afs_InitReq(&treq, ab->cred)))
422         return;
423     AFS_GUNLOCK();
424 #ifdef AFS_LINUX22_ENV
425     code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, &dp);
426     if (dp)
427         tvn = (struct vnode *)dp->d_inode;
428 #else
429     code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, &tvn);
430 #endif
431     AFS_GLOCK();
432     osi_FreeLargeSpace((char *)ab->ptr_parm[0]);        /* free path name buffer here */
433     if (code)
434         return;
435     /* now path may not have been in afs, so check that before calling our cache manager */
436     if (!tvn || !IsAfsVnode(tvn)) {
437         /* release it and give up */
438         if (tvn) {
439 #ifdef AFS_LINUX22_ENV
440             dput(dp);
441 #else
442             AFS_RELE(tvn);
443 #endif
444         }
445         return;
446     }
447     tvc = VTOAFS(tvn);
448     /* here we know its an afs vnode, so we can get the data for the chunk */
449     tdc = afs_GetDCache(tvc, ab->size_parm[0], &treq, &offset, &len, 1);
450     if (tdc) {
451         afs_PutDCache(tdc);
452     }
453 #ifdef AFS_LINUX22_ENV
454     dput(dp);
455 #else
456     AFS_RELE(tvn);
457 #endif
458 }
459
460 /* size_parm 0 to the fetch is the chunk number,
461  * ptr_parm 0 is the dcache entry to wakeup,
462  * size_parm 1 is true iff we should release the dcache entry here.
463  */
464 static void
465 BPrefetch(register struct brequest *ab)
466 {
467     register struct dcache *tdc;
468     register struct vcache *tvc;
469     afs_size_t offset, len;
470     struct vrequest treq;
471
472     AFS_STATCNT(BPrefetch);
473     if ((len = afs_InitReq(&treq, ab->cred)))
474         return;
475     tvc = ab->vc;
476     tdc = afs_GetDCache(tvc, ab->size_parm[0], &treq, &offset, &len, 1);
477     if (tdc) {
478         afs_PutDCache(tdc);
479     }
480     /* now, dude may be waiting for us to clear DFFetchReq bit; do so.  Can't
481      * use tdc from GetDCache since afs_GetDCache may fail, but someone may
482      * be waiting for our wakeup anyway.
483      */
484     tdc = (struct dcache *)(ab->ptr_parm[0]);
485     ObtainSharedLock(&tdc->lock, 640);
486     if (tdc->mflags & DFFetchReq) {
487         UpgradeSToWLock(&tdc->lock, 641);
488         tdc->mflags &= ~DFFetchReq;
489         ReleaseWriteLock(&tdc->lock);
490     } else {
491         ReleaseSharedLock(&tdc->lock);
492     }
493     afs_osi_Wakeup(&tdc->validPos);
494     if (ab->size_parm[1]) {
495         afs_PutDCache(tdc);     /* put this one back, too */
496     }
497 }
498
499
500 static void
501 BStore(register struct brequest *ab)
502 {
503     register struct vcache *tvc;
504     register afs_int32 code;
505     struct vrequest treq;
506 #if defined(AFS_SGI_ENV)
507     struct cred *tmpcred;
508 #endif
509
510     AFS_STATCNT(BStore);
511     if ((code = afs_InitReq(&treq, ab->cred)))
512         return;
513     code = 0;
514     tvc = ab->vc;
515 #if defined(AFS_SGI_ENV)
516     /*
517      * Since StoreOnLastReference can end up calling osi_SyncVM which
518      * calls into VM code that assumes that u.u_cred has the
519      * correct credentials, we set our to theirs for this xaction
520      */
521     tmpcred = OSI_GET_CURRENT_CRED();
522     OSI_SET_CURRENT_CRED(ab->cred);
523
524     /*
525      * To avoid recursion since the WriteLock may be released during VM
526      * operations, we hold the VOP_RWLOCK across this transaction as
527      * do the other callers of StoreOnLastReference
528      */
529     AFS_RWLOCK((vnode_t *) tvc, 1);
530 #endif
531     ObtainWriteLock(&tvc->lock, 209);
532     code = afs_StoreOnLastReference(tvc, &treq);
533     ReleaseWriteLock(&tvc->lock);
534 #if defined(AFS_SGI_ENV)
535     OSI_SET_CURRENT_CRED(tmpcred);
536     AFS_RWUNLOCK((vnode_t *) tvc, 1);
537 #endif
538     /* now set final return code, and wakeup anyone waiting */
539     if ((ab->flags & BUVALID) == 0) {
540         ab->code = afs_CheckCode(code, &treq, 43);      /* set final code, since treq doesn't go across processes */
541         ab->flags |= BUVALID;
542         if (ab->flags & BUWAIT) {
543             ab->flags &= ~BUWAIT;
544             afs_osi_Wakeup(ab);
545         }
546     }
547 }
548
549 /* release a held request buffer */
550 void
551 afs_BRelease(register struct brequest *ab)
552 {
553
554     AFS_STATCNT(afs_BRelease);
555     MObtainWriteLock(&afs_xbrs, 294);
556     if (--ab->refCount <= 0) {
557         ab->flags = 0;
558     }
559     if (afs_brsWaiters)
560         afs_osi_Wakeup(&afs_brsWaiters);
561     MReleaseWriteLock(&afs_xbrs);
562 }
563
564 /* return true if bkg fetch daemons are all busy */
565 int
566 afs_BBusy(void)
567 {
568     AFS_STATCNT(afs_BBusy);
569 #ifdef AFS_DISABLE_BKG
570     if (disable_bkg)
571         return 1;
572 #endif
573     if (afs_brsDaemons > 0)
574         return 0;
575     return 1;
576 }
577
578 struct brequest *
579 afs_BQueue(register short aopcode, register struct vcache *avc,
580            afs_int32 dontwait, afs_int32 ause, struct AFS_UCRED *acred,
581            afs_size_t asparm0, afs_size_t asparm1, void *apparm0)
582 {
583     register int i;
584     register struct brequest *tb;
585
586     AFS_STATCNT(afs_BQueue);
587     MObtainWriteLock(&afs_xbrs, 296);
588     while (1) {
589         tb = afs_brs;
590         for (i = 0; i < NBRS; i++, tb++) {
591             if (tb->refCount == 0)
592                 break;
593         }
594         if (i < NBRS) {
595             /* found a buffer */
596             tb->opcode = aopcode;
597             tb->vc = avc;
598             tb->cred = acred;
599             crhold(tb->cred);
600             if (avc) {
601                 VN_HOLD(AFSTOV(avc));
602             }
603             tb->refCount = ause + 1;
604             tb->size_parm[0] = asparm0;
605             tb->size_parm[1] = asparm1;
606             tb->ptr_parm[0] = apparm0;
607             tb->flags = 0;
608             tb->code = 0;
609             tb->ts = afs_brs_count++;
610             /* if daemons are waiting for work, wake them up */
611             if (afs_brsDaemons > 0) {
612                 afs_osi_Wakeup(&afs_brsDaemons);
613             }
614             MReleaseWriteLock(&afs_xbrs);
615             return tb;
616         }
617         if (dontwait) {
618             MReleaseWriteLock(&afs_xbrs);
619             return NULL;
620         }
621         /* no free buffers, sleep a while */
622         afs_brsWaiters++;
623         MReleaseWriteLock(&afs_xbrs);
624         afs_osi_Sleep(&afs_brsWaiters);
625         MObtainWriteLock(&afs_xbrs, 301);
626         afs_brsWaiters--;
627     }
628 }
629
630 #ifdef AFS_AIX41_ENV
631 /* AIX 4.1 has a much different sleep/wakeup mechanism available for use. 
632  * The modifications here will work for either a UP or MP machine.
633  */
634 struct buf *afs_asyncbuf = (struct buf *)0;
635 tid_t afs_asyncbuf_cv = EVENT_NULL;
636 afs_int32 afs_biodcnt = 0;
637
638 /* in implementing this, I assumed that all external linked lists were
639  * null-terminated.  
640  *
641  * Several places in this code traverse a linked list.  The algorithm
642  * used here is probably unfamiliar to most people.  Careful examination
643  * will show that it eliminates an assignment inside the loop, as compared
644  * to the standard algorithm, at the cost of occasionally using an extra
645  * variable.
646  */
647
648 /* get_bioreq()
649  *
650  * This function obtains, and returns, a pointer to a buffer for
651  * processing by a daemon.  It sleeps until such a buffer is available.
652  * The source of buffers for it is the list afs_asyncbuf (see also 
653  * afs_gn_strategy).  This function may be invoked concurrently by
654  * several processes, that is, several instances of the same daemon.
655  * afs_gn_strategy, which adds buffers to the list, runs at interrupt
656  * level, while get_bioreq runs at process level.
657  *
658  * Since AIX 4.1 can wake just one process at a time, the separate sleep
659  * addresses have been removed.
660  * Note that the kernel_lock is held until the e_sleep_thread() occurs. 
661  * The afs_asyncbuf_lock is primarily used to serialize access between
662  * process and interrupts.
663  */
664 Simple_lock afs_asyncbuf_lock;
665 struct buf *
666 afs_get_bioreq()
667 {
668     struct buf *bp = NULL;
669     struct buf *bestbp;
670     struct buf **bestlbpP, **lbpP;
671     long bestage, stop;
672     struct buf *t1P, *t2P;      /* temp pointers for list manipulation */
673     int oldPriority;
674     afs_uint32 wait_ret;
675     struct afs_bioqueue *s;
676
677     /* ??? Does the forward pointer of the returned buffer need to be NULL?
678      */
679
680     /* Disable interrupts from the strategy function, and save the 
681      * prior priority level and lock access to the afs_asyncbuf.
682      */
683     AFS_GUNLOCK();
684     oldPriority = disable_lock(INTMAX, &afs_asyncbuf_lock);
685
686     while (1) {
687         if (afs_asyncbuf) {
688             /* look for oldest buffer */
689             bp = bestbp = afs_asyncbuf;
690             bestage = (long)bestbp->av_back;
691             bestlbpP = &afs_asyncbuf;
692             while (1) {
693                 lbpP = &bp->av_forw;
694                 bp = *lbpP;
695                 if (!bp)
696                     break;
697                 if ((long)bp->av_back - bestage < 0) {
698                     bestbp = bp;
699                     bestlbpP = lbpP;
700                     bestage = (long)bp->av_back;
701                 }
702             }
703             bp = bestbp;
704             *bestlbpP = bp->av_forw;
705             break;
706         } else {
707             /* If afs_asyncbuf is null, it is necessary to go to sleep.
708              * e_wakeup_one() ensures that only one thread wakes.
709              */
710             int interrupted;
711             /* The LOCK_HANDLER indicates to e_sleep_thread to only drop the
712              * lock on an MP machine.
713              */
714             interrupted =
715                 e_sleep_thread(&afs_asyncbuf_cv, &afs_asyncbuf_lock,
716                                LOCK_HANDLER | INTERRUPTIBLE);
717             if (interrupted == THREAD_INTERRUPTED) {
718                 /* re-enable interrupts from strategy */
719                 unlock_enable(oldPriority, &afs_asyncbuf_lock);
720                 AFS_GLOCK();
721                 return (NULL);
722             }
723         }                       /* end of "else asyncbuf is empty" */
724     }                           /* end of "inner loop" */
725
726     /*assert (bp); */
727
728     unlock_enable(oldPriority, &afs_asyncbuf_lock);
729     AFS_GLOCK();
730
731     /* For the convenience of other code, replace the gnodes in
732      * the b_vp field of bp and the other buffers on the b_work
733      * chain with the corresponding vnodes.   
734      *
735      * ??? what happens to the gnodes?  They're not just cut loose,
736      * are they?
737      */
738     for (t1P = bp;;) {
739         t2P = (struct buf *)t1P->b_work;
740         t1P->b_vp = ((struct gnode *)t1P->b_vp)->gn_vnode;
741         if (!t2P)
742             break;
743
744         t1P = (struct buf *)t2P->b_work;
745         t2P->b_vp = ((struct gnode *)t2P->b_vp)->gn_vnode;
746         if (!t1P)
747             break;
748     }
749
750     /* If the buffer does not specify I/O, it may immediately
751      * be returned to the caller.  This condition is detected
752      * by examining the buffer's flags (the b_flags field).  If
753      * the B_PFPROT bit is set, the buffer represents a protection
754      * violation, rather than a request for I/O.  The remainder
755      * of the outer loop handles the case where the B_PFPROT bit is clear.
756      */
757     if (bp->b_flags & B_PFPROT) {
758         return (bp);
759     }
760     return (bp);
761
762 }                               /* end of function get_bioreq() */
763
764
765 /* afs_BioDaemon
766  *
767  * This function is the daemon.  It is called from the syscall
768  * interface.  Ordinarily, a script or an administrator will run a
769  * daemon startup utility, specifying the number of I/O daemons to
770  * run.  The utility will fork off that number of processes,
771  * each making the appropriate syscall, which will cause this
772  * function to be invoked.
773  */
774 static int afs_initbiod = 0;    /* this is self-initializing code */
775 int DOvmlock = 0;
776 int
777 afs_BioDaemon(afs_int32 nbiods)
778 {
779     afs_int32 code, s, pflg = 0;
780     label_t jmpbuf;
781     struct buf *bp, *bp1, *tbp1, *tbp2; /* temp pointers only */
782     caddr_t tmpaddr;
783     struct vnode *vp;
784     struct vcache *vcp;
785     char tmperr;
786     if (!afs_initbiod) {
787         /* XXX ###1 XXX */
788         afs_initbiod = 1;
789         /* pin lock, since we'll be using it in an interrupt. */
790         lock_alloc(&afs_asyncbuf_lock, LOCK_ALLOC_PIN, 2, 1);
791         simple_lock_init(&afs_asyncbuf_lock);
792         pin(&afs_asyncbuf, sizeof(struct buf *));
793         pin(&afs_asyncbuf_cv, sizeof(afs_int32));
794     }
795
796     /* Ignore HUP signals... */
797     {
798         sigset_t sigbits, osigbits;
799         /*
800          * add SIGHUP to the set of already masked signals
801          */
802         SIGFILLSET(sigbits);    /* allow all signals    */
803         SIGDELSET(sigbits, SIGHUP);     /*   except SIGHUP      */
804         limit_sigs(&sigbits, &osigbits);        /*   and already masked */
805     }
806     /* Main body starts here -- this is an intentional infinite loop, and
807      * should NEVER exit 
808      *
809      * Now, the loop will exit if get_bioreq() returns NULL, indicating 
810      * that we've been interrupted.
811      */
812     while (1) {
813         bp = afs_get_bioreq();
814         if (!bp)
815             break;              /* we were interrupted */
816         if (code = setjmpx(&jmpbuf)) {
817             /* This should not have happend, maybe a lack of resources  */
818             AFS_GUNLOCK();
819             s = disable_lock(INTMAX, &afs_asyncbuf_lock);
820             for (bp1 = bp; bp; bp = bp1) {
821                 if (bp1)
822                     bp1 = (struct buf *)bp1->b_work;
823                 bp->b_actf = 0;
824                 bp->b_error = code;
825                 bp->b_flags |= B_ERROR;
826                 iodone(bp);
827             }
828             unlock_enable(s, &afs_asyncbuf_lock);
829             AFS_GLOCK();
830             continue;
831         }
832         vcp = VTOAFS(bp->b_vp);
833         if (bp->b_flags & B_PFSTORE) {  /* XXXX */
834             ObtainWriteLock(&vcp->lock, 404);
835             if (vcp->v.v_gnode->gn_mwrcnt) {
836                 afs_offs_t newlength =
837                     (afs_offs_t) dbtob(bp->b_blkno) + bp->b_bcount;
838                 if (vcp->m.Length < newlength) {
839                     afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
840                                ICL_TYPE_STRING, __FILE__, ICL_TYPE_LONG,
841                                __LINE__, ICL_TYPE_OFFSET,
842                                ICL_HANDLE_OFFSET(vcp->m.Length),
843                                ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(newlength));
844                     vcp->m.Length = newlength;
845                 }
846             }
847             ReleaseWriteLock(&vcp->lock);
848         }
849         /* If the buffer represents a protection violation, rather than
850          * an actual request for I/O, no special action need be taken.  
851          */
852         if (bp->b_flags & B_PFPROT) {
853             iodone(bp);         /* Notify all users of the buffer that we're done */
854             clrjmpx(&jmpbuf);
855             continue;
856         }
857         if (DOvmlock)
858             ObtainWriteLock(&vcp->pvmlock, 211);
859         /*
860          * First map its data area to a region in the current address space
861          * by calling vm_att with the subspace identifier, and a pointer to
862          * the data area.  vm_att returns  a new data area pointer, but we
863          * also want to hang onto the old one.
864          */
865         tmpaddr = bp->b_baddr;
866         bp->b_baddr = (caddr_t) vm_att(bp->b_xmemd.subspace_id, tmpaddr);
867         tmperr = afs_ustrategy(bp);     /* temp variable saves offset calculation */
868         if (tmperr) {           /* in non-error case */
869             bp->b_flags |= B_ERROR;     /* should other flags remain set ??? */
870             bp->b_error = tmperr;
871         }
872
873         /* Unmap the buffer's data area by calling vm_det.  Reset data area
874          * to the value that we saved above.
875          */
876         vm_det(bp->b_baddr);
877         bp->b_baddr = tmpaddr;
878
879         /*
880          * buffer may be linked with other buffers via the b_work field.
881          * See also afs_gn_strategy.  For each buffer in the chain (including
882          * bp) notify all users of the buffer that the daemon is finished
883          * using it by calling iodone.  
884          * assumes iodone can modify the b_work field.
885          */
886         for (tbp1 = bp;;) {
887             tbp2 = (struct buf *)tbp1->b_work;
888             iodone(tbp1);
889             if (!tbp2)
890                 break;
891
892             tbp1 = (struct buf *)tbp2->b_work;
893             iodone(tbp2);
894             if (!tbp1)
895                 break;
896         }
897         if (DOvmlock)
898             ReleaseWriteLock(&vcp->pvmlock);    /* Unlock the vnode.  */
899         clrjmpx(&jmpbuf);
900     }                           /* infinite loop (unless we're interrupted) */
901 }                               /* end of afs_BioDaemon() */
902
903 #endif /* AFS_AIX41_ENV */
904
905
906 int afs_nbrs = 0;
907 void
908 afs_BackgroundDaemon(void)
909 {
910     struct brequest *tb;
911     int i, foundAny;
912
913     AFS_STATCNT(afs_BackgroundDaemon);
914     /* initialize subsystem */
915     if (brsInit == 0) {
916         LOCK_INIT(&afs_xbrs, "afs_xbrs");
917         memset((char *)afs_brs, 0, sizeof(afs_brs));
918         brsInit = 1;
919 #if defined (AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
920         /*
921          * steal the first daemon for doing delayed DSlot flushing
922          * (see afs_GetDownDSlot)
923          */
924         AFS_GUNLOCK();
925         afs_sgidaemon();
926         return;
927 #endif
928     }
929     afs_nbrs++;
930
931     MObtainWriteLock(&afs_xbrs, 302);
932     while (1) {
933         int min_ts = 0;
934         struct brequest *min_tb = NULL;
935
936         if (afs_termState == AFSOP_STOP_BKG) {
937             if (--afs_nbrs <= 0)
938                 afs_termState = AFSOP_STOP_TRUNCDAEMON;
939             MReleaseWriteLock(&afs_xbrs);
940             afs_osi_Wakeup(&afs_termState);
941             return;
942         }
943
944         /* find a request */
945         tb = afs_brs;
946         foundAny = 0;
947         for (i = 0; i < NBRS; i++, tb++) {
948             /* look for request with smallest ts */
949             if ((tb->refCount > 0) && !(tb->flags & BSTARTED)) {
950                 /* new request, not yet picked up */
951                 if ((min_tb && (min_ts - tb->ts > 0)) || !min_tb) {
952                     min_tb = tb;
953                     min_ts = tb->ts;
954                 }
955             }
956         }
957         if ((tb = min_tb)) {
958             /* claim and process this request */
959             tb->flags |= BSTARTED;
960             MReleaseWriteLock(&afs_xbrs);
961             foundAny = 1;
962             afs_Trace1(afs_iclSetp, CM_TRACE_BKG1, ICL_TYPE_INT32,
963                        tb->opcode);
964             if (tb->opcode == BOP_FETCH)
965                 BPrefetch(tb);
966             else if (tb->opcode == BOP_STORE)
967                 BStore(tb);
968             else if (tb->opcode == BOP_PATH)
969                 BPath(tb);
970             else
971                 panic("background bop");
972             if (tb->vc) {
973                 AFS_RELE(AFSTOV(tb->vc));       /* MUST call vnode layer or could lose vnodes */
974                 tb->vc = NULL;
975             }
976             if (tb->cred) {
977                 crfree(tb->cred);
978                 tb->cred = (struct AFS_UCRED *)0;
979             }
980             afs_BRelease(tb);   /* this grabs and releases afs_xbrs lock */
981             MObtainWriteLock(&afs_xbrs, 305);
982         }
983         if (!foundAny) {
984             /* wait for new request */
985             afs_brsDaemons++;
986             MReleaseWriteLock(&afs_xbrs);
987             afs_osi_Sleep(&afs_brsDaemons);
988             MObtainWriteLock(&afs_xbrs, 307);
989             afs_brsDaemons--;
990         }
991     }
992 }
993
994
995 void
996 shutdown_daemons(void)
997 {
998     AFS_STATCNT(shutdown_daemons);
999     if (afs_cold_shutdown) {
1000         afs_brsDaemons = brsInit = 0;
1001         rxepoch_checked = afs_nbrs = 0;
1002         memset((char *)afs_brs, 0, sizeof(afs_brs));
1003         memset((char *)&afs_xbrs, 0, sizeof(afs_lock_t));
1004         afs_brsWaiters = 0;
1005 #ifdef AFS_AIX41_ENV
1006         lock_free(&afs_asyncbuf_lock);
1007         unpin(&afs_asyncbuf, sizeof(struct buf *));
1008         unpin(&afs_asyncbuf_cv, sizeof(afs_int32));
1009         afs_initbiod = 0;
1010 #endif
1011     }
1012 }
1013
1014 #if defined(AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
1015 /*
1016  * sgi - daemon - handles certain operations that otherwise
1017  * would use up too much kernel stack space
1018  *
1019  * This all assumes that since the caller must have the xdcache lock
1020  * exclusively that the list will never be more than one long
1021  * and noone else can attempt to add anything until we're done.
1022  */
1023 SV_TYPE afs_sgibksync;
1024 SV_TYPE afs_sgibkwait;
1025 lock_t afs_sgibklock;
1026 struct dcache *afs_sgibklist;
1027
1028 int
1029 afs_sgidaemon(void)
1030 {
1031     int s;
1032     struct dcache *tdc;
1033
1034     if (afs_sgibklock == NULL) {
1035         SV_INIT(&afs_sgibksync, "bksync", 0, 0);
1036         SV_INIT(&afs_sgibkwait, "bkwait", 0, 0);
1037         SPINLOCK_INIT(&afs_sgibklock, "bklock");
1038     }
1039     s = SPLOCK(afs_sgibklock);
1040     for (;;) {
1041         /* wait for something to do */
1042         SP_WAIT(afs_sgibklock, s, &afs_sgibksync, PINOD);
1043         osi_Assert(afs_sgibklist);
1044
1045         /* XX will probably need to generalize to real list someday */
1046         s = SPLOCK(afs_sgibklock);
1047         while (afs_sgibklist) {
1048             tdc = afs_sgibklist;
1049             afs_sgibklist = NULL;
1050             SPUNLOCK(afs_sgibklock, s);
1051             AFS_GLOCK();
1052             tdc->dflags &= ~DFEntryMod;
1053             afs_WriteDCache(tdc, 1);
1054             AFS_GUNLOCK();
1055             s = SPLOCK(afs_sgibklock);
1056         }
1057
1058         /* done all the work - wake everyone up */
1059         while (SV_SIGNAL(&afs_sgibkwait));
1060     }
1061 }
1062 #endif