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