afsd-warning-cleanup-20011005
[openafs.git] / src / afsd / afsd.c
index 57eb222..962984b 100644 (file)
   *               This option is now disabled.
   *    -logfile   Place where to put the logfile (default in <cache>/etc/AFSLog.
   *    -waitclose make close calls always synchronous (slows em down, tho)
+  *    -files_per_subdir [n]   number of files per cache subdir. (def=2048)
   *    -shutdown  Shutdown afs daemons
   *---------------------------------------------------------------------------*/
 
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID("$Header$");
+
 #define VFS 1
 
-#include <afs/param.h>
 #include <afs/cmd.h>
 
 #include <assert.h>
-#include <itc.h>
+#include <potpourri.h>
 #include <afs/afsutil.h>
-#undef in
-#undef out
 #include <stdlib.h>
 #include <stdio.h>
 #include <signal.h>
 #include <sys/file.h>
 #include <errno.h>
 #include <sys/time.h>
-#ifdef AFS_DEC_ENV
+#include <dirent.h>
+
+#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
-#include <sys/fs_types.h>
 #endif
-#if    defined(AFS_SUN_ENV)
-#include <sys/vfs.h>
+
+#ifdef HAVE_SYS_FS_TYPES_H
+#include <sys/fs_types.h>
 #endif
-#ifndef        AFS_AIX41_ENV
+
+#ifdef HAVE_SYS_MOUNT_H
 #include <sys/mount.h>
 #endif
-#include <dirent.h>
-#ifdef   AFS_SUN5_ENV
+
+#ifdef HAVE_SYS_FCNTL_H
 #include <sys/fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_MNTTAB_H
 #include <sys/mnttab.h>
+#endif
+
+#ifdef HAVE_SYS_MNTENT_H
 #include <sys/mntent.h>
-#else
-#if    defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
-#include <mntent.h>
 #endif
+
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
 #endif
 
-#if defined(AFS_OSF_ENV) || defined(AFS_DEC_ENV)
+#ifdef HAVE_SYS_MOUNT_H
 #include <sys/mount.h>
-#else
+#endif
+
+#ifdef HAVE_SYS_VFS_H
 #include <sys/vfs.h>
 #endif
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
 #include <netinet/in.h>
 #include <afs/afs_args.h>
 #include <afs/cellconfig.h>
@@ -132,7 +154,7 @@ void set_staticaddrs(void);
 #if AFS_HAVE_STATVFS
 #include <sys/statvfs.h>
 #else
-#if !defined(AFS_OSF_ENV)
+#if !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
 #include <sys/statfs.h>
 #endif
 #endif
@@ -188,7 +210,7 @@ char fullpn_VolInfoFile[1024];              /*Full pathname of VOLINFOFILE*/
 char fullpn_AFSLogFile[1024];          /*Full pathname of AFSLOGFILE*/
 char fullpn_CacheInfo[1024];           /*Full pathname of CACHEINFO*/
 char fullpn_VFile[1024];               /*Full pathname of data cache files*/
-char *vFileNumber;                     /*Ptr to the number part of above pathname*/
+char *vFilePtr;                                /*Ptr to the number part of above pathname*/
 int sawCacheMountDir = 0;              /* from cmd line */
 int sawCacheBaseDir = 0;
 int sawCacheBlocks = 0;
@@ -202,6 +224,7 @@ afs_int32 lookingForHomeCell;               /*Are we still looking for the home cell?*/
 int createAndTrunc = O_CREAT | O_TRUNC; /*Create & truncate on open*/
 int ownerRWmode        = 0600;                 /*Read/write OK by owner*/
 static int filesSet = 0;               /*True if number of files explicitly set*/
+static int nFilesPerDir = 2048;                /* # files per cache dir */
 static int nDaemons = 2;               /* Number of background daemons */
 static int chunkSize = 0;               /* 2^chunkSize bytes per chunk */
 static int dCacheSize = 300;            /* # of dcache entries */
@@ -213,6 +236,9 @@ static int nBiods = 5;                      /* AIX3.1 only */
 static int preallocs = 400;            /* Def # of allocated memory blocks */
 static int enable_peer_stats = 0;      /* enable rx stats */
 static int enable_process_stats = 0;   /* enable rx stats */
+#ifdef AFS_AFSDB_ENV
+static int enable_afsdb = 0;           /* enable AFSDB support */
+#endif
 #ifdef notdef
 static int inodes = 60;                        /* VERY conservative, but has to be */
 #endif
@@ -225,6 +251,17 @@ int afsd_CloseSynch = 0;           /*Are closes synchronous or not? */
 #else
 #define AFSD_INO_T afs_uint32
 #endif
+struct afsd_file_list {
+  int                  fileNum;
+  struct afsd_file_list        *next;
+};
+struct afsd_file_list **cache_dir_filelist = NULL;
+int *cache_dir_list = NULL;            /* Array of cache subdirs */
+int *dir_for_V = NULL;                 /* Array: dir of each cache file.
+                                        * -1: file does not exist
+                                        * -2: file exists in top-level
+                                        * >=0: file exists in Dxxx
+                                        */
 AFSD_INO_T *inode_for_V;               /* Array of inodes for desired
                                         * cache files */
 int missing_DCacheFile = 1;            /*Is the DCACHEFILE missing?*/
@@ -387,6 +424,7 @@ int cs;
   *
   * Arguments:
   *    fname : Char ptr to the filename to parse.
+  *    max   : integer for the highest number to accept
   *
   * Returns:
   *    >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
@@ -399,21 +437,23 @@ int cs;
   *    None.
   *---------------------------------------------------------------------------*/
 
-int GetVFileNumber(fname)
+static int doGetXFileNumber(fname, filechar, maxNum)
     char *fname;
+    char filechar;
+    int maxNum;
 {
     int        computedVNumber;    /*The computed file number we return*/
     int        filenameLen;        /*Number of chars in filename*/
     int        currDigit;          /*Current digit being processed*/
 
     /*
-     * The filename must have at least two characters, the first of which must be a ``V''
+     * The filename must have at least two characters, the first of which must be a ``filechar''
      * and the second of which cannot be a zero unless the file is exactly two chars long.
      */
     filenameLen = strlen(fname);
     if (filenameLen < 2)
        return(-1);
-    if (fname[0] != 'V')
+    if (fname[0] != filechar)
        return(-1);
     if ((filenameLen > 2) && (fname[1] == '0'))
        return(-1);
@@ -437,6 +477,21 @@ int GetVFileNumber(fname)
        return(-1);
 }
 
+int GetVFileNumber(fname, maxFile)
+    char *fname;
+    int maxFile;
+{
+    return doGetXFileNumber(fname, 'V', maxFile);
+}
+
+int GetDDirNumber(fname, maxDir)
+    char *fname;
+    int maxDir;
+{
+    return doGetXFileNumber(fname, 'D', maxDir);
+}
+
+
 /*-----------------------------------------------------------------------------
   * CreateCacheFile
   *
@@ -446,6 +501,8 @@ int GetVFileNumber(fname)
   *
   * Arguments:
   *    fname : Full pathname of file to create.
+  *    statp : A pointer to a stat buffer which, if NON-NULL, will be
+  *            filled by fstat()
   *
   * Returns:
   *    0   iff the file was created,
@@ -458,8 +515,81 @@ int GetVFileNumber(fname)
   *    As described.
   *---------------------------------------------------------------------------*/
 
-int CreateCacheFile(fname)
+static int CreateCacheSubDir (basename, dirNum)
+     char *basename;
+     int dirNum;
+{
+    static char rn[] = "CreateCacheSubDir"; /* Routine Name */
+    char dir[1024];
+    int ret;
+
+    /* Build the new cache subdirectory */
+    sprintf (dir, "%s/D%d", basename, dirNum);
+
+    if (afsd_verbose)
+       printf("%s: Creating cache subdir '%s'\n",
+              rn, dir);
+
+    if ((ret = mkdir(dir, 0700)) != 0) {
+        printf("%s: Can't create '%s', error return is %d (%d)\n",
+              rn, dir, ret, errno);
+        if (errno != EEXIST)
+           return (-1);
+    }
+
+    /* Mark this directory as created */
+    cache_dir_list[dirNum] = 0;
+
+    /* And return success */
+    return (0);
+}
+
+static int MoveCacheFile (basename, fromDir, toDir, cacheFile, maxDir)
+     char *basename;
+     int fromDir, toDir, cacheFile, maxDir;
+{
+  static char rn[] = "MoveCacheFile";
+  char from[1024], to[1024];
+  int ret;
+
+  if (cache_dir_list[toDir] < 0 &&
+      (ret = CreateCacheSubDir(basename, toDir))) {
+    printf("%s: Can't create directory '%s/D%d'\n", rn, basename, toDir);
+    return ret;
+  }
+
+  /* Build the from,to dir */
+  if (fromDir < 0) {
+    /* old-style location */
+    snprintf (from, sizeof(from), "%s/V%d", basename, cacheFile);
+  } else {
+    snprintf (from, sizeof(from), "%s/D%d/V%d", basename, fromDir, cacheFile);
+  }
+
+  snprintf (to, sizeof(from), "%s/D%d/V%d", basename, toDir, cacheFile);
+
+  if (afsd_verbose)
+    printf("%s: Moving cacheFile from '%s' to '%s'\n",
+          rn, from, to);
+  
+  if ((ret = rename (from, to)) != 0) {
+    printf("%s: Can't rename '%s' to '%s', error return is %d (%d)\n",
+          rn, from, to, ret, errno);
+    return -1;
+  }
+
+  /* Reset directory pointer; fix file counts */
+  dir_for_V[cacheFile] = toDir;
+  cache_dir_list[toDir]++;
+  if (fromDir < maxDir && fromDir >= 0)
+    cache_dir_list[fromDir]--;
+  
+  return 0;
+}
+
+int CreateCacheFile(fname, statp)
     char *fname;
+    struct stat *statp;
 {
     static char        rn[] = "CreateCacheFile";   /*Routine name*/
     int        cfd;                                /*File descriptor to AFS cache file*/
@@ -474,6 +604,14 @@ int CreateCacheFile(fname)
               rn, fname, cfd, errno);
        return(-1);
     }
+    if (statp != NULL) {
+        closeResult = fstat (cfd, statp);
+       if (closeResult) {
+           printf("%s: Can't stat newly-created AFS cache file '%s' (code %d)\n",
+                  rn, fname, errno);
+           return(-1);
+       }
+    }
     closeResult = close(cfd);
     if (closeResult) {
        printf("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
@@ -489,7 +627,7 @@ int CreateCacheFile(fname)
   *
   * Description:
   *    Sweep through the AFS cache directory, recording the inode number for
-  *    each valid data cache file there.  Also, delete any file that doesn't beint32
+  *    each valid data cache file there.  Also, delete any file that doesn't belong
   *    in the cache directory during this sweep, and remember which of the other
   *    residents of this directory were seen.  After the sweep, we create any data
   *    cache files that were missing.
@@ -512,10 +650,14 @@ int CreateCacheFile(fname)
   *    explained above.
   *---------------------------------------------------------------------------*/
 
-int SweepAFSCache(vFilesFound)
-    int *vFilesFound;
+
+static int doSweepAFSCache(vFilesFound,directory,dirNum,maxDir)
+     int *vFilesFound;
+     char *directory;          /* /path/to/cache/directory */
+     int dirNum;               /* current directory number */
+     int maxDir;               /* maximum directory number */
 {
-    static char        rn[] = "SweepAFSCache"; /*Routine name*/
+    static char rn[] = "doSweepAFSCache"; /* Routine Name */
     char fullpn_FileToDelete[1024];    /*File to be deleted from cache*/
     char *fileToDelete;                        /*Ptr to last component of above*/
     DIR        *cdirp;                         /*Ptr to cache directory structure*/
@@ -525,36 +667,30 @@ int SweepAFSCache(vFilesFound)
     struct dirent *currp;              /*Current directory entry*/
 #endif
     int        vFileNum;                       /*Data cache file's associated number*/
-
-    if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
-       if (afsd_debug)
-           printf("%s: Memory Cache, no cache sweep done\n", rn);
-       *vFilesFound = 0;
-       return 0;
-    }
+    int thisDir;                       /* A directory number */
+    int highDir = 0;
 
     if (afsd_debug)
-       printf("%s: Opening cache directory '%s'\n",
-              rn, cacheBaseDir);
+       printf("%s: Opening cache directory '%s'\n", rn, directory);
 
-    if (chmod(cacheBaseDir, 0700)) {           /* force it to be 700 */
-       printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n",
-              rn, cacheBaseDir);
+    if (chmod(directory, 0700)) {              /* force it to be 700 */
+       printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n", rn, directory);
        return (-1);
     }
-    cdirp = opendir(cacheBaseDir);
+    cdirp = opendir(directory);
     if (cdirp == (DIR *)0) {
-       printf("%s: Can't open AFS cache directory, '%s'.\n",
-              rn, cacheBaseDir);
+       printf("%s: Can't open AFS cache directory, '%s'.\n", rn, directory);
        return(-1);
     }
 
     /*
-     * Scan the directory entries, remembering data cache file inodes and the existance
-     * of other important residents.  Delete all files that don't belong here.
+     * Scan the directory entries, remembering data cache file inodes
+     * and the existance of other important residents.  Recurse into
+     * the data subdirectories.
+     *
+     * Delete all files and directories that don't belong here.
      */
-    *vFilesFound = 0;
-    sprintf(fullpn_FileToDelete, "%s/", cacheBaseDir);
+    sprintf(fullpn_FileToDelete, "%s/", directory);
     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
 
 #ifdef AFS_SGI62_ENV
@@ -576,24 +712,87 @@ int SweepAFSCache(vFilesFound)
        }
 
        /*
-        * Guess current entry is for a data cache file.
+        * If dirNum < 0, we are a top-level cache directory and should
+        * only contain sub-directories and other sundry files.  Therefore,
+        * V-files are valid only if dirNum >= 0, and Directories are only
+        * valid if dirNum < 0.
         */
-       vFileNum = GetVFileNumber(currp->d_name);
-       if (vFileNum >= 0) {
+
+       if (*(currp->d_name) == 'V' &&
+           ((vFileNum = GetVFileNumber(currp->d_name, cacheFiles)) >= 0)) {
            /*
-            * Found a valid data cache filename.  Remember this file's inode and bump
-            * the number of files found.
+            * Found a valid data cache filename.  Remember this
+            * file's inode, directory, and bump the number of files found
+            * total and in this directory.
             */
            inode_for_V[vFileNum] = currp->d_ino;
+           dir_for_V[vFileNum] = dirNum; /* remember this directory */
+
+           if (!maxDir) {
+             /* If we're in a real subdir, mark this file to be moved
+              * if we've already got too many files in this directory
+              */
+             assert(dirNum >= 0);
+             cache_dir_list[dirNum]++; /* keep directory's file count */
+             if (cache_dir_list[dirNum] > nFilesPerDir) {
+               /* Too many files -- add to filelist */
+               struct afsd_file_list *tmp = (struct afsd_file_list *)
+                 malloc(sizeof(*tmp));
+               if (!tmp)
+                 printf ("%s: MALLOC FAILED allocating file_list entry\n",
+                         rn);
+               else {
+                 tmp->fileNum = vFileNum;
+                 tmp->next = cache_dir_filelist[dirNum];
+                 cache_dir_filelist[dirNum] = tmp;
+               }
+             }
+           }
            (*vFilesFound)++;
        }
-       else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
+       else if (dirNum < 0 && (*(currp->d_name) == 'D') &&
+                GetDDirNumber(currp->d_name, 1<<30) >= 0) {
+         int retval = 0;
+         if ((vFileNum = GetDDirNumber(currp->d_name, maxDir)) >= 0) {
+           /* Found a valid cachefile sub-Directory.  Remember this number
+            * and recurse into it.  Note that subdirs cannot have subdirs.
+            */
+           retval = 1;
+         } else if ((vFileNum = GetDDirNumber(currp->d_name,  1<<30)) >= 0) {
+           /* This directory is going away, but figure out if there
+            * are any cachefiles in here that should be saved by
+            * moving them to other cache directories.  This directory
+            * will be removed later.
+            */
+           retval = 2;
+         }
+
+         /* Save the highest directory number we've seen */
+         if (vFileNum > highDir)
+           highDir = vFileNum;
+
+         /* If this directory is staying, be sure to mark it as 'found' */
+         if (retval == 1) cache_dir_list[vFileNum] = 0;
+
+         /* Print the dirname for recursion */
+         sprintf(fileToDelete, "%s", currp->d_name);
+
+         /* Note: vFileNum is the directory number */
+         retval = doSweepAFSCache(vFilesFound, fullpn_FileToDelete,
+                                  vFileNum, (retval == 1 ? 0 : -1));
+         if (retval) {
+           printf ("%s: Recursive sweep failed on directory %s\n",
+                   rn, currp->d_name);
+           return retval;
+         }
+       }
+       else if (dirNum < 0 && strcmp(currp->d_name, DCACHEFILE) == 0) {
            /*
             * Found the file holding the dcache entries.
             */
            missing_DCacheFile = 0;
        }
-       else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
+       else if (dirNum < 0 && strcmp(currp->d_name, VOLINFOFILE) == 0) {
            /*
             * Found the file holding the volume info.
             */
@@ -601,6 +800,12 @@ int SweepAFSCache(vFilesFound)
        }
        else  if ((strcmp(currp->d_name,          ".") == 0) ||
                  (strcmp(currp->d_name,         "..") == 0) ||
+#ifdef AFS_DECOSF_ENV
+                 /* these are magic AdvFS files */
+                 (strcmp(currp->d_name,         ".tags") == 0) ||
+                 (strcmp(currp->d_name,         "quota.user") == 0) ||
+                 (strcmp(currp->d_name,         "quota.group") == 0) ||
+#endif
                  (strcmp(currp->d_name, "lost+found") == 0)) {
            /*
             * Don't do anything - this file is legit, and is to be left alone.
@@ -608,55 +813,149 @@ int SweepAFSCache(vFilesFound)
        }
        else {
            /*
-            * This file doesn't belong in the cache.  Nuke it.
+            * This file/directory doesn't belong in the cache.  Nuke it.
             */
            sprintf(fileToDelete, "%s", currp->d_name);
            if (afsd_verbose)
                printf("%s: Deleting '%s'\n",
                       rn, fullpn_FileToDelete);
            if (unlink(fullpn_FileToDelete)) {
-               printf("%s: Can't unlink '%s', errno is %d\n",
-                      rn, fullpn_FileToDelete, errno);
+               if (errno == EISDIR && *fileToDelete == 'D') {
+                   if (rmdir(fullpn_FileToDelete)) {
+                       printf("%s: Can't rmdir '%s', errno is %d\n",
+                              rn, fullpn_FileToDelete, errno);
+                   }
+               } else
+                   printf("%s: Can't unlink '%s', errno is %d\n",
+                          rn, fullpn_FileToDelete, errno);
            }
        }
     }
 
-    /*
-     * Create all the cache files that are missing.
-     */
-    if (missing_DCacheFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n",
-                  rn, fullpn_DCacheFile);
-       if (CreateCacheFile(fullpn_DCacheFile))
-           printf("%s: Can't create '%s'\n",
-                  rn, fullpn_DCacheFile);
-    }
-    if (missing_VolInfoFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n",
-                  rn, fullpn_VolInfoFile);
-       if (CreateCacheFile(fullpn_VolInfoFile))
-           printf("%s: Can't create '%s'\n",
-                  rn, fullpn_VolInfoFile);
-    }
+    if (dirNum < 0) {
 
-    if (*vFilesFound < cacheFiles) {
-       /*
-        * We came up short on the number of data cache files found.  Scan through the inode
-        * list and create all missing files.
+        /*
+        * Create all the cache files that are missing.
+        */
+        if (missing_DCacheFile) {
+           if (afsd_verbose)
+               printf("%s: Creating '%s'\n",
+                      rn, fullpn_DCacheFile);
+           if (CreateCacheFile(fullpn_DCacheFile, NULL))
+               printf("%s: Can't create '%s'\n",
+                      rn, fullpn_DCacheFile);
+       }
+       if (missing_VolInfoFile) {
+           if (afsd_verbose)
+               printf("%s: Creating '%s'\n",
+                      rn, fullpn_VolInfoFile);
+           if (CreateCacheFile(fullpn_VolInfoFile, NULL))
+               printf("%s: Can't create '%s'\n",
+                      rn, fullpn_VolInfoFile);
+       }
+
+       /* ADJUST CACHE FILES */
+
+       /* First, let's walk through the list of files and figure out
+        * if there are any leftover files in extra directories or
+        * missing files.  Move the former and create the latter in
+        * subdirs with extra space.
+        */
+
+       thisDir = 0;            /* Keep track of which subdir has space */
+
+       for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++) {
+         if (dir_for_V[vFileNum] == -1) {
+           /* This file does not exist.  Create it in the first
+            * subdir that still has extra space.
+            */
+           while (thisDir < maxDir &&
+                  cache_dir_list[thisDir] >= nFilesPerDir)
+             thisDir++;
+           if (thisDir >= maxDir)
+             printf("%s: can't find directory to create V%d\n", rn, vFileNum);
+           else {
+             struct stat statb;
+             assert (inode_for_V[vFileNum] == (AFSD_INO_T)0);
+             sprintf(vFilePtr, "D%d/V%d", thisDir, vFileNum);
+             if (afsd_verbose)
+               printf("%s: Creating '%s'\n", rn, fullpn_VFile);
+             if (cache_dir_list[thisDir] < 0 &&
+                 CreateCacheSubDir(directory, thisDir))
+               printf("%s: Can't create directory for '%s'\n",
+                      rn, fullpn_VFile);
+             if (CreateCacheFile(fullpn_VFile, &statb))
+               printf("%s: Can't create '%s'\n", rn, fullpn_VFile);
+             else {
+               inode_for_V[vFileNum] = statb.st_ino;
+               dir_for_V[vFileNum] = thisDir;
+               cache_dir_list[thisDir]++;
+               (*vFilesFound)++;
+             }
+           }
+
+         } else if (dir_for_V[vFileNum] >= maxDir ||
+                    dir_for_V[vFileNum] == -2) {
+           /* This file needs to move; move it to the first subdir
+            * that has extra space.  (-2 means it's in the toplevel)
+            */
+           while (thisDir < maxDir && cache_dir_list[thisDir] >= nFilesPerDir)
+             thisDir++;
+           if (thisDir >= maxDir)
+             printf("%s: can't find directory to move V%d\n", rn, vFileNum);
+           else {
+             if (MoveCacheFile (directory, dir_for_V[vFileNum], thisDir,
+                                vFileNum, maxDir)) {
+               /* Cannot move.  Ignore this file??? */
+               /* XXX */
+             }
+           }
+         }
+       } /* for */
+
+       /* At this point, we've moved all of the valid cache files
+        * into the valid subdirs, and created all the extra
+        * cachefiles we need to create.  Next, rebalance any subdirs
+        * with too many cache files into the directories with not
+        * enough cache files.  Note that thisDir currently sits at
+        * the lowest subdir that _may_ have room.
         */
-       for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
-           if (inode_for_V[vFileNum] == (AFSD_INO_T)0) {
-               sprintf(vFileNumber, "%d", vFileNum);
-               if (afsd_verbose)
-                   printf("%s: Creating '%s'\n",
-                          rn, fullpn_VFile);
-               if (CreateCacheFile(fullpn_VFile))
-                   printf("%s: Can't create '%s'\n",
-                          rn, fullpn_VFile);
+
+       for (dirNum = 0; dirNum < maxDir; dirNum++) {
+         struct afsd_file_list *thisFile;
+
+         for (thisFile = cache_dir_filelist[dirNum];
+              thisFile && cache_dir_list[dirNum] >= nFilesPerDir;
+              thisFile = thisFile->next) {
+           while (thisDir < maxDir && cache_dir_list[thisDir] >= nFilesPerDir)
+             thisDir++;
+           if (thisDir >= maxDir)
+             printf("%s: can't find directory to move V%d\n", rn, vFileNum);
+           else {
+             if (MoveCacheFile (directory, dirNum, thisDir,
+                                thisFile->fileNum, maxDir)) {
+               /* Cannot move.  Ignore this file??? */
+               /* XXX */
+             }
            }
-    }
+         } /* for each file to move */
+       } /* for each directory */
+
+       /* Remove any directories >= maxDir -- they should be empty */
+       for (; highDir >= maxDir; highDir--) {
+         sprintf(fileToDelete, "D%d", highDir);
+         if (unlink(fullpn_FileToDelete)) {
+           if (errno == EISDIR && *fileToDelete == 'D') {
+             if (rmdir(fullpn_FileToDelete)) {
+               printf("%s: Can't rmdir '%s', errno is %d\n",
+                      rn, fullpn_FileToDelete, errno);
+             }
+           } else
+             printf("%s: Can't unlink '%s', errno is %d\n",
+                    rn, fullpn_FileToDelete, errno);
+         }
+       }
+    } /* dirNum < 0 */
     
     /*
      * Close the directory, return success.
@@ -668,6 +967,61 @@ int SweepAFSCache(vFilesFound)
     return(0);
 }
 
+int SweepAFSCache(vFilesFound)
+    int *vFilesFound;
+{
+    static char        rn[] = "SweepAFSCache"; /*Routine name*/
+    int maxDir = (cacheFiles + nFilesPerDir - 1 ) / nFilesPerDir;
+    int i;
+
+    *vFilesFound = 0;
+
+    if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
+       if (afsd_debug)
+           printf("%s: Memory Cache, no cache sweep done\n", rn);
+       return 0;
+    }
+
+    if (cache_dir_list == NULL) {
+        cache_dir_list = (int *) malloc (maxDir * sizeof(*cache_dir_list));
+       if (cache_dir_list == NULL) {
+           printf("%s: Malloc Failed!\n", rn);
+           return (-1);
+       }
+       for (i=0; i < maxDir; i++)
+         cache_dir_list[i] = -1; /* Does not exist */
+    }
+
+    if (cache_dir_filelist == NULL) {
+        cache_dir_filelist = (struct afsd_file_list **)
+         malloc (maxDir * sizeof(*cache_dir_filelist));
+       if (cache_dir_filelist == NULL) {
+           printf("%s: Malloc Failed!\n", rn);
+           return (-1);
+       }
+       memset (cache_dir_filelist, 0, maxDir * sizeof(*cache_dir_filelist));
+    }
+
+    if (dir_for_V == NULL) {
+        dir_for_V = (int *) malloc (cacheFiles * sizeof(*dir_for_V));
+       if (dir_for_V == NULL) {
+           printf("%s: Malloc Failed!\n", rn);
+           return (-1);
+       }
+       for (i=0; i < cacheFiles; i++)
+         dir_for_V[i] = -1;    /* Does not exist */
+    }
+
+    /* Note, setting dirNum to -2 here will cause cachefiles found in
+     * the toplevel directory to be marked in directory "-2".  This
+     * allows us to differentiate between 'file not seen' (-1) and
+     * 'file seen in top-level' (-2).  Then when we try to move the
+     * file into a subdirectory, we know it's in the top-level instead
+     * of some other cache subdir.
+     */
+    return doSweepAFSCache (vFilesFound, cacheBaseDir, -2, maxDir);
+}
+
 static ConfigCell(aci, arock, adir)
 register struct afsconf_cell *aci;
 char *arock;
@@ -703,6 +1057,46 @@ struct afsconf_dir *adir; {
     return 0;
 }
 
+#ifdef AFS_AFSDB_ENV
+static AfsdbLookupHandler()
+{
+    afs_int32 kernelMsg[64];
+    char acellName[128];
+    afs_int32 code;
+    struct afsconf_cell acellInfo;
+    int i;
+
+    while (1) {
+       /* On some platforms you only get 4 args to an AFS call */
+       int sizeArg = ((sizeof acellName) << 16) | (sizeof kernelMsg);
+       code = call_syscall(AFSOP_AFSDB_HANDLER, acellName, kernelMsg, sizeArg);
+       if (code) {             /* Something is wrong? */
+           sleep(1);
+           continue;
+       }
+
+       if (*acellName == 1)    /* Shutting down */
+           break;
+
+       code = afsconf_GetAfsdbInfo(acellName, 0, &acellInfo);
+       if (code) {
+           kernelMsg[0] = 0;
+           kernelMsg[1] = 0;
+       } else {
+           kernelMsg[0] = acellInfo.numServers;
+           if (acellInfo.timeout)
+               kernelMsg[1] = acellInfo.timeout - time(0);
+           else
+               kernelMsg[1] = 0;
+           for (i=0; i<acellInfo.numServers; i++)
+               kernelMsg[i+2] = acellInfo.hostAddr[i].sin_addr.s_addr;
+       }    
+    }
+
+    exit(1);
+}
+#endif
+
 #ifdef mac2
 #include <sys/ioctl.h>
 #endif /* mac2 */
@@ -890,6 +1284,23 @@ mainproc(as, arock)
        /* -mem_alloc_sleep */
        cacheFlags |= AFSCALL_INIT_MEMCACHE_SLEEP;
     }
+    if (as->parms[24].items) {
+       /* -afsdb */
+#ifdef AFS_AFSDB_ENV
+       enable_afsdb = 1;
+#else
+       printf("afsd: No AFSDB support; ignoring -afsdb");
+#endif
+    }
+    if (as->parms[25].items) {
+        /* -files_per_subdir */
+        int res = atoi(as->parms[25].items->data);
+       if ( res < 10 || res > 2^30) {
+           printf("afsd:invalid number of files per subdir, \"%s\". Ignored\n", as->parms[25].items->data);
+       } else {
+           nFilesPerDir = res;
+       }
+    }
 
     /*
      * Pull out all the configuration info for the workstation's AFS cache and
@@ -919,7 +1330,7 @@ mainproc(as, arock)
 
     if ((logfd = fopen(fullpn_AFSLogFile,"r+")) == 0) {
        if (afsd_verbose)  printf("%s: Creating '%s'\n",  rn, fullpn_AFSLogFile);
-       if (CreateCacheFile(fullpn_AFSLogFile)) {
+       if (CreateCacheFile(fullpn_AFSLogFile, NULL)) {
            printf("%s: Can't create '%s' (You may want to use the -logfile option)\n",  rn, fullpn_AFSLogFile);
            exit(1);
        }
@@ -1023,11 +1434,13 @@ mainproc(as, arock)
      */
     sprintf(fullpn_DCacheFile,  "%s/%s", cacheBaseDir, DCACHEFILE);
     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
-    sprintf(fullpn_VFile,       "%s/V",  cacheBaseDir);
-    vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
+    sprintf(fullpn_VFile,       "%s/",  cacheBaseDir);
+    vFilePtr = fullpn_VFile + strlen(fullpn_VFile);
 
+#if 0
     fputs(AFS_GOVERNMENT_MESSAGE, stdout); 
     fflush(stdout);
+#endif
 
     /*
      * Set up all the kernel processes needed for AFS.
@@ -1107,6 +1520,18 @@ mainproc(as, arock)
     }
 #endif
 
+#ifdef AFS_AFSDB_ENV
+    if (enable_afsdb) {
+       if (afsd_verbose)
+           printf("%s: Forking AFSDB lookup handler.\n", rn);
+       code = fork();
+       if (code == 0) {
+           AfsdbLookupHandler();
+           exit(1);
+       }
+    }
+#endif
+
     /* Initialize AFS daemon threads. */
     if (afsd_verbose)
        printf("%s: Forking AFS daemon.\n", rn);
@@ -1179,8 +1604,8 @@ mainproc(as, arock)
     }
 
     /*
-         * If the root volume has been explicitly set, tell the kernel.
-         */
+     * If the root volume has been explicitly set, tell the kernel.
+     */
     if (rootVolSet) {
        if (afsd_verbose)
            printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n",
@@ -1335,6 +1760,9 @@ mainproc(as, arock)
 #ifdef AFS_DEC_ENV
     if ((mount("AFS",cacheMountDir,mountFlags,GT_AFS,(caddr_t) 0)) < 0) {
 #else
+#ifdef AFS_FBSD_ENV
+    if ((mount("AFS",cacheMountDir,mountFlags,(caddr_t) 0)) < 0) {
+#else
 #ifdef AFS_AUX_ENV
     if ((fsmount(MOUNT_AFS,cacheMountDir,mountFlags,(caddr_t) 0)) < 0) {
 #else
@@ -1372,7 +1800,6 @@ mainproc(as, arock)
 #else
 #if defined(AFS_SGI_ENV)
     mountFlags = MS_FSS;
-
     if ((mount(MOUNT_AFS,cacheMountDir,mountFlags,(caddr_t) MOUNT_AFS)) < 0) {
 #else
 #ifdef AFS_LINUX20_ENV
@@ -1387,6 +1814,7 @@ mainproc(as, arock)
 #endif /* AFS_HPUX_ENV */
 #endif /* AFS_AIX_ENV */
 #endif /* AFS_AUX_ENV */
+#endif /* AFS_FBSD_ENV */
 #endif /* AFS_DEC_ENV */
          printf("%s: Can't mount AFS on %s(%d)\n",
                   rn, cacheMountDir, errno);
@@ -1449,6 +1877,12 @@ char **argv; {
     cmd_AddParm(ts, "-enable_peer_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics by peer");
     cmd_AddParm(ts, "-enable_process_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics for this process");
     cmd_AddParm(ts, "-mem_alloc_sleep", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE), "Allow sleeps when allocating memory cache");
+    cmd_AddParm(ts, "-afsdb", CMD_FLAG, (CMD_OPTIONAL
+#ifndef AFS_AFSDB_ENV
+               | CMD_HIDE
+#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");
     return (cmd_Dispatch(argc, argv));
 }
 
@@ -1530,6 +1964,16 @@ call_syscall(param1, param2, param3, param4, param5, param6, param7)
 long param1, param2, param3, param4, param5, param6, param7;
 {
     int error;
+#ifdef AFS_LINUX20_ENV
+    long eparm[4];
+
+    eparm[0] = param4;
+    eparm[1] = param5;
+    eparm[2] = param6;
+    eparm[3] = param7;
+
+    param4 = eparm;
+#endif
 
     error = syscall(AFS_SYSCALL, AFSCALL_CALL, param1, param2, param3, param4, param5, param6, param7);
     if (afsd_verbose) printf("SScall(%d, %d)=%d ", AFS_SYSCALL, AFSCALL_CALL, error);