From 1b22507f223cb58cc9021b495b238cd59f30d151 Mon Sep 17 00:00:00 2001 From: Jeffrey Hutzelman Date: Mon, 31 Jul 2006 22:58:28 +0000 Subject: [PATCH] DEVEL15-linux-afs-translator-xen-20060731 FIXES 36646 add linux afs translator plus xen shared afs client support (cherry picked from commit 29dd7923817b621c5d14920513dc26c2f9fda530) --- src/afs/.cvsignore | 1 + src/afs/LINUX/osi_export.c | 933 ++++++++++++ src/afs/LINUX/osi_file.c | 192 ++- src/afs/LINUX/osi_ioctl.c | 145 ++ src/afs/LINUX/osi_misc.c | 330 ++--- src/afs/LINUX/osi_module.c | 16 +- src/afs/LINUX/osi_nfssrv.c | 251 ++++ src/afs/LINUX/osi_pag_module.c | 130 ++ src/afs/LINUX/osi_proc.c | 343 +++++ src/afs/LINUX/osi_prototypes.h | 28 +- src/afs/LINUX/osi_vfsops.c | 35 + src/afs/LINUX/osi_vnodeops.c | 50 +- src/afs/UKERNEL/afs_usrops.c | 3 +- src/afs/VNOPS/afs_vnop_access.c | 10 + src/afs/VNOPS/afs_vnop_lookup.c | 245 +++- src/afs/VNOPS/afs_vnop_remove.c | 3 + src/afs/VNOPS/afs_vnop_symlink.c | 4 + src/afs/afs.h | 8 + src/afs/afs_analyze.c | 214 --- src/afs/afs_call.c | 2109 +--------------------------- src/afs/afs_cell.c | 24 + src/afs/afs_dcache.c | 22 + src/afs/afs_dynroot.c | 222 ++- src/afs/afs_dynroot.h | 32 + src/afs/afs_error.c | 279 ++++ src/afs/afs_icl.c | 1527 ++++++++++++++++++++ src/afs/afs_init.c | 2 + src/afs/afs_md5.c | 290 ++++ src/afs/afs_md5.h | 76 + src/afs/afs_nfsclnt.c | 227 ++- src/afs/afs_osi.c | 863 +----------- src/afs/afs_osi_alloc.c | 87 ++ src/afs/afs_osi_gcpags.c | 522 +++++++ src/afs/afs_osi_pag.c | 9 + src/afs/afs_osi_vm.c | 256 ++++ src/afs/afs_pag_call.c | 560 ++++++++ src/afs/afs_pag_cred.c | 404 ++++++ src/afs/afs_pioctl.c | 245 ++-- src/afs/afs_prototypes.h | 254 ++-- src/afs/afs_syscall.c | 723 ++++++++++ src/afs/afs_user.c | 14 +- src/afs/afs_vcache.c | 18 +- src/afs/afs_volume.c | 8 +- src/afs/exporter.h | 19 +- src/afs/nfsclient.h | 1 + src/config/param.alpha_linux_26.h | 1 - src/config/param.amd64_linux26.h | 1 - src/config/param.i386_linux26.h | 1 - src/config/param.i386_umlinux26.h | 1 - src/config/param.ia64_linux26.h | 1 - src/config/param.ppc64_linux26.h | 1 - src/config/param.ppc_linux26.h | 1 - src/config/param.s390_linux26.h | 1 - src/config/param.s390x_linux26.h | 1 - src/config/param.sparc64_linux26.h | 1 - src/config/venus.h | 3 + src/fsint/.cvsignore | 5 + src/fsint/Makefile.in | 27 +- src/fsint/pagcb.xg | 58 + src/libafs/Makefile.common.in | 96 ++ src/libafs/MakefileProto.LINUX.in | 29 +- src/libafs/make_kbuild_makefile.pl | 30 +- src/libuafs/Makefile.common.in | 40 + src/sys/.cvsignore | 3 + src/sys/Makefile.in | 16 +- src/sys/rmtsys.xg | 1 + src/venus/fs.c | 70 +- 67 files changed, 8352 insertions(+), 3770 deletions(-) create mode 100644 src/afs/LINUX/osi_export.c create mode 100644 src/afs/LINUX/osi_ioctl.c create mode 100644 src/afs/LINUX/osi_nfssrv.c create mode 100644 src/afs/LINUX/osi_pag_module.c create mode 100644 src/afs/LINUX/osi_proc.c create mode 100644 src/afs/afs_dynroot.h create mode 100644 src/afs/afs_error.c create mode 100644 src/afs/afs_icl.c create mode 100644 src/afs/afs_md5.c create mode 100644 src/afs/afs_md5.h create mode 100644 src/afs/afs_osi_gcpags.c create mode 100644 src/afs/afs_osi_vm.c create mode 100644 src/afs/afs_pag_call.c create mode 100644 src/afs/afs_pag_cred.c create mode 100644 src/afs/afs_syscall.c create mode 100644 src/fsint/pagcb.xg diff --git a/src/afs/.cvsignore b/src/afs/.cvsignore index fb596ce66..286e2d2fd 100644 --- a/src/afs/.cvsignore +++ b/src/afs/.cvsignore @@ -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 index 000000000..5de06a1a9 --- /dev/null +++ b/src/afs/LINUX/osi_export.c @@ -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 +#include "afs/param.h" + +RCSID + ("$Header$"); + +#include /* 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, +}; diff --git a/src/afs/LINUX/osi_file.c b/src/afs/LINUX/osi_file.c index 272d81100..f096416b1 100644 --- a/src/afs/LINUX/osi_file.c +++ b/src/afs/LINUX/osi_file.c @@ -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 index 000000000..364241a2f --- /dev/null +++ b/src/afs/LINUX/osi_ioctl.c @@ -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 +#include "afs/param.h" + +RCSID + ("$Header$"); + +#include /* 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 +#endif +#ifdef AFS_SPARC64_LINUX20_ENV +#include +#endif + +#include +#include +#include +#include +#include + +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 +} diff --git a/src/afs/LINUX/osi_misc.c b/src/afs/LINUX/osi_misc.c index 09b3f2285..79314e792 100644 --- a/src/afs/LINUX/osi_misc.c +++ b/src/afs/LINUX/osi_misc.c @@ -17,6 +17,7 @@ RCSID ("$Header$"); +#include /* 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(¤t->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(¤t->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 diff --git a/src/afs/LINUX/osi_module.c b/src/afs/LINUX/osi_module.c index 29a016fdf..33c33275b 100644 --- a/src/afs/LINUX/osi_module.c +++ b/src/afs/LINUX/osi_module.c @@ -38,10 +38,6 @@ RCSID #include #endif -#ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H -#include -#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 index 000000000..57be4bb74 --- /dev/null +++ b/src/afs/LINUX/osi_nfssrv.c @@ -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 +#include "afs/param.h" + +RCSID + ("$Header$"); + +#include /* early to avoid printf->printk mapping */ +#include "afs/sysincludes.h" +#include "afsincludes.h" +#include "nfsclient.h" +#include "h/smp_lock.h" +#include +#include + +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=\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 index 000000000..7c057770b --- /dev/null +++ b/src/afs/LINUX/osi_pag_module.c @@ -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 +#include "afs/param.h" + +RCSID + ("$Header$"); + +#include /* 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 +#endif +#ifdef AFS_SPARC64_LINUX20_ENV +#include +#endif + +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#include +#include +#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 index 000000000..497d496ff --- /dev/null +++ b/src/afs/LINUX/osi_proc.c @@ -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 +#include "afs/param.h" + +RCSID + ("$Header$"); + +#include /* 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 +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H +#include +#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 = ""; + } else { + tc = afs_GetCellStale(tu->cell, READ_LOCK); + if (tc) cellname = tc->cellName; + else cellname = ""; + } + + 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, " "); + } + + } 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); +} diff --git a/src/afs/LINUX/osi_prototypes.h b/src/afs/LINUX/osi_prototypes.h index bf8b88ca6..7f97c75e8 100644 --- a/src/afs/LINUX/osi_prototypes.h +++ b/src/afs/LINUX/osi_prototypes.h @@ -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); diff --git a/src/afs/LINUX/osi_vfsops.c b/src/afs/LINUX/osi_vfsops.c index e79f2dda8..9513ab59f 100644 --- a/src/afs/LINUX/osi_vfsops.c +++ b/src/afs/LINUX/osi_vfsops.c @@ -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; + } + } +} diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index b88c62d99..a854fdbef 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -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 diff --git a/src/afs/UKERNEL/afs_usrops.c b/src/afs/UKERNEL/afs_usrops.c index 3445ea40e..d39aa9adf 100644 --- a/src/afs/UKERNEL/afs_usrops.c +++ b/src/afs/UKERNEL/afs_usrops.c @@ -971,10 +971,9 @@ shutdown_osifile(void) return; } -int +void afs_nfsclient_init(void) { - return 0; } void diff --git a/src/afs/VNOPS/afs_vnop_access.c b/src/afs/VNOPS/afs_vnop_access.c index e21d757a9..5677a097c 100644 --- a/src/afs/VNOPS/afs_vnop_access.c +++ b/src/afs/VNOPS/afs_vnop_access.c @@ -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 diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index 1b402839c..02955ae70 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -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 ".backup" or ".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. diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index 4fdd6b86a..385e46b01 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -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); diff --git a/src/afs/VNOPS/afs_vnop_symlink.c b/src/afs/VNOPS/afs_vnop_symlink.c index 205e40743..fa5a8f4b9 100644 --- a/src/afs/VNOPS/afs_vnop_symlink.c +++ b/src/afs/VNOPS/afs_vnop_symlink.c @@ -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) { diff --git a/src/afs/afs.h b/src/afs/afs.h index 469025ee4..e22530d80 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -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 diff --git a/src/afs/afs_analyze.c b/src/afs/afs_analyze.c index c0705dc73..e42632124 100644 --- a/src/afs/afs_analyze.c +++ b/src/afs/afs_analyze.c @@ -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) diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 17fa236fb..2156aade6 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -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; -} diff --git a/src/afs/afs_cell.c b/src/afs/afs_cell.c index bebdae1e4..3983a194c 100644 --- a/src/afs/afs_cell.c +++ b/src/afs/afs_cell.c @@ -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 */ @@ -570,6 +571,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) { @@ -656,6 +668,17 @@ afs_GetCellByIndex(afs_int32 index, afs_int32 locktype) return tc; } +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) { @@ -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)) diff --git a/src/afs/afs_dcache.c b/src/afs/afs_dcache.c index f091d96b6..8ca37a696 100644 --- a/src/afs/afs_dcache.c +++ b/src/afs/afs_dcache.c @@ -2243,6 +2243,28 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte, 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 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 diff --git a/src/afs/afs_dynroot.c b/src/afs/afs_dynroot.c index 1d2563ef4..80879c7b4 100644 --- a/src/afs/afs_dynroot.c +++ b/src/afs/afs_dynroot.c @@ -12,8 +12,13 @@ * * Implements: * afs_IsDynrootFid + * afs_IsDynrootMountFid + * afs_IsDynrootAnyFid * afs_GetDynrootFid + * afs_GetDynrootMountFid * afs_IsDynroot + * afs_IsDynrootMount + * afs_IsDynrootAny * afs_DynrootInvalidate * afs_GetDynroot * afs_PutDynroot @@ -37,33 +42,15 @@ #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,17 +753,29 @@ 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. */ diff --git a/src/afs/afs_dynroot.h b/src/afs/afs_dynroot.h new file mode 100644 index 000000000..e23e26b7b --- /dev/null +++ b/src/afs/afs_dynroot.h @@ -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 index 000000000..35c92b5f8 --- /dev/null +++ b/src/afs/afs_error.c @@ -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 +#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 +#include +#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 +#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 +#include +#if defined(AFS_SUN58_ENV) +#include +#endif +#include +#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 index 000000000..40bff4bf0 --- /dev/null +++ b/src/afs/afs_icl.c @@ -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 +#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; +} diff --git a/src/afs/afs_init.c b/src/afs/afs_init.c index b2503aefd..ad6defa59 100644 --- a/src/afs/afs_init.c +++ b/src/afs/afs_init.c @@ -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 index 000000000..928725e15 --- /dev/null +++ b/src/afs/afs_md5.c @@ -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 +#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 + */ + +#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 index 000000000..c26128340 --- /dev/null +++ b/src/afs/afs_md5.h @@ -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 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))); +} diff --git a/src/afs/afs_nfsclnt.c b/src/afs/afs_nfsclnt.c index 5f16f661a..ae676da6f 100644 --- a/src/afs/afs_nfsclnt.c +++ b/src/afs/afs_nfsclnt.c @@ -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) diff --git a/src/afs/afs_osi.c b/src/afs/afs_osi.c index 4fb69dad0..e962fb950 100644 --- a/src/afs/afs_osi.c +++ b/src/afs/afs_osi.c @@ -20,18 +20,14 @@ RCSID #include /* 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) - || (pr->state == TASK_STOPPED)) { - cr.cr_ref = 1; - cr.cr_uid = pr->uid; -#if defined(AFS_LINUX26_ENV) - get_group_info(pr->group_info); - cr.cr_group_info = pr->group_info; -#else - cr.cr_ngroups = pr->ngroups; - memcpy(cr.cr_groups, pr->groups, NGROUPS * sizeof(gid_t)); -#endif - rv = &cr; - } - - return rv; -} -#else -const struct AFS_UCRED * -afs_osi_proc2cred(AFS_PROC * pr) -{ - struct AFS_UCRED *rv = NULL; - - if (pr == NULL) { - return NULL; - } - rv = pr->p_cred; - - return rv; -} -#endif - -#endif /* AFS_GCPAGS */ diff --git a/src/afs/afs_osi_alloc.c b/src/afs/afs_osi_alloc.c index 539bc8bd9..9df230a80 100644 --- a/src/afs/afs_osi_alloc.c +++ b/src/afs/afs_osi_alloc.c @@ -38,6 +38,93 @@ static struct osi_packet { } *freePacketList = NULL, *freeSmallList; afs_lock_t osi_flplock; +static char memZero; /* address of 0 bytes for kmem_alloc */ + +struct osimem { + struct osimem *next; +}; + + +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); +} + + /* free space allocated by AllocLargeSpace. Also called by mclput when freeing * a packet allocated by osi_NetReceive. */ diff --git a/src/afs/afs_osi_gcpags.c b/src/afs/afs_osi_gcpags.c new file mode 100644 index 000000000..3c8cfbb14 --- /dev/null +++ b/src/afs/afs_osi_gcpags.c @@ -0,0 +1,522 @@ +/* + * 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 +#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" /* afs statistics */ +#ifdef AFS_AIX_ENV +#include /* for vm_att(), vm_det() */ +#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) + || (pr->state == TASK_STOPPED)) { + cr.cr_ref = 1; + cr.cr_uid = pr->uid; +#if defined(AFS_LINUX26_ENV) + get_group_info(pr->group_info); + cr.cr_group_info = pr->group_info; +#else + cr.cr_ngroups = pr->ngroups; + memcpy(cr.cr_groups, pr->groups, NGROUPS * sizeof(gid_t)); +#endif + rv = &cr; + } + + return rv; +} +#else +const struct AFS_UCRED * +afs_osi_proc2cred(AFS_PROC * pr) +{ + struct AFS_UCRED *rv = NULL; + + if (pr == NULL) { + return NULL; + } + rv = pr->p_cred; + + return rv; +} +#endif + +#endif /* AFS_GCPAGS */ diff --git a/src/afs/afs_osi_pag.c b/src/afs/afs_osi_pag.c index 8d49baf53..53b47391a 100644 --- a/src/afs/afs_osi_pag.c +++ b/src/afs/afs_osi_pag.c @@ -407,9 +407,18 @@ AddPag(afs_int32 aval, struct AFS_UCRED **credpp) int afs_InitReq(register struct vrequest *av, struct AFS_UCRED *acred) { + int code; + AFS_STATCNT(afs_InitReq); + memset(av, 0, sizeof(*av)); if (afs_shuttingdown) return EIO; + +#ifdef AFS_LINUX26_ENV + if (osi_linux_nfs_initreq(av, acred, &code)) + return code; +#endif + av->uid = PagInCred(acred); if (av->uid == NOPAG) { /* Afs doesn't use the unix uid for anuthing except a handle diff --git a/src/afs/afs_osi_vm.c b/src/afs/afs_osi_vm.c new file mode 100644 index 000000000..4aac5232b --- /dev/null +++ b/src/afs/afs_osi_vm.c @@ -0,0 +1,256 @@ +/* + * 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 +#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" /* afs statistics */ +#ifdef AFS_AIX_ENV +#include /* for vm_att(), vm_det() */ +#endif + +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); +} + +#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 */ + +/* ? 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 +} diff --git a/src/afs/afs_pag_call.c b/src/afs/afs_pag_call.c new file mode 100644 index 000000000..3f7b047ac --- /dev/null +++ b/src/afs/afs_pag_call.c @@ -0,0 +1,560 @@ +/* + * 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 +#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 +#include "rmtsys.h" +#include "pagcb.h" + + +afs_int32 afs_termState = 0; +afs_int32 afs_gcpags = AFS_GCPAGS; +int afs_shuttingdown = 0; +int afs_cold_shutdown = 0; +int afs_resourceinit_flag = 0; +afs_int32 afs_nfs_server_addr; +struct interfaceAddr afs_cb_interface; +struct afs_osi_WaitHandle AFS_WaitHandler; +static struct rx_securityClass *srv_secobj; +static struct rx_securityClass *clt_secobj; +static struct rx_service *stats_svc; +static struct rx_service *pagcb_svc; +static struct rx_connection *rmtsys_conn; +char *afs_sysname = 0; +char *afs_sysnamelist[MAXNUMSYSNAMES]; +int afs_sysnamecount = 0; +int afs_sysnamegen = 0; + + +void afs_Daemon(void) +{ + afs_int32 now, last10MinCheck, last60MinCheck; + + last10MinCheck = 0; + last60MinCheck = 0; + while (1) { + rx_CheckPackets(); + now = osi_Time(); + + if (last10MinCheck + 600 < now) { + afs_GCUserData(0); + } + + if (last60MinCheck + 3600 < now) { + afs_int32 didany; + afs_GCPAGs(&didany); + } + + now = 20000 - (osi_Time() - now); + afs_osi_Wait(now, &AFS_WaitHandler, 0); + + if (afs_termState == AFSOP_STOP_AFS) { +#if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV) + afs_termState = AFSOP_STOP_RXEVENT; +#else + afs_termState = AFSOP_STOP_COMPLETE; +#endif + afs_osi_Wakeup(&afs_termState); + return; + } + } +} + + +void afspag_Init(afs_int32 nfs_server_addr) +{ + struct clientcred ccred; + struct rmtbulk idata, odata; + afs_int32 code, err, addr, obuf; + int i; + + afs_uuid_create(&afs_cb_interface.uuid); + + AFS_GLOCK(); + + afs_InitStats(); + rx_Init(htons(7001)); + + AFS_STATCNT(afs_ResourceInit); + RWLOCK_INIT(&afs_xuser, "afs_xuser"); + RWLOCK_INIT(&afs_xpagcell, "afs_xpagcell"); + RWLOCK_INIT(&afs_xpagsys, "afs_xpagsys"); + RWLOCK_INIT(&afs_icl_lock, "afs_icl_lock"); +#ifndef AFS_FBSD_ENV + LOCK_INIT(&osi_fsplock, "osi_fsplock"); + LOCK_INIT(&osi_flplock, "osi_flplock"); +#endif + + afs_resourceinit_flag = 1; + afs_nfs_server_addr = nfs_server_addr; + for (i = 0; i < MAXNUMSYSNAMES; i++) + afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME); + afs_sysname = afs_sysnamelist[0]; + strcpy(afs_sysname, SYS_NAME); + afs_sysnamecount = 1; + afs_sysnamegen++; + + srv_secobj = rxnull_NewServerSecurityObject(); + stats_svc = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", &srv_secobj, + 1, RXSTATS_ExecuteRequest); + pagcb_svc = rx_NewService(0, PAGCB_SERVICEID, "pagcb", &srv_secobj, + 1, PAGCB_ExecuteRequest); + rx_StartServer(0); + + clt_secobj = rxnull_NewClientSecurityObject(); + rmtsys_conn = rx_NewConnection(nfs_server_addr, htons(7009), + RMTSYS_SERVICEID, clt_secobj, 0); + +#ifdef RXK_LISTENER_ENV + afs_start_thread(rxk_Listener, "Rx Listener"); +#endif + afs_start_thread(rx_ServerProc, "Rx Server Thread"); + afs_start_thread(afs_rxevent_daemon, "Rx Event Daemon"); + afs_start_thread(afs_Daemon, "AFS PAG Daemon"); + + afs_icl_InitLogs(); + + AFS_GUNLOCK(); + + /* If it's reachable, tell the translator to nuke our creds. + * We should be more agressive about making sure this gets done, + * even if the translator is unreachable when we boot. + */ + addr = obuf = err = 0; + idata.rmtbulk_len = sizeof(addr); + idata.rmtbulk_val = (char *)&addr; + odata.rmtbulk_len = sizeof(obuf); + odata.rmtbulk_val = (char *)&obuf; + memset(&ccred, 0, sizeof(ccred)); + code = RMTSYS_Pioctl(rmtsys_conn, &ccred, NIL_PATHP, 0x4F01, 0, + &idata, &odata, &err); +} /*afs_ResourceInit */ + + +/* called with the GLOCK held */ +void afspag_Shutdown(void) +{ + if (afs_shuttingdown) + return; + afs_shuttingdown = 1; + afs_termState = AFSOP_STOP_RXCALLBACK; + rx_WakeupServerProcs(); + while (afs_termState == AFSOP_STOP_RXCALLBACK) + afs_osi_Sleep(&afs_termState); + /* rx_ServerProc sets AFS_STOP_AFS */ + + while (afs_termState == AFSOP_STOP_AFS) { + afs_osi_CancelWait(&AFS_WaitHandler); + afs_osi_Sleep(&afs_termState); + } + /* afs_Daemon sets AFS_STOP_RXEVENT */ + +#if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV) + while (afs_termState == AFSOP_STOP_RXEVENT) + afs_osi_Sleep(&afs_termState); + /* afs_rxevent_daemon sets AFSOP_STOP_RXK_LISTENER */ + +#if defined(RXK_LISTENER_ENV) + afs_osi_UnmaskRxkSignals(); + osi_StopListener(); + while (afs_termState == AFSOP_STOP_RXK_LISTENER) + afs_osi_Sleep(&afs_termState); + /* rxk_Listener sets AFSOP_STOP_COMPLETE */ +#endif +#endif +} + +static void token_conversion(char *buffer, int buf_size, int in) +{ + struct ClearToken *ticket; + afs_int32 *lptr, n; + + /* secret ticket */ + if (buf_size < 4) return; + lptr = (afs_int32 *)buffer; + buffer += 4; buf_size -= 4; + if (in) { + *lptr = ntohl(*lptr); + n = *lptr; + } else { + n = *lptr; + *lptr = htonl(*lptr); + } + if (n < 0 || buf_size < n) return; + buffer += n; buf_size -= n; + + /* clear token */ + if (buf_size < 4) return; + lptr = (afs_int32 *)buffer; + buffer += 4; buf_size -= 4; + if (in) { + *lptr = ntohl(*lptr); + n = *lptr; + } else { + n = *lptr; + *lptr = htonl(*lptr); + } + if (n < 0 || buf_size < n) return; + if (n >= sizeof(struct ClearToken)) { + ticket = (struct ClearToken *)buffer; + if (in) { + ticket->AuthHandle = ntohl(ticket->AuthHandle); + ticket->ViceId = ntohl(ticket->ViceId); + ticket->BeginTimestamp = ntohl(ticket->BeginTimestamp); + ticket->EndTimestamp = ntohl(ticket->EndTimestamp); + } else { + ticket->AuthHandle = htonl(ticket->AuthHandle); + ticket->ViceId = htonl(ticket->ViceId); + ticket->BeginTimestamp = htonl(ticket->BeginTimestamp); + ticket->EndTimestamp = htonl(ticket->EndTimestamp); + } + } + buffer += n; buf_size -= n; + + /* primary flag */ + if (buf_size < 4) return; + lptr = (afs_int32 *)buffer; + if (in) { + *lptr = ntohl(*lptr); + } else { + *lptr = htonl((*lptr) & ~0x8000); + } + return; +} + +static void FetchVolumeStatus_conversion(char *buffer, int buf_size, int in) +{ + AFSFetchVolumeStatus *status = (AFSFetchVolumeStatus *)buffer; + + if (buf_size < sizeof(AFSFetchVolumeStatus)) + return; + if (in) { + status->Vid = ntohl(status->Vid); + status->ParentId = ntohl(status->ParentId); + status->Type = ntohl(status->Type); + status->MinQuota = ntohl(status->MinQuota); + status->MaxQuota = ntohl(status->MaxQuota); + status->BlocksInUse = ntohl(status->BlocksInUse); + status->PartBlocksAvail = ntohl(status->PartBlocksAvail); + status->PartMaxBlocks = ntohl(status->PartMaxBlocks); + } else { + status->Vid = htonl(status->Vid); + status->ParentId = htonl(status->ParentId); + status->Type = htonl(status->Type); + status->MinQuota = htonl(status->MinQuota); + status->MaxQuota = htonl(status->MaxQuota); + status->BlocksInUse = htonl(status->BlocksInUse); + status->PartBlocksAvail = htonl(status->PartBlocksAvail); + status->PartMaxBlocks = htonl(status->PartMaxBlocks); + } +} + +static void inparam_conversion(int cmd, char *buffer, int buf_size, int in) +{ + afs_int32 *lptr = (afs_int32 *)buffer; + + switch (cmd & 0xffff) { + case (0x5600 | 3): /* VIOCSETTOK */ + token_conversion(buffer, buf_size, in); + return; + + case (0x5600 | 5): /* VIOCSETVOLSTAT */ + FetchVolumeStatus_conversion(buffer, buf_size, in); + return; + + case (0x5600 | 8): /* VIOCGETTOK */ + case (0x5600 | 10): /* VIOCCKSERV */ + case (0x5600 | 20): /* VIOCACCESS */ + case (0x5600 | 24): /* VIOCSETCACHESIZE */ + case (0x5600 | 27): /* VIOCGETCELL */ + case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */ + case (0x5600 | 34): /* VIOC_VENUSLOG */ + case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ + case (0x5600 | 39): /* VIOC_EXPORTAFS */ + /* one 32-bit integer */ + if (buf_size >= 4) { + if (in) lptr[0] = ntohl(lptr[0]); + else lptr[0] = htonl(lptr[0]); + } + return; + + case (0x5600 | 36): /* VIOCSETCELLSTATUS */ + /* two 32-bit integers */ + if (buf_size >= 4) { + if (in) lptr[0] = ntohl(lptr[0]); + else lptr[0] = htonl(lptr[0]); + } + if (buf_size >= 8) { + if (in) lptr[1] = ntohl(lptr[1]); + else lptr[1] = htonl(lptr[1]); + } + return; + } +} + +static void outparam_conversion(int cmd, char *buffer, int buf_size, int in) +{ + afs_int32 *lptr = (afs_int32 *)buffer; + int i; + + switch (cmd & 0xffff) { + case (0x5600 | 4): /* VIOCGETVOLSTAT */ + case (0x5600 | 5): /* VIOCSETVOLSTAT */ + FetchVolumeStatus_conversion(buffer, buf_size, in); + return; + + case (0x5600 | 8): /* VIOCGETTOK */ + token_conversion(buffer, buf_size, in); + return; + + case (0x5600 | 12): /* VIOCCKCONN */ + case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */ + case (0x5600 | 34): /* VIOC_VENUSLOG */ + case (0x5600 | 35): /* VIOC_GETCELLSTATUS */ + case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ + case (0x5600 | 39): /* VIOC_EXPORTAFS */ + /* one 32-bit integer */ + if (buf_size >= 4) { + if (in) lptr[0] = ntohl(lptr[0]); + else lptr[0] = htonl(lptr[0]); + } + return; + + case (0x5600 | 40): /* VIOCGETCACHEPARMS */ + /* sixteen 32-bit integers */ + for (i = 0; i < 16 && buf_size >= 4; i++) { + if (in) lptr[i] = ntohl(lptr[i]); + else lptr[i] = htonl(lptr[i]); + buf_size -= 4; + } + return; + } +} + + +/* called with the GLOCK held */ +int +#ifdef AFS_SUN5_ENV +afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp) + rval_t *rvp; + struct AFS_UCRED *credp; +#else +#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV) +afs_syscall_pioctl(path, com, cmarg, follow, credp) + struct AFS_UCRED *credp; +#else +afs_syscall_pioctl(path, com, cmarg, follow) +#endif +#endif + char *path; + unsigned int com; + caddr_t cmarg; + int follow; +{ +#ifdef AFS_AIX41_ENV + struct ucred *credp = crref(); /* don't free until done! */ +#endif +#ifdef AFS_LINUX22_ENV + cred_t *credp = crref(); /* don't free until done! */ +#endif + struct afs_ioctl data; + struct clientcred ccred; + struct rmtbulk idata, odata; + short in_size, out_size; + afs_int32 code = 0, pag, err; + gid_t g0, g1; + char *abspath, *pathbuf = 0; + + AFS_STATCNT(afs_syscall_pioctl); + if (follow) + follow = 1; /* compat. with old venus */ + code = copyin_afs_ioctl(cmarg, &data); + if (code) goto out; + + if ((com & 0xff) == 90) { + /* PSetClientContext, in any space */ + code = EINVAL; + goto out; + } + + /* Special handling for a few pioctls */ + switch (com & 0xffff) { + case (0x5600 | 3): /* VIOCSETTOK */ + code = afspag_PSetTokens(data.in, data.in_size, &credp); + if (code) goto out; + break; + + case (0x5600 | 9): /* VIOCUNLOG */ + case (0x5600 | 21): /* VIOCUNPAG */ + code = afspag_PUnlog(data.in, data.in_size, &credp); + if (code) goto out; + break; + + case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ + code = afspag_PSetSysName(data.in, data.in_size, &credp); + if (code) goto out; + break; + } + + /* Set up credentials */ + memset(&ccred, 0, sizeof(ccred)); + pag = PagInCred(credp); + ccred.uid = credp->cr_uid; + if (pag != NOPAG) { + afs_get_groups_from_pag(pag, &g0, &g1); + ccred.group0 = g0; + ccred.group1 = g1; + } + + /* + * Copy the path and convert to absolute, if one was given. + * NB: We can only use osI_AllocLargeSpace here as long as + * RMTSYS_MAXPATHLEN is less than AFS_LRALLOCSIZ. + */ + if (path) { + pathbuf = osi_AllocLargeSpace(RMTSYS_MAXPATHLEN); + if (!pathbuf) { + code = ENOMEM; + goto out; + } + code = osi_abspath(path, pathbuf, RMTSYS_MAXPATHLEN, 0, &abspath); + if (code) + goto out_path; + } else { + abspath = NIL_PATHP; + } + + /* Allocate, copy, and convert incoming data */ + idata.rmtbulk_len = in_size = data.in_size; + if (in_size < 0 || in_size > MAXBUFFERLEN) { + code = EINVAL; + goto out_path; + } + if (in_size > AFS_LRALLOCSIZ) + idata.rmtbulk_val = osi_Alloc(in_size); + else + idata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ); + if (!idata.rmtbulk_val) { + code = ENOMEM; + goto out_path; + } + if (in_size) { + AFS_COPYIN(data.in, idata.rmtbulk_val, in_size, code); + if (code) + goto out_idata; + inparam_conversion(com, idata.rmtbulk_val, in_size, 0); + } + + /* Allocate space for outgoing data */ + odata.rmtbulk_len = out_size = data.out_size; + if (out_size < 0 || out_size > MAXBUFFERLEN) { + code = EINVAL; + goto out_idata; + } + if (out_size > AFS_LRALLOCSIZ) + odata.rmtbulk_val = osi_Alloc(out_size); + else + odata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ); + if (!odata.rmtbulk_val) { + code = ENOMEM; + goto out_idata; + } + + AFS_GUNLOCK(); + code = RMTSYS_Pioctl(rmtsys_conn, &ccred, abspath, com, follow, + &idata, &odata, &err); + AFS_GLOCK(); + if (code) + goto out_odata; + + /* Convert and copy out the result */ + if (odata.rmtbulk_len > out_size) { + code = E2BIG; + goto out_odata; + } + if (odata.rmtbulk_len) { + outparam_conversion(com, odata.rmtbulk_val, odata.rmtbulk_len, 1); + AFS_COPYOUT(odata.rmtbulk_val, data.out, odata.rmtbulk_len, code); + } + if (!code) + code = err; + +out_odata: + if (out_size > AFS_LRALLOCSIZ) + osi_Free(odata.rmtbulk_val, out_size); + else + osi_FreeLargeSpace(odata.rmtbulk_val); + +out_idata: + if (in_size > AFS_LRALLOCSIZ) + osi_Free(idata.rmtbulk_val, in_size); + else + osi_FreeLargeSpace(idata.rmtbulk_val); + +out_path: + if (path) + osi_FreeLargeSpace(pathbuf); + +out: +#if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV) + crfree(credp); +#endif +#if defined(KERNEL_HAVE_UERROR) + if (!getuerror()) + setuerror(code); + return (getuerror()); +#else + return (code); +#endif +} + + +int +afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6) + long parm, parm2, parm3, parm4, parm5, parm6; +{ + /* superusers may shut us down, as with afsd --shutdown */ +#ifdef AFS_SUN5_ENV + if (parm == AFSOP_SHUTDOWN && afs_suser(CRED())) +#else + if (parm == AFSOP_SHUTDOWN && afs_suser(NULL)) +#endif + { + AFS_GLOCK(); + afspag_Shutdown(); + AFS_GUNLOCK(); + return 0; + } + + /* otherwise, we don't support afs_syscall_call, period */ +#if defined(KERNEL_HAVE_UERROR) + setuerror(EPERM); +#endif + return EPERM; +} diff --git a/src/afs/afs_pag_cred.c b/src/afs/afs_pag_cred.c new file mode 100644 index 000000000..72c1b514c --- /dev/null +++ b/src/afs/afs_pag_cred.c @@ -0,0 +1,404 @@ +/* + * 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 +#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 "afs/unified_afs.h" +#include "rx/rx_globals.h" +#include "pagcb.h" + + +struct afspag_cell { + struct afspag_cell *next; + char *cellname; + afs_int32 cellnum; +}; + +afs_rwlock_t afs_xpagcell; +afs_rwlock_t afs_xpagsys; +static int lastcell = 0; +static struct afspag_cell *cells = 0; +static struct afspag_cell *primary_cell = 0; + + +struct afspag_cell *afspag_GetCell(char *acell) +{ + struct afspag_cell *tcell; + + ObtainWriteLock(&afs_xpagcell, 820); + + for (tcell = cells; tcell; tcell = tcell->next) { + if (!strcmp(acell, tcell->cellname)) + break; + } + + if (!tcell) { + tcell = (struct afspag_cell *)afs_osi_Alloc(sizeof(struct afspag_cell)); + if (!tcell) + goto out; + tcell->cellname = (char *)afs_osi_Alloc(strlen(acell) + 1); + if (!tcell->cellname) { + afs_osi_Free(tcell, sizeof(struct afspag_cell)); + tcell = 0; + goto out; + } + strcpy(tcell->cellname, acell); + tcell->cellnum = ++lastcell; + tcell->next = cells; + cells = tcell; + if (!primary_cell) primary_cell = tcell; + } + +out: + ReleaseWriteLock(&afs_xpagcell); + return tcell; +} + + +struct afspag_cell *afspag_GetPrimaryCell() +{ + struct afspag_cell *tcell; + + ObtainWriteLock(&afs_xpagcell, 821); + tcell = primary_cell; + ReleaseWriteLock(&afs_xpagcell); + return tcell; +} + + +void afspag_SetPrimaryCell(char *acell) +{ + struct afspag_cell *tcell; + + tcell = afspag_GetCell(acell); + ObtainWriteLock(&afs_xpagcell, 822); + primary_cell = tcell; + ReleaseWriteLock(&afs_xpagcell); +} + + +int afspag_PUnlog(char *ain, afs_int32 ainSize, struct AFS_UCRED **acred) +{ + register afs_int32 i; + register struct unixuser *tu; + afs_int32 pag, uid; + + AFS_STATCNT(PUnlog); + if (!afs_resourceinit_flag) /* afs daemons haven't started yet */ + return EIO; /* Inappropriate ioctl for device */ + + pag = PagInCred(*acred); + uid = (pag == NOPAG) ? (*acred)->cr_uid : pag; + i = UHash(uid); + ObtainWriteLock(&afs_xuser, 823); + for (tu = afs_users[i]; tu; tu = tu->next) { + if (tu->uid == uid) { + tu->vid = UNDEFVID; + tu->states &= ~UHasTokens; + /* security is not having to say you're sorry */ + memset((char *)&tu->ct, 0, sizeof(struct ClearToken)); +#ifdef UKERNEL + /* set the expire times to 0, causes + * afs_GCUserData to remove this entry + */ + tu->ct.EndTimestamp = 0; + tu->tokenTime = 0; +#endif /* UKERNEL */ + } + } + ReleaseWriteLock(&afs_xuser); + return 0; +} + + +int afspag_PSetTokens(char *ain, afs_int32 ainSize, struct AFS_UCRED **acred) +{ + afs_int32 i; + register struct unixuser *tu; + struct afspag_cell *tcell; + struct ClearToken clear; + char *stp; + int stLen; + afs_int32 flag, set_parent_pag = 0; + afs_int32 pag, uid; + + AFS_STATCNT(PSetTokens); + if (!afs_resourceinit_flag) { + return EIO; + } + memcpy((char *)&i, ain, sizeof(afs_int32)); + ain += sizeof(afs_int32); + stp = ain; /* remember where the ticket is */ + if (i < 0 || i > MAXKTCTICKETLEN) + return EINVAL; /* malloc may fail */ + stLen = i; + ain += i; /* skip over ticket */ + memcpy((char *)&i, ain, sizeof(afs_int32)); + ain += sizeof(afs_int32); + if (i != sizeof(struct ClearToken)) { + return EINVAL; + } + memcpy((char *)&clear, ain, sizeof(struct ClearToken)); + if (clear.AuthHandle == -1) + clear.AuthHandle = 999; /* more rxvab compat stuff */ + ain += sizeof(struct ClearToken); + if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) { + /* still stuff left? we've got primary flag and cell name. Set these */ + memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */ + ain += sizeof(afs_int32); /* skip id field */ + /* rest is cell name, look it up */ + /* some versions of gcc appear to need != 0 in order to get this right */ + if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */ + flag &= ~0x8000; + set_parent_pag = 1; + } + tcell = afspag_GetCell(ain); + } else { + /* default to primary cell, primary id */ + flag = 1; /* primary id */ + tcell = afspag_GetPrimaryCell(); + } + if (!tcell) return ESRCH; + if (set_parent_pag) { +#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV) +#if defined(AFS_DARWIN_ENV) + struct proc *p = current_proc(); /* XXX */ +#else + struct proc *p = curproc; /* XXX */ +#endif +#ifndef AFS_DARWIN80_ENV + uprintf("Process %d (%s) tried to change pags in PSetTokens\n", + p->p_pid, p->p_comm); +#endif + setpag(p, acred, -1, &pag, 1); +#else +#ifdef AFS_OSF_ENV + setpag(u.u_procp, acred, -1, &pag, 1); /* XXX u.u_procp is a no-op XXX */ +#else + setpag(acred, -1, &pag, 1); +#endif +#endif + } + pag = PagInCred(*acred); + uid = (pag == NOPAG) ? (*acred)->cr_uid : pag; + /* now we just set the tokens */ + tu = afs_GetUser(uid, tcell->cellnum, WRITE_LOCK); + if (!tu->cellinfo) + tu->cellinfo = (void *)tcell; + tu->vid = clear.ViceId; + if (tu->stp != NULL) { + afs_osi_Free(tu->stp, tu->stLen); + } + tu->stp = (char *)afs_osi_Alloc(stLen); + tu->stLen = stLen; + memcpy(tu->stp, stp, stLen); + tu->ct = clear; +#ifndef AFS_NOSTATS + afs_stats_cmfullperf.authent.TicketUpdates++; + afs_ComputePAGStats(); +#endif /* AFS_NOSTATS */ + tu->states |= UHasTokens; + tu->states &= ~UTokensBad; + afs_SetPrimary(tu, flag); + tu->tokenTime = osi_Time(); + afs_PutUser(tu, WRITE_LOCK); + + return 0; +} + + +int +SPAGCB_GetCreds(struct rx_call *a_call, afs_int32 a_uid, + CredInfos *a_creds) +{ + struct unixuser *tu; + CredInfo *tci; + int bucket, count, i = 0, clen; + char *cellname; + + RX_AFS_GLOCK(); + + memset(a_creds, 0, sizeof(struct CredInfos)); + if ((rx_HostOf(rx_PeerOf(rx_ConnectionOf(a_call))) != afs_nfs_server_addr + || rx_PortOf(rx_PeerOf(rx_ConnectionOf(a_call))) != htons(7001)) +#if 0 /* for debugging ONLY! */ + && rx_PortOf(rx_PeerOf(rx_ConnectionOf(a_call))) != htons(7901) +#endif + ) { + RX_AFS_GUNLOCK(); + return UAEPERM; + } + + ObtainWriteLock(&afs_xuser, 823); + + /* count them first */ + bucket = UHash(a_uid); + for (count = 0, tu = afs_users[bucket]; tu; tu = tu->next) { + if (tu->uid == a_uid) count++; + } + + if (!count) { + ReleaseWriteLock(&afs_xuser); + RX_AFS_GUNLOCK(); + return UAESRCH; + } + + a_creds->CredInfos_val = + (CredInfo *)afs_osi_Alloc(count * sizeof(CredInfo)); + if (!a_creds->CredInfos_val) + goto out; + a_creds->CredInfos_len = count; + memset(a_creds->CredInfos_val, 0, count * sizeof(CredInfo)); + + for (i = 0, tu = afs_users[bucket]; tu; tu = tu->next, i++) { + if (tu->uid == a_uid && tu->cellinfo && + (tu->states & UHasTokens) && !(tu->states & UTokensBad)) { + + tci = &a_creds->CredInfos_val[i]; + tci->vid = tu->vid; + tci->ct.AuthHandle = tu->ct.AuthHandle; + memcpy(tci->ct.HandShakeKey, tu->ct.HandShakeKey, 8); + tci->ct.ViceId = tu->ct.ViceId; + tci->ct.BeginTimestamp = tu->ct.BeginTimestamp; + tci->ct.EndTimestamp = tu->ct.EndTimestamp; + + cellname = ((struct afspag_cell *)(tu->cellinfo))->cellname; + clen = strlen(cellname) + 1; + tci->cellname = afs_osi_Alloc(clen); + if (!tci->cellname) + goto out; + memcpy(tci->cellname, cellname, clen); + + tci->st.st_len = tu->stLen; + tci->st.st_val = afs_osi_Alloc(tu->stLen); + if (!tci->st.st_val) { + afs_osi_Free(tci->cellname, clen); + goto out; + } + memcpy(tci->st.st_val, tu->stp, tu->stLen); + if (tu->states & UPrimary) + tci->states |= UPrimary; + } + } + + ReleaseWriteLock(&afs_xuser); + RX_AFS_GUNLOCK(); + return 0; + +out: + if (a_creds->CredInfos_val) { + while (i-- > 0) { + afs_osi_Free(a_creds->CredInfos_val[i].st.st_val, + a_creds->CredInfos_val[i].st.st_len); + afs_osi_Free(a_creds->CredInfos_val[i].cellname, + strlen(a_creds->CredInfos_val[i].cellname) + 1); + } + afs_osi_Free(a_creds->CredInfos_val, count * sizeof(CredInfo)); + } + + ReleaseWriteLock(&afs_xuser); + RX_AFS_GUNLOCK(); + return UAENOMEM; +} + + +int afspag_PSetSysName(char *ain, afs_int32 ainSize, struct AFS_UCRED **acred) +{ + int setsysname, count, t; + char *cp, *setp; + + setp = ain; + memcpy((char *)&setsysname, ain, sizeof(afs_int32)); + ain += sizeof(afs_int32); + if (!setsysname) + return 0; /* nothing to do locally */ + + /* Check my args */ + if (setsysname < 0 || setsysname > MAXNUMSYSNAMES) + return EINVAL; + if (!afs_osi_suser(*acred)) + return EACCES; + for (cp = ain, count = 0; count < setsysname; count++) { + /* won't go past end of ain since maxsysname*num < ain length */ + t = strlen(cp); + if (t >= MAXSYSNAME || t <= 0) + return EINVAL; + /* check for names that can shoot us in the foot */ + if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0))) + return EINVAL; + cp += t + 1; + } + + ObtainWriteLock(&afs_xpagsys, 824); + for (cp = ain, count = 0; count < setsysname; count++) { + t = strlen(cp); + memcpy(afs_sysnamelist[count], cp, t + 1); + cp += t + 1; + } + afs_sysnamecount = setsysname; + afs_sysnamegen++; + ReleaseWriteLock(&afs_xpagsys); + + /* Change the arguments so we pass the allpags flag to the server */ + setsysname |= 0x8000; + memcpy(setp, (char *)&setsysname, sizeof(afs_int32)); + return 0; +} + + +int +SPAGCB_GetSysName(struct rx_call *a_call, afs_int32 a_uid, + SysNameList *a_sysnames) +{ + int i; + + RX_AFS_GLOCK(); + + ObtainReadLock(&afs_xpagsys); + memset(a_sysnames, 0, sizeof(struct SysNameList)); + + a_sysnames->SysNameList_len = afs_sysnamecount; + a_sysnames->SysNameList_val = + afs_osi_Alloc(afs_sysnamecount * sizeof(SysNameEnt)); + if (!a_sysnames->SysNameList_val) + goto out; + + for (i = 0; i < afs_sysnamecount; i++) { + a_sysnames->SysNameList_val[i].sysname = + afs_osi_Alloc(strlen(afs_sysnamelist[i]) + 1); + if (!a_sysnames->SysNameList_val[i].sysname) + goto out; + strcpy(a_sysnames->SysNameList_val[i].sysname, afs_sysnamelist[i]); + } + + ReleaseReadLock(&afs_xpagsys); + RX_AFS_GUNLOCK(); + return 0; + +out: + if (a_sysnames->SysNameList_val) { + while (i-- > 0) { + afs_osi_Free(a_sysnames->SysNameList_val[i].sysname, + strlen(a_sysnames->SysNameList_val[i].sysname) + 1); + } + afs_osi_Free(a_sysnames->SysNameList_val, + afs_sysnamecount * sizeof(SysNameEnt)); + } + + ReleaseWriteLock(&afs_xpagsys); + RX_AFS_GUNLOCK(); + return UAENOMEM; +} diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index 2c4599b4c..54dcfcc0f 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -90,6 +90,7 @@ DECL_PIOCTL(PRxStatPeer); DECL_PIOCTL(PPrefetchFromTape); DECL_PIOCTL(PResidencyCmd); DECL_PIOCTL(PCallBackAddr); +DECL_PIOCTL(PNFSNukeCreds); /* * A macro that says whether we're going to need HandleClientContext(). @@ -194,114 +195,14 @@ static int (*(CpioctlSw[])) () = { PCallBackAddr, /* 3 -- request addr for callback rxcon */ }; +static int (*(OpioctlSw[])) () = { + PBogus, /* 0 */ + PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */ +}; + #define PSetClientContext 99 /* Special pioctl to setup caller's creds */ int afs_nobody = NFS_NOBODY; -#if (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)) || defined(AFS_HPUX_64BIT_ENV) || defined(AFS_SUN57_64BIT_ENV) || (defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)) || defined(NEED_IOCTL32) -static void -afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst) -{ - dst->in = (char *)(unsigned long)src->in; - dst->out = (char *)(unsigned long)src->out; - dst->in_size = src->in_size; - dst->out_size = src->out_size; -} -#endif - -/* - * If you need to change copyin_afs_ioctl(), you may also need to change - * copyin_iparam(). - */ - -static int -copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst) -{ - int code; -#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) - struct afs_ioctl32 dst32; - - if (!(IS64U)) { - AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); - if (!code) - afs_ioctl32_to_afs_ioctl(&dst32, dst); - return code; - } -#endif /* defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) */ - - -#if defined(AFS_HPUX_64BIT_ENV) - struct afs_ioctl32 dst32; - - if (is_32bit(u.u_procp)) { /* is_32bit() in proc_iface.h */ - AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); - if (!code) - afs_ioctl32_to_afs_ioctl(&dst32, dst); - return code; - } -#endif /* defined(AFS_HPUX_64BIT_ENV) */ - -#if defined(AFS_SUN57_64BIT_ENV) - struct afs_ioctl32 dst32; - - if (get_udatamodel() == DATAMODEL_ILP32) { - AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); - if (!code) - afs_ioctl32_to_afs_ioctl(&dst32, dst); - return code; - } -#endif /* defined(AFS_SUN57_64BIT_ENV) */ - -#if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) - struct afs_ioctl32 dst32; - - if (!ABI_IS_64BIT(get_current_abi())) { - AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); - if (!code) - afs_ioctl32_to_afs_ioctl(&dst32, dst); - return code; - } -#endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */ - -#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV) - struct afs_ioctl32 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 pioctl32 not done for this linux -#endif - { - AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); - if (!code) - afs_ioctl32_to_afs_ioctl(&dst32, dst); - return code; - } -#endif /* defined(AFS_LINUX_64BIT_KERNEL) */ - - AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code); - return code; -} - int HandleIoctl(register struct vcache *avc, register afs_int32 acom, struct afs_ioctl *adata) @@ -857,7 +758,7 @@ afs_syscall_pioctl(path, com, cmarg, follow) { struct afs_ioctl data; #ifdef AFS_NEED_CLIENTCONTEXT - struct AFS_UCRED *tmpcred; + struct AFS_UCRED *tmpcred = NULL; #endif struct AFS_UCRED *foreigncreds = NULL; register afs_int32 code = 0; @@ -883,7 +784,7 @@ afs_syscall_pioctl(path, com, cmarg, follow) } if ((com & 0xff) == PSetClientContext) { #ifdef AFS_NEED_CLIENTCONTEXT -#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) +#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) code = HandleClientContext(&data, &com, &foreigncreds, credp); #else code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred()); @@ -913,7 +814,7 @@ afs_syscall_pioctl(path, com, cmarg, follow) * like afs_osi_suser(cred) which, I think, is better since it * generalizes and supports multi cred environments... */ -#ifdef AFS_SUN5_ENV +#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) tmpcred = credp; credp = foreigncreds; #elif defined(AFS_AIX41_ENV) @@ -1039,7 +940,9 @@ afs_syscall_pioctl(path, com, cmarg, follow) set_p_cred(u.u_procp, tmpcred); /* restore original credentials */ #elif defined(AFS_SGI_ENV) OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */ -#elif !defined(AFS_SUN5_ENV) +#elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) + credp = tmpcred; /* restore original credentials */ +#else osi_curcred() = tmpcred; /* restore original credentials */ #endif /* AFS_HPUX101_ENV */ crfree(foreigncreds); @@ -1105,6 +1008,10 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom, pioctlSw = CpioctlSw; pioctlSwSize = sizeof(CpioctlSw); break; + case 'O': /* Coordinated/common pioctls */ + pioctlSw = OpioctlSw; + pioctlSwSize = sizeof(OpioctlSw); + break; default: afs_PutFakeStat(&fakestate); return EINVAL; @@ -2811,8 +2718,8 @@ DECL_PIOCTL(PSetSysName) register struct afs_exporter *exporter; register struct unixuser *au; register afs_int32 pag, error; - int t, count, num = 0; - char **sysnamelist[MAXNUMSYSNAMES]; + int t, count, num = 0, allpags = 0; + char **sysnamelist; AFS_STATCNT(PSetSysName); if (!afs_globalVFS) { @@ -2826,6 +2733,10 @@ DECL_PIOCTL(PSetSysName) memset(inname, 0, MAXSYSNAME); memcpy((char *)&setsysname, ain, sizeof(afs_int32)); ain += sizeof(afs_int32); + if (setsysname & 0x8000) { + allpags = 1; + setsysname &= ~0x8000; + } if (setsysname) { /* Check my args */ @@ -2850,7 +2761,11 @@ DECL_PIOCTL(PSetSysName) ain += t + 1; num = count; } - if ((*acred)->cr_gid == RMTUSER_REQ) { /* Handles all exporters */ + if ((*acred)->cr_gid == RMTUSER_REQ || + (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */ + if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) { + return EPERM; + } pag = PagInCred(*acred); if (pag == NOPAG) { return EINVAL; /* Better than panicing */ @@ -2862,8 +2777,8 @@ DECL_PIOCTL(PSetSysName) afs_PutUser(au, READ_LOCK); return EINVAL; /* Better than panicing */ } - error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), sysnamelist, - &num); + error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist, + &num, allpags); if (error) { if (error == ENODEV) foundname = 0; /* sysname not set yet! */ @@ -2873,9 +2788,11 @@ DECL_PIOCTL(PSetSysName) } } else { foundname = num; - strcpy(outname, (*sysnamelist)[0]); + strcpy(outname, sysnamelist[0]); } afs_PutUser(au, READ_LOCK); + if (setsysname) + afs_sysnamegen++; } else { /* Not xlating, so local case */ if (!afs_sysname) @@ -2883,11 +2800,15 @@ DECL_PIOCTL(PSetSysName) if (!setsysname) { /* user just wants the info */ strcpy(outname, afs_sysname); foundname = afs_sysnamecount; - *sysnamelist = afs_sysnamelist; + sysnamelist = afs_sysnamelist; } else { /* Local guy; only root can change sysname */ if (!afs_osi_suser(*acred)) return EACCES; + /* allpags makes no sense for local use */ + if (allpags) + return EINVAL; + /* clear @sys entries from the dnlc, once afs_lookup can * do lookups of @sys entries and thinks it can trust them */ /* privs ok, store the entry, ... */ @@ -2904,6 +2825,7 @@ DECL_PIOCTL(PSetSysName) } } afs_sysnamecount = setsysname; + afs_sysnamegen++; } } if (!setsysname) { @@ -2914,13 +2836,13 @@ DECL_PIOCTL(PSetSysName) strcpy(cp, outname); /* ... the entry, ... */ cp += strlen(outname) + 1; for (count = 1; count < foundname; ++count) { /* ... or list. */ - if (!(*sysnamelist)[count]) + if (!sysnamelist[count]) osi_Panic ("PSetSysName: no afs_sysnamelist entry to read\n"); - t = strlen((*sysnamelist)[count]); + t = strlen(sysnamelist[count]); if (t >= MAXSYSNAME) osi_Panic("PSetSysName: sysname entry garbled\n"); - strcpy(cp, (*sysnamelist)[count]); + strcpy(cp, sysnamelist[count]); cp += t + 1; } } @@ -3189,6 +3111,7 @@ DECL_PIOCTL(PExportAfs) { afs_int32 export, newint = 0, type, changestate, handleValue, convmode, pwsync, smounts; + afs_int32 rempags = 0, pagcb = 0; register struct afs_exporter *exporter; AFS_STATCNT(PExportAfs); @@ -3201,10 +3124,12 @@ DECL_PIOCTL(PExportAfs) exporter = exporter_find(type); if (newint) { export = handleValue & 3; - changestate = handleValue & 0xff; + changestate = handleValue & 0xfff; smounts = (handleValue >> 2) & 3; pwsync = (handleValue >> 4) & 3; convmode = (handleValue >> 6) & 3; + rempags = (handleValue >> 8) & 3; + pagcb = (handleValue >> 10) & 3; } else { changestate = (handleValue >> 16) & 0x1; convmode = (handleValue >> 16) & 0x2; @@ -3251,6 +3176,18 @@ DECL_PIOCTL(PExportAfs) exporter->exp_states &= ~EXP_SUBMOUNTS; } } + if (rempags & 2) { + if (rempags & 1) + exporter->exp_states |= EXP_CLIPAGS; + else + exporter->exp_states &= ~EXP_CLIPAGS; + } + if (pagcb & 2) { + if (pagcb & 1) + exporter->exp_states |= EXP_CALLBACK; + else + exporter->exp_states &= ~EXP_CALLBACK; + } handleValue = exporter->exp_states; memcpy(aout, (char *)&handleValue, sizeof(afs_int32)); *aoutSize = sizeof(afs_int32); @@ -3390,7 +3327,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com, { char *ain, *inData; afs_uint32 hostaddr; - afs_int32 uid, g0, g1, i, code, pag, exporter_type; + afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0; struct afs_exporter *exporter, *outexporter; struct AFS_UCRED *newcred; struct unixuser *au; @@ -3453,26 +3390,28 @@ HandleClientContext(struct afs_ioctl *ablob, int *com, * code fails for remote client roots. */ uid = afs_nobody; /* NFS_NOBODY == -2 */ + isroot = 1; } newcred = crget(); -#if defined(AFS_LINUX26_ENV) - newcred->cr_group_info = groups_alloc(0); -#endif #ifdef AFS_AIX41_ENV setuerror(0); #endif - newcred->cr_gid = RMTUSER_REQ; + newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ; #ifdef AFS_AIX51_ENV newcred->cr_groupset.gs_union.un_groups[0] = g0; newcred->cr_groupset.gs_union.un_groups[1] = g1; +#elif defined(AFS_LINUX26_ENV) + newcred->cr_group_info = groups_alloc(2); + GROUP_AT(newcred->cr_group_info, 0) = g0; + GROUP_AT(newcred->cr_group_info, 1) = g1; #else newcred->cr_groups[0] = g0; newcred->cr_groups[1] = g1; #endif #ifdef AFS_AIX_ENV newcred->cr_ngrps = 2; -#else -#if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) +#elif !defined(AFS_LINUX26_ENV) +#if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) newcred->cr_ngroups = 2; #else for (i = 2; i < NGROUPS; i++) @@ -3967,3 +3906,55 @@ DECL_PIOCTL(PCallBackAddr) #endif /* UKERNEL */ return 0; } + +DECL_PIOCTL(PNFSNukeCreds) +{ + afs_uint32 addr, code; + register afs_int32 i; + register struct unixuser *tu; + + AFS_STATCNT(PUnlog); + if (!afs_resourceinit_flag) /* afs daemons haven't started yet */ + return EIO; /* Inappropriate ioctl for device */ + + if (ainSize < sizeof(afs_int32)) + return EINVAL; + memcpy(&addr, ain, sizeof(afs_int32)); + + if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) { + tu = afs_GetUser(areq->uid, -1, SHARED_LOCK); + if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) { + afs_PutUser(tu, SHARED_LOCK); + return EACCES; + } + afs_PutUser(tu, SHARED_LOCK); + } else if (!afs_osi_suser(acred)) { + return EACCES; + } + + ObtainWriteLock(&afs_xuser, 227); + for (i = 0; i < NUSERS; i++) { + for (tu = afs_users[i]; tu; tu = tu->next) { + if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) { + tu->vid = UNDEFVID; + tu->states &= ~UHasTokens; + /* security is not having to say you're sorry */ + memset((char *)&tu->ct, 0, sizeof(struct ClearToken)); + tu->refCount++; + ReleaseWriteLock(&afs_xuser); + afs_ResetUserConns(tu); + tu->refCount--; + ObtainWriteLock(&afs_xuser, 228); +#ifdef UKERNEL + /* set the expire times to 0, causes + * afs_GCUserData to remove this entry + */ + tu->ct.EndTimestamp = 0; + tu->tokenTime = 0; +#endif /* UKERNEL */ + } + } + } + ReleaseWriteLock(&afs_xuser); + return 0; +} diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 25762d19c..2015eebe8 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -11,15 +11,9 @@ #define _AFS_PROTOTYPES_H_ /* afs_analyze.c */ -extern void init_et_to_sys_error(void); -extern void afs_FinalizeReq(struct vrequest *areq); extern int afs_Analyze(register struct conn *aconn, afs_int32 acode, struct VenusFid *afid, register struct vrequest *areq, int op, afs_int32 locktype, struct cell *cellp); -extern int afs_CheckCode(afs_int32 acode, struct vrequest *areq, int where); -extern void afs_CopyError(register struct vrequest *afrom, - register struct vrequest *ato); -extern void init_sys_error_to_et(void); /* afs_axscache.c */ extern afs_rwlock_t afs_xaxs; @@ -45,82 +39,12 @@ extern afs_int32 afs_setTime; extern char afs_rootVolumeName[64]; extern void afs_shutdown(void); extern void afs_FlushCBs(void); -extern struct afs_icl_set *afs_icl_allSets; -extern int afs_icl_CreateLog(char *name, afs_int32 logSize, - struct afs_icl_log **outLogpp); -extern int afs_icl_CreateLogWithFlags(char *name, afs_int32 logSize, - afs_uint32 flags, - struct afs_icl_log **outLogpp); -extern int afs_icl_CopyOut(register struct afs_icl_log *logp, - afs_int32 * bufferp, afs_int32 * bufSizep, - afs_uint32 * cookiep, afs_int32 * flagsp); -extern int afs_icl_GetLogParms(struct afs_icl_log *logp, afs_int32 * maxSizep, - afs_int32 * curSizep); -extern int afs_icl_LogHold(register struct afs_icl_log *logp); -extern int afs_icl_LogHoldNL(register struct afs_icl_log *logp); -extern int afs_icl_LogUse(register struct afs_icl_log *logp); -extern int afs_icl_LogFreeUse(register struct afs_icl_log *logp); -extern int afs_icl_LogSetSize(register struct afs_icl_log *logp, - afs_int32 logSize); -extern int afs_icl_ZapLog(register struct afs_icl_log *logp); -extern int afs_icl_LogRele(register struct afs_icl_log *logp); -extern int afs_icl_LogReleNL(register struct afs_icl_log *logp); -extern int afs_icl_ZeroLog(register struct afs_icl_log *logp); -extern int afs_icl_LogFree(register struct afs_icl_log *logp); -extern struct afs_icl_log *afs_icl_FindLog(char *name); -extern int - afs_icl_EnumerateLogs(int (*aproc) - - (char *name, char *arock, struct afs_icl_log * tp), - char *arock); -extern int afs_icl_CreateSet(char *name, struct afs_icl_log *baseLogp, - struct afs_icl_log *fatalLogp, - struct afs_icl_set **outSetpp); -extern int afs_icl_CreateSetWithFlags(char *name, - struct afs_icl_log *baseLogp, - struct afs_icl_log *fatalLogp, - afs_uint32 flags, - struct afs_icl_set **outSetpp); -extern int afs_icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, - int setValue); -extern int afs_icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, - int *getValuep); -extern int afs_icl_ZeroSet(struct afs_icl_set *setp); -extern int - afs_icl_EnumerateSets(int (*aproc) - - (char *name, char *arock, struct afs_icl_log * tp), - char *arock); -extern int afs_icl_AddLogToSet(struct afs_icl_set *setp, - struct afs_icl_log *newlogp); -extern int afs_icl_SetSetStat(struct afs_icl_set *setp, int op); -extern int afs_icl_SetHold(register struct afs_icl_set *setp); -extern int afs_icl_ZapSet(register struct afs_icl_set *setp); -extern int afs_icl_SetRele(register struct afs_icl_set *setp); -extern int afs_icl_SetFree(register struct afs_icl_set *setp); -extern struct afs_icl_set *afs_icl_FindSet(char *name); - -extern int afs_icl_Event4(register struct afs_icl_set *setp, - afs_int32 eventID, afs_int32 lAndT, long p1, - long p2, long p3, long p4); -extern int afs_icl_Event3(register struct afs_icl_set *setp, - afs_int32 eventID, afs_int32 lAndT, long p1, - long p2, long p3); -extern int afs_icl_Event2(register struct afs_icl_set *setp, - afs_int32 eventID, afs_int32 lAndT, long p1, - long p2); -extern int afs_icl_Event1(register struct afs_icl_set *setp, - afs_int32 eventID, afs_int32 lAndT, long p1); -extern int afs_icl_Event0(register struct afs_icl_set *setp, - afs_int32 eventID, afs_int32 lAndT); -extern void afs_icl_AppendRecord(register struct afs_icl_log *logp, - afs_int32 op, afs_int32 types, long p1, - long p2, long p3, long p4); - extern int afs_CheckInit(void); extern void afs_shutdown(void); extern void shutdown_afstest(void); extern void afs_shutdown_BKG(void); +extern int afs_syscall_call(long parm, long parm2, long parm3, + long parm4, long parm5, long parm6); /* afs_callback.c */ @@ -208,6 +132,7 @@ extern afs_int32 afs_NewCell(char *acellName, afs_int32 * acellHosts, extern afs_int32 afs_SetPrimaryCell(char *acellName); extern struct cell *afs_GetCell(afs_int32 acell, afs_int32 locktype); extern struct cell *afs_GetCellStale(afs_int32 acell, afs_int32 locktype); +extern struct cell *afs_GetCellByHandle(void *handle, afs_int32 locktype); extern struct cell *afs_GetCellByIndex(afs_int32 cellidx, afs_int32 locktype); extern struct cell *afs_GetCellByName(char *acellName, afs_int32 locktype); extern struct cell *afs_GetPrimaryCell(afs_int32 locktype); @@ -341,14 +266,22 @@ extern int afs_InitCacheFile(char *afile, ino_t ainode); /* afs_dynroot.c */ extern int afs_IsDynrootFid(struct VenusFid *fid); +extern int afs_IsDynrootMountFid(struct VenusFid *fid); +extern int afs_IsDynrootAnyFid(struct VenusFid *fid); extern void afs_GetDynrootFid(struct VenusFid *fid); +extern void afs_GetDynrootMountFid(struct VenusFid *fid); extern int afs_IsDynroot(struct vcache *avc); +extern int afs_IsDynrootMount(struct vcache *avc); +extern int afs_IsDynrootAny(struct vcache *avc); extern void afs_DynrootInvalidate(void); extern void afs_GetDynroot(char **dynrootDir, int *dynrootLen, struct AFSFetchStatus *status); +extern void afs_GetDynrootMount(char **dynrootDir, int *dynrootLen, + struct AFSFetchStatus *status); extern void afs_PutDynroot(void); extern int afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status); +extern int afs_InitDynroot(void); extern int afs_SetDynrootEnable(int enable); extern int afs_GetDynrootEnable(void); extern int afs_DynrootVOPRemove(struct vcache *avc, struct AFS_UCRED *acred, @@ -356,10 +289,96 @@ extern int afs_DynrootVOPRemove(struct vcache *avc, struct AFS_UCRED *acred, extern int afs_DynrootVOPSymlink(struct vcache *avc, struct AFS_UCRED *acred, char *aname, char *atargetName); +/* afs_error.c */ +extern void init_et_to_sys_error(void); +extern afs_int32 et_to_sys_error(afs_int32 in); +extern void afs_FinalizeReq(struct vrequest *areq); +extern int afs_CheckCode(afs_int32 acode, struct vrequest *areq, int where); +extern void afs_CopyError(register struct vrequest *afrom, + register struct vrequest *ato); +extern void init_sys_error_to_et(void); + /* afs_exporter.c */ extern struct afs_exporter *root_exported; extern struct afs_exporter *exporter_find(int type); +/* afs_icl.c */ +extern struct afs_icl_set *afs_icl_allSets; +extern int afs_icl_InitLogs(void); +extern int afs_icl_CreateLog(char *name, afs_int32 logSize, + struct afs_icl_log **outLogpp); +extern int afs_icl_CreateLogWithFlags(char *name, afs_int32 logSize, + afs_uint32 flags, + struct afs_icl_log **outLogpp); +extern int afs_icl_CopyOut(register struct afs_icl_log *logp, + afs_int32 * bufferp, afs_int32 * bufSizep, + afs_uint32 * cookiep, afs_int32 * flagsp); +extern int afs_icl_GetLogParms(struct afs_icl_log *logp, afs_int32 * maxSizep, + afs_int32 * curSizep); +extern int afs_icl_LogHold(register struct afs_icl_log *logp); +extern int afs_icl_LogHoldNL(register struct afs_icl_log *logp); +extern int afs_icl_LogUse(register struct afs_icl_log *logp); +extern int afs_icl_LogFreeUse(register struct afs_icl_log *logp); +extern int afs_icl_LogSetSize(register struct afs_icl_log *logp, + afs_int32 logSize); +extern int afs_icl_ZapLog(register struct afs_icl_log *logp); +extern int afs_icl_LogRele(register struct afs_icl_log *logp); +extern int afs_icl_LogReleNL(register struct afs_icl_log *logp); +extern int afs_icl_ZeroLog(register struct afs_icl_log *logp); +extern int afs_icl_LogFree(register struct afs_icl_log *logp); +extern struct afs_icl_log *afs_icl_FindLog(char *name); +extern int + afs_icl_EnumerateLogs(int (*aproc) + + (char *name, char *arock, struct afs_icl_log * tp), + char *arock); +extern int afs_icl_CreateSet(char *name, struct afs_icl_log *baseLogp, + struct afs_icl_log *fatalLogp, + struct afs_icl_set **outSetpp); +extern int afs_icl_CreateSetWithFlags(char *name, + struct afs_icl_log *baseLogp, + struct afs_icl_log *fatalLogp, + afs_uint32 flags, + struct afs_icl_set **outSetpp); +extern int afs_icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, + int setValue); +extern int afs_icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, + int *getValuep); +extern int afs_icl_ZeroSet(struct afs_icl_set *setp); +extern int + afs_icl_EnumerateSets(int (*aproc) + + (char *name, char *arock, struct afs_icl_log * tp), + char *arock); +extern int afs_icl_AddLogToSet(struct afs_icl_set *setp, + struct afs_icl_log *newlogp); +extern int afs_icl_SetSetStat(struct afs_icl_set *setp, int op); +extern int afs_icl_SetHold(register struct afs_icl_set *setp); +extern int afs_icl_ZapSet(register struct afs_icl_set *setp); +extern int afs_icl_SetRele(register struct afs_icl_set *setp); +extern int afs_icl_SetFree(register struct afs_icl_set *setp); +extern struct afs_icl_set *afs_icl_FindSet(char *name); + +extern int afs_icl_Event4(register struct afs_icl_set *setp, + afs_int32 eventID, afs_int32 lAndT, long p1, + long p2, long p3, long p4); +extern int afs_icl_Event3(register struct afs_icl_set *setp, + afs_int32 eventID, afs_int32 lAndT, long p1, + long p2, long p3); +extern int afs_icl_Event2(register struct afs_icl_set *setp, + afs_int32 eventID, afs_int32 lAndT, long p1, + long p2); +extern int afs_icl_Event1(register struct afs_icl_set *setp, + afs_int32 eventID, afs_int32 lAndT, long p1); +extern int afs_icl_Event0(register struct afs_icl_set *setp, + afs_int32 eventID, afs_int32 lAndT); +extern void afs_icl_AppendRecord(register struct afs_icl_log *logp, + afs_int32 op, afs_int32 types, long p1, + long p2, long p3, long p4); +extern int Afscall_icl(long opcode, long p1, long p2, long p3, long p4, + long *retval); + + /* afs_init.c */ extern struct cm_initparams cm_initParams; extern int afs_resourceinit_flag; @@ -367,6 +386,7 @@ extern afs_rwlock_t afs_puttofileLock; extern char *afs_sysname; extern char *afs_sysnamelist[MAXNUMSYSNAMES]; extern int afs_sysnamecount; +extern int afs_sysnamegen; extern afs_int32 cacheInfoModTime; extern int afs_CacheInit(afs_int32 astatSize, afs_int32 afiles, afs_int32 ablocks, afs_int32 aDentries, @@ -463,6 +483,11 @@ extern void shutdown_memcache(void); /* afs_nfsclnt.c */ extern struct afs_exporter *afs_nfsexported; extern struct afs_exporter *afs_nfsexporter; +extern void afs_nfsclient_init(void); +extern int afs_nfsclient_reqhandler(struct afs_exporter *exporter, + struct AFS_UCRED **cred, + afs_int32 host, afs_int32 *pagparam, + struct afs_exporter **outexporter); /* afs_osi.c */ extern afs_lock_t afs_ftf; @@ -471,27 +496,11 @@ extern void afs_osi_RxkRegister(void); extern void afs_osi_MaskSignals(void); extern void afs_osi_UnmaskRxkSignals(void); extern void afs_osi_MaskUserLoop(void); -extern void *afs_osi_Alloc_debug(size_t x, char *func, int line); -#ifndef afs_osi_Alloc_NoSleep -extern void *afs_osi_Alloc_NoSleep(size_t x); -#endif -#ifndef afs_osi_Free -extern void afs_osi_Free(void *x, size_t asize); -#endif -extern void afs_osi_FreeStr(char *x); extern void osi_Init(void); -extern int osi_Active(register struct vcache *avc); -extern void osi_FlushPages(register struct vcache *avc, - struct AFS_UCRED *credp); -extern void osi_FlushText_really(register struct vcache *vp); extern void afs_osi_MaskSignals(void); extern void afs_osi_UnmaskRxkSignals(void); extern void afs_osi_RxkRegister(void); extern void afs_osi_Invisible(void); -extern int osi_VMDirty_p(struct vcache *avc); -#ifndef UKERNEL -extern void osi_ReleaseVM(struct vcache *avc, struct AFS_UCRED *acred); -#endif extern void shutdown_osi(void); extern int afs_osi_suser(void *credp); extern void afs_osi_TraverseProcTable(void); @@ -499,6 +508,24 @@ extern void afs_osi_TraverseProcTable(void); extern const struct AFS_UCRED *afs_osi_proc2cred(AFS_PROC * pr); #endif +/* afs_osi_alloc.c */ +#ifndef AFS_FBSD_ENV +extern afs_lock_t osi_fsplock; +extern afs_lock_t osi_flplock; +#endif +extern void *afs_osi_Alloc_debug(size_t x, char *func, int line); +#ifndef afs_osi_Alloc_NoSleep +extern void *afs_osi_Alloc_NoSleep(size_t x); +#endif +#ifndef afs_osi_Free +extern void afs_osi_Free(void *x, size_t asize); +#endif +extern void afs_osi_FreeStr(char *x); +extern void osi_FreeLargeSpace(void *adata); +extern void osi_FreeSmallSpace(void *adata); +extern void *osi_AllocLargeSpace(size_t size); +extern void *osi_AllocSmallSpace(size_t size); + /* afs_osi_pag.c */ extern int afs_setpag(); extern afs_uint32 genpag(void); @@ -513,22 +540,22 @@ extern afs_uint32 afs_get_pag_from_groups(gid_t g0a, gid_t g1a); extern void afs_get_groups_from_pag(afs_uint32 pag, gid_t * g0p, gid_t * g1p); extern afs_int32 PagInCred(const struct AFS_UCRED *cred); -/* afs_osi_alloc.c */ -#ifndef AFS_FBSD_ENV -extern afs_lock_t osi_fsplock; -extern afs_lock_t osi_flplock; -#endif -extern void osi_FreeLargeSpace(void *adata); -extern void osi_FreeSmallSpace(void *adata); -extern void *osi_AllocLargeSpace(size_t size); -extern void *osi_AllocSmallSpace(size_t size); - /* afs_osi_uio.c */ extern int afsio_copy(struct uio *ainuio, struct uio *aoutuio, struct iovec *aoutvec); extern int afsio_trim(struct uio *auio, afs_int32 asize); extern int afsio_skip(struct uio *auio, afs_int32 asize); +/* afs_osi_vm.c */ +extern int osi_Active(register struct vcache *avc); +extern void osi_FlushPages(register struct vcache *avc, + struct AFS_UCRED *credp); +extern void osi_FlushText_really(register struct vcache *vp); +extern int osi_VMDirty_p(struct vcache *avc); +#ifndef UKERNEL +extern void osi_ReleaseVM(struct vcache *avc, struct AFS_UCRED *acred); +#endif + /* ARCH/osi_misc.c */ @@ -656,6 +683,21 @@ extern void vcache2inode(struct vcache *avc); extern void vcache2fakeinode(struct vcache *rootvp, struct vcache *mpvp); #endif +/* afs_pag_call.c */ +extern afs_int32 afs_nfs_server_addr; +extern void afspag_Init(afs_int32 nfs_server_addr); +extern void afspag_Shutdown(void); + +/* afs_pag_cred.c */ +extern afs_rwlock_t afs_xpagcell; +extern afs_rwlock_t afs_xpagsys; +extern int afspag_PUnlog(char *ain, afs_int32 ainSize, + struct AFS_UCRED **acred); +extern int afspag_PSetTokens(char *ain, afs_int32 ainSize, + struct AFS_UCRED **acred); +extern int afspag_PSetSysName(char *ain, afs_int32 ainSize, + struct AFS_UCRED **acred); + /* afs_pioctl.c */ extern struct VenusFid afs_rootFid; extern afs_int32 afs_waitForever; @@ -738,6 +780,9 @@ extern void afs_GetCMStat(char **ptr, unsigned *size); extern void afs_AddToMean(struct afs_MeanStats *oldMean, afs_int32 newValue); #endif +/* afs_syscall.c */ +extern int copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst); + /* UKERNEL/afs_usrops.c */ #ifdef UKERNEL @@ -1082,6 +1127,7 @@ extern u_short afs_uuid_hash(afsUUID * uuid); /* MOVE THEM TO APPROPRIATE LOCATIONS */ extern afs_int32 RXAFSCB_ExecuteRequest(struct rx_call *acall); extern afs_int32 RXSTATS_ExecuteRequest(struct rx_call *acall); +extern afs_int32 PAGCB_ExecuteRequest(struct rx_call *acall); diff --git a/src/afs/afs_syscall.c b/src/afs/afs_syscall.c new file mode 100644 index 000000000..b388b5228 --- /dev/null +++ b/src/afs/afs_syscall.c @@ -0,0 +1,723 @@ +/* + * 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 +#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 + +#if (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)) || defined(AFS_HPUX_64BIT_ENV) || defined(AFS_SUN57_64BIT_ENV) || (defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)) || defined(NEED_IOCTL32) +static void +afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst) +{ + dst->in = (char *)(unsigned long)src->in; + dst->out = (char *)(unsigned long)src->out; + dst->in_size = src->in_size; + dst->out_size = src->out_size; +} +#endif + +/* + * If you need to change copyin_afs_ioctl(), you may also need to change + * copyin_iparam(). + */ + +int +copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst) +{ + int code; +#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) + struct afs_ioctl32 dst32; + + if (!(IS64U)) { + AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); + if (!code) + afs_ioctl32_to_afs_ioctl(&dst32, dst); + return code; + } +#endif /* defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) */ + + +#if defined(AFS_HPUX_64BIT_ENV) + struct afs_ioctl32 dst32; + + if (is_32bit(u.u_procp)) { /* is_32bit() in proc_iface.h */ + AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); + if (!code) + afs_ioctl32_to_afs_ioctl(&dst32, dst); + return code; + } +#endif /* defined(AFS_HPUX_64BIT_ENV) */ + +#if defined(AFS_SUN57_64BIT_ENV) + struct afs_ioctl32 dst32; + + if (get_udatamodel() == DATAMODEL_ILP32) { + AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); + if (!code) + afs_ioctl32_to_afs_ioctl(&dst32, dst); + return code; + } +#endif /* defined(AFS_SUN57_64BIT_ENV) */ + +#if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) + struct afs_ioctl32 dst32; + + if (!ABI_IS_64BIT(get_current_abi())) { + AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); + if (!code) + afs_ioctl32_to_afs_ioctl(&dst32, dst); + return code; + } +#endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */ + +#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV) + struct afs_ioctl32 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 pioctl32 not done for this linux +#endif + { + AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); + if (!code) + afs_ioctl32_to_afs_ioctl(&dst32, dst); + return code; + } +#endif /* defined(AFS_LINUX_64BIT_KERNEL) */ + + AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code); + return code; +} + + +#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 */ diff --git a/src/afs/afs_user.c b/src/afs/afs_user.c index 8d3e7dcd7..4fdd3ba71 100644 --- a/src/afs/afs_user.c +++ b/src/afs/afs_user.c @@ -51,6 +51,7 @@ afs_rwlock_t afs_xuser; struct unixuser *afs_users[NUSERS]; +#ifndef AFS_PAG_MANAGER /* Forward declarations */ void afs_ResetAccessCache(afs_int32 uid, int alock); @@ -86,6 +87,7 @@ RemoveUserConns(register struct unixuser *au) } /*For each chain */ } /*RemoveUserConns */ +#endif /* !AFS_PAG_MANAGER */ /* Called from afs_Daemon to garbage collect unixusers no longer using system, @@ -105,8 +107,10 @@ afs_GCUserData(int aforce) AFS_STATCNT(afs_GCUserData); /* Obtain locks in valid order */ ObtainWriteLock(&afs_xuser, 95); +#ifndef AFS_PAG_MANAGER ObtainReadLock(&afs_xserver); ObtainWriteLock(&afs_xconn, 96); +#endif now = osi_Time(); for (i = 0; i < NUSERS; i++) { for (lu = &afs_users[i], tu = *lu; tu; tu = nu) { @@ -128,7 +132,9 @@ afs_GCUserData(int aforce) nu = tu->next; if (delFlag) { *lu = tu->next; +#ifndef AFS_PAG_MANAGER RemoveUserConns(tu); +#endif if (tu->stp) afs_osi_Free(tu->stp, tu->stLen); if (tu->exporter) @@ -139,13 +145,18 @@ afs_GCUserData(int aforce) } } } +#ifndef AFS_PAG_MANAGER ReleaseWriteLock(&afs_xconn); - ReleaseWriteLock(&afs_xuser); +#endif +#ifndef AFS_PAG_MANAGER ReleaseReadLock(&afs_xserver); +#endif + ReleaseWriteLock(&afs_xuser); } /*afs_GCUserData */ +#ifndef AFS_PAG_MANAGER /* * Check for unixusers who encountered bad tokens, and reset the access * cache for these guys. Can't do this when token expiration detected, @@ -253,6 +264,7 @@ afs_ResetUserConns(register struct unixuser *auser) afs_ResetAccessCache(auser->uid, 1); auser->states &= ~UNeedsReset; } /*afs_ResetUserConns */ +#endif /* !AFS_PAG_MANAGER */ struct unixuser * diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index abfc3c531..2c74d4b57 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -1752,7 +1752,8 @@ afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq, if (cached) *cached = 1; osi_Assert((tvc->states & CVInit) == 0); - if (tvc->states & CStatd) { + /* If we are in readdir, return the vnode even if not statd */ + if ((tvc->states & CStatd) || afs_InReadDir(tvc)) { ReleaseSharedLock(&afs_xvcache); return tvc; } @@ -1894,9 +1895,24 @@ afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq, if (afs_DynrootNewVnode(tvc, &OutStatus)) { afs_ProcessFS(tvc, &OutStatus, areq); tvc->states |= CStatd | CUnique; + tvc->parentVnode = OutStatus.ParentVnode; + tvc->parentUnique = OutStatus.ParentUnique; code = 0; } else { code = afs_FetchStatus(tvc, afid, areq, &OutStatus); + /* For the NFS translator's benefit, make sure + * non-directory vnodes always have their parent FID set + * correctly, even when created as a result of decoding an + * NFS filehandle. It would be nice to also do this for + * directories, but we can't because the fileserver fills + * in the FID of the directory itself instead of that of + * its parent. + */ + if (!code && OutStatus.FileType != Directory && + !tvc->parentVnode) { + tvc->parentVnode = OutStatus.ParentVnode; + tvc->parentUnique = OutStatus.ParentUnique; + } } } diff --git a/src/afs/afs_volume.c b/src/afs/afs_volume.c index 98a181357..c8d630013 100644 --- a/src/afs/afs_volume.c +++ b/src/afs/afs_volume.c @@ -40,6 +40,7 @@ RCSID #include "afsincludes.h" /* Afs-based standard headers */ #include "afs/afs_stats.h" /* afs statistics */ +#include "afs/afs_dynroot.h" #if defined(AFS_SUN56_ENV) #include @@ -432,7 +433,7 @@ afs_GetVolume(struct VenusFid *afid, struct vrequest *areq, tv = afs_FindVolume(afid, locktype); if (!tv) { - if (afs_IsDynrootFid(afid)) { + if (afs_IsDynrootAnyFid(afid)) { tv = afs_NewDynrootVolume(afid); } else { bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume); @@ -523,6 +524,11 @@ afs_SetupVolume(afs_int32 volid, char *aname, void *ve, struct cell *tcell, } else { tv->vtix = -1; tv->rootVnode = tv->rootUnique = 0; + afs_GetDynrootMountFid(&tv->dotdot); + afs_GetDynrootMountFid(&tv->mtpoint); + tv->mtpoint.Fid.Vnode = + VNUM_FROM_TYPEID(VN_TYPE_MOUNT, tcell->cellIndex << 2); + tv->mtpoint.Fid.Unique = volid; } } tv->refCount++; diff --git a/src/afs/exporter.h b/src/afs/exporter.h index 61371b46a..14f5b86de 100644 --- a/src/afs/exporter.h +++ b/src/afs/exporter.h @@ -17,6 +17,7 @@ #define NFS_NOBODY -2 /* maps Nfs's "nobody" but since not declared by some systems (i.e. Ultrix) we use a constant */ #endif #define RMTUSER_REQ 0xabc +#define RMTUSER_REQ_PRIV 0xabe /** * There is a limitation on the number of bytes that can be passed into @@ -51,11 +52,13 @@ struct exporterops { int (*export_reqhandler) (); - int (*export_hold) (); - int (*export_rele) (); + void (*export_hold) (); + void (*export_rele) (); int (*export_sysname) (); - int (*export_garbagecollect) (); + void (*export_garbagecollect) (); int (*export_statistics) (); + int (*export_checkhost) (); + afs_int32 (*export_gethost) (); }; struct exporterstats { @@ -83,6 +86,8 @@ struct afs_exporter { #define EXP_UNIXMODE 2 #define EXP_PWSYNC 4 #define EXP_SUBMOUNTS 8 +#define EXP_CLIPAGS 16 +#define EXP_CALLBACK 32 #define AFS_NFSFULLFID 1 @@ -93,12 +98,16 @@ struct afs_exporter { (*(EXP)->exp_op->export_hold)(EXP) #define EXP_RELE(EXP) \ (*(EXP)->exp_op->export_rele)(EXP) -#define EXP_SYSNAME(EXP, INNAME, OUTNAME, NUM) \ - (*(EXP)->exp_op->export_sysname)(EXP, INNAME, OUTNAME, NUM) +#define EXP_SYSNAME(EXP, INNAME, OUTNAME, NUM, ALLPAGS) \ + (*(EXP)->exp_op->export_sysname)(EXP, INNAME, OUTNAME, NUM, ALLPAGS) #define EXP_GC(EXP, param) \ (*(EXP)->exp_op->export_garbagecollect)(EXP, param) #define EXP_STATISTICS(EXP) \ (*(EXP)->exp_op->export_statistics)(EXP) +#define EXP_CHECKHOST(EXP, HOST) \ + (*(EXP)->exp_op->export_checkhost)(EXP, HOST) +#define EXP_GETHOST(EXP) \ + (*(EXP)->exp_op->export_checkhost)(EXP) struct afs3_fid { u_short len; diff --git a/src/afs/nfsclient.h b/src/afs/nfsclient.h index 0db9d3cda..fa96f0b5b 100644 --- a/src/afs/nfsclient.h +++ b/src/afs/nfsclient.h @@ -28,6 +28,7 @@ struct nfsclientpag { afs_int32 uid; /* search based on uid and ... */ afs_int32 host; /* ... nfs client's host ip address */ afs_int32 pag; /* active pag for all (uid, host) "unpaged" conns */ + afs_int32 client_uid; /* actual UID on client */ char *sysname[MAXNUMSYSNAMES];/* user's "@sys" value; also kept in unixuser */ int sysnamecount; /* number of sysnames */ afs_int32 lastcall; /* Used for timing out nfsclientpag structs */ diff --git a/src/config/param.alpha_linux_26.h b/src/config/param.alpha_linux_26.h index 1e4e802a9..3ba85d18d 100644 --- a/src/config/param.alpha_linux_26.h +++ b/src/config/param.alpha_linux_26.h @@ -23,7 +23,6 @@ #define AFS_ALPHA_LINUX26_ENV 1 #define __alpha 1 #define AFS_LINUX_64BIT_KERNEL 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 338 diff --git a/src/config/param.amd64_linux26.h b/src/config/param.amd64_linux26.h index 0eaedbe1e..52c05ec87 100644 --- a/src/config/param.amd64_linux26.h +++ b/src/config/param.amd64_linux26.h @@ -20,7 +20,6 @@ #define AFS_AMD64_LINUX24_ENV 1 #define AFS_AMD64_LINUX26_ENV 1 #define AFS_LINUX_64BIT_KERNEL 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 183 diff --git a/src/config/param.i386_linux26.h b/src/config/param.i386_linux26.h index 7b363a70a..0ad2cd7bd 100644 --- a/src/config/param.i386_linux26.h +++ b/src/config/param.i386_linux26.h @@ -19,7 +19,6 @@ #define AFS_I386_LINUX22_ENV 1 #define AFS_I386_LINUX24_ENV 1 #define AFS_I386_LINUX26_ENV 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 137 diff --git a/src/config/param.i386_umlinux26.h b/src/config/param.i386_umlinux26.h index 0885a92b3..e16cae443 100644 --- a/src/config/param.i386_umlinux26.h +++ b/src/config/param.i386_umlinux26.h @@ -19,7 +19,6 @@ #define AFS_I386_LINUX22_ENV 1 #define AFS_I386_LINUX24_ENV 1 #define AFS_I386_LINUX26_ENV 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 137 diff --git a/src/config/param.ia64_linux26.h b/src/config/param.ia64_linux26.h index 47decbe53..d8c884a16 100644 --- a/src/config/param.ia64_linux26.h +++ b/src/config/param.ia64_linux26.h @@ -30,7 +30,6 @@ #define AFS_IA64_LINUX24_ENV 1 #define AFS_IA64_LINUX26_ENV 1 #define AFS_LINUX_64BIT_KERNEL 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 1141 diff --git a/src/config/param.ppc64_linux26.h b/src/config/param.ppc64_linux26.h index 715646a83..7a23aa1ce 100644 --- a/src/config/param.ppc64_linux26.h +++ b/src/config/param.ppc64_linux26.h @@ -18,7 +18,6 @@ #define AFS_PPC64_LINUX24_ENV 1 #define AFS_PPC64_LINUX26_ENV 1 #define AFS_LINUX_64BIT_KERNEL 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 137 diff --git a/src/config/param.ppc_linux26.h b/src/config/param.ppc_linux26.h index 49d94c7d2..c8d4e211d 100644 --- a/src/config/param.ppc_linux26.h +++ b/src/config/param.ppc_linux26.h @@ -19,7 +19,6 @@ #define AFS_PPC_LINUX22_ENV 1 #define AFS_PPC_LINUX24_ENV 1 #define AFS_PPC_LINUX26_ENV 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 137 diff --git a/src/config/param.s390_linux26.h b/src/config/param.s390_linux26.h index a06c8560b..bb99cabc3 100644 --- a/src/config/param.s390_linux26.h +++ b/src/config/param.s390_linux26.h @@ -29,7 +29,6 @@ #define AFS_S390_LINUX22_ENV 1 #define AFS_S390_LINUX24_ENV 1 #define AFS_S390_LINUX26_ENV 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 137 diff --git a/src/config/param.s390x_linux26.h b/src/config/param.s390x_linux26.h index 5ccaa9d75..f70909763 100644 --- a/src/config/param.s390x_linux26.h +++ b/src/config/param.s390x_linux26.h @@ -32,7 +32,6 @@ #define AFS_S390X_LINUX22_ENV 1 #define AFS_S390X_LINUX24_ENV 1 #define AFS_S390X_LINUX26_ENV 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 137 diff --git a/src/config/param.sparc64_linux26.h b/src/config/param.sparc64_linux26.h index 3b985d39c..4231d97b4 100644 --- a/src/config/param.sparc64_linux26.h +++ b/src/config/param.sparc64_linux26.h @@ -30,7 +30,6 @@ #define AFS_SPARC64_LINUX24_ENV 1 #define AFS_SPARC64_LINUX26_ENV 1 #define AFS_LINUX_64BIT_KERNEL 1 -#define AFS_NONFSTRANS 1 #define AFS_MOUNT_AFS "afs" /* The name of the filesystem type. */ #define AFS_SYSCALL 227 diff --git a/src/config/venus.h b/src/config/venus.h index ac9cb76fa..bf14ae30e 100644 --- a/src/config/venus.h +++ b/src/config/venus.h @@ -183,4 +183,7 @@ struct cm_initparams { #define VIOC_CBADDR _CVICEIOCTL(3) /* push callback addr */ #define VIOC_DISCON _CVICEIOCTL(5) /* set/get discon mode */ +/* OpenAFS-specific 'O' pioctl's */ +#define VIOC_NFS_NUKE_CREDS _OVICEIOCTL(1) /* nuke creds for all PAG's */ + #endif /* AFS_VENUS_H */ diff --git a/src/fsint/.cvsignore b/src/fsint/.cvsignore index a27cc9114..86c740e36 100644 --- a/src/fsint/.cvsignore +++ b/src/fsint/.cvsignore @@ -4,6 +4,10 @@ Kcallback.ss.c Kvice.cs.c Kvice.h Kvice.xdr.c +Kpagcb.cs.c +Kpagcb.ss.c +Kpagcb.h +Kpagcb.xdr.c Makefile afscbint.cs.c afscbint.h @@ -13,3 +17,4 @@ afsint.cs.c afsint.h afsint.ss.c afsint.xdr.c +pagcb.h diff --git a/src/fsint/Makefile.in b/src/fsint/Makefile.in index 40cb7dafc..cf421009d 100644 --- a/src/fsint/Makefile.in +++ b/src/fsint/Makefile.in @@ -16,7 +16,10 @@ all: \ depinstall: \ ${TOP_INCDIR}/afs/afsint.h \ ${TOP_INCDIR}/afs/afscbint.h \ - Kcallback.ss.c Kcallback.h Kvice.cs.c Kvice.h Kvice.xdr.c afscbint.h afsint.h + ${TOP_INCDIR}/afs/pagcb.h \ + Kcallback.ss.c Kcallback.h Kvice.cs.c Kvice.h Kvice.xdr.c \ + Kpagcb.ss.c Kpagcb.h Kpagcb.cs.c Kpagcb.xdr.c \ + afscbint.h afsint.h pagcb.h libafsint.a: ${OBJS} AFS_component_version_number.o -$(RM) -f $@ @@ -46,6 +49,21 @@ Kvice.xdr.c: common.xg afsint.xg Kvice.h: common.xg afsint.xg ${RXGEN} -x -k -h -o Kvice.h ${srcdir}/afsint.xg +Kpagcb.cs.c: pagcb.xg Kpagcb.h + ${RXGEN} -x -k -C -o Kpagcb.cs.c ${srcdir}/pagcb.xg + +Kpagcb.ss.c: pagcb.xg Kpagcb.h + ${RXGEN} -x -k -S -o Kpagcb.ss.c ${srcdir}/pagcb.xg + +Kpagcb.xdr.c: pagcb.xg + ${RXGEN} -x -k -c -o Kpagcb.xdr.c ${srcdir}/pagcb.xg + +Kpagcb.h: pagcb.xg + ${RXGEN} -x -k -h -o Kpagcb.h ${srcdir}/pagcb.xg + +pagcb.h: pagcb.xg + ${RXGEN} -x -h -o pagcb.h ${srcdir}/pagcb.xg + Kcallback.h: common.xg afscbint.xg ${RXGEN} -x -k -h -o Kcallback.h ${srcdir}/afscbint.xg @@ -85,6 +103,9 @@ ${TOP_INCDIR}/afs/afsint.h: afsint.h ${TOP_INCDIR}/afs/afscbint.h: afscbint.h ${INSTALL} $? $@ +${TOP_INCDIR}/afs/pagcb.h: pagcb.h + ${INSTALL} $? $@ + install: \ ${DESTDIR}${libdir}/afs/libafsint.a \ ${DESTDIR}${includedir}/afs/afsint.h \ @@ -119,8 +140,8 @@ ${DEST}/include/afs/afsint.h: afsint.h clean: $(RM) -f *.o *.cs.c *.ss.c *.er.c *.a *.xdr.c core \ - afsint.h afscbint.h AFS_component_version_number.c \ - Kvice.h Kcallback.h + afsint.h afscbint.h pagcb.h AFS_component_version_number.c \ + Kvice.h Kcallback.h Kpagcb.h include ../config/Makefile.version diff --git a/src/fsint/pagcb.xg b/src/fsint/pagcb.xg new file mode 100644 index 000000000..d6b6ab495 --- /dev/null +++ b/src/fsint/pagcb.xg @@ -0,0 +1,58 @@ +/* + * 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 + */ + +/* + * pagcb.xg: + * Definition of the PAG Manager callback RPC interface. + */ + +package PAGCB_ +prefix S +statindex 21 +%#define PAGCB_SERVICEID 2 + +const PAGCB_MAXREALMLEN = 256; +const PAGCB_MAXTICKETLEN = 12000; +const PAGCB_MAXCREDS = 256; +const PAGCB_MAXSYSNAMELEN = 128; +const PAGCB_MAXSYSNAMES = 16; + +struct PAGCB_ClearToken { + afs_int32 AuthHandle; + char HandShakeKey[8]; + afs_int32 ViceId; + afs_int32 BeginTimestamp; + afs_int32 EndTimestamp; +}; + +struct CredInfo { + string cellname; + afs_int32 vid; + afs_int32 states; + PAGCB_ClearToken ct; + opaque st; +}; + +typedef CredInfo CredInfos; + +struct SysNameEnt { + string sysname; +}; + +typedef SysNameEnt SysNameList; + +proc GetCreds( + IN afs_int32 uid, + OUT CredInfos *creds +) = 1; + +proc GetSysName( + IN afs_int32 uid, + OUT SysNameList *sysnames +) = 2; diff --git a/src/libafs/Makefile.common.in b/src/libafs/Makefile.common.in index 351949ddc..9edba2433 100644 --- a/src/libafs/Makefile.common.in +++ b/src/libafs/Makefile.common.in @@ -12,6 +12,7 @@ INCLUDE= -I. -I/usr/include -I${TOP_OBJDIR}/src/config TOP_OBJ_FSINT = ${TOP_OBJDIR}/src/fsint TOP_OBJ_RXSTAT = ${TOP_OBJDIR}/src/rxstat +TOP_OBJ_SYS = ${TOP_OBJDIR}/src/sys TOP_OBJ_VLSERVER = ${TOP_OBJDIR}/src/vlserver TOP_SRC_AFS = ${TOP_SRCDIR}/afs @@ -85,19 +86,25 @@ AFSAOBJS = \ afs_dcache.o \ afs_dir.o \ afs_dynroot.o \ + afs_error.o \ + afs_icl.o \ afs_init.o \ afs_lock.o \ afs_mariner.o \ + afs_md5.o \ afs_memcache.o \ afs_osi.o \ afs_osidnlc.o \ afs_osi_alloc.o \ + afs_osi_gcpags.o \ afs_osi_pag.o \ afs_osi_uio.o \ afs_osi_vget.o \ + afs_osi_vm.o \ afs_segments.o \ afs_server.o \ afs_stat.o \ + afs_syscall.o \ afs_user.o \ afs_util.o \ afs_vcache.o \ @@ -161,6 +168,8 @@ AFSNFSOBJS = \ afs_nfsdisp.o \ afs_call_nfs.o \ afs_pioctl_nfs.o \ + Kpagcb.cs.o \ + Kpagcb.xdr.o \ $(AFS_OS_NFSOBJS) AFSNONFSOBJS = \ @@ -168,6 +177,53 @@ AFSNONFSOBJS = \ afs_pioctl.o \ $(AFS_OS_NONFSOBJS) +# init daemons call pioctl +AFSPAGOBJS = \ + afs_atomlist.o \ + afs_error.o \ + afs_icl.o \ + afs_lhash.o \ + afs_lock.o \ + afs_osi.o \ + afs_osi_alloc.o \ + afs_osi_gcpags.o \ + afs_osi_pag.o \ + afs_pag_call.o \ + afs_pag_cred.o \ + afs_pag_user.o \ + afs_stat.o \ + afs_syscall.o \ + afsaux.o \ + xdr_arrayn.o \ + xdr_array.o \ + xdr_int32.o \ + xdr_int64.o \ + rx.o \ + rx_rdwr.o \ + rx_clock.o \ + rx_event.o \ + rx_globals.o \ + rx_kmutex.o \ + rx_knet.o \ + rx_kcommon.o \ + rx_misc.o \ + rx_null.o \ + rx_getaddr.o \ + rx_packet.o \ + rx_multi.o \ + xdr_rx.o \ + Kpagcb.ss.o \ + Kpagcb.xdr.o \ + Krxstat.ss.o \ + Krxstat.xdr.o \ + Krmtsys.cs.o \ + Krmtsys.xdr.o \ + rxstat.o \ + AFS_component_version_number.o\ + xdr_afsuuid.o \ + xdr.o \ + afs_uuid.o $(AFS_OS_PAGOBJS) + # Compilation rules # These files are to be optimized @@ -191,22 +247,30 @@ afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c $(CRULE_OPT) afs_dynroot.o: $(TOP_SRC_AFS)/afs_dynroot.c $(CRULE_OPT) +afs_error.o: $(TOP_SRC_AFS)/afs_error.c + $(CRULE_OPT) afs_init.o: $(TOP_SRC_AFS)/afs_init.c $(CRULE_OPT) afs_mariner.o: $(TOP_SRC_AFS)/afs_mariner.c $(CRULE_OPT) +afs_md5.o: $(TOP_SRC_AFS)/afs_md5.c + $(CRULE_OPT) afs_osidnlc.o: $(TOP_SRC_AFS)/afs_osidnlc.c $(CRULE_OPT) afs_osi.o: $(TOP_SRC_AFS)/afs_osi.c $(CRULE_OPT) afs_osi_alloc.o: $(TOP_SRC_AFS)/afs_osi_alloc.c $(CRULE_OPT) +afs_osi_gcpags.o: $(TOP_SRC_AFS)/afs_osi_gcpags.c + $(CRULE_OPT) afs_osi_pag.o: $(TOP_SRC_AFS)/afs_osi_pag.c $(CRULE_OPT) afs_osi_uio.o: $(TOP_SRC_AFS)/afs_osi_uio.c $(CRULE_OPT) afs_osi_vget.o: $(TOP_SRC_AFS)/afs_osi_vget.c $(CRULE_NOOPT) +afs_osi_vm.o: $(TOP_SRC_AFS)/afs_osi_vm.c + $(CRULE_OPT) afs_segments.o: $(TOP_SRC_AFS)/afs_segments.c $(CRULE_OPT) afs_server.o: $(TOP_SRC_AFS)/afs_server.c @@ -269,14 +333,22 @@ afs_daemons.o: $(TOP_SRC_AFS)/afs_daemons.c $(CRULE_NOOPT) afs_dir.o: $(TOP_SRCDIR)/dir/dir.c $(CRULE_NOOPT) +afs_icl.o: $(TOP_SRC_AFS)/afs_icl.c + $(CRULE_NOOPT) AFS_component_version_number.o: AFS_component_version_number.c $(CRULE_NOOPT) afs_lock.o: $(TOP_SRC_AFS)/afs_lock.c $(CRULE_NOOPT) afs_memcache.o: $(TOP_SRC_AFS)/afs_memcache.c $(CRULE_NOOPT) +afs_pag_call.o: $(TOP_SRC_AFS)/afs_pag_call.c + $(CRULE_NOOPT) +afs_pag_cred.o: $(TOP_SRC_AFS)/afs_pag_cred.c + $(CRULE_NOOPT) afs_stat.o: $(TOP_SRC_AFS)/afs_stat.c $(CRULE_NOOPT) +afs_syscall.o: $(TOP_SRC_AFS)/afs_syscall.c + $(CRULE_NOOPT) fcrypt.o: $(TOP_SRC_RXKAD)/domestic/fcrypt.c $(CRULE_NOOPT) crypt_conn.o: $(TOP_SRC_RXKAD)/domestic/crypt_conn.c @@ -315,6 +387,12 @@ Kcallback.ss.o: $(TOP_OBJ_FSINT)/Kcallback.ss.c $(CRULE_NOOPT) rxstat.o: $(TOP_SRC_RXSTAT)/rxstat.c $(CRULE_NOOPT) +Kpagcb.cs.o: $(TOP_OBJ_FSINT)/Kpagcb.cs.c + $(CRULE_NOOPT) +Kpagcb.ss.o: $(TOP_OBJ_FSINT)/Kpagcb.ss.c + $(CRULE_NOOPT) +Kpagcb.xdr.o: $(TOP_OBJ_FSINT)/Kpagcb.xdr.c + $(CRULE_NOOPT) Krxstat.ss.o: $(TOP_OBJ_RXSTAT)/Krxstat.ss.c $(CRULE_NOOPT) Krxstat.xdr.o: $(TOP_OBJ_RXSTAT)/Krxstat.xdr.c @@ -323,6 +401,10 @@ Kvice.xdr.o: $(TOP_OBJ_FSINT)/Kvice.xdr.c $(CRULE_NOOPT) Kvice.cs.o: $(TOP_OBJ_FSINT)/Kvice.cs.c $(CRULE_NOOPT) +Krmtsys.xdr.o: $(TOP_OBJ_SYS)/Krmtsys.xdr.c + $(CRULE_NOOPT) +Krmtsys.cs.o: $(TOP_OBJ_SYS)/Krmtsys.cs.c + $(CRULE_NOOPT) afsaux.o: $(TOP_SRC_FSINT)/afsaux.c $(CRULE_NOOPT) xdr_arrayn.o: $(TOP_SRC_RX)/xdr_arrayn.c @@ -361,6 +443,10 @@ afs_call_nfs.o: $(TOP_SRC_AFS)/afs_call.c afs_pioctl_nfs.o: $(TOP_SRC_AFS)/afs_pioctl.c $(CRULE_NOOPT) +# Special objects for the PAG module +afs_pag_user.o: $(TOP_SRC_AFS)/afs_user.c + $(CRULE_OPT) -DAFS_PAG_MANAGER + # Files which are specific to particular architectures/targets # but have common build rules. Place here instead of duplicating # in the per-platform Makefiles. @@ -386,8 +472,14 @@ osi_vnodeops.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_vnodeops.c $(CRULE_NOOPT) osi_debug.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_debug.c $(CRULE_OPT) +osi_ioctl.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_ioctl.c + $(CRULE_NOOPT) osi_module.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_module.c $(CRULE_NOOPT) +osi_pag_module.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_pag_module.c + $(CRULE_NOOPT) +osi_proc.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_proc.c + $(CRULE_NOOPT) osi_probe.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_probe.c $(CRULE_NOOPT) osi_syscall.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_syscall.c @@ -396,6 +488,10 @@ osi_sysctl.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_sysctl.c $(CRULE_NOOPT) osi_flush.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_flush.s $(CRULE_OPT) +osi_export.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_export.c + $(CRULE_NOOPT) +osi_nfssrv.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_nfssrv.c + $(CRULE_NOOPT) osi_alloc.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_alloc.c $(CRULE_NOOPT) osi_cred.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_cred.c diff --git a/src/libafs/MakefileProto.LINUX.in b/src/libafs/MakefileProto.LINUX.in index 6b7895d6f..c70d25566 100644 --- a/src/libafs/MakefileProto.LINUX.in +++ b/src/libafs/MakefileProto.LINUX.in @@ -26,9 +26,31 @@ AFS_OS_OBJS = \ osi_vm.o \ osi_flush.o \ + + osi_export.o \ + osi_nfssrv.o \ + + osi_ioctl.o \ + osi_proc.o \ osi_vnodeops.o +AFS_OS_PAGOBJS = \ + osi_alloc.o \ + osi_cred.o \ + osi_groups.o \ + osi_inode.o \ + osi_misc.o \ + osi_probe.o \ + osi_sleep.o \ + osi_syscall.o \ + + osi_flush.o \ + + osi_ioctl.o \ + + osi_pag_module.o + AFS_OS_NFSOBJS = AFS_OS_NONFSOBJS = @@ -46,6 +68,9 @@ LINUX_KERNEL_PATH=@LINUX_KERNEL_PATH@ CCFLAGS = -Wno-strict-prototypes DEFINES = $(COMMON_DEFINES) +# CFLAGS_* and AFLAGS_* will be copied into the kbuild makefile +CFLAGS_afs_pag_user.o = -DAFS_PAG_MANAGER + CCFLAGS = $(COMMON_KERN_CFLAGS) @P5PLUS_KOPTS@ DEFINES = $(COMMON_DEFINES) -DCPU=586 @@ -255,8 +280,8 @@ ${LIBAFS} ${LIBAFS_MP} ${LIBAFS_EP} ${LIBAFS_BM}: libafs.ko cp libafs.ko $@ .FORCE: -libafs.ko: .FORCE - env EXTRA_CFLAGS="${EXTRA_CFLAGS}" @TOP_SRCDIR@/libafs/make_kbuild_makefile.pl ${KDIR} $@ @TOP_OBJDIR@/src/config/Makefile.config Makefile.afs Makefile.common +libafs.ko afspag.ko: .FORCE + env EXTRA_CFLAGS="${EXTRA_CFLAGS}" @TOP_SRCDIR@/libafs/make_kbuild_makefile.pl ${KDIR} @TOP_OBJDIR@/src/config/Makefile.config Makefile.afs Makefile.common env EXTRA_CFLAGS="${EXTRA_CFLAGS}" $(MAKE) -C ${LINUX_KERNEL_PATH} M=@TOP_OBJDIR@/src/libafs/${KDIR} modules diff --git a/src/libafs/make_kbuild_makefile.pl b/src/libafs/make_kbuild_makefile.pl index ce046e172..dc6e31130 100755 --- a/src/libafs/make_kbuild_makefile.pl +++ b/src/libafs/make_kbuild_makefile.pl @@ -2,25 +2,26 @@ # make_kbuild_makefile.pl # Generate a Makefile for use with the Linux 2.6+ kernel build system # -# Usage: make_kbuild_makefile.pl ${KDIR} ${TARG} Makefiles... +# Usage: make_kbuild_makefile.pl ${KDIR} Makefiles... # # The specified makefiles will be scanned for variable values -# The module ${TARG} will be built in ${TOP_SRCDIR}/src/libafs/${KDIR}. -# It will include objects listed in ${AFSAOBJS} and ${AFSNONFSOBJS} +# The libafs.ko module will be built in ${TOP_SRCDIR}/src/libafs/${KDIR}. +# It will include objects listed in ${AFSAOBJS} and ${AFSNFSOBJS} +# The afspag.ko module will be built from objects listed in ${AFSPAGOBJS}. # Appropriate source files for each object will be symlinked into ${KDIR} # EXTRA_CFLAGS will be set to ${CFLAGS} ${COMMON_INCLUDE} +# Any CFLAGS_* and AFLAGS_* variables will be copied # Produces ${KDIR}/Makefile, suitable for use with kbuild use IO::File; -if (@ARGV < 3) { - die "Usage: echo objects... | $0 KDIR TARG Makefiles...\n"; +if (@ARGV < 2) { + die "Usage: $0 KDIR Makefiles...\n"; } -($KDIR, $TARG, @Makefiles) = @ARGV; -$TARG =~ s/\.k?o$//; +($KDIR, @Makefiles) = @ARGV; ## Read in all of the Makefiles given on the command line ## Our ultimate goal is to find the correct source file for each object. @@ -61,7 +62,8 @@ foreach $mf (@Makefiles) { $KDIR = "$vars{TOP_OBJDIR}/src/libafs/$KDIR"; -@objects = (split(' ', $vars{AFSAOBJS}), split(' ', $vars{AFSNONFSOBJS})); +@libafs_objs = (split(' ', $vars{AFSAOBJS}), split(' ', $vars{AFSNFSOBJS})); +@afspag_objs = (split(' ', $vars{AFSPAGOBJS})); $MV = new IO::File("$vars{TOP_OBJDIR}/src/config/Makefile.version", O_RDONLY) or die "$vars{TOP_OBJDIR}/src/config/Makefile.version: $!\n"; @@ -75,8 +77,9 @@ if (! -d $KDIR) { mkdir($KDIR, 0777) or die "$KDIR: $!\n"; } +%all_objs = map(($_ => 1), @libafs_objs, @afspag_objs); -foreach (@objects) { +foreach (keys %all_objs) { die "No source known for $_\n" unless exists $deps{$_}; if($deps{$_} =~ /\.s$/) { ($src = $_) =~ s/\.o$/.s/; @@ -103,9 +106,14 @@ $cflags =~ s#-I(?!/)#-I$KDIR/#g; $cflags =~ s/\s+/ \\\n /g; $F = new IO::File("$KDIR/Makefile", O_WRONLY|O_CREAT|O_TRUNC, 0666) or die "$KDIR/Makefile: $!\n"; +foreach (sort keys %vars) { + next unless /^[AC]FLAGS_/; + print $F "$_ = $vars{$_}\n"; +} print $F "EXTRA_CFLAGS=$cflags\n"; -print $F "obj-m := $TARG.o\n"; -print $F "$TARG-objs := ", join("\\\n $_", @objects), "\n"; +print $F "obj-m := libafs.o afspag.o\n"; +print $F "libafs-objs := ", join("\\\n $_", @libafs_objs), "\n"; +print $F "afspag-objs := ", join("\\\n $_", @afspag_objs), "\n"; print $F "\n$MakefileVersion\n"; $F->close() or die "$KDIR/Makefile: $!\n"; diff --git a/src/libuafs/Makefile.common.in b/src/libuafs/Makefile.common.in index cef7299c4..0ec920275 100644 --- a/src/libuafs/Makefile.common.in +++ b/src/libuafs/Makefile.common.in @@ -87,6 +87,7 @@ UAFSOBJ = \ $(UOBJ)/afs_atomlist.o \ $(UOBJ)/afs_lhash.o \ $(UOBJ)/afs_analyze.o \ + $(UOBJ)/afs_error.o \ $(UOBJ)/afs_axscache.o \ $(UOBJ)/afs_buffer.o \ $(UOBJ)/afs_callback.o \ @@ -98,15 +99,18 @@ UAFSOBJ = \ $(UOBJ)/afs_dcache.o \ $(UOBJ)/afs_dir.o \ $(UOBJ)/afs_dynroot.o \ + $(UOBJ)/afs_icl.o \ $(UOBJ)/afs_init.o \ $(UOBJ)/afs_lock.o \ $(UOBJ)/afs_mariner.o \ $(UOBJ)/afs_memcache.o \ + $(UOBJ)/afs_md5.o \ $(UOBJ)/afs_osidnlc.o \ $(UOBJ)/afs_osi_pag.o \ $(UOBJ)/afs_segments.o \ $(UOBJ)/afs_server.o \ $(UOBJ)/afs_stat.o \ + $(UOBJ)/afs_syscall.o \ $(UOBJ)/afs_user.o \ $(UOBJ)/afs_util.o \ $(UOBJ)/afs_vcache.o \ @@ -208,6 +212,7 @@ AFSWEBOBJ = \ $(WEBOBJ)/afs_atomlist.o \ $(WEBOBJ)/afs_lhash.o \ $(WEBOBJ)/afs_analyze.o \ + $(WEBOBJ)/afs_error.o \ $(WEBOBJ)/afs_axscache.o \ $(WEBOBJ)/afs_buffer.o \ $(WEBOBJ)/afs_callback.o \ @@ -219,15 +224,18 @@ AFSWEBOBJ = \ $(WEBOBJ)/afs_dcache.o \ $(WEBOBJ)/afs_dir.o \ $(WEBOBJ)/afs_dynroot.o \ + $(WEBOBJ)/afs_icl.o \ $(WEBOBJ)/afs_init.o \ $(WEBOBJ)/afs_lock.o \ $(WEBOBJ)/afs_mariner.o \ $(WEBOBJ)/afs_memcache.o \ + $(WEBOBJ)/afs_md5.o \ $(WEBOBJ)/afs_osidnlc.o \ $(WEBOBJ)/afs_osi_pag.o \ $(WEBOBJ)/afs_segments.o \ $(WEBOBJ)/afs_server.o \ $(WEBOBJ)/afs_stat.o \ + $(WEBOBJ)/afs_syscall.o \ $(WEBOBJ)/afs_user.o \ $(WEBOBJ)/afs_util.o \ $(WEBOBJ)/afs_vcache.o \ @@ -330,6 +338,7 @@ AFSWEBOBJKRB = \ $(WEBOBJ)/afs_atomlist.o \ $(WEBOBJ)/afs_lhash.o \ $(WEBOBJ)/afs_analyze.o \ + $(WEBOBJ)/afs_error.o \ $(WEBOBJ)/afs_axscache.o \ $(WEBOBJ)/afs_buffer.o \ $(WEBOBJ)/afs_callback.o \ @@ -341,15 +350,18 @@ AFSWEBOBJKRB = \ $(WEBOBJ)/afs_dcache.o \ $(WEBOBJ)/afs_dir.o \ $(WEBOBJ)/afs_dynroot.o \ + $(WEBOBJ)/afs_icl.o \ $(WEBOBJ)/afs_init.o \ $(WEBOBJ)/afs_lock.o \ $(WEBOBJ)/afs_mariner.o \ $(WEBOBJ)/afs_memcache.o \ + $(WEBOBJ)/afs_md5.o \ $(WEBOBJ)/afs_osidnlc.o \ $(WEBOBJ)/afs_osi_pag.o \ $(WEBOBJ)/afs_segments.o \ $(WEBOBJ)/afs_server.o \ $(WEBOBJ)/afs_stat.o \ + $(WEBOBJ)/afs_syscall.o \ $(WEBOBJ)/afs_user.o \ $(WEBOBJ)/afs_util.o \ $(WEBOBJ)/afs_vcache.o \ @@ -447,6 +459,7 @@ JUAFSOBJ = \ $(JUAFS)/afs_atomlist.o \ $(JUAFS)/afs_lhash.o \ $(JUAFS)/afs_analyze.o \ + $(JUAFS)/afs_error.o \ $(JUAFS)/afs_axscache.o \ $(JUAFS)/afs_buffer.o \ $(JUAFS)/afs_callback.o \ @@ -458,15 +471,18 @@ JUAFSOBJ = \ $(JUAFS)/afs_dcache.o \ $(JUAFS)/afs_dir.o \ $(JUAFS)/afs_dynroot.o \ + $(JUAFS)/afs_icl.o \ $(JUAFS)/afs_init.o \ $(JUAFS)/afs_lock.o \ $(JUAFS)/afs_mariner.o \ $(JUAFS)/afs_memcache.o \ + $(JUAFS)/afs_md5.o \ $(JUAFS)/afs_osidnlc.o \ $(JUAFS)/afs_osi_pag.o \ $(JUAFS)/afs_segments.o \ $(JUAFS)/afs_server.o \ $(JUAFS)/afs_stat.o \ + $(JUAFS)/afs_syscall.o \ $(JUAFS)/afs_user.o \ $(JUAFS)/afs_util.o \ $(JUAFS)/afs_vcache.o \ @@ -584,6 +600,8 @@ $(UOBJ)/afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c $(CRULE1) $(UOBJ)/afs_dynroot.o: $(TOP_SRC_AFS)/afs_dynroot.c $(CRULE1) +$(UOBJ)/afs_error.o: $(TOP_SRC_AFS)/afs_error.c + $(CRULE1) $(UOBJ)/afs_init.o: $(TOP_SRC_AFS)/afs_init.c $(CRULE1) $(UOBJ)/afs_mariner.o: $(TOP_SRC_AFS)/afs_mariner.c @@ -658,6 +676,8 @@ $(UOBJ)/afs_lock.o: $(TOP_SRC_AFS)/afs_lock.c $(CRULE1) $(UOBJ)/afs_memcache.o: $(TOP_SRC_AFS)/afs_memcache.c $(CRULE1) +$(UOBJ)/afs_md5.o: $(TOP_SRC_AFS)/afs_md5.c + $(CRULE1) $(UOBJ)/afs_stat.o: $(TOP_SRC_AFS)/afs_stat.c $(CRULE1) $(UOBJ)/fcrypt.o: $(TOP_SRC_RXKAD)/domestic/fcrypt.c @@ -736,8 +756,12 @@ $(UOBJ)/rx_kcommon.o: $(TOP_SRCDIR)/rx/rx_kcommon.c $(CRULE1) $(UOBJ)/afs_call.o: $(TOP_SRC_AFS)/afs_call.c $(CRULE1) -DAFS_NONFSTRANS +$(UOBJ)/afs_icl.o: $(TOP_SRC_AFS)/afs_icl.c + $(CRULE1) -DAFS_NONFSTRANS $(UOBJ)/afs_pioctl.o: $(TOP_SRC_AFS)/afs_pioctl.c $(CRULE1) -DAFS_NONFSTRANS +$(UOBJ)/afs_syscall.o: $(TOP_SRC_AFS)/afs_syscall.c + $(CRULE1) -DAFS_NONFSTRANS $(UOBJ)/osi_vfsops.o: $(TOP_SRC_AFS)/UKERNEL/osi_vfsops.c $(CRULE1) -DAFS_NONFSTRANS $(UOBJ)/ktc.o: $(TOP_SRCDIR)/auth/ktc.c @@ -833,6 +857,8 @@ $(WEBOBJ)/afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c $(CRULE2) $(WEBOBJ)/afs_dynroot.o: $(TOP_SRC_AFS)/afs_dynroot.c $(CRULE2) +$(WEBOBJ)/afs_error.o: $(TOP_SRC_AFS)/afs_error.c + $(CRULE2) $(WEBOBJ)/afs_init.o: $(TOP_SRC_AFS)/afs_init.c $(CRULE2) $(WEBOBJ)/afs_mariner.o: $(TOP_SRC_AFS)/afs_mariner.c @@ -907,6 +933,8 @@ $(WEBOBJ)/afs_lock.o: $(TOP_SRC_AFS)/afs_lock.c $(CRULE2) $(WEBOBJ)/afs_memcache.o: $(TOP_SRC_AFS)/afs_memcache.c $(CRULE2) +$(WEBOBJ)/afs_md5.o: $(TOP_SRC_AFS)/afs_md5.c + $(CRULE2) $(WEBOBJ)/afs_stat.o: $(TOP_SRC_AFS)/afs_stat.c $(CRULE2) $(WEBOBJ)/fcrypt.o: $(TOP_SRC_RXKAD)/domestic/fcrypt.c @@ -981,8 +1009,12 @@ $(WEBOBJ)/rx_kcommon.o: $(TOP_SRCDIR)/rx/rx_kcommon.c $(CRULE2) $(WEBOBJ)/afs_call.o: $(TOP_SRC_AFS)/afs_call.c $(CRULE2) -DAFS_NONFSTRANS +$(WEBOBJ)/afs_icl.o: $(TOP_SRC_AFS)/afs_icl.c + $(CRULE2) -DAFS_NONFSTRANS $(WEBOBJ)/afs_pioctl.o: $(TOP_SRC_AFS)/afs_pioctl.c $(CRULE2) -DAFS_NONFSTRANS +$(WEBOBJ)/afs_syscall.o: $(TOP_SRC_AFS)/afs_syscall.c + $(CRULE2) -DAFS_NONFSTRANS $(WEBOBJ)/osi_vfsops.o: $(TOP_SRC_AFS)/UKERNEL/osi_vfsops.c $(CRULE2) -DAFS_NONFSTRANS $(WEBOBJ)/ktc.o: $(TOP_SRCDIR)/auth/ktc.c @@ -1086,6 +1118,8 @@ $(JUAFS)/afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c $(CRULE1) $(JUAFS)/afs_dynroot.o: $(TOP_SRC_AFS)/afs_dynroot.c $(CRULE1) +$(JUAFS)/afs_error.o: $(TOP_SRC_AFS)/afs_error.c + $(CRULE1) $(JUAFS)/afs_init.o: $(TOP_SRC_AFS)/afs_init.c $(CRULE1) $(JUAFS)/afs_mariner.o: $(TOP_SRC_AFS)/afs_mariner.c @@ -1160,6 +1194,8 @@ $(JUAFS)/afs_lock.o: $(TOP_SRC_AFS)/afs_lock.c $(CRULE1) $(JUAFS)/afs_memcache.o: $(TOP_SRC_AFS)/afs_memcache.c $(CRULE1) +$(JUAFS)/afs_md5.o: $(TOP_SRC_AFS)/afs_md5.c + $(CRULE1) $(JUAFS)/afs_stat.o: $(TOP_SRC_AFS)/afs_stat.c $(CRULE1) $(JUAFS)/fcrypt.o: $(TOP_SRC_RXKAD)/domestic/fcrypt.c @@ -1234,8 +1270,12 @@ $(JUAFS)/rx_kcommon.o: $(TOP_SRCDIR)/rx/rx_kcommon.c $(CRULE1) $(JUAFS)/afs_call.o: $(TOP_SRC_AFS)/afs_call.c $(CRULE1) -DAFS_NONFSTRANS +$(JUAFS)/afs_icl.o: $(TOP_SRC_AFS)/afs_icl.c + $(CRULE1) -DAFS_NONFSTRANS $(JUAFS)/afs_pioctl.o: $(TOP_SRC_AFS)/afs_pioctl.c $(CRULE1) -DAFS_NONFSTRANS +$(JUAFS)/afs_syscall.o: $(TOP_SRC_AFS)/afs_syscall.c + $(CRULE1) -DAFS_NONFSTRANS $(JUAFS)/osi_vfsops.o: $(TOP_SRC_AFS)/UKERNEL/osi_vfsops.c $(CRULE1) -DAFS_NONFSTRANS $(JUAFS)/ktc.o: $(TOP_SRCDIR)/auth/ktc.c diff --git a/src/sys/.cvsignore b/src/sys/.cvsignore index d1a117f66..a77e3af91 100644 --- a/src/sys/.cvsignore +++ b/src/sys/.cvsignore @@ -11,3 +11,6 @@ rmtsys.xdr.c rmtsysd afs.exp afsl.exp +Krmtsys.cs.c +Krmtsys.h +Krmtsys.xdr.c diff --git a/src/sys/Makefile.in b/src/sys/Makefile.in index 69c3d08e4..9bd7e8c3b 100644 --- a/src/sys/Makefile.in +++ b/src/sys/Makefile.in @@ -139,6 +139,15 @@ rmtsys.xdr.c: rmtsys.xg rmtsys.h: rmtsys.xg ${RXGEN} -h -o $@ ${srcdir}/rmtsys.xg +Krmtsys.cs.c: rmtsys.xg Krmtsys.h + ${RXGEN} -k -C -o Krmtsys.cs.c ${srcdir}/rmtsys.xg + +Krmtsys.xdr.c: rmtsys.xg + ${RXGEN} -k -c -o Krmtsys.xdr.c ${srcdir}/rmtsys.xg + +Krmtsys.h: rmtsys.xg + ${RXGEN} -k -h -o Krmtsys.h ${srcdir}/rmtsys.xg + rmtsysd: rmtsysd.o libsys.a ${CC} ${CFLAGS} -o rmtsysd rmtsysd.o ${LIBS} @@ -223,6 +232,9 @@ afsl.exp: ${srcdir}/afsl4.exp ${srcdir}/afsl5.exp ${TOP_INCDIR}/afs/afssyscalls.h: afssyscalls.h ${INSTALL} $? $@ +${TOP_INCDIR}/afs/rmtsys.h: rmtsys.h + ${INSTALL} $? $@ + ${TOP_INCDIR}/afs/afs.exp: afs.exp @set -x; case ${SYS_NAME} in \ rs_aix* ) \ @@ -258,10 +270,12 @@ ${KERNELDIR}/afs/xfsattrs.h: xfsattrs.h depinstall: \ ${TOP_INCDIR}/afs/afssyscalls.h \ + ${TOP_INCDIR}/afs/rmtsys.h \ ${TOP_INCDIR}/afs/afs.exp \ ${TOP_INCDIR}/afs/xfsattrs.h \ ${KERNELDIR}/afs/xfsattrs.h \ - ${UKERNELDIR}/afs/afsl.exp + ${UKERNELDIR}/afs/afsl.exp \ + Krmtsys.cs.c Krmtsys.h Krmtsys.xdr.c rmtsys.h install: \ ${DESTDIR}${libdir}/afs/libsys.a \ diff --git a/src/sys/rmtsys.xg b/src/sys/rmtsys.xg index dd4c46902..18058d5b6 100644 --- a/src/sys/rmtsys.xg +++ b/src/sys/rmtsys.xg @@ -10,6 +10,7 @@ package RMTSYS_ statindex 10 prefix S +const RMTSYS_MAXPATHLEN = 4096; #define MAXPATHLEN 4096 %#include diff --git a/src/venus/fs.c b/src/venus/fs.c index 1b2b7a10f..a17c984f5 100644 --- a/src/venus/fs.c +++ b/src/venus/fs.c @@ -2197,6 +2197,37 @@ CallBackRxConnCmd(struct cmd_syndesc *as, char *arock) return 0; } +static int +NukeNFSCredsCmd(struct cmd_syndesc *as, char *arock) +{ + afs_int32 code; + struct ViceIoctl blob; + struct cmd_item *ti; + afs_int32 hostAddr; + struct hostent *thp; + + ti = as->parms[0].items; + thp = hostutil_GetHostByName(ti->data); + if (!thp) { + fprintf(stderr, "host %s not found in host table.\n", ti->data); + return 1; + } + else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32)); + + /* now do operation */ + blob.in_size = sizeof(afs_int32); + blob.out_size = sizeof(afs_int32); + blob.in = (char *) &hostAddr; + blob.out = (char *) &hostAddr; + + code = pioctl(0, VIOC_NFS_NUKE_CREDS, &blob, 1); + if (code < 0) { + Die(errno, 0); + return 1; + } + return 0; +} + static int NewCellCmd(struct cmd_syndesc *as, char *arock) { @@ -2521,7 +2552,7 @@ ExportAfsCmd(struct cmd_syndesc *as, char *arock) struct ViceIoctl blob; struct cmd_item *ti; int export = 0, type = 0, mode = 0, exp = 0, exportcall, pwsync = - 0, smounts = 0; + 0, smounts = 0, clipags = 0, pagcb = 0; ti = as->parms[0].items; if (strcmp(ti->data, "nfs") == 0) @@ -2574,8 +2605,29 @@ ExportAfsCmd(struct cmd_syndesc *as, char *arock) return 1; } } + if (ti = as->parms[5].items) { /* -clipags */ + if (strcmp(ti->data, "on") == 0) + clipags = 3; + else if (strcmp(ti->data, "off") == 0) + clipags = 2; + else { + fprintf(stderr, "Illegal argument %s\n", ti->data); + return 1; + } + } + if (ti = as->parms[6].items) { /* -pagcb */ + if (strcmp(ti->data, "on") == 0) + pagcb = 3; + else if (strcmp(ti->data, "off") == 0) + pagcb = 2; + else { + fprintf(stderr, "Illegal argument %s\n", ti->data); + return 1; + } + } exportcall = - (type << 24) | (mode << 6) | (pwsync << 4) | (smounts << 2) | export; + (type << 24) | (pagcb << 10) | (clipags << 8) | + (mode << 6) | (pwsync << 4) | (smounts << 2) | export; type &= ~0x70; /* make the call */ blob.in = (char *)&exportcall; @@ -2606,6 +2658,13 @@ ExportAfsCmd(struct cmd_syndesc *as, char *arock) printf("\t%s\n", (exportcall & 8 ? "Allow mounts of /afs/.. subdirs" : "Only mounts to /afs allowed")); + printf("\t%s\n", + (exportcall & 16 ? "Client-assigned PAG's are used" : + "Client-assigned PAG's are not used")); + printf("\t%s\n", + (exportcall & 32 ? + "Callbacks are made to get creds from new clients" : + "Callbacks are not made to get creds from new clients")); } else { printf("'%s' translator is disabled\n", exported_types[type]); } @@ -3509,6 +3568,10 @@ defect 3069 "run on strict 'uid check' mode (on | off)"); cmd_AddParm(ts, "-submounts", CMD_SINGLE, CMD_OPTIONAL, "allow nfs mounts to subdirs of /afs/.. (on | off)"); + cmd_AddParm(ts, "-clipags", CMD_SINGLE, CMD_OPTIONAL, + "enable use of client-assigned PAG's (on | off)"); + cmd_AddParm(ts, "-pagcb", CMD_SINGLE, CMD_OPTIONAL, + "enable callbacks to get creds from new clients (on | off)"); ts = cmd_CreateSyntax("storebehind", StoreBehindCmd, 0, @@ -3554,6 +3617,9 @@ defect 3069 cmd_AddParm(ts, "-mode", CMD_SINGLE, CMD_OPTIONAL, "nat | full"); #endif + ts = cmd_CreateSyntax("nukenfscreds", NukeNFSCredsCmd, 0, "nuke credentials for NFS client"); + cmd_AddParm(ts, "-addr", CMD_SINGLE, 0, "host name or address"); + code = cmd_Dispatch(argc, argv); if (rxInitDone) rx_Finalize(); -- 2.39.5