afs: Return to userspace after AFS_NEW_BKG reqs
[openafs.git] / src / afsd / afsd.c
index abe36c4..4df6f7b 100644 (file)
   *    -blocks     The number of blocks available in the workstation cache.
   *    -files      The target number of files in the workstation cache (Default:
   *                1000).
-  *    -rootvol            The name of the root volume to use.
+  *    -rootvol    The name of the root volume to use.
   *    -stat       The number of stat cache entries.
-  *    -hosts      List of servers to check for volume location info FOR THE
+  *    -hosts      [OBSOLETE] List of servers to check for volume location info FOR THE
   *                HOME CELL.
   *     -memcache   Use an in-memory cache rather than disk.
-  *    -cachedir    The base directory for the workstation cache.
+  *    -cachedir   The base directory for the workstation cache.
   *    -mountdir   The directory on which the AFS is to be mounted.
-  *    -confdir    The configuration directory .
+  *    -confdir    The configuration directory.
   *    -nosettime  Don't keep checking the time to avoid drift (default).
-  *     -settime    Keep checking the time to avoid drift.
+  *     -settime    [IGNORED] Keep checking the time to avoid drift.
   *    -rxmaxmtu   Set the max mtu to help with VPN issues.
-  *    -verbose     Be chatty.
+  *    -verbose    Be chatty.
   *    -disable-dynamic-vcaches     Disable the use of -stat value as the starting size of
   *                          the size of the vcache/stat cache pool,
   *                          but increase that pool dynamically as needed.
   *                support daemon
   *     -chunksize [n]   2^n is the chunksize to be used.  0 is default.
   *     -dcache    The number of data cache entries.
+  *     -volumes    The number of volume entries.
   *     -biods     Number of bkg I/O daemons (AIX3.1 only)
   *    -prealloc  Number of preallocated "small" memory blocks
-  *    -logfile   [OBSOLETE] Place where to put the logfile (default in
+  *    -logfile    [IGNORED] 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
+  *    -enable_peer_stats      Collect RPC statistics by peer.
+  *    -enable_process_stats   Collect RPC statistics for this process.
+  *    -mem_alloc_sleep [IGNORED] Sleep when allocating memory.
+  *    -afsdb      Enable AFSDB support.
+  *    -dynroot        Enable dynroot support.
+  *    -dynroot-sparse Enable dynroot support with minimal cell list.
+  *    -fakestat       Enable fake stat() for cross-cell mounts.
+  *    -fakestat-all   Enable fake stat() for all mounts.
+  *    -nomount    Do not mount /afs.
+  *    -backuptree Prefer backup volumes for mountpoints in backup volumes.
+  *    -rxbind     Bind the rx socket.
+  *    -rxpck      Value for rx_extraPackets.
+  *    -splitcache RW/RO ratio for cache.
+  *    -rxmaxfrags Max number of UDP fragments per rx packet.
+  *    -inumcalc  inode number calculation method; 0=compat, 1=MD5 digest
+  *    -volume-ttl vldb cache timeout in seconds
   *---------------------------------------------------------------------------*/
 
 #include <afsconfig.h>
@@ -79,6 +96,7 @@
 
 #include <sys/file.h>
 #include <sys/wait.h>
+#include <hcrypto/rand.h>
 
 /* darwin dirent.h doesn't give us the prototypes we want if KERNEL is
  * defined */
@@ -260,12 +278,14 @@ static int enable_fakestat = 0;   /* enable fakestat support */
 static int enable_backuptree = 0;      /* enable backup tree support */
 static int enable_nomount = 0; /* do not mount */
 static int enable_splitcache = 0;
+static char *inumcalc = NULL;        /* inode number calculation method */
 static int afsd_dynamic_vcaches = 0;   /* Enable dynamic-vcache support */
 int afsd_verbose = 0;          /*Are we being chatty? */
 int afsd_debug = 0;            /*Are we printing debugging info? */
 static int afsd_CloseSynch = 0;        /*Are closes synchronous or not? */
 static int rxmaxmtu = 0;       /* Are we forcing a limit on the mtu? */
 static int rxmaxfrags = 0;      /* Are we forcing a limit on frags? */
+static int volume_ttl = 0;      /* enable vldb cache timeout support */
 
 #ifdef AFS_SGI62_ENV
 #define AFSD_INO_T ino64_t
@@ -343,6 +363,8 @@ enum optionsList {
     OPT_rxmaxmtu,
     OPT_dynrootsparse,
     OPT_rxmaxfrags,
+    OPT_inumcalc,
+    OPT_volume_ttl,
 };
 
 #ifdef MACOS_EVENT_HANDLING
@@ -474,11 +496,6 @@ afsd_install_events(void)
                   (NULL, kSCDynamicStoreDomainState,
                    kSCCompAnyRegex, kSCEntNetIPv4));
 
-#if 0
-       /* This should tell us when the hostname(s) change. do we care? */
-       keys[N] = SCDynamicStoreKeyCreateHostNames (NULL);
-#endif
-
        if (keys[0] != NULL) {
            CFArrayRef pattern_array;
 
@@ -1111,12 +1128,6 @@ doSweepAFSCache(int *vFilesFound,
            SetNoBackupAttr(fullpn_CellInfoFile);
        } 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
 #ifdef AFS_LINUX22_ENV
                   /* this is the ext3 journal file */
                   (strcmp(currp->d_name, ".journal") == 0) ||
@@ -1527,18 +1538,20 @@ BkgHandler(void)
     uspc->ts = -1;
 
     while (1) {
-       pid_t child = 0;
-       int status;
-       char srcpath[BUFSIZ];
-       char dstpath[BUFSIZ];
-
        /* pushing in a buffer this large */
        uspc->bufSz = 256;
 
        code = afsd_syscall(AFSOP_BKG_HANDLER, uspc, srcName, dstName);
        if (code) {             /* Something is wrong? */
-           if (code == -2) /* shutting down */
-               break;
+           if (code == -2) {
+               /*
+                * Before AFS_USPC_SHUTDOWN existed, the kernel module used to
+                * indicate it was shutting down by returning -2. Treat this
+                * like a AFS_USPC_SHUTDOWN, in case we're running with an
+                * older kernel module.
+                */
+               return;
+           }
 
            sleep(1);
            uspc->retval = -1;
@@ -1546,72 +1559,90 @@ BkgHandler(void)
        }
 
        switch (uspc->reqtype) {
-       case AFS_USPC_UMV:
-           snprintf(srcpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s",
-                    uspc->req.umv.sCell, uspc->req.umv.sVolume,
-                    uspc->req.umv.sVnode, uspc->req.umv.sUnique, srcName);
-           snprintf(dstpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s",
-                    uspc->req.umv.dCell, uspc->req.umv.dVolume,
-                    uspc->req.umv.dVnode, uspc->req.umv.dUnique, dstName);
-           if ((child = fork()) == 0) {
-               /* first child does cp; second, rm. mv would re-enter. */
-
-               switch (uspc->req.umv.idtype) {
-               case IDTYPE_UID:
-                   if (setuid(uspc->req.umv.id) != 0) {
-                       exit(-1);
-                   }
-                   break;
-               default:
-                   exit(-1);
-                   break; /* notreached */
-               }
-               execl("/bin/cp", "(afsd EXDEV helper)", "-PRp", "--", srcpath,
-                     dstpath, (char *) NULL);
-           }
-           if (child == (pid_t) -1) {
-               uspc->retval = -1;
-               continue;
-           }
+       case AFS_USPC_SHUTDOWN:
+           /* Client is shutting down */
+           return;
 
-           if (waitpid(child, &status, 0) == -1)
-               uspc->retval = EIO;
-           else if (WIFEXITED(status) != 0 && WEXITSTATUS(status) == 0) {
-               if ((child = fork()) == 0) {
-                   switch (uspc->req.umv.idtype) {
-                   case IDTYPE_UID:
-                       if (setuid(uspc->req.umv.id) != 0) {
-                           exit(-1);
-                       }
-                       break;
-                   default:
-                       exit(-1);
-                       break; /* notreached */
-                   }
-                   execl("/bin/rm", "(afsd EXDEV helper)", "-rf", "--",
-                         srcpath, (char *) NULL);
-               }
-               if (child == (pid_t) -1) {
-                   uspc->retval = -1;
-                   continue;
-               }
-               if (waitpid(child, &status, 0) == -1)
-                   uspc->retval = EIO;
-               else if (WIFEXITED(status) != 0) {
-                   /* rm exit status */
-                   uspc->retval = WEXITSTATUS(status);
-               } else {
-                   /* rm signal status */
-                   uspc->retval = -(WTERMSIG(status));
-               }
-           } else {
-               /* error from cp: exit or signal status */
-               uspc->retval = (WIFEXITED(status) != 0) ?
-                   WEXITSTATUS(status) : -(WTERMSIG(status));
-           }
+       case AFS_USPC_NOOP:
+           /* noop */
+           memset(srcName, 0, sizeof(srcName));
+           memset(dstName, 0, sizeof(dstName));
+           break;
+
+# ifdef AFS_DARWIN_ENV
+       case AFS_USPC_UMV:
+            {
+                pid_t child = 0;
+                int status;
+                char srcpath[BUFSIZ];
+                char dstpath[BUFSIZ];
+                snprintf(srcpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s",
+                         uspc->req.umv.sCell, uspc->req.umv.sVolume,
+                         uspc->req.umv.sVnode, uspc->req.umv.sUnique, srcName);
+                snprintf(dstpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s",
+                         uspc->req.umv.dCell, uspc->req.umv.dVolume,
+                         uspc->req.umv.dVnode, uspc->req.umv.dUnique, dstName);
+                if ((child = fork()) == 0) {
+                    /* first child does cp; second, rm. mv would re-enter. */
+
+                    switch (uspc->req.umv.idtype) {
+                    case IDTYPE_UID:
+                        if (setuid(uspc->req.umv.id) != 0) {
+                            exit(-1);
+                        }
+                        break;
+                    default:
+                        exit(-1);
+                        break; /* notreached */
+                    }
+                    execl("/bin/cp", "(afsd EXDEV helper)", "-PRp", "--", srcpath,
+                          dstpath, (char *) NULL);
+                }
+                if (child == (pid_t) -1) {
+                    uspc->retval = -1;
+                    continue;
+                }
+
+                if (waitpid(child, &status, 0) == -1)
+                    uspc->retval = EIO;
+                else if (WIFEXITED(status) != 0 && WEXITSTATUS(status) == 0) {
+                    if ((child = fork()) == 0) {
+                        switch (uspc->req.umv.idtype) {
+                        case IDTYPE_UID:
+                            if (setuid(uspc->req.umv.id) != 0) {
+                                exit(-1);
+                            }
+                            break;
+                        default:
+                            exit(-1);
+                            break; /* notreached */
+                        }
+                        execl("/bin/rm", "(afsd EXDEV helper)", "-rf", "--",
+                              srcpath, (char *) NULL);
+                    }
+                    if (child == (pid_t) -1) {
+                        uspc->retval = -1;
+                        continue;
+                    }
+                    if (waitpid(child, &status, 0) == -1)
+                        uspc->retval = EIO;
+                    else if (WIFEXITED(status) != 0) {
+                        /* rm exit status */
+                        uspc->retval = WEXITSTATUS(status);
+                    } else {
+                        /* rm signal status */
+                        uspc->retval = -(WTERMSIG(status));
+                    }
+                } else {
+                    /* error from cp: exit or signal status */
+                    uspc->retval = (WIFEXITED(status) != 0) ?
+                        WEXITSTATUS(status) : -(WTERMSIG(status));
+                }
+            }
            memset(srcName, 0, sizeof(srcName));
            memset(dstName, 0, sizeof(dstName));
            break;
+# endif /* AFS_DARWIN_ENV */
 
        default:
            /* unknown req type */
@@ -1665,8 +1696,16 @@ rmtsysd_thread(void *rock)
 }
 #endif /* !UKERNEL */
 
-int
-mainproc(struct cmd_syndesc *as, void *arock)
+/**
+ * Check the command line and cacheinfo options.
+ *
+ * @param[in] as  parsed command line arguments
+ *
+ * @note Invokes the shutdown syscall and exits with 0 when
+ *       -shutdown is given.
+ */
+static int
+CheckOptions(struct cmd_syndesc *as)
 {
     afs_int32 code;            /*Result of fork() */
 #ifdef AFS_SUN5_ENV
@@ -1875,6 +1914,10 @@ mainproc(struct cmd_syndesc *as, void *arock)
     }
 
     cmd_OptionAsInt(as, OPT_rxmaxfrags, &rxmaxfrags);
+    if (cmd_OptionPresent(as, OPT_inumcalc)) {
+       cmd_OptionAsString(as, OPT_inumcalc, &inumcalc);
+    }
+    cmd_OptionAsInt(as, OPT_volume_ttl, &volume_ttl);
 
     /* parse cacheinfo file if this is a diskcache */
     if (ParseCacheInfoFile()) {
@@ -2035,20 +2078,6 @@ afsd_run(void)
            if (afsd_verbose)
                printf("%s: cacheFiles autotuned to %d\n", rn, cacheFiles);
        }
-#if 0
-       /* This actually needs to
-          1) use powers of 2
-          2) not second-guess when a chunksize comes from the command line
-          3) be less, um, small. 2^2??
-       */
-       /* Sanity check chunkSize */
-       i = max(cacheBlocks / 1000, cacheBlocks / cacheFiles);
-       chunkSize = min(chunkSize, i);
-       chunkSize = max(chunkSize, 2);
-       if (afsd_verbose)
-           printf("%s: chunkSize autotuned to %d\n", rn, chunkSize);
-#endif
-
        if (!sawDCacheSize) {
            dCacheSize = cacheFiles / 2;
            if (dCacheSize > 10000) {
@@ -2086,8 +2115,9 @@ afsd_run(void)
        exit(1);
     }
     if (afsd_debug)
-       printf("%s: %d inode_for_V entries at 0x%x, %lu bytes\n", rn,
-              cacheFiles, inode_for_V, (cacheFiles * sizeof(AFSD_INO_T)));
+       printf("%s: %d inode_for_V entries at %p, %lu bytes\n", rn,
+              cacheFiles, inode_for_V,
+              (unsigned long)cacheFiles * sizeof(AFSD_INO_T));
 #endif
 
     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
@@ -2127,6 +2157,13 @@ afsd_run(void)
 
     /* initialize the rx random number generator from user space */
     {
+       /* rand-fortuna wants at least 128 bytes of seed; be generous. */
+       unsigned char seedbuf[256];
+       if (RAND_bytes(seedbuf, sizeof(seedbuf)) != 1) {
+           printf("SEED_ENTROPY: Error retrieving seed entropy\n");
+       }
+       afsd_syscall(AFSOP_SEED_ENTROPY, seedbuf, sizeof(seedbuf));
+       memset(seedbuf, 0, sizeof(seedbuf));
        /* parse multihomed address files */
        afs_uint32 addrbuf[MAXIPADDRS], maskbuf[MAXIPADDRS],
            mtubuf[MAXIPADDRS];
@@ -2137,7 +2174,7 @@ afsd_run(void)
        if (code > 0) {
            if (enable_rxbind)
                code = code | 0x80000000;
-               afsd_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
+           afsd_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
        } else
            printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
                   reason);
@@ -2208,7 +2245,11 @@ afsd_run(void)
     cparams.setTimeFlag = 0;
     cparams.memCacheFlag = cacheFlags;
     cparams.dynamic_vcaches = afsd_dynamic_vcaches;
-    afsd_syscall(AFSOP_CACHEINIT, &cparams);
+    code = afsd_syscall(AFSOP_CACHEINIT, &cparams);
+    if (code) {
+       printf("%s: Error %d during cache init.\n", rn, code);
+        exit(1);
+    }
 
     /* do it before we init the cache inodes */
     if (enable_splitcache) {
@@ -2287,6 +2328,33 @@ afsd_run(void)
             printf("%s: Error seting rxmaxmtu\n", rn);
     }
 
+    if (inumcalc != NULL) {
+       if (strcmp(inumcalc, "compat") == 0) {
+           if (afsd_verbose) {
+               printf("%s: Setting original inode number calculation method in kernel.\n",
+                      rn);
+           }
+           code = afsd_syscall(AFSOP_SET_INUMCALC, AFS_INUMCALC_COMPAT);
+           if (code) {
+               printf("%s: Error setting inode calculation method: code=%d.\n",
+                      rn, code);
+           }
+       } else if (strcmp(inumcalc, "md5") == 0) {
+           if (afsd_verbose) {
+               printf("%s: Setting md5 digest inode number calculation in kernel.\n",
+                      rn);
+           }
+           code = afsd_syscall(AFSOP_SET_INUMCALC, AFS_INUMCALC_MD5);
+           if (code) {
+               printf("%s: Error setting inode calculation method: code=%d.\n",
+                      rn, code);
+           }
+       } else {
+           printf("%s: Unknown value for -inumcalc: %s."
+                  "Using default inode calculation method.\n", rn, inumcalc);
+       }
+    }
+
     if (enable_dynroot) {
        if (afsd_verbose)
            printf("%s: Enabling dynroot support in kernel%s.\n", rn,
@@ -2360,6 +2428,26 @@ afsd_run(void)
        afsd_syscall(AFSOP_ROOTVOLUME, rootVolume);
     }
 
+    if (volume_ttl != 0) {
+       if (afsd_verbose)
+           printf("%s: Calling AFSOP_SET_VOLUME_TTL with '%d'\n", rn, volume_ttl);
+       code = afsd_syscall(AFSOP_SET_VOLUME_TTL, volume_ttl);
+       if (code == EFAULT) {
+           if (volume_ttl < AFS_MIN_VOLUME_TTL)
+               printf("%s: Failed to set volume ttl to %d seconds; "
+                      "value is too low.\n", rn, volume_ttl);
+           else if (volume_ttl > AFS_MAX_VOLUME_TTL)
+               printf("%s: Failed to set volume ttl to %d seconds; "
+                      "value is too high.\n", rn, volume_ttl);
+           else
+               printf("%s: Failed to set volume ttl to %d seconds; "
+                      "value is out of range.\n", rn, volume_ttl);
+       } else if (code != 0) {
+           printf("%s: Failed to set volume ttl to %d seconds; "
+                  "code=%d.\n", rn, volume_ttl, code);
+       }
+    }
+
     /*
      * Pass the kernel the name of the workstation cache file holding the
      * volume information.
@@ -2422,7 +2510,7 @@ afsd_run(void)
     if (afsd_debug)
        printf("%s: Calling AFSOP_GO with cacheSetTime = %d\n", rn,
               0);
-       afsd_syscall(AFSOP_GO, 0);
+    afsd_syscall(AFSOP_GO, 0);
 
     /*
      * At this point, we have finished passing the kernel all the info
@@ -2454,14 +2542,16 @@ afsd_run(void)
     return 0;
 }
 
+#ifndef UKERNEL
 #include "AFS_component_version_number.c"
+#endif
 
 void
 afsd_init(void)
 {
     struct cmd_syndesc *ts;
 
-    ts = cmd_CreateSyntax(NULL, mainproc, NULL, "start AFS");
+    ts = cmd_CreateSyntax(NULL, NULL, NULL, 0, "start AFS");
 
     /* 0 - 10 */
     cmd_AddParmAtOffset(ts, OPT_blocks, "-blocks", CMD_SINGLE,
@@ -2531,7 +2621,7 @@ afsd_init(void)
                        CMD_OPTIONAL, "Do not mount AFS");
     cmd_AddParmAtOffset(ts, OPT_backuptree, "-backuptree", CMD_FLAG,
                        CMD_OPTIONAL,
-                       "Prefer backup volumes for mointpoints in backup "
+                       "Prefer backup volumes for mountpoints in backup "
                        "volumes");
     cmd_AddParmAtOffset(ts, OPT_rxbind, "-rxbind", CMD_FLAG,
                        CMD_OPTIONAL,
@@ -2555,12 +2645,31 @@ afsd_init(void)
                        CMD_OPTIONAL,
                        "Set the maximum number of UDP fragments Rx should "
                        "send/receive per Rx packet");
+    cmd_AddParmAtOffset(ts, OPT_inumcalc, "-inumcalc", CMD_SINGLE, CMD_OPTIONAL,
+                       "Set inode number calculation method");
+    cmd_AddParmAtOffset(ts, OPT_volume_ttl, "-volume-ttl", CMD_SINGLE,
+                       CMD_OPTIONAL,
+                       "Set the vldb cache timeout value in seconds.");
 }
 
+/**
+ * Parse and check the command line options.
+ *
+ * @note The -shutdown command is handled in CheckOptions().
+ */
 int
 afsd_parse(int argc, char **argv)
 {
-    return cmd_Dispatch(argc, argv);
+    struct cmd_syndesc *ts = NULL;
+    int code;
+
+    code = cmd_Parse(argc, argv, &ts);
+    if (code) {
+       return code;
+    }
+    code = CheckOptions(ts);
+    cmd_FreeOptions(&ts);
+    return code;
 }
 
 /**
@@ -2620,6 +2729,8 @@ afsd_syscall_populate(struct afsd_syscall_args *args, int syscall, va_list ap)
     case AFSOP_BUCKETPCT:
     case AFSOP_GO:
     case AFSOP_SET_RMTSYS_FLAG:
+    case AFSOP_SET_INUMCALC:
+    case AFSOP_SET_VOLUME_TTL:
        params[0] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
        break;
     case AFSOP_SET_THISCELL:
@@ -2674,6 +2785,10 @@ afsd_syscall_populate(struct afsd_syscall_args *args, int syscall, va_list ap)
        params[0] = CAST_SYSCALL_PARAM((va_arg(ap, afs_uint32)));
 #endif
        break;
+    case AFSOP_SEED_ENTROPY:
+       params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
+       params[1] = CAST_SYSCALL_PARAM((va_arg(ap, afs_uint32)));
+       break;
     default:
        printf("Unknown syscall enountered: %d\n", syscall);
        opr_Assert(0);