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.
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 for (i = 0; i < NHASHENT; i++)
411 dirHeader->hashTable[i] = 0;
413 /* Install ".", "..", and the dynamic mount directory */
414 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
415 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
416 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
417 AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE);
420 for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
421 c = afs_GetCellByIndex(cellidx, READ_LOCK);
424 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
425 afs_PutCell(c, READ_LOCK);
429 dotLen = strlen(c->cellName) + 2;
430 dotCell = afs_osi_Alloc(dotLen);
431 osi_Assert(dotCell != NULL);
432 strcpy(dotCell, ".");
433 afs_strcat(dotCell, c->cellName);
434 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName,
435 VNUM_FROM_CIDX_RW(cellidx, 0));
436 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
437 VNUM_FROM_CIDX_RW(cellidx, 1));
438 afs_osi_Free(dotCell, dotLen);
441 afs_PutCell(c, READ_LOCK);
444 for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) {
445 ca = afs_GetCellAlias(aliasidx);
449 dotLen = strlen(ca->alias) + 2;
450 dotCell = afs_osi_Alloc(dotLen);
451 osi_Assert(dotCell != NULL);
452 strcpy(dotCell, ".");
453 afs_strcat(dotCell, ca->alias);
454 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias,
455 VNUM_FROM_CAIDX_RW(aliasidx, 0));
456 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
457 VNUM_FROM_CAIDX_RW(aliasidx, 1));
458 afs_osi_Free(dotCell, dotLen);
459 afs_PutCellAlias(ca);
462 ts = afs_dynSymlinkBase;
464 int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index);
465 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum);
469 ReleaseReadLock(&afs_dynSymlinkLock);
471 ObtainWriteLock(&afs_dynrootDirLock, 549);
473 afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
474 afs_dynrootDir = newDir;
475 afs_dynrootDirLen = dirSize;
476 afs_dynrootDirLinkcnt = linkCount;
477 afs_dynrootDirVersion = newVersion;
478 ReleaseWriteLock(&afs_dynrootDirLock);
482 afs_RebuildDynrootMount(void)
485 int curChunk, curPage;
487 struct DirHeader *dirHeader;
489 newDir = afs_osi_Alloc(AFS_PAGESIZE);
490 osi_Assert(newDir != NULL);
493 * Now actually construct the directory.
497 dirHeader = (struct DirHeader *)newDir;
499 dirHeader->header.pgcount = 0;
500 dirHeader->header.tag = htons(1234);
501 dirHeader->header.freecount = 0;
503 dirHeader->header.freebitmap[0] = 0xff;
504 dirHeader->header.freebitmap[1] = 0x1f;
505 for (i = 2; i < EPP / 8; i++)
506 dirHeader->header.freebitmap[i] = 0;
507 dirHeader->alloMap[0] = EPP - DHE - 1;
508 for (i = 1; i < MAXPAGES; i++)
509 dirHeader->alloMap[i] = EPP;
510 for (i = 0; i < NHASHENT; i++)
511 dirHeader->hashTable[i] = 0;
513 /* Install "." and ".." */
514 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
515 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
517 ObtainWriteLock(&afs_dynrootDirLock, 549);
518 if (afs_dynrootMountDir)
519 afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
520 afs_dynrootMountDir = newDir;
521 afs_dynrootMountDirLen = AFS_PAGESIZE;
522 ReleaseWriteLock(&afs_dynrootDirLock);
526 * Returns a pointer to the base of the dynroot directory in memory,
527 * length thereof, and a FetchStatus.
530 afs_GetDynroot(char **dynrootDir, int *dynrootLen,
531 struct AFSFetchStatus *status)
533 ObtainReadLock(&afs_dynrootDirLock);
534 if (!afs_dynrootDir || afs_dynrootDirVersion != afs_dynrootVersion) {
535 ReleaseReadLock(&afs_dynrootDirLock);
536 afs_RebuildDynroot();
537 ObtainReadLock(&afs_dynrootDirLock);
541 *dynrootDir = afs_dynrootDir;
543 *dynrootLen = afs_dynrootDirLen;
546 memset(status, 0, sizeof(struct AFSFetchStatus));
547 status->FileType = Directory;
548 status->LinkCount = afs_dynrootDirLinkcnt;
549 status->Length = afs_dynrootDirLen;
550 status->DataVersion = afs_dynrootVersion;
551 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
552 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
553 status->UnixModeBits = 0755;
554 status->ParentVnode = 1;
555 status->ParentUnique = 1;
556 status->dataVersionHigh = afs_dynrootVersionHigh;
561 afs_GetDynrootMount(char **dynrootDir, int *dynrootLen,
562 struct AFSFetchStatus *status)
564 ObtainReadLock(&afs_dynrootDirLock);
565 if (!afs_dynrootMountDir) {
566 ReleaseReadLock(&afs_dynrootDirLock);
567 afs_RebuildDynrootMount();
568 ObtainReadLock(&afs_dynrootDirLock);
572 *dynrootDir = afs_dynrootMountDir;
574 *dynrootLen = afs_dynrootMountDirLen;
577 memset(status, 0, sizeof(struct AFSFetchStatus));
578 status->FileType = Directory;
579 status->LinkCount = 1;
580 status->Length = afs_dynrootMountDirLen;
581 status->DataVersion = 1;
582 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
583 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
584 status->UnixModeBits = 0755;
585 status->ParentVnode = 1;
586 status->ParentUnique = 1;
587 status->dataVersionHigh = 0;
592 * Puts back the dynroot read lock.
597 ReleaseReadLock(&afs_dynrootDirLock);
601 * Inform dynroot that a new vnode is being created. Return value
602 * is non-zero if this vnode is handled by dynroot, in which case
603 * FetchStatus will be filled in.
606 afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
608 char *bp, tbuf[CVBS];
610 if (_afs_IsDynrootFid(&avc->f.fid)) {
611 if (!afs_dynrootEnable)
613 afs_GetDynroot(0, 0, status);
618 if (afs_IsDynrootMount(avc)) {
619 afs_GetDynrootMount(0, 0, status);
625 * Check if this is an entry under /afs, e.g. /afs/cellname.
627 if (avc->f.fid.Cell == afs_dynrootCell
628 && avc->f.fid.Fid.Volume == AFS_DYNROOT_VOLUME) {
631 struct cell_alias *ca;
632 int namelen, linklen, cellidx, rw;
634 memset(status, 0, sizeof(struct AFSFetchStatus));
636 status->FileType = SymbolicLink;
637 status->LinkCount = 1;
638 status->DataVersion = 1;
639 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
640 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
641 status->ParentVnode = 1;
642 status->ParentUnique = 1;
644 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_SYMLINK) {
645 struct afs_dynSymlink *ts;
646 int index = VNUM_TO_VNID(avc->f.fid.Fid.Vnode);
648 ObtainReadLock(&afs_dynSymlinkLock);
649 ts = afs_dynSymlinkBase;
651 if (ts->index == index)
657 linklen = strlen(ts->target);
658 avc->linkData = afs_osi_Alloc(linklen + 1);
659 osi_Assert(avc->linkData != NULL);
660 strcpy(avc->linkData, ts->target);
662 status->Length = linklen;
663 status->UnixModeBits = 0755;
665 ReleaseReadLock(&afs_dynSymlinkLock);
673 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_CELL
674 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_ALIAS
675 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_MOUNT) {
676 afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
677 VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode));
681 cellidx = VNUM_TO_CIDX(avc->f.fid.Fid.Vnode);
682 rw = VNUM_TO_RW(avc->f.fid.Fid.Vnode);
684 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_ALIAS) {
687 ca = afs_GetCellAlias(cellidx);
689 afs_warn("dynroot vnode inconsistency, can't find alias %d\n",
695 * linkData needs to contain the name of the cell
696 * we're aliasing for.
700 afs_warn("dynroot: alias %s missing real cell name\n",
702 avc->linkData = afs_strdup("unknown");
705 int namelen = strlen(realName);
706 linklen = rw + namelen;
707 avc->linkData = afs_osi_Alloc(linklen + 1);
708 osi_Assert(avc->linkData != NULL);
709 strcpy(avc->linkData, rw ? "." : "");
710 afs_strcat(avc->linkData, realName);
713 status->UnixModeBits = 0755;
714 afs_PutCellAlias(ca);
716 } else if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
717 c = afs_GetCellByIndex(cellidx, READ_LOCK);
719 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
725 * linkData needs to contain "%cell:volumeid"
727 namelen = strlen(c->cellName);
728 bp = afs_cv2string(&tbuf[CVBS], avc->f.fid.Fid.Unique);
729 linklen = 2 + namelen + strlen(bp);
730 avc->linkData = afs_osi_Alloc(linklen + 1);
731 osi_Assert(avc->linkData != NULL);
732 strcpy(avc->linkData, "%");
733 afs_strcat(avc->linkData, c->cellName);
734 afs_strcat(avc->linkData, ":");
735 afs_strcat(avc->linkData, bp);
737 status->UnixModeBits = 0644;
738 status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE;
739 afs_PutCell(c, READ_LOCK);
742 c = afs_GetCellByIndex(cellidx, READ_LOCK);
744 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
750 * linkData needs to contain "#cell:root.cell" or "%cell:root.cell"
752 namelen = strlen(c->cellName);
753 linklen = 1 + namelen + 10;
754 avc->linkData = afs_osi_Alloc(linklen + 1);
755 osi_Assert(avc->linkData != NULL);
756 strcpy(avc->linkData, rw ? "%" : "#");
757 afs_strcat(avc->linkData, c->cellName);
758 afs_strcat(avc->linkData, ":root.cell");
760 status->UnixModeBits = 0644;
761 afs_PutCell(c, READ_LOCK);
764 status->Length = linklen;
770 /* make sure we set type correctly when we do this. used to stay VREG */
772 switch (status->FileType) {
780 if (afs_fakestat_enable && (avc->f.m.Mode & 0111) == 0)
786 /* shouldn't happen */
793 * Make sure dynroot initialization has been done.
796 afs_InitDynroot(void)
800 AFS_RWLOCK_INIT(&afs_dynrootDirLock, "afs_dynrootDirLock");
801 AFS_RWLOCK_INIT(&afs_dynSymlinkLock, "afs_dynSymlinkLock");
803 return afs_dynrootCellInit();
807 * Enable or disable dynroot. Returns 0 if successful.
810 afs_SetDynrootEnable(int enable)
812 afs_dynrootEnable = enable;
813 return afs_InitDynroot();
817 * Check if dynroot support is enabled.
820 afs_GetDynrootEnable(void)
822 return afs_dynrootEnable;
826 * Remove a temporary symlink entry from /afs.
829 afs_DynrootVOPRemove(struct vcache *avc, afs_ucred_t *acred, char *aname)
831 struct afs_dynSymlink **tpps;
832 struct afs_dynSymlink *tps;
835 #if defined(AFS_SUN510_ENV)
836 if (crgetruid(acred))
838 if (afs_cr_uid(acred))
842 ObtainWriteLock(&afs_dynSymlinkLock, 97);
843 tpps = &afs_dynSymlinkBase;
846 if (afs_strcasecmp(aname, tps->name) == 0) {
847 afs_osi_Free(tps->name, strlen(tps->name) + 1);
848 afs_osi_Free(tps->target, strlen(tps->target) + 1);
850 afs_osi_Free(tps, sizeof(*tps));
851 afs_dynSymlinkIndex++;
857 ReleaseWriteLock(&afs_dynSymlinkLock);
859 afs_DynrootInvalidate();
863 if (afs_CellOrAliasExists(aname))
870 * Create a temporary symlink entry in /afs.
873 afs_DynrootVOPSymlink(struct vcache *avc, afs_ucred_t *acred,
874 char *aname, char *atargetName)
876 struct afs_dynSymlink *tps;
878 if (afs_cr_uid(acred))
880 if (afs_CellOrAliasExists(aname))
883 /* Check if it's already a symlink */
884 ObtainWriteLock(&afs_dynSymlinkLock, 91);
885 tps = afs_dynSymlinkBase;
887 if (afs_strcasecmp(aname, tps->name) == 0) {
888 ReleaseWriteLock(&afs_dynSymlinkLock);
894 /* Doesn't already exist -- go ahead and create it */
895 tps = afs_osi_Alloc(sizeof(*tps));
896 osi_Assert(tps != NULL);
897 tps->index = afs_dynSymlinkIndex++;
898 tps->next = afs_dynSymlinkBase;
899 tps->name = afs_osi_Alloc(strlen(aname) + 1);
900 osi_Assert(tps->name != NULL);
901 strcpy(tps->name, aname);
902 tps->target = afs_osi_Alloc(strlen(atargetName) + 1);
903 osi_Assert(tps->target != NULL);
904 strcpy(tps->target, atargetName);
905 afs_dynSymlinkBase = tps;
906 ReleaseWriteLock(&afs_dynSymlinkLock);
908 afs_DynrootInvalidate();