diff --git a/NEWS b/NEWS index 2a2c3ece35..bc0af8ffed 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,18 @@ -Openafs News -- history of user Visible changes. September 17, 2001 +OpenAFS News -- history of user-visible changes. October 9, 2001 * Changes incorporated in OpenAFS 1.2.2 +** If afsd is started with the -dynroot flag, /afs will be locally + generated from the CellServDB. AFSDB cells will be mounted + automatically upon access. + ** The namei fileserver allows vice "partitions" to be directories instead of partitions and will attach and display accordingly. Creating the file "AlwaysAttach" in the /vicepX directory is used as the trigger to attach it. +** TSM support for butc no longer requires editing a Makefile, simply + specify the --enable-tivoli-tsm configure option. + ** Linux builds no longer require source changes every time the kernel inode structure changes; the OpenAFS sources will now configure itself to the actual inode structure as defined in the kernel diff --git a/README b/README index 9d20c5a0d4..44ed3d5e91 100644 --- a/README +++ b/README @@ -39,6 +39,7 @@ A. Creating the proper directory structure. sun4x_56 sun4x_57 sun4x_58 + sun4x_59 ppc_darwin_13 ppc_linux22 ppc_linux24 diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index 4ff31586f3..d416f76073 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -912,6 +912,7 @@ afs_lookup(adp, aname, avcp, acred) afs_hyper_t versionNo; int no_read_access = 0; struct sysname_info sysState; /* used only for @sys checking */ + int dynrootRetry = 1; AFS_STATCNT(afs_lookup); #ifdef AFS_OSF_ENV @@ -1112,9 +1113,27 @@ afs_lookup(adp, aname, avcp, acred) } tname = sysState.name; - ReleaseReadLock(&adp->lock); afs_PutDCache(tdc); + if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) { + struct cell *tcell; + + ReleaseReadLock(&adp->lock); + dynrootRetry = 0; + if (*tname == '.') + tcell = afs_GetCellByName(tname + 1, READ_LOCK); + else + tcell = afs_GetCellByName(tname, READ_LOCK); + if (tcell) { + afs_PutCell(tcell, READ_LOCK); + afs_RefreshDynroot(); + if (tname != aname && tname) osi_FreeLargeSpace(tname); + goto redo; + } + } else { + ReleaseReadLock(&adp->lock); + } + /* new fid has same cell and volume */ tfid.Cell = adp->fid.Cell; tfid.Fid.Volume = adp->fid.Fid.Volume; @@ -1132,7 +1151,7 @@ afs_lookup(adp, aname, avcp, acred) /* prefetch some entries, if the dir is currently open. The variable * dirCookie tells us where to start prefetching from. */ - if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)) { + if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign) && !afs_IsDynroot(adp)) { afs_int32 retry; /* if the entry is not in the cache, or is in the cache, * but hasn't been statd, then do a bulk stat operation. diff --git a/src/afs/afs.h b/src/afs/afs.h index 32ab01bc82..d1918d5367 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -960,6 +960,7 @@ extern struct brequest afs_brs[NBRS]; /* request structures */ extern struct cell *afs_GetCell(); extern struct cell *afs_GetCellByName(); +extern struct cell *afs_GetCellByIndex(); extern struct unixuser *afs_GetUser(); extern struct volume *afs_GetVolume(); extern struct volume *afs_GetVolumeByName(); @@ -992,6 +993,17 @@ extern void afs_shutdown(); /* afs_osifile.c */ extern void shutdown_osifile(); +/* afs_dynroot.c */ +extern int afs_IsDynrootFid(); +extern void afs_GetDynrootFid(); +extern int afs_IsDynroot(); +extern void afs_RefreshDynroot(); +extern void afs_GetDynroot(); +extern void afs_PutDynroot(); +extern int afs_DynrootNewVnode(); +extern int afs_SetDynrootEnable(); +extern int afs_GetDynrootEnable(); + /* Performance hack - we could replace VerifyVCache2 with the appropriate * GetVCache incantation, and could eliminate even this code from afs_UFSRead @@ -1050,6 +1062,7 @@ extern int afs_CacheTooFull; * afs_GetDownD wakes those processes once the cache is 95% full * (CM_CACHESIZEDRAINEDPCT). */ +extern void afs_MaybeWakeupTruncateDaemon(); extern void afs_CacheTruncateDaemon(); extern int afs_WaitForCacheDrain; #define CM_MAXDISCARDEDCHUNKS 16 /* # of chunks */ @@ -1065,19 +1078,6 @@ extern int afs_WaitForCacheDrain; afs_freeDCCount - afs_discardDCCount < \ ((100-CM_DCACHECOUNTFREEPCT)*afs_cacheFiles)/100) -#define afs_MaybeWakeupTruncateDaemon() \ - do { \ - if (!afs_CacheTooFull && afs_CacheIsTooFull()) { \ - afs_CacheTooFull = 1; \ - if (!afs_TruncateDaemonRunning) { \ - afs_osi_Wakeup((char *)afs_CacheTruncateDaemon); \ - } \ - } else if (!afs_TruncateDaemonRunning && \ - afs_blocksDiscarded > CM_MAXDISCARDEDCHUNKS) { \ - afs_osi_Wakeup((char *)afs_CacheTruncateDaemon); \ - } \ - } while (0) - /* Handy max length of a numeric string. */ #define CVBS 12 /* max afs_int32 is 2^32 ~ 4*10^9, +1 for NULL, +luck */ diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index e2f28e96c5..72d5b4d501 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -625,6 +625,9 @@ long parm, parm2, parm3, parm4, parm5, parm6; afs_osi_Free(cellname, cellLen); } #endif + else if (parm == AFSOP_SET_DYNROOT) { + code = afs_SetDynrootEnable(parm2); + } else code = EINVAL; diff --git a/src/afs/afs_daemons.c b/src/afs/afs_daemons.c index 18cda8fd12..5ee44eb418 100644 --- a/src/afs/afs_daemons.c +++ b/src/afs/afs_daemons.c @@ -268,6 +268,7 @@ void afs_Daemon() { afs_CheckRootVolume () { char rootVolName[32]; register struct volume *tvp; + int usingDynroot = afs_GetDynrootEnable(); AFS_STATCNT(afs_CheckRootVolume); if (*afs_rootVolumeName == 0) { @@ -276,7 +277,12 @@ afs_CheckRootVolume () { else { strcpy(rootVolName, afs_rootVolumeName); } - tvp = afs_GetVolumeByName(rootVolName, LOCALCELL, 1, (struct vrequest *) 0, READ_LOCK); + if (usingDynroot) { + afs_GetDynrootFid(&afs_rootFid); + tvp = afs_GetVolume(&afs_rootFid, (struct vrequest *) 0, READ_LOCK); + } else { + tvp = afs_GetVolumeByName(rootVolName, LOCALCELL, 1, (struct vrequest *) 0, READ_LOCK); + } if (!tvp) { char buf[128]; int len = strlen(rootVolName); @@ -288,23 +294,25 @@ afs_CheckRootVolume () { } } 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. - */ - AFS_FAST_RELE(afs_globalVp); - afs_globalVp = 0; + if (!usingDynroot) { + 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. + */ + AFS_FAST_RELE(afs_globalVp); + afs_globalVp = 0; + } + afs_rootFid.Fid.Volume = volid; + afs_rootFid.Fid.Vnode = 1; + afs_rootFid.Fid.Unique = 1; } - afs_rootFid.Fid.Volume = volid; - afs_rootFid.Fid.Vnode = 1; - afs_rootFid.Fid.Unique = 1; afs_initState = 300; /* won */ afs_osi_Wakeup(&afs_initState); afs_PutVolume(tvp, READ_LOCK); diff --git a/src/afs/afs_dcache.c b/src/afs/afs_dcache.c index ee28e5dd15..f1839c31e1 100644 --- a/src/afs/afs_dcache.c +++ b/src/afs/afs_dcache.c @@ -218,6 +218,17 @@ struct CTD_stats { int CTD_nSleeps; } CTD_stats; +void afs_MaybeWakeupTruncateDaemon() { + if (!afs_CacheTooFull && afs_CacheIsTooFull()) { + afs_CacheTooFull = 1; + if (!afs_TruncateDaemonRunning) + afs_osi_Wakeup((char *)afs_CacheTruncateDaemon); + } else if (!afs_TruncateDaemonRunning && + afs_blocksDiscarded > CM_MAXDISCARDEDCHUNKS) { + afs_osi_Wakeup((char *)afs_CacheTruncateDaemon); + } +} + u_int afs_min_cache = 0; void afs_CacheTruncateDaemon() { osi_timeval_t CTD_tmpTime; @@ -1436,18 +1447,19 @@ struct tlocal1 { /* these fields are protected by the lock on the vcache and luck * on the dcache */ -#define updateV2DC(l,v,d,src) { \ - if (!l || 0 == NBObtainWriteLock(&((v)->lock),src)) { \ - if (hsame((v)->m.DataVersion, (d)->f.versionNo) && (v)->callback) { \ - (v)->quick.dc = (d); \ - (v)->quick.stamp = (d)->stamp = MakeStamp(); \ - (v)->quick.minLoc = AFS_CHUNKTOBASE((d)->f.chunk); \ - /* Don't think I need these next two lines forever */ \ - (v)->quick.len = (d)->f.chunkBytes; \ - (v)->h1.dchint = (d); \ - } \ - if(l) ReleaseWriteLock(&((v)->lock)); \ - } } +void updateV2DC(int l, struct vcache *v, struct dcache *d, int src) { + if (!l || 0 == NBObtainWriteLock(&(v->lock),src)) { + if (hsame(v->m.DataVersion, d->f.versionNo) && v->callback) { + v->quick.dc = d; + v->quick.stamp = d->stamp = MakeStamp(); + v->quick.minLoc = AFS_CHUNKTOBASE(d->f.chunk); + /* Don't think I need these next two lines forever */ + v->quick.len = d->f.chunkBytes; + v->h1.dchint = d; + } + if(l) ReleaseWriteLock(&((v)->lock)); + } +} struct dcache *afs_GetDCache(avc, abyte, areq, aoffset, alen, aflags) register struct vcache *avc; /*Held*/ @@ -1773,7 +1785,7 @@ struct dcache *afs_GetDCache(avc, abyte, areq, aoffset, alen, aflags) /* Watch for standard race condition */ if (hsame(avc->m.DataVersion, tdc->f.versionNo)) { - updateV2DC(0,avc,tdc,569); /* set hint */ + updateV2DC(0,avc,tdc,569); /* set hint */ if (setLocks) ReleaseWriteLock(&avc->lock); afs_stats_cmperf.dcacheHits++; goto done; @@ -1868,6 +1880,35 @@ struct dcache *afs_GetDCache(avc, abyte, areq, aoffset, alen, aflags) afs_stats_cmperf.dcacheMisses++; afs_Trace3(afs_iclSetp, CM_TRACE_FETCHPROC, ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, Position, ICL_TYPE_INT32, size); + + /* + * Dynamic root support: fetch data from local memory. + */ + if (afs_IsDynroot(avc)) { + char *dynrootDir; + int dynrootLen; + + afs_GetDynroot(&dynrootDir, &dynrootLen, &tsmall->OutStatus); + + dynrootDir += Position; + dynrootLen -= Position; + if (size > dynrootLen) + size = dynrootLen; + if (size < 0) size = 0; + code = afs_osi_Write(file, -1, dynrootDir, size); + afs_PutDynroot(); + + if (code == size) + code = 0; + else + code = -1; + + tdc->validPos = Position + size; + afs_CFileTruncate(file, size); /* prune it */ + } else + /* + * Not a dynamic vnode: do the real fetch. + */ do { tc = afs_Conn(&avc->fid, areq, SHARED_LOCK); if (tc) { diff --git a/src/afs/afs_dynroot.c b/src/afs/afs_dynroot.c new file mode 100644 index 0000000000..6e42e2b234 --- /dev/null +++ b/src/afs/afs_dynroot.c @@ -0,0 +1,461 @@ +/* + * Copyright 2000, International Business Machines Corporation and others. + * All Rights Reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + */ + +/* + * Dynamic /afs volume support. + * + * Implements: + * afs_IsDynrootFid + * afs_GetDynrootFid + * afs_IsDynroot + * afs_RefreshDynroot + * afs_GetDynroot + * afs_PutDynroot + * afs_DynrootNewVnode + * afs_SetDynrootEnable + * afs_GetDynrootEnable + * + */ + +#include +#include "../afs/param.h" + +#include "../afs/stds.h" +#include "../afs/sysincludes.h" /* Standard vendor system headers */ +#include "../afs/afsincludes.h" +#include "../afs/afs_osi.h" +#include "../afsint/afsint.h" +#include "../afs/lock.h" + +#include "../afs/prs_fs.h" +#include "../afs/dir.h" + +#define AFS_DYNROOT_CELL 1 +#define AFS_DYNROOT_VOLUME 1 +#define AFS_DYNROOT_VNODE 1 +#define AFS_DYNROOT_UNIQUE 1 + +#define VNUM2CIDX(vnum) ((vnum) >> 2) +#define VNUM2RW(vnum) (((vnum) >> 1) & 1) +#define CIDXRW2VNUM(cidx, rw) (((cidx) << 2) | ((rw) << 1)) + +static int afs_dynrootEnable = 0; + +static afs_rwlock_t afs_dynrootDirLock; +/* Start of variables protected by afs_dynrootDirLock */ +static char *afs_dynrootDir = NULL; +static int afs_dynrootDirLen; +static int afs_dynrootDirLinkcnt; +static int afs_dynrootCellCount; +static int afs_dynrootVersion = 1; +static int afs_dynrootVersionHigh = 1; +/* End of variables protected by afs_dynrootDirLock */ + +extern afs_int32 afs_cellindex; +extern afs_rwlock_t afs_xvcache; + +/* + * Returns non-zero iff fid corresponds to the top of the dynroot volume. + */ +int +afs_IsDynrootFid(struct VenusFid *fid) +{ + return + (afs_dynrootEnable && + fid->Cell == AFS_DYNROOT_CELL && + fid->Fid.Volume == AFS_DYNROOT_VOLUME && + fid->Fid.Vnode == AFS_DYNROOT_VNODE && + fid->Fid.Unique == AFS_DYNROOT_UNIQUE); +} + +/* + * Obtain the magic dynroot volume Fid. + */ +void +afs_GetDynrootFid(struct VenusFid *fid) +{ + fid->Cell = AFS_DYNROOT_CELL; + fid->Fid.Volume = AFS_DYNROOT_VOLUME; + fid->Fid.Vnode = AFS_DYNROOT_VNODE; + fid->Fid.Unique = AFS_DYNROOT_UNIQUE; +} + +/* + * Returns non-zero iff avc is a pointer to the dynroot /afs vnode. + */ +int +afs_IsDynroot(avc) + struct vcache *avc; +{ + return afs_IsDynrootFid(&avc->fid); +} + +/* + * Add directory entry by given name to a directory. Assumes the + * caller has allocated the directory to be large enough to hold + * the necessary entry. + */ +static void +afs_dynroot_addDirEnt(dirHeader, curPageP, curChunkP, name, vnode) + struct DirHeader *dirHeader; + int *curPageP; + int *curChunkP; + char *name; + int vnode; +{ + char *dirBase = (char *) dirHeader; + struct PageHeader *pageHeader; + struct DirEntry *dirEntry; + int sizeOfEntry, i, t1, t2; + int curPage = *curPageP; + int curChunk = *curChunkP; + int didNewPage = 0; + + /* + * Check if we need to flip pages.. If so, init the new page. + */ + sizeOfEntry = afs_dir_NameBlobs(name); + if (curChunk + sizeOfEntry > EPP) { + curPage++; + curChunk = 1; + didNewPage = 1; + } + + pageHeader = (struct PageHeader *) (dirBase + curPage * AFS_PAGESIZE); + if (didNewPage) { + pageHeader->pgcount = 0; + pageHeader->tag = htons(1234); + pageHeader->freecount = 0; + pageHeader->freebitmap[0] = 0x01; + for (i = 1; i < EPP/8; i++) + pageHeader->freebitmap[i] = 0; + + dirHeader->alloMap[curPage] = EPP - 1; + } + + dirEntry = (struct DirEntry *) (pageHeader + curChunk); + dirEntry->flag = 1; + dirEntry->length = 0; + dirEntry->next = 0; + dirEntry->fid.vnode = htonl(vnode); + dirEntry->fid.vunique = htonl(1); + strcpy(dirEntry->name, name); + + for (i = curChunk; i < curChunk + sizeOfEntry; i++) { + t1 = i / 8; + t2 = i % 8; + pageHeader->freebitmap[t1] |= (1 << t2); + } + + /* + * Add the new entry to the correct hash chain. + */ + i = DirHash(name); + dirEntry->next = dirHeader->hashTable[i]; + dirHeader->hashTable[i] = htons(curPage * EPP + curChunk); + + curChunk += sizeOfEntry; + dirHeader->alloMap[curPage] -= sizeOfEntry; + + *curPageP = curPage; + *curChunkP = curChunk; +} + +/* + * 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. + */ +void +afs_RefreshDynroot() +{ + int cellidx, maxcellidx, i; + struct cell *c; + int curChunk, curPage; + int dirSize; + char *newDir, *dotCell; + struct DirHeader *dirHeader; + struct PageHeader *pageHeader; + struct DirEntry *dirEntry; + int doFlush = 0; + int linkCount = 0; + + /* + * Save afs_cellindex here, in case it changes between the + * two loops. + */ + maxcellidx = afs_cellindex; + + /* + * Compute the amount of space we need for the fake dir + */ + curChunk = 13; + curPage = 0; + + for (cellidx = 0; cellidx < maxcellidx; cellidx++) { + int sizeOfCurEntry; + + c = afs_GetCellByIndex(cellidx, READ_LOCK); + if (!c) continue; + + sizeOfCurEntry = afs_dir_NameBlobs(c->cellName); + if (curChunk + sizeOfCurEntry > EPP) { + curPage++; + curChunk = 1; + } + curChunk += sizeOfCurEntry; + + dotCell = afs_osi_Alloc(strlen(c->cellName) + 2); + strcpy(dotCell, "."); + strcat(dotCell, c->cellName); + sizeOfCurEntry = afs_dir_NameBlobs(dotCell); + if (curChunk + sizeOfCurEntry > EPP) { + curPage++; + curChunk = 1; + } + curChunk += sizeOfCurEntry; + + afs_PutCell(c, READ_LOCK); + } + + 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 ".." */ + afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1); + afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1); + linkCount += 2; + + for (cellidx = 0; cellidx < maxcellidx; cellidx++) { + c = afs_GetCellByIndex(cellidx, READ_LOCK); + afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, + c->cellName, CIDXRW2VNUM(cellidx, 0)); + + dotCell = afs_osi_Alloc(strlen(c->cellName) + 2); + strcpy(dotCell, "."); + strcat(dotCell, c->cellName); + afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, + dotCell, CIDXRW2VNUM(cellidx, 1)); + + linkCount += 2; + + afs_PutCell(c, READ_LOCK); + } + + ObtainWriteLock(&afs_dynrootDirLock, 549); + if (afs_dynrootDir) afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen); + afs_dynrootDir = newDir; + afs_dynrootDirLen = dirSize; + afs_dynrootDirLinkcnt = linkCount; + if (afs_dynrootCellCount != maxcellidx) { + /* + * New cells added -- bump data version, invalidate vcache. + */ + afs_dynrootCellCount = maxcellidx; + afs_dynrootVersion++; + afs_dynrootVersionHigh = osi_Time(); + doFlush = 1; + } + ReleaseWriteLock(&afs_dynrootDirLock); + + if (doFlush) { + afs_int32 retry; + struct vcache *tvc; + struct VenusFid tfid; + + afs_GetDynrootFid(&tfid); + do { + retry = 0; + ObtainReadLock(&afs_xvcache); + tvc = afs_FindVCache(&tfid, 0, 0, &retry, 0); + ReleaseReadLock(&afs_xvcache); + } while (retry); + if (tvc) { + tvc->states &= ~(CStatd | CUnique); + osi_dnlc_purgedp(tvc); + afs_PutVCache(tvc); + } + } +} + +/* + * Returns a pointer to the base of the dynroot directory in memory, + * length thereof, and a FetchStatus. + */ +void +afs_GetDynroot(dynrootDir, dynrootLen, status) + char **dynrootDir; + int *dynrootLen; + struct AFSFetchStatus *status; +{ + ObtainReadLock(&afs_dynrootDirLock); + if (!afs_dynrootDir) { + ReleaseReadLock(&afs_dynrootDirLock); + afs_RefreshDynroot(); + ObtainReadLock(&afs_dynrootDirLock); + } + + if (dynrootDir) *dynrootDir = afs_dynrootDir; + if (dynrootLen) *dynrootLen = afs_dynrootDirLen; + + if (status) { + memset(status, 0, sizeof(struct AFSFetchStatus)); + status->FileType = Directory; + status->LinkCount = afs_dynrootDirLinkcnt; + status->Length = afs_dynrootDirLen; + status->DataVersion = afs_dynrootVersion; + status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ; + status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ; + status->UnixModeBits = 0755; + status->ParentVnode = 1; + status->ParentUnique = 1; + status->dataVersionHigh = afs_dynrootVersionHigh; + } +} + +/* + * Puts back the dynroot read lock. + */ +void +afs_PutDynroot() +{ + ReleaseReadLock(&afs_dynrootDirLock); +} + +/* + * Inform dynroot that a new vnode is being created. Return value + * is non-zero if this vnode is handled by dynroot, in which case + * FetchStatus will be filled in. + */ +int +afs_DynrootNewVnode(avc, status) + struct vcache *avc; + struct AFSFetchStatus *status; +{ + if (!afs_dynrootEnable) return 0; + + if (afs_IsDynroot(avc)) { + afs_GetDynroot(0, 0, status); + afs_PutDynroot(); + return 1; + } + + /* + * Check if this is an entry under /afs, e.g. /afs/cellname. + */ + if (avc->fid.Cell == AFS_DYNROOT_CELL && + avc->fid.Fid.Volume == AFS_DYNROOT_VOLUME) { + + struct cell *c; + int namelen, linklen, cellidx, rw; + + cellidx = VNUM2CIDX(avc->fid.Fid.Vnode); + rw = VNUM2RW(avc->fid.Fid.Vnode); + + c = afs_GetCellByIndex(cellidx, READ_LOCK); + if (!c) { + afs_warn("dynroot vnode inconsistency, can't find cell %d\n", + cellidx); + return 0; + } + + memset(status, 0, sizeof(struct AFSFetchStatus)); + + if (c->states & CAlias) { + /* + * linkData needs to contain the name of the cell + * we're aliasing for. + */ + struct cell *tca = c->alias; + + if (!tca) { + afs_warn("dynroot: alias %s missing cell alias pointer\n", + c->cellName); + linklen = 7; + avc->linkData = afs_osi_Alloc(linklen + 1); + strcpy(avc->linkData, "unknown"); + } else { + int namelen = strlen(tca->cellName); + linklen = rw + namelen; + avc->linkData = afs_osi_Alloc(linklen + 1); + strcpy(avc->linkData, rw ? "." : ""); + strcat(avc->linkData, tca->cellName); + } + + status->UnixModeBits = 0755; + } else { + /* + * linkData needs to contain "#cell:root.cell" or "%cell:root.cell" + */ + namelen = strlen(c->cellName); + linklen = 1 + namelen + 10; + avc->linkData = afs_osi_Alloc(linklen + 1); + strcpy(avc->linkData, rw ? "%" : "#"); + strcat(avc->linkData, c->cellName); + strcat(avc->linkData, ":root.cell"); + + status->UnixModeBits = 0644; + } + + status->FileType = SymbolicLink; + status->LinkCount = 1; + status->Length = linklen; + status->DataVersion = 1; + status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ; + status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ; + status->ParentVnode = 1; + status->ParentUnique = 1; + + afs_PutCell(c, READ_LOCK); + return 1; + } + + return 0; +} + +/* + * Enable or disable dynroot. Returns 0 if successful. + */ +int +afs_SetDynrootEnable(enable) + int enable; +{ + afs_dynrootEnable = enable; + return 0; +} + +/* + * Check if dynroot support is enabled. + */ +int +afs_GetDynrootEnable() +{ + return afs_dynrootEnable; +} diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index bad48b2810..53ed8aa172 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -1687,8 +1687,15 @@ loop: /* stat the file */ afs_RemoveVCB(afid); { - struct AFSFetchStatus OutStatus; - code = afs_FetchStatus(tvc, afid, areq, &OutStatus); + struct AFSFetchStatus OutStatus; + + if (afs_DynrootNewVnode(tvc, &OutStatus)) { + afs_ProcessFS(tvc, &OutStatus, areq); + tvc->states |= CStatd | CUnique; + code = 0; + } else { + code = afs_FetchStatus(tvc, afid, areq, &OutStatus); + } } if (code) { diff --git a/src/afs/afs_volume.c b/src/afs/afs_volume.c index 46bc9ba8af..53da1b47f7 100644 --- a/src/afs/afs_volume.c +++ b/src/afs/afs_volume.c @@ -72,6 +72,7 @@ afs_int32 fvTable[NFENTRIES]; /* Forward declarations */ static struct volume *afs_NewVolumeByName(char *aname, afs_int32 acell, int agood, struct vrequest *areq, afs_int32 locktype); +static struct volume *afs_NewDynrootVolume(struct VenusFid *fid); static inVolList(); @@ -402,8 +403,12 @@ struct volume *afs_GetVolume(afid, areq, locktype) tv = afs_FindVolume(afid, locktype); if (!tv) { - bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume); - tv = afs_NewVolumeByName(bp, afid->Cell, 0, areq, locktype); + if (afs_IsDynrootFid(afid)) { + tv = afs_NewDynrootVolume(afid); + } else { + bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume); + tv = afs_NewVolumeByName(bp, afid->Cell, 0, areq, locktype); + } } return tv; } /*afs_GetVolume*/ @@ -549,6 +554,29 @@ struct volume *afs_GetVolumeByName(aname, acell, agood, areq, locktype) return(tv); } +static struct volume *afs_NewDynrootVolume(struct VenusFid *fid) { + struct cell *tcell; + struct volume *tv; + struct vldbentry tve; + char *bp, tbuf[CVBS]; + + tcell = afs_GetCell(fid->Cell, READ_LOCK); + if (!tcell) + return (struct volume *) 0; + if (!(tcell->states & CHasVolRef)) + tcell->states |= CHasVolRef; + + bp = afs_cv2string(&tbuf[CVBS], fid->Fid.Volume); + memset(&tve, 0, sizeof(tve)); + strcpy(tve.name, "local-dynroot"); + tve.volumeId[ROVOL] = fid->Fid.Volume; + tve.flags = VLF_ROEXISTS; + + tv = afs_SetupVolume(0, bp, &tve, tcell, 0, 0, 0); + afs_PutCell(tcell, READ_LOCK); + return tv; +} + int lastnvcode; static struct volume *afs_NewVolumeByName(char *aname, afs_int32 acell, int agood, struct vrequest *areq, afs_int32 locktype) diff --git a/src/afsd/afsd.c b/src/afsd/afsd.c index 2a03af9618..74023d1df1 100644 --- a/src/afsd/afsd.c +++ b/src/afsd/afsd.c @@ -239,6 +239,7 @@ static int enable_process_stats = 0; /* enable rx stats */ #ifdef AFS_AFSDB_ENV static int enable_afsdb = 0; /* enable AFSDB support */ #endif +static int enable_dynroot = 0; /* enable dynroot support */ #ifdef notdef static int inodes = 60; /* VERY conservative, but has to be */ #endif @@ -1307,6 +1308,10 @@ mainproc(as, arock) nFilesPerDir = res; } } + if (as->parms[26].items) { + /* -dynroot */ + enable_dynroot = 1; + } /* * Pull out all the configuration info for the workstation's AFS cache and @@ -1538,6 +1543,14 @@ mainproc(as, arock) } #endif + if (enable_dynroot) { + if (afsd_verbose) + printf("%s: Enabling dynroot support in kernel.\n", rn); + code = call_syscall(AFSOP_SET_DYNROOT, 1); + if (code) + printf("%s: Error enabling dynroot support.\n", rn); + } + /* Initialize AFS daemon threads. */ if (afsd_verbose) printf("%s: Forking AFS daemon.\n", rn); @@ -1889,6 +1902,7 @@ char **argv; { #endif ), "Enable AFSDB support"); cmd_AddParm(ts, "-files_per_subdir", CMD_SINGLE, CMD_OPTIONAL, "log(2) of the number of cache files per cache subdirectory"); + cmd_AddParm(ts, "-dynroot", CMD_FLAG, CMD_OPTIONAL, "Enable dynroot support"); return (cmd_Dispatch(argc, argv)); } diff --git a/src/config/afs_args.h b/src/config/afs_args.h index 1c76a9e299..93a50a9079 100644 --- a/src/config/afs_args.h +++ b/src/config/afs_args.h @@ -39,6 +39,7 @@ #define AFSOP_ADDCELL2 29 /* 2nd add cell protocol interface */ #define AFSOP_AFSDB_HANDLER 30 /* userspace AFSDB lookup handler */ +#define AFSOP_SET_DYNROOT 31 /* enable/disable dynroot support */ /* The range 20-30 is reserved for AFS system offsets in the afs_syscall */ #define AFSCALL_PIOCTL 20 diff --git a/src/dir/dir.h b/src/dir/dir.h index 369b250693..97aaede321 100644 --- a/src/dir/dir.h +++ b/src/dir/dir.h @@ -39,8 +39,8 @@ struct PageHeader }; struct DirHeader - {/* A directory header object. - */struct PageHeader header; + {/* A directory header object. */ + struct PageHeader header; char alloMap[MAXPAGES]; /* one byte per 2K page */ unsigned short hashTable[NHASHENT]; }; diff --git a/src/libafs/Makefile.common b/src/libafs/Makefile.common index dc869c28db..9f1afd2ac1 100644 --- a/src/libafs/Makefile.common +++ b/src/libafs/Makefile.common @@ -55,6 +55,7 @@ AFSAOBJS = \ afs_daemons.o \ afs_dcache.o \ afs_dir.o \ + afs_dynroot.o \ afs_init.o \ afs_lock.o \ afs_mariner.o \ @@ -152,6 +153,8 @@ afs_conn.o: $(AFS)/afs_conn.c $(CRULE2); afs_dcache.o: $(AFS)/afs_dcache.c $(CRULE2); +afs_dynroot.o: $(AFS)/afs_dynroot.c + $(CRULE2); afs_init.o: $(AFS)/afs_init.c $(CRULE2); afs_mariner.o: $(AFS)/afs_mariner.c diff --git a/src/libuafs/Makefile.common b/src/libuafs/Makefile.common index bb8fe04cc9..00a930380c 100644 --- a/src/libuafs/Makefile.common +++ b/src/libuafs/Makefile.common @@ -63,6 +63,7 @@ UAFSOBJ = \ $(UOBJ)/afs_daemons.o \ $(UOBJ)/afs_dcache.o \ $(UOBJ)/afs_dir.o \ + $(UOBJ)/afs_dynroot.o \ $(UOBJ)/afs_init.o \ $(UOBJ)/afs_lock.o \ $(UOBJ)/afs_mariner.o \ @@ -179,6 +180,7 @@ AFSWEBOBJ = \ $(WEBOBJ)/afs_daemons.o \ $(WEBOBJ)/afs_dcache.o \ $(WEBOBJ)/afs_dir.o \ + $(WEBOBJ)/afs_dynroot.o \ $(WEBOBJ)/afs_init.o \ $(WEBOBJ)/afs_lock.o \ $(WEBOBJ)/afs_mariner.o \ @@ -297,6 +299,7 @@ AFSWEBOBJKRB = \ $(WEBOBJ)/afs_daemons.o \ $(WEBOBJ)/afs_dcache.o \ $(WEBOBJ)/afs_dir.o \ + $(WEBOBJ)/afs_dynroot.o \ $(WEBOBJ)/afs_init.o \ $(WEBOBJ)/afs_lock.o \ $(WEBOBJ)/afs_mariner.o \ @@ -417,6 +420,8 @@ $(UOBJ)/afs_conn.o: $(AFS)/afs_conn.c $(CRULE1); $(UOBJ)/afs_dcache.o: $(AFS)/afs_dcache.c $(CRULE1); +$(UOBJ)/afs_dynroot.o: $(AFS)/afs_dynroot.c + $(CRULE1); $(UOBJ)/afs_init.o: $(AFS)/afs_init.c $(CRULE1); $(UOBJ)/afs_mariner.o: $(AFS)/afs_mariner.c @@ -660,6 +665,8 @@ $(WEBOBJ)/afs_conn.o: $(AFS)/afs_conn.c $(CRULE2); $(WEBOBJ)/afs_dcache.o: $(AFS)/afs_dcache.c $(CRULE2); +$(WEBOBJ)/afs_dynroot.o: $(AFS)/afs_dynroot.c + $(CRULE2); $(WEBOBJ)/afs_init.o: $(AFS)/afs_init.c $(CRULE2); $(WEBOBJ)/afs_mariner.o: $(AFS)/afs_mariner.c