Linux - Fix disk cache access for selinux/AppArmor constrained processes
[openafs.git] / src / afs / afs_init.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 /*
11  * afs_init.c - initialize AFS client.
12  *
13  * Implements:
14  */
15
16 #include <afsconfig.h>
17 #include "afs/param.h"
18
19
20 #include "afs/stds.h"
21 #include "afs/sysincludes.h"    /* Standard vendor system headers */
22 #include "afsincludes.h"        /* Afs-based standard headers */
23 #include "afs/afs_stats.h"      /* afs statistics */
24 #include "rx/rxstat.h"
25 #if defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_HAS_CRED)
26 #include <linux/cred.h>
27 #endif
28
29 #define FSINT_COMMON_XG
30 #include "afs/afscbint.h"
31
32 /* Exported variables */
33 struct osi_dev cacheDev;        /*Cache device */
34 afs_int32 cacheInfoModTime;     /*Last time cache info modified */
35 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
36 struct mount *afs_cacheVfsp = 0;
37 #elif defined(AFS_LINUX20_ENV)
38 struct super_block *afs_cacheSBp = 0;
39 #else
40 struct vfs *afs_cacheVfsp = 0;
41 #endif
42 afs_rwlock_t afs_puttofileLock; /* not used */
43 char *afs_sysname = 0;          /* So that superuser may change the
44                                  * local value of @sys */
45 char *afs_sysnamelist[MAXNUMSYSNAMES];  /* For support of a list of sysname */
46 int afs_sysnamecount = 0;
47 int afs_sysnamegen = 0;
48 struct volume *Initialafs_freeVolList;
49 int afs_memvolumes = 0;
50 #if defined(AFS_XBSD_ENV)
51 static struct vnode *volumeVnode;
52 #endif
53 #if defined(AFS_DISCON_ENV)
54 afs_rwlock_t afs_discon_lock;
55 extern afs_rwlock_t afs_disconDirtyLock;
56 #endif
57 #if defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_HAS_CRED)
58 const struct cred *cache_creds;
59 #endif
60
61 /* This is the kernel side of the dynamic vcache setting */
62 #ifdef AFS_MAXVCOUNT_ENV
63 int afsd_dynamic_vcaches = 0;   /* Enable dynamic-vcache support */
64 #endif
65
66 /*
67  * Initialization order is important.  Must first call afs_CacheInit,
68  * then cache file and volume file initialization routines.  Next, the
69  * individual cache entry initialization routines are called.
70  */
71
72
73 /*
74  * afs_CacheInit
75  *
76  * Description:
77  *
78  * Parameters:
79  *      astatSize : The number of stat cache (vnode) entries to
80  *                  allocate.
81  *      afiles    : The number of disk files to allocate to the cache
82  *      ablocks   : The max number of 1 Kbyte blocks that all of
83  *                  the files in the cache may occupy.
84  *      aDentries : Number of dcache entries to allocate.
85  *      aVolumes  : Number of volume cache entries to allocate.
86  *      achunk    : Power of 2 to make the chunks.
87  *      aflags    : Flags passed in.
88  *      inodes    : max inodes to pin down in inode[]
89  *      users     : what should size of per-user access cache be?
90  *
91  * Environment:
92  *      This routine should only be called at initialization time, since
93  *      it reclaims no resources and doesn't sufficiently synchronize
94  *      with other processes.
95  */
96
97 struct cm_initparams cm_initParams;
98 static int afs_cacheinit_flag = 0;
99 int
100 afs_CacheInit(afs_int32 astatSize, afs_int32 afiles, afs_int32 ablocks,
101               afs_int32 aDentries, afs_int32 aVolumes, afs_int32 achunk,
102               afs_int32 aflags, afs_int32 ninodes, afs_int32 nusers, afs_int32 dynamic_vcaches)
103 {
104     register afs_int32 i;
105     register struct volume *tv;
106
107     AFS_STATCNT(afs_CacheInit);
108     /*
109      * Jot down the epoch time, namely when this incarnation of the
110      * Cache Manager started.
111      */
112     afs_stats_cmperf.epoch = pag_epoch = osi_Time();
113 #ifdef SYS_NAME_ID
114     afs_stats_cmperf.sysName_ID = SYS_NAME_ID;
115 #else
116     afs_stats_cmperf.sysName_ID = SYS_NAME_ID_UNDEFINED;
117 #endif /* SYS_NAME_ID */
118
119 #ifdef AFS_MAXVCOUNT_ENV
120     afsd_dynamic_vcaches = dynamic_vcaches;
121     printf("%s dynamically allocated vcaches\n",
122            ( afsd_dynamic_vcaches ? "enabling" : "disabling" ));
123 #endif
124
125     printf("Starting AFS cache scan...");
126     if (afs_cacheinit_flag)
127         return 0;
128     afs_cacheinit_flag = 1;
129     cacheInfoModTime = 0;
130     maxIHint = ninodes;
131     nihints = 0;
132     usedihint = 0;
133
134     LOCK_INIT(&afs_ftf, "afs_ftf");
135     AFS_RWLOCK_INIT(&afs_xaxs, "afs_xaxs");
136 #ifdef AFS_DISCON_ENV
137     AFS_RWLOCK_INIT(&afs_discon_lock, "afs_discon_lock");
138     AFS_RWLOCK_INIT(&afs_disconDirtyLock, "afs_disconDirtyLock");
139     QInit(&afs_disconDirty);
140     QInit(&afs_disconShadow);
141 #endif
142     osi_dnlc_init();
143
144     /* 
145      * create volume list structure 
146      */
147     if (aVolumes < 50)
148         aVolumes = 50;
149     else if (aVolumes > 32767)
150         aVolumes = 32767;
151
152     tv = (struct volume *)afs_osi_Alloc(aVolumes * sizeof(struct volume));
153     for (i = 0; i < aVolumes - 1; i++)
154         tv[i].next = &tv[i + 1];
155     tv[aVolumes - 1].next = NULL;
156     afs_freeVolList = Initialafs_freeVolList = tv;
157     afs_memvolumes = aVolumes;
158
159     afs_cacheFiles = afiles;
160     afs_cacheStats = astatSize;
161     afs_vcacheInit(astatSize);
162     afs_dcacheInit(afiles, ablocks, aDentries, achunk, aflags);
163 #if defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_HAS_CRED)
164     /*
165      * Save current credentials for later access to disk cache files.
166      * If selinux, apparmor or other security modules are enabled,
167      * they might deny access to cache files if the userspace process
168      * is restricted.  Save the credentials used at cache initialisation
169      * for later use when opening cache files.
170      */
171     cache_creds = get_current_cred();
172 #endif
173 #ifdef AFS_64BIT_CLIENT
174 #ifdef AFS_VM_RDWR_ENV
175     afs_vmMappingEnd = AFS_CHUNKBASE(0x7fffffff);
176 #endif /* AFS_VM_RDWR_ENV */
177 #endif /* AFS_64BIT_CLIENT */
178
179 #if defined(AFS_AIX_ENV) && !defined(AFS_AIX51_ENV)
180     {
181         static void afs_procsize_init(void);
182
183         afs_procsize_init();
184     }
185 #endif
186
187     /* Save the initialization parameters for later pioctl queries. */
188     cm_initParams.cmi_version = CMI_VERSION;
189     cm_initParams.cmi_nChunkFiles = afiles;
190     cm_initParams.cmi_nStatCaches = astatSize;
191     cm_initParams.cmi_nDataCaches = aDentries;
192     cm_initParams.cmi_nVolumeCaches = aVolumes;
193     cm_initParams.cmi_firstChunkSize = AFS_FIRSTCSIZE;
194     cm_initParams.cmi_otherChunkSize = AFS_OTHERCSIZE;
195     cm_initParams.cmi_cacheSize = afs_cacheBlocks;
196     cm_initParams.cmi_setTime = afs_setTime;
197     cm_initParams.cmi_memCache = (aflags & AFSCALL_INIT_MEMCACHE) ? 1 : 0;
198
199     return 0;
200
201 }                               /*afs_CacheInit */
202
203
204 /*
205   * afs_ComputeCacheParams
206   *
207   * Description:
208   *     Set some cache parameters.
209   *
210   * Parameters:
211   *     None.
212   */
213
214 void
215 afs_ComputeCacheParms(void)
216 {
217     register afs_int32 i;
218     afs_int32 afs_maxCacheDirty;
219
220     /*
221      * Don't allow more than 2/3 of the files in the cache to be dirty.
222      */
223     afs_maxCacheDirty = (2 * afs_cacheFiles) / 3;
224
225     /*
226      * Also, don't allow more than 2/3 of the total space get filled
227      * with dirty chunks.  Compute the total number of chunks required
228      * to fill the cache, make sure we don't set out limit above 2/3 of
229      * that. If the cache size is greater than 1G, avoid overflow at
230      * the expense of precision on the chunk size.
231      */
232     if (afs_cacheBlocks & 0xffe00000) {
233         i = afs_cacheBlocks / (AFS_FIRSTCSIZE >> 10);
234     } else {
235         i = (afs_cacheBlocks << 10) / AFS_FIRSTCSIZE;
236     }
237     i = (2 * i) / 3;
238     if (afs_maxCacheDirty > i)
239         afs_maxCacheDirty = i;
240     if (afs_maxCacheDirty < 1)
241         afs_maxCacheDirty = 1;
242     afs_stats_cmperf.cacheMaxDirtyChunks = afs_maxCacheDirty;
243 }                               /*afs_ComputeCacheParms */
244
245
246 /*
247  * afs_LookupInodeByPath
248  *
249  * Look up inode given a file name.
250  * Optionally return the vnode too.
251  * If the vnode is not returned, we rele it.
252  */
253 int
254 afs_LookupInodeByPath(char *filename, afs_ufs_dcache_id_t *inode, struct vnode **fvpp)
255 {
256     afs_int32 code;
257
258 #if defined(AFS_LINUX22_ENV)
259     struct dentry *dp;
260     code = gop_lookupname(filename, AFS_UIOSYS, 0, &dp);
261     if (code)
262         return code;
263     osi_get_fh(dp, inode);
264     dput(dp);
265 #else
266     struct vnode *filevp;
267     code = gop_lookupname(filename, AFS_UIOSYS, 0, &filevp);
268     if (code)
269         return code;
270     *inode = afs_vnodeToInumber(filevp);
271     if (fvpp)
272         *fvpp = filevp;
273     else {
274         AFS_RELE(filevp);
275     }
276 #endif
277
278     return 0;
279 }
280
281 int
282 afs_InitCellInfo(char *afile)
283 {
284     afs_dcache_id_t inode;
285     int code = 0;
286     
287 #ifdef AFS_CACHE_VNODE_PATH
288     inode.ufs = AFS_CACHE_CELLS_INODE;
289 #else
290     code = afs_LookupInodeByPath(afile, &inode.ufs, NULL);
291 #endif
292     return afs_cellname_init(&inode, code);
293 }
294
295 /*
296  * afs_InitVolumeInfo
297  *
298  * Description:
299  *      Set up the volume info storage file.
300  *
301  * Parameters:
302  *      afile : the file to be declared to be the volume info storage
303  *              file for AFS.  It must be already truncated to 0 length.
304  *
305  * Environment:
306  *      This function is called only during initialization.
307  *
308  *      WARNING: Data will be written to this file over time by AFS.
309  */
310
311 int
312 afs_InitVolumeInfo(char *afile)
313 {
314     int code = 0;
315     struct osi_file *tfile;
316
317     AFS_STATCNT(afs_InitVolumeInfo);
318 #if defined(AFS_XBSD_ENV)
319     /*
320      * On Open/Free/NetBSD, we can get into big trouble if we don't hold the volume file
321      * vnode.  SetupVolume holds afs_xvolume lock exclusive.
322      * SetupVolume->GetVolSlot->UFSGetVolSlot->{GetVolCache or WriteVolCache}
323      * ->osi_UFSOpen->VFS_VGET()->ffs_vget->getnewvnode->vgone on some vnode.
324      * If it's AFS, then ->vclean->afs_nbsd_reclaim->FlushVCache->QueueVCB->
325      * GetVolume->FindVolume-> waits on afs_xvolume lock !
326      *
327      * In general, anything that's called with afs_xvolume locked must not
328      * end up calling getnewvnode().  The only cases I've found so far
329      * are things which try to get the volumeInode, and since we keep
330      * it in the cache...
331      */
332     code = afs_LookupInodeByPath(afile, &volumeInode.ufs, &volumeVnode);
333 #elif defined(AFS_CACHE_VNODE_PATH)
334     volumeInode.ufs = AFS_CACHE_VOLUME_INODE;
335 #else
336     code = afs_LookupInodeByPath(afile, &volumeInode.ufs, NULL);
337 #endif
338     if (code)
339         return code;
340     tfile = afs_CFileOpen(&volumeInode);
341     afs_CFileTruncate(tfile, 0);
342     afs_CFileClose(tfile);
343     return 0;
344 }
345
346 /*
347  * afs_InitCacheInfo
348  *
349  * Description:
350  *      Set up the given file as the AFS cache info file.
351  *
352  * Parameters:
353  *      afile : Name of the file assumed to be the cache info file
354  *              for the Cache Manager; it will be used as such.
355  * Side Effects:  This sets afs_fragsize, which is used in the cache usage 
356  *                calculations such as in afs_adjustsize()
357  *
358  * Environment:
359  *      This function is called only during initialization.  The given
360  *      file should NOT be truncated to 0 lenght; its contents descrebe
361  *      what data is really in the cache.
362  *
363  *      WARNING: data will be written to this file over time by AFS.
364  *
365  * NOTE: Starting to use separate osi_InitCacheInfo() routines to clean up
366  * code.
367  *
368  */
369 int
370 afs_InitCacheInfo(register char *afile)
371 {
372     register afs_int32 code;
373     struct osi_stat tstat;
374     register struct osi_file *tfile;
375     struct afs_fheader theader;
376 #ifndef AFS_LINUX22_ENV
377     struct vnode *filevp;
378 #endif
379     int goodFile;
380
381     AFS_STATCNT(afs_InitCacheInfo);
382     if (cacheDiskType != AFS_FCACHE_TYPE_UFS)
383         osi_Panic("afs_InitCacheInfo --- called for non-ufs cache!");
384 #ifdef AFS_LINUX22_ENV
385     code = osi_InitCacheInfo(afile);
386     if (code)
387         return code;
388 #else
389     code = gop_lookupname(afile, AFS_UIOSYS, 0, &filevp);
390     if (code || !filevp)
391         return ENOENT;
392     {
393 #if     defined(AFS_SUN56_ENV)
394         struct statvfs64 st;
395 #elif   defined(AFS_HPUX102_ENV)
396         struct k_statvfs st;
397 #elif   defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) ||defined(AFS_HPUX100_ENV)
398         struct statvfs st;
399 #elif defined(AFS_DUX40_ENV)
400         struct nstatfs st;
401 #elif defined(AFS_DARWIN80_ENV)
402         struct vfsstatfs st;
403 #else
404         struct statfs st;
405 #endif /* SUN56 */
406
407 #if     defined(AFS_SGI_ENV)
408 #ifdef AFS_SGI65_ENV
409         VFS_STATVFS(filevp->v_vfsp, &st, NULL, code);
410         if (!code)
411 #else
412         if (!VFS_STATFS(filevp->v_vfsp, &st, NULL))
413 #endif /* AFS_SGI65_ENV */
414 #elif   defined(AFS_SUN5_ENV) || defined(AFS_HPUX100_ENV)
415         if (!VFS_STATVFS(filevp->v_vfsp, &st))
416 #elif defined(AFS_OSF_ENV)
417
418         VFS_STATFS(filevp->v_vfsp, code);
419         /* struct copy */
420         st = filevp->v_vfsp->m_stat;
421         if (code == 0)
422 #elif defined(AFS_AIX41_ENV)
423         if (!VFS_STATFS(filevp->v_vfsp, &st, &afs_osi_cred))
424 #elif defined(AFS_LINUX20_ENV)
425         {
426             KERNEL_SPACE_DECL;
427             TO_USER_SPACE();
428
429             VFS_STATFS(filevp->v_vfsp, &st);
430             TO_KERNEL_SPACE();
431         }
432 #elif defined(AFS_DARWIN80_ENV)
433         afs_cacheVfsp = vnode_mount(filevp);
434         if (afs_cacheVfsp && ((st = *(vfs_statfs(afs_cacheVfsp))),1))
435 #elif defined(AFS_DARWIN_ENV)
436         if (!VFS_STATFS(filevp->v_mount, &st, current_proc()))
437 #elif defined(AFS_FBSD50_ENV)
438         if (!VFS_STATFS(filevp->v_mount, &st, curthread))
439 #elif defined(AFS_XBSD_ENV)
440         if (!VFS_STATFS(filevp->v_mount, &st, curproc))
441 #else
442         if (!VFS_STATFS(filevp->v_vfsp, &st))
443 #endif /* SGI... */
444 #if     defined(AFS_SUN5_ENV) || defined(AFS_HPUX100_ENV)
445             if (strcmp("zfs", st.f_basetype) == 0) {
446                 /*
447                  * Files in ZFS can take up to around the next
448                  * recordsize boundary after being truncated. recordsize
449                  * is reported in statvfs by f_bsize, so use that
450                  * instead.
451                  */
452                 afs_fsfragsize = st.f_bsize - 1;
453             } else {
454                 afs_fsfragsize = st.f_frsize - 1;
455             }
456 #else
457             afs_fsfragsize = st.f_bsize - 1;
458 #endif
459     }
460 #if defined(AFS_LINUX20_ENV)
461     cacheInode.ufs = filevp->i_ino;
462     afs_cacheSBp = filevp->i_sb;
463 #elif defined(AFS_XBSD_ENV)
464     cacheInode.ufs = VTOI(filevp)->i_number;
465     cacheDev.mp = filevp->v_mount;
466     cacheDev.held_vnode = filevp;
467     vref(filevp);               /* Make sure mount point stays busy. XXX */
468 #if !defined(AFS_OBSD_ENV)
469     afs_cacheVfsp = filevp->v_vfsp;
470 #endif
471 #else
472 #if defined(AFS_SGI62_ENV) || defined(AFS_HAVE_VXFS) || defined(AFS_DARWIN_ENV)
473     afs_InitDualFSCacheOps(filevp);
474 #endif
475 #ifndef AFS_CACHE_VNODE_PATH
476 #ifndef AFS_DARWIN80_ENV
477     afs_cacheVfsp = filevp->v_vfsp;
478 #endif
479     cacheInode.ufs = afs_vnodeToInumber(filevp);
480 #else
481     cacheInode.ufs = AFS_CACHE_ITEMS_INODE;
482 #endif
483     cacheDev.dev = afs_vnodeToDev(filevp);
484 #endif /* AFS_LINUX20_ENV */
485     AFS_RELE(filevp);
486 #endif /* AFS_LINUX22_ENV */
487     if (afs_fsfragsize < AFS_MIN_FRAGSIZE) {
488         afs_fsfragsize = AFS_MIN_FRAGSIZE;
489     }
490     tfile = osi_UFSOpen(&cacheInode);
491     afs_osi_Stat(tfile, &tstat);
492     cacheInfoModTime = tstat.mtime;
493     code = afs_osi_Read(tfile, -1, &theader, sizeof(theader));
494     goodFile = 0;
495     if (code == sizeof(theader)) {
496         /* read the header correctly */
497         if (theader.magic == AFS_FHMAGIC
498             && theader.firstCSize == AFS_FIRSTCSIZE
499             && theader.otherCSize == AFS_OTHERCSIZE
500             && theader.version == AFS_CI_VERSION)
501             goodFile = 1;
502     }
503     if (!goodFile) {
504         /* write out a good file label */
505         theader.magic = AFS_FHMAGIC;
506         theader.firstCSize = AFS_FIRSTCSIZE;
507         theader.otherCSize = AFS_OTHERCSIZE;
508         theader.version = AFS_CI_VERSION;
509         afs_osi_Write(tfile, 0, &theader, sizeof(theader));
510         /*
511          * Truncate the rest of the file, since it may be arbitrarily
512          * wrong
513          */
514         osi_UFSTruncate(tfile, sizeof(struct afs_fheader));
515     }
516     /* Leave the file open now, since reopening the file makes public pool
517      * vnode systems (like OSF/Alpha) much harder to handle, That's because
518      * they can do a vnode recycle operation any time we open a file, which
519      * we'd do on any afs_GetDSlot call, etc.
520      */
521     afs_cacheInodep = (struct osi_file *)tfile;
522     return 0;
523 }
524
525 int afs_resourceinit_flag = 0;
526 int
527 afs_ResourceInit(int preallocs)
528 {
529     register afs_int32 i;
530     static struct rx_securityClass *secobj;
531
532     AFS_STATCNT(afs_ResourceInit);
533     AFS_RWLOCK_INIT(&afs_xuser, "afs_xuser");
534     AFS_RWLOCK_INIT(&afs_xvolume, "afs_xvolume");
535     AFS_RWLOCK_INIT(&afs_xserver, "afs_xserver");
536     AFS_RWLOCK_INIT(&afs_xsrvAddr, "afs_xsrvAddr");
537     AFS_RWLOCK_INIT(&afs_icl_lock, "afs_icl_lock");
538     AFS_RWLOCK_INIT(&afs_xinterface, "afs_xinterface");
539     LOCK_INIT(&afs_puttofileLock, "afs_puttofileLock");
540 #ifndef AFS_FBSD_ENV
541     LOCK_INIT(&osi_fsplock, "osi_fsplock");
542     LOCK_INIT(&osi_flplock, "osi_flplock");
543 #endif
544     AFS_RWLOCK_INIT(&afs_xconn, "afs_xconn");
545
546     afs_CellInit();
547     afs_InitCBQueue(1);         /* initialize callback queues */
548
549     if (afs_resourceinit_flag == 0) {
550         afs_resourceinit_flag = 1;
551         for (i = 0; i < NFENTRIES; i++)
552             fvTable[i] = 0;
553         for (i = 0; i < MAXNUMSYSNAMES; i++)
554             afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME);
555         afs_sysname = afs_sysnamelist[0];
556         strcpy(afs_sysname, SYS_NAME);
557         afs_sysnamecount = 1;
558         afs_sysnamegen++;
559     }
560
561     secobj = rxnull_NewServerSecurityObject();
562     afs_server =
563         rx_NewService(0, 1, "afs", &secobj, 1, RXAFSCB_ExecuteRequest);
564     afs_server =
565         rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", &secobj, 1,
566                       RXSTATS_ExecuteRequest);
567     rx_StartServer(0);
568     afs_osi_Wakeup(&afs_server);        /* wakeup anyone waiting for it */
569     return 0;
570
571 }                               /*afs_ResourceInit */
572
573 #if defined(AFS_AIX_ENV) && !defined(AFS_AIX51_ENV)
574
575 /*
576  * AIX dynamic sizeof(struct proc)
577  *
578  * AIX keeps its proc structures in an array.  The size of struct proc
579  * varies from release to release of the OS.  In order to maintain
580  * binary compatibility with releases later than what we build on, we
581  * need to determine the size of struct proc at run time.
582  *
583  * We need this in order to walk the proc[] array to do PAG garbage
584  * collection.
585  *
586  * We also need this in order to support 'klog -setpag', since the
587  * kernel code needs to locate the proc structure for the parent process
588  * of the current process.
589  *
590  * To compute sizeof(struct proc), we need the addresses of two proc
591  * structures and their corresponding pids.  Given the pids, we can use
592  * the PROCMASK() macro to compute their corresponding indices in the
593  * proc[] array.  By dividing the distance between the pointers by the
594  * number of proc structures, we can compute the size of a single proc
595  * structure.
596  *
597  * We know the base address of the proc table from v.vb_proc:
598  *
599  * <sys/sysconfig.h> declares sysconfig() and SYS_GETPARMS;
600  * (we don't use this, but I note it here for completeness)
601  *
602  * <sys/var.h> declares struct var and external variable v;
603  *
604  * v.v_proc             NPROC
605  * v.vb_proc            &proc[0]
606  * v.ve_proc            &proc[x] (current highwater mark for
607  *                                proc[] array usage)
608  *
609  * The first proc pointer is v.vb_proc, which is the proc structure for
610  * process 0.  Process 0's pointer to its first child is the other proc
611  * pointer.  If process 0 has no children, we simply give up and do not
612  * support features that require knowing the size of struct proc.
613  */
614
615 static void
616 afs_procsize_init(void)
617 {
618     afs_proc_t *p0;             /* pointer to process 0 */
619     afs_proc_t *pN;             /* pointer to process 0's first child */
620 #ifdef AFS_AIX51_ENV
621     struct pvproc *pV;
622 #endif
623     int pN_index;
624     ptrdiff_t pN_offset;
625     int procsize;
626
627     p0 = (afs_proc_t *)v.vb_proc;
628     if (!p0) {
629         afs_gcpags = AFS_GCPAGS_EPROC0;
630         return;
631     }
632 #ifdef AFS_AIX51_ENV
633     pN = NULL;
634     pV = p0->p_pvprocp;
635     if (pV) {
636         pV = pV->pv_child;
637         if (pV)
638             pN = pV->pv_procp;
639     }
640 #else
641     pN = p0->p_child;
642 #endif
643     if (!pN) {
644         afs_gcpags = AFS_GCPAGS_EPROCN;
645         return;
646     }
647
648     if (pN->p_pid == p0->p_pid) {
649         afs_gcpags = AFS_GCPAGS_EEQPID;
650         return;
651     }
652
653     pN_index = PROCMASK(pN->p_pid);
654     pN_offset = ((char *)pN - (char *)p0);
655     procsize = pN_offset / pN_index;
656
657     /*
658      * check that the computation was exact
659      */
660
661     if (pN_index * procsize != pN_offset) {
662         afs_gcpags = AFS_GCPAGS_EINEXACT;
663         return;
664     }
665
666     /*
667      * check that the proc table size is a multiple of procsize.
668      */
669
670     if ((((char *)v.ve_proc - (char *)v.vb_proc) % procsize) != 0) {
671         afs_gcpags = AFS_GCPAGS_EPROCEND;
672         return;
673     }
674
675     /* okay, use it */
676
677     afs_gcpags_procsize = procsize;
678 }
679 #endif
680
681 /*
682  * shutdown_cache
683  *
684  * Description:
685  *      Clean up and shut down the AFS cache.
686  *
687  * Parameters:
688  *      None.
689  *
690  * Environment:
691  *      Nothing interesting.
692  */
693 void
694 shutdown_cache(void)
695 {
696     AFS_STATCNT(shutdown_cache);
697     afs_WriteThroughDSlots();
698     if (afs_cold_shutdown) {
699         afs_cacheinit_flag = 0;
700         shutdown_dcache();
701         shutdown_vcache();
702
703         afs_cacheStats = 0;
704         afs_cacheFiles = afs_cacheBlocks = 0;
705         pag_epoch = maxIHint = nihints = usedihint = 0;
706         pagCounter = 0;
707 #if defined(AFS_XBSD_ENV)
708         vrele(volumeVnode);     /* let it go, finally. */
709         volumeVnode = NULL;
710         if (cacheDev.held_vnode) {
711             vrele(cacheDev.held_vnode);
712             cacheDev.held_vnode = NULL;
713         }
714 #endif
715         afs_reset_inode(&cacheInode);
716         afs_reset_inode(&volumeInode);
717         cacheInfoModTime = 0;
718
719         afs_fsfragsize = 1023;
720         memset(&afs_stats_cmperf, 0, sizeof(afs_stats_cmperf));
721         memset(&cacheDev, 0, sizeof(struct osi_dev));
722         osi_dnlc_shutdown();
723     }
724 #if defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_HAS_CRED)
725     put_cred(cache_creds);
726 #endif
727 }                               /*shutdown_cache */
728
729
730 void
731 shutdown_vnodeops(void)
732 {
733 #if !defined(AFS_SGI_ENV) && !defined(AFS_SUN5_ENV)
734     struct buf *afs_bread_freebp = 0;
735 #endif
736
737
738     AFS_STATCNT(shutdown_vnodeops);
739     if (afs_cold_shutdown) {
740 #ifndef AFS_SUN5_ENV            /* XXX */
741         lastWarnTime = 0;
742 #endif
743 #ifndef AFS_LINUX20_ENV
744         afs_rd_stash_i = 0;
745 #endif
746 #if !defined(AFS_SGI_ENV) && !defined(AFS_SUN5_ENV)
747         afs_bread_freebp = 0;
748 #endif
749         shutdown_mariner();
750     }
751 }
752
753
754 void
755 shutdown_AFS(void)
756 {
757     int i;
758     register struct srvAddr *sa;
759
760     AFS_STATCNT(shutdown_AFS);
761     if (afs_cold_shutdown) {
762         afs_resourceinit_flag = 0;
763         /* 
764          * Free Volumes table allocations 
765          */
766         {
767             struct volume *tv;
768             for (i = 0; i < NVOLS; i++) {
769                 for (tv = afs_volumes[i]; tv; tv = tv->next) {
770                     if (tv->name) {
771                         afs_osi_Free(tv->name, strlen(tv->name) + 1);
772                         tv->name = 0;
773                     }
774                 }
775                 afs_volumes[i] = 0;
776             }
777         }
778
779         /* 
780          * Free FreeVolList allocations 
781          */
782         afs_osi_Free(Initialafs_freeVolList,
783                      afs_memvolumes * sizeof(struct volume));
784         afs_freeVolList = Initialafs_freeVolList = 0;
785
786         /* XXX HACK fort MEM systems XXX 
787          *
788          * For -memcache cache managers when we run out of free in memory volumes
789          * we simply malloc more; we won't be able to free those additional volumes.
790          */
791
792
793
794         /* 
795          * Free Users table allocation 
796          */
797         {
798             struct unixuser *tu, *ntu;
799             for (i = 0; i < NUSERS; i++) {
800                 for (tu = afs_users[i]; tu; tu = ntu) {
801                     ntu = tu->next;
802                     if (tu->stp)
803                         afs_osi_Free(tu->stp, tu->stLen);
804                     if (tu->exporter)
805                         EXP_RELE(tu->exporter);
806                     afs_osi_Free(tu, sizeof(struct unixuser));
807                 }
808                 afs_users[i] = 0;
809             }
810         }
811
812         /* 
813          * Free Servers table allocation 
814          */
815         {
816             struct server *ts, *nts;
817             struct afs_conn *tc, *ntc;
818             register struct afs_cbr *tcbrp, *tbrp;
819
820             for (i = 0; i < NSERVERS; i++) {
821                 for (ts = afs_servers[i]; ts; ts = nts) {
822                     nts = ts->next;
823                     for (sa = ts->addr; sa; sa = sa->next_sa) {
824                         if (sa->conns) {
825                             /*
826                              * Free all server's connection structs
827                              */
828                             tc = sa->conns;
829                             while (tc) {
830                                 ntc = tc->next;
831                                 AFS_GUNLOCK();
832                                 rx_DestroyConnection(tc->id);
833                                 AFS_GLOCK();
834                                 afs_osi_Free(tc, sizeof(struct afs_conn));
835                                 tc = ntc;
836                             }
837                         }
838                     }
839                     for (tcbrp = ts->cbrs; tcbrp; tcbrp = tbrp) {
840                         /*
841                          * Free all server's callback structs
842                          */
843                         tbrp = tcbrp->next;
844                         afs_FreeCBR(tcbrp);
845                     }
846                     afs_osi_Free(ts, sizeof(struct server));
847                 }
848                 afs_servers[i] = 0;
849             }
850         }
851         for (i = 0; i < NFENTRIES; i++)
852             fvTable[i] = 0;
853         /* Reinitialize local globals to defaults */
854         for (i = 0; i < MAXNUMSYSNAMES; i++)
855             afs_osi_Free(afs_sysnamelist[i], MAXSYSNAME);
856         afs_sysname = 0;
857         afs_sysnamecount = 0;
858         afs_marinerHost = 0;
859         afs_setTimeHost = NULL;
860         afs_volCounter = 1;
861         afs_waitForever = afs_waitForeverCount = 0;
862         afs_FVIndex = -1;
863         afs_server = (struct rx_service *)0;
864         AFS_RWLOCK_INIT(&afs_xconn, "afs_xconn");
865         memset(&afs_rootFid, 0, sizeof(struct VenusFid));
866         AFS_RWLOCK_INIT(&afs_xuser, "afs_xuser");
867         AFS_RWLOCK_INIT(&afs_xvolume, "afs_xvolume");
868         AFS_RWLOCK_INIT(&afs_xserver, "afs_xserver");
869         LOCK_INIT(&afs_puttofileLock, "afs_puttofileLock");
870
871         shutdown_cell();
872         shutdown_server();
873     }
874 }