DEVEL15-linux-afs-translator-xen-20060731
authorJeffrey Hutzelman <jhutz@cmu.edu>
Mon, 31 Jul 2006 22:58:28 +0000 (22:58 +0000)
committerDerrick Brashear <shadow@dementia.org>
Mon, 31 Jul 2006 22:58:28 +0000 (22:58 +0000)
FIXES 36646

add linux afs translator plus xen shared afs client support

(cherry picked from commit 29dd7923817b621c5d14920513dc26c2f9fda530)

67 files changed:
src/afs/.cvsignore
src/afs/LINUX/osi_export.c [new file with mode: 0644]
src/afs/LINUX/osi_file.c
src/afs/LINUX/osi_ioctl.c [new file with mode: 0644]
src/afs/LINUX/osi_misc.c
src/afs/LINUX/osi_module.c
src/afs/LINUX/osi_nfssrv.c [new file with mode: 0644]
src/afs/LINUX/osi_pag_module.c [new file with mode: 0644]
src/afs/LINUX/osi_proc.c [new file with mode: 0644]
src/afs/LINUX/osi_prototypes.h
src/afs/LINUX/osi_vfsops.c
src/afs/LINUX/osi_vnodeops.c
src/afs/UKERNEL/afs_usrops.c
src/afs/VNOPS/afs_vnop_access.c
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/VNOPS/afs_vnop_remove.c
src/afs/VNOPS/afs_vnop_symlink.c
src/afs/afs.h
src/afs/afs_analyze.c
src/afs/afs_call.c
src/afs/afs_cell.c
src/afs/afs_dcache.c
src/afs/afs_dynroot.c
src/afs/afs_dynroot.h [new file with mode: 0644]
src/afs/afs_error.c [new file with mode: 0644]
src/afs/afs_icl.c [new file with mode: 0644]
src/afs/afs_init.c
src/afs/afs_md5.c [new file with mode: 0644]
src/afs/afs_md5.h [new file with mode: 0644]
src/afs/afs_nfsclnt.c
src/afs/afs_osi.c
src/afs/afs_osi_alloc.c
src/afs/afs_osi_gcpags.c [new file with mode: 0644]
src/afs/afs_osi_pag.c
src/afs/afs_osi_vm.c [new file with mode: 0644]
src/afs/afs_pag_call.c [new file with mode: 0644]
src/afs/afs_pag_cred.c [new file with mode: 0644]
src/afs/afs_pioctl.c
src/afs/afs_prototypes.h
src/afs/afs_syscall.c [new file with mode: 0644]
src/afs/afs_user.c
src/afs/afs_vcache.c
src/afs/afs_volume.c
src/afs/exporter.h
src/afs/nfsclient.h
src/config/param.alpha_linux_26.h
src/config/param.amd64_linux26.h
src/config/param.i386_linux26.h
src/config/param.i386_umlinux26.h
src/config/param.ia64_linux26.h
src/config/param.ppc64_linux26.h
src/config/param.ppc_linux26.h
src/config/param.s390_linux26.h
src/config/param.s390x_linux26.h
src/config/param.sparc64_linux26.h
src/config/venus.h
src/fsint/.cvsignore
src/fsint/Makefile.in
src/fsint/pagcb.xg [new file with mode: 0644]
src/libafs/Makefile.common.in
src/libafs/MakefileProto.LINUX.in
src/libafs/make_kbuild_makefile.pl
src/libuafs/Makefile.common.in
src/sys/.cvsignore
src/sys/Makefile.in
src/sys/rmtsys.xg
src/venus/fs.c

index fb596ce..286e2d2 100644 (file)
@@ -5,3 +5,4 @@ afs_trace.msf
 afszcm.cat
 unified_afs.c
 unified_afs.h
+_locks_
diff --git a/src/afs/LINUX/osi_export.c b/src/afs/LINUX/osi_export.c
new file mode 100644 (file)
index 0000000..5de06a1
--- /dev/null
@@ -0,0 +1,933 @@
+/*
+ * vi:set cin noet sw=4 tw=70:
+ * Copyright 2006, 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
+ */
+
+/*
+ * Filesystem export operations for Linux
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "afs/afs_dynroot.h"
+#include "h/smp_lock.h"
+
+/* #define OSI_EXPORT_DEBUG */
+
+extern struct dentry_operations afs_dentry_operations;
+
+struct get_name_data {
+    char *name;
+    struct VenusFid fid;
+    int found;
+};
+
+/*
+ * Linux reserved the following filehandle types:
+ * - 0 is always the filesystem root; NFS deals with this for us
+ * - 1,2 are reserved by Linux for inode-number-based filehandles
+ * - 0xff is reserved by linux
+ *
+ * We encode filehandles for AFS files using the types defined below.
+ * Internally, our "object ID" is a VenusFid; if we get a filehandle
+ * with a more-stable cell ID, we'll turn it into a cell number in
+ * the decode_fh wrapper.
+ */
+
+#define AFSFH_VENUSFID      0xa0 /* cell, volume, vnode, uniq           */
+#define AFSFH_CELLFID       0xa1 /* cellhandle, volume, vnode, uniq     */
+#define AFSFH_NET_VENUSFID  0xa2 /* net cell, volume, vnode, uniq       */
+#define AFSFH_NET_CELLFID   0xa3 /* net cellhandle, volume, vnode, uniq */
+#define AFSFH_DYN_RO_CELL   0xd0 /* cellhandle for RO root.cell mount   */
+#define AFSFH_DYN_RW_CELL   0xd1 /* cellhandle for RW root.cell mount   */
+#define AFSFH_DYN_RO_LINK   0xd2 /* cellhandle for RO root.cell symlink */
+#define AFSFH_DYN_RW_LINK   0xd3 /* cellhandle for RW root.cell symlink */
+#define AFSFH_DYN_MOUNT     0xd4 /* cellhandle, volume for mount point  */
+#define AFSFH_DYN_SYMLINK   0xd5 /* hash of dynroot symlink target */
+
+static int afs_encode_fh(struct dentry *de, __u32 *fh, int *max_len,
+                        int connectable)
+{
+    struct vcache *tvc;
+    struct cell *tc;
+    int vntype;
+
+    if (!de->d_inode) /* encode a negative dentry?! */
+       return 255;
+    if (*max_len < 4)  /* not enough space */
+       return 255;
+
+    tvc = VTOAFS(de->d_inode);
+
+#ifdef OSI_EXPORT_DEBUG
+    printk("afs: encode_fh(0x%08x/%d/%d.%d)\n",
+          tvc->fid.Cell,      tvc->fid.Fid.Volume,
+          tvc->fid.Fid.Vnode, tvc->fid.Fid.Unique);
+#endif
+    if (afs_IsDynrootAnyFid(&tvc->fid)) {
+       vntype = VNUM_TO_VNTYPE(tvc->fid.Fid.Vnode);
+       switch (vntype) {
+           case 0:
+               /* encode as a normal filehandle */
+               break;
+
+           case VN_TYPE_MOUNT:
+               if (*max_len < 5) {
+                   return 255;
+               }
+               /* fall through */
+
+           case VN_TYPE_CELL:
+           case VN_TYPE_ALIAS:
+               AFS_GLOCK();
+               tc = afs_GetCellByIndex(VNUM_TO_CIDX(tvc->fid.Fid.Vnode),
+                                       READ_LOCK);
+               if (!tc) {
+                   AFS_GUNLOCK();
+                   return 255;
+               }
+               memcpy((void *)fh, tc->cellHandle, 16);
+               afs_PutCell(tc, READ_LOCK);
+               AFS_GUNLOCK();
+               if (vntype == VN_TYPE_MOUNT) {
+                   fh[4] = htonl(tvc->fid.Fid.Unique);
+                   *max_len = 5;
+                   return AFSFH_DYN_MOUNT;
+               }
+               *max_len = 4;
+               if (vntype == VN_TYPE_CELL) {
+                   return AFSFH_DYN_RO_CELL | VNUM_TO_RW(tvc->fid.Fid.Vnode);
+               } else {
+                   return AFSFH_DYN_RO_LINK | VNUM_TO_RW(tvc->fid.Fid.Vnode);
+               }
+
+           case VN_TYPE_SYMLINK:
+               /* XXX fill in filehandle for dynroot symlink */
+               /* XXX return AFSFH_DYN_SYMLINK; */
+
+           default:
+               return 255;
+       }
+    }
+
+    if (*max_len < 7) {
+       /* not big enough for a migratable filehandle */
+       /* always encode in network order */
+       fh[0] = htonl(tvc->fid.Cell);
+       fh[1] = htonl(tvc->fid.Fid.Volume);
+       fh[2] = htonl(tvc->fid.Fid.Vnode);
+       fh[3] = htonl(tvc->fid.Fid.Unique);
+       *max_len = 4;
+       return AFSFH_NET_VENUSFID;
+    }
+
+    AFS_GLOCK();
+    tc = afs_GetCell(tvc->fid.Cell, READ_LOCK);
+    if (!tc) {
+       AFS_GUNLOCK();
+       return 255;
+    }
+    memcpy((void *)fh, tc->cellHandle, 16);
+    afs_PutCell(tc, READ_LOCK);
+    AFS_GUNLOCK();
+    /* always encode in network order */
+    fh[4] = htonl(tvc->fid.Fid.Volume);
+    fh[5] = htonl(tvc->fid.Fid.Vnode);
+    fh[6] = htonl(tvc->fid.Fid.Unique);
+
+    *max_len = 7;
+    return AFSFH_NET_CELLFID;
+}
+
+static struct dentry *afs_decode_fh(struct super_block *sb, __u32 *fh,
+                                   int fh_len, int fh_type,
+                                   int (*acceptable)(void *, struct dentry *),
+                                   void *context)
+{
+    struct VenusFid fid;
+    struct cell *tc;
+    struct dentry *result;
+
+    switch (fh_type) {
+       case AFSFH_VENUSFID:
+           if (fh_len != 4)
+               return NULL;
+           fid.Cell       = fh[0];
+           fid.Fid.Volume = fh[1];
+           fid.Fid.Vnode  = fh[2];
+           fid.Fid.Unique = fh[3];
+           break;
+
+       case AFSFH_CELLFID:
+           if (fh_len != 7)
+               return NULL;
+           AFS_GLOCK();
+           tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
+           if (!tc) {
+               AFS_GUNLOCK();
+               return NULL;
+           }
+           fid.Cell       = tc->cellNum;
+           fid.Fid.Volume = fh[4];
+           fid.Fid.Vnode  = fh[5];
+           fid.Fid.Unique = fh[6];
+           afs_PutCell(tc, READ_LOCK);
+           AFS_GUNLOCK();
+           break;
+
+       case AFSFH_NET_VENUSFID:
+           if (fh_len != 4)
+               return NULL;
+           fid.Cell       = ntohl(fh[0]);
+           fid.Fid.Volume = ntohl(fh[1]);
+           fid.Fid.Vnode  = ntohl(fh[2]);
+           fid.Fid.Unique = ntohl(fh[3]);
+           break;
+
+       case AFSFH_NET_CELLFID:
+           if (fh_len != 7)
+               return NULL;
+           AFS_GLOCK();
+           tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
+           if (!tc) {
+               AFS_GUNLOCK();
+               return NULL;
+           }
+           fid.Cell       = tc->cellNum;
+           fid.Fid.Volume = ntohl(fh[4]);
+           fid.Fid.Vnode  = ntohl(fh[5]);
+           fid.Fid.Unique = ntohl(fh[6]);
+           afs_PutCell(tc, READ_LOCK);
+           AFS_GUNLOCK();
+           break;
+
+       case AFSFH_DYN_RO_CELL:
+       case AFSFH_DYN_RW_CELL:
+           if (fh_len != 4)
+               return NULL;
+           AFS_GLOCK();
+           tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
+           if (!tc) {
+               AFS_GUNLOCK();
+               return NULL;
+           }
+           afs_GetDynrootFid(&fid);
+           fid.Fid.Vnode  = VNUM_FROM_CIDX_RW(tc->cellIndex, fh_type & 1);
+           fid.Fid.Unique = 1;
+           afs_PutCell(tc, READ_LOCK);
+           AFS_GUNLOCK();
+           break;
+
+       case AFSFH_DYN_RO_LINK:
+       case AFSFH_DYN_RW_LINK:
+           if (fh_len != 4)
+               return NULL;
+           AFS_GLOCK();
+           tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
+           if (!tc) {
+               AFS_GUNLOCK();
+               return NULL;
+           }
+           afs_GetDynrootFid(&fid);
+           fid.Fid.Vnode  = VNUM_FROM_CAIDX_RW(tc->cellIndex, fh_type & 1);
+           fid.Fid.Unique = 1;
+           afs_PutCell(tc, READ_LOCK);
+           AFS_GUNLOCK();
+           break;
+
+       case AFSFH_DYN_MOUNT:
+           if (fh_len != 5)
+               return NULL;
+           AFS_GLOCK();
+           tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
+           if (!tc) {
+               AFS_GUNLOCK();
+               return NULL;
+           }
+           afs_GetDynrootFid(&fid);
+           fid.Fid.Vnode  = VNUM_FROM_TYPEID(VN_TYPE_MOUNT,
+                                             tc->cellIndex << 2);
+           fid.Fid.Unique = ntohl(fh[4]);
+           afs_PutCell(tc, READ_LOCK);
+           AFS_GUNLOCK();
+           break;
+
+       case AFSFH_DYN_SYMLINK:
+           /* XXX parse dynroot symlink filehandle */
+           /* break; */
+
+       default:
+           return NULL;
+    }
+
+    result = sb->s_export_op->find_exported_dentry(sb, &fid, 0,
+                                                  acceptable, context);
+#ifdef OSI_EXPORT_DEBUG
+    if (!result) {
+       printk("afs: decode_fh(0x%08x/%d/%d.%d): no dentry\n",
+              fid.Cell,      fid.Fid.Volume,
+              fid.Fid.Vnode, fid.Fid.Unique);
+    } else if (IS_ERR(result)) {
+       printk("afs: decode_fh(0x%08x/%d/%d.%d): error %ld\n",
+              fid.Cell,      fid.Fid.Volume,
+              fid.Fid.Vnode, fid.Fid.Unique, PTR_ERR(result));
+    }
+#endif
+    return result;
+}
+
+static int update_dir_parent(struct vrequest *areq, struct vcache *adp)
+{
+    struct VenusFid tfid;
+    struct dcache *tdc;
+    afs_size_t dirOffset, dirLen;
+    int code;
+
+redo:
+    if (!(adp->states & CStatd)) {
+       if ((code = afs_VerifyVCache2(adp, areq))) {
+#ifdef OSI_EXPORT_DEBUG
+           printk("afs: update_dir_parent(0x%08x/%d/%d.%d): VerifyVCache2: %d\n",
+                  adp->fid.Cell,      adp->fid.Fid.Volume,
+                  adp->fid.Fid.Vnode, adp->fid.Fid.Unique, code);
+#endif
+           return code;
+       }
+    }
+
+    tdc = afs_GetDCache(adp, (afs_size_t) 0, areq, &dirOffset, &dirLen, 1);
+    if (!tdc) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: update_dir_parent(0x%08x/%d/%d.%d): no dcache\n",
+              adp->fid.Cell,      adp->fid.Fid.Volume,
+              adp->fid.Fid.Vnode, adp->fid.Fid.Unique);
+#endif
+       return EIO;
+    }
+
+    /* now we will just call dir package with appropriate inode.
+     * Dirs are always fetched in their entirety for now */
+    ObtainSharedLock(&adp->lock, 801);
+    ObtainReadLock(&tdc->lock);
+
+    /*
+     * Make sure that the data in the cache is current. There are two
+     * cases we need to worry about:
+     * 1. The cache data is being fetched by another process.
+     * 2. The cache data is no longer valid
+     */
+    while ((adp->states & CStatd)
+          && (tdc->dflags & DFFetching)
+          && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
+       ReleaseReadLock(&tdc->lock);
+       ReleaseSharedLock(&adp->lock);
+       afs_osi_Sleep(&tdc->validPos);
+       ObtainSharedLock(&adp->lock, 802);
+       ObtainReadLock(&tdc->lock);
+    }
+    if (!(adp->states & CStatd)
+       || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
+       ReleaseReadLock(&tdc->lock);
+       ReleaseSharedLock(&adp->lock);
+       afs_PutDCache(tdc);
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: update_dir_parent(0x%08x/%d/%d.%d): dir changed; retrying\n",
+              adp->fid.Cell,      adp->fid.Fid.Volume,
+              adp->fid.Fid.Vnode, adp->fid.Fid.Unique);
+#endif
+       goto redo;
+    }
+
+    /* lookup the name in the appropriate dir, and return a cache entry
+     * on the resulting fid */
+    code = afs_dir_Lookup(tdc, "..", &tfid.Fid);
+
+    ReleaseReadLock(&tdc->lock);
+    afs_PutDCache(tdc);
+
+    if (!code) {
+       UpgradeSToWLock(&adp->lock, 803);
+       adp->parentVnode  = tfid.Fid.Vnode;
+       adp->parentUnique = tfid.Fid.Unique;
+    }
+#ifdef OSI_EXPORT_DEBUG
+    if (code) {
+       printk("afs: update_dir_parent(0x%08x/%d/%d.%d): afs_dir_Lookup: %d\n",
+              adp->fid.Cell,      adp->fid.Fid.Volume,
+              adp->fid.Fid.Vnode, adp->fid.Fid.Unique, code);
+    } else {
+       printk("afs: update_dir_parent(0x%08x/%d/%d.%d) => %d.%d\n",
+              adp->fid.Cell,      adp->fid.Fid.Volume,
+              adp->fid.Fid.Vnode, adp->fid.Fid.Unique,
+              adp->parentVnode,   adp->parentUnique);
+    }
+#endif
+    ReleaseSharedLock(&adp->lock);
+    return code;
+}
+
+
+static int UnEvalFakeStat(struct vrequest *areq, struct vcache **vcpp)
+{
+    struct VenusFid tfid;
+    struct volume *tvp;
+    struct vcache *tvc;
+    int code;
+
+    if (!afs_fakestat_enable)
+       return 0;
+
+    if (*vcpp == afs_globalVp || vType(*vcpp) != VDIR || (*vcpp)->mvstat != 2)
+       return 0;
+
+    /* Figure out what FID to look for */
+    tvp = afs_GetVolume(&(*vcpp)->fid, 0, READ_LOCK);
+    if (!tvp) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: UnEvalFakeStat(0x%08x/%d/%d.%d): no volume\n",
+              (*vcpp)->fid.Cell,      (*vcpp)->fid.Fid.Volume,
+              (*vcpp)->fid.Fid.Vnode, (*vcpp)->fid.Fid.Unique);
+#endif
+       return ENOENT;
+    }
+    tfid = tvp->mtpoint;
+    afs_PutVolume(tvp, READ_LOCK);
+
+    tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+    if (!tvc) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: UnEvalFakeStat(0x%08x/%d/%d.%d): GetVCache(0x%08x/%d/%d.%d) failed\n",
+              (*vcpp)->fid.Cell,      (*vcpp)->fid.Fid.Volume,
+              (*vcpp)->fid.Fid.Vnode, (*vcpp)->fid.Fid.Unique,
+              tfid.Cell,          tfid.Fid.Volume,
+              tfid.Fid.Vnode,     tfid.Fid.Unique);
+#endif
+       return ENOENT;
+    }
+
+    if (afs_fakestat_enable == 2) {
+       ObtainWriteLock(&tvc->lock, 806);
+       code = afs_HandleLink(tvc, areq);
+       if (code) {
+           ReleaseWriteLock(&tvc->lock);
+           afs_PutVCache(tvc);
+           return code;
+       }
+       if (!strchr(tvc->linkData, ':')) {
+           ReleaseWriteLock(&tvc->lock);
+           afs_PutVCache(tvc);
+           return 0;
+       }
+       ReleaseWriteLock(&tvc->lock);
+    }
+
+    afs_PutVCache(*vcpp);
+    *vcpp = tvc;
+    return 0;
+}
+
+
+/* 
+ * Given a FID, obtain or construct a dentry, or return an error.
+ * This should be called with the BKL and AFS_GLOCK held.
+ */
+static struct dentry *get_dentry_from_fid(cred_t *credp, struct VenusFid *afid)
+{
+    struct vrequest treq;
+    struct vcache *vcp;
+    struct vattr vattr;
+    struct inode *ip;
+    struct dentry *dp;
+    afs_int32 code;
+
+    code = afs_InitReq(&treq, credp);
+    if (code) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): afs_InitReq: %d\n",
+              afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique,
+              code);
+#endif
+       return ERR_PTR(-afs_CheckCode(code, &treq, 101));
+    }
+    vcp = afs_GetVCache(afid, &treq, NULL, NULL);
+    if (vcp == NULL) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): no vcache\n",
+              afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique);
+#endif
+       return NULL;
+    }
+
+    /* 
+     * Now, it might be that we just caused a directory vnode to
+     * spring into existence, in which case its parent FID is unset.
+     * We need to do something about that, but only because we care
+     * in our own get_parent(), below -- the common code never looks
+     * at parentVnode on directories, except for VIOCGETVCXSTATUS.
+     * So, if this fails, we don't really care very much.
+     */
+    if (vType(vcp) == VDIR && vcp->mvstat != 2 && !vcp->parentVnode)
+       update_dir_parent(&treq, vcp);
+
+    /*
+     * If this is a volume root directory and fakestat is enabled,
+     * we might need to replace the directory by a mount point.
+     */
+    code = UnEvalFakeStat(&treq, &vcp);
+    if (code) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): UnEvalFakeStat: %d\n",
+              afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique,
+              code);
+#endif
+       afs_PutVCache(vcp);
+       return ERR_PTR(-afs_CheckCode(code, &treq, 101));
+    }
+
+    ip = AFSTOV(vcp);
+    afs_getattr(vcp, &vattr, credp);
+    afs_fill_inode(ip, &vattr);
+
+    /* d_alloc_anon might block, so we shouldn't hold the glock */
+    AFS_GUNLOCK();
+    dp = d_alloc_anon(ip);
+    AFS_GLOCK();
+
+    if (!dp) {
+       iput(ip);
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): out of memory\n",
+              afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique);
+#endif
+       return ERR_PTR(-ENOMEM);
+    }
+
+    dp->d_op = &afs_dentry_operations;
+    return dp;
+}
+
+static struct dentry *afs_export_get_dentry(struct super_block *sb,
+                                           void *inump)
+{
+    struct dentry *dp;
+    cred_t *credp;
+
+    credp = crref();
+    lock_kernel();
+    AFS_GLOCK();
+
+    dp = get_dentry_from_fid(credp, inump);
+
+    AFS_GUNLOCK();
+    unlock_kernel();
+    crfree(credp);
+
+    return dp;
+}
+
+
+static int get_name_hook(void *hdata, char *name,
+                        afs_int32 vnode, afs_int32 unique)
+{
+    struct get_name_data *data = (struct get_name_data *)hdata;
+    int len;
+
+    if (vnode == data->fid.Fid.Vnode && unique == data->fid.Fid.Unique) {
+       len = strlen(name);
+       if (len > NAME_MAX) len = NAME_MAX;
+       memcpy(data->name, name, len);
+       data->name[len] = '\0';
+       data->found = 1;
+    }
+    return 0;
+}
+
+static int afs_export_get_name(struct dentry *parent, char *name,
+                              struct dentry *child)
+{
+    struct afs_fakestat_state fakestate;
+    struct get_name_data data;
+    struct vrequest treq;
+    struct volume *tvp;
+    struct vcache *vcp;
+    struct dcache *tdc;
+    cred_t *credp;
+    afs_size_t dirOffset, dirLen;
+    afs_int32 code = 0;
+
+    if (!parent->d_inode) {
+#ifdef OSI_EXPORT_DEBUG
+       /* can't lookup name in a negative dentry */
+       printk("afs: get_name(%s, %s): no parent inode\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              child->d_name.name  ? (char *)child->d_name.name  : "?");
+#endif
+       return -EIO;
+    }
+    if (!child->d_inode) {
+#ifdef OSI_EXPORT_DEBUG
+       /* can't find the FID of negative dentry */
+       printk("afs: get_name(%s, %s): no child inode\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              child->d_name.name  ? (char *)child->d_name.name  : "?");
+#endif
+       return -ENOENT;
+    }
+
+    afs_InitFakeStat(&fakestate);
+
+    credp = crref();
+    lock_kernel();
+    AFS_GLOCK();
+
+    vcp = VTOAFS(child->d_inode);
+
+    /* special case dynamic mount directory */
+    if (afs_IsDynrootMount(vcp)) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): this is the dynmount dir\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              vcp->fid.Cell,      vcp->fid.Fid.Volume,
+              vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique);
+#endif
+       data.fid = vcp->fid;
+       if (VTOAFS(parent->d_inode) == afs_globalVp)
+           strcpy(name, AFS_DYNROOT_MOUNTNAME);
+       else
+           code = -ENOENT;
+       goto done;
+    }
+
+    /* Figure out what FID to look for */
+    if (vcp->mvstat == 2) { /* volume root */
+       tvp = afs_GetVolume(&vcp->fid, 0, READ_LOCK);
+       if (!tvp) {
+#ifdef OSI_EXPORT_DEBUG
+           printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no volume for root\n",
+                  parent->d_name.name ? (char *)parent->d_name.name : "?",
+                  vcp->fid.Cell,      vcp->fid.Fid.Volume,
+                  vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique);
+#endif
+           code = ENOENT;
+           goto done;
+       }
+       data.fid = tvp->mtpoint;
+       afs_PutVolume(tvp, READ_LOCK);
+    } else {
+       data.fid = vcp->fid;
+    }
+
+    vcp = VTOAFS(parent->d_inode);
+#ifdef OSI_EXPORT_DEBUG
+    printk("afs: get_name(%s, 0x%08x/%d/%d.%d): parent is 0x%08x/%d/%d.%d\n",
+          parent->d_name.name ? (char *)parent->d_name.name : "?",
+          data.fid.Cell,      data.fid.Fid.Volume,
+          data.fid.Fid.Vnode, data.fid.Fid.Unique,
+          vcp->fid.Cell,      vcp->fid.Fid.Volume,
+          vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique);
+#endif
+
+    code = afs_InitReq(&treq, credp);
+    if (code) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): afs_InitReq: %d\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique, code);
+#endif
+       goto done;
+    }
+
+    /* a dynamic mount point in the dynamic mount directory */
+    if (afs_IsDynrootMount(vcp) && afs_IsDynrootAnyFid(&data.fid)
+       && VNUM_TO_VNTYPE(data.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dynamic mount point\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique);
+#endif
+       vcp = afs_GetVCache(&data.fid, &treq, NULL, NULL);
+       if (vcp) {
+           ObtainReadLock(&vcp->lock);
+           if (strlen(vcp->linkData + 1) <= NAME_MAX)
+               strcpy(name, vcp->linkData + 1);
+           else
+               code = ENOENT;
+           ReleaseReadLock(&vcp->lock);
+           afs_PutVCache(vcp);
+       } else {
+#ifdef OSI_EXPORT_DEBUG
+           printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no vcache\n",
+                  parent->d_name.name ? (char *)parent->d_name.name : "?",
+                  data.fid.Cell,      data.fid.Fid.Volume,
+                  data.fid.Fid.Vnode, data.fid.Fid.Unique);
+#endif
+           code = ENOENT;
+       }
+       goto done;
+    }
+
+    code = afs_EvalFakeStat(&vcp, &fakestate, &treq);
+    if (code)
+       goto done;
+
+    if (vcp->fid.Cell != data.fid.Cell ||
+       vcp->fid.Fid.Volume != data.fid.Fid.Volume) {
+       /* parent is not the expected cell and volume; thus it
+        * cannot possibly contain the fid we are looking for */
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): wrong parent 0x%08x/%d\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique,
+              vcp->fid.Cell,      vcp->fid.Fid.Volume);
+#endif
+       code = ENOENT;
+       goto done;
+    }
+
+
+redo:
+    if (!(vcp->states & CStatd)) {
+       if ((code = afs_VerifyVCache2(vcp, &treq))) {
+#ifdef OSI_EXPORT_DEBUG
+           printk("afs: get_name(%s, 0x%08x/%d/%d.%d): VerifyVCache2(0x%08x/%d/%d.%d): %d\n",
+                  parent->d_name.name ? (char *)parent->d_name.name : "?",
+                  data.fid.Cell,      data.fid.Fid.Volume,
+                  data.fid.Fid.Vnode, data.fid.Fid.Unique,
+                  vcp->fid.Cell,      vcp->fid.Fid.Volume,
+                  vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique, code);
+#endif
+           goto done;
+       }
+    }
+
+    tdc = afs_GetDCache(vcp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
+    if (!tdc) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): GetDCache(0x%08x/%d/%d.%d): %d\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique,
+              vcp->fid.Cell,      vcp->fid.Fid.Volume,
+              vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique, code);
+#endif
+       code = EIO;
+       goto done;
+    }
+
+    ObtainReadLock(&vcp->lock);
+    ObtainReadLock(&tdc->lock);
+
+    /*
+     * Make sure that the data in the cache is current. There are two
+     * cases we need to worry about:
+     * 1. The cache data is being fetched by another process.
+     * 2. The cache data is no longer valid
+     */
+    while ((vcp->states & CStatd)
+          && (tdc->dflags & DFFetching)
+          && hsame(vcp->m.DataVersion, tdc->f.versionNo)) {
+       ReleaseReadLock(&tdc->lock);
+       ReleaseReadLock(&vcp->lock);
+       afs_osi_Sleep(&tdc->validPos);
+       ObtainReadLock(&vcp->lock);
+       ObtainReadLock(&tdc->lock);
+    }
+    if (!(vcp->states & CStatd)
+       || !hsame(vcp->m.DataVersion, tdc->f.versionNo)) {
+       ReleaseReadLock(&tdc->lock);
+       ReleaseReadLock(&vcp->lock);
+       afs_PutDCache(tdc);
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dir (0x%08x/%d/%d.%d) changed; retrying\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique,
+              vcp->fid.Cell,      vcp->fid.Fid.Volume,
+              vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique);
+#endif
+       goto redo;
+    }
+
+    data.name  = name;
+    data.found = 0;
+    code = afs_dir_EnumerateDir(tdc, get_name_hook, &data);
+    if (!code && !data.found) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): not found\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique);
+#endif
+       code = ENOENT;
+    } else if (code) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d): Enumeratedir(0x%08x/%d/%d.%d): %d\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique,
+              vcp->fid.Cell,      vcp->fid.Fid.Volume,
+              vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique, code);
+#endif
+    }
+
+    ReleaseReadLock(&tdc->lock);
+    ReleaseReadLock(&vcp->lock);
+    afs_PutDCache(tdc);
+
+done:
+    if (!code) {
+       printk("afs: get_name(%s, 0x%08x/%d/%d.%d) => %s\n",
+              parent->d_name.name ? (char *)parent->d_name.name : "?",
+              data.fid.Cell,      data.fid.Fid.Volume,
+              data.fid.Fid.Vnode, data.fid.Fid.Unique, name);
+    }
+    afs_PutFakeStat(&fakestate);
+    AFS_GUNLOCK();
+    unlock_kernel();
+    crfree(credp);
+    code = afs_CheckCode(code, &treq, 102);
+    return -code;
+}
+
+
+static struct dentry *afs_export_get_parent(struct dentry *child)
+{
+    struct VenusFid tfid;
+    struct vrequest treq;
+    struct cell *tcell;
+    struct vcache *vcp;
+    struct dentry *dp = NULL;
+    cred_t *credp;
+    afs_uint32 cellidx;
+    int code;
+
+    if (!child->d_inode) {
+       /* can't find the parent of a negative dentry */
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_parent(%s): no inode\n",
+              child->d_name.name ? (char *)child->d_name.name : "?");
+#endif
+       return ERR_PTR(-EIO);
+    }
+
+    credp = crref();
+    lock_kernel();
+    AFS_GLOCK();
+
+    vcp = VTOAFS(child->d_inode);
+
+    if (afs_IsDynrootMount(vcp)) {
+       /* the dynmount directory; parent is always the AFS root */
+       tfid = afs_globalVp->fid;
+
+    } else if (afs_IsDynrootAny(vcp) &&
+              VNUM_TO_VNTYPE(vcp->fid.Fid.Vnode) == VN_TYPE_MOUNT) {
+       /* a mount point in the dynmount directory */
+       afs_GetDynrootMountFid(&tfid);
+
+    } else if (vcp->mvstat == 2) {
+       /* volume root */
+       ObtainReadLock(&vcp->lock);
+       if (vcp->mvid && vcp->mvid->Fid.Volume) {
+           tfid = *vcp->mvid;
+           ReleaseReadLock(&vcp->lock);
+       } else {
+           ReleaseReadLock(&vcp->lock);
+           tcell = afs_GetCell(vcp->fid.Cell, READ_LOCK);
+           if (!tcell) {
+#ifdef OSI_EXPORT_DEBUG
+               printk("afs: get_parent(0x%08x/%d/%d.%d): no cell\n",
+                      vcp->fid.Cell, vcp->fid.Fid.Volume,
+                      vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique);
+#endif
+               dp = ERR_PTR(-ENOENT);
+               goto done;
+           }
+
+           cellidx = tcell->cellIndex;
+           afs_PutCell(tcell, READ_LOCK);
+
+           afs_GetDynrootMountFid(&tfid);
+           tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
+           tfid.Fid.Unique = vcp->fid.Fid.Volume;
+       }
+
+    } else {
+       /* any other vnode */
+       if (vType(vcp) == VDIR && !vcp->parentVnode && vcp->mvstat != 1) {
+           code = afs_InitReq(&treq, credp);
+           if (code) {
+#ifdef OSI_EXPORT_DEBUG
+               printk("afs: get_parent(0x%08x/%d/%d.%d): InitReq: %d\n",
+                      vcp->fid.Cell, vcp->fid.Fid.Volume,
+                      vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique, code);
+#endif
+               dp = ERR_PTR(-ENOENT);
+               goto done;
+           } else {
+               code = update_dir_parent(&treq, vcp);
+               if (code) {
+#ifdef OSI_EXPORT_DEBUG
+                   printk("afs: get_parent(0x%08x/%d/%d.%d): update_dir_parent: %d\n",
+                          vcp->fid.Cell, vcp->fid.Fid.Volume,
+                          vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique, code);
+#endif
+                   dp = ERR_PTR(-ENOENT);
+                   goto done;
+               }
+           }
+       }
+
+       tfid.Cell       = vcp->fid.Cell;
+       tfid.Fid.Volume = vcp->fid.Fid.Volume;
+       tfid.Fid.Vnode  = vcp->parentVnode;
+       tfid.Fid.Unique = vcp->parentUnique;
+    }
+
+#ifdef OSI_EXPORT_DEBUG
+    printk("afs: get_parent(0x%08x/%d/%d.%d): => 0x%08x/%d/%d.%d\n",
+          vcp->fid.Cell, vcp->fid.Fid.Volume,
+          vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique,
+          tfid.Cell, tfid.Fid.Volume, tfid.Fid.Vnode, tfid.Fid.Unique);
+#endif
+
+    dp = get_dentry_from_fid(credp, &tfid);
+    if (!dp) {
+#ifdef OSI_EXPORT_DEBUG
+       printk("afs: get_parent(0x%08x/%d/%d.%d): no dentry\n",
+              vcp->fid.Cell, vcp->fid.Fid.Volume,
+              vcp->fid.Fid.Vnode, vcp->fid.Fid.Unique);
+#endif
+       dp = ERR_PTR(-ENOENT);
+    }
+
+done:
+    AFS_GUNLOCK();
+    unlock_kernel();
+    crfree(credp);
+
+    return dp;
+}
+
+
+struct export_operations afs_export_ops = {
+    .encode_fh  = afs_encode_fh,
+    .decode_fh  = afs_decode_fh,
+    .get_dentry = afs_export_get_dentry,
+    .get_name   = afs_export_get_name,
+    .get_parent = afs_export_get_parent,
+};
index 272d811..f096416 100644 (file)
@@ -20,10 +20,11 @@ RCSID
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* afs statistics */
 #include "h/smp_lock.h"
+#if defined(AFS_LINUX26_ENV)
+#include "h/namei.h"
+#endif
 
 
-int afs_osicred_initialized = 0;
-struct AFS_UCRED afs_osi_cred;
 afs_lock_t afs_xosi;           /* lock is for tvattr */
 extern struct osi_dev cacheDev;
 #if defined(AFS_LINUX24_ENV)
@@ -356,3 +357,190 @@ shutdown_osifile(void)
        afs_osicred_initialized = 0;
     }
 }
+
+/* Intialize cache device info and fragment size for disk cache partition. */
+int
+osi_InitCacheInfo(char *aname)
+{
+    int code;
+    struct dentry *dp;
+    extern ino_t cacheInode;
+    extern struct osi_dev cacheDev;
+    extern afs_int32 afs_fsfragsize;
+    extern struct super_block *afs_cacheSBp;
+    extern struct vfsmount *afs_cacheMnt;
+    code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
+    if (code)
+       return ENOENT;
+
+    cacheInode = dp->d_inode->i_ino;
+    cacheDev.dev = dp->d_inode->i_sb->s_dev;
+    afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
+    afs_cacheSBp = dp->d_inode->i_sb;
+
+    dput(dp);
+
+    return 0;
+}
+
+
+#define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
+#define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
+
+/* osi_rdwr
+ * seek, then read or write to an open inode. addrp points to data in
+ * kernel space.
+ */
+int
+osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
+{
+#ifdef AFS_LINUX26_ENV
+    struct file *filp = osifile->filp;
+#else
+    struct file *filp = &osifile->file;
+#endif
+    KERNEL_SPACE_DECL;
+    int code = 0;
+    struct iovec *iov;
+    afs_size_t count;
+    unsigned long savelim;
+
+    savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
+    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+
+    if (uiop->uio_seg == AFS_UIOSYS)
+       TO_USER_SPACE();
+
+    /* seek to the desired position. Return -1 on error. */
+    if (filp->f_op->llseek) {
+       if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
+           return -1;
+    } else
+       filp->f_pos = uiop->uio_offset;
+
+    while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
+       iov = uiop->uio_iov;
+       count = iov->iov_len;
+       if (count == 0) {
+           uiop->uio_iov++;
+           uiop->uio_iovcnt--;
+           continue;
+       }
+
+       if (rw == UIO_READ)
+           code = FOP_READ(filp, iov->iov_base, count);
+       else
+           code = FOP_WRITE(filp, iov->iov_base, count);
+
+       if (code < 0) {
+           code = -code;
+           break;
+       } else if (code == 0) {
+           /*
+            * This is bad -- we can't read any more data from the
+            * file, but we have no good way of signaling a partial
+            * read either.
+            */
+           code = EIO;
+           break;
+       }
+
+       iov->iov_base += code;
+       iov->iov_len -= code;
+       uiop->uio_resid -= code;
+       uiop->uio_offset += code;
+       code = 0;
+    }
+
+    if (uiop->uio_seg == AFS_UIOSYS)
+       TO_KERNEL_SPACE();
+
+    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
+
+    return code;
+}
+
+/* setup_uio 
+ * Setup a uio struct.
+ */
+void
+setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
+         int count, uio_flag_t flag, uio_seg_t seg)
+{
+    iovecp->iov_base = (char *)buf;
+    iovecp->iov_len = count;
+    uiop->uio_iov = iovecp;
+    uiop->uio_iovcnt = 1;
+    uiop->uio_offset = pos;
+    uiop->uio_seg = seg;
+    uiop->uio_resid = count;
+    uiop->uio_flag = flag;
+}
+
+
+/* uiomove
+ * UIO_READ : dp -> uio
+ * UIO_WRITE : uio -> dp
+ */
+int
+uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
+{
+    int count;
+    struct iovec *iov;
+    int code;
+
+    while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
+       iov = uiop->uio_iov;
+       count = iov->iov_len;
+
+       if (!count) {
+           uiop->uio_iov++;
+           uiop->uio_iovcnt--;
+           continue;
+       }
+
+       if (count > length)
+           count = length;
+
+       switch (uiop->uio_seg) {
+       case AFS_UIOSYS:
+           switch (rw) {
+           case UIO_READ:
+               memcpy(iov->iov_base, dp, count);
+               break;
+           case UIO_WRITE:
+               memcpy(dp, iov->iov_base, count);
+               break;
+           default:
+               printf("uiomove: Bad rw = %d\n", rw);
+               return -EINVAL;
+           }
+           break;
+       case AFS_UIOUSER:
+           switch (rw) {
+           case UIO_READ:
+               AFS_COPYOUT(dp, iov->iov_base, count, code);
+               break;
+           case UIO_WRITE:
+               AFS_COPYIN(iov->iov_base, dp, count, code);
+               break;
+           default:
+               printf("uiomove: Bad rw = %d\n", rw);
+               return -EINVAL;
+           }
+           break;
+       default:
+           printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
+           return -EINVAL;
+       }
+
+       dp += count;
+       length -= count;
+       iov->iov_base += count;
+       iov->iov_len -= count;
+       uiop->uio_offset += count;
+       uiop->uio_resid -= count;
+    }
+    return 0;
+}
+
diff --git a/src/afs/LINUX/osi_ioctl.c b/src/afs/LINUX/osi_ioctl.c
new file mode 100644 (file)
index 0000000..364241a
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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
+ */
+
+/*
+ * Linux module support routines.
+ *
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "h/unistd.h"          /* For syscall numbers. */
+#include "h/mm.h"
+
+#ifdef AFS_AMD64_LINUX20_ENV
+#include <asm/ia32_unistd.h>
+#endif
+#ifdef AFS_SPARC64_LINUX20_ENV
+#include <linux/ioctl32.h>
+#endif
+
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+extern struct proc_dir_entry *openafs_procfs;
+#if defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
+static int ioctl32_done;
+#endif
+
+extern asmlinkage long
+afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
+
+static int
+afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+         unsigned long arg)
+{
+
+    struct afsprocdata sysargs;
+#ifdef NEED_IOCTL32
+    struct afsprocdata32 sysargs32;
+#endif
+
+    if (cmd != VIOC_SYSCALL && cmd != VIOC_SYSCALL32) return -EINVAL;
+
+#ifdef NEED_IOCTL32
+#ifdef AFS_LINUX26_ENV 
+#ifdef AFS_S390X_LINUX26_ENV
+    if (test_thread_flag(TIF_31BIT))
+#elif AFS_AMD64_LINUX20_ENV
+    if (test_thread_flag(TIF_IA32))
+#else
+    if (test_thread_flag(TIF_32BIT))
+#endif /* AFS_S390X_LINUX26_ENV */
+#else
+#ifdef AFS_SPARC64_LINUX24_ENV
+    if (current->thread.flags & SPARC_FLAG_32BIT)
+#elif defined(AFS_SPARC64_LINUX20_ENV)
+    if (current->tss.flags & SPARC_FLAG_32BIT)
+#elif defined(AFS_AMD64_LINUX20_ENV)
+    if (current->thread.flags & THREAD_IA32)
+#elif defined(AFS_PPC64_LINUX20_ENV)
+    if (current->thread.flags & PPC_FLAG_32BIT)
+#elif defined(AFS_S390X_LINUX20_ENV)
+    if (current->thread.flags & S390_FLAG_31BIT)
+#else
+#error Not done for this linux type
+#endif /* AFS_LINUX26_ENV */
+#endif /* NEED_IOCTL32 */
+    {
+       if (copy_from_user(&sysargs32, (void *)arg,
+                          sizeof(struct afsprocdata32)))
+           return -EFAULT;
+
+       return afs_syscall((unsigned long)sysargs32.syscall,
+                          (unsigned long)sysargs32.param1,
+                          (unsigned long)sysargs32.param2,
+                          (unsigned long)sysargs32.param3,
+                          (unsigned long)sysargs32.param4);
+    } else
+#endif
+    {
+       if (copy_from_user(&sysargs, (void *)arg, sizeof(struct afsprocdata)))
+           return -EFAULT;
+
+       return afs_syscall(sysargs.syscall, sysargs.param1,
+                          sysargs.param2, sysargs.param3, sysargs.param4);
+    }
+}
+
+#if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COMPAT_IOCTL)
+static long afs_unlocked_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg) {
+    return afs_ioctl(FILE_INODE(file), file, cmd, arg);
+}
+#endif
+
+static struct file_operations afs_syscall_fops = {
+#ifdef HAVE_UNLOCKED_IOCTL
+    .unlocked_ioctl = afs_unlocked_ioctl,
+#else
+    .ioctl = afs_ioctl,
+#endif
+#ifdef HAVE_COMPAT_IOCTL
+    .compat_ioctl = afs_unlocked_ioctl,
+#endif
+};
+
+void
+osi_ioctl_init(void)
+{
+    struct proc_dir_entry *entry;
+
+    entry = create_proc_entry(PROC_SYSCALL_NAME, 0666, openafs_procfs);
+    entry->proc_fops = &afs_syscall_fops;
+    entry->owner = THIS_MODULE;
+
+#if defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
+    if (register_ioctl32_conversion(VIOC_SYSCALL32, NULL) == 0) 
+       ioctl32_done = 1;
+#endif
+}
+
+void
+osi_ioctl_clean(void)
+{
+    remove_proc_entry(PROC_SYSCALL_NAME, openafs_procfs);
+#if defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
+    if (ioctl32_done)
+           unregister_ioctl32_conversion(VIOC_SYSCALL32);
+#endif
+}
index 09b3f22..79314e7 100644 (file)
@@ -17,6 +17,7 @@
 RCSID
     ("$Header$");
 
+#include <linux/module.h> /* early to avoid printf->printk mapping */
 #include "afs/sysincludes.h"
 #include "afsincludes.h"
 #include "afs/afs_stats.h"
@@ -25,8 +26,63 @@ RCSID
 #endif
 #if defined(AFS_LINUX26_ENV)
 #include "h/namei.h"
+#include "h/kthread.h"
 #endif
 
+int afs_osicred_initialized = 0;
+struct AFS_UCRED afs_osi_cred;
+
+void
+afs_osi_SetTime(osi_timeval_t * tvp)
+{
+#if defined(AFS_LINUX24_ENV)
+
+#if defined(AFS_LINUX26_ENV)
+    struct timespec tv;
+    tv.tv_sec = tvp->tv_sec;
+    tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
+#else
+    struct timeval tv;
+    tv.tv_sec = tvp->tv_sec;
+    tv.tv_usec = tvp->tv_usec;
+#endif
+
+    AFS_STATCNT(osi_SetTime);
+
+    do_settimeofday(&tv);
+#else
+    extern int (*sys_settimeofdayp) (struct timeval * tv,
+                                    struct timezone * tz);
+
+    KERNEL_SPACE_DECL;
+
+    AFS_STATCNT(osi_SetTime);
+
+    TO_USER_SPACE();
+    if (sys_settimeofdayp)
+       (void)(*sys_settimeofdayp) (tvp, NULL);
+    TO_KERNEL_SPACE();
+#endif
+}
+
+struct task_struct *rxk_ListenerTask;
+
+void
+osi_linux_mask(void)
+{
+    SIG_LOCK(current);
+    sigfillset(&current->blocked);
+    RECALC_SIGPENDING(current);
+    SIG_UNLOCK(current);
+}
+
+void
+osi_linux_rxkreg(void)
+{
+    rxk_ListenerTask = current;
+}
+
+
 #if defined(AFS_LINUX24_ENV)
 /* LOOKUP_POSITIVE is becoming the default */
 #ifndef LOOKUP_POSITIVE
@@ -105,262 +161,56 @@ osi_lookupname(char *aname, uio_seg_t seg, int followlink, struct dentry **dpp)
 }
 #endif
 
-/* Intialize cache device info and fragment size for disk cache partition. */
-int
-osi_InitCacheInfo(char *aname)
-{
-    int code;
-    struct dentry *dp;
-    extern ino_t cacheInode;
-    extern struct osi_dev cacheDev;
-    extern afs_int32 afs_fsfragsize;
-    extern struct super_block *afs_cacheSBp;
-    extern struct vfsmount *afs_cacheMnt;
-    code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
-    if (code)
-       return ENOENT;
-
-    cacheInode = dp->d_inode->i_ino;
-    cacheDev.dev = dp->d_inode->i_sb->s_dev;
-    afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
-    afs_cacheSBp = dp->d_inode->i_sb;
-
-    dput(dp);
 
-    return 0;
-}
-
-
-#define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
-#define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
-
-/* osi_rdwr
- * seek, then read or write to an open inode. addrp points to data in
- * kernel space.
- */
-int
-osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
-{
 #ifdef AFS_LINUX26_ENV
-    struct file *filp = osifile->filp;
-#else
-    struct file *filp = &osifile->file;
-#endif
-    KERNEL_SPACE_DECL;
-    int code = 0;
-    struct iovec *iov;
-    afs_size_t count;
-    unsigned long savelim;
-
-    savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
-    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
-
-    if (uiop->uio_seg == AFS_UIOSYS)
-       TO_USER_SPACE();
-
-    /* seek to the desired position. Return -1 on error. */
-    if (filp->f_op->llseek) {
-       if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
-           return -1;
-    } else
-       filp->f_pos = uiop->uio_offset;
-
-    while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
-       iov = uiop->uio_iov;
-       count = iov->iov_len;
-       if (count == 0) {
-           uiop->uio_iov++;
-           uiop->uio_iovcnt--;
-           continue;
-       }
-
-       if (rw == UIO_READ)
-           code = FOP_READ(filp, iov->iov_base, count);
-       else
-           code = FOP_WRITE(filp, iov->iov_base, count);
-
-       if (code < 0) {
-           code = -code;
-           break;
-       } else if (code == 0) {
-           /*
-            * This is bad -- we can't read any more data from the
-            * file, but we have no good way of signaling a partial
-            * read either.
-            */
-           code = EIO;
-           break;
-       }
-
-       iov->iov_base += code;
-       iov->iov_len -= code;
-       uiop->uio_resid -= code;
-       uiop->uio_offset += code;
-       code = 0;
-    }
-
-    if (uiop->uio_seg == AFS_UIOSYS)
-       TO_KERNEL_SPACE();
-
-    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
-
-    return code;
-}
-
-/* setup_uio 
- * Setup a uio struct.
+/* This is right even for Linux 2.4, but on that version d_path is inline
+ * and implemented in terms of __d_path, which is not exported.
  */
-void
-setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
-         int count, uio_flag_t flag, uio_seg_t seg)
+int osi_abspath(char *aname, char *buf, int buflen,
+               int followlink, char **pathp)
 {
-    iovecp->iov_base = (char *)buf;
-    iovecp->iov_len = count;
-    uiop->uio_iov = iovecp;
-    uiop->uio_iovcnt = 1;
-    uiop->uio_offset = pos;
-    uiop->uio_seg = seg;
-    uiop->uio_resid = count;
-    uiop->uio_flag = flag;
-}
-
-
-/* uiomove
- * UIO_READ : dp -> uio
- * UIO_WRITE : uio -> dp
- */
-int
-uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
-{
-    int count;
-    struct iovec *iov;
+    struct dentry *dp = NULL;
+    struct vfsmnt *mnt = NULL;
+    char *tname, *path;
     int code;
 
-    while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
-       iov = uiop->uio_iov;
-       count = iov->iov_len;
-
-       if (!count) {
-           uiop->uio_iov++;
-           uiop->uio_iovcnt--;
-           continue;
-       }
-
-       if (count > length)
-           count = length;
+    code = ENOENT;
+    tname = getname(aname);
+    if (IS_ERR(tname)) 
+       return -PTR_ERR(tname);
+    code = osi_lookupname_internal(tname, followlink, &mnt, &dp);   
+    if (!code) {
+       path = d_path(dp, mnt, buf, buflen);
 
-       switch (uiop->uio_seg) {
-       case AFS_UIOSYS:
-           switch (rw) {
-           case UIO_READ:
-               memcpy(iov->iov_base, dp, count);
-               break;
-           case UIO_WRITE:
-               memcpy(dp, iov->iov_base, count);
-               break;
-           default:
-               printf("uiomove: Bad rw = %d\n", rw);
-               return -EINVAL;
-           }
-           break;
-       case AFS_UIOUSER:
-           switch (rw) {
-           case UIO_READ:
-               AFS_COPYOUT(dp, iov->iov_base, count, code);
-               break;
-           case UIO_WRITE:
-               AFS_COPYIN(iov->iov_base, dp, count, code);
-               break;
-           default:
-               printf("uiomove: Bad rw = %d\n", rw);
-               return -EINVAL;
-           }
-           break;
-       default:
-           printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
-           return -EINVAL;
+       if (IS_ERR(path)) {
+           code = -PTR_ERR(path);
+       } else {
+           *pathp = path;
        }
 
-       dp += count;
-       length -= count;
-       iov->iov_base += count;
-       iov->iov_len -= count;
-       uiop->uio_offset += count;
-       uiop->uio_resid -= count;
+       dput(dp);
+       mntput(mnt);
     }
-    return 0;
-}
-
-void
-afs_osi_SetTime(osi_timeval_t * tvp)
-{
-#if defined(AFS_LINUX24_ENV)
-
-#if defined(AFS_LINUX26_ENV)
-    struct timespec tv;
-    tv.tv_sec = tvp->tv_sec;
-    tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
-#else
-    struct timeval tv;
-    tv.tv_sec = tvp->tv_sec;
-    tv.tv_usec = tvp->tv_usec;
-#endif
 
-    AFS_STATCNT(osi_SetTime);
-
-    do_settimeofday(&tv);
-#else
-    extern int (*sys_settimeofdayp) (struct timeval * tv,
-                                    struct timezone * tz);
-
-    KERNEL_SPACE_DECL;
-
-    AFS_STATCNT(osi_SetTime);
-
-    TO_USER_SPACE();
-    if (sys_settimeofdayp)
-       (void)(*sys_settimeofdayp) (tvp, NULL);
-    TO_KERNEL_SPACE();
-#endif
-}
-
-/* osi_linux_free_inode_pages
- *
- * Free all vnodes remaining in the afs hash.  Must be done before
- * shutting down afs and freeing all memory.
- */
-void
-osi_linux_free_inode_pages(void)
-{
-    int i;
-    struct vcache *tvc, *nvc;
-    extern struct vcache *afs_vhashT[VCSIZE];
-
-    for (i = 0; i < VCSIZE; i++) {
-       for (tvc = afs_vhashT[i]; tvc; ) {
-           int slept;
-       
-           nvc = tvc->hnext;
-           if (afs_FlushVCache(tvc, &slept))           /* slept always 0 for linux? */
-               printf("Failed to invalidate all pages on inode 0x%p\n", tvc);
-           tvc = nvc;
-       }
-    }
+    putname(tname);
+    return code;
 }
 
-struct task_struct *rxk_ListenerTask;
 
-void
-osi_linux_mask(void)
+/* This could use some work, and support on more platforms. */
+int afs_thread_wrapper(void *rock)
 {
-    SIG_LOCK(current);
-    sigfillset(&current->blocked);
-    RECALC_SIGPENDING(current);
-    SIG_UNLOCK(current);
+    void (*proc)(void) = rock;
+    __module_get(THIS_MODULE);
+    AFS_GLOCK();
+    (*proc)();
+    AFS_GUNLOCK();
+    module_put(THIS_MODULE);
+    return 0;
 }
 
-void
-osi_linux_rxkreg(void)
+void afs_start_thread(void (*proc)(void), char *name)
 {
-    rxk_ListenerTask = current;
+    kthread_run(afs_thread_wrapper, proc, "%s", name);
 }
+#endif
index 29a016f..33c3327 100644 (file)
@@ -38,10 +38,6 @@ RCSID
 #include <linux/kernel.h>
 #endif
 
-#ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
-#include <linux/seq_file.h>
-#endif
-
 extern struct file_system_type afs_fs_type;
 
 #if !defined(AFS_LINUX24_ENV)
@@ -86,6 +82,9 @@ init_module(void)
 #endif /* !defined(AFS_LINUX24_ENV) */
 
     osi_Init();
+#ifdef AFS_LINUX26_ENV
+    osi_linux_nfssrv_init();
+#endif
 
     err = osi_syscall_init();
     if (err)
@@ -96,7 +95,8 @@ init_module(void)
     register_filesystem(&afs_fs_type);
     osi_sysctl_init();
 #ifdef AFS_LINUX24_ENV
-    afsproc_init();
+    osi_proc_init();
+    osi_ioctl_init();
 #endif
 
     return 0;
@@ -115,10 +115,14 @@ cleanup_module(void)
     unregister_filesystem(&afs_fs_type);
 
     afs_destroy_inodecache();
+#ifdef AFS_LINUX26_ENV
+    osi_linux_nfssrv_shutdown();
+#endif
     osi_linux_free_afs_memory();
 
 #ifdef AFS_LINUX24_ENV
-    afsproc_exit();
+    osi_ioctl_clean();
+    osi_proc_clean();
 #endif
     return;
 }
diff --git a/src/afs/LINUX/osi_nfssrv.c b/src/afs/LINUX/osi_nfssrv.c
new file mode 100644 (file)
index 0000000..57be4bb
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * vi:set cin noet sw=4 tw=70:
+ * Copyright 2006, 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
+ */
+
+/*
+ * Filesystem export operations for Linux
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "nfsclient.h"
+#include "h/smp_lock.h"
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svcauth.h>
+
+static unsigned long authtab_addr = 0;
+MODULE_PARM(authtab_addr, "l");
+MODULE_PARM_DESC(authtab_addr, "Address of the authtab array.");
+
+extern struct auth_ops *authtab[] __attribute__((weak));
+static struct auth_ops **afs_authtab;
+static struct auth_ops *afs_new_authtab[RPC_AUTH_MAXFLAVOR];
+static struct auth_ops *afs_orig_authtab[RPC_AUTH_MAXFLAVOR];
+
+static int whine_memory = 0;
+
+afs_lock_t afs_xnfssrv;
+
+struct nfs_server_thread {
+    struct nfs_server_thread *next;    /* next in chain */
+    pid_t pid;                         /* pid of this thread */
+    int active;                                /* this thread is servicing an RPC */
+    struct sockaddr_in client_addr;    /* latest client of this thread */
+    int client_addrlen;
+    afs_int32 uid;                     /* AFS UID/PAG for this thread */
+    afs_int32 code;                    /* What should InitReq return? */
+    int flavor;                                /* auth flavor */
+    uid_t client_uid;                  /* UID claimed by client */
+    gid_t client_gid;                  /* GID claimed by client */
+    gid_t client_g0, client_g1;                /* groups claimed by client */
+};
+
+static struct nfs_server_thread *nfssrv_list = 0;
+
+static struct nfs_server_thread *find_nfs_thread(int create)
+{
+    struct nfs_server_thread *this;
+
+    /* Check that this is an nfsd kernel thread */
+    if (current->files != init_task.files || strcmp(current->comm, "nfsd"))
+       return 0;
+
+    ObtainWriteLock(&afs_xnfssrv, 804);
+    for (this = nfssrv_list; this; this = this->next)
+       if (this->pid == current->pid)
+           break;
+    if (!this && create) {
+       this = afs_osi_Alloc(sizeof(struct nfs_server_thread));
+       if (this) {
+           this->next = nfssrv_list;
+           this->pid  = current->pid;
+           this->client_addrlen = 0;
+           nfssrv_list = this;
+           printk("afs: added nfsd task %d/%d\n",
+                  current->tgid, current->pid);
+       } else if (!whine_memory) {
+           whine_memory = 1;
+           printk("afs: failed to allocate memory for nfsd task %d/%d\n",
+                  current->tgid, current->pid);
+       }
+    }
+    ReleaseWriteLock(&afs_xnfssrv);
+    return this;
+}
+
+static int
+svcauth_afs_accept(struct svc_rqst *rqstp, u32 *authp)
+{
+    struct nfs_server_thread *ns;
+    struct afs_exporter *outexp;
+    struct AFS_UCRED *credp;
+    int code;
+
+    code = afs_orig_authtab[rqstp->rq_authop->flavour]->accept(rqstp, authp);
+    if (code != SVC_OK)
+       return code;
+
+    AFS_GLOCK();
+    ns = find_nfs_thread(1);
+    if (!ns) {
+       AFS_GUNLOCK();
+       /* XXX maybe we should fail this with rpc_system_err? */
+       return SVC_OK;
+    }
+
+    ns->active         = 1;
+    ns->flavor         = rqstp->rq_authop->flavour;
+    ns->code           = EACCES;
+    ns->client_addr    = rqstp->rq_addr;
+    ns->client_addrlen = rqstp->rq_addrlen;
+    ns->client_uid     = rqstp->rq_cred.cr_uid;
+    ns->client_gid     = rqstp->rq_cred.cr_gid;
+    if (rqstp->rq_cred.cr_group_info->ngroups > 0)
+       ns->client_g0   = GROUP_AT(rqstp->rq_cred.cr_group_info, 0);
+    else
+       ns->client_g0   = -1;
+    if (rqstp->rq_cred.cr_group_info->ngroups > 1)
+       ns->client_g1   = GROUP_AT(rqstp->rq_cred.cr_group_info, 1);
+    else
+       ns->client_g1   = -1;
+
+    /* NB: Don't check the length; it's not always filled in! */
+    if (rqstp->rq_addr.sin_family != AF_INET) {
+       printk("afs: NFS request from non-IPv4 client (family %d len %d)\n",
+              rqstp->rq_addr.sin_family, rqstp->rq_addrlen);
+       goto done;
+    }
+
+    credp = crget();
+    credp->cr_uid = rqstp->rq_cred.cr_uid;
+    credp->cr_gid = rqstp->rq_cred.cr_gid;
+    get_group_info(rqstp->rq_cred.cr_group_info);
+    credp->cr_group_info = rqstp->rq_cred.cr_group_info;
+
+    /* avoid creating wildcard entries by mapping anonymous
+     * clients to afs_nobody */
+    if (credp->cr_uid == -1)
+       credp->cr_uid = -2;
+    code = afs_nfsclient_reqhandler(0, &credp, rqstp->rq_addr.sin_addr.s_addr,
+                                   &ns->uid, &outexp);
+    if (!code && outexp) EXP_RELE(outexp);
+    if (!code) ns->code = 0;
+    if (code)
+       printk("afs: svcauth_afs_accept: afs_nfsclient_reqhandler: %d\n", code);
+    crfree(credp);
+
+done:
+    AFS_GUNLOCK();
+    return SVC_OK;
+}
+
+
+#if 0
+/* This doesn't work, because they helpfully NULL out rqstp->authop
+ * before calling us, so we have no way to tell what the original
+ * auth flavor was.
+ */
+static int
+svcauth_afs_release(struct svc_rqst *rqstp)
+{
+    struct nfs_server_thread *ns;
+
+    AFS_GLOCK();
+    ns = find_nfs_thread(0);
+    if (ns) ns->active = 0;
+    AFS_GUNLOCK();
+
+    return afs_orig_authtab[rqstp->rq_authop->flavour]->release(rqstp);
+}
+#endif
+
+
+int osi_linux_nfs_initreq(struct vrequest *av, struct AFS_UCRED *cr, int *code)
+{
+    struct nfs_server_thread *ns;
+
+    ns = find_nfs_thread(0);
+    if (!ns || !ns->active)
+       return 0;
+
+    *code = ns->code;
+    if (!ns->code) {
+       cr->cr_ruid = NFSXLATOR_CRED;
+       av->uid = ns->uid;
+    }
+    return 1;
+}
+
+void osi_linux_nfssrv_init(void)
+{
+    int i;
+
+    nfssrv_list = 0;
+    RWLOCK_INIT(&afs_xnfssrv, "afs_xnfssrv");
+
+    if (authtab)          afs_authtab = authtab;
+    else if (authtab_addr) afs_authtab = (struct auth_ops **)authtab_addr;
+    else {
+       printk("Warning: Unable to find the address of authtab\n");
+       printk("NFS Translator hooks will not be installed\n");
+       printk("To correct, specify authtab_addr=<authtab>\n");
+       afs_authtab = 0;
+       return;
+    }
+
+    for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
+       afs_orig_authtab[i] = afs_authtab[i];
+       if (!afs_orig_authtab[i] || afs_orig_authtab[i]->flavour != i ||
+           !try_module_get(afs_orig_authtab[i]->owner)) {
+           afs_orig_authtab[i] = 0;
+           continue;
+       }
+
+       afs_new_authtab[i] = afs_osi_Alloc(sizeof(struct auth_ops));
+       *(afs_new_authtab[i]) = *(afs_orig_authtab[i]);
+       afs_new_authtab[i]->owner = THIS_MODULE;
+       afs_new_authtab[i]->accept = svcauth_afs_accept;
+       /* afs_new_authtab[i]->release = svcauth_afs_release; */
+       svc_auth_unregister(i);
+       svc_auth_register(i, afs_new_authtab[i]);
+    }
+}
+
+void osi_linux_nfssrv_shutdown(void)
+{
+    struct nfs_server_thread *next;
+    int i;
+
+    if (afs_authtab) {
+       for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
+           if (!afs_orig_authtab[i])
+               continue;
+           svc_auth_unregister(i);
+           svc_auth_register(i, afs_orig_authtab[i]);
+           module_put(afs_orig_authtab[i]->owner);
+           afs_osi_Free(afs_new_authtab[i], sizeof(struct auth_ops));
+       }
+    }
+
+    AFS_GLOCK();
+    ObtainWriteLock(&afs_xnfssrv, 805);
+    while (nfssrv_list) {
+       next = nfssrv_list->next;
+       afs_osi_Free(nfssrv_list, sizeof(struct nfs_server_thread));
+       nfssrv_list = next;
+    }
+    ReleaseWriteLock(&afs_xnfssrv);
+    AFS_GUNLOCK();
+}
diff --git a/src/afs/LINUX/osi_pag_module.c b/src/afs/LINUX/osi_pag_module.c
new file mode 100644 (file)
index 0000000..7c05777
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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
+ */
+
+/*
+ * Linux module support routines.
+ *
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "h/unistd.h"          /* For syscall numbers. */
+#include "h/mm.h"
+
+#ifdef AFS_AMD64_LINUX20_ENV
+#include <asm/ia32_unistd.h>
+#endif
+#ifdef AFS_SPARC64_LINUX20_ENV
+#include <linux/ioctl32.h>
+#endif
+
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#endif
+
+static unsigned long nfs_server_addr = 0;
+MODULE_PARM(nfs_server_addr,  "l");
+MODULE_PARM_DESC(nfs_server_addr,  "IP Address of NFS Server");
+
+static char *this_cell = 0;
+MODULE_PARM(this_cell, "s");
+MODULE_PARM_DESC(this_cell, "Local cell name");
+
+#if defined(AFS_LINUX24_ENV)
+DECLARE_MUTEX(afs_global_lock);
+struct proc_dir_entry *openafs_procfs;
+#else
+struct semaphore afs_global_lock = MUTEX;
+#endif
+int afs_global_owner = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+int __init
+afspag_init(void)
+#else
+int
+init_module(void)
+#endif
+{
+    int err;
+
+    osi_Init();
+
+    err = osi_syscall_init();
+    if (err)
+       return err;
+#ifdef AFS_LINUX24_ENV
+    openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
+    osi_ioctl_init();
+#endif
+
+    afspag_Init(htonl(nfs_server_addr));
+    if (this_cell)
+       afspag_SetPrimaryCell(this_cell);
+
+    return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+void __exit
+afspag_cleanup(void)
+#else
+void
+cleanup_module(void)
+#endif
+{
+    osi_syscall_clean();
+
+    osi_linux_free_afs_memory();
+
+#ifdef AFS_LINUX24_ENV
+    osi_ioctl_clean();
+    remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
+#endif
+    return;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+MODULE_LICENSE("http://www.openafs.org/dl/license10.html");
+module_init(afspag_init);
+module_exit(afspag_cleanup);
+#endif
+
+#ifdef AFS_LINUX26_ENV
+/* Hack alert!
+ * These will never be called in the standalone PAG manager, because
+ * they are only referenced in afs_InitReq, and nothing calls that.
+ * However, we need to define them in order to resolve the reference,
+ * unless we want to move afs_InitReq out of afs_osi_pag.c.
+ */
+int osi_linux_nfs_initreq(struct vrequest *av, struct AFS_UCRED *cr, int *code)
+{
+    *code = EACCES;
+    return 1;
+}
+
+int
+afs_nfsclient_reqhandler(struct afs_exporter *exporter,
+                        struct AFS_UCRED **cred,
+                        afs_int32 host, afs_int32 *pagparam,
+                        struct afs_exporter **outexporter)
+{
+    return EINVAL;
+}
+#endif
diff --git a/src/afs/LINUX/osi_proc.c b/src/afs/LINUX/osi_proc.c
new file mode 100644 (file)
index 0000000..497d496
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * 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
+ */
+
+/*
+ * Linux module support routines.
+ *
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "afs/nfsclient.h"
+#include "h/unistd.h"          /* For syscall numbers. */
+#include "h/mm.h"
+
+#ifdef AFS_AMD64_LINUX20_ENV
+#include <asm/ia32_unistd.h>
+#endif
+
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
+#include <linux/seq_file.h>
+#endif
+
+struct proc_dir_entry *openafs_procfs;
+
+#ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       struct afs_q *cq, *tq;
+       loff_t n = 0;
+
+       ObtainReadLock(&afs_xcell);
+       for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
+               tq = QNext(cq);
+
+               if (n++ == *pos)
+                       break;
+       }
+       if (cq == &CellLRU)
+               return NULL;
+
+       return cq;
+}
+
+static void *c_next(struct seq_file *m, void *p, loff_t *pos)
+{
+       struct afs_q *cq = p, *tq;
+
+       (*pos)++;
+       tq = QNext(cq);
+
+       if (tq == &CellLRU)
+               return NULL;
+
+       return tq;
+}
+
+static void c_stop(struct seq_file *m, void *p)
+{
+       ReleaseReadLock(&afs_xcell);
+}
+
+static int c_show(struct seq_file *m, void *p)
+{
+       struct afs_q *cq = p;
+       struct cell *tc = QTOC(cq);
+       int j;
+
+       seq_printf(m, ">%s #(%d/%d)\n", tc->cellName,
+                  tc->cellNum, tc->cellIndex);
+
+       for (j = 0; j < MAXCELLHOSTS; j++) {
+               afs_uint32 addr;
+
+               if (!tc->cellHosts[j]) break;
+
+               addr = tc->cellHosts[j]->addr->sa_ip;
+               seq_printf(m, "%u.%u.%u.%u #%u.%u.%u.%u\n",
+                          NIPQUAD(addr), NIPQUAD(addr));
+       }
+
+       return 0;
+}
+
+static struct seq_operations afs_csdb_op = {
+       .start          = c_start,
+       .next           = c_next,
+       .stop           = c_stop,
+       .show           = c_show,
+};
+
+static int afs_csdb_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &afs_csdb_op);
+}
+
+static struct file_operations afs_csdb_operations = {
+       .open           = afs_csdb_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+
+static void *uu_start(struct seq_file *m, loff_t *pos)
+{
+    struct unixuser *tu;
+    loff_t n = 0;
+    afs_int32 i;
+
+    ObtainReadLock(&afs_xuser);
+    if (!*pos)
+       return (void *)(1);
+
+    for (i = 0; i < NUSERS; i++) {
+       for (tu = afs_users[i]; tu; tu = tu->next) {
+           if (++n == *pos)
+               return tu;
+       }
+    }
+
+    return NULL;
+}
+
+static void *uu_next(struct seq_file *m, void *p, loff_t *pos)
+{
+    struct unixuser *tu = p;
+    afs_int32 i = 0;
+
+    (*pos)++;
+    if (!p) return NULL;
+
+    if (p != (void *)1) {
+       if (tu->next) return tu->next;
+       i = UHash(tu->uid) + 1;
+    }
+
+    for (; i < NUSERS; i++)
+       if (afs_users[i]) return afs_users[i];
+    return NULL;
+}
+
+static void uu_stop(struct seq_file *m, void *p)
+{
+    ReleaseReadLock(&afs_xuser);
+}
+
+static int uu_show(struct seq_file *m, void *p)
+{
+    struct cell *tc = 0;
+    struct unixuser *tu = p;
+    char *cellname;
+
+    if (p == (void *)1) {
+       seq_printf(m, "%10s %4s %-6s  %-25s %10s",
+                  "UID/PAG", "Refs", "States", "Cell", "ViceID");
+       seq_printf(m, "  %10s %10s %10s %3s",
+                  "Tok Set", "Tok Begin", "Tok Expire", "vno");
+       seq_printf(m, "  %-15s %10s %10s %s\n",
+                  "NFS Client", "UID/PAG", "Client UID", "Sysname(s)");
+
+       return 0;
+    }
+
+    if (tu->cell == -1) {
+       cellname = "<default>";
+    } else {
+       tc = afs_GetCellStale(tu->cell, READ_LOCK);
+       if (tc) cellname = tc->cellName;
+       else cellname = "<unknown>";
+    }
+
+    seq_printf(m, "%10d %4d %04x    %-25s %10d",
+              tu->uid, tu->refCount, tu->states, cellname, tu->vid);
+
+    if (tc) afs_PutCell(tc, READ_LOCK);
+
+    if (tu->states & UHasTokens) {
+       seq_printf(m, "  %10d %10d %10d %3d",
+                  tu->tokenTime, tu->ct.BeginTimestamp, tu->ct.EndTimestamp,
+                  tu->ct.AuthHandle);
+    } else {
+       seq_printf(m, "  %-36s", "Tokens Not Set");
+    }
+
+    if (tu->exporter && tu->exporter->exp_type == EXP_NFS) {
+       struct nfsclientpag *np = (struct nfsclientpag *)(tu->exporter);
+        char ipaddr[16];
+       int i;
+
+        sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(np->host));
+       seq_printf(m, "  %-15s %10d %10d", ipaddr, np->uid, np->client_uid);
+       if (np->sysnamecount) {
+           for (i = 0; i < np->sysnamecount; i++)
+               seq_printf(m, " %s", np->sysname[i]);
+       } else { 
+           seq_printf(m, " <no sysname list>");
+       }
+
+    } else if (tu->exporter) {
+       seq_printf(m, "  Unknown exporter type %d", tu->exporter->exp_type);
+    }
+    seq_printf(m, "\n");
+
+    return 0;
+}
+
+static struct seq_operations afs_unixuser_seqop = {
+    .start             = uu_start,
+    .next              = uu_next,
+    .stop              = uu_stop,
+    .show              = uu_show,
+};
+
+static int afs_unixuser_open(struct inode *inode, struct file *file)
+{
+    return seq_open(file, &afs_unixuser_seqop);
+}
+
+static struct file_operations afs_unixuser_fops = {
+    .open              = afs_unixuser_open,
+    .read              = seq_read,
+    .llseek            = seq_lseek,
+    .release   = seq_release,
+};
+
+
+#else /* HAVE_KERNEL_LINUX_SEQ_FILE_H */
+
+static int
+csdbproc_info(char *buffer, char **start, off_t offset, int
+length)
+{
+    int len = 0;
+    off_t pos = 0;
+    int cnt;
+    struct afs_q *cq, *tq;
+    struct cell *tc;
+    char tbuffer[16];
+    /* 90 - 64 cellname, 10 for 32 bit num and index, plus
+       decor */
+    char temp[91];
+    afs_uint32 addr;
+    
+    ObtainReadLock(&afs_xcell);
+
+    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
+        tc = QTOC(cq); tq = QNext(cq);
+
+        pos += 90;
+
+        if (pos <= offset) {
+            len = 0;
+        } else {
+            sprintf(temp, ">%s #(%d/%d)\n", tc->cellName, 
+                    tc->cellNum, tc->cellIndex);
+            sprintf(buffer + len, "%-89s\n", temp);
+            len += 90;
+            if (pos >= offset+length) {
+                ReleaseReadLock(&afs_xcell);
+                goto done;
+            }
+        }
+
+        for (cnt = 0; cnt < MAXCELLHOSTS; cnt++) {
+            if (!tc->cellHosts[cnt]) break;
+            pos += 90;
+            if (pos <= offset) {
+                len = 0;
+            } else {
+                addr = ntohl(tc->cellHosts[cnt]->addr->sa_ip);
+                sprintf(tbuffer, "%d.%d.%d.%d", 
+                        (int)((addr>>24) & 0xff),
+(int)((addr>>16) & 0xff),
+                        (int)((addr>>8)  & 0xff), (int)( addr & 0xff));
+                sprintf(temp, "%s #%s\n", tbuffer, tbuffer);
+                sprintf(buffer + len, "%-89s\n", temp);
+                len += 90;
+                if (pos >= offset+length) {
+                    ReleaseReadLock(&afs_xcell);
+                    goto done;
+                }
+            }
+        }
+    }
+
+    ReleaseReadLock(&afs_xcell);
+    
+done:
+    *start = buffer + len - (pos - offset);
+    len = pos - offset;
+    if (len > length)
+        len = length;
+    return len;
+}
+
+#endif /* HAVE_KERNEL_LINUX_SEQ_FILE_H */
+
+void
+osi_proc_init(void)
+{
+    struct proc_dir_entry *entry;
+
+    openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
+
+#ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
+    entry = create_proc_entry("unixusers", 0, openafs_procfs);
+    if (entry) {
+       entry->proc_fops = &afs_unixuser_fops;
+       entry->owner = THIS_MODULE;
+    }
+    entry = create_proc_entry(PROC_CELLSERVDB_NAME, 0, openafs_procfs);
+    if (entry)
+       entry->proc_fops = &afs_csdb_operations;
+#else
+    entry = create_proc_info_entry(PROC_CELLSERVDB_NAME, (S_IFREG|S_IRUGO), openafs_procfs, csdbproc_info);
+#endif
+    entry->owner = THIS_MODULE;
+}
+
+void
+osi_proc_clean(void)
+{
+    remove_proc_entry(PROC_CELLSERVDB_NAME, openafs_procfs);
+    remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
+}
index bf8b88c..7f97c75 100644 (file)
@@ -27,20 +27,39 @@ extern cred_t *crdup(cred_t * cr);
 extern cred_t *crref(void);
 extern void crset(cred_t * cr);
 
+/* osi_nfssrv.c */
+extern int osi_linux_nfs_initreq(struct vrequest *av, struct AFS_UCRED *cr,
+                                 int *code);
+extern void osi_linux_nfssrv_init(void);
+extern void osi_linux_nfssrv_shutdown(void);
+extern afs_rwlock_t afs_xnfssrv;
+
 /* osi_file.c */
 extern afs_rwlock_t afs_xosi;
+extern int osi_InitCacheInfo(char *aname);
+extern int osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw);
+
+/* osi_ioctl.c */
+extern void osi_ioctl_init(void);
+extern void osi_ioctl_clean(void);
 
 /* osi_misc.c */
+extern void afs_osi_SetTime(osi_timeval_t * tvp);
+extern int osi_lookupname_internal(char *aname, int followlink,
+                                  struct vfsmount **mnt, struct dentry **dpp);
 extern int osi_lookupname(char *aname, uio_seg_t seg, int followlink,
                          struct dentry **dpp);
-extern int osi_InitCacheInfo(char *aname);
-extern int osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw);
-extern void afs_osi_SetTime(osi_timeval_t * tvp);
-extern void osi_linux_free_inode_pages(void);
+extern int osi_abspath(char *aname, char *buf, int buflen,
+                      int followlink, char **pathp);
+extern void afs_start_thread(void (*proc)(void), char *name);
 
 /* osi_probe.c */
 extern void *osi_find_syscall_table(int which);
 
+/* osi_proc.c */
+extern void osi_proc_init(void);
+extern void osi_proc_clean(void);
+
 /* osi_syscall.c */
 extern int osi_syscall_init(void);
 extern void osi_syscall_clean(void);
@@ -63,6 +82,7 @@ extern void osi_VM_Truncate(struct vcache *avc, int alen,
 extern void vattr2inode(struct inode *ip, struct vattr *vp);
 extern int afs_init_inodecache(void);
 extern void afs_destroy_inodecache(void);
+extern void osi_linux_free_inode_pages(void);
 
 /* osi_vnodeops.c */
 extern void afs_fill_inode(struct inode *ip, struct vattr *vattr);
index e79f2dd..9513ab5 100644 (file)
@@ -39,6 +39,9 @@ struct vfsmount *afs_cacheMnt;
 int afs_was_mounted = 0;       /* Used to force reload if mount/unmount/mount */
 
 extern struct super_operations afs_sops;
+#if defined(AFS_LINUX26_ENV)
+extern struct export_operations afs_export_ops;
+#endif
 extern afs_rwlock_t afs_xvcache;
 extern struct afs_q VLRU;
 
@@ -131,6 +134,9 @@ afs_read_super(struct super_block *sb, void *data, int silent)
     sb->s_blocksize_bits = 10;
     sb->s_magic = AFS_VFSMAGIC;
     sb->s_op = &afs_sops;      /* Super block (vfs) ops */
+#if defined(AFS_LINUX26_ENV)
+    sb->s_export_op = &afs_export_ops;
+#endif
 #if defined(MAX_NON_LFS)
 #ifdef AFS_64BIT_CLIENT
 #if !defined(MAX_LFS_FILESIZE)
@@ -503,6 +509,11 @@ vattr2inode(struct inode *ip, struct vattr *vp)
 #if defined(AFS_LINUX26_ENV)
     ip->i_atime.tv_sec = vp->va_atime.tv_sec;
     ip->i_mtime.tv_sec = vp->va_mtime.tv_sec;
+    /* Set the mtime nanoseconds to the sysname generation number.
+     * This convinces NFS clients that all directories have changed
+     * any time the sysname list changes.
+     */
+    ip->i_mtime.tv_nsec = afs_sysnamegen;
     ip->i_ctime.tv_sec = vp->va_ctime.tv_sec;
 #else
     ip->i_atime = vp->va_atime.tv_sec;
@@ -510,3 +521,27 @@ vattr2inode(struct inode *ip, struct vattr *vp)
     ip->i_ctime = vp->va_ctime.tv_sec;
 #endif
 }
+
+/* osi_linux_free_inode_pages
+ *
+ * Free all vnodes remaining in the afs hash.  Must be done before
+ * shutting down afs and freeing all memory.
+ */
+void
+osi_linux_free_inode_pages(void)
+{
+    int i;
+    struct vcache *tvc, *nvc;
+    extern struct vcache *afs_vhashT[VCSIZE];
+
+    for (i = 0; i < VCSIZE; i++) {
+       for (tvc = afs_vhashT[i]; tvc; ) {
+           int slept;
+       
+           nvc = tvc->hnext;
+           if (afs_FlushVCache(tvc, &slept))           /* slept always 0 for linux? */
+               printf("Failed to invalidate all pages on inode 0x%p\n", tvc);
+           tvc = nvc;
+       }
+    }
+}
index b88c62d..a854fdb 100644 (file)
@@ -188,7 +188,8 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
        code = -ENOENT;
        goto out;
     }
-    ObtainReadLock(&avc->lock);
+    ObtainSharedLock(&avc->lock, 810);
+    UpgradeSToWLock(&avc->lock, 811);
     ObtainReadLock(&tdc->lock);
     /*
      * Make sure that the data in the cache is current. There are two
@@ -200,19 +201,27 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
           && (tdc->dflags & DFFetching)
           && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
        ReleaseReadLock(&tdc->lock);
-       ReleaseReadLock(&avc->lock);
+       ReleaseSharedLock(&avc->lock);
        afs_osi_Sleep(&tdc->validPos);
-       ObtainReadLock(&avc->lock);
+       ObtainSharedLock(&avc->lock, 812);
        ObtainReadLock(&tdc->lock);
     }
     if (!(avc->states & CStatd)
        || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
        ReleaseReadLock(&tdc->lock);
-       ReleaseReadLock(&avc->lock);
+       ReleaseSharedLock(&avc->lock);
        afs_PutDCache(tdc);
        goto tagain;
     }
 
+    /* Set the readdir-in-progress flag, and downgrade the lock
+     * to shared so others will be able to acquire a read lock.
+     */
+    avc->states |= CReadDir;
+    avc->dcreaddir = tdc;
+    avc->readdir_pid = MyPidxx;
+    ConvertWToSLock(&avc->lock);
+
     /* Fill in until we get an error or we're done. This implementation
      * takes an offset in units of blobs, rather than bytes.
      */
@@ -235,8 +244,8 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
            printf("afs_linux_readdir: afs_dir_GetBlob failed, null name (inode %lx, dirpos %d)\n", 
                   (unsigned long)&tdc->f.inode, dirpos);
            DRelease((struct buffer *) de, 0);
+           ReleaseSharedLock(&avc->lock);
            afs_PutDCache(tdc);
-           ReleaseReadLock(&avc->lock);
            code = -ENOENT;
            goto out;
        }
@@ -273,7 +282,14 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
                /* clean up from afs_FindVCache */
                afs_PutVCache(tvc);
            }
+           /* 
+            * If this is NFS readdirplus, then the filler is going to
+            * call getattr on this inode, which will deadlock if we're
+            * holding the GLOCK.
+            */
+           AFS_GUNLOCK();
            code = (*filldir) (dirbuf, de->name, len, offset, ino, type);
+           AFS_GLOCK();
        }
 #else
        code = (*filldir) (dirbuf, de->name, len, offset, ino);
@@ -290,7 +306,11 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
 
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);
-    ReleaseReadLock(&avc->lock);
+    UpgradeSToWLock(&avc->lock, 813);
+    avc->states &= ~CReadDir;
+    avc->dcreaddir = 0;
+    avc->readdir_pid = 0;
+    ReleaseSharedLock(&avc->lock);
     code = 0;
 
 out:
@@ -900,6 +920,9 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
     struct vcache *vcp = NULL;
     const char *comp = dp->d_name.name;
     struct inode *ip = NULL;
+#if defined(AFS_LINUX26_ENV)
+    struct dentry *newdp = NULL;
+#endif
     int code;
 
 #if defined(AFS_LINUX26_ENV)
@@ -923,8 +946,14 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
     if (ip && S_ISDIR(ip->i_mode)) {
        struct dentry *alias;
 
+        /* Try to invalidate an existing alias in favor of our new one */
        alias = d_find_alias(ip);
+#if defined(AFS_LINUX26_ENV)
+        /* But not if it's disconnected; then we want d_splice_alias below */
+       if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
+#else
        if (alias) {
+#endif
            if (d_invalidate(alias) == 0) {
                dput(alias);
            } else {
@@ -937,7 +966,11 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
        }
     }
 #endif
+#if defined(AFS_LINUX26_ENV)
+    newdp = d_splice_alias(ip, dp);
+#else
     d_add(dp, ip);
+#endif
 
 #if defined(AFS_LINUX26_ENV)
     unlock_kernel();
@@ -948,8 +981,13 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
      * seeing that the dp->d_inode field is NULL.
      */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
+#if defined(AFS_LINUX26_ENV)
+    if (!code || code == ENOENT)
+       return newdp;
+#else
     if (code == ENOENT)
        return ERR_PTR(0);
+#endif
     else
        return ERR_PTR(-code);
 #else
index 3445ea4..d39aa9a 100644 (file)
@@ -971,10 +971,9 @@ shutdown_osifile(void)
     return;
 }
 
-int
+void
 afs_nfsclient_init(void)
 {
-    return 0;
 }
 
 void
index e21d757..5677a09 100644 (file)
@@ -118,6 +118,16 @@ afs_AccessOK(struct vcache *avc, afs_int32 arights, struct vrequest *areq,
 
     if ((vType(avc) == VDIR) || (avc->states & CForeign)) {
        /* rights are just those from acl */
+       if (afs_InReadDir(avc)) {
+           /* if we are already in readdir, then they may have read and
+            * lookup, and nothing else, and nevermind the real ACL.
+            * Otherwise we might end up with problems trying to call
+            * FetchStatus on the vnode readdir is working on, and that
+            * would be a real mess.
+            */
+           dirBits = PRSFS_LOOKUP | PRSFS_READ;
+           return (arights == (dirBits & arights));
+       }
        return (arights == afs_GetAccessBits(avc, arights, areq));
     } else {
        /* some rights come from dir and some from file.  Specifically, you 
index 1b40283..02955ae 100644 (file)
@@ -27,9 +27,11 @@ RCSID
 #include "afs/nfsclient.h"
 #include "afs/exporter.h"
 #include "afs/afs_osidnlc.h"
+#include "afs/afs_dynroot.h"
 
 
 extern struct DirEntry *afs_dir_GetBlob();
+extern struct vcache *afs_globalVp;
 
 
 afs_int32 afs_bkvolpref = 0;
@@ -52,45 +54,37 @@ int afs_fakestat_enable = 0;        /* 1: fakestat-all, 2: fakestat-crosscell */
  *
  * NOTE: this function returns a held volume structure in *volpp if it returns 0!
  */
-int
-EvalMountPoint(register struct vcache *avc, struct vcache *advc,
-              struct volume **avolpp, register struct vrequest *areq)
+static int
+EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
+              struct volume **avolpp, register struct vrequest *areq,
+             afs_uint32 *acellidxp, afs_uint32 *avolnump)
 {
-    afs_int32 code;
     struct volume *tvp = 0;
     struct VenusFid tfid;
     struct cell *tcell;
-    char *cpos, *volnamep;
-    char type, *buf;
+    char *cpos, *volnamep, *x;
+    char *buf;
     afs_int32 prefetch;                /* 1=>None  2=>RO  3=>BK */
     afs_int32 mtptCell, assocCell = 0, hac = 0;
     afs_int32 samecell, roname, len;
+    afs_uint32 volid, cellidx;
 
-    AFS_STATCNT(EvalMountPoint);
-#ifdef notdef
-    if (avc->mvid && (avc->states & CMValid))
-       return 0;               /* done while racing */
-#endif
-    *avolpp = NULL;
-    code = afs_HandleLink(avc, areq);
-    if (code)
-       return code;
-
-    /* Determine which cell and volume the mointpoint goes to */
-    type = avc->linkData[0];   /* '#'=>Regular '%'=>RW */
-    cpos = afs_strchr(&avc->linkData[1], ':'); /* if cell name present */
+    cpos = afs_strchr(data, ':');      /* if cell name present */
     if (cpos) {
        volnamep = cpos + 1;
        *cpos = 0;
-       tcell = afs_GetCellByName(&avc->linkData[1], READ_LOCK);
+       tcell = afs_GetCellByName(data, READ_LOCK);
        *cpos = ':';
+    } else if (cellnum) {
+       volnamep = data;
+       tcell = afs_GetCell(cellnum, READ_LOCK);
     } else {
-       volnamep = &avc->linkData[1];
-       tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
+       return ENODEV;
     }
     if (!tcell)
        return ENODEV;
 
+    cellidx = tcell->cellIndex;
     mtptCell = tcell->cellNum; /* The cell for the mountpoint */
     if (tcell->lcellp) {
        hac = 1;                /* has associated cell */
@@ -98,15 +92,47 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
     }
     afs_PutCell(tcell, READ_LOCK);
 
+    /* Look for an all-numeric volume ID */
+    volid = 0;
+    for (x = volnamep; *x >= '0' && *x <= '9'; x++)
+       volid = (volid * 10) + (*x - '0');
+
+    /*
+     * If the volume ID was all-numeric, and they didn't ask for a
+     * pointer to the volume structure, then just return the number
+     * as-is.  This is currently only used for handling name lookups
+     * in the dynamic mount directory.
+     */
+    if (!*x && !avolpp) {
+       if (acellidxp)
+           *acellidxp = cellidx;
+       if (avolnump)
+           *avolnump = volid;
+       return 0;
+    }
+
+    /*
+     * If the volume ID was all-numeric, and the type was '%', then
+     * assume whoever made the mount point knew what they were doing,
+     * and don't second-guess them by forcing use of a RW volume when
+     * they gave the ID of something else.
+     */
+    if (!*x && type == '%') {
+       tfid.Fid.Volume = volid;        /* remember BK volume */
+       tfid.Cell = mtptCell;
+       tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK);   /* get the new one */
+       if (!tvp)
+           return ENODEV;      /* oops, can't do it */
+       goto done;
+    }
+
     /* Is volume name a "<n>.backup" or "<n>.readonly" name */
     len = strlen(volnamep);
     roname = ((len > 9) && (strcmp(&volnamep[len - 9], ".readonly") == 0))
        || ((len > 7) && (strcmp(&volnamep[len - 7], ".backup") == 0));
 
     /* When we cross mountpoint, do we stay in the same cell */
-    samecell = (avc->fid.Cell == mtptCell) || (hac
-                                              && (avc->fid.Cell ==
-                                                  assocCell));
+    samecell = (cellnum == mtptCell) || (hac && (cellnum == assocCell));
 
     /* Decide whether to prefetch the BK, or RO.  Also means we want the BK or
      * RO.
@@ -117,9 +143,9 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
      *   want to prefetch the RO volume.
      */
     if ((type == '#') && !roname) {
-       if (afs_bkvolpref && samecell && (avc->states & CBackup))
+       if (afs_bkvolpref && samecell && (states & CBackup))
            prefetch = 3;       /* Prefetch the BK */
-       else if (!samecell || (avc->states & CRO))
+       else if (!samecell || (states & CRO))
            prefetch = 2;       /* Prefetch the RO */
        else
            prefetch = 1;       /* Do not prefetch */
@@ -163,7 +189,7 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
        return ENODEV;          /* Couldn't find the volume */
 
     /* Don't cross mountpoint from a BK to a BK volume */
-    if ((avc->states & CBackup) && (tvp->states & VBackup)) {
+    if ((states & CBackup) && (tvp->states & VBackup)) {
        afs_PutVolume(tvp, WRITE_LOCK);
        return ENODEV;
     }
@@ -190,11 +216,44 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
            return ENODEV;      /* oops, can't do it */
     }
 
+done:
+    if (acellidxp)
+       *acellidxp = cellidx;
+    if (avolnump)
+       *avolnump = tvp->volume;
+    if (avolpp)
+       *avolpp = tvp;
+    else
+       afs_PutVolume(tvp, WRITE_LOCK);
+    return 0;
+}
+
+int
+EvalMountPoint(register struct vcache *avc, struct vcache *advc,
+              struct volume **avolpp, register struct vrequest *areq)
+{
+    afs_int32 code;
+
+    AFS_STATCNT(EvalMountPoint);
+#ifdef notdef
+    if (avc->mvid && (avc->states & CMValid))
+       return 0;               /* done while racing */
+#endif
+    *avolpp = NULL;
+    code = afs_HandleLink(avc, areq);
+    if (code)
+       return code;
+
+    /* Determine which cell and volume the mointpoint goes to */
+    code = EvalMountData(avc->linkData[0], avc->linkData + 1,
+                         avc->states, avc->fid.Cell, avolpp, areq, 0, 0);
+    if (code) return code;
+
     if (avc->mvid == 0)
        avc->mvid =
            (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid));
-    avc->mvid->Cell = tvp->cell;
-    avc->mvid->Fid.Volume = tvp->volume;
+    avc->mvid->Cell = (*avolpp)->cell;
+    avc->mvid->Fid.Volume = (*avolpp)->volume;
     avc->mvid->Fid.Vnode = 1;
     avc->mvid->Fid.Unique = 1;
     avc->states |= CMValid;
@@ -214,11 +273,10 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
      * cd'ing via a new path to a volume will reset the ".." pointer
      * to the new path.
      */
-    tvp->mtpoint = avc->fid;   /* setup back pointer to mtpoint */
+    (*avolpp)->mtpoint = avc->fid;     /* setup back pointer to mtpoint */
     if (advc)
-       tvp->dotdot = advc->fid;
+       (*avolpp)->dotdot = advc->fid;
 
-    *avolpp = tvp;
     return 0;
 }
 
@@ -313,7 +371,7 @@ afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
         if (code) goto done;
         vnode_ref(AFSTOV(root_vp));
 #endif
-       if (tvolp) {
+       if (tvolp && !afs_InReadDir(root_vp)) {
            /* Is this always kosher?  Perhaps we should instead use
             * NBObtainWriteLock to avoid potential deadlock.
             */
@@ -420,7 +478,7 @@ afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
     else {
        au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
        if (au->exporter) {
-           error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num);
+           error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
            if (error) {
                strcpy(bufp, "@sys");
                afs_PutUser(au, 0);
@@ -444,7 +502,7 @@ Check_AtSys(register struct vcache *avc, const char *aname,
 
     if (AFS_EQ_ATSYS(aname)) {
        state->offset = 0;
-       state->name = (char *)osi_AllocLargeSpace(AFS_SMALLOCSIZ);
+       state->name = (char *)osi_AllocLargeSpace(MAXSYSNAME);
        state->allocked = 1;
        state->index =
            afs_getsysname(areq, avc, state->name, &num, sysnamelist);
@@ -497,8 +555,9 @@ Next_AtSys(register struct vcache *avc, struct vrequest *areq,
            au = afs_GetUser(areq->uid, avc->fid.Cell, 0);
            if (au->exporter) {
                error =
-                   EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num);
+                   EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, &num, 0);
                if (error) {
+                   afs_PutUser(au, 0);
                    return 0;
                }
            }
@@ -1170,7 +1229,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
     *avcp = NULL;              /* Since some callers don't initialize it */
     bulkcode = 0;
 
-    if (!(adp->states & CStatd)) {
+    if (!(adp->states & CStatd) && !afs_InReadDir(adp)) {
        if ((code = afs_VerifyVCache2(adp, &treq))) {
            goto done;
        }
@@ -1182,7 +1241,6 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
        /* looking up ".." in root via special hacks */
        if (adp->mvid == (struct VenusFid *)0 || adp->mvid->Fid.Volume == 0) {
 #ifdef AFS_OSF_ENV
-           extern struct vcache *afs_globalVp;
            if (adp == afs_globalVp) {
                struct vnode *rvp = AFSTOV(adp);
 /*
@@ -1249,6 +1307,63 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
        goto done;
     }
 
+    /*
+     * Special case lookup of ".." in the dynamic mount directory.
+     * The parent of this directory is _always_ the AFS root volume.
+     */
+    if (afs_IsDynrootMount(adp) &&
+       aname[0] == '.' && aname[1] == '.' && !aname[2]) {
+
+       ObtainReadLock(&afs_xvcache);
+       osi_vnhold(afs_globalVp, 0);
+       ReleaseReadLock(&afs_xvcache);
+#ifdef AFS_DARWIN80_ENV
+        vnode_get(AFSTOV(afs_globalVp));
+#endif
+       code = 0;
+       *avcp = tvc = afs_globalVp;
+       hit = 1;
+       goto done;
+    }
+
+    /*
+     * Special case lookups in the dynamic mount directory.
+     * The names here take the form cell:volume, similar to a mount point.
+     * EvalMountData parses that and returns a cell and volume ID, which
+     * we use to construct the appropriate dynroot Fid.
+     */
+    if (afs_IsDynrootMount(adp)) {
+       struct VenusFid tfid;
+       afs_uint32 cellidx, volid;
+
+       code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid);
+       if (code)
+           goto done;
+       afs_GetDynrootMountFid(&tfid);
+       tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
+       tfid.Fid.Unique = volid;
+       *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
+       hit = 1;
+       goto done;
+    }
+
+#ifdef AFS_LINUX26_ENV
+    /*
+     * Special case of the dynamic mount volume in a static root.
+     * This is really unfortunate, but we need this for the translator.
+     */
+    if (adp == afs_globalVp && !afs_GetDynrootEnable() &&
+       !strcmp(aname, AFS_DYNROOT_MOUNTNAME)) {
+       struct VenusFid tfid;
+
+       afs_GetDynrootMountFid(&tfid);
+       *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
+       code = 0;
+       hit = 1;
+       goto done;
+    }
+#endif
+
     Check_AtSys(adp, aname, &sysState, &treq);
     tname = sysState.name;
 
@@ -1291,8 +1406,11 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
        struct VenusFid tfid;
 
        /* now we have to lookup the next fid */
-       tdc =
-           afs_GetDCache(adp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
+       if (afs_InReadDir(adp))
+           tdc = adp->dcreaddir;
+       else
+           tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq,
+                               &dirOffset, &dirLen, 1);
        if (!tdc) {
            *avcp = NULL;       /* redundant, but harmless */
            code = EIO;
@@ -1309,24 +1427,30 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
         * cases we need to worry about:
         * 1. The cache data is being fetched by another process.
         * 2. The cache data is no longer valid
+        *
+        * If a readdir is in progress _in this thread_, it has a shared
+        * lock on the vcache and has obtained current data, so we just
+        * use that.  This eliminates several possible deadlocks.  
         */
-       while ((adp->states & CStatd)
-              && (tdc->dflags & DFFetching)
-              && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
-           ReleaseReadLock(&tdc->lock);
-           ReleaseReadLock(&adp->lock);
-           afs_osi_Sleep(&tdc->validPos);
-           ObtainReadLock(&adp->lock);
-           ObtainReadLock(&tdc->lock);
-       }
-       if (!(adp->states & CStatd)
-           || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
-           ReleaseReadLock(&tdc->lock);
-           ReleaseReadLock(&adp->lock);
-           afs_PutDCache(tdc);
-           if (tname && tname != aname)
-               osi_FreeLargeSpace(tname);
-           goto redo;
+       if (!afs_InReadDir(adp)) {
+           while ((adp->states & CStatd)
+                  && (tdc->dflags & DFFetching)
+                  && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
+               ReleaseReadLock(&tdc->lock);
+               ReleaseReadLock(&adp->lock);
+               afs_osi_Sleep(&tdc->validPos);
+               ObtainReadLock(&adp->lock);
+               ObtainReadLock(&tdc->lock);
+           }
+           if (!(adp->states & CStatd)
+               || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
+               ReleaseReadLock(&tdc->lock);
+               ReleaseReadLock(&adp->lock);
+               afs_PutDCache(tdc);
+               if (tname && tname != aname)
+                   osi_FreeLargeSpace(tname);
+               goto redo;
+           }
        }
 
        /* Save the version number for when we call osi_dnlc_enter */
@@ -1357,7 +1481,8 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
        tname = sysState.name;
 
        ReleaseReadLock(&tdc->lock);
-       afs_PutDCache(tdc);
+       if (!afs_InReadDir(adp))
+           afs_PutDCache(tdc);
 
        if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
            ReleaseReadLock(&adp->lock);
@@ -1391,7 +1516,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
         * dirCookie tells us where to start prefetching from.
         */
        if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)
-           && !afs_IsDynroot(adp)) {
+           && !afs_IsDynroot(adp) && !afs_InReadDir(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 4fdd6b8..385e46b 100644 (file)
@@ -263,6 +263,9 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
 #endif
        return code;
     }
+    if (afs_IsDynrootMount(adp)) {
+       return ENOENT;
+    }
 
     if (strlen(aname) > AFSNAMEMAX) {
        afs_PutFakeStat(&fakestate);
index 205e407..fa5a8f4 100644 (file)
@@ -89,6 +89,10 @@ int afs_symlink
        code = afs_DynrootVOPSymlink(adp, acred, aname, atargetName);
        goto done;
     }
+    if (afs_IsDynrootMount(adp)) {
+       code = EROFS;
+       goto done;
+    }
 
     code = afs_VerifyVCache(adp, &treq);
     if (code) {
index 469025e..e22530d 100644 (file)
@@ -224,6 +224,7 @@ struct cell {
     time_t timeout;            /* data expire time, if non-zero */
     struct cell_name *cnamep;  /* pointer to our cell_name */
     afs_rwlock_t lock;         /* protects cell data */
+    unsigned char cellHandle[16];      /* deterministic handle for this cell */
 };
 
 struct cell_name {
@@ -248,6 +249,7 @@ struct cell_alias {
 #define UPrimary        4      /* on iff primary identity */
 #define UNeedsReset    8       /* needs afs_ResetAccessCache call done */
 #define UPAGCounted    16      /* entry seen during PAG search (for stats) */
+#define UNFSGetCreds   32      /* getting creds for NFS client */
 /* A flag used by afs_GCPAGs to keep track of
  * which entries in afs_users need to be deleted.
  * The lifetime of its presence in the table is the
@@ -279,6 +281,7 @@ struct unixuser {
     char *stp;                 /* pointer to ticket itself */
     struct ClearToken ct;
     struct afs_exporter *exporter;     /* more info about the exporter for the remote user */
+    void *cellinfo;             /* pointer to cell info (PAG manager only) */
 };
 
 struct conn {
@@ -539,6 +542,7 @@ struct SimpleLocks {
 #endif
 #define CUnique                0x00001000      /* vc's uniquifier - latest unifiquier for fid */
 #define CForeign       0x00002000      /* this is a non-afs vcache */
+#define CReadDir       0x00004000      /* readdir in progress */
 #define CUnlinked      0x00010000
 #define CBulkStat      0x00020000      /* loaded by a bulk stat, and not ref'd since */
 #define CUnlinkedDel   0x00040000
@@ -696,6 +700,8 @@ struct vcache {
     afs_uint32 vstates;                /* vstate bits */
 #endif                         /* defined(AFS_SUN5_ENV) */
     struct dcache *dchint;
+    struct dcache *dcreaddir;  /* dcache for in-progress readdir */
+    unsigned int readdir_pid;   /* pid of the thread in readdir */
 #ifdef AFS_LINUX22_ENV
     u_short mapcnt;            /* Number of mappings of this file. */
 #endif
@@ -1044,6 +1050,8 @@ struct memCacheEntry {
 /*#define afs_DirtyPages(avc)  (((avc)->states & CDirty) || osi_VMDirty_p((avc)))*/
 #define        afs_DirtyPages(avc)     ((avc)->states & CDirty)
 
+#define afs_InReadDir(avc) (((avc)->states & CReadDir) && (avc)->readdir_pid == MyPidxx)
+
 /* The PFlush algorithm makes use of the fact that Fid.Unique is not used in
   below hash algorithms.  Change it if need be so that flushing algorithm
   doesn't move things from one hash chain to another
index c0705dc..e426321 100644 (file)
@@ -71,220 +71,6 @@ afs_int32 hm_retry_RO = 0;  /* don't wait */
 afs_int32 hm_retry_RW = 0;     /* don't wait */
 afs_int32 hm_retry_int = 0;    /* don't wait */
 
-static int et2sys[512];
-
-void
-init_et_to_sys_error(void)
-{
-    memset(&et2sys, 0, sizeof(et2sys));
-    et2sys[(UAEPERM - ERROR_TABLE_BASE_uae)] = EPERM;
-    et2sys[(UAENOENT - ERROR_TABLE_BASE_uae)] = ENOENT;
-    et2sys[(UAESRCH - ERROR_TABLE_BASE_uae)] = ESRCH;
-    et2sys[(UAEINTR - ERROR_TABLE_BASE_uae)] = EINTR;
-    et2sys[(UAEIO - ERROR_TABLE_BASE_uae)] = EIO;
-    et2sys[(UAENXIO - ERROR_TABLE_BASE_uae)] = ENXIO;
-    et2sys[(UAE2BIG - ERROR_TABLE_BASE_uae)] = E2BIG;
-    et2sys[(UAENOEXEC - ERROR_TABLE_BASE_uae)] = ENOEXEC;
-    et2sys[(UAEBADF - ERROR_TABLE_BASE_uae)] = EBADF;
-    et2sys[(UAECHILD - ERROR_TABLE_BASE_uae)] = ECHILD;
-    et2sys[(UAEAGAIN - ERROR_TABLE_BASE_uae)] = EAGAIN;
-    et2sys[(UAENOMEM - ERROR_TABLE_BASE_uae)] = ENOMEM;
-    et2sys[(UAEACCES - ERROR_TABLE_BASE_uae)] = EACCES;
-    et2sys[(UAEFAULT - ERROR_TABLE_BASE_uae)] = EFAULT;
-    et2sys[(UAENOTBLK - ERROR_TABLE_BASE_uae)] = ENOTBLK;
-    et2sys[(UAEBUSY - ERROR_TABLE_BASE_uae)] = EBUSY;
-    et2sys[(UAEEXIST - ERROR_TABLE_BASE_uae)] = EEXIST;
-    et2sys[(UAEXDEV - ERROR_TABLE_BASE_uae)] = EXDEV;
-    et2sys[(UAENODEV - ERROR_TABLE_BASE_uae)] = ENODEV;
-    et2sys[(UAENOTDIR - ERROR_TABLE_BASE_uae)] = ENOTDIR;
-    et2sys[(UAEISDIR - ERROR_TABLE_BASE_uae)] = EISDIR;
-    et2sys[(UAEINVAL - ERROR_TABLE_BASE_uae)] = EINVAL;
-    et2sys[(UAENFILE - ERROR_TABLE_BASE_uae)] = ENFILE;
-    et2sys[(UAEMFILE - ERROR_TABLE_BASE_uae)] = EMFILE;
-    et2sys[(UAENOTTY - ERROR_TABLE_BASE_uae)] = ENOTTY;
-    et2sys[(UAETXTBSY - ERROR_TABLE_BASE_uae)] = ETXTBSY;
-    et2sys[(UAEFBIG - ERROR_TABLE_BASE_uae)] = EFBIG;
-    et2sys[(UAENOSPC - ERROR_TABLE_BASE_uae)] = ENOSPC;
-    et2sys[(UAESPIPE - ERROR_TABLE_BASE_uae)] = ESPIPE;
-    et2sys[(UAEROFS - ERROR_TABLE_BASE_uae)] = EROFS;
-    et2sys[(UAEMLINK - ERROR_TABLE_BASE_uae)] = EMLINK;
-    et2sys[(UAEPIPE - ERROR_TABLE_BASE_uae)] = EPIPE;
-    et2sys[(UAEDOM - ERROR_TABLE_BASE_uae)] = EDOM;
-    et2sys[(UAERANGE - ERROR_TABLE_BASE_uae)] = ERANGE;
-    et2sys[(UAEDEADLK - ERROR_TABLE_BASE_uae)] = EDEADLK;
-    et2sys[(UAENAMETOOLONG - ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
-    et2sys[(UAENOLCK - ERROR_TABLE_BASE_uae)] = ENOLCK;
-    et2sys[(UAENOSYS - ERROR_TABLE_BASE_uae)] = ENOSYS;
-    et2sys[(UAENOTEMPTY - ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
-    et2sys[(UAELOOP - ERROR_TABLE_BASE_uae)] = ELOOP;
-    et2sys[(UAEWOULDBLOCK - ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
-    et2sys[(UAENOMSG - ERROR_TABLE_BASE_uae)] = ENOMSG;
-    et2sys[(UAEIDRM - ERROR_TABLE_BASE_uae)] = EIDRM;
-    et2sys[(UAECHRNG - ERROR_TABLE_BASE_uae)] = ECHRNG;
-    et2sys[(UAEL2NSYNC - ERROR_TABLE_BASE_uae)] = EL2NSYNC;
-    et2sys[(UAEL3HLT - ERROR_TABLE_BASE_uae)] = EL3HLT;
-    et2sys[(UAEL3RST - ERROR_TABLE_BASE_uae)] = EL3RST;
-    et2sys[(UAELNRNG - ERROR_TABLE_BASE_uae)] = ELNRNG;
-    et2sys[(UAEUNATCH - ERROR_TABLE_BASE_uae)] = EUNATCH;
-    et2sys[(UAENOCSI - ERROR_TABLE_BASE_uae)] = ENOCSI;
-    et2sys[(UAEL2HLT - ERROR_TABLE_BASE_uae)] = EL2HLT;
-    et2sys[(UAEBADE - ERROR_TABLE_BASE_uae)] = EBADE;
-    et2sys[(UAEBADR - ERROR_TABLE_BASE_uae)] = EBADR;
-    et2sys[(UAEXFULL - ERROR_TABLE_BASE_uae)] = EXFULL;
-    et2sys[(UAENOANO - ERROR_TABLE_BASE_uae)] = ENOANO;
-    et2sys[(UAEBADRQC - ERROR_TABLE_BASE_uae)] = EBADRQC;
-    et2sys[(UAEBADSLT - ERROR_TABLE_BASE_uae)] = EBADSLT;
-    et2sys[(UAEBFONT - ERROR_TABLE_BASE_uae)] = EBFONT;
-    et2sys[(UAENOSTR - ERROR_TABLE_BASE_uae)] = ENOSTR;
-    et2sys[(UAENODATA - ERROR_TABLE_BASE_uae)] = ENODATA;
-    et2sys[(UAETIME - ERROR_TABLE_BASE_uae)] = ETIME;
-    et2sys[(UAENOSR - ERROR_TABLE_BASE_uae)] = ENOSR;
-    et2sys[(UAENONET - ERROR_TABLE_BASE_uae)] = ENONET;
-    et2sys[(UAENOPKG - ERROR_TABLE_BASE_uae)] = ENOPKG;
-    et2sys[(UAEREMOTE - ERROR_TABLE_BASE_uae)] = EREMOTE;
-    et2sys[(UAENOLINK - ERROR_TABLE_BASE_uae)] = ENOLINK;
-    et2sys[(UAEADV - ERROR_TABLE_BASE_uae)] = EADV;
-    et2sys[(UAESRMNT - ERROR_TABLE_BASE_uae)] = ESRMNT;
-    et2sys[(UAECOMM - ERROR_TABLE_BASE_uae)] = ECOMM;
-    et2sys[(UAEPROTO - ERROR_TABLE_BASE_uae)] = EPROTO;
-    et2sys[(UAEMULTIHOP - ERROR_TABLE_BASE_uae)] = EMULTIHOP;
-    et2sys[(UAEDOTDOT - ERROR_TABLE_BASE_uae)] = EDOTDOT;
-    et2sys[(UAEBADMSG - ERROR_TABLE_BASE_uae)] = EBADMSG;
-    et2sys[(UAEOVERFLOW - ERROR_TABLE_BASE_uae)] = EOVERFLOW;
-    et2sys[(UAENOTUNIQ - ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
-    et2sys[(UAEBADFD - ERROR_TABLE_BASE_uae)] = EBADFD;
-    et2sys[(UAEREMCHG - ERROR_TABLE_BASE_uae)] = EREMCHG;
-    et2sys[(UAELIBACC - ERROR_TABLE_BASE_uae)] = ELIBACC;
-    et2sys[(UAELIBBAD - ERROR_TABLE_BASE_uae)] = ELIBBAD;
-    et2sys[(UAELIBSCN - ERROR_TABLE_BASE_uae)] = ELIBSCN;
-    et2sys[(UAELIBMAX - ERROR_TABLE_BASE_uae)] = ELIBMAX;
-    et2sys[(UAELIBEXEC - ERROR_TABLE_BASE_uae)] = ELIBEXEC;
-    et2sys[(UAEILSEQ - ERROR_TABLE_BASE_uae)] = EILSEQ;
-    et2sys[(UAERESTART - ERROR_TABLE_BASE_uae)] = ERESTART;
-    et2sys[(UAESTRPIPE - ERROR_TABLE_BASE_uae)] = ESTRPIPE;
-    et2sys[(UAEUSERS - ERROR_TABLE_BASE_uae)] = EUSERS;
-    et2sys[(UAENOTSOCK - ERROR_TABLE_BASE_uae)] = ENOTSOCK;
-    et2sys[(UAEDESTADDRREQ - ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
-    et2sys[(UAEMSGSIZE - ERROR_TABLE_BASE_uae)] = EMSGSIZE;
-    et2sys[(UAEPROTOTYPE - ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
-    et2sys[(UAENOPROTOOPT - ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
-    et2sys[(UAEPROTONOSUPPORT - ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
-    et2sys[(UAESOCKTNOSUPPORT - ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
-    et2sys[(UAEOPNOTSUPP - ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
-    et2sys[(UAEPFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
-    et2sys[(UAEAFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
-    et2sys[(UAEADDRINUSE - ERROR_TABLE_BASE_uae)] = EADDRINUSE;
-    et2sys[(UAEADDRNOTAVAIL - ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
-    et2sys[(UAENETDOWN - ERROR_TABLE_BASE_uae)] = ENETDOWN;
-    et2sys[(UAENETUNREACH - ERROR_TABLE_BASE_uae)] = ENETUNREACH;
-    et2sys[(UAENETRESET - ERROR_TABLE_BASE_uae)] = ENETRESET;
-    et2sys[(UAECONNABORTED - ERROR_TABLE_BASE_uae)] = ECONNABORTED;
-    et2sys[(UAECONNRESET - ERROR_TABLE_BASE_uae)] = ECONNRESET;
-    et2sys[(UAENOBUFS - ERROR_TABLE_BASE_uae)] = ENOBUFS;
-    et2sys[(UAEISCONN - ERROR_TABLE_BASE_uae)] = EISCONN;
-    et2sys[(UAENOTCONN - ERROR_TABLE_BASE_uae)] = ENOTCONN;
-    et2sys[(UAESHUTDOWN - ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
-    et2sys[(UAETOOMANYREFS - ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
-    et2sys[(UAETIMEDOUT - ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
-    et2sys[(UAECONNREFUSED - ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
-    et2sys[(UAEHOSTDOWN - ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
-    et2sys[(UAEHOSTUNREACH - ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
-    et2sys[(UAEALREADY - ERROR_TABLE_BASE_uae)] = EALREADY;
-    et2sys[(UAEINPROGRESS - ERROR_TABLE_BASE_uae)] = EINPROGRESS;
-    et2sys[(UAESTALE - ERROR_TABLE_BASE_uae)] = ESTALE;
-    et2sys[(UAEUCLEAN - ERROR_TABLE_BASE_uae)] = EUCLEAN;
-    et2sys[(UAENOTNAM - ERROR_TABLE_BASE_uae)] = ENOTNAM;
-    et2sys[(UAENAVAIL - ERROR_TABLE_BASE_uae)] = ENAVAIL;
-    et2sys[(UAEISNAM - ERROR_TABLE_BASE_uae)] = EISNAM;
-    et2sys[(UAEREMOTEIO - ERROR_TABLE_BASE_uae)] = EREMOTEIO;
-    et2sys[(UAEDQUOT - ERROR_TABLE_BASE_uae)] = EDQUOT;
-    et2sys[(UAENOMEDIUM - ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
-    et2sys[(UAEMEDIUMTYPE - ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
-}
-
-static afs_int32
-et_to_sys_error(afs_int32 in)
-{
-    if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
-       return in;
-    if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
-       return et2sys[in - ERROR_TABLE_BASE_uae];
-    return in;
-}
-
-void
-afs_CopyError(register struct vrequest *afrom, register struct vrequest *ato)
-{
-    AFS_STATCNT(afs_CopyError);
-    if (!afrom->initd)
-       return;
-    afs_FinalizeReq(ato);
-    if (afrom->accessError)
-       ato->accessError = 1;
-    if (afrom->volumeError)
-       ato->volumeError = 1;
-    if (afrom->networkError)
-       ato->networkError = 1;
-    if (afrom->permWriteError)
-       ato->permWriteError = 1;
-
-}
-
-void
-afs_FinalizeReq(register struct vrequest *areq)
-{
-    AFS_STATCNT(afs_FinalizeReq);
-    if (areq->initd)
-       return;
-    areq->busyCount = 0;
-    areq->accessError = 0;
-    areq->volumeError = 0;
-    areq->networkError = 0;
-    areq->permWriteError = 0;
-    areq->initd = 1;
-
-}
-
-int
-afs_CheckCode(afs_int32 acode, struct vrequest *areq, int where)
-{
-    AFS_STATCNT(afs_CheckCode);
-    if (acode) {
-       afs_Trace2(afs_iclSetp, CM_TRACE_CHECKCODE, ICL_TYPE_INT32, acode,
-                  ICL_TYPE_INT32, where);
-    }
-    if ((acode & ~0xff) == ERROR_TABLE_BASE_uae)
-       acode = et_to_sys_error(acode);
-    if (!areq || !areq->initd)
-       return acode;
-    if (areq->networkError)
-       return ETIMEDOUT;
-    if (acode == 0)
-       return 0;
-    if (areq->accessError)
-       return EACCES;
-    if (areq->volumeError == VOLMISSING)
-       return ENODEV;
-    if (areq->volumeError == VOLBUSY)
-       return EWOULDBLOCK;
-    if (acode == VNOVNODE)
-       return ENOENT;
-    if (acode == VDISKFULL)
-       return ENOSPC;
-    if (acode == VOVERQUOTA)
-       return
-#ifdef EDQUOT
-           EDQUOT
-#else
-           ENOSPC
-#endif
-           ;
-
-    return acode;
-
-}                              /*afs_CheckCode */
-
-
 #define        VSleep(at)      afs_osi_Wait((at)*1000, 0, 0)
 
 
index 17fa236..2156aad 100644 (file)
@@ -46,6 +46,7 @@ char afs_zeros[AFS_ZEROS];
 char afs_rootVolumeName[64] = "";
 afs_uint32 rx_bindhost;
 
+afs_int32 afs_initState = 0;
 afs_int32 afs_termState = 0;
 afs_int32 afs_setTime = 0;
 int afs_cold_shutdown = 0;
@@ -61,9 +62,6 @@ static int afs_InitSetup_done = 0;
 afs_int32 afs_rx_deadtime = AFS_RXDEADTIME;
 afs_int32 afs_rx_harddead = AFS_HARDDEADTIME;
 
-static int
-  Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval);
-
 static int afscall_set_rxpck_received = 0;
 
 #if defined(AFS_HPUX_ENV)
@@ -629,8 +627,11 @@ afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
         * home cell flag (0x1 bit) and the nosuid flag (0x2 bit) */
        struct afsop_cell *tcell = afs_osi_Alloc(sizeof(struct afsop_cell));
 
-       AFS_COPYIN((char *)parm2, (char *)tcell->hosts, sizeof(tcell->hosts),
-                  code);
+       code = afs_InitDynroot();
+       if (!code) {
+           AFS_COPYIN((char *)parm2, (char *)tcell->hosts, sizeof(tcell->hosts),
+                      code);
+       }
        if (!code) {
            if (parm4 > sizeof(tcell->cellName))
                code = EFAULT;
@@ -648,14 +649,17 @@ afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
        char *tbuffer1 = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
        int cflags = parm4;
 
+       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);
+           /* 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((char *)parm2, (char *)tcell->hosts, sizeof(tcell->hosts),
-                  code);
+           AFS_COPYIN((char *)parm2, (char *)tcell->hosts, sizeof(tcell->hosts),
+                      code);
+       }
        if (!code) {
            AFS_COPYINSTR((char *)parm3, tbuffer1, AFS_SMALLOCSIZ,
                          &bufferSize, code);
@@ -686,8 +690,11 @@ afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
        char *aliasName = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
        char *cellName = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
-       AFS_COPYINSTR((char *)parm2, aliasName, AFS_SMALLOCSIZ, &bufferSize,
-                     code);
+       code = afs_InitDynroot();
+       if (!code) {
+           AFS_COPYINSTR((char *)parm2, aliasName, AFS_SMALLOCSIZ, &bufferSize,
+                         code);
+       }
        if (!code)
            AFS_COPYINSTR((char *)parm3, cellName, AFS_SMALLOCSIZ,
                          &bufferSize, code);
@@ -702,7 +709,10 @@ afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
         */
        char *cell = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
-       AFS_COPYINSTR((char *)parm2, cell, AFS_SMALLOCSIZ, &bufferSize, code);
+       code = afs_InitDynroot();
+       if (!code) {
+           AFS_COPYINSTR((char *)parm2, cell, AFS_SMALLOCSIZ, &bufferSize, code);
+       }
        if (!code)
            afs_SetPrimaryCell(cell);
        osi_FreeSmallSpace(cell);
@@ -721,19 +731,7 @@ afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
            goto out;
        }
        afs_CacheInit_Done = 1;
-       {
-           struct afs_icl_log *logp;
-           /* initialize the ICL system */
-           code = afs_icl_CreateLog("cmfx", 60 * 1024, &logp);
-           if (code == 0)
-               code =
-                   afs_icl_CreateSetWithFlags("cm", logp, NULL,
-                                              ICL_CRSET_FLAG_DEFAULT_OFF,
-                                              &afs_iclSetp);
-           code =
-               afs_icl_CreateSet("cmlongterm", logp, NULL,
-                                 &afs_iclLongTermSetp);
-       }
+        code = afs_icl_InitLogs();
        afs_setTime = cparms.setTimeFlag;
 
        code =
@@ -1047,592 +1045,6 @@ afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
 #endif
 }
 
-#ifdef AFS_AIX32_ENV
-
-#include "sys/lockl.h"
-
-/*
- * syscall -   this is the VRMIX system call entry point.
- *
- * NOTE:
- *     THIS SHOULD BE CHANGED TO afs_syscall(), but requires
- *     all the user-level calls to `syscall' to change.
- */
-syscall(syscall, p1, p2, p3, p4, p5, p6)
-{
-    register rval1 = 0, code;
-    register monster;
-    int retval = 0;
-#ifndef AFS_AIX41_ENV
-    extern lock_t kernel_lock;
-    monster = lockl(&kernel_lock, LOCK_SHORT);
-#endif /* !AFS_AIX41_ENV */
-
-    AFS_STATCNT(syscall);
-    setuerror(0);
-    switch (syscall) {
-    case AFSCALL_CALL:
-       rval1 = afs_syscall_call(p1, p2, p3, p4, p5, p6);
-       break;
-
-    case AFSCALL_SETPAG:
-       AFS_GLOCK();
-       rval1 = afs_setpag();
-       AFS_GUNLOCK();
-       break;
-
-    case AFSCALL_PIOCTL:
-       AFS_GLOCK();
-       rval1 = afs_syscall_pioctl(p1, p2, p3, p4);
-       AFS_GUNLOCK();
-       break;
-
-    case AFSCALL_ICREATE:
-       rval1 = afs_syscall_icreate(p1, p2, p3, p4, p5, p6);
-       break;
-
-    case AFSCALL_IOPEN:
-       rval1 = afs_syscall_iopen(p1, p2, p3);
-       break;
-
-    case AFSCALL_IDEC:
-       rval1 = afs_syscall_iincdec(p1, p2, p3, -1);
-       break;
-
-    case AFSCALL_IINC:
-       rval1 = afs_syscall_iincdec(p1, p2, p3, 1);
-       break;
-
-    case AFSCALL_ICL:
-       AFS_GLOCK();
-       code = Afscall_icl(p1, p2, p3, p4, p5, &retval);
-       AFS_GUNLOCK();
-       if (!code)
-           rval1 = retval;
-       if (!rval1)
-           rval1 = code;
-       break;
-
-    default:
-       rval1 = EINVAL;
-       setuerror(EINVAL);
-       break;
-    }
-
-  out:
-#ifndef AFS_AIX41_ENV
-    if (monster != LOCK_NEST)
-       unlockl(&kernel_lock);
-#endif /* !AFS_AIX41_ENV */
-    return getuerror()? -1 : rval1;
-}
-
-/*
- * lsetpag -   interface to afs_setpag().
- */
-lsetpag()
-{
-
-    AFS_STATCNT(lsetpag);
-    return syscall(AFSCALL_SETPAG, 0, 0, 0, 0, 0);
-}
-
-/*
- * lpioctl -   interface to pioctl()
- */
-lpioctl(path, cmd, cmarg, follow)
-     char *path, *cmarg;
-{
-
-    AFS_STATCNT(lpioctl);
-    return syscall(AFSCALL_PIOCTL, path, cmd, cmarg, follow);
-}
-
-#else /* !AFS_AIX32_ENV       */
-
-#if defined(AFS_SGI_ENV)
-struct afsargs {
-    sysarg_t syscall;
-    sysarg_t parm1;
-    sysarg_t parm2;
-    sysarg_t parm3;
-    sysarg_t parm4;
-    sysarg_t parm5;
-};
-
-
-int
-Afs_syscall(struct afsargs *uap, rval_t * rvp)
-{
-    int error;
-    long retval;
-
-    AFS_STATCNT(afs_syscall);
-    switch (uap->syscall) {
-    case AFSCALL_ICL:
-       retval = 0;
-       AFS_GLOCK();
-       error =
-           Afscall_icl(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                       uap->parm5, &retval);
-       AFS_GUNLOCK();
-       rvp->r_val1 = retval;
-       break;
-#ifdef AFS_SGI_XFS_IOPS_ENV
-    case AFSCALL_IDEC64:
-       error =
-           afs_syscall_idec64(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                              uap->parm5);
-       break;
-    case AFSCALL_IINC64:
-       error =
-           afs_syscall_iinc64(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                              uap->parm5);
-       break;
-    case AFSCALL_ILISTINODE64:
-       error =
-           afs_syscall_ilistinode64(uap->parm1, uap->parm2, uap->parm3,
-                                    uap->parm4, uap->parm5);
-       break;
-    case AFSCALL_ICREATENAME64:
-       error =
-           afs_syscall_icreatename64(uap->parm1, uap->parm2, uap->parm3,
-                                     uap->parm4, uap->parm5);
-       break;
-#endif
-#ifdef AFS_SGI_VNODE_GLUE
-    case AFSCALL_INIT_KERNEL_CONFIG:
-       error = afs_init_kernel_config(uap->parm1);
-       break;
-#endif
-    default:
-       error =
-           afs_syscall_call(uap->syscall, uap->parm1, uap->parm2, uap->parm3,
-                            uap->parm4, uap->parm5);
-    }
-    return error;
-}
-
-#else /* AFS_SGI_ENV */
-
-struct iparam {
-    long param1;
-    long param2;
-    long param3;
-    long param4;
-};
-
-struct iparam32 {
-    int param1;
-    int param2;
-    int param3;
-    int param4;
-};
-
-
-#if defined(AFS_HPUX_64BIT_ENV) || defined(AFS_SUN57_64BIT_ENV) || (defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV))
-static void
-iparam32_to_iparam(const struct iparam32 *src, struct iparam *dst)
-{
-    dst->param1 = src->param1;
-    dst->param2 = src->param2;
-    dst->param3 = src->param3;
-    dst->param4 = src->param4;
-}
-#endif
-
-/*
- * If you need to change copyin_iparam(), you may also need to change
- * copyin_afs_ioctl().
- */
-
-static int
-copyin_iparam(caddr_t cmarg, struct iparam *dst)
-{
-    int code;
-
-#if defined(AFS_HPUX_64BIT_ENV)
-    struct iparam32 dst32;
-
-    if (is_32bit(u.u_procp)) { /* is_32bit() in proc_iface.h */
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           iparam32_to_iparam(&dst32, dst);
-       return code;
-    }
-#endif /* AFS_HPUX_64BIT_ENV */
-
-#if defined(AFS_SUN57_64BIT_ENV)
-    struct iparam32 dst32;
-
-    if (get_udatamodel() == DATAMODEL_ILP32) {
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           iparam32_to_iparam(&dst32, dst);
-       return code;
-    }
-#endif /* AFS_SUN57_64BIT_ENV */
-
-#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
-    struct iparam32 dst32;
-
-#ifdef AFS_SPARC64_LINUX26_ENV
-    if (test_thread_flag(TIF_32BIT))
-#elif AFS_SPARC64_LINUX24_ENV
-    if (current->thread.flags & SPARC_FLAG_32BIT)
-#elif defined(AFS_SPARC64_LINUX20_ENV)
-    if (current->tss.flags & SPARC_FLAG_32BIT)
-
-#elif defined(AFS_AMD64_LINUX26_ENV)
-    if (test_thread_flag(TIF_IA32))
-#elif defined(AFS_AMD64_LINUX20_ENV)
-    if (current->thread.flags & THREAD_IA32)
-
-#elif defined(AFS_PPC64_LINUX26_ENV)
-    if (current->thread_info->flags & _TIF_32BIT) 
-#elif defined(AFS_PPC64_LINUX20_ENV)
-    if (current->thread.flags & PPC_FLAG_32BIT) 
-
-#elif defined(AFS_S390X_LINUX26_ENV)
-    if (test_thread_flag(TIF_31BIT))
-#elif defined(AFS_S390X_LINUX20_ENV)
-    if (current->thread.flags & S390_FLAG_31BIT) 
-
-#else
-#error iparam32 not done for this linux platform
-#endif
-    {
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           iparam32_to_iparam(&dst32, dst);
-       return code;
-    }
-#endif /* AFS_LINUX_64BIT_KERNEL */
-
-    AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
-    return code;
-}
-
-/* Main entry of all afs system calls */
-#ifdef AFS_SUN5_ENV
-extern int afs_sinited;
-
-/** The 32 bit OS expects the members of this structure to be 32 bit
- * quantities and the 64 bit OS expects them as 64 bit quanties. Hence
- * to accomodate both, *long* is used instead of afs_int32
- */
-
-#ifdef AFS_SUN57_ENV
-struct afssysa {
-    long syscall;
-    long parm1;
-    long parm2;
-    long parm3;
-    long parm4;
-    long parm5;
-    long parm6;
-};
-#else
-struct afssysa {
-    afs_int32 syscall;
-    afs_int32 parm1;
-    afs_int32 parm2;
-    afs_int32 parm3;
-    afs_int32 parm4;
-    afs_int32 parm5;
-    afs_int32 parm6;
-};
-#endif
-
-Afs_syscall(register struct afssysa *uap, rval_t * rvp)
-{
-    int *retval = &rvp->r_val1;
-#else /* AFS_SUN5_ENV */
-#if    defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-int
-afs3_syscall(p, args, retval)
-#ifdef AFS_FBSD50_ENV
-     struct thread *p;
-#else
-     struct proc *p;
-#endif
-     void *args;
-     long *retval;
-{
-    register struct a {
-       long syscall;
-       long parm1;
-       long parm2;
-       long parm3;
-       long parm4;
-       long parm5;
-       long parm6;
-    } *uap = (struct a *)args;
-#else /* AFS_OSF_ENV */
-#ifdef AFS_LINUX20_ENV
-struct afssysargs {
-    long syscall;
-    long parm1;
-    long parm2;
-    long parm3;
-    long parm4;
-    long parm5;
-    long parm6;                        /* not actually used - should be removed */
-};
-/* Linux system calls only set up for 5 arguments. */
-asmlinkage long
-afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4)
-{
-    struct afssysargs args, *uap = &args;
-    long linux_ret = 0;
-    long *retval = &linux_ret;
-    long eparm[4];             /* matches AFSCALL_ICL in fstrace.c */
-#ifdef AFS_SPARC64_LINUX24_ENV
-    afs_int32 eparm32[4];
-#endif
-    /* eparm is also used by AFSCALL_CALL in afsd.c */
-#else
-#if defined(UKERNEL)
-Afs_syscall()
-{
-    register struct a {
-       long syscall;
-       long parm1;
-       long parm2;
-       long parm3;
-       long parm4;
-       long parm5;
-       long parm6;
-    } *uap = (struct a *)u.u_ap;
-#else /* UKERNEL */
-int
-Afs_syscall()
-{
-    register struct a {
-       long syscall;
-       long parm1;
-       long parm2;
-       long parm3;
-       long parm4;
-       long parm5;
-       long parm6;
-    } *uap = (struct a *)u.u_ap;
-#endif /* UKERNEL */
-#if defined(AFS_HPUX_ENV)
-    long *retval = &u.u_rval1;
-#else
-    int *retval = &u.u_rval1;
-#endif
-#endif /* AFS_LINUX20_ENV */
-#endif /* AFS_OSF_ENV */
-#endif /* AFS_SUN5_ENV */
-    register int code = 0;
-
-    AFS_STATCNT(afs_syscall);
-#ifdef        AFS_SUN5_ENV
-    rvp->r_vals = 0;
-    if (!afs_sinited) {
-       return (ENODEV);
-    }
-#endif
-#ifdef AFS_LINUX20_ENV
-    lock_kernel();
-    /* setup uap for use below - pull out the magic decoder ring to know
-     * which syscalls have folded argument lists.
-     */
-    uap->syscall = syscall;
-    uap->parm1 = parm1;
-    uap->parm2 = parm2;
-    uap->parm3 = parm3;
-    if (syscall == AFSCALL_ICL || syscall == AFSCALL_CALL) {
-#ifdef AFS_SPARC64_LINUX24_ENV
-/* from arch/sparc64/kernel/sys_sparc32.c */
-#define AA(__x)                                \
-({     unsigned long __ret;            \
-       __asm__ ("srl   %0, 0, %0"      \
-                : "=r" (__ret)         \
-                : "0" (__x));          \
-       __ret;                          \
-})
-
-
-#ifdef AFS_SPARC64_LINUX26_ENV
-       if (test_thread_flag(TIF_32BIT))
-#else
-       if (current->thread.flags & SPARC_FLAG_32BIT)
-#endif
-       {
-           AFS_COPYIN((char *)parm4, (char *)eparm32, sizeof(eparm32), code);
-           eparm[0] = AA(eparm32[0]);
-           eparm[1] = AA(eparm32[1]);
-           eparm[2] = AA(eparm32[2]);
-#undef AA
-       } else
-#endif
-           AFS_COPYIN((char *)parm4, (char *)eparm, sizeof(eparm), code);
-       uap->parm4 = eparm[0];
-       uap->parm5 = eparm[1];
-       uap->parm6 = eparm[2];
-    } else {
-       uap->parm4 = parm4;
-       uap->parm5 = 0;
-       uap->parm6 = 0;
-    }
-#endif
-#if defined(AFS_DARWIN80_ENV)
-    get_vfs_context();
-    osi_Assert(*retval == 0);
-#endif
-#if defined(AFS_HPUX_ENV)
-    /*
-     * There used to be code here (duplicated from osi_Init()) for
-     * initializing the semaphore used by AFS_GLOCK().  Was the
-     * duplication to handle the case of a dynamically loaded kernel
-     * module?
-     */
-    osi_InitGlock();
-#endif
-    if (uap->syscall == AFSCALL_CALL) {
-#ifdef AFS_SUN5_ENV
-       code =
-           afs_syscall_call(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                            uap->parm5, uap->parm6, rvp, CRED());
-#else
-       code =
-           afs_syscall_call(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                            uap->parm5, uap->parm6);
-#endif
-    } else if (uap->syscall == AFSCALL_SETPAG) {
-#ifdef AFS_SUN5_ENV
-       register proc_t *procp;
-
-       procp = ttoproc(curthread);
-       AFS_GLOCK();
-       code = afs_setpag(&procp->p_cred);
-       AFS_GUNLOCK();
-#else
-       AFS_GLOCK();
-#if    defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-       code = afs_setpag(p, args, retval);
-#else /* AFS_OSF_ENV */
-       code = afs_setpag();
-#endif
-       AFS_GUNLOCK();
-#endif
-    } else if (uap->syscall == AFSCALL_PIOCTL) {
-       AFS_GLOCK();
-#if defined(AFS_SUN5_ENV)
-       code =
-           afs_syscall_pioctl(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                              rvp, CRED());
-#elif defined(AFS_FBSD50_ENV)
-       code =
-           afs_syscall_pioctl(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                              p->td_ucred);
-#elif defined(AFS_DARWIN80_ENV)
-       code =
-           afs_syscall_pioctl(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                              kauth_cred_get());
-#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-       code =
-           afs_syscall_pioctl(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                              p->p_cred->pc_ucred);
-#else
-       code =
-           afs_syscall_pioctl(uap->parm1, uap->parm2, uap->parm3,
-                              uap->parm4);
-#endif
-       AFS_GUNLOCK();
-    } else if (uap->syscall == AFSCALL_ICREATE) {
-       struct iparam iparams;
-
-       code = copyin_iparam((char *)uap->parm3, &iparams);
-       if (code) {
-#if defined(KERNEL_HAVE_UERROR)
-           setuerror(code);
-#endif
-       } else
-#ifdef AFS_SUN5_ENV
-           code =
-               afs_syscall_icreate(uap->parm1, uap->parm2, iparams.param1,
-                                   iparams.param2, iparams.param3,
-                                   iparams.param4, rvp, CRED());
-#else
-           code =
-               afs_syscall_icreate(uap->parm1, uap->parm2, iparams.param1,
-                                   iparams.param2,
-#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-                                   iparams.param3, iparams.param4, retval);
-#else
-                                   iparams.param3, iparams.param4);
-#endif
-#endif /* AFS_SUN5_ENV */
-    } else if (uap->syscall == AFSCALL_IOPEN) {
-#ifdef AFS_SUN5_ENV
-       code =
-           afs_syscall_iopen(uap->parm1, uap->parm2, uap->parm3, rvp,
-                             CRED());
-#else
-#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-       code = afs_syscall_iopen(uap->parm1, uap->parm2, uap->parm3, retval);
-#else
-       code = afs_syscall_iopen(uap->parm1, uap->parm2, uap->parm3);
-#endif
-#endif /* AFS_SUN5_ENV */
-    } else if (uap->syscall == AFSCALL_IDEC) {
-#ifdef AFS_SUN5_ENV
-       code =
-           afs_syscall_iincdec(uap->parm1, uap->parm2, uap->parm3, -1, rvp,
-                               CRED());
-#else
-       code = afs_syscall_iincdec(uap->parm1, uap->parm2, uap->parm3, -1);
-#endif /* AFS_SUN5_ENV */
-    } else if (uap->syscall == AFSCALL_IINC) {
-#ifdef AFS_SUN5_ENV
-       code =
-           afs_syscall_iincdec(uap->parm1, uap->parm2, uap->parm3, 1, rvp,
-                               CRED());
-#else
-       code = afs_syscall_iincdec(uap->parm1, uap->parm2, uap->parm3, 1);
-#endif /* AFS_SUN5_ENV */
-    } else if (uap->syscall == AFSCALL_ICL) {
-       AFS_GLOCK();
-       code =
-           Afscall_icl(uap->parm1, uap->parm2, uap->parm3, uap->parm4,
-                       uap->parm5, retval);
-       AFS_GUNLOCK();
-#ifdef AFS_LINUX20_ENV
-       if (!code) {
-           /* ICL commands can return values. */
-           code = -linux_ret;  /* Gets negated again at exit below */
-       }
-#else
-       if (code) {
-#if defined(KERNEL_HAVE_UERROR)
-           setuerror(code);
-#endif
-       }
-#endif /* !AFS_LINUX20_ENV */
-    } else {
-#if defined(KERNEL_HAVE_UERROR)
-       setuerror(EINVAL);
-#else
-       code = EINVAL;
-#endif
-    }
-
-#if defined(AFS_DARWIN80_ENV)
-    put_vfs_context();
-#endif
-#ifdef AFS_LINUX20_ENV
-    code = -code;
-    unlock_kernel();
-#endif
-    return code;
-}
-#endif /* AFS_SGI_ENV */
-#endif /* !AFS_AIX32_ENV       */
-
 /*
  * Initstate in the range 0 < x < 100 are early initialization states.
  * Initstate of 100 means a AFSOP_START operation has been done.  After this,
@@ -1805,1476 +1217,3 @@ afs_shutdown_BKG(void)
 {
     AFS_STATCNT(shutdown_BKG);
 }
-
-
-#if defined(AFS_OSF_ENV) || defined(AFS_SGI61_ENV)
-/* For SGI 6.2, this can is changed to 1 if it's a 32 bit kernel. */
-#if defined(AFS_SGI62_ENV) && defined(KERNEL) && !defined(_K64U64)
-int afs_icl_sizeofLong = 1;
-#else
-int afs_icl_sizeofLong = 2;
-#endif /* SGI62 */
-#else
-#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
-int afs_icl_sizeofLong = 2;
-#else
-int afs_icl_sizeofLong = 1;
-#endif
-#endif
-
-int afs_icl_inited = 0;
-
-/* init function, called once, under afs_icl_lock */
-int
-afs_icl_Init(void)
-{
-    afs_icl_inited = 1;
-    return 0;
-}
-
-extern struct afs_icl_log *afs_icl_FindLog();
-extern struct afs_icl_set *afs_icl_FindSet();
-
-
-static int
-Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval)
-{
-    afs_int32 *lp, elts, flags;
-    register afs_int32 code;
-    struct afs_icl_log *logp;
-    struct afs_icl_set *setp;
-#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-    size_t temp;
-#else /* AFS_SGI61_ENV */
-#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
-    afs_uint64 temp;
-#else
-    afs_uint32 temp;
-#endif
-#endif /* AFS_SGI61_ENV */
-    char tname[65];
-    afs_int32 startCookie;
-    afs_int32 allocated;
-    struct afs_icl_log *tlp;
-
-#ifdef AFS_SUN5_ENV
-    if (!afs_suser(CRED())) {  /* only root can run this code */
-       return (EACCES);
-    }
-#else
-    if (!afs_suser(NULL)) {    /* only root can run this code */
-#if defined(KERNEL_HAVE_UERROR)
-       setuerror(EACCES);
-       return EACCES;
-#else
-       return EPERM;
-#endif
-    }
-#endif
-    switch (opcode) {
-    case ICL_OP_COPYOUTCLR:    /* copy out data then clear */
-    case ICL_OP_COPYOUT:       /* copy ouy data */
-       /* copyout: p1=logname, p2=&buffer, p3=size(words), p4=&cookie
-        * return flags<<24 + nwords.
-        * updates cookie to updated start (not end) if we had to
-        * skip some records.
-        */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       AFS_COPYIN((char *)p4, (char *)&startCookie, sizeof(afs_int32), code);
-       if (code)
-           return code;
-       logp = afs_icl_FindLog(tname);
-       if (!logp)
-           return ENOENT;
-#define        BUFFERSIZE      AFS_LRALLOCSIZ
-       lp = (afs_int32 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-       elts = BUFFERSIZE / sizeof(afs_int32);
-       if (p3 < elts)
-           elts = p3;
-       flags = (opcode == ICL_OP_COPYOUT) ? 0 : ICL_COPYOUTF_CLRAFTERREAD;
-       code =
-           afs_icl_CopyOut(logp, lp, &elts, (afs_uint32 *) & startCookie,
-                           &flags);
-       if (code) {
-           osi_FreeLargeSpace((struct osi_buffer *)lp);
-           break;
-       }
-       AFS_COPYOUT((char *)lp, (char *)p2, elts * sizeof(afs_int32), code);
-       if (code)
-           goto done;
-       AFS_COPYOUT((char *)&startCookie, (char *)p4, sizeof(afs_int32),
-                   code);
-       if (code)
-           goto done;
-#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
-       if (!(IS64U))
-           *retval = ((long)((flags << 24) | (elts & 0xffffff))) << 32;
-       else
-#endif
-           *retval = (flags << 24) | (elts & 0xffffff);
-      done:
-       afs_icl_LogRele(logp);
-       osi_FreeLargeSpace((struct osi_buffer *)lp);
-       break;
-
-    case ICL_OP_ENUMLOGS:      /* enumerate logs */
-       /* enumerate logs: p1=index, p2=&name, p3=sizeof(name), p4=&size.
-        * return 0 for success, otherwise error.
-        */
-       for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
-           if (p1-- == 0)
-               break;
-       }
-       if (!tlp)
-           return ENOENT;      /* past the end of file */
-       temp = strlen(tlp->name) + 1;
-       if (temp > p3)
-           return EINVAL;
-       AFS_COPYOUT(tlp->name, (char *)p2, temp, code);
-       if (!code)              /* copy out size of log */
-           AFS_COPYOUT((char *)&tlp->logSize, (char *)p4, sizeof(afs_int32),
-                       code);
-       break;
-
-    case ICL_OP_ENUMLOGSBYSET: /* enumerate logs by set name */
-       /* enumerate logs: p1=setname, p2=index, p3=&name, p4=sizeof(name).
-        * return 0 for success, otherwise error.
-        */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       setp = afs_icl_FindSet(tname);
-       if (!setp)
-           return ENOENT;
-       if (p2 > ICL_LOGSPERSET)
-           return EINVAL;
-       if (!(tlp = setp->logs[p2]))
-           return EBADF;
-       temp = strlen(tlp->name) + 1;
-       if (temp > p4)
-           return EINVAL;
-       AFS_COPYOUT(tlp->name, (char *)p3, temp, code);
-       break;
-
-    case ICL_OP_CLRLOG:        /* clear specified log */
-       /* zero out the specified log: p1=logname */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       logp = afs_icl_FindLog(tname);
-       if (!logp)
-           return ENOENT;
-       code = afs_icl_ZeroLog(logp);
-       afs_icl_LogRele(logp);
-       break;
-
-    case ICL_OP_CLRSET:        /* clear specified set */
-       /* zero out the specified set: p1=setname */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       setp = afs_icl_FindSet(tname);
-       if (!setp)
-           return ENOENT;
-       code = afs_icl_ZeroSet(setp);
-       afs_icl_SetRele(setp);
-       break;
-
-    case ICL_OP_CLRALL:        /* clear all logs */
-       /* zero out all logs -- no args */
-       code = 0;
-       ObtainWriteLock(&afs_icl_lock, 178);
-       for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
-           tlp->refCount++;    /* hold this guy */
-           ReleaseWriteLock(&afs_icl_lock);
-           /* don't clear persistent logs */
-           if ((tlp->states & ICL_LOGF_PERSISTENT) == 0)
-               code = afs_icl_ZeroLog(tlp);
-           ObtainWriteLock(&afs_icl_lock, 179);
-           if (--tlp->refCount == 0)
-               afs_icl_ZapLog(tlp);
-           if (code)
-               break;
-       }
-       ReleaseWriteLock(&afs_icl_lock);
-       break;
-
-    case ICL_OP_ENUMSETS:      /* enumerate all sets */
-       /* enumerate sets: p1=index, p2=&name, p3=sizeof(name), p4=&states.
-        * return 0 for success, otherwise error.
-        */
-       for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
-           if (p1-- == 0)
-               break;
-       }
-       if (!setp)
-           return ENOENT;      /* past the end of file */
-       temp = strlen(setp->name) + 1;
-       if (temp > p3)
-           return EINVAL;
-       AFS_COPYOUT(setp->name, (char *)p2, temp, code);
-       if (!code)              /* copy out size of log */
-           AFS_COPYOUT((char *)&setp->states, (char *)p4, sizeof(afs_int32),
-                       code);
-       break;
-
-    case ICL_OP_SETSTAT:       /* set status on a set */
-       /* activate the specified set: p1=setname, p2=op */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       setp = afs_icl_FindSet(tname);
-       if (!setp)
-           return ENOENT;
-       code = afs_icl_SetSetStat(setp, p2);
-       afs_icl_SetRele(setp);
-       break;
-
-    case ICL_OP_SETSTATALL:    /* set status on all sets */
-       /* activate the specified set: p1=op */
-       code = 0;
-       ObtainWriteLock(&afs_icl_lock, 180);
-       for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
-           setp->refCount++;   /* hold this guy */
-           ReleaseWriteLock(&afs_icl_lock);
-           /* don't set states on persistent sets */
-           if ((setp->states & ICL_SETF_PERSISTENT) == 0)
-               code = afs_icl_SetSetStat(setp, p1);
-           ObtainWriteLock(&afs_icl_lock, 181);
-           if (--setp->refCount == 0)
-               afs_icl_ZapSet(setp);
-           if (code)
-               break;
-       }
-       ReleaseWriteLock(&afs_icl_lock);
-       break;
-
-    case ICL_OP_SETLOGSIZE:    /* set size of log */
-       /* set the size of the specified log: p1=logname, p2=size (in words) */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       logp = afs_icl_FindLog(tname);
-       if (!logp)
-           return ENOENT;
-       code = afs_icl_LogSetSize(logp, p2);
-       afs_icl_LogRele(logp);
-       break;
-
-    case ICL_OP_GETLOGINFO:    /* get size of log */
-       /* zero out the specified log: p1=logname, p2=&logSize, p3=&allocated */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       logp = afs_icl_FindLog(tname);
-       if (!logp)
-           return ENOENT;
-       allocated = !!logp->datap;
-       AFS_COPYOUT((char *)&logp->logSize, (char *)p2, sizeof(afs_int32),
-                   code);
-       if (!code)
-           AFS_COPYOUT((char *)&allocated, (char *)p3, sizeof(afs_int32),
-                       code);
-       afs_icl_LogRele(logp);
-       break;
-
-    case ICL_OP_GETSETINFO:    /* get state of set */
-       /* zero out the specified set: p1=setname, p2=&state */
-       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
-       if (code)
-           return code;
-       setp = afs_icl_FindSet(tname);
-       if (!setp)
-           return ENOENT;
-       AFS_COPYOUT((char *)&setp->states, (char *)p2, sizeof(afs_int32),
-                   code);
-       afs_icl_SetRele(setp);
-       break;
-
-    default:
-       code = EINVAL;
-    }
-
-    return code;
-}
-
-
-afs_lock_t afs_icl_lock;
-
-/* exported routine: a 4 parameter event */
-int
-afs_icl_Event4(register struct afs_icl_set *setp, afs_int32 eventID,
-              afs_int32 lAndT, long p1, long p2, long p3, long p4)
-{
-    afs_int32 mask;
-    register int i;
-    register afs_int32 tmask;
-    int ix;
-
-    /* If things aren't init'ed yet (or the set is inactive), don't panic */
-    if (!ICL_SETACTIVE(setp))
-       return 0;
-
-    AFS_ASSERT_GLOCK();
-    mask = lAndT >> 24 & 0xff; /* mask of which logs to log to */
-    ix = ICL_EVENTBYTE(eventID);
-    ObtainReadLock(&setp->lock);
-    if (setp->eventFlags[ix] & ICL_EVENTMASK(eventID)) {
-       for (i = 0, tmask = 1; i < ICL_LOGSPERSET; i++, tmask <<= 1) {
-           if (mask & tmask) {
-               afs_icl_AppendRecord(setp->logs[i], eventID, lAndT & 0xffffff,
-                                    p1, p2, p3, p4);
-           }
-           mask &= ~tmask;
-           if (mask == 0)
-               break;          /* break early */
-       }
-    }
-    ReleaseReadLock(&setp->lock);
-    return 0;
-}
-
-/* Next 4 routines should be implemented via var-args or something.
- * Whole purpose is to avoid compiler warnings about parameter # mismatches.
- * Otherwise, could call afs_icl_Event4 directly.
- */
-int
-afs_icl_Event3(register struct afs_icl_set *setp, afs_int32 eventID,
-              afs_int32 lAndT, long p1, long p2, long p3)
-{
-    return afs_icl_Event4(setp, eventID, lAndT, p1, p2, p3, (long)0);
-}
-
-int
-afs_icl_Event2(register struct afs_icl_set *setp, afs_int32 eventID,
-              afs_int32 lAndT, long p1, long p2)
-{
-    return afs_icl_Event4(setp, eventID, lAndT, p1, p2, (long)0, (long)0);
-}
-
-int
-afs_icl_Event1(register struct afs_icl_set *setp, afs_int32 eventID,
-              afs_int32 lAndT, long p1)
-{
-    return afs_icl_Event4(setp, eventID, lAndT, p1, (long)0, (long)0,
-                         (long)0);
-}
-
-int
-afs_icl_Event0(register struct afs_icl_set *setp, afs_int32 eventID,
-              afs_int32 lAndT)
-{
-    return afs_icl_Event4(setp, eventID, lAndT, (long)0, (long)0, (long)0,
-                         (long)0);
-}
-
-struct afs_icl_log *afs_icl_allLogs = 0;
-
-/* function to purge records from the start of the log, until there
- * is at least minSpace long's worth of space available without
- * making the head and the tail point to the same word.
- *
- * Log must be write-locked.
- */
-static void
-afs_icl_GetLogSpace(register struct afs_icl_log *logp, afs_int32 minSpace)
-{
-    register unsigned int tsize;
-
-    while (logp->logSize - logp->logElements <= minSpace) {
-       /* eat a record */
-       tsize = ((logp->datap[logp->firstUsed]) >> 24) & 0xff;
-       logp->logElements -= tsize;
-       logp->firstUsed += tsize;
-       if (logp->firstUsed >= logp->logSize)
-           logp->firstUsed -= logp->logSize;
-       logp->baseCookie += tsize;
-    }
-}
-
-/* append string astr to buffer, including terminating null char.
- *
- * log must be write-locked.
- */
-#define ICL_CHARSPERLONG       4
-static void
-afs_icl_AppendString(struct afs_icl_log *logp, char *astr)
-{
-    char *op;                  /* ptr to char to write */
-    int tc;
-    register int bib;          /* bytes in buffer */
-
-    bib = 0;
-    op = (char *)&(logp->datap[logp->firstFree]);
-    while (1) {
-       tc = *astr++;
-       *op++ = tc;
-       if (++bib >= ICL_CHARSPERLONG) {
-           /* new word */
-           bib = 0;
-           if (++(logp->firstFree) >= logp->logSize) {
-               logp->firstFree = 0;
-               op = (char *)&(logp->datap[0]);
-           }
-           logp->logElements++;
-       }
-       if (tc == 0)
-           break;
-    }
-    if (bib > 0) {
-       /* if we've used this word at all, allocate it */
-       if (++(logp->firstFree) >= logp->logSize) {
-           logp->firstFree = 0;
-       }
-       logp->logElements++;
-    }
-}
-
-/* add a long to the log, ignoring overflow (checked already) */
-#define ICL_APPENDINT32(lp, x) \
-    MACRO_BEGIN \
-        (lp)->datap[(lp)->firstFree] = (x); \
-       if (++((lp)->firstFree) >= (lp)->logSize) { \
-               (lp)->firstFree = 0; \
-       } \
-        (lp)->logElements++; \
-    MACRO_END
-
-#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
-#define ICL_APPENDLONG(lp, x) \
-    MACRO_BEGIN \
-       ICL_APPENDINT32((lp), ((x) >> 32) & 0xffffffffL); \
-       ICL_APPENDINT32((lp), (x) & 0xffffffffL); \
-    MACRO_END
-
-#else /* AFS_OSF_ENV */
-#define ICL_APPENDLONG(lp, x) ICL_APPENDINT32((lp), (x))
-#endif /* AFS_OSF_ENV */
-
-/* routine to tell whether we're dealing with the address or the
- * object itself
- */
-int
-afs_icl_UseAddr(int type)
-{
-    if (type == ICL_TYPE_HYPER || type == ICL_TYPE_STRING
-       || type == ICL_TYPE_FID || type == ICL_TYPE_INT64)
-       return 1;
-    else
-       return 0;
-}
-
-/* Function to append a record to the log.  Written for speed
- * since we know that we're going to have to make this work fast
- * pretty soon, anyway.  The log must be unlocked.
- */
-
-void
-afs_icl_AppendRecord(register struct afs_icl_log *logp, afs_int32 op,
-                    afs_int32 types, long p1, long p2, long p3, long p4)
-{
-    int rsize;                 /* record size in longs */
-    register int tsize;                /* temp size */
-    osi_timeval_t tv;
-    int t1, t2, t3, t4;
-
-    t4 = types & 0x3f;         /* decode types */
-    types >>= 6;
-    t3 = types & 0x3f;
-    types >>= 6;
-    t2 = types & 0x3f;
-    types >>= 6;
-    t1 = types & 0x3f;
-
-    osi_GetTime(&tv);          /* It panics for solaris if inside */
-    ObtainWriteLock(&logp->lock, 182);
-    if (!logp->datap) {
-       ReleaseWriteLock(&logp->lock);
-       return;
-    }
-
-    /* get timestamp as # of microseconds since some time that doesn't
-     * change that often.  This algorithm ticks over every 20 minutes
-     * or so (1000 seconds).  Write a timestamp record if it has.
-     */
-    if (tv.tv_sec - logp->lastTS > 1024) {
-       /* the timer has wrapped -- write a timestamp record */
-       if (logp->logSize - logp->logElements <= 5)
-           afs_icl_GetLogSpace(logp, 5);
-
-       ICL_APPENDINT32(logp,
-                       (afs_int32) (5 << 24) + (ICL_TYPE_UNIXDATE << 18));
-       ICL_APPENDINT32(logp, (afs_int32) ICL_INFO_TIMESTAMP);
-       ICL_APPENDINT32(logp, (afs_int32) 0);   /* use thread ID zero for clocks */
-       ICL_APPENDINT32(logp,
-                       (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 +
-                       tv.tv_usec);
-       ICL_APPENDINT32(logp, (afs_int32) tv.tv_sec);
-
-       logp->lastTS = tv.tv_sec;
-    }
-
-    rsize = 4;                 /* base case */
-    if (t1) {
-       /* compute size of parameter p1.  Only tricky case is string.
-        * In that case, we have to call strlen to get the string length.
-        */
-       ICL_SIZEHACK(t1, p1);
-    }
-    if (t2) {
-       /* compute size of parameter p2.  Only tricky case is string.
-        * In that case, we have to call strlen to get the string length.
-        */
-       ICL_SIZEHACK(t2, p2);
-    }
-    if (t3) {
-       /* compute size of parameter p3.  Only tricky case is string.
-        * In that case, we have to call strlen to get the string length.
-        */
-       ICL_SIZEHACK(t3, p3);
-    }
-    if (t4) {
-       /* compute size of parameter p4.  Only tricky case is string.
-        * In that case, we have to call strlen to get the string length.
-        */
-       ICL_SIZEHACK(t4, p4);
-    }
-
-    /* At this point, we've computed all of the parameter sizes, and
-     * have in rsize the size of the entire record we want to append.
-     * Next, we check that we actually have room in the log to do this
-     * work, and then we do the append.
-     */
-    if (rsize > 255) {
-       ReleaseWriteLock(&logp->lock);
-       return;                 /* log record too big to express */
-    }
-
-    if (logp->logSize - logp->logElements <= rsize)
-       afs_icl_GetLogSpace(logp, rsize);
-
-    ICL_APPENDINT32(logp,
-                   (afs_int32) (rsize << 24) + (t1 << 18) + (t2 << 12) +
-                   (t3 << 6) + t4);
-    ICL_APPENDINT32(logp, (afs_int32) op);
-    ICL_APPENDINT32(logp, (afs_int32) osi_ThreadUnique());
-    ICL_APPENDINT32(logp,
-                   (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 + tv.tv_usec);
-
-    if (t1) {
-       /* marshall parameter 1 now */
-       if (t1 == ICL_TYPE_STRING) {
-           afs_icl_AppendString(logp, (char *)p1);
-       } else if (t1 == ICL_TYPE_HYPER) {
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p1)->high);
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p1)->low);
-       } else if (t1 == ICL_TYPE_INT64) {
-#ifdef AFSLITTLE_ENDIAN
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[0]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) p1);
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-#endif /* AFS_64BIT_CLIENT */
-#else /* AFSLITTLE_ENDIAN */
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[1]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-           ICL_APPENDINT32(logp, (afs_int32) p1);
-#endif /* AFS_64BIT_CLIENT */
-#endif /* AFSLITTLE_ENDIAN */
-       } else if (t1 == ICL_TYPE_FID) {
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[2]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[3]);
-       }
-#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
-       else if (t1 == ICL_TYPE_INT32)
-           ICL_APPENDINT32(logp, (afs_int32) p1);
-#endif /* AFS_OSF_ENV */
-       else
-           ICL_APPENDLONG(logp, p1);
-    }
-    if (t2) {
-       /* marshall parameter 2 now */
-       if (t2 == ICL_TYPE_STRING)
-           afs_icl_AppendString(logp, (char *)p2);
-       else if (t2 == ICL_TYPE_HYPER) {
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p2)->high);
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p2)->low);
-       } else if (t2 == ICL_TYPE_INT64) {
-#ifdef AFSLITTLE_ENDIAN
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[0]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) p2);
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-#endif /* AFS_64BIT_CLIENT */
-#else /* AFSLITTLE_ENDIAN */
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[1]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-           ICL_APPENDINT32(logp, (afs_int32) p2);
-#endif /* AFS_64BIT_CLIENT */
-#endif /* AFSLITTLE_ENDIAN */
-       } else if (t2 == ICL_TYPE_FID) {
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[2]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[3]);
-       }
-#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
-       else if (t2 == ICL_TYPE_INT32)
-           ICL_APPENDINT32(logp, (afs_int32) p2);
-#endif /* AFS_OSF_ENV */
-       else
-           ICL_APPENDLONG(logp, p2);
-    }
-    if (t3) {
-       /* marshall parameter 3 now */
-       if (t3 == ICL_TYPE_STRING)
-           afs_icl_AppendString(logp, (char *)p3);
-       else if (t3 == ICL_TYPE_HYPER) {
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p3)->high);
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p3)->low);
-       } else if (t3 == ICL_TYPE_INT64) {
-#ifdef AFSLITTLE_ENDIAN
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[0]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) p3);
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-#endif /* AFS_64BIT_CLIENT */
-#else /* AFSLITTLE_ENDIAN */
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[1]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-           ICL_APPENDINT32(logp, (afs_int32) p3);
-#endif /* AFS_64BIT_CLIENT */
-#endif /* AFSLITTLE_ENDIAN */
-       } else if (t3 == ICL_TYPE_FID) {
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[2]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[3]);
-       }
-#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
-       else if (t3 == ICL_TYPE_INT32)
-           ICL_APPENDINT32(logp, (afs_int32) p3);
-#endif /* AFS_OSF_ENV */
-       else
-           ICL_APPENDLONG(logp, p3);
-    }
-    if (t4) {
-       /* marshall parameter 4 now */
-       if (t4 == ICL_TYPE_STRING)
-           afs_icl_AppendString(logp, (char *)p4);
-       else if (t4 == ICL_TYPE_HYPER) {
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p4)->high);
-           ICL_APPENDINT32(logp,
-                           (afs_int32) ((struct afs_hyper_t *)p4)->low);
-       } else if (t4 == ICL_TYPE_INT64) {
-#ifdef AFSLITTLE_ENDIAN
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[0]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) p4);
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-#endif /* AFS_64BIT_CLIENT */
-#else /* AFSLITTLE_ENDIAN */
-#ifdef AFS_64BIT_CLIENT
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[1]);
-#else /* AFS_64BIT_CLIENT */
-           ICL_APPENDINT32(logp, (afs_int32) 0);
-           ICL_APPENDINT32(logp, (afs_int32) p4);
-#endif /* AFS_64BIT_CLIENT */
-#endif /* AFSLITTLE_ENDIAN */
-       } else if (t4 == ICL_TYPE_FID) {
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[0]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[1]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[2]);
-           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[3]);
-       }
-#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
-       else if (t4 == ICL_TYPE_INT32)
-           ICL_APPENDINT32(logp, (afs_int32) p4);
-#endif /* AFS_OSF_ENV */
-       else
-           ICL_APPENDLONG(logp, p4);
-    }
-    ReleaseWriteLock(&logp->lock);
-}
-
-/* create a log with size logSize; return it in *outLogpp and tag
- * it with name "name."
- */
-int
-afs_icl_CreateLog(char *name, afs_int32 logSize,
-                 struct afs_icl_log **outLogpp)
-{
-    return afs_icl_CreateLogWithFlags(name, logSize, /*flags */ 0, outLogpp);
-}
-
-/* create a log with size logSize; return it in *outLogpp and tag
- * it with name "name."  'flags' can be set to make the log unclearable.
- */
-int
-afs_icl_CreateLogWithFlags(char *name, afs_int32 logSize, afs_uint32 flags,
-                          struct afs_icl_log **outLogpp)
-{
-    register struct afs_icl_log *logp;
-
-    /* add into global list under lock */
-    ObtainWriteLock(&afs_icl_lock, 183);
-    if (!afs_icl_inited)
-       afs_icl_Init();
-
-    for (logp = afs_icl_allLogs; logp; logp = logp->nextp) {
-       if (strcmp(logp->name, name) == 0) {
-           /* found it already created, just return it */
-           logp->refCount++;
-           *outLogpp = logp;
-           if (flags & ICL_CRLOG_FLAG_PERSISTENT) {
-               ObtainWriteLock(&logp->lock, 184);
-               logp->states |= ICL_LOGF_PERSISTENT;
-               ReleaseWriteLock(&logp->lock);
-           }
-           ReleaseWriteLock(&afs_icl_lock);
-           return 0;
-       }
-    }
-
-    logp = (struct afs_icl_log *)
-       osi_AllocSmallSpace(sizeof(struct afs_icl_log));
-    memset((caddr_t) logp, 0, sizeof(*logp));
-
-    logp->refCount = 1;
-    logp->name = osi_AllocSmallSpace(strlen(name) + 1);
-    strcpy(logp->name, name);
-    LOCK_INIT(&logp->lock, "logp lock");
-    logp->logSize = logSize;
-    logp->datap = NULL;                /* don't allocate it until we need it */
-
-    if (flags & ICL_CRLOG_FLAG_PERSISTENT)
-       logp->states |= ICL_LOGF_PERSISTENT;
-
-    logp->nextp = afs_icl_allLogs;
-    afs_icl_allLogs = logp;
-    ReleaseWriteLock(&afs_icl_lock);
-
-    *outLogpp = logp;
-    return 0;
-}
-
-/* called with a log, a pointer to a buffer, the size of the buffer
- * (in *bufSizep), the starting cookie (in *cookiep, use 0 at the start)
- * and returns data in the provided buffer, and returns output flags
- * in *flagsp.  The flag ICL_COPYOUTF_MISSEDSOME is set if we can't
- * find the record with cookie value cookie.
- */
-int
-afs_icl_CopyOut(register struct afs_icl_log *logp, afs_int32 * bufferp,
-               afs_int32 * bufSizep, afs_uint32 * cookiep,
-               afs_int32 * flagsp)
-{
-    afs_int32 nwords;          /* number of words to copy out */
-    afs_uint32 startCookie;    /* first cookie to use */
-    afs_int32 outWords;                /* words we've copied out */
-    afs_int32 inWords;         /* max words to copy out */
-    afs_int32 code;            /* return code */
-    afs_int32 ix;              /* index we're copying from */
-    afs_int32 outFlags;                /* return flags */
-    afs_int32 inFlags;         /* flags passed in */
-    afs_int32 end;
-
-    inWords = *bufSizep;       /* max to copy out */
-    outWords = 0;              /* amount copied out */
-    startCookie = *cookiep;
-    outFlags = 0;
-    inFlags = *flagsp;
-    code = 0;
-
-    ObtainWriteLock(&logp->lock, 185);
-    if (!logp->datap) {
-       ReleaseWriteLock(&logp->lock);
-       goto done;
-    }
-
-    /* first, compute the index of the start cookie we've been passed */
-    while (1) {
-       /* (re-)compute where we should start */
-       if (startCookie < logp->baseCookie) {
-           if (startCookie)    /* missed some output */
-               outFlags |= ICL_COPYOUTF_MISSEDSOME;
-           /* skip to the first available record */
-           startCookie = logp->baseCookie;
-           *cookiep = startCookie;
-       }
-
-       /* compute where we find the first element to copy out */
-       ix = logp->firstUsed + startCookie - logp->baseCookie;
-       if (ix >= logp->logSize)
-           ix -= logp->logSize;
-
-       /* if have some data now, break out and process it */
-       if (startCookie - logp->baseCookie < logp->logElements)
-           break;
-
-       /* At end of log, so clear it if we need to */
-       if (inFlags & ICL_COPYOUTF_CLRAFTERREAD) {
-           logp->firstUsed = logp->firstFree = 0;
-           logp->logElements = 0;
-       }
-       /* otherwise, either wait for the data to arrive, or return */
-       if (!(inFlags & ICL_COPYOUTF_WAITIO)) {
-           ReleaseWriteLock(&logp->lock);
-           code = 0;
-           goto done;
-       }
-       logp->states |= ICL_LOGF_WAITING;
-       ReleaseWriteLock(&logp->lock);
-       afs_osi_Sleep(&logp->lock);
-       ObtainWriteLock(&logp->lock, 186);
-    }
-    /* copy out data from ix to logSize or firstFree, depending
-     * upon whether firstUsed <= firstFree (no wrap) or otherwise.
-     * be careful not to copy out more than nwords.
-     */
-    if (ix >= logp->firstUsed) {
-       if (logp->firstUsed <= logp->firstFree)
-           /* no wrapping */
-           end = logp->firstFree;      /* first element not to copy */
-       else
-           end = logp->logSize;
-       nwords = inWords;       /* don't copy more than this */
-       if (end - ix < nwords)
-           nwords = end - ix;
-       if (nwords > 0) {
-           memcpy((char *)bufferp, (char *)&logp->datap[ix],
-                  sizeof(afs_int32) * nwords);
-           outWords += nwords;
-           inWords -= nwords;
-           bufferp += nwords;
-       }
-       /* if we're going to copy more out below, we'll start here */
-       ix = 0;
-    }
-    /* now, if active part of the log has wrapped, there's more stuff
-     * starting at the head of the log.  Copy out more from there.
-     */
-    if (logp->firstUsed > logp->firstFree && ix < logp->firstFree
-       && inWords > 0) {
-       /* (more to) copy out from the wrapped section at the
-        * start of the log.  May get here even if didn't copy any
-        * above, if the cookie points directly into the wrapped section.
-        */
-       nwords = inWords;
-       if (logp->firstFree - ix < nwords)
-           nwords = logp->firstFree - ix;
-       memcpy((char *)bufferp, (char *)&logp->datap[ix],
-              sizeof(afs_int32) * nwords);
-       outWords += nwords;
-       inWords -= nwords;
-       bufferp += nwords;
-    }
-
-    ReleaseWriteLock(&logp->lock);
-
-  done:
-    if (code == 0) {
-       *bufSizep = outWords;
-       *flagsp = outFlags;
-    }
-    return code;
-}
-
-/* return basic parameter information about a log */
-int
-afs_icl_GetLogParms(struct afs_icl_log *logp, afs_int32 * maxSizep,
-                   afs_int32 * curSizep)
-{
-    ObtainReadLock(&logp->lock);
-    *maxSizep = logp->logSize;
-    *curSizep = logp->logElements;
-    ReleaseReadLock(&logp->lock);
-    return 0;
-}
-
-
-/* hold and release logs */
-int
-afs_icl_LogHold(register struct afs_icl_log *logp)
-{
-    ObtainWriteLock(&afs_icl_lock, 187);
-    logp->refCount++;
-    ReleaseWriteLock(&afs_icl_lock);
-    return 0;
-}
-
-/* hold and release logs, called with lock already held */
-int
-afs_icl_LogHoldNL(register struct afs_icl_log *logp)
-{
-    logp->refCount++;
-    return 0;
-}
-
-/* keep track of how many sets believe the log itself is allocated */
-int
-afs_icl_LogUse(register struct afs_icl_log *logp)
-{
-    ObtainWriteLock(&logp->lock, 188);
-    if (logp->setCount == 0) {
-       /* this is the first set actually using the log -- allocate it */
-       if (logp->logSize == 0) {
-           /* we weren't passed in a hint and it wasn't set */
-           logp->logSize = ICL_DEFAULT_LOGSIZE;
-       }
-       logp->datap =
-           (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * logp->logSize);
-#ifdef KERNEL_HAVE_PIN
-       pin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
-#endif
-    }
-    logp->setCount++;
-    ReleaseWriteLock(&logp->lock);
-    return 0;
-}
-
-/* decrement the number of real users of the log, free if possible */
-int
-afs_icl_LogFreeUse(register struct afs_icl_log *logp)
-{
-    ObtainWriteLock(&logp->lock, 189);
-    if (--logp->setCount == 0) {
-       /* no more users -- free it (but keep log structure around) */
-#ifdef KERNEL_HAVE_PIN
-       unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
-#endif
-       afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
-       logp->firstUsed = logp->firstFree = 0;
-       logp->logElements = 0;
-       logp->datap = NULL;
-    }
-    ReleaseWriteLock(&logp->lock);
-    return 0;
-}
-
-/* set the size of the log to 'logSize' */
-int
-afs_icl_LogSetSize(register struct afs_icl_log *logp, afs_int32 logSize)
-{
-    ObtainWriteLock(&logp->lock, 190);
-    if (!logp->datap) {
-       /* nothing to worry about since it's not allocated */
-       logp->logSize = logSize;
-    } else {
-       /* reset log */
-       logp->firstUsed = logp->firstFree = 0;
-       logp->logElements = 0;
-
-       /* free and allocate a new one */
-#ifdef KERNEL_HAVE_PIN
-       unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
-#endif
-       afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
-       logp->datap =
-           (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * logSize);
-#ifdef KERNEL_HAVE_PIN
-       pin((char *)logp->datap, sizeof(afs_int32) * logSize);
-#endif
-       logp->logSize = logSize;
-    }
-    ReleaseWriteLock(&logp->lock);
-
-    return 0;
-}
-
-/* free a log.  Called with afs_icl_lock locked. */
-int
-afs_icl_ZapLog(register struct afs_icl_log *logp)
-{
-    register struct afs_icl_log **lpp, *tp;
-
-    for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
-       if (tp == logp) {
-           /* found the dude we want to remove */
-           *lpp = logp->nextp;
-           osi_FreeSmallSpace(logp->name);
-#ifdef KERNEL_HAVE_PIN
-           unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
-#endif
-           afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
-           osi_FreeSmallSpace(logp);
-           break;              /* won't find it twice */
-       }
-    }
-    return 0;
-}
-
-/* do the release, watching for deleted entries */
-int
-afs_icl_LogRele(register struct afs_icl_log *logp)
-{
-    ObtainWriteLock(&afs_icl_lock, 191);
-    if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
-       afs_icl_ZapLog(logp);   /* destroys logp's lock! */
-    }
-    ReleaseWriteLock(&afs_icl_lock);
-    return 0;
-}
-
-/* do the release, watching for deleted entries, log already held */
-int
-afs_icl_LogReleNL(register struct afs_icl_log *logp)
-{
-    if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
-       afs_icl_ZapLog(logp);   /* destroys logp's lock! */
-    }
-    return 0;
-}
-
-/* zero out the log */
-int
-afs_icl_ZeroLog(register struct afs_icl_log *logp)
-{
-    ObtainWriteLock(&logp->lock, 192);
-    logp->firstUsed = logp->firstFree = 0;
-    logp->logElements = 0;
-    logp->baseCookie = 0;
-    ReleaseWriteLock(&logp->lock);
-    return 0;
-}
-
-/* free a log entry, and drop its reference count */
-int
-afs_icl_LogFree(register struct afs_icl_log *logp)
-{
-    ObtainWriteLock(&logp->lock, 193);
-    logp->states |= ICL_LOGF_DELETED;
-    ReleaseWriteLock(&logp->lock);
-    afs_icl_LogRele(logp);
-    return 0;
-}
-
-/* find a log by name, returning it held */
-struct afs_icl_log *
-afs_icl_FindLog(char *name)
-{
-    register struct afs_icl_log *tp;
-    ObtainWriteLock(&afs_icl_lock, 194);
-    for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
-       if (strcmp(tp->name, name) == 0) {
-           /* this is the dude we want */
-           tp->refCount++;
-           break;
-       }
-    }
-    ReleaseWriteLock(&afs_icl_lock);
-    return tp;
-}
-
-int
-afs_icl_EnumerateLogs(int (*aproc)
-                       (char *name, char *arock, struct afs_icl_log * tp),
-                     char *arock)
-{
-    register struct afs_icl_log *tp;
-    register afs_int32 code;
-
-    code = 0;
-    ObtainWriteLock(&afs_icl_lock, 195);
-    for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
-       tp->refCount++;         /* hold this guy */
-       ReleaseWriteLock(&afs_icl_lock);
-       ObtainReadLock(&tp->lock);
-       code = (*aproc) (tp->name, arock, tp);
-       ReleaseReadLock(&tp->lock);
-       ObtainWriteLock(&afs_icl_lock, 196);
-       if (--tp->refCount == 0)
-           afs_icl_ZapLog(tp);
-       if (code)
-           break;
-    }
-    ReleaseWriteLock(&afs_icl_lock);
-    return code;
-}
-
-struct afs_icl_set *afs_icl_allSets = 0;
-
-int
-afs_icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
-                 struct afs_icl_log *fatalLogp,
-                 struct afs_icl_set **outSetpp)
-{
-    return afs_icl_CreateSetWithFlags(name, baseLogp, fatalLogp,
-                                     /*flags */ 0, outSetpp);
-}
-
-/* create a set, given pointers to base and fatal logs, if any.
- * Logs are unlocked, but referenced, and *outSetpp is returned
- * referenced.  Function bumps reference count on logs, since it
- * addds references from the new afs_icl_set.  When the set is destroyed,
- * those references will be released.
- */
-int
-afs_icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
-                          struct afs_icl_log *fatalLogp, afs_uint32 flags,
-                          struct afs_icl_set **outSetpp)
-{
-    register struct afs_icl_set *setp;
-    register int i;
-    afs_int32 states = ICL_DEFAULT_SET_STATES;
-
-    ObtainWriteLock(&afs_icl_lock, 197);
-    if (!afs_icl_inited)
-       afs_icl_Init();
-
-    for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
-       if (strcmp(setp->name, name) == 0) {
-           setp->refCount++;
-           *outSetpp = setp;
-           if (flags & ICL_CRSET_FLAG_PERSISTENT) {
-               ObtainWriteLock(&setp->lock, 198);
-               setp->states |= ICL_SETF_PERSISTENT;
-               ReleaseWriteLock(&setp->lock);
-           }
-           ReleaseWriteLock(&afs_icl_lock);
-           return 0;
-       }
-    }
-
-    /* determine initial state */
-    if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
-       states = ICL_SETF_ACTIVE;
-    else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
-       states = ICL_SETF_FREED;
-    if (flags & ICL_CRSET_FLAG_PERSISTENT)
-       states |= ICL_SETF_PERSISTENT;
-
-    setp = (struct afs_icl_set *)afs_osi_Alloc(sizeof(struct afs_icl_set));
-    memset((caddr_t) setp, 0, sizeof(*setp));
-    setp->refCount = 1;
-    if (states & ICL_SETF_FREED)
-       states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
-    setp->states = states;
-
-    LOCK_INIT(&setp->lock, "setp lock");
-    /* next lock is obtained in wrong order, hierarchy-wise, but
-     * it doesn't matter, since no one can find this lock yet, since
-     * the afs_icl_lock is still held, and thus the obtain can't block.
-     */
-    ObtainWriteLock(&setp->lock, 199);
-    setp->name = osi_AllocSmallSpace(strlen(name) + 1);
-    strcpy(setp->name, name);
-    setp->nevents = ICL_DEFAULTEVENTS;
-    setp->eventFlags = afs_osi_Alloc(ICL_DEFAULTEVENTS);
-#ifdef KERNEL_HAVE_PIN
-    pin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
-#endif
-    for (i = 0; i < ICL_DEFAULTEVENTS; i++)
-       setp->eventFlags[i] = 0xff;     /* default to enabled */
-
-    /* update this global info under the afs_icl_lock */
-    setp->nextp = afs_icl_allSets;
-    afs_icl_allSets = setp;
-    ReleaseWriteLock(&afs_icl_lock);
-
-    /* set's basic lock is still held, so we can finish init */
-    if (baseLogp) {
-       setp->logs[0] = baseLogp;
-       afs_icl_LogHold(baseLogp);
-       if (!(setp->states & ICL_SETF_FREED))
-           afs_icl_LogUse(baseLogp);   /* log is actually being used */
-    }
-    if (fatalLogp) {
-       setp->logs[1] = fatalLogp;
-       afs_icl_LogHold(fatalLogp);
-       if (!(setp->states & ICL_SETF_FREED))
-           afs_icl_LogUse(fatalLogp);  /* log is actually being used */
-    }
-    ReleaseWriteLock(&setp->lock);
-
-    *outSetpp = setp;
-    return 0;
-}
-
-/* function to change event enabling information for a particular set */
-int
-afs_icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
-{
-    char *tp;
-
-    ObtainWriteLock(&setp->lock, 200);
-    if (!ICL_EVENTOK(setp, eventID)) {
-       ReleaseWriteLock(&setp->lock);
-       return -1;
-    }
-    tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
-    if (setValue)
-       *tp |= ICL_EVENTMASK(eventID);
-    else
-       *tp &= ~(ICL_EVENTMASK(eventID));
-    ReleaseWriteLock(&setp->lock);
-    return 0;
-}
-
-/* return indication of whether a particular event ID is enabled
- * for tracing.  If *getValuep is set to 0, the event is disabled,
- * otherwise it is enabled.  All events start out enabled by default.
- */
-int
-afs_icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
-{
-    ObtainReadLock(&setp->lock);
-    if (!ICL_EVENTOK(setp, eventID)) {
-       ReleaseWriteLock(&setp->lock);
-       return -1;
-    }
-    if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
-       *getValuep = 1;
-    else
-       *getValuep = 0;
-    ReleaseReadLock(&setp->lock);
-    return 0;
-}
-
-/* hold and release event sets */
-int
-afs_icl_SetHold(register struct afs_icl_set *setp)
-{
-    ObtainWriteLock(&afs_icl_lock, 201);
-    setp->refCount++;
-    ReleaseWriteLock(&afs_icl_lock);
-    return 0;
-}
-
-/* free a set.  Called with afs_icl_lock locked */
-int
-afs_icl_ZapSet(register struct afs_icl_set *setp)
-{
-    register struct afs_icl_set **lpp, *tp;
-    int i;
-    register struct afs_icl_log *tlp;
-
-    for (lpp = &afs_icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
-       if (tp == setp) {
-           /* found the dude we want to remove */
-           *lpp = setp->nextp;
-           osi_FreeSmallSpace(setp->name);
-#ifdef KERNEL_HAVE_PIN
-           unpin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
-#endif
-           afs_osi_Free(setp->eventFlags, ICL_DEFAULTEVENTS);
-           for (i = 0; i < ICL_LOGSPERSET; i++) {
-               if ((tlp = setp->logs[i]))
-                   afs_icl_LogReleNL(tlp);
-           }
-           osi_FreeSmallSpace(setp);
-           break;              /* won't find it twice */
-       }
-    }
-    return 0;
-}
-
-/* do the release, watching for deleted entries */
-int
-afs_icl_SetRele(register struct afs_icl_set *setp)
-{
-    ObtainWriteLock(&afs_icl_lock, 202);
-    if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
-       afs_icl_ZapSet(setp);   /* destroys setp's lock! */
-    }
-    ReleaseWriteLock(&afs_icl_lock);
-    return 0;
-}
-
-/* free a set entry, dropping its reference count */
-int
-afs_icl_SetFree(register struct afs_icl_set *setp)
-{
-    ObtainWriteLock(&setp->lock, 203);
-    setp->states |= ICL_SETF_DELETED;
-    ReleaseWriteLock(&setp->lock);
-    afs_icl_SetRele(setp);
-    return 0;
-}
-
-/* find a set by name, returning it held */
-struct afs_icl_set *
-afs_icl_FindSet(char *name)
-{
-    register struct afs_icl_set *tp;
-    ObtainWriteLock(&afs_icl_lock, 204);
-    for (tp = afs_icl_allSets; tp; tp = tp->nextp) {
-       if (strcmp(tp->name, name) == 0) {
-           /* this is the dude we want */
-           tp->refCount++;
-           break;
-       }
-    }
-    ReleaseWriteLock(&afs_icl_lock);
-    return tp;
-}
-
-/* zero out all the logs in the set */
-int
-afs_icl_ZeroSet(struct afs_icl_set *setp)
-{
-    register int i;
-    int code = 0;
-    int tcode;
-    struct afs_icl_log *logp;
-
-    ObtainReadLock(&setp->lock);
-    for (i = 0; i < ICL_LOGSPERSET; i++) {
-       logp = setp->logs[i];
-       if (logp) {
-           afs_icl_LogHold(logp);
-           tcode = afs_icl_ZeroLog(logp);
-           if (tcode != 0)
-               code = tcode;   /* save the last bad one */
-           afs_icl_LogRele(logp);
-       }
-    }
-    ReleaseReadLock(&setp->lock);
-    return code;
-}
-
-int
-afs_icl_EnumerateSets(int (*aproc)
-                       (char *name, char *arock, struct afs_icl_log * tp),
-                     char *arock)
-{
-    register struct afs_icl_set *tp, *np;
-    register afs_int32 code;
-
-    code = 0;
-    ObtainWriteLock(&afs_icl_lock, 205);
-    for (tp = afs_icl_allSets; tp; tp = np) {
-       tp->refCount++;         /* hold this guy */
-       ReleaseWriteLock(&afs_icl_lock);
-       code = (*aproc) (tp->name, arock, (struct afs_icl_log *)tp);
-       ObtainWriteLock(&afs_icl_lock, 206);
-       np = tp->nextp;         /* tp may disappear next, but not np */
-       if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
-           afs_icl_ZapSet(tp);
-       if (code)
-           break;
-    }
-    ReleaseWriteLock(&afs_icl_lock);
-    return code;
-}
-
-int
-afs_icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
-{
-    register int i;
-    int code = -1;
-
-    ObtainWriteLock(&setp->lock, 207);
-    for (i = 0; i < ICL_LOGSPERSET; i++) {
-       if (!setp->logs[i]) {
-           setp->logs[i] = newlogp;
-           code = i;
-           afs_icl_LogHold(newlogp);
-           if (!(setp->states & ICL_SETF_FREED)) {
-               /* bump up the number of sets using the log */
-               afs_icl_LogUse(newlogp);
-           }
-           break;
-       }
-    }
-    ReleaseWriteLock(&setp->lock);
-    return code;
-}
-
-int
-afs_icl_SetSetStat(struct afs_icl_set *setp, int op)
-{
-    int i;
-    afs_int32 code;
-    struct afs_icl_log *logp;
-
-    ObtainWriteLock(&setp->lock, 208);
-    switch (op) {
-    case ICL_OP_SS_ACTIVATE:   /* activate a log */
-       /*
-        * If we are not already active, see if we have released
-        * our demand that the log be allocated (FREED set).  If
-        * we have, reassert our desire.
-        */
-       if (!(setp->states & ICL_SETF_ACTIVE)) {
-           if (setp->states & ICL_SETF_FREED) {
-               /* have to reassert desire for logs */
-               for (i = 0; i < ICL_LOGSPERSET; i++) {
-                   logp = setp->logs[i];
-                   if (logp) {
-                       afs_icl_LogHold(logp);
-                       afs_icl_LogUse(logp);
-                       afs_icl_LogRele(logp);
-                   }
-               }
-               setp->states &= ~ICL_SETF_FREED;
-           }
-           setp->states |= ICL_SETF_ACTIVE;
-       }
-       code = 0;
-       break;
-
-    case ICL_OP_SS_DEACTIVATE: /* deactivate a log */
-       /* this doesn't require anything beyond clearing the ACTIVE flag */
-       setp->states &= ~ICL_SETF_ACTIVE;
-       code = 0;
-       break;
-
-    case ICL_OP_SS_FREE:       /* deassert design for log */
-       /* 
-        * if we are already in this state, do nothing; otherwise
-        * deassert desire for log
-        */
-       if (setp->states & ICL_SETF_ACTIVE)
-           code = EINVAL;
-       else {
-           if (!(setp->states & ICL_SETF_FREED)) {
-               for (i = 0; i < ICL_LOGSPERSET; i++) {
-                   logp = setp->logs[i];
-                   if (logp) {
-                       afs_icl_LogHold(logp);
-                       afs_icl_LogFreeUse(logp);
-                       afs_icl_LogRele(logp);
-                   }
-               }
-               setp->states |= ICL_SETF_FREED;
-           }
-           code = 0;
-       }
-       break;
-
-    default:
-       code = EINVAL;
-    }
-    ReleaseWriteLock(&setp->lock);
-    return code;
-}
index bebdae1..3983a19 100644 (file)
@@ -21,6 +21,7 @@ RCSID
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* afs statistics */
 #include "afs/afs_osi.h"
+#include "afs/afs_md5.h"
 
 /* Local variables. */
 afs_rwlock_t afs_xcell;                /* Export for cmdebug peeking at locks */
@@ -571,6 +572,17 @@ afs_choose_cell_by_name(struct cell *cell, void *arg)
 }
 
 static void *
+afs_choose_cell_by_handle(struct cell *cell, void *arg)
+{
+    if (!arg) {
+       /* Safety net */
+       return cell;
+    } else {
+       return memcmp(cell->cellHandle, (char *)arg, 16) ? NULL : cell;
+    }
+}
+
+static void *
 afs_choose_cell_by_num(struct cell *cell, void *arg)
 {
     return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
@@ -657,6 +669,17 @@ afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
 }
 
 struct cell *
+afs_GetCellByHandle(void *handle, afs_int32 locktype)
+{
+    struct cell *tc;
+
+    tc = afs_TraverseCells(&afs_choose_cell_by_handle, handle);
+    if (tc)
+       afs_UpdateCellLRU(tc);
+    return tc;
+}
+
+struct cell *
 afs_GetPrimaryCell(afs_int32 locktype)
 {
     return afs_GetCellByName(afs_thiscell, locktype);
@@ -725,6 +748,7 @@ afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags,
        tc->cellName = afs_strdup(acellName);
        tc->fsport = AFS_FSPORT;
        tc->vlport = AFS_VLPORT;
+       AFS_MD5_String(tc->cellHandle, tc->cellName, strlen(tc->cellName));
        RWLOCK_INIT(&tc->lock, "cell lock");
        newc = 1;
        if (afs_thiscell && !strcmp(acellName, afs_thiscell))
index f091d96..8ca37a6 100644 (file)
@@ -2250,6 +2250,28 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
 
            tdc->validPos = Position + size;
            afs_CFileTruncate(file, size);      /* prune it */
+        } else if (afs_IsDynrootMount(avc)) {
+           char *dynrootDir;
+           int dynrootLen;
+
+           afs_GetDynrootMount(&dynrootDir, &dynrootLen, &tsmall->OutStatus);
+
+           dynrootDir += Position;
+           dynrootLen -= Position;
+           if (size > dynrootLen)
+               size = dynrootLen;
+           if (size < 0)
+               size = 0;
+           code = afs_CFileWrite(file, 0, 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.
index 1d2563e..80879c7 100644 (file)
  *
  * Implements:
  * afs_IsDynrootFid
+ * afs_IsDynrootMountFid
+ * afs_IsDynrootAnyFid
  * afs_GetDynrootFid
+ * afs_GetDynrootMountFid
  * afs_IsDynroot
+ * afs_IsDynrootMount
+ * afs_IsDynrootAny
  * afs_DynrootInvalidate
  * afs_GetDynroot
  * afs_PutDynroot
 
 #include "afs/prs_fs.h"
 #include "afs/dir.h"
+#include "afs/afs_dynroot.h"
 
 #define AFS_DYNROOT_CELLNAME   "dynroot"
 #define AFS_DYNROOT_VOLUME     1
 #define AFS_DYNROOT_VNODE      1
+#define AFS_DYNROOT_MOUNT_VNODE 3
 #define AFS_DYNROOT_UNIQUE     1
 
-/*
- * Vnode numbers in dynroot are composed of a type field (upper 8 bits)
- * and a type-specific identifier in the lower 24 bits.
- */
-#define VN_TYPE_CELL           0x01    /* Corresponds to a struct cell */
-#define VN_TYPE_ALIAS          0x02    /* Corresponds to a struct cell_alias */
-#define VN_TYPE_SYMLINK                0x03    /* User-created symlink in /afs */
-
-#define VNUM_TO_VNTYPE(vnum)   ((vnum) >> 24)
-#define VNUM_TO_VNID(vnum)     ((vnum) & 0x00ffffff)
-#define VNUM_FROM_TYPEID(type, id) \
-                               ((type) << 24 | (id))
-#define VNUM_TO_CIDX(vnum)     (VNUM_TO_VNID(vnum) >> 2)
-#define VNUM_TO_RW(vnum)       (VNUM_TO_VNID(vnum) >> 1 & 1)
-#define VNUM_FROM_CIDX_RW(cidx, rw) \
-                               VNUM_FROM_TYPEID(VN_TYPE_CELL, \
-                                                ((cidx) << 2 | (rw) << 1))
-#define VNUM_FROM_CAIDX_RW(caidx, rw) \
-                               VNUM_FROM_TYPEID(VN_TYPE_ALIAS, \
-                                                ((caidx) << 2 | (rw) << 1))
-
+static int afs_dynrootInit = 0;
 static int afs_dynrootEnable = 0;
 static int afs_dynrootCell = 0;
 
@@ -71,6 +58,8 @@ static afs_rwlock_t afs_dynrootDirLock;
 /* Start of variables protected by afs_dynrootDirLock */
 static char *afs_dynrootDir = NULL;
 static int afs_dynrootDirLen;
+static char *afs_dynrootMountDir = NULL;
+static int afs_dynrootMountDirLen;
 static int afs_dynrootDirLinkcnt;
 static int afs_dynrootDirVersion;
 static int afs_dynrootVersion = 1;
@@ -97,7 +86,7 @@ static int afs_dynSymlinkIndex = 0;
 static int
 afs_dynrootCellInit()
 {
-    if (afs_dynrootEnable && !afs_dynrootCell) {
+    if (!afs_dynrootCell) {
        afs_int32 cellHosts[MAXCELLHOSTS];
        struct cell *tc;
        int code;
@@ -121,15 +110,37 @@ afs_dynrootCellInit()
 /*
  * Returns non-zero iff fid corresponds to the top of the dynroot volume.
  */
+static int
+_afs_IsDynrootFid(struct VenusFid *fid)
+{
+    return (fid->Cell == afs_dynrootCell
+           && fid->Fid.Volume == AFS_DYNROOT_VOLUME
+           && fid->Fid.Vnode == AFS_DYNROOT_VNODE
+           && fid->Fid.Unique == AFS_DYNROOT_UNIQUE);
+}
+
 int
 afs_IsDynrootFid(struct VenusFid *fid)
 {
-    return (afs_dynrootEnable && fid->Cell == afs_dynrootCell
+    return (afs_dynrootEnable && _afs_IsDynrootFid(fid));
+}
+
+int
+afs_IsDynrootMountFid(struct VenusFid *fid)
+{
+    return (fid->Cell == afs_dynrootCell
            && fid->Fid.Volume == AFS_DYNROOT_VOLUME
-           && fid->Fid.Vnode == AFS_DYNROOT_VNODE
+           && fid->Fid.Vnode == AFS_DYNROOT_MOUNT_VNODE
            && fid->Fid.Unique == AFS_DYNROOT_UNIQUE);
 }
 
+int
+afs_IsDynrootAnyFid(struct VenusFid *fid)
+{
+    return (fid->Cell == afs_dynrootCell
+           && fid->Fid.Volume == AFS_DYNROOT_VOLUME);
+}
+
 /*
  * Obtain the magic dynroot volume Fid.
  */
@@ -142,6 +153,15 @@ afs_GetDynrootFid(struct VenusFid *fid)
     fid->Fid.Unique = AFS_DYNROOT_UNIQUE;
 }
 
+void
+afs_GetDynrootMountFid(struct VenusFid *fid)
+{
+    fid->Cell = afs_dynrootCell;
+    fid->Fid.Volume = AFS_DYNROOT_VOLUME;
+    fid->Fid.Vnode = AFS_DYNROOT_MOUNT_VNODE;
+    fid->Fid.Unique = AFS_DYNROOT_UNIQUE;
+}
+
 /*
  * Returns non-zero iff avc is a pointer to the dynroot /afs vnode.
  */
@@ -151,6 +171,18 @@ afs_IsDynroot(struct vcache *avc)
     return afs_IsDynrootFid(&avc->fid);
 }
 
+int
+afs_IsDynrootMount(struct vcache *avc)
+{
+    return afs_IsDynrootMountFid(&avc->fid);
+}
+
+int
+afs_IsDynrootAny(struct vcache *avc)
+{
+    return afs_IsDynrootAnyFid(&avc->fid);
+}
+
 /*
  * Given the current page and chunk pointers in a directory, adjust them
  * appropriately so that the given file name can be appended.  Used for
@@ -302,6 +334,9 @@ afs_RebuildDynroot(void)
     /* Reserve space for "." and ".." */
     curChunk += 2;
 
+    /* Reserve space for the dynamic-mount directory */
+    afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME, &curPage, &curChunk);
+
     for (cellidx = 0;; cellidx++) {
        c = afs_GetCellByIndex(cellidx, READ_LOCK);
        if (!c)
@@ -371,10 +406,12 @@ afs_RebuildDynroot(void)
     for (i = 0; i < NHASHENT; i++)
        dirHeader->hashTable[i] = 0;
 
-    /* Install "." and ".." */
+    /* Install ".", "..", and the dynamic mount directory */
     afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
     afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
-    linkCount += 2;
+    afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
+                         AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE);
+    linkCount += 3;
 
     for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
        c = afs_GetCellByIndex(cellidx, READ_LOCK);
@@ -433,6 +470,49 @@ afs_RebuildDynroot(void)
     ReleaseWriteLock(&afs_dynrootDirLock);
 }
 
+static void
+afs_RebuildDynrootMount(void)
+{
+    int i;
+    int curChunk, curPage;
+    char *newDir;
+    struct DirHeader *dirHeader;
+
+    newDir = afs_osi_Alloc(AFS_PAGESIZE);
+
+    /*
+     * 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);
+
+    ObtainWriteLock(&afs_dynrootDirLock, 549);
+    if (afs_dynrootMountDir)
+       afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
+    afs_dynrootMountDir = newDir;
+    afs_dynrootMountDirLen = AFS_PAGESIZE;
+    ReleaseWriteLock(&afs_dynrootDirLock);
+}
+
 /*
  * Returns a pointer to the base of the dynroot directory in memory,
  * length thereof, and a FetchStatus.
@@ -468,6 +548,37 @@ afs_GetDynroot(char **dynrootDir, int *dynrootLen,
     }
 }
 
+void
+afs_GetDynrootMount(char **dynrootDir, int *dynrootLen,
+                   struct AFSFetchStatus *status)
+{
+    ObtainReadLock(&afs_dynrootDirLock);
+    if (!afs_dynrootMountDir) {
+       ReleaseReadLock(&afs_dynrootDirLock);
+       afs_RebuildDynrootMount();
+       ObtainReadLock(&afs_dynrootDirLock);
+    }
+
+    if (dynrootDir)
+       *dynrootDir = afs_dynrootMountDir;
+    if (dynrootLen)
+       *dynrootLen = afs_dynrootMountDirLen;
+
+    if (status) {
+       memset(status, 0, sizeof(struct AFSFetchStatus));
+       status->FileType = Directory;
+       status->LinkCount = 1;
+       status->Length = afs_dynrootMountDirLen;
+       status->DataVersion = 1;
+       status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
+       status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
+       status->UnixModeBits = 0755;
+       status->ParentVnode = 1;
+       status->ParentUnique = 1;
+       status->dataVersionHigh = 0;
+    }
+}
+
 /*
  * Puts back the dynroot read lock.
  */
@@ -485,15 +596,22 @@ afs_PutDynroot(void)
 int
 afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
 {
-    if (!afs_dynrootEnable)
-       return 0;
+    char *bp, tbuf[CVBS];
 
-    if (afs_IsDynroot(avc)) {
+    if (_afs_IsDynrootFid(&avc->fid)) {
+       if (!afs_dynrootEnable)
+           return 0;
        afs_GetDynroot(0, 0, status);
        afs_PutDynroot();
        return 1;
     }
 
+    if (afs_IsDynrootMount(avc)) {
+       afs_GetDynrootMount(0, 0, status);
+       afs_PutDynroot();
+       return 1;
+    }
+
     /*
      * Check if this is an entry under /afs, e.g. /afs/cellname.
      */
@@ -540,7 +658,8 @@ afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
        }
 
        if (VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) != VN_TYPE_CELL
-           && VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) != VN_TYPE_ALIAS) {
+           && VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) != VN_TYPE_ALIAS
+           && VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) != VN_TYPE_MOUNT) {
            afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
                     VNUM_TO_VNTYPE(avc->fid.Fid.Vnode));
            return 0;
@@ -579,6 +698,31 @@ afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
 
            status->UnixModeBits = 0755;
            afs_PutCellAlias(ca);
+
+       } else if (VNUM_TO_VNTYPE(avc->fid.Fid.Vnode) == VN_TYPE_MOUNT) {
+           c = afs_GetCellByIndex(cellidx, READ_LOCK);
+           if (!c) {
+               afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
+                        cellidx);
+               return 0;
+           }
+
+           /*
+            * linkData needs to contain "%cell:volumeid"
+            */
+           namelen = strlen(c->cellName);
+           bp = afs_cv2string(&tbuf[CVBS], avc->fid.Fid.Unique);
+           linklen = 2 + namelen + strlen(bp);
+           avc->linkData = afs_osi_Alloc(linklen + 1);
+           strcpy(avc->linkData, "%");
+           afs_strcat(avc->linkData, c->cellName);
+           afs_strcat(avc->linkData, ":");
+           afs_strcat(avc->linkData, bp);
+
+           status->UnixModeBits = 0644;
+           status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE;
+           afs_PutCell(c, READ_LOCK);
+
        } else {
            c = afs_GetCellByIndex(cellidx, READ_LOCK);
            if (!c) {
@@ -609,18 +753,30 @@ afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
 }
 
 /*
- * Enable or disable dynroot.  Returns 0 if successful.
+ * Make sure dynroot initialization has been done.
  */
 int
-afs_SetDynrootEnable(int enable)
+afs_InitDynroot(void)
 {
+    if (afs_dynrootInit)
+       return 0;
     RWLOCK_INIT(&afs_dynrootDirLock, "afs_dynrootDirLock");
     RWLOCK_INIT(&afs_dynSymlinkLock, "afs_dynSymlinkLock");
-    afs_dynrootEnable = enable;
+    afs_dynrootInit = 0;
     return afs_dynrootCellInit();
 }
 
 /*
+ * Enable or disable dynroot.  Returns 0 if successful.
+ */
+int
+afs_SetDynrootEnable(int enable)
+{
+    afs_dynrootEnable = enable;
+    return afs_InitDynroot();
+}
+
+/*
  * Check if dynroot support is enabled.
  */
 int
diff --git a/src/afs/afs_dynroot.h b/src/afs/afs_dynroot.h
new file mode 100644 (file)
index 0000000..e23e26b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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
+ */
+
+/*
+ * Vnode numbers in dynroot are composed of a type field (upper 8 bits)
+ * and a type-specific identifier in the lower 24 bits.
+ */
+#define VN_TYPE_CELL           0x01    /* Corresponds to a struct cell */
+#define VN_TYPE_ALIAS          0x02    /* Corresponds to a struct cell_alias */
+#define VN_TYPE_SYMLINK                0x03    /* User-created symlink in /afs */
+#define VN_TYPE_MOUNT                  0x04    /* Mount point by volume ID */
+
+#define VNUM_TO_VNTYPE(vnum)   ((vnum) >> 24)
+#define VNUM_TO_VNID(vnum)     ((vnum) & 0x00ffffff)
+#define VNUM_FROM_TYPEID(type, id) \
+                               ((type) << 24 | (id))
+#define VNUM_TO_CIDX(vnum)     (VNUM_TO_VNID(vnum) >> 2)
+#define VNUM_TO_RW(vnum)       (VNUM_TO_VNID(vnum) >> 1 & 1)
+#define VNUM_FROM_CIDX_RW(cidx, rw) \
+                               VNUM_FROM_TYPEID(VN_TYPE_CELL, \
+                                                ((cidx) << 2 | (rw) << 1))
+#define VNUM_FROM_CAIDX_RW(caidx, rw) \
+                               VNUM_FROM_TYPEID(VN_TYPE_ALIAS, \
+                                                ((caidx) << 2 | (rw) << 1))
+
+#define AFS_DYNROOT_MOUNTNAME  ".:mount"
diff --git a/src/afs/afs_error.c b/src/afs/afs_error.c
new file mode 100644 (file)
index 0000000..35c92b5
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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
+ */
+
+/*
+ * Implements:
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include "afs/stds.h"
+#include "afs/sysincludes.h"   /* Standard vendor system headers */
+
+#ifndef UKERNEL
+#if !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
+#include <net/if.h>
+#include <netinet/in.h>
+#endif
+
+#ifdef AFS_SGI62_ENV
+#include "h/hashing.h"
+#endif
+#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV) && !defined(AFS_DARWIN60_ENV)
+#include <netinet/in_var.h>
+#endif
+#endif /* !UKERNEL */
+
+#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afs_stats.h"     /* afs statistics */
+#include "afs/afs_util.h"
+#include "afs/unified_afs.h"
+
+#if    defined(AFS_SUN56_ENV)
+#include <inet/led.h>
+#include <inet/common.h>
+#if     defined(AFS_SUN58_ENV)
+#include <netinet/ip6.h>
+#endif
+#include <inet/ip.h>
+#endif
+
+
+/* shouldn't do it this way, but for now will do */
+#ifndef ERROR_TABLE_BASE_U
+#define ERROR_TABLE_BASE_U     (5376L)
+#endif /* ubik error base define */
+
+/* shouldn't do it this way, but for now will do */
+#ifndef ERROR_TABLE_BASE_uae
+#define ERROR_TABLE_BASE_uae   (49733376L)
+#endif /* unified afs error base define */
+
+/* same hack for vlserver error base as for ubik error base */
+#ifndef ERROR_TABLE_BASE_VL
+#define ERROR_TABLE_BASE_VL    (363520L)
+#define VL_NOENT               (363524L)
+#endif /* vlserver error base define */
+
+
+static int et2sys[512];
+
+void
+init_et_to_sys_error(void)
+{
+    memset(&et2sys, 0, sizeof(et2sys));
+    et2sys[(UAEPERM - ERROR_TABLE_BASE_uae)] = EPERM;
+    et2sys[(UAENOENT - ERROR_TABLE_BASE_uae)] = ENOENT;
+    et2sys[(UAESRCH - ERROR_TABLE_BASE_uae)] = ESRCH;
+    et2sys[(UAEINTR - ERROR_TABLE_BASE_uae)] = EINTR;
+    et2sys[(UAEIO - ERROR_TABLE_BASE_uae)] = EIO;
+    et2sys[(UAENXIO - ERROR_TABLE_BASE_uae)] = ENXIO;
+    et2sys[(UAE2BIG - ERROR_TABLE_BASE_uae)] = E2BIG;
+    et2sys[(UAENOEXEC - ERROR_TABLE_BASE_uae)] = ENOEXEC;
+    et2sys[(UAEBADF - ERROR_TABLE_BASE_uae)] = EBADF;
+    et2sys[(UAECHILD - ERROR_TABLE_BASE_uae)] = ECHILD;
+    et2sys[(UAEAGAIN - ERROR_TABLE_BASE_uae)] = EAGAIN;
+    et2sys[(UAENOMEM - ERROR_TABLE_BASE_uae)] = ENOMEM;
+    et2sys[(UAEACCES - ERROR_TABLE_BASE_uae)] = EACCES;
+    et2sys[(UAEFAULT - ERROR_TABLE_BASE_uae)] = EFAULT;
+    et2sys[(UAENOTBLK - ERROR_TABLE_BASE_uae)] = ENOTBLK;
+    et2sys[(UAEBUSY - ERROR_TABLE_BASE_uae)] = EBUSY;
+    et2sys[(UAEEXIST - ERROR_TABLE_BASE_uae)] = EEXIST;
+    et2sys[(UAEXDEV - ERROR_TABLE_BASE_uae)] = EXDEV;
+    et2sys[(UAENODEV - ERROR_TABLE_BASE_uae)] = ENODEV;
+    et2sys[(UAENOTDIR - ERROR_TABLE_BASE_uae)] = ENOTDIR;
+    et2sys[(UAEISDIR - ERROR_TABLE_BASE_uae)] = EISDIR;
+    et2sys[(UAEINVAL - ERROR_TABLE_BASE_uae)] = EINVAL;
+    et2sys[(UAENFILE - ERROR_TABLE_BASE_uae)] = ENFILE;
+    et2sys[(UAEMFILE - ERROR_TABLE_BASE_uae)] = EMFILE;
+    et2sys[(UAENOTTY - ERROR_TABLE_BASE_uae)] = ENOTTY;
+    et2sys[(UAETXTBSY - ERROR_TABLE_BASE_uae)] = ETXTBSY;
+    et2sys[(UAEFBIG - ERROR_TABLE_BASE_uae)] = EFBIG;
+    et2sys[(UAENOSPC - ERROR_TABLE_BASE_uae)] = ENOSPC;
+    et2sys[(UAESPIPE - ERROR_TABLE_BASE_uae)] = ESPIPE;
+    et2sys[(UAEROFS - ERROR_TABLE_BASE_uae)] = EROFS;
+    et2sys[(UAEMLINK - ERROR_TABLE_BASE_uae)] = EMLINK;
+    et2sys[(UAEPIPE - ERROR_TABLE_BASE_uae)] = EPIPE;
+    et2sys[(UAEDOM - ERROR_TABLE_BASE_uae)] = EDOM;
+    et2sys[(UAERANGE - ERROR_TABLE_BASE_uae)] = ERANGE;
+    et2sys[(UAEDEADLK - ERROR_TABLE_BASE_uae)] = EDEADLK;
+    et2sys[(UAENAMETOOLONG - ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
+    et2sys[(UAENOLCK - ERROR_TABLE_BASE_uae)] = ENOLCK;
+    et2sys[(UAENOSYS - ERROR_TABLE_BASE_uae)] = ENOSYS;
+    et2sys[(UAENOTEMPTY - ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
+    et2sys[(UAELOOP - ERROR_TABLE_BASE_uae)] = ELOOP;
+    et2sys[(UAEWOULDBLOCK - ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
+    et2sys[(UAENOMSG - ERROR_TABLE_BASE_uae)] = ENOMSG;
+    et2sys[(UAEIDRM - ERROR_TABLE_BASE_uae)] = EIDRM;
+    et2sys[(UAECHRNG - ERROR_TABLE_BASE_uae)] = ECHRNG;
+    et2sys[(UAEL2NSYNC - ERROR_TABLE_BASE_uae)] = EL2NSYNC;
+    et2sys[(UAEL3HLT - ERROR_TABLE_BASE_uae)] = EL3HLT;
+    et2sys[(UAEL3RST - ERROR_TABLE_BASE_uae)] = EL3RST;
+    et2sys[(UAELNRNG - ERROR_TABLE_BASE_uae)] = ELNRNG;
+    et2sys[(UAEUNATCH - ERROR_TABLE_BASE_uae)] = EUNATCH;
+    et2sys[(UAENOCSI - ERROR_TABLE_BASE_uae)] = ENOCSI;
+    et2sys[(UAEL2HLT - ERROR_TABLE_BASE_uae)] = EL2HLT;
+    et2sys[(UAEBADE - ERROR_TABLE_BASE_uae)] = EBADE;
+    et2sys[(UAEBADR - ERROR_TABLE_BASE_uae)] = EBADR;
+    et2sys[(UAEXFULL - ERROR_TABLE_BASE_uae)] = EXFULL;
+    et2sys[(UAENOANO - ERROR_TABLE_BASE_uae)] = ENOANO;
+    et2sys[(UAEBADRQC - ERROR_TABLE_BASE_uae)] = EBADRQC;
+    et2sys[(UAEBADSLT - ERROR_TABLE_BASE_uae)] = EBADSLT;
+    et2sys[(UAEBFONT - ERROR_TABLE_BASE_uae)] = EBFONT;
+    et2sys[(UAENOSTR - ERROR_TABLE_BASE_uae)] = ENOSTR;
+    et2sys[(UAENODATA - ERROR_TABLE_BASE_uae)] = ENODATA;
+    et2sys[(UAETIME - ERROR_TABLE_BASE_uae)] = ETIME;
+    et2sys[(UAENOSR - ERROR_TABLE_BASE_uae)] = ENOSR;
+    et2sys[(UAENONET - ERROR_TABLE_BASE_uae)] = ENONET;
+    et2sys[(UAENOPKG - ERROR_TABLE_BASE_uae)] = ENOPKG;
+    et2sys[(UAEREMOTE - ERROR_TABLE_BASE_uae)] = EREMOTE;
+    et2sys[(UAENOLINK - ERROR_TABLE_BASE_uae)] = ENOLINK;
+    et2sys[(UAEADV - ERROR_TABLE_BASE_uae)] = EADV;
+    et2sys[(UAESRMNT - ERROR_TABLE_BASE_uae)] = ESRMNT;
+    et2sys[(UAECOMM - ERROR_TABLE_BASE_uae)] = ECOMM;
+    et2sys[(UAEPROTO - ERROR_TABLE_BASE_uae)] = EPROTO;
+    et2sys[(UAEMULTIHOP - ERROR_TABLE_BASE_uae)] = EMULTIHOP;
+    et2sys[(UAEDOTDOT - ERROR_TABLE_BASE_uae)] = EDOTDOT;
+    et2sys[(UAEBADMSG - ERROR_TABLE_BASE_uae)] = EBADMSG;
+    et2sys[(UAEOVERFLOW - ERROR_TABLE_BASE_uae)] = EOVERFLOW;
+    et2sys[(UAENOTUNIQ - ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
+    et2sys[(UAEBADFD - ERROR_TABLE_BASE_uae)] = EBADFD;
+    et2sys[(UAEREMCHG - ERROR_TABLE_BASE_uae)] = EREMCHG;
+    et2sys[(UAELIBACC - ERROR_TABLE_BASE_uae)] = ELIBACC;
+    et2sys[(UAELIBBAD - ERROR_TABLE_BASE_uae)] = ELIBBAD;
+    et2sys[(UAELIBSCN - ERROR_TABLE_BASE_uae)] = ELIBSCN;
+    et2sys[(UAELIBMAX - ERROR_TABLE_BASE_uae)] = ELIBMAX;
+    et2sys[(UAELIBEXEC - ERROR_TABLE_BASE_uae)] = ELIBEXEC;
+    et2sys[(UAEILSEQ - ERROR_TABLE_BASE_uae)] = EILSEQ;
+    et2sys[(UAERESTART - ERROR_TABLE_BASE_uae)] = ERESTART;
+    et2sys[(UAESTRPIPE - ERROR_TABLE_BASE_uae)] = ESTRPIPE;
+    et2sys[(UAEUSERS - ERROR_TABLE_BASE_uae)] = EUSERS;
+    et2sys[(UAENOTSOCK - ERROR_TABLE_BASE_uae)] = ENOTSOCK;
+    et2sys[(UAEDESTADDRREQ - ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
+    et2sys[(UAEMSGSIZE - ERROR_TABLE_BASE_uae)] = EMSGSIZE;
+    et2sys[(UAEPROTOTYPE - ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
+    et2sys[(UAENOPROTOOPT - ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
+    et2sys[(UAEPROTONOSUPPORT - ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
+    et2sys[(UAESOCKTNOSUPPORT - ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
+    et2sys[(UAEOPNOTSUPP - ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
+    et2sys[(UAEPFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
+    et2sys[(UAEAFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
+    et2sys[(UAEADDRINUSE - ERROR_TABLE_BASE_uae)] = EADDRINUSE;
+    et2sys[(UAEADDRNOTAVAIL - ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
+    et2sys[(UAENETDOWN - ERROR_TABLE_BASE_uae)] = ENETDOWN;
+    et2sys[(UAENETUNREACH - ERROR_TABLE_BASE_uae)] = ENETUNREACH;
+    et2sys[(UAENETRESET - ERROR_TABLE_BASE_uae)] = ENETRESET;
+    et2sys[(UAECONNABORTED - ERROR_TABLE_BASE_uae)] = ECONNABORTED;
+    et2sys[(UAECONNRESET - ERROR_TABLE_BASE_uae)] = ECONNRESET;
+    et2sys[(UAENOBUFS - ERROR_TABLE_BASE_uae)] = ENOBUFS;
+    et2sys[(UAEISCONN - ERROR_TABLE_BASE_uae)] = EISCONN;
+    et2sys[(UAENOTCONN - ERROR_TABLE_BASE_uae)] = ENOTCONN;
+    et2sys[(UAESHUTDOWN - ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
+    et2sys[(UAETOOMANYREFS - ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
+    et2sys[(UAETIMEDOUT - ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
+    et2sys[(UAECONNREFUSED - ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
+    et2sys[(UAEHOSTDOWN - ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
+    et2sys[(UAEHOSTUNREACH - ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
+    et2sys[(UAEALREADY - ERROR_TABLE_BASE_uae)] = EALREADY;
+    et2sys[(UAEINPROGRESS - ERROR_TABLE_BASE_uae)] = EINPROGRESS;
+    et2sys[(UAESTALE - ERROR_TABLE_BASE_uae)] = ESTALE;
+    et2sys[(UAEUCLEAN - ERROR_TABLE_BASE_uae)] = EUCLEAN;
+    et2sys[(UAENOTNAM - ERROR_TABLE_BASE_uae)] = ENOTNAM;
+    et2sys[(UAENAVAIL - ERROR_TABLE_BASE_uae)] = ENAVAIL;
+    et2sys[(UAEISNAM - ERROR_TABLE_BASE_uae)] = EISNAM;
+    et2sys[(UAEREMOTEIO - ERROR_TABLE_BASE_uae)] = EREMOTEIO;
+    et2sys[(UAEDQUOT - ERROR_TABLE_BASE_uae)] = EDQUOT;
+    et2sys[(UAENOMEDIUM - ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
+    et2sys[(UAEMEDIUMTYPE - ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
+}
+
+afs_int32
+et_to_sys_error(afs_int32 in)
+{
+    if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
+       return in;
+    if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
+       return et2sys[in - ERROR_TABLE_BASE_uae];
+    return in;
+}
+
+void
+afs_CopyError(register struct vrequest *afrom, register struct vrequest *ato)
+{
+    AFS_STATCNT(afs_CopyError);
+    if (!afrom->initd)
+       return;
+    afs_FinalizeReq(ato);
+    if (afrom->accessError)
+       ato->accessError = 1;
+    if (afrom->volumeError)
+       ato->volumeError = 1;
+    if (afrom->networkError)
+       ato->networkError = 1;
+    if (afrom->permWriteError)
+       ato->permWriteError = 1;
+
+}
+
+void
+afs_FinalizeReq(register struct vrequest *areq)
+{
+    AFS_STATCNT(afs_FinalizeReq);
+    if (areq->initd)
+       return;
+    areq->busyCount = 0;
+    areq->accessError = 0;
+    areq->volumeError = 0;
+    areq->networkError = 0;
+    areq->permWriteError = 0;
+    areq->initd = 1;
+
+}
+
+int
+afs_CheckCode(afs_int32 acode, struct vrequest *areq, int where)
+{
+    AFS_STATCNT(afs_CheckCode);
+    if (acode) {
+       afs_Trace2(afs_iclSetp, CM_TRACE_CHECKCODE, ICL_TYPE_INT32, acode,
+                  ICL_TYPE_INT32, where);
+    }
+    if ((acode & ~0xff) == ERROR_TABLE_BASE_uae)
+       acode = et_to_sys_error(acode);
+    if (!areq || !areq->initd)
+       return acode;
+    if (areq->networkError)
+       return ETIMEDOUT;
+    if (acode == 0)
+       return 0;
+    if (areq->accessError)
+       return EACCES;
+    if (areq->volumeError == VOLMISSING)
+       return ENODEV;
+    if (areq->volumeError == VOLBUSY)
+       return EWOULDBLOCK;
+    if (acode == VNOVNODE)
+       return ENOENT;
+    if (acode == VDISKFULL)
+       return ENOSPC;
+    if (acode == VOVERQUOTA)
+       return
+#ifdef EDQUOT
+           EDQUOT
+#else
+           ENOSPC
+#endif
+           ;
+
+    return acode;
+
+}                              /*afs_CheckCode */
diff --git a/src/afs/afs_icl.c b/src/afs/afs_icl.c
new file mode 100644 (file)
index 0000000..40bff4b
--- /dev/null
@@ -0,0 +1,1527 @@
+/*
+ * 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
+ */
+
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#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_DARWIN60_ENV)
+#include "netinet/in_var.h"
+#endif
+#endif /* !defined(UKERNEL) */
+#ifdef AFS_LINUX22_ENV
+#include "h/smp_lock.h"
+#endif
+
+
+struct afs_icl_set *afs_iclSetp = (struct afs_icl_set *)0;
+struct afs_icl_set *afs_iclLongTermSetp = (struct afs_icl_set *)0;
+
+#if defined(AFS_OSF_ENV) || defined(AFS_SGI61_ENV)
+/* For SGI 6.2, this can is changed to 1 if it's a 32 bit kernel. */
+#if defined(AFS_SGI62_ENV) && defined(KERNEL) && !defined(_K64U64)
+int afs_icl_sizeofLong = 1;
+#else
+int afs_icl_sizeofLong = 2;
+#endif /* SGI62 */
+#else
+#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
+int afs_icl_sizeofLong = 2;
+#else
+int afs_icl_sizeofLong = 1;
+#endif
+#endif
+
+int afs_icl_inited = 0;
+
+/* init function, called once, under afs_icl_lock */
+int
+afs_icl_Init(void)
+{
+    afs_icl_inited = 1;
+    return 0;
+}
+
+int
+afs_icl_InitLogs(void)
+{
+    struct afs_icl_log *logp;
+    int code;
+
+    /* initialize the ICL system */
+    code = afs_icl_CreateLog("cmfx", 60 * 1024, &logp);
+    if (code == 0)
+       code =
+           afs_icl_CreateSetWithFlags("cm", logp, NULL,
+                                      ICL_CRSET_FLAG_DEFAULT_OFF,
+                                      &afs_iclSetp);
+    code =
+       afs_icl_CreateSet("cmlongterm", logp, NULL,
+                         &afs_iclLongTermSetp);
+    return code;
+}
+
+
+struct afs_icl_log *afs_icl_FindLog();
+struct afs_icl_set *afs_icl_FindSet();
+
+
+int
+Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval)
+{
+    afs_int32 *lp, elts, flags;
+    register afs_int32 code;
+    struct afs_icl_log *logp;
+    struct afs_icl_set *setp;
+#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+    size_t temp;
+#else /* AFS_SGI61_ENV */
+#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
+    afs_uint64 temp;
+#else
+    afs_uint32 temp;
+#endif
+#endif /* AFS_SGI61_ENV */
+    char tname[65];
+    afs_int32 startCookie;
+    afs_int32 allocated;
+    struct afs_icl_log *tlp;
+
+#ifdef AFS_SUN5_ENV
+    if (!afs_suser(CRED())) {  /* only root can run this code */
+       return (EACCES);
+    }
+#else
+    if (!afs_suser(NULL)) {    /* only root can run this code */
+#if defined(KERNEL_HAVE_UERROR)
+       setuerror(EACCES);
+       return EACCES;
+#else
+       return EPERM;
+#endif
+    }
+#endif
+    switch (opcode) {
+    case ICL_OP_COPYOUTCLR:    /* copy out data then clear */
+    case ICL_OP_COPYOUT:       /* copy ouy data */
+       /* copyout: p1=logname, p2=&buffer, p3=size(words), p4=&cookie
+        * return flags<<24 + nwords.
+        * updates cookie to updated start (not end) if we had to
+        * skip some records.
+        */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       AFS_COPYIN((char *)p4, (char *)&startCookie, sizeof(afs_int32), code);
+       if (code)
+           return code;
+       logp = afs_icl_FindLog(tname);
+       if (!logp)
+           return ENOENT;
+#define        BUFFERSIZE      AFS_LRALLOCSIZ
+       lp = (afs_int32 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+       elts = BUFFERSIZE / sizeof(afs_int32);
+       if (p3 < elts)
+           elts = p3;
+       flags = (opcode == ICL_OP_COPYOUT) ? 0 : ICL_COPYOUTF_CLRAFTERREAD;
+       code =
+           afs_icl_CopyOut(logp, lp, &elts, (afs_uint32 *) & startCookie,
+                           &flags);
+       if (code) {
+           osi_FreeLargeSpace((struct osi_buffer *)lp);
+           break;
+       }
+       AFS_COPYOUT((char *)lp, (char *)p2, elts * sizeof(afs_int32), code);
+       if (code)
+           goto done;
+       AFS_COPYOUT((char *)&startCookie, (char *)p4, sizeof(afs_int32),
+                   code);
+       if (code)
+           goto done;
+#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
+       if (!(IS64U))
+           *retval = ((long)((flags << 24) | (elts & 0xffffff))) << 32;
+       else
+#endif
+           *retval = (flags << 24) | (elts & 0xffffff);
+      done:
+       afs_icl_LogRele(logp);
+       osi_FreeLargeSpace((struct osi_buffer *)lp);
+       break;
+
+    case ICL_OP_ENUMLOGS:      /* enumerate logs */
+       /* enumerate logs: p1=index, p2=&name, p3=sizeof(name), p4=&size.
+        * return 0 for success, otherwise error.
+        */
+       for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
+           if (p1-- == 0)
+               break;
+       }
+       if (!tlp)
+           return ENOENT;      /* past the end of file */
+       temp = strlen(tlp->name) + 1;
+       if (temp > p3)
+           return EINVAL;
+       AFS_COPYOUT(tlp->name, (char *)p2, temp, code);
+       if (!code)              /* copy out size of log */
+           AFS_COPYOUT((char *)&tlp->logSize, (char *)p4, sizeof(afs_int32),
+                       code);
+       break;
+
+    case ICL_OP_ENUMLOGSBYSET: /* enumerate logs by set name */
+       /* enumerate logs: p1=setname, p2=index, p3=&name, p4=sizeof(name).
+        * return 0 for success, otherwise error.
+        */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       setp = afs_icl_FindSet(tname);
+       if (!setp)
+           return ENOENT;
+       if (p2 > ICL_LOGSPERSET)
+           return EINVAL;
+       if (!(tlp = setp->logs[p2]))
+           return EBADF;
+       temp = strlen(tlp->name) + 1;
+       if (temp > p4)
+           return EINVAL;
+       AFS_COPYOUT(tlp->name, (char *)p3, temp, code);
+       break;
+
+    case ICL_OP_CLRLOG:        /* clear specified log */
+       /* zero out the specified log: p1=logname */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       logp = afs_icl_FindLog(tname);
+       if (!logp)
+           return ENOENT;
+       code = afs_icl_ZeroLog(logp);
+       afs_icl_LogRele(logp);
+       break;
+
+    case ICL_OP_CLRSET:        /* clear specified set */
+       /* zero out the specified set: p1=setname */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       setp = afs_icl_FindSet(tname);
+       if (!setp)
+           return ENOENT;
+       code = afs_icl_ZeroSet(setp);
+       afs_icl_SetRele(setp);
+       break;
+
+    case ICL_OP_CLRALL:        /* clear all logs */
+       /* zero out all logs -- no args */
+       code = 0;
+       ObtainWriteLock(&afs_icl_lock, 178);
+       for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
+           tlp->refCount++;    /* hold this guy */
+           ReleaseWriteLock(&afs_icl_lock);
+           /* don't clear persistent logs */
+           if ((tlp->states & ICL_LOGF_PERSISTENT) == 0)
+               code = afs_icl_ZeroLog(tlp);
+           ObtainWriteLock(&afs_icl_lock, 179);
+           if (--tlp->refCount == 0)
+               afs_icl_ZapLog(tlp);
+           if (code)
+               break;
+       }
+       ReleaseWriteLock(&afs_icl_lock);
+       break;
+
+    case ICL_OP_ENUMSETS:      /* enumerate all sets */
+       /* enumerate sets: p1=index, p2=&name, p3=sizeof(name), p4=&states.
+        * return 0 for success, otherwise error.
+        */
+       for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
+           if (p1-- == 0)
+               break;
+       }
+       if (!setp)
+           return ENOENT;      /* past the end of file */
+       temp = strlen(setp->name) + 1;
+       if (temp > p3)
+           return EINVAL;
+       AFS_COPYOUT(setp->name, (char *)p2, temp, code);
+       if (!code)              /* copy out size of log */
+           AFS_COPYOUT((char *)&setp->states, (char *)p4, sizeof(afs_int32),
+                       code);
+       break;
+
+    case ICL_OP_SETSTAT:       /* set status on a set */
+       /* activate the specified set: p1=setname, p2=op */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       setp = afs_icl_FindSet(tname);
+       if (!setp)
+           return ENOENT;
+       code = afs_icl_SetSetStat(setp, p2);
+       afs_icl_SetRele(setp);
+       break;
+
+    case ICL_OP_SETSTATALL:    /* set status on all sets */
+       /* activate the specified set: p1=op */
+       code = 0;
+       ObtainWriteLock(&afs_icl_lock, 180);
+       for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
+           setp->refCount++;   /* hold this guy */
+           ReleaseWriteLock(&afs_icl_lock);
+           /* don't set states on persistent sets */
+           if ((setp->states & ICL_SETF_PERSISTENT) == 0)
+               code = afs_icl_SetSetStat(setp, p1);
+           ObtainWriteLock(&afs_icl_lock, 181);
+           if (--setp->refCount == 0)
+               afs_icl_ZapSet(setp);
+           if (code)
+               break;
+       }
+       ReleaseWriteLock(&afs_icl_lock);
+       break;
+
+    case ICL_OP_SETLOGSIZE:    /* set size of log */
+       /* set the size of the specified log: p1=logname, p2=size (in words) */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       logp = afs_icl_FindLog(tname);
+       if (!logp)
+           return ENOENT;
+       code = afs_icl_LogSetSize(logp, p2);
+       afs_icl_LogRele(logp);
+       break;
+
+    case ICL_OP_GETLOGINFO:    /* get size of log */
+       /* zero out the specified log: p1=logname, p2=&logSize, p3=&allocated */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       logp = afs_icl_FindLog(tname);
+       if (!logp)
+           return ENOENT;
+       allocated = !!logp->datap;
+       AFS_COPYOUT((char *)&logp->logSize, (char *)p2, sizeof(afs_int32),
+                   code);
+       if (!code)
+           AFS_COPYOUT((char *)&allocated, (char *)p3, sizeof(afs_int32),
+                       code);
+       afs_icl_LogRele(logp);
+       break;
+
+    case ICL_OP_GETSETINFO:    /* get state of set */
+       /* zero out the specified set: p1=setname, p2=&state */
+       AFS_COPYINSTR((char *)p1, tname, sizeof(tname), &temp, code);
+       if (code)
+           return code;
+       setp = afs_icl_FindSet(tname);
+       if (!setp)
+           return ENOENT;
+       AFS_COPYOUT((char *)&setp->states, (char *)p2, sizeof(afs_int32),
+                   code);
+       afs_icl_SetRele(setp);
+       break;
+
+    default:
+       code = EINVAL;
+    }
+
+    return code;
+}
+
+
+afs_lock_t afs_icl_lock;
+
+/* exported routine: a 4 parameter event */
+int
+afs_icl_Event4(register struct afs_icl_set *setp, afs_int32 eventID,
+              afs_int32 lAndT, long p1, long p2, long p3, long p4)
+{
+    afs_int32 mask;
+    register int i;
+    register afs_int32 tmask;
+    int ix;
+
+    /* If things aren't init'ed yet (or the set is inactive), don't panic */
+    if (!ICL_SETACTIVE(setp))
+       return 0;
+
+    AFS_ASSERT_GLOCK();
+    mask = lAndT >> 24 & 0xff; /* mask of which logs to log to */
+    ix = ICL_EVENTBYTE(eventID);
+    ObtainReadLock(&setp->lock);
+    if (setp->eventFlags[ix] & ICL_EVENTMASK(eventID)) {
+       for (i = 0, tmask = 1; i < ICL_LOGSPERSET; i++, tmask <<= 1) {
+           if (mask & tmask) {
+               afs_icl_AppendRecord(setp->logs[i], eventID, lAndT & 0xffffff,
+                                    p1, p2, p3, p4);
+           }
+           mask &= ~tmask;
+           if (mask == 0)
+               break;          /* break early */
+       }
+    }
+    ReleaseReadLock(&setp->lock);
+    return 0;
+}
+
+/* Next 4 routines should be implemented via var-args or something.
+ * Whole purpose is to avoid compiler warnings about parameter # mismatches.
+ * Otherwise, could call afs_icl_Event4 directly.
+ */
+int
+afs_icl_Event3(register struct afs_icl_set *setp, afs_int32 eventID,
+              afs_int32 lAndT, long p1, long p2, long p3)
+{
+    return afs_icl_Event4(setp, eventID, lAndT, p1, p2, p3, (long)0);
+}
+
+int
+afs_icl_Event2(register struct afs_icl_set *setp, afs_int32 eventID,
+              afs_int32 lAndT, long p1, long p2)
+{
+    return afs_icl_Event4(setp, eventID, lAndT, p1, p2, (long)0, (long)0);
+}
+
+int
+afs_icl_Event1(register struct afs_icl_set *setp, afs_int32 eventID,
+              afs_int32 lAndT, long p1)
+{
+    return afs_icl_Event4(setp, eventID, lAndT, p1, (long)0, (long)0,
+                         (long)0);
+}
+
+int
+afs_icl_Event0(register struct afs_icl_set *setp, afs_int32 eventID,
+              afs_int32 lAndT)
+{
+    return afs_icl_Event4(setp, eventID, lAndT, (long)0, (long)0, (long)0,
+                         (long)0);
+}
+
+struct afs_icl_log *afs_icl_allLogs = 0;
+
+/* function to purge records from the start of the log, until there
+ * is at least minSpace long's worth of space available without
+ * making the head and the tail point to the same word.
+ *
+ * Log must be write-locked.
+ */
+static void
+afs_icl_GetLogSpace(register struct afs_icl_log *logp, afs_int32 minSpace)
+{
+    register unsigned int tsize;
+
+    while (logp->logSize - logp->logElements <= minSpace) {
+       /* eat a record */
+       tsize = ((logp->datap[logp->firstUsed]) >> 24) & 0xff;
+       logp->logElements -= tsize;
+       logp->firstUsed += tsize;
+       if (logp->firstUsed >= logp->logSize)
+           logp->firstUsed -= logp->logSize;
+       logp->baseCookie += tsize;
+    }
+}
+
+/* append string astr to buffer, including terminating null char.
+ *
+ * log must be write-locked.
+ */
+#define ICL_CHARSPERLONG       4
+static void
+afs_icl_AppendString(struct afs_icl_log *logp, char *astr)
+{
+    char *op;                  /* ptr to char to write */
+    int tc;
+    register int bib;          /* bytes in buffer */
+
+    bib = 0;
+    op = (char *)&(logp->datap[logp->firstFree]);
+    while (1) {
+       tc = *astr++;
+       *op++ = tc;
+       if (++bib >= ICL_CHARSPERLONG) {
+           /* new word */
+           bib = 0;
+           if (++(logp->firstFree) >= logp->logSize) {
+               logp->firstFree = 0;
+               op = (char *)&(logp->datap[0]);
+           }
+           logp->logElements++;
+       }
+       if (tc == 0)
+           break;
+    }
+    if (bib > 0) {
+       /* if we've used this word at all, allocate it */
+       if (++(logp->firstFree) >= logp->logSize) {
+           logp->firstFree = 0;
+       }
+       logp->logElements++;
+    }
+}
+
+/* add a long to the log, ignoring overflow (checked already) */
+#define ICL_APPENDINT32(lp, x) \
+    MACRO_BEGIN \
+        (lp)->datap[(lp)->firstFree] = (x); \
+       if (++((lp)->firstFree) >= (lp)->logSize) { \
+               (lp)->firstFree = 0; \
+       } \
+        (lp)->logElements++; \
+    MACRO_END
+
+#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
+#define ICL_APPENDLONG(lp, x) \
+    MACRO_BEGIN \
+       ICL_APPENDINT32((lp), ((x) >> 32) & 0xffffffffL); \
+       ICL_APPENDINT32((lp), (x) & 0xffffffffL); \
+    MACRO_END
+
+#else /* AFS_OSF_ENV */
+#define ICL_APPENDLONG(lp, x) ICL_APPENDINT32((lp), (x))
+#endif /* AFS_OSF_ENV */
+
+/* routine to tell whether we're dealing with the address or the
+ * object itself
+ */
+int
+afs_icl_UseAddr(int type)
+{
+    if (type == ICL_TYPE_HYPER || type == ICL_TYPE_STRING
+       || type == ICL_TYPE_FID || type == ICL_TYPE_INT64)
+       return 1;
+    else
+       return 0;
+}
+
+/* Function to append a record to the log.  Written for speed
+ * since we know that we're going to have to make this work fast
+ * pretty soon, anyway.  The log must be unlocked.
+ */
+
+void
+afs_icl_AppendRecord(register struct afs_icl_log *logp, afs_int32 op,
+                    afs_int32 types, long p1, long p2, long p3, long p4)
+{
+    int rsize;                 /* record size in longs */
+    register int tsize;                /* temp size */
+    osi_timeval_t tv;
+    int t1, t2, t3, t4;
+
+    t4 = types & 0x3f;         /* decode types */
+    types >>= 6;
+    t3 = types & 0x3f;
+    types >>= 6;
+    t2 = types & 0x3f;
+    types >>= 6;
+    t1 = types & 0x3f;
+
+    osi_GetTime(&tv);          /* It panics for solaris if inside */
+    ObtainWriteLock(&logp->lock, 182);
+    if (!logp->datap) {
+       ReleaseWriteLock(&logp->lock);
+       return;
+    }
+
+    /* get timestamp as # of microseconds since some time that doesn't
+     * change that often.  This algorithm ticks over every 20 minutes
+     * or so (1000 seconds).  Write a timestamp record if it has.
+     */
+    if (tv.tv_sec - logp->lastTS > 1024) {
+       /* the timer has wrapped -- write a timestamp record */
+       if (logp->logSize - logp->logElements <= 5)
+           afs_icl_GetLogSpace(logp, 5);
+
+       ICL_APPENDINT32(logp,
+                       (afs_int32) (5 << 24) + (ICL_TYPE_UNIXDATE << 18));
+       ICL_APPENDINT32(logp, (afs_int32) ICL_INFO_TIMESTAMP);
+       ICL_APPENDINT32(logp, (afs_int32) 0);   /* use thread ID zero for clocks */
+       ICL_APPENDINT32(logp,
+                       (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 +
+                       tv.tv_usec);
+       ICL_APPENDINT32(logp, (afs_int32) tv.tv_sec);
+
+       logp->lastTS = tv.tv_sec;
+    }
+
+    rsize = 4;                 /* base case */
+    if (t1) {
+       /* compute size of parameter p1.  Only tricky case is string.
+        * In that case, we have to call strlen to get the string length.
+        */
+       ICL_SIZEHACK(t1, p1);
+    }
+    if (t2) {
+       /* compute size of parameter p2.  Only tricky case is string.
+        * In that case, we have to call strlen to get the string length.
+        */
+       ICL_SIZEHACK(t2, p2);
+    }
+    if (t3) {
+       /* compute size of parameter p3.  Only tricky case is string.
+        * In that case, we have to call strlen to get the string length.
+        */
+       ICL_SIZEHACK(t3, p3);
+    }
+    if (t4) {
+       /* compute size of parameter p4.  Only tricky case is string.
+        * In that case, we have to call strlen to get the string length.
+        */
+       ICL_SIZEHACK(t4, p4);
+    }
+
+    /* At this point, we've computed all of the parameter sizes, and
+     * have in rsize the size of the entire record we want to append.
+     * Next, we check that we actually have room in the log to do this
+     * work, and then we do the append.
+     */
+    if (rsize > 255) {
+       ReleaseWriteLock(&logp->lock);
+       return;                 /* log record too big to express */
+    }
+
+    if (logp->logSize - logp->logElements <= rsize)
+       afs_icl_GetLogSpace(logp, rsize);
+
+    ICL_APPENDINT32(logp,
+                   (afs_int32) (rsize << 24) + (t1 << 18) + (t2 << 12) +
+                   (t3 << 6) + t4);
+    ICL_APPENDINT32(logp, (afs_int32) op);
+    ICL_APPENDINT32(logp, (afs_int32) osi_ThreadUnique());
+    ICL_APPENDINT32(logp,
+                   (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 + tv.tv_usec);
+
+    if (t1) {
+       /* marshall parameter 1 now */
+       if (t1 == ICL_TYPE_STRING) {
+           afs_icl_AppendString(logp, (char *)p1);
+       } else if (t1 == ICL_TYPE_HYPER) {
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p1)->high);
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p1)->low);
+       } else if (t1 == ICL_TYPE_INT64) {
+#ifdef AFSLITTLE_ENDIAN
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[0]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) p1);
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+#endif /* AFS_64BIT_CLIENT */
+#else /* AFSLITTLE_ENDIAN */
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[1]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+           ICL_APPENDINT32(logp, (afs_int32) p1);
+#endif /* AFS_64BIT_CLIENT */
+#endif /* AFSLITTLE_ENDIAN */
+       } else if (t1 == ICL_TYPE_FID) {
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[2]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p1)[3]);
+       }
+#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
+       else if (t1 == ICL_TYPE_INT32)
+           ICL_APPENDINT32(logp, (afs_int32) p1);
+#endif /* AFS_OSF_ENV */
+       else
+           ICL_APPENDLONG(logp, p1);
+    }
+    if (t2) {
+       /* marshall parameter 2 now */
+       if (t2 == ICL_TYPE_STRING)
+           afs_icl_AppendString(logp, (char *)p2);
+       else if (t2 == ICL_TYPE_HYPER) {
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p2)->high);
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p2)->low);
+       } else if (t2 == ICL_TYPE_INT64) {
+#ifdef AFSLITTLE_ENDIAN
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[0]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) p2);
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+#endif /* AFS_64BIT_CLIENT */
+#else /* AFSLITTLE_ENDIAN */
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[1]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+           ICL_APPENDINT32(logp, (afs_int32) p2);
+#endif /* AFS_64BIT_CLIENT */
+#endif /* AFSLITTLE_ENDIAN */
+       } else if (t2 == ICL_TYPE_FID) {
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[2]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p2)[3]);
+       }
+#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
+       else if (t2 == ICL_TYPE_INT32)
+           ICL_APPENDINT32(logp, (afs_int32) p2);
+#endif /* AFS_OSF_ENV */
+       else
+           ICL_APPENDLONG(logp, p2);
+    }
+    if (t3) {
+       /* marshall parameter 3 now */
+       if (t3 == ICL_TYPE_STRING)
+           afs_icl_AppendString(logp, (char *)p3);
+       else if (t3 == ICL_TYPE_HYPER) {
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p3)->high);
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p3)->low);
+       } else if (t3 == ICL_TYPE_INT64) {
+#ifdef AFSLITTLE_ENDIAN
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[0]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) p3);
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+#endif /* AFS_64BIT_CLIENT */
+#else /* AFSLITTLE_ENDIAN */
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[1]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+           ICL_APPENDINT32(logp, (afs_int32) p3);
+#endif /* AFS_64BIT_CLIENT */
+#endif /* AFSLITTLE_ENDIAN */
+       } else if (t3 == ICL_TYPE_FID) {
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[2]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p3)[3]);
+       }
+#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
+       else if (t3 == ICL_TYPE_INT32)
+           ICL_APPENDINT32(logp, (afs_int32) p3);
+#endif /* AFS_OSF_ENV */
+       else
+           ICL_APPENDLONG(logp, p3);
+    }
+    if (t4) {
+       /* marshall parameter 4 now */
+       if (t4 == ICL_TYPE_STRING)
+           afs_icl_AppendString(logp, (char *)p4);
+       else if (t4 == ICL_TYPE_HYPER) {
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p4)->high);
+           ICL_APPENDINT32(logp,
+                           (afs_int32) ((struct afs_hyper_t *)p4)->low);
+       } else if (t4 == ICL_TYPE_INT64) {
+#ifdef AFSLITTLE_ENDIAN
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[0]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) p4);
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+#endif /* AFS_64BIT_CLIENT */
+#else /* AFSLITTLE_ENDIAN */
+#ifdef AFS_64BIT_CLIENT
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[1]);
+#else /* AFS_64BIT_CLIENT */
+           ICL_APPENDINT32(logp, (afs_int32) 0);
+           ICL_APPENDINT32(logp, (afs_int32) p4);
+#endif /* AFS_64BIT_CLIENT */
+#endif /* AFSLITTLE_ENDIAN */
+       } else if (t4 == ICL_TYPE_FID) {
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[0]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[1]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[2]);
+           ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) p4)[3]);
+       }
+#if defined(AFS_OSF_ENV) || (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
+       else if (t4 == ICL_TYPE_INT32)
+           ICL_APPENDINT32(logp, (afs_int32) p4);
+#endif /* AFS_OSF_ENV */
+       else
+           ICL_APPENDLONG(logp, p4);
+    }
+    ReleaseWriteLock(&logp->lock);
+}
+
+/* create a log with size logSize; return it in *outLogpp and tag
+ * it with name "name."
+ */
+int
+afs_icl_CreateLog(char *name, afs_int32 logSize,
+                 struct afs_icl_log **outLogpp)
+{
+    return afs_icl_CreateLogWithFlags(name, logSize, /*flags */ 0, outLogpp);
+}
+
+/* create a log with size logSize; return it in *outLogpp and tag
+ * it with name "name."  'flags' can be set to make the log unclearable.
+ */
+int
+afs_icl_CreateLogWithFlags(char *name, afs_int32 logSize, afs_uint32 flags,
+                          struct afs_icl_log **outLogpp)
+{
+    register struct afs_icl_log *logp;
+
+    /* add into global list under lock */
+    ObtainWriteLock(&afs_icl_lock, 183);
+    if (!afs_icl_inited)
+       afs_icl_Init();
+
+    for (logp = afs_icl_allLogs; logp; logp = logp->nextp) {
+       if (strcmp(logp->name, name) == 0) {
+           /* found it already created, just return it */
+           logp->refCount++;
+           *outLogpp = logp;
+           if (flags & ICL_CRLOG_FLAG_PERSISTENT) {
+               ObtainWriteLock(&logp->lock, 184);
+               logp->states |= ICL_LOGF_PERSISTENT;
+               ReleaseWriteLock(&logp->lock);
+           }
+           ReleaseWriteLock(&afs_icl_lock);
+           return 0;
+       }
+    }
+
+    logp = (struct afs_icl_log *)
+       osi_AllocSmallSpace(sizeof(struct afs_icl_log));
+    memset((caddr_t) logp, 0, sizeof(*logp));
+
+    logp->refCount = 1;
+    logp->name = osi_AllocSmallSpace(strlen(name) + 1);
+    strcpy(logp->name, name);
+    LOCK_INIT(&logp->lock, "logp lock");
+    logp->logSize = logSize;
+    logp->datap = NULL;                /* don't allocate it until we need it */
+
+    if (flags & ICL_CRLOG_FLAG_PERSISTENT)
+       logp->states |= ICL_LOGF_PERSISTENT;
+
+    logp->nextp = afs_icl_allLogs;
+    afs_icl_allLogs = logp;
+    ReleaseWriteLock(&afs_icl_lock);
+
+    *outLogpp = logp;
+    return 0;
+}
+
+/* called with a log, a pointer to a buffer, the size of the buffer
+ * (in *bufSizep), the starting cookie (in *cookiep, use 0 at the start)
+ * and returns data in the provided buffer, and returns output flags
+ * in *flagsp.  The flag ICL_COPYOUTF_MISSEDSOME is set if we can't
+ * find the record with cookie value cookie.
+ */
+int
+afs_icl_CopyOut(register struct afs_icl_log *logp, afs_int32 * bufferp,
+               afs_int32 * bufSizep, afs_uint32 * cookiep,
+               afs_int32 * flagsp)
+{
+    afs_int32 nwords;          /* number of words to copy out */
+    afs_uint32 startCookie;    /* first cookie to use */
+    afs_int32 outWords;                /* words we've copied out */
+    afs_int32 inWords;         /* max words to copy out */
+    afs_int32 code;            /* return code */
+    afs_int32 ix;              /* index we're copying from */
+    afs_int32 outFlags;                /* return flags */
+    afs_int32 inFlags;         /* flags passed in */
+    afs_int32 end;
+
+    inWords = *bufSizep;       /* max to copy out */
+    outWords = 0;              /* amount copied out */
+    startCookie = *cookiep;
+    outFlags = 0;
+    inFlags = *flagsp;
+    code = 0;
+
+    ObtainWriteLock(&logp->lock, 185);
+    if (!logp->datap) {
+       ReleaseWriteLock(&logp->lock);
+       goto done;
+    }
+
+    /* first, compute the index of the start cookie we've been passed */
+    while (1) {
+       /* (re-)compute where we should start */
+       if (startCookie < logp->baseCookie) {
+           if (startCookie)    /* missed some output */
+               outFlags |= ICL_COPYOUTF_MISSEDSOME;
+           /* skip to the first available record */
+           startCookie = logp->baseCookie;
+           *cookiep = startCookie;
+       }
+
+       /* compute where we find the first element to copy out */
+       ix = logp->firstUsed + startCookie - logp->baseCookie;
+       if (ix >= logp->logSize)
+           ix -= logp->logSize;
+
+       /* if have some data now, break out and process it */
+       if (startCookie - logp->baseCookie < logp->logElements)
+           break;
+
+       /* At end of log, so clear it if we need to */
+       if (inFlags & ICL_COPYOUTF_CLRAFTERREAD) {
+           logp->firstUsed = logp->firstFree = 0;
+           logp->logElements = 0;
+       }
+       /* otherwise, either wait for the data to arrive, or return */
+       if (!(inFlags & ICL_COPYOUTF_WAITIO)) {
+           ReleaseWriteLock(&logp->lock);
+           code = 0;
+           goto done;
+       }
+       logp->states |= ICL_LOGF_WAITING;
+       ReleaseWriteLock(&logp->lock);
+       afs_osi_Sleep(&logp->lock);
+       ObtainWriteLock(&logp->lock, 186);
+    }
+    /* copy out data from ix to logSize or firstFree, depending
+     * upon whether firstUsed <= firstFree (no wrap) or otherwise.
+     * be careful not to copy out more than nwords.
+     */
+    if (ix >= logp->firstUsed) {
+       if (logp->firstUsed <= logp->firstFree)
+           /* no wrapping */
+           end = logp->firstFree;      /* first element not to copy */
+       else
+           end = logp->logSize;
+       nwords = inWords;       /* don't copy more than this */
+       if (end - ix < nwords)
+           nwords = end - ix;
+       if (nwords > 0) {
+           memcpy((char *)bufferp, (char *)&logp->datap[ix],
+                  sizeof(afs_int32) * nwords);
+           outWords += nwords;
+           inWords -= nwords;
+           bufferp += nwords;
+       }
+       /* if we're going to copy more out below, we'll start here */
+       ix = 0;
+    }
+    /* now, if active part of the log has wrapped, there's more stuff
+     * starting at the head of the log.  Copy out more from there.
+     */
+    if (logp->firstUsed > logp->firstFree && ix < logp->firstFree
+       && inWords > 0) {
+       /* (more to) copy out from the wrapped section at the
+        * start of the log.  May get here even if didn't copy any
+        * above, if the cookie points directly into the wrapped section.
+        */
+       nwords = inWords;
+       if (logp->firstFree - ix < nwords)
+           nwords = logp->firstFree - ix;
+       memcpy((char *)bufferp, (char *)&logp->datap[ix],
+              sizeof(afs_int32) * nwords);
+       outWords += nwords;
+       inWords -= nwords;
+       bufferp += nwords;
+    }
+
+    ReleaseWriteLock(&logp->lock);
+
+  done:
+    if (code == 0) {
+       *bufSizep = outWords;
+       *flagsp = outFlags;
+    }
+    return code;
+}
+
+/* return basic parameter information about a log */
+int
+afs_icl_GetLogParms(struct afs_icl_log *logp, afs_int32 * maxSizep,
+                   afs_int32 * curSizep)
+{
+    ObtainReadLock(&logp->lock);
+    *maxSizep = logp->logSize;
+    *curSizep = logp->logElements;
+    ReleaseReadLock(&logp->lock);
+    return 0;
+}
+
+
+/* hold and release logs */
+int
+afs_icl_LogHold(register struct afs_icl_log *logp)
+{
+    ObtainWriteLock(&afs_icl_lock, 187);
+    logp->refCount++;
+    ReleaseWriteLock(&afs_icl_lock);
+    return 0;
+}
+
+/* hold and release logs, called with lock already held */
+int
+afs_icl_LogHoldNL(register struct afs_icl_log *logp)
+{
+    logp->refCount++;
+    return 0;
+}
+
+/* keep track of how many sets believe the log itself is allocated */
+int
+afs_icl_LogUse(register struct afs_icl_log *logp)
+{
+    ObtainWriteLock(&logp->lock, 188);
+    if (logp->setCount == 0) {
+       /* this is the first set actually using the log -- allocate it */
+       if (logp->logSize == 0) {
+           /* we weren't passed in a hint and it wasn't set */
+           logp->logSize = ICL_DEFAULT_LOGSIZE;
+       }
+       logp->datap =
+           (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * logp->logSize);
+#ifdef KERNEL_HAVE_PIN
+       pin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
+#endif
+    }
+    logp->setCount++;
+    ReleaseWriteLock(&logp->lock);
+    return 0;
+}
+
+/* decrement the number of real users of the log, free if possible */
+int
+afs_icl_LogFreeUse(register struct afs_icl_log *logp)
+{
+    ObtainWriteLock(&logp->lock, 189);
+    if (--logp->setCount == 0) {
+       /* no more users -- free it (but keep log structure around) */
+#ifdef KERNEL_HAVE_PIN
+       unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
+#endif
+       afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
+       logp->firstUsed = logp->firstFree = 0;
+       logp->logElements = 0;
+       logp->datap = NULL;
+    }
+    ReleaseWriteLock(&logp->lock);
+    return 0;
+}
+
+/* set the size of the log to 'logSize' */
+int
+afs_icl_LogSetSize(register struct afs_icl_log *logp, afs_int32 logSize)
+{
+    ObtainWriteLock(&logp->lock, 190);
+    if (!logp->datap) {
+       /* nothing to worry about since it's not allocated */
+       logp->logSize = logSize;
+    } else {
+       /* reset log */
+       logp->firstUsed = logp->firstFree = 0;
+       logp->logElements = 0;
+
+       /* free and allocate a new one */
+#ifdef KERNEL_HAVE_PIN
+       unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
+#endif
+       afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
+       logp->datap =
+           (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * logSize);
+#ifdef KERNEL_HAVE_PIN
+       pin((char *)logp->datap, sizeof(afs_int32) * logSize);
+#endif
+       logp->logSize = logSize;
+    }
+    ReleaseWriteLock(&logp->lock);
+
+    return 0;
+}
+
+/* free a log.  Called with afs_icl_lock locked. */
+int
+afs_icl_ZapLog(register struct afs_icl_log *logp)
+{
+    register struct afs_icl_log **lpp, *tp;
+
+    for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
+       if (tp == logp) {
+           /* found the dude we want to remove */
+           *lpp = logp->nextp;
+           osi_FreeSmallSpace(logp->name);
+#ifdef KERNEL_HAVE_PIN
+           unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
+#endif
+           afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
+           osi_FreeSmallSpace(logp);
+           break;              /* won't find it twice */
+       }
+    }
+    return 0;
+}
+
+/* do the release, watching for deleted entries */
+int
+afs_icl_LogRele(register struct afs_icl_log *logp)
+{
+    ObtainWriteLock(&afs_icl_lock, 191);
+    if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
+       afs_icl_ZapLog(logp);   /* destroys logp's lock! */
+    }
+    ReleaseWriteLock(&afs_icl_lock);
+    return 0;
+}
+
+/* do the release, watching for deleted entries, log already held */
+int
+afs_icl_LogReleNL(register struct afs_icl_log *logp)
+{
+    if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
+       afs_icl_ZapLog(logp);   /* destroys logp's lock! */
+    }
+    return 0;
+}
+
+/* zero out the log */
+int
+afs_icl_ZeroLog(register struct afs_icl_log *logp)
+{
+    ObtainWriteLock(&logp->lock, 192);
+    logp->firstUsed = logp->firstFree = 0;
+    logp->logElements = 0;
+    logp->baseCookie = 0;
+    ReleaseWriteLock(&logp->lock);
+    return 0;
+}
+
+/* free a log entry, and drop its reference count */
+int
+afs_icl_LogFree(register struct afs_icl_log *logp)
+{
+    ObtainWriteLock(&logp->lock, 193);
+    logp->states |= ICL_LOGF_DELETED;
+    ReleaseWriteLock(&logp->lock);
+    afs_icl_LogRele(logp);
+    return 0;
+}
+
+/* find a log by name, returning it held */
+struct afs_icl_log *
+afs_icl_FindLog(char *name)
+{
+    register struct afs_icl_log *tp;
+    ObtainWriteLock(&afs_icl_lock, 194);
+    for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
+       if (strcmp(tp->name, name) == 0) {
+           /* this is the dude we want */
+           tp->refCount++;
+           break;
+       }
+    }
+    ReleaseWriteLock(&afs_icl_lock);
+    return tp;
+}
+
+int
+afs_icl_EnumerateLogs(int (*aproc)
+                       (char *name, char *arock, struct afs_icl_log * tp),
+                     char *arock)
+{
+    register struct afs_icl_log *tp;
+    register afs_int32 code;
+
+    code = 0;
+    ObtainWriteLock(&afs_icl_lock, 195);
+    for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
+       tp->refCount++;         /* hold this guy */
+       ReleaseWriteLock(&afs_icl_lock);
+       ObtainReadLock(&tp->lock);
+       code = (*aproc) (tp->name, arock, tp);
+       ReleaseReadLock(&tp->lock);
+       ObtainWriteLock(&afs_icl_lock, 196);
+       if (--tp->refCount == 0)
+           afs_icl_ZapLog(tp);
+       if (code)
+           break;
+    }
+    ReleaseWriteLock(&afs_icl_lock);
+    return code;
+}
+
+struct afs_icl_set *afs_icl_allSets = 0;
+
+int
+afs_icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
+                 struct afs_icl_log *fatalLogp,
+                 struct afs_icl_set **outSetpp)
+{
+    return afs_icl_CreateSetWithFlags(name, baseLogp, fatalLogp,
+                                     /*flags */ 0, outSetpp);
+}
+
+/* create a set, given pointers to base and fatal logs, if any.
+ * Logs are unlocked, but referenced, and *outSetpp is returned
+ * referenced.  Function bumps reference count on logs, since it
+ * addds references from the new afs_icl_set.  When the set is destroyed,
+ * those references will be released.
+ */
+int
+afs_icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
+                          struct afs_icl_log *fatalLogp, afs_uint32 flags,
+                          struct afs_icl_set **outSetpp)
+{
+    register struct afs_icl_set *setp;
+    register int i;
+    afs_int32 states = ICL_DEFAULT_SET_STATES;
+
+    ObtainWriteLock(&afs_icl_lock, 197);
+    if (!afs_icl_inited)
+       afs_icl_Init();
+
+    for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
+       if (strcmp(setp->name, name) == 0) {
+           setp->refCount++;
+           *outSetpp = setp;
+           if (flags & ICL_CRSET_FLAG_PERSISTENT) {
+               ObtainWriteLock(&setp->lock, 198);
+               setp->states |= ICL_SETF_PERSISTENT;
+               ReleaseWriteLock(&setp->lock);
+           }
+           ReleaseWriteLock(&afs_icl_lock);
+           return 0;
+       }
+    }
+
+    /* determine initial state */
+    if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
+       states = ICL_SETF_ACTIVE;
+    else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
+       states = ICL_SETF_FREED;
+    if (flags & ICL_CRSET_FLAG_PERSISTENT)
+       states |= ICL_SETF_PERSISTENT;
+
+    setp = (struct afs_icl_set *)afs_osi_Alloc(sizeof(struct afs_icl_set));
+    memset((caddr_t) setp, 0, sizeof(*setp));
+    setp->refCount = 1;
+    if (states & ICL_SETF_FREED)
+       states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
+    setp->states = states;
+
+    LOCK_INIT(&setp->lock, "setp lock");
+    /* next lock is obtained in wrong order, hierarchy-wise, but
+     * it doesn't matter, since no one can find this lock yet, since
+     * the afs_icl_lock is still held, and thus the obtain can't block.
+     */
+    ObtainWriteLock(&setp->lock, 199);
+    setp->name = osi_AllocSmallSpace(strlen(name) + 1);
+    strcpy(setp->name, name);
+    setp->nevents = ICL_DEFAULTEVENTS;
+    setp->eventFlags = afs_osi_Alloc(ICL_DEFAULTEVENTS);
+#ifdef KERNEL_HAVE_PIN
+    pin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
+#endif
+    for (i = 0; i < ICL_DEFAULTEVENTS; i++)
+       setp->eventFlags[i] = 0xff;     /* default to enabled */
+
+    /* update this global info under the afs_icl_lock */
+    setp->nextp = afs_icl_allSets;
+    afs_icl_allSets = setp;
+    ReleaseWriteLock(&afs_icl_lock);
+
+    /* set's basic lock is still held, so we can finish init */
+    if (baseLogp) {
+       setp->logs[0] = baseLogp;
+       afs_icl_LogHold(baseLogp);
+       if (!(setp->states & ICL_SETF_FREED))
+           afs_icl_LogUse(baseLogp);   /* log is actually being used */
+    }
+    if (fatalLogp) {
+       setp->logs[1] = fatalLogp;
+       afs_icl_LogHold(fatalLogp);
+       if (!(setp->states & ICL_SETF_FREED))
+           afs_icl_LogUse(fatalLogp);  /* log is actually being used */
+    }
+    ReleaseWriteLock(&setp->lock);
+
+    *outSetpp = setp;
+    return 0;
+}
+
+/* function to change event enabling information for a particular set */
+int
+afs_icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
+{
+    char *tp;
+
+    ObtainWriteLock(&setp->lock, 200);
+    if (!ICL_EVENTOK(setp, eventID)) {
+       ReleaseWriteLock(&setp->lock);
+       return -1;
+    }
+    tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
+    if (setValue)
+       *tp |= ICL_EVENTMASK(eventID);
+    else
+       *tp &= ~(ICL_EVENTMASK(eventID));
+    ReleaseWriteLock(&setp->lock);
+    return 0;
+}
+
+/* return indication of whether a particular event ID is enabled
+ * for tracing.  If *getValuep is set to 0, the event is disabled,
+ * otherwise it is enabled.  All events start out enabled by default.
+ */
+int
+afs_icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
+{
+    ObtainReadLock(&setp->lock);
+    if (!ICL_EVENTOK(setp, eventID)) {
+       ReleaseWriteLock(&setp->lock);
+       return -1;
+    }
+    if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
+       *getValuep = 1;
+    else
+       *getValuep = 0;
+    ReleaseReadLock(&setp->lock);
+    return 0;
+}
+
+/* hold and release event sets */
+int
+afs_icl_SetHold(register struct afs_icl_set *setp)
+{
+    ObtainWriteLock(&afs_icl_lock, 201);
+    setp->refCount++;
+    ReleaseWriteLock(&afs_icl_lock);
+    return 0;
+}
+
+/* free a set.  Called with afs_icl_lock locked */
+int
+afs_icl_ZapSet(register struct afs_icl_set *setp)
+{
+    register struct afs_icl_set **lpp, *tp;
+    int i;
+    register struct afs_icl_log *tlp;
+
+    for (lpp = &afs_icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
+       if (tp == setp) {
+           /* found the dude we want to remove */
+           *lpp = setp->nextp;
+           osi_FreeSmallSpace(setp->name);
+#ifdef KERNEL_HAVE_PIN
+           unpin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
+#endif
+           afs_osi_Free(setp->eventFlags, ICL_DEFAULTEVENTS);
+           for (i = 0; i < ICL_LOGSPERSET; i++) {
+               if ((tlp = setp->logs[i]))
+                   afs_icl_LogReleNL(tlp);
+           }
+           osi_FreeSmallSpace(setp);
+           break;              /* won't find it twice */
+       }
+    }
+    return 0;
+}
+
+/* do the release, watching for deleted entries */
+int
+afs_icl_SetRele(register struct afs_icl_set *setp)
+{
+    ObtainWriteLock(&afs_icl_lock, 202);
+    if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
+       afs_icl_ZapSet(setp);   /* destroys setp's lock! */
+    }
+    ReleaseWriteLock(&afs_icl_lock);
+    return 0;
+}
+
+/* free a set entry, dropping its reference count */
+int
+afs_icl_SetFree(register struct afs_icl_set *setp)
+{
+    ObtainWriteLock(&setp->lock, 203);
+    setp->states |= ICL_SETF_DELETED;
+    ReleaseWriteLock(&setp->lock);
+    afs_icl_SetRele(setp);
+    return 0;
+}
+
+/* find a set by name, returning it held */
+struct afs_icl_set *
+afs_icl_FindSet(char *name)
+{
+    register struct afs_icl_set *tp;
+    ObtainWriteLock(&afs_icl_lock, 204);
+    for (tp = afs_icl_allSets; tp; tp = tp->nextp) {
+       if (strcmp(tp->name, name) == 0) {
+           /* this is the dude we want */
+           tp->refCount++;
+           break;
+       }
+    }
+    ReleaseWriteLock(&afs_icl_lock);
+    return tp;
+}
+
+/* zero out all the logs in the set */
+int
+afs_icl_ZeroSet(struct afs_icl_set *setp)
+{
+    register int i;
+    int code = 0;
+    int tcode;
+    struct afs_icl_log *logp;
+
+    ObtainReadLock(&setp->lock);
+    for (i = 0; i < ICL_LOGSPERSET; i++) {
+       logp = setp->logs[i];
+       if (logp) {
+           afs_icl_LogHold(logp);
+           tcode = afs_icl_ZeroLog(logp);
+           if (tcode != 0)
+               code = tcode;   /* save the last bad one */
+           afs_icl_LogRele(logp);
+       }
+    }
+    ReleaseReadLock(&setp->lock);
+    return code;
+}
+
+int
+afs_icl_EnumerateSets(int (*aproc)
+                       (char *name, char *arock, struct afs_icl_log * tp),
+                     char *arock)
+{
+    register struct afs_icl_set *tp, *np;
+    register afs_int32 code;
+
+    code = 0;
+    ObtainWriteLock(&afs_icl_lock, 205);
+    for (tp = afs_icl_allSets; tp; tp = np) {
+       tp->refCount++;         /* hold this guy */
+       ReleaseWriteLock(&afs_icl_lock);
+       code = (*aproc) (tp->name, arock, (struct afs_icl_log *)tp);
+       ObtainWriteLock(&afs_icl_lock, 206);
+       np = tp->nextp;         /* tp may disappear next, but not np */
+       if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
+           afs_icl_ZapSet(tp);
+       if (code)
+           break;
+    }
+    ReleaseWriteLock(&afs_icl_lock);
+    return code;
+}
+
+int
+afs_icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
+{
+    register int i;
+    int code = -1;
+
+    ObtainWriteLock(&setp->lock, 207);
+    for (i = 0; i < ICL_LOGSPERSET; i++) {
+       if (!setp->logs[i]) {
+           setp->logs[i] = newlogp;
+           code = i;
+           afs_icl_LogHold(newlogp);
+           if (!(setp->states & ICL_SETF_FREED)) {
+               /* bump up the number of sets using the log */
+               afs_icl_LogUse(newlogp);
+           }
+           break;
+       }
+    }
+    ReleaseWriteLock(&setp->lock);
+    return code;
+}
+
+int
+afs_icl_SetSetStat(struct afs_icl_set *setp, int op)
+{
+    int i;
+    afs_int32 code;
+    struct afs_icl_log *logp;
+
+    ObtainWriteLock(&setp->lock, 208);
+    switch (op) {
+    case ICL_OP_SS_ACTIVATE:   /* activate a log */
+       /*
+        * If we are not already active, see if we have released
+        * our demand that the log be allocated (FREED set).  If
+        * we have, reassert our desire.
+        */
+       if (!(setp->states & ICL_SETF_ACTIVE)) {
+           if (setp->states & ICL_SETF_FREED) {
+               /* have to reassert desire for logs */
+               for (i = 0; i < ICL_LOGSPERSET; i++) {
+                   logp = setp->logs[i];
+                   if (logp) {
+                       afs_icl_LogHold(logp);
+                       afs_icl_LogUse(logp);
+                       afs_icl_LogRele(logp);
+                   }
+               }
+               setp->states &= ~ICL_SETF_FREED;
+           }
+           setp->states |= ICL_SETF_ACTIVE;
+       }
+       code = 0;
+       break;
+
+    case ICL_OP_SS_DEACTIVATE: /* deactivate a log */
+       /* this doesn't require anything beyond clearing the ACTIVE flag */
+       setp->states &= ~ICL_SETF_ACTIVE;
+       code = 0;
+       break;
+
+    case ICL_OP_SS_FREE:       /* deassert design for log */
+       /* 
+        * if we are already in this state, do nothing; otherwise
+        * deassert desire for log
+        */
+       if (setp->states & ICL_SETF_ACTIVE)
+           code = EINVAL;
+       else {
+           if (!(setp->states & ICL_SETF_FREED)) {
+               for (i = 0; i < ICL_LOGSPERSET; i++) {
+                   logp = setp->logs[i];
+                   if (logp) {
+                       afs_icl_LogHold(logp);
+                       afs_icl_LogFreeUse(logp);
+                       afs_icl_LogRele(logp);
+                   }
+               }
+               setp->states |= ICL_SETF_FREED;
+           }
+           code = 0;
+       }
+       break;
+
+    default:
+       code = EINVAL;
+    }
+    ReleaseWriteLock(&setp->lock);
+    return code;
+}
index b2503ae..ad6defa 100644 (file)
@@ -39,6 +39,7 @@ char *afs_sysname = 0;                /* So that superuser may change the
                                 * local value of @sys */
 char *afs_sysnamelist[MAXNUMSYSNAMES]; /* For support of a list of sysname */
 int afs_sysnamecount = 0;
+int afs_sysnamegen = 0;
 struct volume *Initialafs_freeVolList;
 int afs_memvolumes = 0;
 #if defined(AFS_XBSD_ENV)
@@ -492,6 +493,7 @@ afs_ResourceInit(int preallocs)
        afs_sysname = afs_sysnamelist[0];
        strcpy(afs_sysname, SYS_NAME);
        afs_sysnamecount = 1;
+       afs_sysnamegen++;
     }
 
     secobj = rxnull_NewServerSecurityObject();
diff --git a/src/afs/afs_md5.c b/src/afs/afs_md5.c
new file mode 100644 (file)
index 0000000..928725e
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include "afs/param.h"
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+
+
+RCSID("$Id$");
+
+#undef WORDS_BIGENDIAN
+#ifdef AFSBIG_ENDIAN
+#define WORDS_BIGENDIAN 1
+#endif
+
+#include "afs_md5.h"
+
+#define A m->counter[0]
+#define B m->counter[1]
+#define C m->counter[2]
+#define D m->counter[3]
+#define X data
+
+void
+AFS_MD5_Init(struct afs_md5 *m)
+{
+    m->sz[0] = 0;
+    m->sz[1] = 0;
+    D = 0x10325476;
+    C = 0x98badcfe;
+    B = 0xefcdab89;
+    A = 0x67452301;
+}
+
+#define F(x,y,z) CRAYFIX((x & y) | (~x & z))
+#define G(x,y,z) CRAYFIX((x & z) | (y & ~z))
+#define H(x,y,z) (x ^ y ^ z)
+#define I(x,y,z) CRAYFIX(y ^ (x | ~z))
+
+#define DOIT(a,b,c,d,k,s,i,OP) \
+a = b + cshift(a + OP(b,c,d) + X[k] + (i), s)
+
+#define DO1(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,F)
+#define DO2(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,G)
+#define DO3(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,H)
+#define DO4(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,I)
+
+static inline void
+calc(struct afs_md5 *m, afs_uint32 * data)
+{
+    afs_uint32 AA, BB, CC, DD;
+
+    AA = A;
+    BB = B;
+    CC = C;
+    DD = D;
+
+    /* Round 1 */
+
+    DO1(A, B, C, D, 0, 7, 0xd76aa478);
+    DO1(D, A, B, C, 1, 12, 0xe8c7b756);
+    DO1(C, D, A, B, 2, 17, 0x242070db);
+    DO1(B, C, D, A, 3, 22, 0xc1bdceee);
+
+    DO1(A, B, C, D, 4, 7, 0xf57c0faf);
+    DO1(D, A, B, C, 5, 12, 0x4787c62a);
+    DO1(C, D, A, B, 6, 17, 0xa8304613);
+    DO1(B, C, D, A, 7, 22, 0xfd469501);
+
+    DO1(A, B, C, D, 8, 7, 0x698098d8);
+    DO1(D, A, B, C, 9, 12, 0x8b44f7af);
+    DO1(C, D, A, B, 10, 17, 0xffff5bb1);
+    DO1(B, C, D, A, 11, 22, 0x895cd7be);
+
+    DO1(A, B, C, D, 12, 7, 0x6b901122);
+    DO1(D, A, B, C, 13, 12, 0xfd987193);
+    DO1(C, D, A, B, 14, 17, 0xa679438e);
+    DO1(B, C, D, A, 15, 22, 0x49b40821);
+
+    /* Round 2 */
+
+    DO2(A, B, C, D, 1, 5, 0xf61e2562);
+    DO2(D, A, B, C, 6, 9, 0xc040b340);
+    DO2(C, D, A, B, 11, 14, 0x265e5a51);
+    DO2(B, C, D, A, 0, 20, 0xe9b6c7aa);
+
+    DO2(A, B, C, D, 5, 5, 0xd62f105d);
+    DO2(D, A, B, C, 10, 9, 0x2441453);
+    DO2(C, D, A, B, 15, 14, 0xd8a1e681);
+    DO2(B, C, D, A, 4, 20, 0xe7d3fbc8);
+
+    DO2(A, B, C, D, 9, 5, 0x21e1cde6);
+    DO2(D, A, B, C, 14, 9, 0xc33707d6);
+    DO2(C, D, A, B, 3, 14, 0xf4d50d87);
+    DO2(B, C, D, A, 8, 20, 0x455a14ed);
+
+    DO2(A, B, C, D, 13, 5, 0xa9e3e905);
+    DO2(D, A, B, C, 2, 9, 0xfcefa3f8);
+    DO2(C, D, A, B, 7, 14, 0x676f02d9);
+    DO2(B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+    /* Round 3 */
+
+    DO3(A, B, C, D, 5, 4, 0xfffa3942);
+    DO3(D, A, B, C, 8, 11, 0x8771f681);
+    DO3(C, D, A, B, 11, 16, 0x6d9d6122);
+    DO3(B, C, D, A, 14, 23, 0xfde5380c);
+
+    DO3(A, B, C, D, 1, 4, 0xa4beea44);
+    DO3(D, A, B, C, 4, 11, 0x4bdecfa9);
+    DO3(C, D, A, B, 7, 16, 0xf6bb4b60);
+    DO3(B, C, D, A, 10, 23, 0xbebfbc70);
+
+    DO3(A, B, C, D, 13, 4, 0x289b7ec6);
+    DO3(D, A, B, C, 0, 11, 0xeaa127fa);
+    DO3(C, D, A, B, 3, 16, 0xd4ef3085);
+    DO3(B, C, D, A, 6, 23, 0x4881d05);
+
+    DO3(A, B, C, D, 9, 4, 0xd9d4d039);
+    DO3(D, A, B, C, 12, 11, 0xe6db99e5);
+    DO3(C, D, A, B, 15, 16, 0x1fa27cf8);
+    DO3(B, C, D, A, 2, 23, 0xc4ac5665);
+
+    /* Round 4 */
+
+    DO4(A, B, C, D, 0, 6, 0xf4292244);
+    DO4(D, A, B, C, 7, 10, 0x432aff97);
+    DO4(C, D, A, B, 14, 15, 0xab9423a7);
+    DO4(B, C, D, A, 5, 21, 0xfc93a039);
+
+    DO4(A, B, C, D, 12, 6, 0x655b59c3);
+    DO4(D, A, B, C, 3, 10, 0x8f0ccc92);
+    DO4(C, D, A, B, 10, 15, 0xffeff47d);
+    DO4(B, C, D, A, 1, 21, 0x85845dd1);
+
+    DO4(A, B, C, D, 8, 6, 0x6fa87e4f);
+    DO4(D, A, B, C, 15, 10, 0xfe2ce6e0);
+    DO4(C, D, A, B, 6, 15, 0xa3014314);
+    DO4(B, C, D, A, 13, 21, 0x4e0811a1);
+
+    DO4(A, B, C, D, 4, 6, 0xf7537e82);
+    DO4(D, A, B, C, 11, 10, 0xbd3af235);
+    DO4(C, D, A, B, 2, 15, 0x2ad7d2bb);
+    DO4(B, C, D, A, 9, 21, 0xeb86d391);
+
+    A += AA;
+    B += BB;
+    C += CC;
+    D += DD;
+}
+
+/*
+ * From `Performance analysis of MD5' by Joseph D. Touch <touch@isi.edu>
+ */
+
+#if defined(WORDS_BIGENDIAN)
+static inline afs_uint32
+swap_afs_uint32(afs_uint32 t)
+{
+    afs_uint32 temp1, temp2;
+
+    temp1 = cshift(t, 16);
+    temp2 = temp1 >> 8;
+    temp1 &= 0x00ff00ff;
+    temp2 &= 0x00ff00ff;
+    temp1 <<= 8;
+    return temp1 | temp2;
+}
+#endif
+
+struct x32 {
+    unsigned int a:32;
+    unsigned int b:32;
+};
+
+void
+AFS_MD5_Update(struct afs_md5 *m, const void *v, size_t len)
+{
+    const unsigned char *p = v;
+    size_t old_sz = m->sz[0];
+    size_t offset;
+
+    m->sz[0] += len * 8;
+    if (m->sz[0] < old_sz)
+       ++m->sz[1];
+    offset = (old_sz / 8) % 64;
+    while (len > 0) {
+       size_t l = min(len, 64 - offset);
+       memcpy(m->save + offset, p, l);
+       offset += l;
+       p += l;
+       len -= l;
+       if (offset == 64) {
+#if defined(WORDS_BIGENDIAN)
+           int i;
+           afs_uint32 current[16];
+           struct x32 *u = (struct x32 *)m->save;
+           for (i = 0; i < 8; i++) {
+               current[2 * i + 0] = swap_afs_uint32(u[i].a);
+               current[2 * i + 1] = swap_afs_uint32(u[i].b);
+           }
+           calc(m, current);
+#else
+           calc(m, (afs_uint32 *) m->save);
+#endif
+           offset = 0;
+       }
+    }
+}
+
+void
+AFS_MD5_Final(void *res, struct afs_md5 *m)
+{
+    static unsigned char zeros[72];
+    unsigned offset = (m->sz[0] / 8) % 64;
+    unsigned int dstart = (120 - offset - 1) % 64 + 1;
+
+    *zeros = 0x80;
+    memset(zeros + 1, 0, sizeof(zeros) - 1);
+    zeros[dstart + 0] = (m->sz[0] >> 0) & 0xff;
+    zeros[dstart + 1] = (m->sz[0] >> 8) & 0xff;
+    zeros[dstart + 2] = (m->sz[0] >> 16) & 0xff;
+    zeros[dstart + 3] = (m->sz[0] >> 24) & 0xff;
+    zeros[dstart + 4] = (m->sz[1] >> 0) & 0xff;
+    zeros[dstart + 5] = (m->sz[1] >> 8) & 0xff;
+    zeros[dstart + 6] = (m->sz[1] >> 16) & 0xff;
+    zeros[dstart + 7] = (m->sz[1] >> 24) & 0xff;
+    AFS_MD5_Update(m, zeros, dstart + 8);
+    {
+       int i;
+       unsigned char *r = (unsigned char *)res;
+
+       for (i = 0; i < 4; ++i) {
+           r[4 * i] = m->counter[i] & 0xFF;
+           r[4 * i + 1] = (m->counter[i] >> 8) & 0xFF;
+           r[4 * i + 2] = (m->counter[i] >> 16) & 0xFF;
+           r[4 * i + 3] = (m->counter[i] >> 24) & 0xFF;
+       }
+    }
+#if 0
+    {
+       int i;
+       afs_uint32 *r = (afs_uint32 *) res;
+
+       for (i = 0; i < 4; ++i)
+           r[i] = swap_afs_uint32(m->counter[i]);
+    }
+#endif
+}
+
+void
+AFS_MD5_String(void *res, const void *v, size_t len)
+{
+    struct afs_md5 m;
+
+    AFS_MD5_Init(&m);
+    AFS_MD5_Update(&m, v, len);
+    AFS_MD5_Final(res, &m);
+}
diff --git a/src/afs/afs_md5.h b/src/afs/afs_md5.h
new file mode 100644 (file)
index 0000000..c261283
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+
+struct afs_md5 {
+    unsigned int sz[2];
+    afs_uint32 counter[4];
+    unsigned char save[64];
+};
+
+void AFS_MD5_Init(struct afs_md5 *m);
+void AFS_MD5_Update(struct afs_md5 *m, const void *p, size_t len);
+void AFS_MD5_Final(void *res, struct afs_md5 *m);      /* afs_uint32 res[4] */
+void AFS_MD5_String(void *res, const void *v, size_t len);
+
+/* stuff in common between md4, md5, and sha1 */
+
+#ifndef min
+#define min(a,b) (((a)>(b))?(b):(a))
+#endif
+
+/* Vector Crays doesn't have a good 32-bit type, or more precisely,
+   int32_t as defined by <bind/bitypes.h> isn't 32 bits, and we don't
+   want to depend in being able to redefine this type.  To cope with
+   this we have to clamp the result in some places to [0,2^32); no
+   need to do this on other machines.  Did I say this was a mess?
+   */
+
+#ifdef _CRAY
+#define CRAYFIX(X) ((X) & 0xffffffff)
+#else
+#define CRAYFIX(X) (X)
+#endif
+
+#if !defined(inline) && !defined(__GNUC__)
+#define inline
+#endif
+
+static inline afs_uint32
+cshift(afs_uint32 x, unsigned int n)
+{
+    x = CRAYFIX(x);
+    return CRAYFIX((x << n) | (x >> (32 - n)));
+}
index 5f16f66..ae676da 100644 (file)
@@ -18,9 +18,13 @@ RCSID
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* statistics */
 #include "afs/nfsclient.h"
+#include "rx/rx_globals.h"
+#include "afs/pagcb.h"
 
-int afs_nfsclient_reqhandler(), afs_nfsclient_hold(), afs_PutNfsClientPag();
-int afs_nfsclient_sysname(), afs_nfsclient_GC(), afs_nfsclient_stats();
+void afs_nfsclient_hold(), afs_PutNfsClientPag(), afs_nfsclient_GC();
+static void afs_nfsclient_getcreds();
+int afs_nfsclient_sysname(), afs_nfsclient_stats(), afs_nfsclient_checkhost();
+afs_int32 afs_nfsclient_gethost();
 #ifdef AFS_AIX_IAUTH_ENV
 int afs_allnfsreqs, afs_nfscalls;
 #endif
@@ -33,6 +37,8 @@ struct exporterops nfs_exportops = {
     afs_nfsclient_sysname,
     afs_nfsclient_GC,
     afs_nfsclient_stats,
+    afs_nfsclient_checkhost,
+    afs_nfsclient_gethost
 };
 
 
@@ -89,7 +95,7 @@ afs_GetNfsClientPag(uid, host)
 
 /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call .
 It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */
-int
+void
 afs_PutNfsClientPag(np)
      register struct nfsclientpag *np;
 {
@@ -146,7 +152,9 @@ afs_FindNfsClientPag(uid, host, pag)
  */
 struct afs_exporter *afs_nfsexported = 0;
 static afs_int32 init_nfsexporter = 0;
-afs_nfsclient_init()
+
+void
+afs_nfsclient_init(void)
 {
 #if defined(AFS_SGIMP_ENV)
     osi_Assert(ISAFS_GLOCK());
@@ -166,16 +174,15 @@ afs_nfsclient_init()
  * phases of any remote call (via the NFS server or pioctl).
  */
 int
-afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
-     register struct afs_exporter *exporter, **outexporter;
-     struct AFS_UCRED **cred;
-     register afs_int32 host;
-     afs_int32 *pagparam;
+afs_nfsclient_reqhandler(struct afs_exporter *exporter,
+                        struct AFS_UCRED **cred,
+                        afs_int32 host, afs_int32 *pagparam,
+                        struct afs_exporter **outexporter)
 {
     register struct nfsclientpag *np, *tnp;
     extern struct unixuser *afs_FindUser(), *afs_GetUser();
     register struct unixuser *au = 0;
-    afs_int32 pag, code = 0;
+    afs_int32 uid, pag, code = 0;
 
     AFS_ASSERT_GLOCK();
     AFS_STATCNT(afs_nfsclient_reqhandler);
@@ -191,12 +198,15 @@ afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
     }
 /*    ObtainWriteLock(&afs_xnfsreq); */
     pag = PagInCred(*cred);
-    if (pag != NOPAG) {
+    uid = (*cred)->cr_uid;
+    if ((afs_nfsexporter->exp_states & EXP_CLIPAGS) && pag != NOPAG) {
+       uid = pag;
+    } else if (pag != NOPAG) {
        /* Do some minimal pag verification */
        if (pag > getpag()) {
            pag = NOPAG;        /* treat it as not paged since couldn't be good  */
        } else {
-           if (au = afs_FindUser(pag, -1, READ_LOCK)) {
+           if ((au = afs_FindUser(pag, -1, READ_LOCK))) {
                if (!au->exporter) {
                    pag = NOPAG;
                    afs_PutUser(au, READ_LOCK);
@@ -206,16 +216,24 @@ afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
                pag = NOPAG;    /*  No unixuser struct so pag not trusted  */
        }
     }
-    np = afs_FindNfsClientPag((*cred)->cr_uid, host, 0);
+    np = afs_FindNfsClientPag(uid, host, 0);
     afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag,
               ICL_TYPE_LONG, (*cred)->cr_uid, ICL_TYPE_INT32, host,
               ICL_TYPE_POINTER, np);
+    /* If remote-pags are enabled, we are no longer interested in what PAG
+     * they claimed, and from here on we should behave as if they claimed
+     * none at all, which is to say we use the (local) pag named in the
+     * nfsclientpag structure (if any).  This is deferred until here so
+     * that we can log the PAG they claimed.
+     */
+    if ((afs_nfsexporter->exp_states & EXP_CLIPAGS))
+               pag = NOPAG;
     if (!np) {
        /* Even if there is a "good" pag coming in we don't accept it if no nfsclientpag struct exists for the user since that would mean that the translator rebooted and therefore we ignore all older pag values */
 #ifdef AFS_OSF_ENV
-       if (code = setpag(u.u_procp, cred, -1, &pag, 1)) {      /* XXX u.u_procp is a no-op XXX */
+       if (code = setpag(u.u_procp, cred, -1, &pag, 0)) {      /* XXX u.u_procp is a no-op XXX */
 #else
-       if (code = setpag(cred, -1, &pag, 1)) {
+       if ((code = setpag(cred, -1, &pag, 0))) {
 #endif
            if (au)
                afs_PutUser(au, READ_LOCK);
@@ -225,14 +243,15 @@ afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
 #endif
            return (code);
        }
-       np = afs_GetNfsClientPag((*cred)->cr_uid, host);
+       np = afs_GetNfsClientPag(uid, host);
        np->pag = pag;
+       np->client_uid = (*cred)->cr_uid;
     } else {
        if (pag == NOPAG) {
 #ifdef AFS_OSF_ENV
-           if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) {     /* XXX u.u_procp is a no-op XXX */
+           if (code = setpag(u.u_procp, cred, np->pag, &pag, 0)) {     /* XXX u.u_procp is a no-op XXX */
 #else
-           if (code = setpag(cred, np->pag, &pag, 1)) {
+           if ((code = setpag(cred, np->pag, &pag, 0))) {
 #endif
                afs_PutNfsClientPag(np);
 /*             ReleaseWriteLock(&afs_xnfsreq); */
@@ -247,9 +266,9 @@ afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
            if (tnp->uid && (tnp->uid != (afs_int32) - 2)) {    /* allow "root" initiators */
                /* Pag doesn't belong to caller; treat it as an unpaged call too */
 #ifdef AFS_OSF_ENV
-               if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
+               if (code = setpag(u.u_procp, cred, np->pag, &pag, 0)) { /* XXX u.u_procp is a no-op XXX */
 #else
-               if (code = setpag(cred, np->pag, &pag, 1)) {
+               if ((code = setpag(cred, np->pag, &pag, 0))) {
 #endif
                    afs_PutNfsClientPag(np);
                    afs_PutUser(au, READ_LOCK);
@@ -269,6 +288,10 @@ afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
     if (!(au->exporter)) {     /* Created new unixuser struct */
        np->refCount++;         /* so it won't disappear */
        au->exporter = (struct afs_exporter *)np;
+       if ((afs_nfsexporter->exp_states & EXP_CALLBACK))
+           afs_nfsclient_getcreds(au);
+    } else while (au->states & UNFSGetCreds) {
+       afs_osi_Sleep((void *)au);
     }
     *pagparam = pag;
     *outexporter = (struct afs_exporter *)np;
@@ -282,9 +305,123 @@ afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
     return 0;
 }
 
+void
+afs_nfsclient_getcreds(au)
+    struct unixuser *au;
+{
+    struct nfsclientpag *np = (struct nfsclientpag *)(au->exporter);
+    struct rx_securityClass *csec;
+    struct rx_connection *tconn;
+    SysNameList tsysnames;
+    CredInfos tcreds;
+    CredInfo *tcred;
+    struct unixuser *tu;
+    struct cell *tcell;
+    int code, i, cellnum;
+
+    au->states |= UNFSGetCreds;
+    memset(&tcreds, 0, sizeof(tcreds));
+    memset(&tsysnames, 0, sizeof(tsysnames));
+
+    /* Get a connection */
+    /* This sucks a little.  We should cache the connections or something.
+     * But at this point I don't yet think it's worth the effort.
+     */
+    csec = rxnull_NewClientSecurityObject();
+    AFS_GUNLOCK();
+    tconn = rx_NewConnection(np->host, htons(7001), PAGCB_SERVICEID, csec, 0);
+    AFS_GLOCK();
+
+    /* Get the sysname, if needed */
+    if (!np->sysnamecount) {
+       AFS_GUNLOCK();
+       code = PAGCB_GetSysName(tconn, np->uid, &tsysnames);
+       AFS_GLOCK();
+       if (code ||
+           tsysnames.SysNameList_len <= 0 ||
+           tsysnames.SysNameList_len > MAXNUMSYSNAMES)
+           goto done;
+    
+       for(i = 0; i < np->sysnamecount; i++)
+           afs_osi_Free(np->sysname[i], MAXSYSNAME);
+
+       np->sysnamecount = tsysnames.SysNameList_len;
+       for(i = 0; i < np->sysnamecount; i++)
+           np->sysname[i] = tsysnames.SysNameList_val[i].sysname;
+        afs_osi_Free(tsysnames.SysNameList_val,
+                     tsysnames.SysNameList_len * sizeof(SysNameEnt));
+    }
+
+    /* Get credentials */
+    AFS_GUNLOCK();
+    code = PAGCB_GetCreds(tconn, np->uid, &tcreds);
+    AFS_GLOCK();
+    if (code)
+       goto done;
+
+    /* Now, set the credentials they gave us... */
+    for (i = 0; i < tcreds.CredInfos_len; i++) {
+       tcred = &tcreds.CredInfos_val[i];
+
+       /* Find the cell.  If it is unknown to us, punt this entry. */
+       tcell = afs_GetCellByName(tcred->cellname, READ_LOCK);
+       afs_osi_Free(tcred->cellname, strlen(tcred->cellname) + 1);
+       if (!tcell) {
+           memset(tcred->ct.HandShakeKey, 0, 8);
+           memset(tcred->st.st_val, 0, tcred->st.st_len);
+           afs_osi_Free(tcred->st.st_val, tcred->st.st_len);
+           continue;
+       }
+       cellnum = tcell->cellNum;
+       afs_PutCell(tcell, READ_LOCK);
+
+       /* Find the appropriate unixuser.  This might be the same as
+        * the one we were passed (au), but that's OK.
+        */
+       tu = afs_GetUser(np->pag, cellnum, WRITE_LOCK);
+       if (!(tu->exporter)) {  /* Created new unixuser struct */
+           np->refCount++;             /* so it won't disappear */
+           tu->exporter = (struct afs_exporter *)np;
+       }
+
+       /* free any old secret token, and keep the new one */
+       if (tu->stp != NULL) {
+           afs_osi_Free(tu->stp, tu->stLen);
+       }
+       tu->stp = tcred->st.st_val;
+       tu->stLen = tcred->st.st_len;
+
+       /* copy the clear token */
+       memset(&tu->ct, 0, sizeof(tu->ct));
+       memcpy(tu->ct.HandShakeKey, tcred->ct.HandShakeKey, 8);
+       memset(tcred->ct.HandShakeKey, 0, 8);
+       tu->ct.AuthHandle     = tcred->ct.AuthHandle;
+       tu->ct.ViceId         = tcred->ct.ViceId;
+       tu->ct.BeginTimestamp = tcred->ct.BeginTimestamp;
+       tu->ct.EndTimestamp   = tcred->ct.EndTimestamp;
+
+       /* Set everything else, reset connections, and move on. */
+       tu->vid = tcred->vid;
+       tu->states |= UHasTokens;
+       tu->states &= ~UTokensBad;
+       afs_SetPrimary(tu, !!(tcred->states & UPrimary));
+       tu->tokenTime = osi_Time();
+       afs_ResetUserConns(tu);
+       afs_PutUser(tu, WRITE_LOCK);
+    }
+    afs_osi_Free(tcreds.CredInfos_val, tcreds.CredInfos_len * sizeof(CredInfo));
+
+done:
+    AFS_GUNLOCK();
+    rx_DestroyConnection(tconn);
+    AFS_GLOCK();
+    au->states &= ~UNFSGetCreds;
+    afs_osi_Wakeup((void *)au);
+}
+
 
 /* It's called whenever a new unixuser structure is created for the remote user associated with the nfsclientpag structure, np */
-int
+void
 afs_nfsclient_hold(np)
      register struct nfsclientpag *np;
 {
@@ -296,17 +433,51 @@ afs_nfsclient_hold(np)
 }
 
 
+/* check if this exporter corresponds to the specified host */
+int
+afs_nfsclient_checkhost(np, host)
+    register struct nfsclientpag *np;
+{
+    if (np->type != EXP_NFS)
+       return 0;
+    return np->host == host;
+}
+
+
+/* get the host for this exporter, or 0 if there is an error */
+afs_int32
+afs_nfsclient_gethost(np)
+    register struct nfsclientpag *np;
+{
+    if (np->type != EXP_NFS)
+       return 0;
+    return np->host;
+}
+
+
 /* if inname is non-null, a new system name value is set for the remote user (inname contains the new sysname). In all cases, outname returns the current sysname value for this remote user */
 int 
 afs_nfsclient_sysname(register struct nfsclientpag *np, char *inname, 
-                     char **outname[], int *num)
+                     char ***outname, int *num, int allpags)
 {
+    register struct nfsclientpag *tnp;
+    register afs_int32 i;
     char *cp;
     int count, t;
 #if defined(AFS_SGIMP_ENV)
     osi_Assert(ISAFS_GLOCK());
 #endif
     AFS_STATCNT(afs_nfsclient_sysname);
+    if (allpags > 0) {
+       /* update every client, not just the one making the request */
+       i = NHash(np->host);
+       MObtainWriteLock(&afs_xnfspag, 315);
+       for (tnp = afs_nfspags[i]; tnp; tnp = tnp->next) {
+           if (tnp != np && tnp->host == np->host)
+               afs_nfsclient_sysname(tnp, inname, outname, num, -1);
+       }
+       MReleaseWriteLock(&afs_xnfspag);
+    }
     if (inname) {
        if (np->sysname) {
            for(count=0; count < np->sysnamecount;++count) {
@@ -323,17 +494,20 @@ afs_nfsclient_sysname(register struct nfsclientpag *np, char *inname,
            cp += t+1;
        }
        np->sysnamecount = *num;
-    } else if (!np->sysname) {
+    } else if (!np->sysnamecount) {
        return ENODEV;      /* XXX */
     }
-    *outname = np->sysname;
-    *num = np->sysnamecount;
+    if (allpags >= 0) {
+       /* Don't touch our arguments when called recursively */
+       *outname = np->sysname;
+       *num = np->sysnamecount;
+    }
     return 0;
 }
 
 
 /* Garbage collect routine for the nfs exporter. When pag is -1 then all entries are removed (used by the nfsclient_shutdown routine); else if it's non zero then only the entry with that pag is removed, else all "timedout" entries are removed. TimedOut entries are those who have no "unixuser" structures associated with them (i.e. unixusercnt == 0) and they haven't had any activity the last NFSCLIENTGC seconds */
-int
+void
 afs_nfsclient_GC(exporter, pag)
      register struct afs_exporter *exporter;
      register afs_int32 pag;
@@ -457,6 +631,7 @@ afs_iauth_unregister()
 
 
 
+void
 shutdown_nfsclnt()
 {
 #if defined(AFS_SGIMP_ENV)
index 4fb69da..e962fb9 100644 (file)
@@ -20,18 +20,14 @@ RCSID
 #include <sys/adspace.h>       /* for vm_att(), vm_det() */
 #endif
 
-static char memZero;           /* address of 0 bytes for kmem_alloc */
-
-struct osimem {
-    struct osimem *next;
-};
-
 /* osi_Init -- do once per kernel installation initialization.
  *     -- On Solaris this is called from modload initialization.
  *     -- On AIX called from afs_config.
  *     -- On HP called from afsc_link.
  *     -- On SGI called from afs_init. */
 
+afs_lock_t afs_ftf;            /* flush text lock */
+
 #ifdef AFS_SGI53_ENV
 lock_t afs_event_lock;
 #endif
@@ -42,6 +38,43 @@ flid_t osi_flid;
 
 struct AFS_UCRED *afs_osi_credp;
 
+#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
+kmutex_t afs_global_lock;
+kmutex_t afs_rxglobal_lock;
+#endif
+
+#if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
+long afs_global_owner;
+#endif
+
+#if defined(AFS_OSF_ENV)
+simple_lock_data_t afs_global_lock;
+#endif
+
+#if defined(AFS_DARWIN_ENV) 
+#ifdef AFS_DARWIN80_ENV
+lck_mtx_t  *afs_global_lock;
+#else
+struct lock__bsd__ afs_global_lock;
+#endif
+#endif
+
+#if defined(AFS_XBSD_ENV) && !defined(AFS_FBSD50_ENV)
+struct lock afs_global_lock;
+struct proc *afs_global_owner;
+#endif
+#ifdef AFS_FBSD50_ENV
+struct mtx afs_global_mtx;
+#endif
+
+#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
+thread_t afs_global_owner;
+#endif /* AFS_OSF_ENV */
+
+#if defined(AFS_AIX41_ENV)
+simple_lock_data afs_global_lock;
+#endif
+
 void
 osi_Init(void)
 {
@@ -105,142 +138,6 @@ osi_Init(void)
     init_et_to_sys_error();
 }
 
-int
-osi_Active(register struct vcache *avc)
-{
-    AFS_STATCNT(osi_Active);
-#if defined(AFS_AIX_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || (AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-    if ((avc->opens > 0) || (avc->states & CMAPPED))
-       return 1;               /* XXX: Warning, verify this XXX  */
-#elif defined(AFS_SGI_ENV)
-    if ((avc->opens > 0) || AFS_VN_MAPPED(AFSTOV(avc)))
-       return 1;
-#else
-    if (avc->opens > 0 || (AFSTOV(avc)->v_flag & VTEXT))
-       return (1);
-#endif
-    return 0;
-}
-
-/* this call, unlike osi_FlushText, is supposed to discard caches that may
-   contain invalid information if a file is written remotely, but that may
-   contain valid information that needs to be written back if the file is
-   being written locally.  It doesn't subsume osi_FlushText, since the latter
-   function may be needed to flush caches that are invalidated by local writes.
-
-   avc->pvnLock is already held, avc->lock is guaranteed not to be held (by
-   us, of course).
-*/
-void
-osi_FlushPages(register struct vcache *avc, struct AFS_UCRED *credp)
-{
-    afs_hyper_t origDV;
-    ObtainReadLock(&avc->lock);
-    /* If we've already purged this version, or if we're the ones
-     * writing this version, don't flush it (could lose the
-     * data we're writing). */
-    if ((hcmp((avc->m.DataVersion), (avc->mapDV)) <= 0)
-       || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
-       ReleaseReadLock(&avc->lock);
-       return;
-    }
-    ReleaseReadLock(&avc->lock);
-    ObtainWriteLock(&avc->lock, 10);
-    /* Check again */
-    if ((hcmp((avc->m.DataVersion), (avc->mapDV)) <= 0)
-       || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
-       ReleaseWriteLock(&avc->lock);
-       return;
-    }
-    if (hiszero(avc->mapDV)) {
-       hset(avc->mapDV, avc->m.DataVersion);
-       ReleaseWriteLock(&avc->lock);
-       return;
-    }
-
-    AFS_STATCNT(osi_FlushPages);
-    hset(origDV, avc->m.DataVersion);
-    afs_Trace3(afs_iclSetp, CM_TRACE_FLUSHPAGES, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_INT32, origDV.low, ICL_TYPE_INT32, avc->m.Length);
-
-    ReleaseWriteLock(&avc->lock);
-    AFS_GUNLOCK();
-    osi_VM_FlushPages(avc, credp);
-    AFS_GLOCK();
-    ObtainWriteLock(&avc->lock, 88);
-
-    /* do this last, and to original version, since stores may occur
-     * while executing above PUTPAGE call */
-    hset(avc->mapDV, origDV);
-    ReleaseWriteLock(&avc->lock);
-}
-
-afs_lock_t afs_ftf;            /* flush text lock */
-
-#ifdef AFS_TEXT_ENV
-
-/* This call is supposed to flush all caches that might be invalidated
- * by either a local write operation or a write operation done on
- * another client.  This call may be called repeatedly on the same
- * version of a file, even while a file is being written, so it
- * shouldn't do anything that would discard newly written data before
- * it is written to the file system. */
-
-void
-osi_FlushText_really(register struct vcache *vp)
-{
-    afs_hyper_t fdv;           /* version before which we'll flush */
-
-    AFS_STATCNT(osi_FlushText);
-    /* see if we've already flushed this data version */
-    if (hcmp(vp->m.DataVersion, vp->flushDV) <= 0)
-       return;
-
-    MObtainWriteLock(&afs_ftf, 317);
-    hset(fdv, vp->m.DataVersion);
-
-    /* why this disgusting code below?
-     *    xuntext, called by xrele, doesn't notice when it is called
-     * with a freed text object.  Sun continually calls xrele or xuntext
-     * without any locking, as long as VTEXT is set on the
-     * corresponding vnode.
-     *    But, if the text object is locked when you check the VTEXT
-     * flag, several processes can wait in xuntext, waiting for the
-     * text lock; when the second one finally enters xuntext's
-     * critical region, the text object is already free, but the check
-     * was already done by xuntext's caller.
-     *    Even worse, it turns out that xalloc locks the text object
-     * before reading or stating a file via the vnode layer.  Thus, we
-     * could end up in getdcache, being asked to bring in a new
-     * version of a file, but the corresponding text object could be
-     * locked.  We can't flush the text object without causing
-     * deadlock, so now we just don't try to lock the text object
-     * unless it is guaranteed to work.  And we try to flush the text
-     * when we need to a bit more often at the vnode layer.  Sun
-     * really blew the vm-cache flushing interface.
-     */
-
-#if defined (AFS_HPUX_ENV)
-    if (vp->v.v_flag & VTEXT) {
-       xrele(vp);
-
-       if (vp->v.v_flag & VTEXT) {     /* still has a text object? */
-           MReleaseWriteLock(&afs_ftf);
-           return;
-       }
-    }
-#endif
-
-    /* next do the stuff that need not check for deadlock problems */
-    mpurge(vp);
-
-    /* finally, record that we've done it */
-    hset(vp->flushDV, fdv);
-    MReleaseWriteLock(&afs_ftf);
-
-}
-#endif /* AFS_TEXT_ENV */
-
 /* mask signals in afsds */
 void
 afs_osi_MaskSignals(void)
@@ -389,187 +286,6 @@ afs_osi_SetTime(osi_timeval_t * atv)
 #endif /* AFS_LINUX20_ENV */
 
 
-void *
-afs_osi_Alloc(size_t x)
-{
-#if !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
-    register struct osimem *tm = NULL;
-    register int size;
-#endif
-
-    AFS_STATCNT(osi_Alloc);
-    /* 0-length allocs may return NULL ptr from AFS_KALLOC, so we special-case
-     * things so that NULL returned iff an error occurred */
-    if (x == 0)
-       return &memZero;
-
-    AFS_STATS(afs_stats_cmperf.OutStandingAllocs++);
-    AFS_STATS(afs_stats_cmperf.OutStandingMemUsage += x);
-#ifdef AFS_LINUX20_ENV
-    return osi_linux_alloc(x, 1);
-#elif defined(AFS_FBSD_ENV)
-    return osi_fbsd_alloc(x, 1);
-#else
-    size = x;
-    tm = (struct osimem *)AFS_KALLOC(size);
-#ifdef AFS_SUN5_ENV
-    if (!tm)
-       osi_Panic("osi_Alloc: Couldn't allocate %d bytes; out of memory!\n",
-                 size);
-#endif
-    return (void *)tm;
-#endif
-}
-
-#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
-
-void *
-afs_osi_Alloc_NoSleep(size_t x)
-{
-    register struct osimem *tm;
-    register int size;
-
-    AFS_STATCNT(osi_Alloc);
-    /* 0-length allocs may return NULL ptr from AFS_KALLOC, so we special-case
-     * things so that NULL returned iff an error occurred */
-    if (x == 0)
-       return &memZero;
-
-    size = x;
-    AFS_STATS(afs_stats_cmperf.OutStandingAllocs++);
-    AFS_STATS(afs_stats_cmperf.OutStandingMemUsage += x);
-    tm = (struct osimem *)AFS_KALLOC_NOSLEEP(size);
-    return (void *)tm;
-}
-
-#endif /* SUN || SGI */
-
-void
-afs_osi_Free(void *x, size_t asize)
-{
-    AFS_STATCNT(osi_Free);
-    if (x == &memZero)
-       return;                 /* check for putting memZero back */
-
-    AFS_STATS(afs_stats_cmperf.OutStandingAllocs--);
-    AFS_STATS(afs_stats_cmperf.OutStandingMemUsage -= asize);
-#if defined(AFS_LINUX20_ENV)
-    osi_linux_free(x);
-#elif defined(AFS_FBSD_ENV)
-    osi_fbsd_free(x);
-#else
-    AFS_KFREE((struct osimem *)x, asize);
-#endif
-}
-
-void
-afs_osi_FreeStr(char *x)
-{
-    afs_osi_Free(x, strlen(x) + 1);
-}
-
-/* ? is it moderately likely that there are dirty VM pages associated with
- * this vnode?
- *
- *  Prereqs:  avc must be write-locked
- *
- *  System Dependencies:  - *must* support each type of system for which
- *                          memory mapped files are supported, even if all
- *                          it does is return TRUE;
- *
- * NB:  this routine should err on the side of caution for ProcessFS to work
- *      correctly (or at least, not to introduce worse bugs than already exist)
- */
-#ifdef notdef
-int
-osi_VMDirty_p(struct vcache *avc)
-{
-    int dirtyPages;
-
-    if (avc->execsOrWriters <= 0)
-       return 0;               /* can't be many dirty pages here, I guess */
-
-#if defined (AFS_AIX32_ENV)
-#ifdef notdef
-    /* because of the level of hardware involvment with VM and all the
-     * warnings about "This routine must be called at VMM interrupt
-     * level", I thought it would be safest to disable interrupts while
-     * looking at the software page fault table.  */
-
-    /* convert vm handle into index into array:  I think that stoinio is
-     * always zero...  Look into this XXX  */
-#define VMHASH(handle) ( \
-                       ( ((handle) & ~vmker.stoinio)  \
-                        ^ ((((handle) & ~vmker.stoinio) & vmker.stoimask) << vmker.stoihash) \
-                        ) & 0x000fffff)
-
-    if (avc->segid) {
-       unsigned int pagef, pri, index, next;
-
-       index = VMHASH(avc->segid);
-       if (scb_valid(index)) { /* could almost be an ASSERT */
-
-           pri = disable_ints();
-           for (pagef = scb_sidlist(index); pagef >= 0; pagef = next) {
-               next = pft_sidfwd(pagef);
-               if (pft_modbit(pagef)) {        /* has page frame been modified? */
-                   enable_ints(pri);
-                   return 1;
-               }
-           }
-           enable_ints(pri);
-       }
-    }
-#undef VMHASH
-#endif
-#endif /* AFS_AIX32_ENV */
-
-#if defined (AFS_SUN5_ENV)
-    if (avc->states & CMAPPED) {
-       struct page *pg;
-       for (pg = avc->v.v_s.v_Pages; pg; pg = pg->p_vpnext) {
-           if (pg->p_mod) {
-               return 1;
-           }
-       }
-    }
-#endif
-    return 0;
-}
-#endif /* notdef */
-
-
-/*
- * Solaris osi_ReleaseVM should not drop and re-obtain the vcache entry lock.
- * This leads to bad races when osi_ReleaseVM() is called from
- * afs_InvalidateAllSegments().
-
- * We can do this because Solaris osi_VM_Truncate() doesn't care whether the
- * vcache entry lock is held or not.
- *
- * For other platforms, in some cases osi_VM_Truncate() doesn't care, but
- * there may be cases where it does care.  If so, it would be good to fix
- * them so they don't care.  Until then, we assume the worst.
- *
- * Locking:  the vcache entry lock is held.  It is dropped and re-obtained.
- */
-void
-osi_ReleaseVM(struct vcache *avc, struct AFS_UCRED *acred)
-{
-#ifdef AFS_SUN5_ENV
-    AFS_GUNLOCK();
-    osi_VM_Truncate(avc, 0, acred);
-    AFS_GLOCK();
-#else
-    ReleaseWriteLock(&avc->lock);
-    AFS_GUNLOCK();
-    osi_VM_Truncate(avc, 0, acred);
-    AFS_GLOCK();
-    ObtainWriteLock(&avc->lock, 80);
-#endif
-}
-
-
 void
 shutdown_osi(void)
 {
@@ -598,504 +314,3 @@ afs_osi_suser(void *credp)
 #endif
 }
 #endif
-
-#if AFS_GCPAGS
-
-/* afs_osi_TraverseProcTable() - Walk through the systems process
- * table, calling afs_GCPAGs_perproc_func() for each process.
- */
-
-#if defined(AFS_SUN5_ENV)
-void
-afs_osi_TraverseProcTable(void)
-{
-    struct proc *prp;
-    for (prp = practive; prp != NULL; prp = prp->p_next) {
-       afs_GCPAGs_perproc_func(prp);
-    }
-}
-#endif
-
-#if defined(AFS_HPUX_ENV)
-
-/*
- * NOTE: h/proc_private.h gives the process table locking rules
- * It indicates that access to p_cred must be protected by
- * mp_mtproc_lock(p);
- * mp_mtproc_unlock(p);
- *
- * The code in sys/pm_prot.c uses pcred_lock() to protect access to
- * the process creds, and uses mp_mtproc_lock() only for audit-related
- * changes.  To be safe, we use both.
- */
-
-void
-afs_osi_TraverseProcTable(void)
-{
-    register proc_t *p;
-    int endchain = 0;
-
-    MP_SPINLOCK(activeproc_lock);
-    MP_SPINLOCK(sched_lock);
-    pcred_lock();
-
-    /*
-     * Instead of iterating through all of proc[], traverse only
-     * the list of active processes.  As an example of this,
-     * see foreach_process() in sys/vm_sched.c.
-     *
-     * We hold the locks for the entire scan in order to get a
-     * consistent view of the current set of creds.
-     */
-
-    for (p = proc; endchain == 0; p = &proc[p->p_fandx]) {
-       if (p->p_fandx == 0) {
-           endchain = 1;
-       }
-
-       if (system_proc(p))
-           continue;
-
-       mp_mtproc_lock(p);
-       afs_GCPAGs_perproc_func(p);
-       mp_mtproc_unlock(p);
-    }
-
-    pcred_unlock();
-    MP_SPINUNLOCK(sched_lock);
-    MP_SPINUNLOCK(activeproc_lock);
-}
-#endif
-
-#if defined(AFS_SGI_ENV)
-
-#ifdef AFS_SGI65_ENV
-/* TODO: Fix this later. */
-static int
-SGI_ProcScanFunc(void *p, void *arg, int mode)
-{
-    return 0;
-}
-#else /* AFS_SGI65_ENV */
-static int
-SGI_ProcScanFunc(proc_t * p, void *arg, int mode)
-{
-    afs_int32(*perproc_func) (struct proc *) = arg;
-    int code = 0;
-    /* we pass in the function pointer for arg,
-     * mode ==0 for startup call, ==1 for each valid proc,
-     * and ==2 for terminate call.
-     */
-    if (mode == 1) {
-       code = perproc_func(p);
-    }
-    return code;
-}
-#endif /* AFS_SGI65_ENV */
-
-void
-afs_osi_TraverseProcTable(void)
-{
-    procscan(SGI_ProcScanFunc, afs_GCPAGs_perproc_func);
-}
-#endif /* AFS_SGI_ENV */
-
-#if defined(AFS_AIX_ENV)
-#ifdef AFS_AIX51_ENV
-#define max_proc v.ve_proc
-#endif
-void
-afs_osi_TraverseProcTable(void)
-{
-    struct proc *p;
-    int i;
-
-    /*
-     * For binary compatibility, on AIX we need to be careful to use the
-     * proper size of a struct proc, even if it is different from what
-     * we were compiled with.
-     */
-    if (!afs_gcpags_procsize)
-       return;
-
-#ifndef AFS_AIX51_ENV
-    simple_lock(&proc_tbl_lock);
-#endif
-    for (p = (struct proc *)v.vb_proc, i = 0; p < max_proc;
-        p = (struct proc *)((char *)p + afs_gcpags_procsize), i++) {
-
-#ifdef AFS_AIX51_ENV
-       if (p->p_pvprocp->pv_stat == SNONE)
-           continue;
-       if (p->p_pvprocp->pv_stat == SIDL)
-           continue;
-       if (p->p_pvprocp->pv_stat == SEXIT)
-           continue;
-#else
-       if (p->p_stat == SNONE)
-           continue;
-       if (p->p_stat == SIDL)
-           continue;
-       if (p->p_stat == SEXIT)
-           continue;
-#endif
-
-       /* sanity check */
-
-       if (PROCMASK(p->p_pid) != i) {
-           afs_gcpags = AFS_GCPAGS_EPIDCHECK;
-           break;
-       }
-
-       /* sanity check */
-
-       if ((p->p_nice < P_NICE_MIN) || (P_NICE_MAX < p->p_nice)) {
-           afs_gcpags = AFS_GCPAGS_ENICECHECK;
-           break;
-       }
-
-       afs_GCPAGs_perproc_func(p);
-    }
-#ifndef AFS_AIX51_ENV
-    simple_unlock(&proc_tbl_lock);
-#endif
-}
-#endif
-
-#if defined(AFS_OSF_ENV)
-
-#ifdef AFS_DUX50_ENV
-extern struct pid_entry *pidtab;
-extern int npid; 
-#endif
-
-void
-afs_osi_TraverseProcTable(void)
-{
-    struct pid_entry *pe;
-#ifdef AFS_DUX50_ENV
-#define pidNPID (pidtab + npid)
-#define PID_LOCK()
-#define PID_UNLOCK()
-#endif
-    PID_LOCK();
-    for (pe = pidtab; pe < pidNPID; ++pe) {
-       if (pe->pe_proc != PROC_NULL)
-           afs_GCPAGs_perproc_func(pe->pe_proc);
-    }
-    PID_UNLOCK();
-}
-#endif
-
-#if (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)) || defined(AFS_FBSD_ENV)
-void
-afs_osi_TraverseProcTable(void)
-{
-    struct proc *p;
-    LIST_FOREACH(p, &allproc, p_list) {
-       if (p->p_stat == SIDL)
-           continue;
-       if (p->p_stat == SZOMB)
-           continue;
-       if (p->p_flag & P_SYSTEM)
-           continue;
-       afs_GCPAGs_perproc_func(p);
-    }
-}
-#endif
-
-#if defined(AFS_LINUX22_ENV)
-extern rwlock_t tasklist_lock __attribute__((weak));
-void
-afs_osi_TraverseProcTable()
-{
-    struct task_struct *p;
-    if (&tasklist_lock)
-       read_lock(&tasklist_lock);
-#ifdef DEFINED_FOR_EACH_PROCESS
-    for_each_process(p) if (p->pid) {
-#ifdef STRUCT_TASK_STRUCT_HAS_EXIT_STATE
-       if (p->exit_state)
-           continue;
-#else
-       if (p->state & TASK_ZOMBIE)
-           continue;
-#endif
-       afs_GCPAGs_perproc_func(p);
-    }
-#else
-    for_each_task(p) if (p->pid) {
-#ifdef STRUCT_TASK_STRUCT_HAS_EXIT_STATE
-       if (p->exit_state)
-           continue;
-#else
-       if (p->state & TASK_ZOMBIE)
-           continue;
-#endif
-       afs_GCPAGs_perproc_func(p);
-    }
-#endif
-    if (&tasklist_lock)
-       read_unlock(&tasklist_lock);
-}
-#endif
-
-/* return a pointer (sometimes a static copy ) to the cred for a
- * given AFS_PROC.
- * subsequent calls may overwrite the previously returned value.
- */
-
-#if defined(AFS_SGI65_ENV)
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * p)
-{
-    return NULL;
-}
-#elif defined(AFS_HPUX_ENV)
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * p)
-{
-    if (!p)
-       return;
-
-    /*
-     * Cannot use afs_warnuser() here, as the code path
-     * eventually wants to grab sched_lock, which is
-     * already held here
-     */
-
-    return p_cred(p);
-}
-#elif defined(AFS_AIX_ENV)
-
-/* GLOBAL DECLARATIONS */
-
-/*
- * LOCKS: the caller must do
- *  simple_lock(&proc_tbl_lock);
- *  simple_unlock(&proc_tbl_lock);
- * around calls to this function.
- */
-
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * pproc)
-{
-    struct AFS_UCRED *pcred = 0;
-
-    /*
-     * pointer to process user structure valid in *our*
-     * address space
-     *
-     * The user structure for a process is stored in the user
-     * address space (as distinct from the kernel address
-     * space), and so to refer to the user structure of a
-     * different process we must employ special measures.
-     *
-     * I followed the example used in the AIX getproc() system
-     * call in bos/kernel/proc/getproc.c
-     */
-    struct user *xmem_userp;
-
-    struct xmem dp;            /* ptr to xmem descriptor */
-    int xm;                    /* xmem result */
-
-    if (!pproc) {
-       return pcred;
-    }
-
-    /*
-     * The process private segment in which the user
-     * area is located may disappear. We need to increment
-     * its use count. Therefore we
-     *    - get the proc_tbl_lock to hold the segment.
-     *    - get the p_lock to lockout vm_cleardata.
-     *    - vm_att to load the segment register (no check)
-     *    - xmattach to bump its use count.
-     *    - release the p_lock.
-     *    - release the proc_tbl_lock.
-     *    - do whatever we need.
-     *    - xmdetach to decrement the use count.
-     *    - vm_det to free the segment register (no check)
-     */
-
-    xmem_userp = NULL;
-    xm = XMEM_FAIL;
-    /* simple_lock(&proc_tbl_lock); */
-#ifdef __64BIT__
-    if (pproc->p_adspace != vm_handle(NULLSEGID, (int32long64_t) 0)) {
-#else
-    if (pproc->p_adspace != NULLSEGVAL) {
-#endif
-
-#ifdef AFS_AIX51_ENV
-       simple_lock(&pproc->p_pvprocp->pv_lock);
-#else
-       simple_lock(&pproc->p_lock);
-#endif
-
-       if (pproc->p_threadcount &&
-#ifdef AFS_AIX51_ENV
-           pproc->p_pvprocp->pv_threadlist) {
-#else
-           pproc->p_threadlist) {
-#endif
-
-           /*
-            * arbitrarily pick the first thread in pproc
-            */
-           struct thread *pproc_thread =
-#ifdef AFS_AIX51_ENV
-               pproc->p_pvprocp->pv_threadlist;
-#else
-               pproc->p_threadlist;
-#endif
-
-           /*
-            * location of 'struct user' in pproc's
-            * address space
-            */
-           struct user *pproc_userp = pproc_thread->t_userp;
-
-           /*
-            * create a pointer valid in my own address space
-            */
-
-           xmem_userp = (struct user *)vm_att(pproc->p_adspace, pproc_userp);
-
-           dp.aspace_id = XMEM_INVAL;
-           xm = xmattach(xmem_userp, sizeof(*xmem_userp), &dp, SYS_ADSPACE);
-       }
-
-#ifdef AFS_AIX51_ENV
-       simple_unlock(&pproc->p_pvprocp->pv_lock);
-#else
-       simple_unlock(&pproc->p_lock);
-#endif
-    }
-    /* simple_unlock(&proc_tbl_lock); */
-    if (xm == XMEM_SUCC) {
-
-       static struct AFS_UCRED cred;
-
-       /*
-        * What locking should we use to protect access to the user
-        * area?  If needed also change the code in AIX/osi_groups.c.
-        */
-
-       /* copy cred to local address space */
-       cred = *xmem_userp->U_cred;
-       pcred = &cred;
-
-       xmdetach(&dp);
-    }
-    if (xmem_userp) {
-       vm_det((void *)xmem_userp);
-    }
-
-    return pcred;
-}
-
-#elif defined(AFS_OSF_ENV)
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * pr)
-{
-    struct AFS_UCRED *rv = NULL;
-
-    if (pr == NULL) {
-       return NULL;
-    }
-
-    if ((pr->p_stat == SSLEEP) || (pr->p_stat == SRUN)
-       || (pr->p_stat == SSTOP))
-       rv = pr->p_rcred;
-
-    return rv;
-}
-#elif defined(AFS_DARWIN80_ENV) 
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * pr)
-{
-    struct AFS_UCRED *rv = NULL;
-    static struct AFS_UCRED cr;
-    struct ucred *pcred;
-
-    if (pr == NULL) {
-       return NULL;
-    }
-    pcred = proc_ucred(pr);
-    cr.cr_ref = 1;
-    cr.cr_uid = pcred->cr_uid;
-    cr.cr_ngroups = pcred->cr_ngroups;
-    memcpy(cr.cr_groups, pcred->cr_groups,
-           NGROUPS * sizeof(gid_t));
-    return &cr;
-}
-#elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * pr)
-{
-    struct AFS_UCRED *rv = NULL;
-    static struct AFS_UCRED cr;
-
-    if (pr == NULL) {
-       return NULL;
-    }
-
-    if ((pr->p_stat == SSLEEP) || (pr->p_stat == SRUN)
-       || (pr->p_stat == SSTOP)) {
-       pcred_readlock(pr);
-       cr.cr_ref = 1;
-       cr.cr_uid = pr->p_cred->pc_ucred->cr_uid;
-       cr.cr_ngroups = pr->p_cred->pc_ucred->cr_ngroups;
-       memcpy(cr.cr_groups, pr->p_cred->pc_ucred->cr_groups,
-              NGROUPS * sizeof(gid_t));
-       pcred_unlock(pr);
-       rv = &cr;
-    }
-
-    return rv;
-}
-#elif defined(AFS_LINUX22_ENV)
-const struct AFS_UCRED *
-afs_osi_proc2cred(AFS_PROC * pr)
-{
-    struct AFS_UCRED *rv = NULL;
-    static struct AFS_UCRED cr;
-
-    if (pr == NULL) {
-       return NULL;
-    }
-
-    if ((pr->state == TASK_RUNNING) || (pr->state == TASK_INTERRUPTIBLE)
-       || (pr->state == TASK_UNINTERRUPTIBLE)