unix-dynroot-support-20011009
authorNickolai Zeldovich <kolya@mit.edu>
Wed, 10 Oct 2001 01:10:29 +0000 (01:10 +0000)
committerDerrick Brashear <shadow@dementia.org>
Wed, 10 Oct 2001 01:10:29 +0000 (01:10 +0000)
  The result is that if afsd is started with "-dynroot", /afs
  will be a locally-generated directory, with mountpoints for every
  cell in CellServDB (and /afs/.cellname as the rw mountpoint).  If
  AFSDB support is also enabled, attempting to access /afs/foo will
  cause the cache manager to do an AFSDB lookup on foo, similar to
  an automounter.  Cell aliases become symlinks to the real cell
  names under /afs.

15 files changed:
NEWS
README
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/afs.h
src/afs/afs_call.c
src/afs/afs_daemons.c
src/afs/afs_dcache.c
src/afs/afs_dynroot.c [new file with mode: 0644]
src/afs/afs_vcache.c
src/afs/afs_volume.c
src/afsd/afsd.c
src/config/afs_args.h
src/dir/dir.h
src/libafs/Makefile.common
src/libuafs/Makefile.common

diff --git a/NEWS b/NEWS
index 2a2c3ec..bc0af8f 100644 (file)
--- 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 9d20c5a..44ed3d5 100644 (file)
--- 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
index 4ff3158..d416f76 100644 (file)
@@ -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.
index 32ab01b..d1918d5 100644 (file)
@@ -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 */
 
index e2f28e9..72d5b4d 100644 (file)
@@ -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;
 
index 18cda8f..5ee44eb 100644 (file)
@@ -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);
index ee28e5d..f1839c3 100644 (file)
@@ -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 (file)
index 0000000..6e42e2b
--- /dev/null
@@ -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 <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;
+}
index bad48b2..53ed8aa 100644 (file)
@@ -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) {
index 46bc9ba..53da1b4 100644 (file)
@@ -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)
index 2a03af9..74023d1 100644 (file)
@@ -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));
 }
 
index 1c76a9e..93a50a9 100644 (file)
@@ -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
index 369b250..97aaede 100644 (file)
@@ -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];
     };
index dc869c2..9f1afd2 100644 (file)
@@ -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
index bb8fe04..00a9303 100644 (file)
@@ -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