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 strcpy(dotCell, ".");
351 afs_strcat(dotCell, c->cellName);
353 afs_dynroot_computeDirEnt(c->cellName, &curPage, &curChunk);
354 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
356 afs_osi_Free(dotCell, dotLen);
357 afs_PutCell(c, READ_LOCK);
359 maxcellidx = cellidx;
361 for (aliasidx = 0;; aliasidx++) {
362 ca = afs_GetCellAlias(aliasidx);
366 dotLen = strlen(ca->alias) + 2;
367 dotCell = afs_osi_Alloc(dotLen);
368 strcpy(dotCell, ".");
369 afs_strcat(dotCell, ca->alias);
371 afs_dynroot_computeDirEnt(ca->alias, &curPage, &curChunk);
372 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
374 afs_osi_Free(dotCell, dotLen);
375 afs_PutCellAlias(ca);
377 maxaliasidx = aliasidx;
379 ObtainReadLock(&afs_dynSymlinkLock);
380 ts = afs_dynSymlinkBase;
382 afs_dynroot_computeDirEnt(ts->name, &curPage, &curChunk);
386 dirSize = (curPage + 1) * AFS_PAGESIZE;
387 newDir = afs_osi_Alloc(dirSize);
390 * Now actually construct the directory.
394 dirHeader = (struct DirHeader *)newDir;
396 dirHeader->header.pgcount = 0;
397 dirHeader->header.tag = htons(1234);
398 dirHeader->header.freecount = 0;
400 dirHeader->header.freebitmap[0] = 0xff;
401 dirHeader->header.freebitmap[1] = 0x1f;
402 for (i = 2; i < EPP / 8; i++)
403 dirHeader->header.freebitmap[i] = 0;
404 dirHeader->alloMap[0] = EPP - DHE - 1;
405 for (i = 1; i < MAXPAGES; i++)
406 dirHeader->alloMap[i] = EPP;
407 for (i = 0; i < NHASHENT; i++)
408 dirHeader->hashTable[i] = 0;
410 /* Install ".", "..", and the dynamic mount directory */
411 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
412 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
413 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
414 AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE);
417 for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
418 c = afs_GetCellByIndex(cellidx, READ_LOCK);
421 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
422 afs_PutCell(c, READ_LOCK);
426 dotLen = strlen(c->cellName) + 2;
427 dotCell = afs_osi_Alloc(dotLen);
428 strcpy(dotCell, ".");
429 afs_strcat(dotCell, c->cellName);
430 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName,
431 VNUM_FROM_CIDX_RW(cellidx, 0));
432 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
433 VNUM_FROM_CIDX_RW(cellidx, 1));
434 afs_osi_Free(dotCell, dotLen);
437 afs_PutCell(c, READ_LOCK);
440 for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) {
441 ca = afs_GetCellAlias(aliasidx);
445 dotLen = strlen(ca->alias) + 2;
446 dotCell = afs_osi_Alloc(dotLen);
447 strcpy(dotCell, ".");
448 afs_strcat(dotCell, ca->alias);
449 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias,
450 VNUM_FROM_CAIDX_RW(aliasidx, 0));
451 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
452 VNUM_FROM_CAIDX_RW(aliasidx, 1));
453 afs_osi_Free(dotCell, dotLen);
454 afs_PutCellAlias(ca);
457 ts = afs_dynSymlinkBase;
459 int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index);
460 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum);
464 ReleaseReadLock(&afs_dynSymlinkLock);
466 ObtainWriteLock(&afs_dynrootDirLock, 549);
468 afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
469 afs_dynrootDir = newDir;
470 afs_dynrootDirLen = dirSize;
471 afs_dynrootDirLinkcnt = linkCount;
472 afs_dynrootDirVersion = newVersion;
473 ReleaseWriteLock(&afs_dynrootDirLock);
477 afs_RebuildDynrootMount(void)
480 int curChunk, curPage;
482 struct DirHeader *dirHeader;
484 newDir = afs_osi_Alloc(AFS_PAGESIZE);
487 * Now actually construct the directory.
491 dirHeader = (struct DirHeader *)newDir;
493 dirHeader->header.pgcount = 0;
494 dirHeader->header.tag = htons(1234);
495 dirHeader->header.freecount = 0;
497 dirHeader->header.freebitmap[0] = 0xff;
498 dirHeader->header.freebitmap[1] = 0x1f;
499 for (i = 2; i < EPP / 8; i++)
500 dirHeader->header.freebitmap[i] = 0;
501 dirHeader->alloMap[0] = EPP - DHE - 1;
502 for (i = 1; i < MAXPAGES; i++)
503 dirHeader->alloMap[i] = EPP;
504 for (i = 0; i < NHASHENT; i++)
505 dirHeader->hashTable[i] = 0;
507 /* Install "." and ".." */
508 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
509 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
511 ObtainWriteLock(&afs_dynrootDirLock, 549);
512 if (afs_dynrootMountDir)
513 afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
514 afs_dynrootMountDir = newDir;
515 afs_dynrootMountDirLen = AFS_PAGESIZE;
516 ReleaseWriteLock(&afs_dynrootDirLock);
520 * Returns a pointer to the base of the dynroot directory in memory,
521 * length thereof, and a FetchStatus.
524 afs_GetDynroot(char **dynrootDir, int *dynrootLen,
525 struct AFSFetchStatus *status)
527 ObtainReadLock(&afs_dynrootDirLock);
528 if (!afs_dynrootDir || afs_dynrootDirVersion != afs_dynrootVersion) {
529 ReleaseReadLock(&afs_dynrootDirLock);
530 afs_RebuildDynroot();
531 ObtainReadLock(&afs_dynrootDirLock);
535 *dynrootDir = afs_dynrootDir;
537 *dynrootLen = afs_dynrootDirLen;
540 memset(status, 0, sizeof(struct AFSFetchStatus));
541 status->FileType = Directory;
542 status->LinkCount = afs_dynrootDirLinkcnt;
543 status->Length = afs_dynrootDirLen;
544 status->DataVersion = afs_dynrootVersion;
545 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
546 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
547 status->UnixModeBits = 0755;
548 status->ParentVnode = 1;
549 status->ParentUnique = 1;
550 status->dataVersionHigh = afs_dynrootVersionHigh;
555 afs_GetDynrootMount(char **dynrootDir, int *dynrootLen,
556 struct AFSFetchStatus *status)
558 ObtainReadLock(&afs_dynrootDirLock);
559 if (!afs_dynrootMountDir) {
560 ReleaseReadLock(&afs_dynrootDirLock);
561 afs_RebuildDynrootMount();
562 ObtainReadLock(&afs_dynrootDirLock);
566 *dynrootDir = afs_dynrootMountDir;
568 *dynrootLen = afs_dynrootMountDirLen;
571 memset(status, 0, sizeof(struct AFSFetchStatus));
572 status->FileType = Directory;
573 status->LinkCount = 1;
574 status->Length = afs_dynrootMountDirLen;
575 status->DataVersion = 1;
576 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
577 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
578 status->UnixModeBits = 0755;
579 status->ParentVnode = 1;
580 status->ParentUnique = 1;
581 status->dataVersionHigh = 0;
586 * Puts back the dynroot read lock.
591 ReleaseReadLock(&afs_dynrootDirLock);
595 * Inform dynroot that a new vnode is being created. Return value
596 * is non-zero if this vnode is handled by dynroot, in which case
597 * FetchStatus will be filled in.
600 afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
602 char *bp, tbuf[CVBS];
604 if (_afs_IsDynrootFid(&avc->f.fid)) {
605 if (!afs_dynrootEnable)
607 afs_GetDynroot(0, 0, status);
612 if (afs_IsDynrootMount(avc)) {
613 afs_GetDynrootMount(0, 0, status);
619 * Check if this is an entry under /afs, e.g. /afs/cellname.
621 if (avc->f.fid.Cell == afs_dynrootCell
622 && avc->f.fid.Fid.Volume == AFS_DYNROOT_VOLUME) {
625 struct cell_alias *ca;
626 int namelen, linklen, cellidx, rw;
628 memset(status, 0, sizeof(struct AFSFetchStatus));
630 status->FileType = SymbolicLink;
631 status->LinkCount = 1;
632 status->DataVersion = 1;
633 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
634 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
635 status->ParentVnode = 1;
636 status->ParentUnique = 1;
638 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_SYMLINK) {
639 struct afs_dynSymlink *ts;
640 int index = VNUM_TO_VNID(avc->f.fid.Fid.Vnode);
642 ObtainReadLock(&afs_dynSymlinkLock);
643 ts = afs_dynSymlinkBase;
645 if (ts->index == index)
651 linklen = strlen(ts->target);
652 avc->linkData = afs_osi_Alloc(linklen + 1);
653 strcpy(avc->linkData, ts->target);
655 status->Length = linklen;
656 status->UnixModeBits = 0755;
658 ReleaseReadLock(&afs_dynSymlinkLock);
663 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_CELL
664 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_ALIAS
665 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_MOUNT) {
666 afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
667 VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode));
671 cellidx = VNUM_TO_CIDX(avc->f.fid.Fid.Vnode);
672 rw = VNUM_TO_RW(avc->f.fid.Fid.Vnode);
674 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_ALIAS) {
677 ca = afs_GetCellAlias(cellidx);
679 afs_warn("dynroot vnode inconsistency, can't find alias %d\n",
685 * linkData needs to contain the name of the cell
686 * we're aliasing for.
690 afs_warn("dynroot: alias %s missing real cell name\n",
692 avc->linkData = afs_strdup("unknown");
695 int namelen = strlen(realName);
696 linklen = rw + namelen;
697 avc->linkData = afs_osi_Alloc(linklen + 1);
698 strcpy(avc->linkData, rw ? "." : "");
699 afs_strcat(avc->linkData, realName);
702 status->UnixModeBits = 0755;
703 afs_PutCellAlias(ca);
705 } else if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
706 c = afs_GetCellByIndex(cellidx, READ_LOCK);
708 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
714 * linkData needs to contain "%cell:volumeid"
716 namelen = strlen(c->cellName);
717 bp = afs_cv2string(&tbuf[CVBS], avc->f.fid.Fid.Unique);
718 linklen = 2 + namelen + strlen(bp);
719 avc->linkData = afs_osi_Alloc(linklen + 1);
720 strcpy(avc->linkData, "%");
721 afs_strcat(avc->linkData, c->cellName);
722 afs_strcat(avc->linkData, ":");
723 afs_strcat(avc->linkData, bp);
725 status->UnixModeBits = 0644;
726 status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE;
727 afs_PutCell(c, READ_LOCK);
730 c = afs_GetCellByIndex(cellidx, READ_LOCK);
732 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
738 * linkData needs to contain "#cell:root.cell" or "%cell:root.cell"
740 namelen = strlen(c->cellName);
741 linklen = 1 + namelen + 10;
742 avc->linkData = afs_osi_Alloc(linklen + 1);
743 strcpy(avc->linkData, rw ? "%" : "#");
744 afs_strcat(avc->linkData, c->cellName);
745 afs_strcat(avc->linkData, ":root.cell");
747 status->UnixModeBits = 0644;
748 afs_PutCell(c, READ_LOCK);
751 status->Length = linklen;
759 * Make sure dynroot initialization has been done.
762 afs_InitDynroot(void)
766 AFS_RWLOCK_INIT(&afs_dynrootDirLock, "afs_dynrootDirLock");
767 AFS_RWLOCK_INIT(&afs_dynSymlinkLock, "afs_dynSymlinkLock");
769 return afs_dynrootCellInit();
773 * Enable or disable dynroot. Returns 0 if successful.
776 afs_SetDynrootEnable(int enable)
778 afs_dynrootEnable = enable;
779 return afs_InitDynroot();
783 * Check if dynroot support is enabled.
786 afs_GetDynrootEnable(void)
788 return afs_dynrootEnable;
792 * Remove a temporary symlink entry from /afs.
795 afs_DynrootVOPRemove(struct vcache *avc, afs_ucred_t *acred, char *aname)
797 struct afs_dynSymlink **tpps;
798 struct afs_dynSymlink *tps;
801 #if defined(AFS_SUN510_ENV)
802 if (crgetruid(acred))
804 if (afs_cr_uid(acred))
808 ObtainWriteLock(&afs_dynSymlinkLock, 97);
809 tpps = &afs_dynSymlinkBase;
812 if (afs_strcasecmp(aname, tps->name) == 0) {
813 afs_osi_Free(tps->name, strlen(tps->name) + 1);
814 afs_osi_Free(tps->target, strlen(tps->target) + 1);
816 afs_osi_Free(tps, sizeof(*tps));
817 afs_dynSymlinkIndex++;
823 ReleaseWriteLock(&afs_dynSymlinkLock);
825 afs_DynrootInvalidate();
829 if (afs_CellOrAliasExists(aname))
836 * Create a temporary symlink entry in /afs.
839 afs_DynrootVOPSymlink(struct vcache *avc, afs_ucred_t *acred,
840 char *aname, char *atargetName)
842 struct afs_dynSymlink *tps;
844 if (afs_cr_uid(acred))
846 if (afs_CellOrAliasExists(aname))
849 /* Check if it's already a symlink */
850 ObtainWriteLock(&afs_dynSymlinkLock, 91);
851 tps = afs_dynSymlinkBase;
853 if (afs_strcasecmp(aname, tps->name) == 0) {
854 ReleaseWriteLock(&afs_dynSymlinkLock);
860 /* Doesn't already exist -- go ahead and create it */
861 tps = afs_osi_Alloc(sizeof(*tps));
862 tps->index = afs_dynSymlinkIndex++;
863 tps->next = afs_dynSymlinkBase;
864 tps->name = afs_osi_Alloc(strlen(aname) + 1);
865 strcpy(tps->name, aname);
866 tps->target = afs_osi_Alloc(strlen(atargetName) + 1);
867 strcpy(tps->target, atargetName);
868 afs_dynSymlinkBase = tps;
869 ReleaseWriteLock(&afs_dynSymlinkLock);
871 afs_DynrootInvalidate();