2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Dynamic /afs volume support.
15 * afs_IsDynrootMountFid
18 * afs_GetDynrootMountFid
22 * afs_DynrootInvalidate
26 * afs_SetDynrootEnable
27 * afs_GetDynrootEnable
28 * afs_DynrootVOPRemove
29 * afs_DynrootVOPSymlink
33 #include <afsconfig.h>
34 #include "afs/param.h"
37 #include "afs/sysincludes.h" /* Standard vendor system headers */
38 #include "afsincludes.h"
39 #include "afs/afs_osi.h"
43 #include "afs/prs_fs.h"
45 #include "afs/afs_dynroot.h"
47 #define AFS_DYNROOT_CELLNAME "dynroot"
48 #define AFS_DYNROOT_VOLUME 1
49 #define AFS_DYNROOT_VNODE 1
50 #define AFS_DYNROOT_MOUNT_VNODE 3
51 #define AFS_DYNROOT_UNIQUE 1
53 static int afs_dynrootInit
= 0;
54 static int afs_dynrootEnable
= 0;
55 static int afs_dynrootCell
= 0;
57 afs_rwlock_t afs_dynrootDirLock
;
58 /* Start of variables protected by afs_dynrootDirLock */
59 static char *afs_dynrootDir
= NULL
;
60 static int afs_dynrootDirLen
;
61 static char *afs_dynrootMountDir
= NULL
;
62 static int afs_dynrootMountDirLen
;
63 static int afs_dynrootDirLinkcnt
;
64 static int afs_dynrootDirVersion
;
65 static int afs_dynrootVersion
= 1;
66 static int afs_dynrootVersionHigh
= 1;
67 /* End of variables protected by afs_dynrootDirLock */
69 /* A dynamically-created symlink in a dynroot /afs */
70 struct afs_dynSymlink
{
71 struct afs_dynSymlink
*next
;
77 afs_rwlock_t afs_dynSymlinkLock
;
78 /* Start of variables protected by afs_dynSymlinkLock */
79 static struct afs_dynSymlink
*afs_dynSymlinkBase
= NULL
;
80 static int afs_dynSymlinkIndex
= 0;
81 /* End of variables protected by afs_dynSymlinkLock */
84 * Set up a cell for dynroot if it's not there yet.
87 afs_dynrootCellInit(void)
89 if (!afs_dynrootCell
) {
90 afs_int32 cellHosts
[AFS_MAXCELLHOSTS
];
94 memset(cellHosts
, 0, sizeof(cellHosts
));
96 afs_NewCell(AFS_DYNROOT_CELLNAME
, cellHosts
, CNoSUID
| CNoAFSDB
,
100 tc
= afs_GetCellByName(AFS_DYNROOT_CELLNAME
, READ_LOCK
);
103 afs_dynrootCell
= tc
->cellNum
;
104 afs_PutCell(tc
, READ_LOCK
);
111 * Returns non-zero if the volume is the dynroot volume.
114 afs_IsDynrootVolume(struct volume
*v
)
116 return (afs_dynrootEnable
117 && v
->cell
== afs_dynrootCell
118 && v
->volume
== AFS_DYNROOT_VOLUME
);
122 * Returns non-zero iff fid corresponds to the top of the dynroot volume.
125 _afs_IsDynrootFid(struct VenusFid
*fid
)
127 return (fid
->Cell
== afs_dynrootCell
128 && fid
->Fid
.Volume
== AFS_DYNROOT_VOLUME
129 && fid
->Fid
.Vnode
== AFS_DYNROOT_VNODE
130 && fid
->Fid
.Unique
== AFS_DYNROOT_UNIQUE
);
134 afs_IsDynrootFid(struct VenusFid
*fid
)
136 return (afs_dynrootEnable
&& _afs_IsDynrootFid(fid
));
140 afs_IsDynrootMountFid(struct VenusFid
*fid
)
142 return (fid
->Cell
== afs_dynrootCell
143 && fid
->Fid
.Volume
== AFS_DYNROOT_VOLUME
144 && fid
->Fid
.Vnode
== AFS_DYNROOT_MOUNT_VNODE
145 && fid
->Fid
.Unique
== AFS_DYNROOT_UNIQUE
);
149 afs_IsDynrootAnyFid(struct VenusFid
*fid
)
151 return (fid
->Cell
== afs_dynrootCell
152 && fid
->Fid
.Volume
== AFS_DYNROOT_VOLUME
);
156 * Obtain the magic dynroot volume Fid.
159 afs_GetDynrootFid(struct VenusFid
*fid
)
161 fid
->Cell
= afs_dynrootCell
;
162 fid
->Fid
.Volume
= AFS_DYNROOT_VOLUME
;
163 fid
->Fid
.Vnode
= AFS_DYNROOT_VNODE
;
164 fid
->Fid
.Unique
= AFS_DYNROOT_UNIQUE
;
168 afs_GetDynrootMountFid(struct VenusFid
*fid
)
170 fid
->Cell
= afs_dynrootCell
;
171 fid
->Fid
.Volume
= AFS_DYNROOT_VOLUME
;
172 fid
->Fid
.Vnode
= AFS_DYNROOT_MOUNT_VNODE
;
173 fid
->Fid
.Unique
= AFS_DYNROOT_UNIQUE
;
177 * Returns non-zero iff avc is a pointer to the dynroot /afs vnode.
180 afs_IsDynroot(struct vcache
*avc
)
182 return afs_IsDynrootFid(&avc
->f
.fid
);
186 afs_IsDynrootMount(struct vcache
*avc
)
188 return afs_IsDynrootMountFid(&avc
->f
.fid
);
192 afs_IsDynrootAny(struct vcache
*avc
)
194 return afs_IsDynrootAnyFid(&avc
->f
.fid
);
198 * Given the current page and chunk pointers in a directory, adjust them
199 * appropriately so that the given file name can be appended. Used for
200 * computing the size of a directory.
203 afs_dynroot_computeDirEnt(char *name
, int *curPageP
, int *curChunkP
)
207 esize
= afs_dir_NameBlobs(name
);
208 if (*curChunkP
+ esize
> EPP
) {
216 * Add directory entry by given name to a directory. Assumes the
217 * caller has allocated the directory to be large enough to hold
218 * the necessary entry.
221 afs_dynroot_addDirEnt(struct DirHeader
*dirHeader
, int *curPageP
,
222 int *curChunkP
, char *name
, int vnode
)
224 char *dirBase
= (char *)dirHeader
;
225 struct PageHeader
*pageHeader
;
226 struct DirEntry
*dirEntry
;
227 int sizeOfEntry
, i
, t1
, t2
;
228 int curPage
= *curPageP
;
229 int curChunk
= *curChunkP
;
233 * Check if we need to flip pages.. If so, init the new page.
235 sizeOfEntry
= afs_dir_NameBlobs(name
);
236 if (curChunk
+ sizeOfEntry
> EPP
) {
242 pageHeader
= (struct PageHeader
*)(dirBase
+ curPage
* AFS_PAGESIZE
);
244 pageHeader
->pgcount
= 0;
245 pageHeader
->tag
= htons(1234);
246 pageHeader
->freecount
= 0;
247 pageHeader
->freebitmap
[0] = 0x01;
248 for (i
= 1; i
< EPP
/ 8; i
++)
249 pageHeader
->freebitmap
[i
] = 0;
251 dirHeader
->alloMap
[curPage
] = EPP
- 1;
254 dirEntry
= (struct DirEntry
*)(pageHeader
+ curChunk
);
256 dirEntry
->length
= 0;
258 dirEntry
->fid
.vnode
= htonl(vnode
);
259 dirEntry
->fid
.vunique
= htonl(1);
260 strcpy(dirEntry
->name
, name
);
262 for (i
= curChunk
; i
< curChunk
+ sizeOfEntry
; i
++) {
265 pageHeader
->freebitmap
[t1
] |= (1 << t2
);
269 * Add the new entry to the correct hash chain.
271 i
= afs_dir_DirHash(name
);
272 dirEntry
->next
= dirHeader
->hashTable
[i
];
273 dirHeader
->hashTable
[i
] = htons(curPage
* EPP
+ curChunk
);
275 curChunk
+= sizeOfEntry
;
276 dirHeader
->alloMap
[curPage
] -= sizeOfEntry
;
279 *curChunkP
= curChunk
;
283 * Invalidate the /afs vnode for dynroot; called when the underlying
284 * directory has changed and needs to be re-read.
287 afs_DynrootInvalidate(void)
291 struct VenusFid tfid
;
293 if (!afs_dynrootEnable
)
296 ObtainWriteLock(&afs_dynrootDirLock
, 687);
297 afs_dynrootVersion
++;
298 afs_dynrootVersionHigh
= osi_Time();
299 ReleaseWriteLock(&afs_dynrootDirLock
);
301 afs_GetDynrootFid(&tfid
);
304 ObtainReadLock(&afs_xvcache
);
305 tvc
= afs_FindVCache(&tfid
, &retry
, 0);
306 ReleaseReadLock(&afs_xvcache
);
309 afs_StaleVCacheFlags(tvc
, AFS_STALEVC_NOCB
, CUnique
);
315 * Regenerates the dynroot contents from the current list of
316 * cells. Useful when the list of cells has changed due to
317 * an AFSDB lookup, for instance.
320 afs_RebuildDynroot(void)
322 int cellidx
, maxcellidx
, i
;
323 int aliasidx
, maxaliasidx
;
325 struct cell_alias
*ca
;
326 int curChunk
, curPage
;
328 char *newDir
, *dotCell
;
329 struct DirHeader
*dirHeader
;
331 struct afs_dynSymlink
*ts
;
334 ObtainReadLock(&afs_dynrootDirLock
);
335 newVersion
= afs_dynrootVersion
;
336 ReleaseReadLock(&afs_dynrootDirLock
);
339 * Compute the amount of space we need for the fake dir
344 /* Reserve space for "." and ".." */
347 /* Reserve space for the dynamic-mount directory */
348 afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME
, &curPage
, &curChunk
);
350 for (cellidx
= 0;; cellidx
++) {
351 c
= afs_GetCellByIndex(cellidx
, READ_LOCK
);
354 if ((c
->cellNum
== afs_dynrootCell
) || (c
->states
& CHush
)) {
355 afs_PutCell(c
, READ_LOCK
);
358 dotLen
= strlen(c
->cellName
) + 2;
359 dotCell
= afs_osi_Alloc(dotLen
);
360 osi_Assert(dotCell
!= NULL
);
361 strcpy(dotCell
, ".");
362 afs_strcat(dotCell
, c
->cellName
);
364 afs_dynroot_computeDirEnt(c
->cellName
, &curPage
, &curChunk
);
365 afs_dynroot_computeDirEnt(dotCell
, &curPage
, &curChunk
);
367 afs_osi_Free(dotCell
, dotLen
);
368 afs_PutCell(c
, READ_LOCK
);
370 maxcellidx
= cellidx
;
372 for (aliasidx
= 0;; aliasidx
++) {
373 ca
= afs_GetCellAlias(aliasidx
);
377 dotLen
= strlen(ca
->alias
) + 2;
378 dotCell
= afs_osi_Alloc(dotLen
);
379 osi_Assert(dotCell
!= NULL
);
380 strcpy(dotCell
, ".");
381 afs_strcat(dotCell
, ca
->alias
);
383 afs_dynroot_computeDirEnt(ca
->alias
, &curPage
, &curChunk
);
384 afs_dynroot_computeDirEnt(dotCell
, &curPage
, &curChunk
);
386 afs_osi_Free(dotCell
, dotLen
);
387 afs_PutCellAlias(ca
);
389 maxaliasidx
= aliasidx
;
391 ObtainReadLock(&afs_dynSymlinkLock
);
392 ts
= afs_dynSymlinkBase
;
394 afs_dynroot_computeDirEnt(ts
->name
, &curPage
, &curChunk
);
398 dirSize
= (curPage
+ 1) * AFS_PAGESIZE
;
399 newDir
= afs_osi_Alloc(dirSize
);
400 osi_Assert(newDir
!= NULL
);
403 * Now actually construct the directory.
407 dirHeader
= (struct DirHeader
*)newDir
;
409 dirHeader
->header
.pgcount
= 0;
410 dirHeader
->header
.tag
= htons(1234);
411 dirHeader
->header
.freecount
= 0;
413 dirHeader
->header
.freebitmap
[0] = 0xff;
414 dirHeader
->header
.freebitmap
[1] = 0x1f;
415 for (i
= 2; i
< EPP
/ 8; i
++)
416 dirHeader
->header
.freebitmap
[i
] = 0;
417 dirHeader
->alloMap
[0] = EPP
- DHE
- 1;
418 for (i
= 1; i
< MAXPAGES
; i
++)
419 dirHeader
->alloMap
[i
] = EPP
;
420 memset(dirHeader
->hashTable
, 0, NHASHENT
* sizeof(dirHeader
->hashTable
[0]));
422 /* Install ".", "..", and the dynamic mount directory */
423 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, ".", 1);
424 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, "..", 1);
425 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
,
426 AFS_DYNROOT_MOUNTNAME
, AFS_DYNROOT_MOUNT_VNODE
);
429 for (cellidx
= 0; cellidx
< maxcellidx
; cellidx
++) {
430 c
= afs_GetCellByIndex(cellidx
, READ_LOCK
);
433 if ((c
->cellNum
== afs_dynrootCell
) || (c
->states
& CHush
)) {
434 afs_PutCell(c
, READ_LOCK
);
438 dotLen
= strlen(c
->cellName
) + 2;
439 dotCell
= afs_osi_Alloc(dotLen
);
440 osi_Assert(dotCell
!= NULL
);
441 strcpy(dotCell
, ".");
442 afs_strcat(dotCell
, c
->cellName
);
443 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, c
->cellName
,
444 VNUM_FROM_CIDX_RW(cellidx
, 0));
445 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, dotCell
,
446 VNUM_FROM_CIDX_RW(cellidx
, 1));
447 afs_osi_Free(dotCell
, dotLen
);
450 afs_PutCell(c
, READ_LOCK
);
453 for (aliasidx
= 0; aliasidx
< maxaliasidx
; aliasidx
++) {
454 ca
= afs_GetCellAlias(aliasidx
);
458 dotLen
= strlen(ca
->alias
) + 2;
459 dotCell
= afs_osi_Alloc(dotLen
);
460 osi_Assert(dotCell
!= NULL
);
461 strcpy(dotCell
, ".");
462 afs_strcat(dotCell
, ca
->alias
);
463 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, ca
->alias
,
464 VNUM_FROM_CAIDX_RW(aliasidx
, 0));
465 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, dotCell
,
466 VNUM_FROM_CAIDX_RW(aliasidx
, 1));
467 afs_osi_Free(dotCell
, dotLen
);
468 afs_PutCellAlias(ca
);
471 ts
= afs_dynSymlinkBase
;
473 int vnum
= VNUM_FROM_TYPEID(VN_TYPE_SYMLINK
, ts
->index
);
474 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, ts
->name
, vnum
);
478 ReleaseReadLock(&afs_dynSymlinkLock
);
480 ObtainWriteLock(&afs_dynrootDirLock
, 549);
482 afs_osi_Free(afs_dynrootDir
, afs_dynrootDirLen
);
483 afs_dynrootDir
= newDir
;
484 afs_dynrootDirLen
= dirSize
;
485 afs_dynrootDirLinkcnt
= linkCount
;
486 afs_dynrootDirVersion
= newVersion
;
487 ReleaseWriteLock(&afs_dynrootDirLock
);
491 afs_RebuildDynrootMount(void)
494 int curChunk
, curPage
;
496 struct DirHeader
*dirHeader
;
498 newDir
= afs_osi_Alloc(AFS_PAGESIZE
);
499 osi_Assert(newDir
!= NULL
);
502 * Now actually construct the directory.
506 dirHeader
= (struct DirHeader
*)newDir
;
508 dirHeader
->header
.pgcount
= 0;
509 dirHeader
->header
.tag
= htons(1234);
510 dirHeader
->header
.freecount
= 0;
512 dirHeader
->header
.freebitmap
[0] = 0xff;
513 dirHeader
->header
.freebitmap
[1] = 0x1f;
514 for (i
= 2; i
< EPP
/ 8; i
++)
515 dirHeader
->header
.freebitmap
[i
] = 0;
516 dirHeader
->alloMap
[0] = EPP
- DHE
- 1;
517 for (i
= 1; i
< MAXPAGES
; i
++)
518 dirHeader
->alloMap
[i
] = EPP
;
519 memset(dirHeader
->hashTable
, 0, NHASHENT
* sizeof(dirHeader
->hashTable
[0]));
521 /* Install "." and ".." */
522 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, ".", 1);
523 afs_dynroot_addDirEnt(dirHeader
, &curPage
, &curChunk
, "..", 1);
525 ObtainWriteLock(&afs_dynrootDirLock
, 549);
526 if (afs_dynrootMountDir
)
527 afs_osi_Free(afs_dynrootMountDir
, afs_dynrootMountDirLen
);
528 afs_dynrootMountDir
= newDir
;
529 afs_dynrootMountDirLen
= AFS_PAGESIZE
;
530 ReleaseWriteLock(&afs_dynrootDirLock
);
534 * Returns a pointer to the base of the dynroot directory in memory,
535 * length thereof, and a FetchStatus.
538 afs_GetDynroot(char **dynrootDir
, int *dynrootLen
,
539 struct AFSFetchStatus
*status
)
541 ObtainReadLock(&afs_dynrootDirLock
);
542 if (!afs_dynrootDir
|| afs_dynrootDirVersion
!= afs_dynrootVersion
) {
543 ReleaseReadLock(&afs_dynrootDirLock
);
544 afs_RebuildDynroot();
545 ObtainReadLock(&afs_dynrootDirLock
);
549 *dynrootDir
= afs_dynrootDir
;
551 *dynrootLen
= afs_dynrootDirLen
;
554 memset(status
, 0, sizeof(struct AFSFetchStatus
));
555 status
->FileType
= Directory
;
556 status
->LinkCount
= afs_dynrootDirLinkcnt
;
557 status
->Length
= afs_dynrootDirLen
;
558 status
->DataVersion
= afs_dynrootVersion
;
559 status
->CallerAccess
= PRSFS_LOOKUP
| PRSFS_READ
;
560 status
->AnonymousAccess
= PRSFS_LOOKUP
| PRSFS_READ
;
561 status
->UnixModeBits
= 0755;
562 status
->ParentVnode
= 1;
563 status
->ParentUnique
= 1;
564 status
->dataVersionHigh
= afs_dynrootVersionHigh
;
569 afs_GetDynrootMount(char **dynrootDir
, int *dynrootLen
,
570 struct AFSFetchStatus
*status
)
572 ObtainReadLock(&afs_dynrootDirLock
);
573 if (!afs_dynrootMountDir
) {
574 ReleaseReadLock(&afs_dynrootDirLock
);
575 afs_RebuildDynrootMount();
576 ObtainReadLock(&afs_dynrootDirLock
);
580 *dynrootDir
= afs_dynrootMountDir
;
582 *dynrootLen
= afs_dynrootMountDirLen
;
585 memset(status
, 0, sizeof(struct AFSFetchStatus
));
586 status
->FileType
= Directory
;
587 status
->LinkCount
= 1;
588 status
->Length
= afs_dynrootMountDirLen
;
589 status
->DataVersion
= 1;
590 status
->CallerAccess
= PRSFS_LOOKUP
| PRSFS_READ
;
591 status
->AnonymousAccess
= PRSFS_LOOKUP
| PRSFS_READ
;
592 status
->UnixModeBits
= 0755;
593 status
->ParentVnode
= 1;
594 status
->ParentUnique
= 1;
595 status
->dataVersionHigh
= 0;
600 * Puts back the dynroot read lock.
605 ReleaseReadLock(&afs_dynrootDirLock
);
609 * Inform dynroot that a new vnode is being created. Return value
610 * is non-zero if this vnode is handled by dynroot, in which case
611 * FetchStatus will be filled in.
614 afs_DynrootNewVnode(struct vcache
*avc
, struct AFSFetchStatus
*status
)
616 char *bp
, tbuf
[CVBS
];
618 if (_afs_IsDynrootFid(&avc
->f
.fid
)) {
619 if (!afs_dynrootEnable
)
621 afs_GetDynroot(0, 0, status
);
626 if (afs_IsDynrootMount(avc
)) {
627 afs_GetDynrootMount(0, 0, status
);
633 * Check if this is an entry under /afs, e.g. /afs/cellname.
635 if (avc
->f
.fid
.Cell
== afs_dynrootCell
636 && avc
->f
.fid
.Fid
.Volume
== AFS_DYNROOT_VOLUME
) {
639 struct cell_alias
*ca
;
640 int namelen
, linklen
, cellidx
, rw
;
642 memset(status
, 0, sizeof(struct AFSFetchStatus
));
644 status
->FileType
= SymbolicLink
;
645 status
->LinkCount
= 1;
646 status
->DataVersion
= 1;
647 status
->CallerAccess
= PRSFS_LOOKUP
| PRSFS_READ
;
648 status
->AnonymousAccess
= PRSFS_LOOKUP
| PRSFS_READ
;
649 status
->ParentVnode
= 1;
650 status
->ParentUnique
= 1;
652 if (VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
) == VN_TYPE_SYMLINK
) {
653 struct afs_dynSymlink
*ts
;
654 int index
= VNUM_TO_VNID(avc
->f
.fid
.Fid
.Vnode
);
656 ObtainReadLock(&afs_dynSymlinkLock
);
657 ts
= afs_dynSymlinkBase
;
659 if (ts
->index
== index
)
665 linklen
= strlen(ts
->target
);
666 avc
->linkData
= afs_osi_Alloc(linklen
+ 1);
667 osi_Assert(avc
->linkData
!= NULL
);
668 strcpy(avc
->linkData
, ts
->target
);
670 status
->Length
= linklen
;
671 status
->UnixModeBits
= 0755;
673 ReleaseReadLock(&afs_dynSymlinkLock
);
681 if (VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
) != VN_TYPE_CELL
682 && VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
) != VN_TYPE_ALIAS
683 && VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
) != VN_TYPE_MOUNT
) {
684 afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
685 VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
));
689 cellidx
= VNUM_TO_CIDX(avc
->f
.fid
.Fid
.Vnode
);
690 rw
= VNUM_TO_RW(avc
->f
.fid
.Fid
.Vnode
);
692 if (VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
) == VN_TYPE_ALIAS
) {
695 ca
= afs_GetCellAlias(cellidx
);
697 afs_warn("dynroot vnode inconsistency, can't find alias %d\n",
703 * linkData needs to contain the name of the cell
704 * we're aliasing for.
708 afs_warn("dynroot: alias %s missing real cell name\n",
710 avc
->linkData
= afs_strdup("unknown");
713 int namelen
= strlen(realName
);
714 linklen
= rw
+ namelen
;
715 avc
->linkData
= afs_osi_Alloc(linklen
+ 1);
716 osi_Assert(avc
->linkData
!= NULL
);
717 strcpy(avc
->linkData
, rw
? "." : "");
718 afs_strcat(avc
->linkData
, realName
);
721 status
->UnixModeBits
= 0755;
722 afs_PutCellAlias(ca
);
724 } else if (VNUM_TO_VNTYPE(avc
->f
.fid
.Fid
.Vnode
) == VN_TYPE_MOUNT
) {
725 c
= afs_GetCellByIndex(cellidx
, READ_LOCK
);
727 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
733 * linkData needs to contain "%cell:volumeid"
735 namelen
= strlen(c
->cellName
);
736 bp
= afs_cv2string(&tbuf
[CVBS
], avc
->f
.fid
.Fid
.Unique
);
737 linklen
= 2 + namelen
+ strlen(bp
);
738 avc
->linkData
= afs_osi_Alloc(linklen
+ 1);
739 osi_Assert(avc
->linkData
!= NULL
);
740 strcpy(avc
->linkData
, "%");
741 afs_strcat(avc
->linkData
, c
->cellName
);
742 afs_strcat(avc
->linkData
, ":");
743 afs_strcat(avc
->linkData
, bp
);
745 status
->UnixModeBits
= 0644;
746 status
->ParentVnode
= AFS_DYNROOT_MOUNT_VNODE
;
747 afs_PutCell(c
, READ_LOCK
);
750 c
= afs_GetCellByIndex(cellidx
, READ_LOCK
);
752 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
758 * linkData needs to contain "#cell:root.cell" or "%cell:root.cell"
760 namelen
= strlen(c
->cellName
);
761 linklen
= 1 + namelen
+ 10;
762 avc
->linkData
= afs_osi_Alloc(linklen
+ 1);
763 osi_Assert(avc
->linkData
!= NULL
);
764 strcpy(avc
->linkData
, rw
? "%" : "#");
765 afs_strcat(avc
->linkData
, c
->cellName
);
766 afs_strcat(avc
->linkData
, ":root.cell");
768 status
->UnixModeBits
= 0644;
769 afs_PutCell(c
, READ_LOCK
);
772 status
->Length
= linklen
;
778 /* make sure we set type correctly when we do this. used to stay VREG */
780 switch (status
->FileType
) {
788 if (afs_fakestat_enable
&& (avc
->f
.m
.Mode
& 0111) == 0)
794 /* shouldn't happen */
801 * Make sure dynroot initialization has been done.
804 afs_InitDynroot(void)
808 AFS_RWLOCK_INIT(&afs_dynrootDirLock
, "afs_dynrootDirLock");
809 AFS_RWLOCK_INIT(&afs_dynSymlinkLock
, "afs_dynSymlinkLock");
811 return afs_dynrootCellInit();
815 * Enable or disable dynroot. Returns 0 if successful.
818 afs_SetDynrootEnable(int enable
)
820 afs_dynrootEnable
= enable
;
821 return afs_InitDynroot();
825 * Check if dynroot support is enabled.
828 afs_GetDynrootEnable(void)
830 return afs_dynrootEnable
;
834 * Remove a temporary symlink entry from /afs.
837 afs_DynrootVOPRemove(struct vcache
*avc
, afs_ucred_t
*acred
, char *aname
)
839 struct afs_dynSymlink
**tpps
;
840 struct afs_dynSymlink
*tps
;
843 #if defined(AFS_SUN510_ENV)
844 if (crgetruid(acred
))
846 if (afs_cr_uid(acred
))
850 ObtainWriteLock(&afs_dynSymlinkLock
, 97);
851 tpps
= &afs_dynSymlinkBase
;
854 if (afs_strcasecmp(aname
, tps
->name
) == 0) {
855 afs_osi_Free(tps
->name
, strlen(tps
->name
) + 1);
856 afs_osi_Free(tps
->target
, strlen(tps
->target
) + 1);
858 afs_osi_Free(tps
, sizeof(*tps
));
859 afs_dynSymlinkIndex
++;
865 ReleaseWriteLock(&afs_dynSymlinkLock
);
867 afs_DynrootInvalidate();
871 if (afs_CellOrAliasExists(aname
))
878 * Create a temporary symlink entry in /afs.
881 afs_DynrootVOPSymlink(struct vcache
*avc
, afs_ucred_t
*acred
,
882 char *aname
, char *atargetName
)
884 struct afs_dynSymlink
*tps
;
886 if (afs_cr_uid(acred
))
888 if (afs_CellOrAliasExists(aname
))
891 /* Check if it's already a symlink */
892 ObtainWriteLock(&afs_dynSymlinkLock
, 91);
893 tps
= afs_dynSymlinkBase
;
895 if (afs_strcasecmp(aname
, tps
->name
) == 0) {
896 ReleaseWriteLock(&afs_dynSymlinkLock
);
902 /* Doesn't already exist -- go ahead and create it */
903 tps
= afs_osi_Alloc(sizeof(*tps
));
904 osi_Assert(tps
!= NULL
);
905 tps
->index
= afs_dynSymlinkIndex
++;
906 tps
->next
= afs_dynSymlinkBase
;
907 tps
->name
= afs_osi_Alloc(strlen(aname
) + 1);
908 osi_Assert(tps
->name
!= NULL
);
909 strcpy(tps
->name
, aname
);
910 tps
->target
= afs_osi_Alloc(strlen(atargetName
) + 1);
911 osi_Assert(tps
->target
!= NULL
);
912 strcpy(tps
->target
, atargetName
);
913 afs_dynSymlinkBase
= tps
;
914 ReleaseWriteLock(&afs_dynSymlinkLock
);
916 afs_DynrootInvalidate();