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