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 static 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 static 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 iff fid corresponds to the top of the dynroot volume.
114 _afs_IsDynrootFid(struct VenusFid *fid)
116 return (fid->Cell == afs_dynrootCell
117 && fid->Fid.Volume == AFS_DYNROOT_VOLUME
118 && fid->Fid.Vnode == AFS_DYNROOT_VNODE
119 && fid->Fid.Unique == AFS_DYNROOT_UNIQUE);
123 afs_IsDynrootFid(struct VenusFid *fid)
125 return (afs_dynrootEnable && _afs_IsDynrootFid(fid));
129 afs_IsDynrootMountFid(struct VenusFid *fid)
131 return (fid->Cell == afs_dynrootCell
132 && fid->Fid.Volume == AFS_DYNROOT_VOLUME
133 && fid->Fid.Vnode == AFS_DYNROOT_MOUNT_VNODE
134 && fid->Fid.Unique == AFS_DYNROOT_UNIQUE);
138 afs_IsDynrootAnyFid(struct VenusFid *fid)
140 return (fid->Cell == afs_dynrootCell
141 && fid->Fid.Volume == AFS_DYNROOT_VOLUME);
145 * Obtain the magic dynroot volume Fid.
148 afs_GetDynrootFid(struct VenusFid *fid)
150 fid->Cell = afs_dynrootCell;
151 fid->Fid.Volume = AFS_DYNROOT_VOLUME;
152 fid->Fid.Vnode = AFS_DYNROOT_VNODE;
153 fid->Fid.Unique = AFS_DYNROOT_UNIQUE;
157 afs_GetDynrootMountFid(struct VenusFid *fid)
159 fid->Cell = afs_dynrootCell;
160 fid->Fid.Volume = AFS_DYNROOT_VOLUME;
161 fid->Fid.Vnode = AFS_DYNROOT_MOUNT_VNODE;
162 fid->Fid.Unique = AFS_DYNROOT_UNIQUE;
166 * Returns non-zero iff avc is a pointer to the dynroot /afs vnode.
169 afs_IsDynroot(struct vcache *avc)
171 return afs_IsDynrootFid(&avc->f.fid);
175 afs_IsDynrootMount(struct vcache *avc)
177 return afs_IsDynrootMountFid(&avc->f.fid);
181 afs_IsDynrootAny(struct vcache *avc)
183 return afs_IsDynrootAnyFid(&avc->f.fid);
187 * Given the current page and chunk pointers in a directory, adjust them
188 * appropriately so that the given file name can be appended. Used for
189 * computing the size of a directory.
192 afs_dynroot_computeDirEnt(char *name, int *curPageP, int *curChunkP)
196 esize = afs_dir_NameBlobs(name);
197 if (*curChunkP + esize > EPP) {
205 * Add directory entry by given name to a directory. Assumes the
206 * caller has allocated the directory to be large enough to hold
207 * the necessary entry.
210 afs_dynroot_addDirEnt(struct DirHeader *dirHeader, int *curPageP,
211 int *curChunkP, char *name, int vnode)
213 char *dirBase = (char *)dirHeader;
214 struct PageHeader *pageHeader;
215 struct DirEntry *dirEntry;
216 int sizeOfEntry, i, t1, t2;
217 int curPage = *curPageP;
218 int curChunk = *curChunkP;
222 * Check if we need to flip pages.. If so, init the new page.
224 sizeOfEntry = afs_dir_NameBlobs(name);
225 if (curChunk + sizeOfEntry > EPP) {
231 pageHeader = (struct PageHeader *)(dirBase + curPage * AFS_PAGESIZE);
233 pageHeader->pgcount = 0;
234 pageHeader->tag = htons(1234);
235 pageHeader->freecount = 0;
236 pageHeader->freebitmap[0] = 0x01;
237 for (i = 1; i < EPP / 8; i++)
238 pageHeader->freebitmap[i] = 0;
240 dirHeader->alloMap[curPage] = EPP - 1;
243 dirEntry = (struct DirEntry *)(pageHeader + curChunk);
245 dirEntry->length = 0;
247 dirEntry->fid.vnode = htonl(vnode);
248 dirEntry->fid.vunique = htonl(1);
249 strcpy(dirEntry->name, name);
251 for (i = curChunk; i < curChunk + sizeOfEntry; i++) {
254 pageHeader->freebitmap[t1] |= (1 << t2);
258 * Add the new entry to the correct hash chain.
260 i = afs_dir_DirHash(name);
261 dirEntry->next = dirHeader->hashTable[i];
262 dirHeader->hashTable[i] = htons(curPage * EPP + curChunk);
264 curChunk += sizeOfEntry;
265 dirHeader->alloMap[curPage] -= sizeOfEntry;
268 *curChunkP = curChunk;
272 * Invalidate the /afs vnode for dynroot; called when the underlying
273 * directory has changed and needs to be re-read.
276 afs_DynrootInvalidate(void)
280 struct VenusFid tfid;
282 if (!afs_dynrootEnable)
285 ObtainWriteLock(&afs_dynrootDirLock, 687);
286 afs_dynrootVersion++;
287 afs_dynrootVersionHigh = osi_Time();
288 ReleaseWriteLock(&afs_dynrootDirLock);
290 afs_GetDynrootFid(&tfid);
293 ObtainReadLock(&afs_xvcache);
294 tvc = afs_FindVCache(&tfid, &retry, 0);
295 ReleaseReadLock(&afs_xvcache);
298 tvc->f.states &= ~(CStatd | CUnique);
299 osi_dnlc_purgedp(tvc);
305 * Regenerates the dynroot contents from the current list of
306 * cells. Useful when the list of cells has changed due to
307 * an AFSDB lookup, for instance.
310 afs_RebuildDynroot(void)
312 int cellidx, maxcellidx, i;
313 int aliasidx, maxaliasidx;
315 struct cell_alias *ca;
316 int curChunk, curPage;
318 char *newDir, *dotCell;
319 struct DirHeader *dirHeader;
321 struct afs_dynSymlink *ts;
324 ObtainReadLock(&afs_dynrootDirLock);
325 newVersion = afs_dynrootVersion;
326 ReleaseReadLock(&afs_dynrootDirLock);
329 * Compute the amount of space we need for the fake dir
334 /* Reserve space for "." and ".." */
337 /* Reserve space for the dynamic-mount directory */
338 afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME, &curPage, &curChunk);
340 for (cellidx = 0;; cellidx++) {
341 c = afs_GetCellByIndex(cellidx, READ_LOCK);
344 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
345 afs_PutCell(c, READ_LOCK);
348 dotLen = strlen(c->cellName) + 2;
349 dotCell = afs_osi_Alloc(dotLen);
350 osi_Assert(dotCell != NULL);
351 strcpy(dotCell, ".");
352 afs_strcat(dotCell, c->cellName);
354 afs_dynroot_computeDirEnt(c->cellName, &curPage, &curChunk);
355 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
357 afs_osi_Free(dotCell, dotLen);
358 afs_PutCell(c, READ_LOCK);
360 maxcellidx = cellidx;
362 for (aliasidx = 0;; aliasidx++) {
363 ca = afs_GetCellAlias(aliasidx);
367 dotLen = strlen(ca->alias) + 2;
368 dotCell = afs_osi_Alloc(dotLen);
369 osi_Assert(dotCell != NULL);
370 strcpy(dotCell, ".");
371 afs_strcat(dotCell, ca->alias);
373 afs_dynroot_computeDirEnt(ca->alias, &curPage, &curChunk);
374 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
376 afs_osi_Free(dotCell, dotLen);
377 afs_PutCellAlias(ca);
379 maxaliasidx = aliasidx;
381 ObtainReadLock(&afs_dynSymlinkLock);
382 ts = afs_dynSymlinkBase;
384 afs_dynroot_computeDirEnt(ts->name, &curPage, &curChunk);
388 dirSize = (curPage + 1) * AFS_PAGESIZE;
389 newDir = afs_osi_Alloc(dirSize);
390 osi_Assert(newDir != NULL);
393 * Now actually construct the directory.
397 dirHeader = (struct DirHeader *)newDir;
399 dirHeader->header.pgcount = 0;
400 dirHeader->header.tag = htons(1234);
401 dirHeader->header.freecount = 0;
403 dirHeader->header.freebitmap[0] = 0xff;
404 dirHeader->header.freebitmap[1] = 0x1f;
405 for (i = 2; i < EPP / 8; i++)
406 dirHeader->header.freebitmap[i] = 0;
407 dirHeader->alloMap[0] = EPP - DHE - 1;
408 for (i = 1; i < MAXPAGES; i++)
409 dirHeader->alloMap[i] = EPP;
410 memset(dirHeader->hashTable, 0, NHASHENT * sizeof(dirHeader->hashTable[0]));
412 /* Install ".", "..", and the dynamic mount directory */
413 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
414 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
415 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
416 AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE);
419 for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
420 c = afs_GetCellByIndex(cellidx, READ_LOCK);
423 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
424 afs_PutCell(c, READ_LOCK);
428 dotLen = strlen(c->cellName) + 2;
429 dotCell = afs_osi_Alloc(dotLen);
430 osi_Assert(dotCell != NULL);
431 strcpy(dotCell, ".");
432 afs_strcat(dotCell, c->cellName);
433 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName,
434 VNUM_FROM_CIDX_RW(cellidx, 0));
435 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
436 VNUM_FROM_CIDX_RW(cellidx, 1));
437 afs_osi_Free(dotCell, dotLen);
440 afs_PutCell(c, READ_LOCK);
443 for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) {
444 ca = afs_GetCellAlias(aliasidx);
448 dotLen = strlen(ca->alias) + 2;
449 dotCell = afs_osi_Alloc(dotLen);
450 osi_Assert(dotCell != NULL);
451 strcpy(dotCell, ".");
452 afs_strcat(dotCell, ca->alias);
453 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias,
454 VNUM_FROM_CAIDX_RW(aliasidx, 0));
455 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
456 VNUM_FROM_CAIDX_RW(aliasidx, 1));
457 afs_osi_Free(dotCell, dotLen);
458 afs_PutCellAlias(ca);
461 ts = afs_dynSymlinkBase;
463 int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index);
464 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum);
468 ReleaseReadLock(&afs_dynSymlinkLock);
470 ObtainWriteLock(&afs_dynrootDirLock, 549);
472 afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
473 afs_dynrootDir = newDir;
474 afs_dynrootDirLen = dirSize;
475 afs_dynrootDirLinkcnt = linkCount;
476 afs_dynrootDirVersion = newVersion;
477 ReleaseWriteLock(&afs_dynrootDirLock);
481 afs_RebuildDynrootMount(void)
484 int curChunk, curPage;
486 struct DirHeader *dirHeader;
488 newDir = afs_osi_Alloc(AFS_PAGESIZE);
489 osi_Assert(newDir != NULL);
492 * Now actually construct the directory.
496 dirHeader = (struct DirHeader *)newDir;
498 dirHeader->header.pgcount = 0;
499 dirHeader->header.tag = htons(1234);
500 dirHeader->header.freecount = 0;
502 dirHeader->header.freebitmap[0] = 0xff;
503 dirHeader->header.freebitmap[1] = 0x1f;
504 for (i = 2; i < EPP / 8; i++)
505 dirHeader->header.freebitmap[i] = 0;
506 dirHeader->alloMap[0] = EPP - DHE - 1;
507 for (i = 1; i < MAXPAGES; i++)
508 dirHeader->alloMap[i] = EPP;
509 memset(dirHeader->hashTable, 0, NHASHENT * sizeof(dirHeader->hashTable[0]));
511 /* Install "." and ".." */
512 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
513 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
515 ObtainWriteLock(&afs_dynrootDirLock, 549);
516 if (afs_dynrootMountDir)
517 afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
518 afs_dynrootMountDir = newDir;
519 afs_dynrootMountDirLen = AFS_PAGESIZE;
520 ReleaseWriteLock(&afs_dynrootDirLock);
524 * Returns a pointer to the base of the dynroot directory in memory,
525 * length thereof, and a FetchStatus.
528 afs_GetDynroot(char **dynrootDir, int *dynrootLen,
529 struct AFSFetchStatus *status)
531 ObtainReadLock(&afs_dynrootDirLock);
532 if (!afs_dynrootDir || afs_dynrootDirVersion != afs_dynrootVersion) {
533 ReleaseReadLock(&afs_dynrootDirLock);
534 afs_RebuildDynroot();
535 ObtainReadLock(&afs_dynrootDirLock);
539 *dynrootDir = afs_dynrootDir;
541 *dynrootLen = afs_dynrootDirLen;
544 memset(status, 0, sizeof(struct AFSFetchStatus));
545 status->FileType = Directory;
546 status->LinkCount = afs_dynrootDirLinkcnt;
547 status->Length = afs_dynrootDirLen;
548 status->DataVersion = afs_dynrootVersion;
549 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
550 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
551 status->UnixModeBits = 0755;
552 status->ParentVnode = 1;
553 status->ParentUnique = 1;
554 status->dataVersionHigh = afs_dynrootVersionHigh;
559 afs_GetDynrootMount(char **dynrootDir, int *dynrootLen,
560 struct AFSFetchStatus *status)
562 ObtainReadLock(&afs_dynrootDirLock);
563 if (!afs_dynrootMountDir) {
564 ReleaseReadLock(&afs_dynrootDirLock);
565 afs_RebuildDynrootMount();
566 ObtainReadLock(&afs_dynrootDirLock);
570 *dynrootDir = afs_dynrootMountDir;
572 *dynrootLen = afs_dynrootMountDirLen;
575 memset(status, 0, sizeof(struct AFSFetchStatus));
576 status->FileType = Directory;
577 status->LinkCount = 1;
578 status->Length = afs_dynrootMountDirLen;
579 status->DataVersion = 1;
580 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
581 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
582 status->UnixModeBits = 0755;
583 status->ParentVnode = 1;
584 status->ParentUnique = 1;
585 status->dataVersionHigh = 0;
590 * Puts back the dynroot read lock.
595 ReleaseReadLock(&afs_dynrootDirLock);
599 * Inform dynroot that a new vnode is being created. Return value
600 * is non-zero if this vnode is handled by dynroot, in which case
601 * FetchStatus will be filled in.
604 afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
606 char *bp, tbuf[CVBS];
608 if (_afs_IsDynrootFid(&avc->f.fid)) {
609 if (!afs_dynrootEnable)
611 afs_GetDynroot(0, 0, status);
616 if (afs_IsDynrootMount(avc)) {
617 afs_GetDynrootMount(0, 0, status);
623 * Check if this is an entry under /afs, e.g. /afs/cellname.
625 if (avc->f.fid.Cell == afs_dynrootCell
626 && avc->f.fid.Fid.Volume == AFS_DYNROOT_VOLUME) {
629 struct cell_alias *ca;
630 int namelen, linklen, cellidx, rw;
632 memset(status, 0, sizeof(struct AFSFetchStatus));
634 status->FileType = SymbolicLink;
635 status->LinkCount = 1;
636 status->DataVersion = 1;
637 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
638 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
639 status->ParentVnode = 1;
640 status->ParentUnique = 1;
642 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_SYMLINK) {
643 struct afs_dynSymlink *ts;
644 int index = VNUM_TO_VNID(avc->f.fid.Fid.Vnode);
646 ObtainReadLock(&afs_dynSymlinkLock);
647 ts = afs_dynSymlinkBase;
649 if (ts->index == index)
655 linklen = strlen(ts->target);
656 avc->linkData = afs_osi_Alloc(linklen + 1);
657 osi_Assert(avc->linkData != NULL);
658 strcpy(avc->linkData, ts->target);
660 status->Length = linklen;
661 status->UnixModeBits = 0755;
663 ReleaseReadLock(&afs_dynSymlinkLock);
671 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_CELL
672 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_ALIAS
673 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_MOUNT) {
674 afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
675 VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode));
679 cellidx = VNUM_TO_CIDX(avc->f.fid.Fid.Vnode);
680 rw = VNUM_TO_RW(avc->f.fid.Fid.Vnode);
682 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_ALIAS) {
685 ca = afs_GetCellAlias(cellidx);
687 afs_warn("dynroot vnode inconsistency, can't find alias %d\n",
693 * linkData needs to contain the name of the cell
694 * we're aliasing for.
698 afs_warn("dynroot: alias %s missing real cell name\n",
700 avc->linkData = afs_strdup("unknown");
703 int namelen = strlen(realName);
704 linklen = rw + namelen;
705 avc->linkData = afs_osi_Alloc(linklen + 1);
706 osi_Assert(avc->linkData != NULL);
707 strcpy(avc->linkData, rw ? "." : "");
708 afs_strcat(avc->linkData, realName);
711 status->UnixModeBits = 0755;
712 afs_PutCellAlias(ca);
714 } else if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
715 c = afs_GetCellByIndex(cellidx, READ_LOCK);
717 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
723 * linkData needs to contain "%cell:volumeid"
725 namelen = strlen(c->cellName);
726 bp = afs_cv2string(&tbuf[CVBS], avc->f.fid.Fid.Unique);
727 linklen = 2 + namelen + strlen(bp);
728 avc->linkData = afs_osi_Alloc(linklen + 1);
729 osi_Assert(avc->linkData != NULL);
730 strcpy(avc->linkData, "%");
731 afs_strcat(avc->linkData, c->cellName);
732 afs_strcat(avc->linkData, ":");
733 afs_strcat(avc->linkData, bp);
735 status->UnixModeBits = 0644;
736 status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE;
737 afs_PutCell(c, READ_LOCK);
740 c = afs_GetCellByIndex(cellidx, READ_LOCK);
742 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
748 * linkData needs to contain "#cell:root.cell" or "%cell:root.cell"
750 namelen = strlen(c->cellName);
751 linklen = 1 + namelen + 10;
752 avc->linkData = afs_osi_Alloc(linklen + 1);
753 osi_Assert(avc->linkData != NULL);
754 strcpy(avc->linkData, rw ? "%" : "#");
755 afs_strcat(avc->linkData, c->cellName);
756 afs_strcat(avc->linkData, ":root.cell");
758 status->UnixModeBits = 0644;
759 afs_PutCell(c, READ_LOCK);
762 status->Length = linklen;
768 /* make sure we set type correctly when we do this. used to stay VREG */
770 switch (status->FileType) {
778 if (afs_fakestat_enable && (avc->f.m.Mode & 0111) == 0)
784 /* shouldn't happen */
791 * Make sure dynroot initialization has been done.
794 afs_InitDynroot(void)
798 AFS_RWLOCK_INIT(&afs_dynrootDirLock, "afs_dynrootDirLock");
799 AFS_RWLOCK_INIT(&afs_dynSymlinkLock, "afs_dynSymlinkLock");
801 return afs_dynrootCellInit();
805 * Enable or disable dynroot. Returns 0 if successful.
808 afs_SetDynrootEnable(int enable)
810 afs_dynrootEnable = enable;
811 return afs_InitDynroot();
815 * Check if dynroot support is enabled.
818 afs_GetDynrootEnable(void)
820 return afs_dynrootEnable;
824 * Remove a temporary symlink entry from /afs.
827 afs_DynrootVOPRemove(struct vcache *avc, afs_ucred_t *acred, char *aname)
829 struct afs_dynSymlink **tpps;
830 struct afs_dynSymlink *tps;
833 #if defined(AFS_SUN510_ENV)
834 if (crgetruid(acred))
836 if (afs_cr_uid(acred))
840 ObtainWriteLock(&afs_dynSymlinkLock, 97);
841 tpps = &afs_dynSymlinkBase;
844 if (afs_strcasecmp(aname, tps->name) == 0) {
845 afs_osi_Free(tps->name, strlen(tps->name) + 1);
846 afs_osi_Free(tps->target, strlen(tps->target) + 1);
848 afs_osi_Free(tps, sizeof(*tps));
849 afs_dynSymlinkIndex++;
855 ReleaseWriteLock(&afs_dynSymlinkLock);
857 afs_DynrootInvalidate();
861 if (afs_CellOrAliasExists(aname))
868 * Create a temporary symlink entry in /afs.
871 afs_DynrootVOPSymlink(struct vcache *avc, afs_ucred_t *acred,
872 char *aname, char *atargetName)
874 struct afs_dynSymlink *tps;
876 if (afs_cr_uid(acred))
878 if (afs_CellOrAliasExists(aname))
881 /* Check if it's already a symlink */
882 ObtainWriteLock(&afs_dynSymlinkLock, 91);
883 tps = afs_dynSymlinkBase;
885 if (afs_strcasecmp(aname, tps->name) == 0) {
886 ReleaseWriteLock(&afs_dynSymlinkLock);
892 /* Doesn't already exist -- go ahead and create it */
893 tps = afs_osi_Alloc(sizeof(*tps));
894 osi_Assert(tps != NULL);
895 tps->index = afs_dynSymlinkIndex++;
896 tps->next = afs_dynSymlinkBase;
897 tps->name = afs_osi_Alloc(strlen(aname) + 1);
898 osi_Assert(tps->name != NULL);
899 strcpy(tps->name, aname);
900 tps->target = afs_osi_Alloc(strlen(atargetName) + 1);
901 osi_Assert(tps->target != NULL);
902 strcpy(tps->target, atargetName);
903 afs_dynSymlinkBase = tps;
904 ReleaseWriteLock(&afs_dynSymlinkLock);
906 afs_DynrootInvalidate();