SOLARIS: provide cache manager stats via kstat
[openafs.git] / src / afs / afs_call.c
index 01704ad..367265d 100644 (file)
 #include <afsconfig.h>
 #include "afs/param.h"
 
+#if defined(HAVE_LINUX_KTHREAD_RUN) && !defined(UKERNEL)
+#  include "h/kthread.h"
+#endif
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"
 #include "rx/rx_globals.h"
-#if !defined(UKERNEL) && !defined(AFS_LINUX20_ENV)
-#include "net/if.h"
-#ifdef AFS_SGI62_ENV
-#include "h/hashing.h"
-#endif
-#if !defined(AFS_HPUX110_ENV) && !defined(AFS_DARWIN_ENV)
-#include "netinet/in_var.h"
-#endif
+#if !defined(UKERNEL)
+# if !defined(AFS_LINUX20_ENV)
+#  include "net/if.h"
+#  ifdef AFS_SGI62_ENV
+#   include "h/hashing.h"
+#  endif
+#  if !defined(AFS_HPUX110_ENV) && !defined(AFS_DARWIN_ENV)
+#   include "netinet/in_var.h"
+#  endif
+# endif
 #endif /* !defined(UKERNEL) */
-#ifdef AFS_LINUX22_ENV
-#include "h/smp_lock.h"
-#endif
 #ifdef AFS_SUN510_ENV
 #include "h/ksynch.h"
 #include "h/sunddi.h"
 #endif
+#include <hcrypto/rand.h>
 
 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_HPUX_ENV)
 #define        AFS_MINBUFFERS  100
 #define        AFS_MINBUFFERS  50
 #endif
 
+#if (defined(AFS_SUN5_ENV) || defined(AFS_LINUX26_ENV) || defined(AFS_DARWIN80_ENV)) && !defined(UKERNEL)
+/* If AFS_DAEMONOP_ENV is defined, it indicates we run "daemon" AFS syscalls by
+ * spawning a kernel thread to do the work, instead of running them in the
+ * calling process. */
+# define AFS_DAEMONOP_ENV
+#endif
+
 struct afsop_cell {
     afs_int32 hosts[AFS_MAXCELLHOSTS];
     char cellName[100];
@@ -54,7 +64,6 @@ krwlock_t afsifinfo_lock;
 
 afs_int32 afs_initState = 0;
 afs_int32 afs_termState = 0;
-afs_int32 afs_setTime = 0;
 int afs_cold_shutdown = 0;
 char afs_SynchronousCloses = '\0';
 static int afs_CB_Running = 0;
@@ -62,21 +71,26 @@ static int AFS_Running = 0;
 static int afs_CacheInit_Done = 0;
 static int afs_Go_Done = 0;
 extern struct interfaceAddr afs_cb_interface;
+#ifdef RXK_LISTENER_ENV
 static int afs_RX_Running = 0;
+#endif
 static int afs_InitSetup_done = 0;
 afs_int32 afs_numcachefiles = -1;
 afs_int32 afs_numfilesperdir = -1;
 char afs_cachebasedir[1024];
+afs_int32 afs_rmtsys_enable = 0;
 
 afs_int32 afs_rx_deadtime = AFS_RXDEADTIME;
 afs_int32 afs_rx_harddead = AFS_HARDDEADTIME;
 afs_int32 afs_rx_idledead = AFS_IDLEDEADTIME;
+afs_int32 afs_rx_idledead_rep = AFS_IDLEDEADTIME_REP;
 
 static int afscall_set_rxpck_received = 0;
 
-#if defined(AFS_HPUX_ENV)
-extern int afs_vfs_mount();
-#endif /* defined(AFS_HPUX_ENV) */
+extern afs_int32 afs_volume_ttl;
+
+/* From afs_util.c */
+extern afs_int32 afs_md5inum;
 
 /* This is code which needs to be called once when the first daemon enters
  * the client. A non-zero return means an error and AFS should not start.
@@ -85,6 +99,7 @@ static int
 afs_InitSetup(int preallocs)
 {
     int code;
+    afs_uint32 host;
 
     if (afs_InitSetup_done)
        return EAGAIN;
@@ -110,11 +125,17 @@ afs_InitSetup(int preallocs)
 
     memset(afs_zeros, 0, AFS_ZEROS);
 
-    rx_SetBusyChannelError(RX_CALL_TIMEOUT);
-
     /* start RX */
     if(!afscall_set_rxpck_received)
     rx_extraPackets = AFS_NRXPACKETS;  /* smaller # of packets */
+
+    host = ntohl(rx_bindhost);
+    afs_warn("afs: Binding rx to %d.%d.%d.%d:%d\n",
+             (host >> 24),
+             (host >> 16) & 0xff,
+             (host >>  8) & 0xff,
+             (host)       & 0xff,
+             7001);
     code = rx_InitHost(rx_bindhost, htons(7001));
     if (code) {
        afs_warn("AFS: RX failed to initialize %d).\n", code);
@@ -129,6 +150,39 @@ afs_InitSetup(int preallocs)
 
     return code;
 }
+
+#ifdef AFS_DAEMONOP_ENV
+static int
+daemonOp_common(long parm, long parm2, long parm3, long parm4, long parm5,
+                long parm6)
+{
+    int code;
+    if (parm == AFSOP_START_RXCALLBACK) {
+       if (afs_CB_Running)
+           return -1;
+# ifdef RXK_LISTENER_ENV
+    } else if (parm == AFSOP_RXLISTENER_DAEMON) {
+       if (afs_RX_Running)
+           return -1;
+       afs_RX_Running = 1;
+# endif
+       code = afs_InitSetup(parm2);
+       if (parm3) {
+           rx_enablePeerRPCStats();
+       }
+       if (parm4) {
+           rx_enableProcessRPCStats();
+       }
+       if (code)
+           return -1;
+    } else if (parm == AFSOP_START_AFS) {
+       if (AFS_Running)
+           return -1;
+    }                          /* other functions don't need setup in the parent */
+    return 0;
+}
+#endif /* AFS_DAEMONOP_ENV */
+
 #if defined(AFS_DARWIN80_ENV)
 struct afsd_thread_info {
     unsigned long parm;
@@ -144,8 +198,13 @@ afsd_thread(int *rock)
        AFS_GLOCK();
        wakeup(arg);
        afs_CB_Running = 1;
+#ifndef RXK_LISTENER_ENV
+       afs_initState = AFSOP_START_AFS;
+       afs_osi_Wakeup(&afs_initState);
+#else
        while (afs_RX_Running != 2)
            afs_osi_Sleep(&afs_RX_Running);
+#endif
        afs_RXCallBackServer();
        AFS_GUNLOCK();
        thread_terminate(current_thread());
@@ -191,6 +250,7 @@ afsd_thread(int *rock)
        AFS_GUNLOCK();
        thread_terminate(current_thread());
        break;
+#ifdef RXK_LISTENER_ENV
     case AFSOP_RXLISTENER_DAEMON:
        AFS_GLOCK();
        wakeup(arg);
@@ -203,6 +263,7 @@ afsd_thread(int *rock)
        AFS_GUNLOCK();
        thread_terminate(current_thread());
        break;
+#endif
     default:
        afs_warn("Unknown op %ld in StartDaemon()\n", (long)parm);
        break;
@@ -213,29 +274,11 @@ void
 afs_DaemonOp(long parm, long parm2, long parm3, long parm4, long parm5,
             long parm6)
 {
-    int code;
     struct afsd_thread_info info;
     thread_t thread;
-    if (parm == AFSOP_START_RXCALLBACK) {
-       if (afs_CB_Running)
-           return;
-    } else if (parm == AFSOP_RXLISTENER_DAEMON) {
-       if (afs_RX_Running)
-           return;
-       afs_RX_Running = 1;
-       code = afs_InitSetup(parm2);
-       if (parm3) {
-           rx_enablePeerRPCStats();
-       }
-       if (parm4) {
-           rx_enableProcessRPCStats();
-       }
-       if (code)
-           return;
-    } else if (parm == AFSOP_START_AFS) {
-       if (AFS_Running)
-           return;
-    }                          /* other functions don't need setup in the parent */
+    if (daemonOp_common(parm, parm2, parm3, parm4, parm5, parm6)) {
+       return;
+    }
     info.parm = parm;
     kernel_thread_start((thread_continue_t)afsd_thread, &info, &thread);
     AFS_GUNLOCK();
@@ -247,11 +290,11 @@ afs_DaemonOp(long parm, long parm2, long parm3, long parm4, long parm5,
 #endif
 
 
-#if defined(AFS_LINUX24_ENV) && defined(HAVE_LINUX_COMPLETION_H)
+#if defined(AFS_LINUX26_ENV)
 struct afsd_thread_info {
-#if defined(AFS_LINUX26_ENV) && !defined(INIT_WORK_HAS_DATA)
+# if !defined(INIT_WORK_HAS_DATA)
     struct work_struct tq;
-#endif
+# endif
     unsigned long parm;
     struct completion *complete;
 };
@@ -261,20 +304,22 @@ afsd_thread(void *rock)
 {
     struct afsd_thread_info *arg = rock;
     unsigned long parm = arg->parm;
-#ifdef SYS_SETPRIORITY_EXPORTED
+# ifdef SYS_SETPRIORITY_EXPORTED
     int (*sys_setpriority) (int, int, int) = sys_call_table[__NR_setpriority];
-#endif
-#if defined(AFS_LINUX26_ENV)
+# endif
+# if !defined(HAVE_LINUX_KTHREAD_RUN)
+#  if defined(AFS_LINUX26_ENV)
     daemonize("afsd");
-#else
+#  else
     daemonize();
-#endif
+#  endif
+# endif /* !HAVE_LINUX_KTHREAD_RUN */
                                /* doesn't do much, since we were forked from keventd, but
                                 * does call mm_release, which wakes up our parent (since it
                                 * used CLONE_VFORK) */
-#if !defined(AFS_LINUX26_ENV)
+# if !defined(AFS_LINUX26_ENV)
     reparent_to_init();
-#endif
+# endif
     afs_osi_MaskSignals();
     switch (parm) {
     case AFSOP_START_RXCALLBACK:
@@ -282,8 +327,13 @@ afsd_thread(void *rock)
        AFS_GLOCK();
        complete(arg->complete);
        afs_CB_Running = 1;
+#if !defined(RXK_LISTENER_ENV)
+       afs_initState = AFSOP_START_AFS;
+       afs_osi_Wakeup(&afs_initState);
+#else
        while (afs_RX_Running != 2)
            afs_osi_Sleep(&afs_RX_Running);
+#endif
        sprintf(current->comm, "afs_callback");
        afs_RXCallBackServer();
        AFS_GUNLOCK();
@@ -304,6 +354,9 @@ afsd_thread(void *rock)
        complete_and_exit(0, 0);
        break;
     case AFSOP_START_BKG:
+#ifdef AFS_NEW_BKG
+       afs_warn("Install matching afsd! Old background daemons not supported.\n");
+#else
        sprintf(current->comm, "afs_bkgstart");
        AFS_GLOCK();
        complete(arg->complete);
@@ -316,6 +369,7 @@ afsd_thread(void *rock)
        sprintf(current->comm, "afs_background");
        afs_BackgroundDaemon();
        AFS_GUNLOCK();
+#endif
        complete_and_exit(0, 0);
        break;
     case AFSOP_START_TRUNCDAEMON:
@@ -339,13 +393,13 @@ afsd_thread(void *rock)
        break;
     case AFSOP_RXEVENT_DAEMON:
        sprintf(current->comm, "afs_evtstart");
-#ifdef SYS_SETPRIORITY_EXPORTED
+# ifdef SYS_SETPRIORITY_EXPORTED
        sys_setpriority(PRIO_PROCESS, 0, -10);
-#else
-#ifdef CURRENT_INCLUDES_NICE
+# else
+#  ifdef CURRENT_INCLUDES_NICE
        current->nice = -10;
-#endif
-#endif
+#  endif
+# endif
        AFS_GLOCK();
        complete(arg->complete);
        while (afs_initState < AFSOP_START_BKG)
@@ -355,15 +409,16 @@ afsd_thread(void *rock)
        AFS_GUNLOCK();
        complete_and_exit(0, 0);
        break;
+#ifdef RXK_LISTENER_ENV
     case AFSOP_RXLISTENER_DAEMON:
        sprintf(current->comm, "afs_lsnstart");
-#ifdef SYS_SETPRIORITY_EXPORTED
+# ifdef SYS_SETPRIORITY_EXPORTED
        sys_setpriority(PRIO_PROCESS, 0, -10);
-#else
-#ifdef CURRENT_INCLUDES_NICE
+# else
+#  ifdef CURRENT_INCLUDES_NICE
        current->nice = -10;
-#endif
-#endif
+#  endif
+# endif
        AFS_GLOCK();
        complete(arg->complete);
        afs_initState = AFSOP_START_AFS;
@@ -376,6 +431,7 @@ afsd_thread(void *rock)
        AFS_GUNLOCK();
        complete_and_exit(0, 0);
        break;
+#endif
     default:
        afs_warn("Unknown op %ld in StartDaemon()\n", (long)parm);
        break;
@@ -384,71 +440,59 @@ afsd_thread(void *rock)
 }
 
 void
-#if defined(AFS_LINUX26_ENV) && !defined(INIT_WORK_HAS_DATA)
+# if defined(AFS_LINUX26_ENV) && !defined(INIT_WORK_HAS_DATA)
 afsd_launcher(struct work_struct *work)
-#else
+# else
 afsd_launcher(void *rock)
-#endif
+# endif
 {
-#if defined(AFS_LINUX26_ENV) && !defined(INIT_WORK_HAS_DATA)
+# if defined(AFS_LINUX26_ENV) && !defined(INIT_WORK_HAS_DATA)
     struct afsd_thread_info *rock = container_of(work, struct afsd_thread_info, tq);
-#endif
+# endif
 
+# if defined(HAVE_LINUX_KTHREAD_RUN)
+    if (IS_ERR(kthread_run(afsd_thread, (void *)rock, "afsd"))) {
+       afs_warn("kthread_run failed; afs startup will not complete\n");
+    }
+# else /* !HAVE_LINUX_KTHREAD_RUN */
     if (!kernel_thread(afsd_thread, (void *)rock, CLONE_VFORK | SIGCHLD))
        afs_warn("kernel_thread failed. afs startup will not complete\n");
+# endif /* !HAVE_LINUX_KTHREAD_RUN */
 }
 
 void
 afs_DaemonOp(long parm, long parm2, long parm3, long parm4, long parm5,
             long parm6)
 {
-    int code;
     DECLARE_COMPLETION(c);
-#if defined(AFS_LINUX26_ENV)
-#if defined(INIT_WORK_HAS_DATA)
+# if defined(AFS_LINUX26_ENV)
+#  if defined(INIT_WORK_HAS_DATA)
     struct work_struct tq;
-#endif
-#else
+#  endif
+# else
     struct tq_struct tq;
-#endif
+# endif
     struct afsd_thread_info info;
-    if (parm == AFSOP_START_RXCALLBACK) {
-       if (afs_CB_Running)
-           return;
-    } else if (parm == AFSOP_RXLISTENER_DAEMON) {
-       if (afs_RX_Running)
-           return;
-       afs_RX_Running = 1;
-       code = afs_InitSetup(parm2);
-       if (parm3) {
-           rx_enablePeerRPCStats();
-       }
-       if (parm4) {
-           rx_enableProcessRPCStats();
-       }
-       if (code)
-           return;
-    } else if (parm == AFSOP_START_AFS) {
-       if (AFS_Running)
-           return;
-    }                          /* other functions don't need setup in the parent */
+    if (daemonOp_common(parm, parm2, parm3, parm4, parm5, parm6)) {
+       return;
+    }
     info.complete = &c;
     info.parm = parm;
-#if defined(AFS_LINUX26_ENV)
-#if !defined(INIT_WORK_HAS_DATA)
+# if defined(AFS_LINUX26_ENV)
+#  if !defined(INIT_WORK_HAS_DATA)
     INIT_WORK(&info.tq, afsd_launcher);
     schedule_work(&info.tq);
-#else
+#  else
     INIT_WORK(&tq, afsd_launcher, &info);
     schedule_work(&tq);
-#endif
-#else
+#  endif
+# else
     tq.sync = 0;
     INIT_LIST_HEAD(&tq.list);
     tq.routine = afsd_launcher;
     tq.data = &info;
     schedule_task(&tq);
-#endif
+# endif
     AFS_GUNLOCK();
     /* we need to wait cause we passed stack pointers around.... */
     wait_for_completion(&c);
@@ -456,8 +500,117 @@ afs_DaemonOp(long parm, long parm2, long parm3, long parm4, long parm5,
 }
 #endif
 
+#ifdef AFS_SUN5_ENV
+struct afs_daemonop_args {
+    kcondvar_t cv;
+    long parm;
+};
+
+static void
+afsd_thread(struct afs_daemonop_args *args)
+{
+    long parm = args->parm;
+
+    AFS_GLOCK();
+    cv_signal(&args->cv);
+
+    switch (parm) {
+    case AFSOP_START_RXCALLBACK:
+       if (afs_CB_Running)
+           goto out;
+       afs_CB_Running = 1;
+       while (afs_RX_Running != 2)
+           afs_osi_Sleep(&afs_RX_Running);
+       afs_RXCallBackServer();
+       AFS_GUNLOCK();
+       return;
+    case AFSOP_START_AFS:
+       if (AFS_Running)
+           goto out;
+       AFS_Running = 1;
+       while (afs_initState < AFSOP_START_AFS)
+           afs_osi_Sleep(&afs_initState);
+       afs_initState = AFSOP_START_BKG;
+       afs_osi_Wakeup(&afs_initState);
+       afs_Daemon();
+       AFS_GUNLOCK();
+       return;
+    case AFSOP_START_BKG:
+       while (afs_initState < AFSOP_START_BKG)
+           afs_osi_Sleep(&afs_initState);
+       if (afs_initState < AFSOP_GO) {
+           afs_initState = AFSOP_GO;
+           afs_osi_Wakeup(&afs_initState);
+       }
+       afs_BackgroundDaemon();
+       AFS_GUNLOCK();
+       return;
+    case AFSOP_START_TRUNCDAEMON:
+       while (afs_initState < AFSOP_GO)
+           afs_osi_Sleep(&afs_initState);
+       afs_CacheTruncateDaemon();
+       AFS_GUNLOCK();
+       return;
+    case AFSOP_START_CS:
+       afs_CheckServerDaemon();
+       AFS_GUNLOCK();
+       return;
+    case AFSOP_RXEVENT_DAEMON:
+       while (afs_initState < AFSOP_START_BKG)
+           afs_osi_Sleep(&afs_initState);
+       afs_rxevent_daemon();
+       AFS_GUNLOCK();
+       return;
+    case AFSOP_RXLISTENER_DAEMON:
+       afs_initState = AFSOP_START_AFS;
+       afs_osi_Wakeup(&afs_initState);
+       afs_RX_Running = 2;
+       afs_osi_Wakeup(&afs_RX_Running);
+       afs_osi_RxkRegister();
+       rxk_Listener();
+       AFS_GUNLOCK();
+       return;
+    default:
+       AFS_GUNLOCK();
+       afs_warn("Unknown op %ld in afsd_thread()\n", parm);
+       return;
+    }
+ out:
+    AFS_GUNLOCK();
+    return;
+}
+
+static void
+afs_DaemonOp(long parm, long parm2, long parm3, long parm4, long parm5,
+            long parm6)
+{
+    struct afs_daemonop_args args;
+
+    if (daemonOp_common(parm, parm2, parm3, parm4, parm5, parm6)) {
+       return;
+    }
+
+    args.parm = parm;
+
+    cv_init(&args.cv, "AFS DaemonOp cond var", CV_DEFAULT, NULL);
+
+    if (thread_create(NULL, 0, afsd_thread, &args, 0, &p0, TS_RUN,
+        minclsyspri) == NULL) {
+
+       afs_warn("thread_create failed: AFS startup will not complete\n");
+    }
+
+    /* we passed &args to the new thread, which is on the stack. wait until
+     * it has read the arguments so it doesn't try to read the args after we
+     * have returned */
+    cv_wait(&args.cv, &afs_global_lock);
+
+    cv_destroy(&args.cv);
+}
+#endif /* AFS_SUN5_ENV */
+
 #ifdef AFS_DARWIN100_ENV
-#define AFSKPTR(X) k ## X
+# define AFSKPTR(X) k ## X
 int
 afs_syscall_call(long parm, long parm2, long parm3,
                 long parm4, long parm5, long parm6)
@@ -470,7 +623,7 @@ afs_syscall_call(long parm, long parm2, long parm3,
                              CAST_USER_ADDR_T((parm6)));
 }
 #else
-#define AFSKPTR(X) ((caddr_t)X)
+# define AFSKPTR(X) ((caddr_t)X)
 #endif
 int
 #ifdef AFS_DARWIN100_ENV
@@ -482,7 +635,7 @@ afs_syscall_call(long parm, long parm2, long parm3,
 #endif
 {
     afs_int32 code = 0;
-#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if defined(AFS_SGI61_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     size_t bufferSize;
 #else /* AFS_SGI61_ENV */
     u_int bufferSize;
@@ -507,9 +660,9 @@ afs_syscall_call(long parm, long parm2, long parm3,
                    && (parm != AFSOP_GETMTU) && (parm != AFSOP_GETMASK)) {
        /* only root can run this code */
 #if defined(AFS_SUN5_ENV) || defined(KERNEL_HAVE_UERROR)
-#if defined(KERNEL_HAVE_UERROR)
+# if defined(KERNEL_HAVE_UERROR)
        setuerror(EACCES);
-#endif
+# endif
        code = EACCES;
 #else
        code = EPERM;
@@ -524,8 +677,8 @@ afs_syscall_call(long parm, long parm2, long parm3,
 #ifdef AFS_DARWIN80_ENV
     put_vfs_context();
 #endif
-#if ((defined(AFS_LINUX24_ENV) && defined(HAVE_LINUX_COMPLETION_H)) || defined(AFS_DARWIN80_ENV)) && !defined(UKERNEL)
-#if defined(AFS_DARWIN80_ENV)
+#ifdef AFS_DAEMONOP_ENV
+# if defined(AFS_NEW_BKG)
     if (parm == AFSOP_BKG_HANDLER) {
        /* if afs_uspc_param grows this should be checked */
        struct afs_uspc_param *mvParam = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
@@ -553,6 +706,7 @@ afs_syscall_call(long parm, long parm2, long parm3,
        if (!code) {
            mvParam->retval = 0;
            /* for reqs where pointers are strings: */
+#  ifdef AFS_DARWIN_ENV
            if (mvParam->reqtype == AFS_USPC_UMV) {
                /* don't copy out random kernel memory */
                AFS_COPYOUT(param2, AFSKPTR(parm4),
@@ -560,6 +714,7 @@ afs_syscall_call(long parm, long parm2, long parm3,
                AFS_COPYOUT(param1, AFSKPTR(parm3),
                            MIN(namebufsz, strlen((char *)param1)+1), code);
            }
+#  endif /* AFS_DARWIN_ENV */
            AFS_COPYOUT((caddr_t)mvParam, AFSKPTR(parm2),
                       sizeof(struct afs_uspc_param), code);
        }
@@ -568,38 +723,44 @@ afs_syscall_call(long parm, long parm2, long parm3,
        afs_osi_Free(param2, namebufsz);
        osi_FreeSmallSpace(mvParam);
     } else
-#endif /* DARWIN80 */
+# endif /* AFS_NEW_BKG */
     if (parm < AFSOP_ADDCELL || parm == AFSOP_RXEVENT_DAEMON
        || parm == AFSOP_RXLISTENER_DAEMON) {
        afs_DaemonOp(parm, parm2, parm3, parm4, parm5, parm6);
     }
-#else /* !(AFS_LINUX24_ENV && !UKERNEL) */
+#else /* !AFS_DAEMONOP_ENV */
     if (parm == AFSOP_START_RXCALLBACK) {
        if (afs_CB_Running)
            goto out;
        afs_CB_Running = 1;
-#ifndef RXK_LISTENER_ENV
+# ifndef RXK_LISTENER_ENV
        code = afs_InitSetup(parm2);
        if (!code)
-#endif /* !RXK_LISTENER_ENV */
+# endif /* !RXK_LISTENER_ENV */
        {
-#ifdef RXK_LISTENER_ENV
-               while (afs_RX_Running != 2)
+# ifdef RXK_LISTENER_ENV
+           while (afs_RX_Running != 2)
                afs_osi_Sleep(&afs_RX_Running);
-#else /* !RXK_LISTENER_ENV */
+# else /* !RXK_LISTENER_ENV */
+           if (parm3) {
+               rx_enablePeerRPCStats();
+           }
+           if (parm4) {
+               rx_enableProcessRPCStats();
+           }
            afs_initState = AFSOP_START_AFS;
            afs_osi_Wakeup(&afs_initState);
-#endif /* RXK_LISTENER_ENV */
+# endif /* RXK_LISTENER_ENV */
            afs_osi_Invisible();
            afs_RXCallBackServer();
            afs_osi_Visible();
        }
-#ifdef AFS_SGI_ENV
+# ifdef AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, code);
-#endif /* AFS_SGI_ENV */
+# endif /* AFS_SGI_ENV */
     }
-#ifdef RXK_LISTENER_ENV
+# ifdef RXK_LISTENER_ENV
     else if (parm == AFSOP_RXLISTENER_DAEMON) {
        if (afs_RX_Running)
            goto out;
@@ -617,18 +778,18 @@ afs_syscall_call(long parm, long parm2, long parm3,
            afs_osi_Invisible();
            afs_RX_Running = 2;
            afs_osi_Wakeup(&afs_RX_Running);
-#ifndef UKERNEL
+#  ifndef UKERNEL
            afs_osi_RxkRegister();
-#endif /* !UKERNEL */
+#  endif /* !UKERNEL */
            rxk_Listener();
            afs_osi_Visible();
        }
-#ifdef AFS_SGI_ENV
+#  ifdef       AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, code);
-#endif /* AFS_SGI_ENV */
+#  endif /* AFS_SGI_ENV */
     }
-#endif /* RXK_LISTENER_ENV */
+# endif /* RXK_LISTENER_ENV */
     else if (parm == AFSOP_START_AFS) {
        /* afs daemon */
        if (AFS_Running)
@@ -642,19 +803,19 @@ afs_syscall_call(long parm, long parm2, long parm3,
        afs_osi_Invisible();
        afs_Daemon();
        afs_osi_Visible();
-#ifdef AFS_SGI_ENV
+# ifdef AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, 0);
-#endif /* AFS_SGI_ENV */
+# endif /* AFS_SGI_ENV */
     } else if (parm == AFSOP_START_CS) {
        afs_osi_Invisible();
        afs_CheckServerDaemon();
        afs_osi_Visible();
-#ifdef AFS_SGI_ENV
+# ifdef AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, 0);
-#endif /* AFS_SGI_ENV */
-#ifndef AFS_DARWIN80_ENV
+# endif /* AFS_SGI_ENV */
+# ifndef AFS_NEW_BKG
     } else if (parm == AFSOP_START_BKG) {
        while (afs_initState < AFSOP_START_BKG)
            afs_osi_Sleep(&afs_initState);
@@ -664,18 +825,18 @@ afs_syscall_call(long parm, long parm2, long parm3,
        }
        /* start the bkg daemon */
        afs_osi_Invisible();
-# ifdef AFS_AIX32_ENV
+#  ifdef AFS_AIX32_ENV
        if (parm2)
            afs_BioDaemon(parm2);
        else
-# endif /* AFS_AIX32_ENV */
+#  endif /* AFS_AIX32_ENV */
            afs_BackgroundDaemon();
        afs_osi_Visible();
-# ifdef AFS_SGI_ENV
+#  ifdef AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, 0);
-# endif /* AFS_SGI_ENV */
-#endif /* ! AFS_DARWIN80_ENV */
+#  endif /* AFS_SGI_ENV */
+# endif /* ! AFS_NEW_BKG */
     } else if (parm == AFSOP_START_TRUNCDAEMON) {
        while (afs_initState < AFSOP_GO)
            afs_osi_Sleep(&afs_initState);
@@ -683,25 +844,25 @@ afs_syscall_call(long parm, long parm2, long parm3,
        afs_osi_Invisible();
        afs_CacheTruncateDaemon();
        afs_osi_Visible();
-#ifdef AFS_SGI_ENV
+# ifdef        AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, 0);
-#endif /* AFS_SGI_ENV */
+# endif /* AFS_SGI_ENV */
     }
-#if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV)
+# if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV) || defined(RXK_UPCALL_ENV)
     else if (parm == AFSOP_RXEVENT_DAEMON) {
        while (afs_initState < AFSOP_START_BKG)
            afs_osi_Sleep(&afs_initState);
        afs_osi_Invisible();
        afs_rxevent_daemon();
        afs_osi_Visible();
-#ifdef AFS_SGI_ENV
+#  ifdef AFS_SGI_ENV
        AFS_GUNLOCK();
        exit(CLD_EXITED, 0);
-#endif /* AFS_SGI_ENV */
+#  endif /* AFS_SGI_ENV */
     }
-#endif /* AFS_SUN5_ENV || RXK_LISTENER_ENV */
-#endif /* AFS_LINUX24_ENV && !UKERNEL */
+# endif /* AFS_SUN5_ENV || RXK_LISTENER_ENV || RXK_UPCALL_ENV */
+#endif /* AFS_DAEMONOP_ENV */
     else if (parm == AFSOP_BASIC_INIT) {
        afs_int32 temp;
 
@@ -766,12 +927,6 @@ afs_syscall_call(long parm, long parm2, long parm3,
        osi_Assert(tbuffer1 != NULL);
        code = afs_InitDynroot();
        if (!code) {
-#if 0
-           /* wait for basic init - XXX can't find any reason we need this? */
-           while (afs_initState < AFSOP_START_BKG)
-               afs_osi_Sleep(&afs_initState);
-#endif
-
            AFS_COPYIN(AFSKPTR(parm2), (caddr_t)tcell->hosts, sizeof(tcell->hosts),
                       code);
        }
@@ -851,7 +1006,10 @@ afs_syscall_call(long parm, long parm2, long parm3,
        }
        afs_CacheInit_Done = 1;
         code = afs_icl_InitLogs();
-       afs_setTime = cparms.setTimeFlag;
+       if (cparms.setTimeFlag) {
+           afs_warn("afs: AFSOP_CACHEINIT setTimeFlag ignored; are you "
+                    "running an old afsd?\n");
+       }
 
        code =
            afs_CacheInit(cparms.cacheScaches, cparms.cacheFiles,
@@ -901,10 +1059,6 @@ afs_syscall_call(long parm, long parm2, long parm3,
        code = 0;
        AFS_COPYINSTR(AFSKPTR(parm2), tbuffer, AFS_SMALLOCSIZ, &bufferSize,
                      code);
-       if (code) {
-           osi_FreeSmallSpace(tbuffer);
-           goto out;
-       }
        if (!code) {
            tbuffer[AFS_SMALLOCSIZ - 1] = '\0'; /* null-terminate the name */
            /* We have the cache dir copied in.  Call the cache init routine */
@@ -934,7 +1088,11 @@ afs_syscall_call(long parm, long parm2, long parm3,
        while (afs_initState < AFSOP_GO)
            afs_osi_Sleep(&afs_initState);
        afs_initState = 101;
-       afs_setTime = parm2;
+       if (parm2) {
+           /* parm2 used to set afs_setTime */
+           afs_warn("afs: AFSOP_GO setTime flag ignored; are you running an "
+                    "old afsd?\n");
+       }
        if (afs_tpct1 + afs_tpct2 != 100) {
            afs_tpct1 = 0;
            afs_tpct2 = 0;
@@ -946,7 +1104,13 @@ afs_syscall_call(long parm, long parm2, long parm3,
 #if    (!defined(AFS_NONFSTRANS)) || defined(AFS_AIX_IAUTH_ENV)
        afs_nfsclient_init();
 #endif
-       afs_uuid_create(&afs_cb_interface.uuid);
+       if (afs_uuid_create(&afs_cb_interface.uuid) != 0)
+           memset(&afs_cb_interface.uuid, 0, sizeof(afsUUID));
+
+#if defined(AFS_SUN5_ENV)
+       afs_kstat_init();
+#endif
+
        printf("found %d non-empty cache files (%d%%).\n",
               afs_stats_cmperf.cacheFilesReused,
               (100 * afs_stats_cmperf.cacheFilesReused) /
@@ -1034,35 +1198,9 @@ afs_syscall_call(long parm, long parm2, long parm3,
 
        if (refresh) {
            afs_CheckServers(1, NULL);     /* check down servers */
-           afs_CheckServers(0, NULL);     /* check down servers */
+           afs_CheckServers(0, NULL);     /* check up servers */
        }
     }
-#ifdef AFS_SGI53_ENV
-    else if (parm == AFSOP_NFSSTATICADDR) {
-       extern int (*nfs_rfsdisptab_v2) ();
-       nfs_rfsdisptab_v2 = (int (*)())parm2;
-    } else if (parm == AFSOP_NFSSTATICADDR2) {
-       extern int (*nfs_rfsdisptab_v2) ();
-#ifdef _K64U64
-       nfs_rfsdisptab_v2 = (int (*)())((parm2 << 32) | (parm3 & 0xffffffff));
-#else /* _K64U64 */
-       nfs_rfsdisptab_v2 = (int (*)())(parm3 & 0xffffffff);
-#endif /* _K64U64 */
-    }
-#if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
-    else if (parm == AFSOP_SBLOCKSTATICADDR2) {
-       extern int (*afs_sblockp) ();
-       extern void (*afs_sbunlockp) ();
-#ifdef _K64U64
-       afs_sblockp = (int (*)())((parm2 << 32) | (parm3 & 0xffffffff));
-       afs_sbunlockp = (void (*)())((parm4 << 32) | (parm5 & 0xffffffff));
-#else
-       afs_sblockp = (int (*)())(parm3 & 0xffffffff);
-       afs_sbunlockp = (void (*)())(parm5 & 0xffffffff);
-#endif /* _K64U64 */
-    }
-#endif /* AFS_SGI62_ENV && !AFS_SGI65_ENV */
-#endif /* AFS_SGI53_ENV */
     else if (parm == AFSOP_SHUTDOWN) {
        afs_cold_shutdown = 0;
        if (parm2 == 1)
@@ -1076,51 +1214,35 @@ afs_syscall_call(long parm, long parm2, long parm3,
 #ifdef AFS_HPUX_ENV
        vfsmount(parm2, parm3, parm4, parm5);
 #else /* defined(AFS_HPUX_ENV) */
-#if defined(KERNEL_HAVE_UERROR)
+# if defined(KERNEL_HAVE_UERROR)
        setuerror(EINVAL);
-#else
+# else
        code = EINVAL;
-#endif
+# endif
 #endif /* defined(AFS_HPUX_ENV) */
     } else if (parm == AFSOP_CLOSEWAIT) {
        afs_SynchronousCloses = 'S';
     } else if (parm == AFSOP_GETMTU) {
        afs_uint32 mtu = 0;
 #if    !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV)
-#ifdef AFS_USERSPACE_IP_ADDR
+# ifdef AFS_USERSPACE_IP_ADDR
        afs_int32 i;
        i = rxi_Findcbi(parm2);
        mtu = ((i == -1) ? htonl(1500) : afs_cb_interface.mtu[i]);
-#else /* AFS_USERSPACE_IP_ADDR */
+# else /* AFS_USERSPACE_IP_ADDR */
        rx_ifnet_t tifnp;
 
        tifnp = rxi_FindIfnet(parm2, NULL);     /*  make iterative */
        mtu = (tifnp ? rx_ifnet_mtu(tifnp) : htonl(1500));
-#endif /* else AFS_USERSPACE_IP_ADDR */
+# endif /* else AFS_USERSPACE_IP_ADDR */
 #endif /* !AFS_SUN5_ENV */
        if (!code)
            AFS_COPYOUT((caddr_t) & mtu, AFSKPTR(parm3),
                        sizeof(afs_int32), code);
-#ifdef AFS_AIX32_ENV
-/* this is disabled for now because I can't figure out how to get access
- * to these kernel variables.  It's only for supporting user-mode rx
- * programs -- it makes a huge difference on the 220's in my testbed,
- * though I don't know why. The bosserver does this with /etc/no, so it's
- * being handled a different way for the servers right now.  */
-/*      {
-       static adjusted = 0;
-       extern u_long sb_max_dflt;
-       if (!adjusted) {
-         adjusted = 1;
-         if (sb_max_dflt < 131072) sb_max_dflt = 131072;
-         if (sb_max < 131072) sb_max = 131072;
-       }
-      } */
-#endif /* AFS_AIX32_ENV */
     } else if (parm == AFSOP_GETMASK) {        /* parm2 == addr in net order */
        afs_uint32 mask = 0;
 #if    !defined(AFS_SUN5_ENV)
-#ifdef AFS_USERSPACE_IP_ADDR
+# ifdef AFS_USERSPACE_IP_ADDR
        afs_int32 i;
        i = rxi_Findcbi(parm2);
        if (i != -1) {
@@ -1128,13 +1250,13 @@ afs_syscall_call(long parm, long parm2, long parm3,
        } else {
            code = -1;
        }
-#else /* AFS_USERSPACE_IP_ADDR */
+# else /* AFS_USERSPACE_IP_ADDR */
        rx_ifnet_t tifnp;
 
        tifnp = rxi_FindIfnet(parm2, &mask);    /* make iterative */
        if (!tifnp)
            code = -1;
-#endif /* else AFS_USERSPACE_IP_ADDR */
+# endif /* else AFS_USERSPACE_IP_ADDR */
 #endif /* !AFS_SUN5_ENV */
        if (!code)
            AFS_COPYOUT((caddr_t) & mask, AFSKPTR(parm3),
@@ -1171,8 +1293,14 @@ afs_syscall_call(long parm, long parm2, long parm3,
     else if (parm == AFSOP_SET_DYNROOT) {
        code = afs_SetDynrootEnable(parm2);
     } else if (parm == AFSOP_SET_FAKESTAT) {
-       afs_fakestat_enable = parm2;
-       code = 0;
+       if (parm2 >= 0 && parm2 <= 2) {
+           afs_fakestat_enable = parm2;
+           code = 0;
+       } else {
+           afs_warn("afs: afsd gave us unknown fakestat value %ld (are afsd "
+                    "and libafs running the same version?\n", parm2);
+           code = EINVAL;
+       }
     } else if (parm == AFSOP_SET_BACKUPTREE) {
        afs_bkvolpref = parm2;
     } else if (parm == AFSOP_SET_RXPCK) {
@@ -1180,6 +1308,45 @@ afs_syscall_call(long parm, long parm2, long parm3,
        afscall_set_rxpck_received = 1;
     } else if (parm == AFSOP_SET_RXMAXMTU) {
        rx_MyMaxSendSize = rx_maxReceiveSizeUser = rx_maxReceiveSize = parm2;
+    } else if (parm == AFSOP_SET_RXMAXFRAGS) {
+       rxi_nSendFrags = rxi_nRecvFrags = parm2;
+    } else if (parm == AFSOP_SET_RMTSYS_FLAG) {
+       afs_rmtsys_enable = parm2;
+       code = 0;
+#ifndef UKERNEL
+    } else if (parm == AFSOP_SEED_ENTROPY) {
+       unsigned char *seedbuf;
+
+       if (parm3 > 4096) {
+           code = EFAULT;
+       } else {
+           seedbuf = afs_osi_Alloc(parm3);
+           AFS_COPYIN(AFSKPTR(parm2), seedbuf, parm3, code);
+           RAND_seed(seedbuf, parm3);
+           memset(seedbuf, 0, parm3);
+           afs_osi_Free(seedbuf, parm3);
+       }
+#endif
+    } else if (parm == AFSOP_SET_INUMCALC) {
+       switch (parm2) {
+       case AFS_INUMCALC_COMPAT:
+           afs_md5inum = 0;
+           code = 0;
+           break;
+       case AFS_INUMCALC_MD5:
+           afs_md5inum = 1;
+           code = 0;
+           break;
+       default:
+           code = EINVAL;
+       }
+    } else if (parm == AFSOP_SET_VOLUME_TTL) {
+       if ((parm2 < AFS_MIN_VOLUME_TTL) || (parm2 > AFS_MAX_VOLUME_TTL)) {
+           code = EFAULT;
+       } else {
+           afs_volume_ttl = parm2;
+           code = 0;
+       }
     } else {
        code = EINVAL;
     }
@@ -1219,7 +1386,7 @@ afs_CheckInit(void)
     return code;
 }
 
-int afs_shuttingdown = 0;
+enum afs_shutdown_state afs_shuttingdown = AFS_RUNNING;
 void
 afs_shutdown(void)
 {
@@ -1234,16 +1401,43 @@ afs_shutdown(void)
       return;
     }
 
-    if (afs_shuttingdown)
+    if (afs_shuttingdown != AFS_RUNNING)
        return;
-    afs_FlushVCBs(2);       /* Reasonable effort to free dynamically allocated callback returns */
 
-    afs_shuttingdown = 1;
+    afs_shuttingdown = AFS_FLUSHING_CB;
+
+    /* Give up all of our callbacks if we can. */
+    afs_FlushVCBs(2);
+
+    afs_shuttingdown = AFS_SHUTDOWN;
+
+#if defined(AFS_SUN5_ENV)
+    afs_kstat_shutdown();
+#endif
+
     if (afs_cold_shutdown)
        afs_warn("afs: COLD ");
     else
        afs_warn("afs: WARM ");
-    afs_warn("shutting down of: CB... ");
+    afs_warn("shutting down of: vcaches... ");
+
+#if !defined(AFS_FBSD_ENV)
+    /* The FBSD afs_unmount() calls vflush(), which reclaims all vnodes
+     * on the mountpoint, flushing them in the process.  In the presence
+     * of bugs, flushing again here can cause panics. */
+    afs_FlushAllVCaches();
+#endif
+
+    afs_termState = AFSOP_STOP_BKG;
+
+    afs_warn("BkG... ");
+    /* Wake-up afs_brsDaemons so that we don't have to wait for a bkg job! */
+    while (afs_termState == AFSOP_STOP_BKG) {
+       afs_osi_Wakeup(&afs_brsDaemons);
+       afs_osi_Sleep(&afs_termState);
+    }
+
+    afs_warn("CB... ");
 
     afs_termState = AFSOP_STOP_RXCALLBACK;
     rx_WakeupServerProcs();
@@ -1265,12 +1459,6 @@ afs_shutdown(void)
            afs_osi_Sleep(&afs_termState);
        }
     }
-    afs_warn("BkG... ");
-    /* Wake-up afs_brsDaemons so that we don't have to wait for a bkg job! */
-    while (afs_termState == AFSOP_STOP_BKG) {
-       afs_osi_Wakeup(&afs_brsDaemons);
-       afs_osi_Sleep(&afs_termState);
-    }
     afs_warn("CTrunc... ");
     /* Cancel cache truncate daemon. */
     while (afs_termState == AFSOP_STOP_TRUNCDAEMON) {
@@ -1281,16 +1469,16 @@ afs_shutdown(void)
     afs_StopAFSDB();
     while (afs_termState == AFSOP_STOP_AFSDB)
        afs_osi_Sleep(&afs_termState);
-#if    defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV) || defined(RXK_UPCALL_ENV)
     afs_warn("RxEvent... ");
     /* cancel rx event daemon */
     while (afs_termState == AFSOP_STOP_RXEVENT)
        afs_osi_Sleep(&afs_termState);
-#if defined(RXK_LISTENER_ENV)
-#ifndef UKERNEL
+# if defined(RXK_LISTENER_ENV)
+#  ifndef UKERNEL
     afs_warn("UnmaskRxkSignals... ");
     afs_osi_UnmaskRxkSignals();
-#endif
+#  endif
     /* cancel rx listener */
     afs_warn("RxListener... ");
     osi_StopListener();                /* This closes rx_socket. */
@@ -1298,13 +1486,14 @@ afs_shutdown(void)
        afs_warn("Sleep... ");
        afs_osi_Sleep(&afs_termState);
     }
-#endif
+# endif
 #endif
 
-#ifdef AFS_SUN510_ENV
+#if defined(AFS_SUN510_ENV) || defined(RXK_UPCALL_ENV)
     afs_warn("NetIfPoller... ");
     osi_StopNetIfPoller();
 #endif
+    rxi_FreeAllPackets();
 
     afs_termState = AFSOP_STOP_COMPLETE;
 
@@ -1339,6 +1528,7 @@ afs_shutdown(void)
     shutdown_nfsclnt();
 #endif
     shutdown_afstest();
+    shutdown_dynroot();
     shutdown_AFS();
     /* The following hold the cm stats */
     memset(&afs_cmstats, 0, sizeof(struct afs_CMStats));
@@ -1346,7 +1536,7 @@ afs_shutdown(void)
     memset(&afs_stats_cmfullperf, 0, sizeof(struct afs_stats_CMFullPerf));
     afs_warn(" ALL allocated tables... ");
 
-    afs_shuttingdown = 0;
+    afs_shuttingdown = AFS_RUNNING;
     afs_warn("done\n");
 
     return;                    /* Just kill daemons for now */
@@ -1356,7 +1546,7 @@ void
 shutdown_afstest(void)
 {
     AFS_STATCNT(shutdown_afstest);
-    afs_initState = afs_termState = afs_setTime = 0;
+    afs_initState = afs_termState = 0;
     AFS_Running = afs_CB_Running = 0;
     afs_CacheInit_Done = afs_Go_Done = 0;
     if (afs_cold_shutdown) {