/* * Regenerates the dynroot contents from the current list of * cells. Useful when the list of cells has changed due to * an AFSDB lookup, for instance. */ static void afs_RebuildDynroot(void) { int cellidx, maxcellidx, i; int aliasidx, maxaliasidx; struct cell *c; struct cell_alias *ca; int curChunk, curPage; int dirSize, dotLen; char *newDir, *dotCell; struct DirHeader *dirHeader; int linkCount = 0; struct afs_dynSymlink *ts; int newVersion; ObtainReadLock(&afs_dynrootDirLock); newVersion = afs_dynrootVersion; ReleaseReadLock(&afs_dynrootDirLock); /* * Compute the amount of space we need for the fake dir */ curChunk = 13; curPage = 0; /* Reserve space for "." and ".." */ curChunk += 2; /* Reserve space for the dynamic-mount directory */ afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME, &curPage, &curChunk); for (cellidx = 0;; cellidx++) { c = afs_GetCellByIndex(cellidx, READ_LOCK); if (!c) break; if (c->cellNum == afs_dynrootCell) continue; dotLen = strlen(c->cellName) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, c->cellName); afs_dynroot_computeDirEnt(c->cellName, &curPage, &curChunk); afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk); afs_osi_Free(dotCell, dotLen); afs_PutCell(c, READ_LOCK); } maxcellidx = cellidx; for (aliasidx = 0;; aliasidx++) { ca = afs_GetCellAlias(aliasidx); if (!ca) break; dotLen = strlen(ca->alias) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, ca->alias); afs_dynroot_computeDirEnt(ca->alias, &curPage, &curChunk); afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk); afs_osi_Free(dotCell, dotLen); afs_PutCellAlias(ca); } maxaliasidx = aliasidx; ObtainReadLock(&afs_dynSymlinkLock); ts = afs_dynSymlinkBase; while (ts) { afs_dynroot_computeDirEnt(ts->name, &curPage, &curChunk); ts = ts->next; } dirSize = (curPage + 1) * AFS_PAGESIZE; newDir = afs_osi_Alloc(dirSize); /* * Now actually construct the directory. */ curChunk = 13; curPage = 0; dirHeader = (struct DirHeader *)newDir; dirHeader->header.pgcount = 0; dirHeader->header.tag = htons(1234); dirHeader->header.freecount = 0; dirHeader->header.freebitmap[0] = 0xff; dirHeader->header.freebitmap[1] = 0x1f; for (i = 2; i < EPP / 8; i++) dirHeader->header.freebitmap[i] = 0; dirHeader->alloMap[0] = EPP - DHE - 1; for (i = 1; i < MAXPAGES; i++) dirHeader->alloMap[i] = EPP; for (i = 0; i < NHASHENT; i++) dirHeader->hashTable[i] = 0; /* Install ".", "..", and the dynamic mount directory */ afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE); linkCount += 3; for (cellidx = 0; cellidx < maxcellidx; cellidx++) { c = afs_GetCellByIndex(cellidx, READ_LOCK); if (!c) continue; if (c->cellNum == afs_dynrootCell) continue; dotLen = strlen(c->cellName) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, c->cellName); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName, VNUM_FROM_CIDX_RW(cellidx, 0)); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell, VNUM_FROM_CIDX_RW(cellidx, 1)); afs_osi_Free(dotCell, dotLen); linkCount += 2; afs_PutCell(c, READ_LOCK); } for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) { ca = afs_GetCellAlias(aliasidx); if (!ca) continue; dotLen = strlen(ca->alias) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, ca->alias); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias, VNUM_FROM_CAIDX_RW(aliasidx, 0)); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell, VNUM_FROM_CAIDX_RW(aliasidx, 1)); afs_osi_Free(dotCell, dotLen); afs_PutCellAlias(ca); } ts = afs_dynSymlinkBase; while (ts) { int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum); ts = ts->next; } ReleaseReadLock(&afs_dynSymlinkLock); ObtainWriteLock(&afs_dynrootDirLock, 549); if (afs_dynrootDir) afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen); afs_dynrootDir = newDir; afs_dynrootDirLen = dirSize; afs_dynrootDirLinkcnt = linkCount; afs_dynrootDirVersion = newVersion; ReleaseWriteLock(&afs_dynrootDirLock); }
int afs_CheckRootVolume(void) { char rootVolName[32]; struct volume *tvp = NULL; int usingDynroot = afs_GetDynrootEnable(); int localcell; AFS_STATCNT(afs_CheckRootVolume); if (*afs_rootVolumeName == 0) { strcpy(rootVolName, "root.afs"); } else { strcpy(rootVolName, afs_rootVolumeName); } if (usingDynroot) { afs_GetDynrootFid(&afs_rootFid); tvp = afs_GetVolume(&afs_rootFid, NULL, READ_LOCK); } else { struct cell *lc = afs_GetPrimaryCell(READ_LOCK); if (!lc) return ENOENT; localcell = lc->cellNum; afs_PutCell(lc, READ_LOCK); tvp = afs_GetVolumeByName(rootVolName, localcell, 1, NULL, READ_LOCK); if (!tvp) { char buf[128]; int len = strlen(rootVolName); if ((len < 9) || strcmp(&rootVolName[len - 9], ".readonly")) { strcpy(buf, rootVolName); afs_strcat(buf, ".readonly"); tvp = afs_GetVolumeByName(buf, localcell, 1, NULL, READ_LOCK); } } if (tvp) { int volid = (tvp->roVol ? tvp->roVol : tvp->volume); afs_rootFid.Cell = localcell; if (afs_rootFid.Fid.Volume && afs_rootFid.Fid.Volume != volid && afs_globalVp) { /* If we had a root fid before and it changed location we reset * the afs_globalVp so that it will be reevaluated. * Just decrement the reference count. This only occurs during * initial cell setup and can panic the machine if we set the * count to zero and fs checkv is executed when the current * directory is /afs. */ #ifdef AFS_LINUX20_ENV { struct vrequest *treq = NULL; struct vattr vattr; cred_t *credp; struct dentry *dp; struct vcache *vcp; afs_rootFid.Fid.Volume = volid; afs_rootFid.Fid.Vnode = 1; afs_rootFid.Fid.Unique = 1; credp = crref(); if (afs_CreateReq(&treq, credp)) goto out; vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL); if (!vcp) goto out; afs_getattr(vcp, &vattr, credp); afs_fill_inode(AFSTOV(vcp), &vattr); dp = d_find_alias(AFSTOV(afs_globalVp)); #if defined(AFS_LINUX24_ENV) #if defined(HAVE_DCACHE_LOCK) spin_lock(&dcache_lock); #else spin_lock(&AFSTOV(vcp)->i_lock); #endif #if defined(AFS_LINUX26_ENV) spin_lock(&dp->d_lock); #endif #endif #if defined(D_ALIAS_IS_HLIST) hlist_del_init(&dp->d_alias); hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry)); #else list_del_init(&dp->d_alias); list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry)); #endif dp->d_inode = AFSTOV(vcp); #if defined(AFS_LINUX24_ENV) #if defined(AFS_LINUX26_ENV) spin_unlock(&dp->d_lock); #endif #if defined(HAVE_DCACHE_LOCK) spin_unlock(&dcache_lock); #else spin_unlock(&AFSTOV(vcp)->i_lock); #endif #endif dput(dp); AFS_FAST_RELE(afs_globalVp); afs_globalVp = vcp; out: crfree(credp); afs_DestroyReq(treq); } #else #ifdef AFS_DARWIN80_ENV afs_PutVCache(afs_globalVp); #else AFS_FAST_RELE(afs_globalVp); #endif afs_globalVp = 0; #endif } afs_rootFid.Fid.Volume = volid; afs_rootFid.Fid.Vnode = 1; afs_rootFid.Fid.Unique = 1; } } if (tvp) { afs_initState = 300; /* won */ afs_osi_Wakeup(&afs_initState); afs_PutVolume(tvp, READ_LOCK); } if (afs_rootFid.Fid.Volume) return 0; else return ENOENT; }