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.
220 * In order to make sure that memory isn't being accidentally stomped, receive
221 * the size of the directory as an argument (dirSize) and use this info to
222 * calculate the maximum number of bytes that can be occupied by the name
226 afs_dynroot_addDirEnt(struct DirHeader *dirHeader, int *curPageP,
227 int *curChunkP, char *name, int vnode, size_t dirSize)
229 char *dirBase = (char *)dirHeader;
230 struct PageHeader *pageHeader;
231 struct DirEntry *dirEntry;
232 int sizeOfEntry, i, t1, t2;
233 int curPage = *curPageP;
234 int curChunk = *curChunkP;
236 size_t offset, limit;
239 * Check if we need to flip pages.. If so, init the new page.
241 sizeOfEntry = afs_dir_NameBlobs(name);
242 if (curChunk + sizeOfEntry > EPP) {
248 pageHeader = (struct PageHeader *)(dirBase + curPage * AFS_PAGESIZE);
250 pageHeader->pgcount = 0;
251 pageHeader->tag = htons(1234);
252 pageHeader->freecount = 0;
253 pageHeader->freebitmap[0] = 0x01;
254 for (i = 1; i < EPP / 8; i++)
255 pageHeader->freebitmap[i] = 0;
257 dirHeader->alloMap[curPage] = EPP - 1;
260 dirEntry = (struct DirEntry *)(pageHeader + curChunk);
262 dirEntry->length = 0;
264 dirEntry->fid.vnode = htonl(vnode);
265 dirEntry->fid.vunique = htonl(1);
267 osi_Assert(dirEntry->name > dirBase);
268 offset = dirEntry->name - dirBase;
269 osi_Assert(dirSize > offset);
270 limit = dirSize - offset;
272 * The caller must have ensured that the directory is large enough, so
273 * strlcpy() should never truncate the string.
275 strlcpy(dirEntry->name, name, limit);
277 for (i = curChunk; i < curChunk + sizeOfEntry; i++) {
280 pageHeader->freebitmap[t1] |= (1 << t2);
284 * Add the new entry to the correct hash chain.
286 i = afs_dir_DirHash(name);
287 dirEntry->next = dirHeader->hashTable[i];
288 dirHeader->hashTable[i] = htons(curPage * EPP + curChunk);
290 curChunk += sizeOfEntry;
291 dirHeader->alloMap[curPage] -= sizeOfEntry;
294 *curChunkP = curChunk;
298 * Invalidate the /afs vnode for dynroot; called when the underlying
299 * directory has changed and needs to be re-read.
302 afs_DynrootInvalidate(void)
305 struct VenusFid tfid;
307 if (!afs_dynrootEnable)
310 ObtainWriteLock(&afs_dynrootDirLock, 687);
311 afs_dynrootVersion++;
312 afs_dynrootVersionHigh = osi_Time();
313 ReleaseWriteLock(&afs_dynrootDirLock);
315 afs_GetDynrootFid(&tfid);
316 ObtainReadLock(&afs_xvcache);
317 tvc = afs_FindVCache(&tfid, 0);
318 ReleaseReadLock(&afs_xvcache);
320 afs_StaleVCacheFlags(tvc, AFS_STALEVC_NOCB, CUnique);
326 * Regenerates the dynroot contents from the current list of
327 * cells. Useful when the list of cells has changed due to
328 * an AFSDB lookup, for instance.
331 afs_RebuildDynroot(void)
333 int cellidx, maxcellidx, i;
334 int aliasidx, maxaliasidx;
336 struct cell_alias *ca;
337 int curChunk, curPage;
339 char *newDir, *dotCell;
340 struct DirHeader *dirHeader;
342 struct afs_dynSymlink *ts;
345 ObtainReadLock(&afs_dynrootDirLock);
346 newVersion = afs_dynrootVersion;
347 ReleaseReadLock(&afs_dynrootDirLock);
350 * Compute the amount of space we need for the fake dir
355 /* Reserve space for "." and ".." */
358 /* Reserve space for the dynamic-mount directory */
359 afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME, &curPage, &curChunk);
361 for (cellidx = 0;; cellidx++) {
362 c = afs_GetCellByIndex(cellidx, READ_LOCK);
365 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
366 afs_PutCell(c, READ_LOCK);
369 dotLen = strlen(c->cellName) + 2;
370 dotCell = afs_osi_Alloc(dotLen);
371 osi_Assert(dotCell != NULL);
372 osi_Assert(snprintf(dotCell, dotLen, ".%s", c->cellName) < dotLen);
374 afs_dynroot_computeDirEnt(c->cellName, &curPage, &curChunk);
375 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
377 afs_osi_Free(dotCell, dotLen);
378 afs_PutCell(c, READ_LOCK);
380 maxcellidx = cellidx;
382 for (aliasidx = 0;; aliasidx++) {
383 ca = afs_GetCellAlias(aliasidx);
387 dotLen = strlen(ca->alias) + 2;
388 dotCell = afs_osi_Alloc(dotLen);
389 osi_Assert(dotCell != NULL);
390 osi_Assert(snprintf(dotCell, dotLen, ".%s", ca->alias) < dotLen);
392 afs_dynroot_computeDirEnt(ca->alias, &curPage, &curChunk);
393 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
395 afs_osi_Free(dotCell, dotLen);
396 afs_PutCellAlias(ca);
398 maxaliasidx = aliasidx;
400 ObtainReadLock(&afs_dynSymlinkLock);
401 ts = afs_dynSymlinkBase;
403 afs_dynroot_computeDirEnt(ts->name, &curPage, &curChunk);
407 dirSize = (curPage + 1) * AFS_PAGESIZE;
408 newDir = afs_osi_Alloc(dirSize);
409 osi_Assert(newDir != NULL);
412 * Now actually construct the directory.
416 dirHeader = (struct DirHeader *)newDir;
418 dirHeader->header.pgcount = 0;
419 dirHeader->header.tag = htons(1234);
420 dirHeader->header.freecount = 0;
422 dirHeader->header.freebitmap[0] = 0xff;
423 dirHeader->header.freebitmap[1] = 0x1f;
424 for (i = 2; i < EPP / 8; i++)
425 dirHeader->header.freebitmap[i] = 0;
426 dirHeader->alloMap[0] = EPP - DHE - 1;
427 for (i = 1; i < MAXPAGES; i++)
428 dirHeader->alloMap[i] = EPP;
429 memset(dirHeader->hashTable, 0, NHASHENT * sizeof(dirHeader->hashTable[0]));
431 /* Install ".", "..", and the dynamic mount directory */
432 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1, dirSize);
433 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1, dirSize);
434 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
435 AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE,
439 for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
440 c = afs_GetCellByIndex(cellidx, READ_LOCK);
443 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
444 afs_PutCell(c, READ_LOCK);
448 dotLen = strlen(c->cellName) + 2;
449 dotCell = afs_osi_Alloc(dotLen);
450 osi_Assert(dotCell != NULL);
451 osi_Assert(snprintf(dotCell, dotLen, ".%s", c->cellName) < dotLen);
452 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName,
453 VNUM_FROM_CIDX_RW(cellidx, 0), dirSize);
454 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
455 VNUM_FROM_CIDX_RW(cellidx, 1), dirSize);
456 afs_osi_Free(dotCell, dotLen);
459 afs_PutCell(c, READ_LOCK);
462 for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) {
463 ca = afs_GetCellAlias(aliasidx);
467 dotLen = strlen(ca->alias) + 2;
468 dotCell = afs_osi_Alloc(dotLen);
469 osi_Assert(dotCell != NULL);
470 osi_Assert(snprintf(dotCell, dotLen, ".%s", ca->alias) < dotLen);
471 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias,
472 VNUM_FROM_CAIDX_RW(aliasidx, 0), dirSize);
473 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
474 VNUM_FROM_CAIDX_RW(aliasidx, 1), dirSize);
475 afs_osi_Free(dotCell, dotLen);
476 afs_PutCellAlias(ca);
479 ts = afs_dynSymlinkBase;
481 int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index);
482 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum,
487 ReleaseReadLock(&afs_dynSymlinkLock);
489 ObtainWriteLock(&afs_dynrootDirLock, 549);
491 afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
492 afs_dynrootDir = newDir;
493 afs_dynrootDirLen = dirSize;
494 afs_dynrootDirLinkcnt = linkCount;
495 afs_dynrootDirVersion = newVersion;
496 ReleaseWriteLock(&afs_dynrootDirLock);
500 afs_RebuildDynrootMount(void)
503 int curChunk, curPage;
505 struct DirHeader *dirHeader;
506 size_t dirSize = AFS_PAGESIZE;
508 newDir = afs_osi_Alloc(dirSize);
509 osi_Assert(newDir != NULL);
512 * Now actually construct the directory.
516 dirHeader = (struct DirHeader *)newDir;
518 dirHeader->header.pgcount = 0;
519 dirHeader->header.tag = htons(1234);
520 dirHeader->header.freecount = 0;
522 dirHeader->header.freebitmap[0] = 0xff;
523 dirHeader->header.freebitmap[1] = 0x1f;
524 for (i = 2; i < EPP / 8; i++)
525 dirHeader->header.freebitmap[i] = 0;
526 dirHeader->alloMap[0] = EPP - DHE - 1;
527 for (i = 1; i < MAXPAGES; i++)
528 dirHeader->alloMap[i] = EPP;
529 memset(dirHeader->hashTable, 0, NHASHENT * sizeof(dirHeader->hashTable[0]));
531 /* Install "." and ".." */
532 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1, dirSize);
533 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1, dirSize);
535 ObtainWriteLock(&afs_dynrootDirLock, 549);
536 if (afs_dynrootMountDir)
537 afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
538 afs_dynrootMountDir = newDir;
539 afs_dynrootMountDirLen = dirSize;
540 ReleaseWriteLock(&afs_dynrootDirLock);
544 * Returns a pointer to the base of the dynroot directory in memory,
545 * length thereof, and a FetchStatus.
548 afs_GetDynroot(char **dynrootDir, int *dynrootLen,
549 struct AFSFetchStatus *status)
551 ObtainReadLock(&afs_dynrootDirLock);
552 if (!afs_dynrootDir || afs_dynrootDirVersion != afs_dynrootVersion) {
553 ReleaseReadLock(&afs_dynrootDirLock);
554 afs_RebuildDynroot();
555 ObtainReadLock(&afs_dynrootDirLock);
559 *dynrootDir = afs_dynrootDir;
561 *dynrootLen = afs_dynrootDirLen;
564 memset(status, 0, sizeof(struct AFSFetchStatus));
565 status->FileType = Directory;
566 status->LinkCount = afs_dynrootDirLinkcnt;
567 status->Length = afs_dynrootDirLen;
568 status->DataVersion = afs_dynrootVersion;
569 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
570 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
571 status->UnixModeBits = 0755;
572 status->ParentVnode = 1;
573 status->ParentUnique = 1;
574 status->dataVersionHigh = afs_dynrootVersionHigh;
579 afs_GetDynrootMount(char **dynrootDir, int *dynrootLen,
580 struct AFSFetchStatus *status)
582 ObtainReadLock(&afs_dynrootDirLock);
583 if (!afs_dynrootMountDir) {
584 ReleaseReadLock(&afs_dynrootDirLock);
585 afs_RebuildDynrootMount();
586 ObtainReadLock(&afs_dynrootDirLock);
590 *dynrootDir = afs_dynrootMountDir;
592 *dynrootLen = afs_dynrootMountDirLen;
595 memset(status, 0, sizeof(struct AFSFetchStatus));
596 status->FileType = Directory;
597 status->LinkCount = 1;
598 status->Length = afs_dynrootMountDirLen;
599 status->DataVersion = 1;
600 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
601 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
602 status->UnixModeBits = 0755;
603 status->ParentVnode = 1;
604 status->ParentUnique = 1;
605 status->dataVersionHigh = 0;
610 * Puts back the dynroot read lock.
615 ReleaseReadLock(&afs_dynrootDirLock);
619 * Inform dynroot that a new vnode is being created. Return value
620 * is non-zero if this vnode is handled by dynroot, in which case
621 * FetchStatus will be filled in.
624 afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
626 char *bp, tbuf[CVBS];
628 if (_afs_IsDynrootFid(&avc->f.fid)) {
629 if (!afs_dynrootEnable)
631 afs_GetDynroot(0, 0, status);
636 if (afs_IsDynrootMount(avc)) {
637 afs_GetDynrootMount(0, 0, status);
643 * Check if this is an entry under /afs, e.g. /afs/cellname.
645 if (avc->f.fid.Cell == afs_dynrootCell
646 && avc->f.fid.Fid.Volume == AFS_DYNROOT_VOLUME) {
649 struct cell_alias *ca;
650 int namelen, linklen, cellidx, rw;
652 memset(status, 0, sizeof(struct AFSFetchStatus));
654 status->FileType = SymbolicLink;
655 status->LinkCount = 1;
656 status->DataVersion = 1;
657 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
658 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
659 status->ParentVnode = 1;
660 status->ParentUnique = 1;
662 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_SYMLINK) {
663 struct afs_dynSymlink *ts;
664 int index = VNUM_TO_VNID(avc->f.fid.Fid.Vnode);
666 ObtainReadLock(&afs_dynSymlinkLock);
667 ts = afs_dynSymlinkBase;
669 if (ts->index == index)
675 linklen = strlen(ts->target);
676 avc->linkData = afs_osi_Alloc(linklen + 1);
677 osi_Assert(avc->linkData != NULL);
678 osi_Assert(strlcpy(avc->linkData, ts->target, linklen + 1) <
681 status->Length = linklen;
682 status->UnixModeBits = 0755;
684 ReleaseReadLock(&afs_dynSymlinkLock);
692 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_CELL
693 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_ALIAS
694 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_MOUNT) {
695 afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
696 VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode));
700 cellidx = VNUM_TO_CIDX(avc->f.fid.Fid.Vnode);
701 rw = VNUM_TO_RW(avc->f.fid.Fid.Vnode);
703 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_ALIAS) {
706 ca = afs_GetCellAlias(cellidx);
708 afs_warn("dynroot vnode inconsistency, can't find alias %d\n",
714 * linkData needs to contain the name of the cell
715 * we're aliasing for.
719 afs_warn("dynroot: alias %s missing real cell name\n",
721 avc->linkData = afs_strdup("unknown");
724 int namelen = strlen(realName);
725 char *prefix = rw ? "." : "";
726 linklen = rw + namelen;
727 avc->linkData = afs_osi_Alloc(linklen + 1);
728 osi_Assert(avc->linkData != NULL);
729 osi_Assert(snprintf(avc->linkData, linklen + 1, "%s%s", prefix,
730 realName) < linklen + 1);
733 status->UnixModeBits = 0755;
734 afs_PutCellAlias(ca);
736 } else if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
737 c = afs_GetCellByIndex(cellidx, READ_LOCK);
739 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
745 * linkData needs to contain "%cell:volumeid"
747 namelen = strlen(c->cellName);
748 bp = afs_cv2string(&tbuf[CVBS], avc->f.fid.Fid.Unique);
749 linklen = 2 + namelen + strlen(bp);
750 avc->linkData = afs_osi_Alloc(linklen + 1);
751 osi_Assert(avc->linkData != NULL);
752 osi_Assert(snprintf(avc->linkData, linklen + 1, "%%%s:%s",
753 c->cellName, bp) < linklen + 1);
755 status->UnixModeBits = 0644;
756 status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE;
757 afs_PutCell(c, READ_LOCK);
760 char *prefix = rw ? "%" : "#";
762 c = afs_GetCellByIndex(cellidx, READ_LOCK);
764 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
770 * linkData needs to contain "#cell:root.cell" or "%cell:root.cell"
772 namelen = strlen(c->cellName);
773 linklen = 1 + namelen + 10;
774 avc->linkData = afs_osi_Alloc(linklen + 1);
775 osi_Assert(avc->linkData != NULL);
776 osi_Assert(snprintf(avc->linkData, linklen + 1, "%s%s:root.cell",
777 prefix, c->cellName) < linklen + 1);
779 status->UnixModeBits = 0644;
780 afs_PutCell(c, READ_LOCK);
783 status->Length = linklen;
789 /* make sure we set type correctly when we do this. used to stay VREG */
791 switch (status->FileType) {
799 if (afs_fakestat_enable && (avc->f.m.Mode & 0111) == 0)
805 /* shouldn't happen */
812 * Make sure dynroot initialization has been done.
815 afs_InitDynroot(void)
819 AFS_RWLOCK_INIT(&afs_dynrootDirLock, "afs_dynrootDirLock");
820 AFS_RWLOCK_INIT(&afs_dynSymlinkLock, "afs_dynSymlinkLock");
822 return afs_dynrootCellInit();
826 * Enable or disable dynroot. Returns 0 if successful.
829 afs_SetDynrootEnable(int enable)
831 afs_dynrootEnable = enable;
832 return afs_InitDynroot();
836 * Check if dynroot support is enabled.
839 afs_GetDynrootEnable(void)
841 return afs_dynrootEnable;
845 * Remove a temporary symlink entry from /afs.
848 afs_DynrootVOPRemove(struct vcache *avc, afs_ucred_t *acred, char *aname)
850 struct afs_dynSymlink **tpps;
851 struct afs_dynSymlink *tps;
854 #if defined(AFS_SUN510_ENV)
855 if (crgetruid(acred))
857 if (afs_cr_uid(acred))
861 ObtainWriteLock(&afs_dynSymlinkLock, 97);
862 tpps = &afs_dynSymlinkBase;
865 if (afs_strcasecmp(aname, tps->name) == 0) {
866 afs_osi_Free(tps->name, strlen(tps->name) + 1);
867 afs_osi_Free(tps->target, strlen(tps->target) + 1);
869 afs_osi_Free(tps, sizeof(*tps));
870 afs_dynSymlinkIndex++;
876 ReleaseWriteLock(&afs_dynSymlinkLock);
878 afs_DynrootInvalidate();
882 if (afs_CellOrAliasExists(aname))
889 * Create a temporary symlink entry in /afs.
892 afs_DynrootVOPSymlink(struct vcache *avc, afs_ucred_t *acred,
893 char *aname, char *atargetName)
895 struct afs_dynSymlink *tps;
898 if (afs_cr_uid(acred))
900 if (afs_CellOrAliasExists(aname))
903 /* Check if it's already a symlink */
904 ObtainWriteLock(&afs_dynSymlinkLock, 91);
905 tps = afs_dynSymlinkBase;
907 if (afs_strcasecmp(aname, tps->name) == 0) {
908 ReleaseWriteLock(&afs_dynSymlinkLock);
914 /* Doesn't already exist -- go ahead and create it */
915 tps = afs_osi_Alloc(sizeof(*tps));
916 osi_Assert(tps != NULL);
917 tps->index = afs_dynSymlinkIndex++;
918 tps->next = afs_dynSymlinkBase;
919 len = strlen(aname) + 1;
920 tps->name = afs_osi_Alloc(len);
921 osi_Assert(tps->name != NULL);
922 osi_Assert(strlcpy(tps->name, aname, len) < len);
923 len = strlen(atargetName) + 1;
924 tps->target = afs_osi_Alloc(len);
925 osi_Assert(tps->target != NULL);
926 osi_Assert(strlcpy(tps->target, atargetName, len) < len);
927 afs_dynSymlinkBase = tps;
928 ReleaseWriteLock(&afs_dynSymlinkLock);
930 afs_DynrootInvalidate();
935 shutdown_dynroot(void)
937 if (!afs_dynrootEnable) {
941 ObtainWriteLock(&afs_dynrootDirLock, 554);
943 if (afs_dynrootDir) {
944 afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
945 afs_dynrootDir = NULL;
946 afs_dynrootDirLen = 0;
948 if (afs_dynrootMountDir) {
949 afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
950 afs_dynrootMountDir = NULL;
951 afs_dynrootMountDirLen = 0;
954 ReleaseWriteLock(&afs_dynrootDirLock);