-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
sun4x_56
sun4x_57
sun4x_58
+ sun4x_59
ppc_darwin_13
ppc_linux22
ppc_linux24
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
}
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;
/* 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.
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();
/* 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
* 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 */
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 */
afs_osi_Free(cellname, cellLen);
}
#endif
+ else if (parm == AFSOP_SET_DYNROOT) {
+ code = afs_SetDynrootEnable(parm2);
+ }
else
code = EINVAL;
afs_CheckRootVolume () {
char rootVolName[32];
register struct volume *tvp;
+ int usingDynroot = afs_GetDynrootEnable();
AFS_STATCNT(afs_CheckRootVolume);
if (*afs_rootVolumeName == 0) {
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);
}
}
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);
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;
/* 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*/
/* 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;
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) {
--- /dev/null
+/*
+ * 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 <afsconfig.h>
+#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;
+}
/* 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) {
/* 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();
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*/
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)
#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
nFilesPerDir = res;
}
}
+ if (as->parms[26].items) {
+ /* -dynroot */
+ enable_dynroot = 1;
+ }
/*
* Pull out all the configuration info for the workstation's AFS cache and
}
#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);
#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));
}
#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
};
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];
};
afs_daemons.o \
afs_dcache.o \
afs_dir.o \
+ afs_dynroot.o \
afs_init.o \
afs_lock.o \
afs_mariner.o \
$(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
$(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 \
$(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 \
$(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 \
$(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
$(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