fs-getcache-show-more-20060615
[openafs.git] / src / afs / afs_pioctl.c
index 05f5100..2c4599b 100644 (file)
@@ -71,6 +71,7 @@ DECL_PIOCTL(PGetCellStatus);
 DECL_PIOCTL(PSetCellStatus);
 DECL_PIOCTL(PFlushVolumeData);
 DECL_PIOCTL(PGetVnodeXStatus);
+DECL_PIOCTL(PGetVnodeXStatus2);
 DECL_PIOCTL(PSetSysName);
 DECL_PIOCTL(PSetSPrefs);
 DECL_PIOCTL(PSetSPrefs33);
@@ -88,6 +89,7 @@ DECL_PIOCTL(PRxStatProc);
 DECL_PIOCTL(PRxStatPeer);
 DECL_PIOCTL(PPrefetchFromTape);
 DECL_PIOCTL(PResidencyCmd);
+DECL_PIOCTL(PCallBackAddr);
 
 /*
  * A macro that says whether we're going to need HandleClientContext().
@@ -182,17 +184,20 @@ static int (*(VpioctlSw[])) () = {
        PPrefetchFromTape,      /* 66 -- MR-AFS: prefetch file from tape */
        PResidencyCmd,          /* 67 -- MR-AFS: generic commnd interface */
        PBogus,                 /* 68 -- arla: fetch stats */
+       PGetVnodeXStatus2,      /* 69 - get caller access and some vcache status */
 };
 
 static int (*(CpioctlSw[])) () = {
     PBogus,                    /* 0 */
        PNewAlias,              /* 1 -- create new cell alias */
        PListAliases,           /* 2 -- list cell aliases */
+       PCallBackAddr,          /* 3 -- request addr for callback rxcon */
 };
 
 #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)
 {
@@ -201,6 +206,7 @@ afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
     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
@@ -256,19 +262,33 @@ copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
     }
 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
 
-#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV) && !defined(AFS_AMD64_LINUX20_ENV)
+#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
     struct afs_ioctl32 dst32;
 
-#ifdef AFS_SPARC64_LINUX24_ENV
+#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 Not done for this linux type
+#error pioctl32 not done for this linux
 #endif
     {
        AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
@@ -410,7 +430,7 @@ afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
    interface call.
    */
 /* AFS_HPUX102 and up uses VNODE ioctl instead */
-#ifndef AFS_HPUX102_ENV
+#if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
 #if !defined(AFS_SGI_ENV)
 #ifdef AFS_AIX32_ENV
 #ifdef AFS_AIX51_ENV
@@ -484,7 +504,7 @@ struct afs_ioctl_sys {
     unsigned int com;
     unsigned long arg;
 };
-asmlinkage int
+int
 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
           unsigned long arg)
 {
@@ -512,16 +532,16 @@ afs_xioctl(void)
     register int ioctlDone = 0, code = 0;
 
     AFS_STATCNT(afs_xioctl);
-#if defined(AFS_XBSD_ENV)
+#if defined(AFS_DARWIN_ENV)
+    if ((code = fdgetf(p, uap->fd, &fd)))
+       return code;
+#elif defined(AFS_XBSD_ENV)
     fdp = p->p_fd;
     if ((u_int) uap->fd >= fdp->fd_nfiles
        || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
        return EBADF;
     if ((fd->f_flag & (FREAD | FWRITE)) == 0)
        return EBADF;
-#elif defined(AFS_DARWIN_ENV)
-    if ((code = fdgetf(p, uap->fd, &fd)))
-       return code;
 #elif defined(AFS_LINUX22_ENV)
     ua.com = com;
     ua.arg = arg;
@@ -581,21 +601,13 @@ afs_xioctl(void)
 #endif
 #endif /* AFS_LINUX22_ENV */
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
-#ifdef AFS_DEC_ENV
-           tvc = VTOAFS(afs_gntovn((struct gnode *)tvc));
-           if (!tvc) {         /* shouldn't happen with held gnodes */
-               u.u_error = ENOENT;
-               return;
-           }
-#endif
            /* This is an AFS vnode */
            if (((uap->com >> 8) & 0xff) == 'V') {
                register struct afs_ioctl *datap;
                AFS_GLOCK();
                datap =
                    (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
-               AFS_COPYIN((char *)uap->arg, (caddr_t) datap,
-                          sizeof(struct afs_ioctl), code);
+               code=copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
                    AFS_GUNLOCK();
@@ -805,9 +817,15 @@ afs_pioctl(p, args, retval)
     } *uap = (struct a *)args;
 
     AFS_STATCNT(afs_pioctl);
+#ifdef AFS_DARWIN80_ENV
+    return (afs_syscall_pioctl
+           (uap->path, uap->cmd, uap->cmarg, uap->follow,
+            kauth_cred_get()));
+#else
     return (afs_syscall_pioctl
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
             p->p_cred->pc_ucred));
+#endif
 }
 
 #endif
@@ -838,12 +856,12 @@ afs_syscall_pioctl(path, com, cmarg, follow)
      int follow;
 {
     struct afs_ioctl data;
-    struct AFS_UCRED *tmpcred, *foreigncreds = NULL;
-    register afs_int32 code = 0;
-    struct vnode *vp;
-#ifdef AFS_DEC_ENV
-    struct vnode *gp;
+#ifdef AFS_NEED_CLIENTCONTEXT
+    struct AFS_UCRED *tmpcred;
 #endif
+    struct AFS_UCRED *foreigncreds = NULL;
+    register afs_int32 code = 0;
+    struct vnode *vp = NULL;
 #ifdef AFS_AIX41_ENV
     struct ucred *credp = crref();     /* don't free until done! */
 #endif
@@ -937,11 +955,11 @@ afs_syscall_pioctl(path, com, cmarg, follow)
                       foreigncreds ? foreigncreds : credp);
 #else
 #ifdef AFS_LINUX22_ENV
-       code = gop_lookupname(path, AFS_UIOUSER, follow, NULL, &dp);
+       code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
        if (!code)
            vp = (struct vnode *)dp->d_inode;
 #else
-       code = gop_lookupname(path, AFS_UIOUSER, follow, NULL, &vp);
+       code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
 #endif /* AFS_LINUX22_ENV */
 #endif /* AFS_AIX41_ENV */
        AFS_GLOCK();
@@ -955,20 +973,22 @@ afs_syscall_pioctl(path, com, cmarg, follow)
     } else
        vp = NULL;
 
+#if defined(AFS_SUN510_ENV)
+    if (vp && !IsAfsVnode(vp)) {
+       struct vnode *realvp;
+       
+       if (VOP_REALVP(vp, &realvp) == 0) {
+           struct vnode *oldvp = vp;
+           
+           VN_HOLD(realvp);
+           vp = realvp;
+           AFS_RELE(oldvp);
+       }
+    }
+#endif
     /* now make the call if we were passed no file, or were passed an AFS file */
     if (!vp || IsAfsVnode(vp)) {
-#if defined(AFS_DEC_ENV)
-       /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
-        * So, we must test in this part of the code.  Also, must arrange to
-        * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
-        * we hold gnodes, whose references hold our vcache entries.
-        */
-       if (vp) {
-           gp = vp;            /* remember for "put" */
-           vp = (struct vnode *)afs_gntovn(vp);        /* get vcache from gp */
-       } else
-           gp = NULL;
-#elif defined(AFS_SUN5_ENV)
+#if defined(AFS_SUN5_ENV)
        code = afs_HandlePioctl(vp, com, &data, follow, &credp);
 #elif defined(AFS_AIX41_ENV)
        {
@@ -1007,12 +1027,6 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #else
        code = EINVAL;          /* not in /afs */
 #endif
-#ifdef AFS_DEC_ENV
-       if (vp) {
-           GRELE(vp);
-           vp = NULL;
-       }
-#endif
     }
 
   rescred:
@@ -1049,6 +1063,8 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
 }
 
+#define MAXPIOCTLTOKENLEN \
+(3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
 
 int
 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
@@ -1059,7 +1075,7 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     struct vrequest treq;
     register afs_int32 code;
     register afs_int32 function, device;
-    afs_int32 inSize, outSize;
+    afs_int32 inSize, outSize, outSizeMax;
     char *inData, *outData;
     int (*(*pioctlSw)) ();
     int pioctlSwSize;
@@ -1101,37 +1117,68 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     inSize = ablob->in_size;
 
     /* Do all range checking before continuing */
-    if (inSize >= PIGGYSIZE || inSize < 0 || ablob->out_size < 0)
+    if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
        return E2BIG;
 
-    inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
+    if (inSize > AFS_LRALLOCSIZ) {
+       inData = osi_Alloc(inSize + 1);
+    } else {
+       inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    }
+    if (!inData)
+       return ENOMEM;
     if (inSize > 0) {
        AFS_COPYIN(ablob->in, inData, inSize, code);
        inData[inSize] = '\0';
     } else
        code = 0;
     if (code) {
-       osi_FreeLargeSpace(inData);
+       if (inSize > AFS_LRALLOCSIZ) {
+           osi_Free(inData, inSize + 1);
+       } else {
+           osi_FreeLargeSpace(inData);
+       }
        afs_PutFakeStat(&fakestate);
        return code;
     }
-    outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    if (function == 8 && device == 'V') {      /* PGetTokens */
+       outSizeMax = MAXPIOCTLTOKENLEN;
+       outData = osi_Alloc(outSizeMax);
+    } else {
+       outSizeMax = AFS_LRALLOCSIZ;
+       outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    }
+    if (!outData) {
+       if (inSize > AFS_LRALLOCSIZ) {
+           osi_Free(inData, inSize + 1);
+       } else {
+           osi_FreeLargeSpace(inData);
+       }
+       afs_PutFakeStat(&fakestate);
+       return ENOMEM;
+    }
     outSize = 0;
     code =
        (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
                               &outSize, acred);
-    osi_FreeLargeSpace(inData);
+    if (inSize > AFS_LRALLOCSIZ) {
+       osi_Free(inData, inSize + 1);
+    } else {
+       osi_FreeLargeSpace(inData);
+    }
     if (code == 0 && ablob->out_size > 0) {
-       if (outSize > ablob->out_size)
-           outSize = ablob->out_size;
-       if (outSize >= PIGGYSIZE)
-           code = E2BIG;
-       else if (outSize) {
-           outData[outSize] = '\0';
+       if (outSize > ablob->out_size) {
+           code = E2BIG;       /* data wont fit in user buffer */
+       } else if (outSize) {
            AFS_COPYOUT(outData, ablob->out, outSize, code);
        }
     }
-    osi_FreeLargeSpace(outData);
+    if (outSizeMax > AFS_LRALLOCSIZ) {
+       osi_Free(outData, outSizeMax);
+    } else {
+       osi_FreeLargeSpace(outData);
+    }
     afs_PutFakeStat(&fakestate);
     return afs_CheckCode(code, &treq, 41);
 }
@@ -1158,7 +1205,7 @@ DECL_PIOCTL(PSetAcl)
     AFS_STATCNT(PSetAcl);
     if (!avc)
        return EINVAL;
-    if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1000)
+    if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
        return EINVAL;
 
     acl.AFSOpaque_val = ain;
@@ -1382,10 +1429,8 @@ DECL_PIOCTL(PSetTokens)
     memcpy((char *)&i, ain, sizeof(afs_int32));
     ain += sizeof(afs_int32);
     stp = ain;                 /* remember where the ticket is */
-    if (i < 0 || i > 2000)
+    if (i < 0 || i > MAXKTCTICKETLEN)
        return EINVAL;          /* malloc may fail */
-    if (i > MAXKTCTICKETLEN)
-       return EINVAL;
     stLen = i;
     ain += i;                  /* skip over ticket */
     memcpy((char *)&i, ain, sizeof(afs_int32));
@@ -1427,8 +1472,10 @@ DECL_PIOCTL(PSetTokens)
 #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
        if (!setpag(p, acred, -1, &pag, 1)) {
 #else
 #ifdef AFS_OSF_ENV
@@ -1482,7 +1529,7 @@ DECL_PIOCTL(PGetVolumeStatus)
     char *motd = afs_osi_Alloc(256);
     register struct conn *tc;
     register afs_int32 code = 0;
-    struct VolumeStatus volstat;
+    struct AFSFetchVolumeStatus volstat;
     register char *cp;
     char *Name, *OfflineMsg, *MOTD;
     XSTATS_DECLS;
@@ -1544,32 +1591,43 @@ DECL_PIOCTL(PSetVolumeStatus)
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
-    if (!avc)
-       return EINVAL;
+    if (!avc) {
+       code = EINVAL;
+       goto out;
+    }
 
     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
     if (tvp) {
        if (tvp->states & (VRO | VBackup)) {
            afs_PutVolume(tvp, READ_LOCK);
-           return EROFS;
+           code = EROFS;
+           goto out;
        }
        afs_PutVolume(tvp, READ_LOCK);
-    } else
-       return ENODEV;
+    } else {
+       code = ENODEV;
+       goto out;
+    }
     /* Copy the junk out, using cp as a roving pointer. */
     cp = ain;
     memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
     cp += sizeof(AFSFetchVolumeStatus);
-    if (strlen(cp) >= sizeof(volName))
-       return E2BIG;
+    if (strlen(cp) >= sizeof(volName)) {
+       code = E2BIG;
+       goto out;
+    }
     strcpy(volName, cp);
     cp += strlen(volName) + 1;
-    if (strlen(cp) >= sizeof(offLineMsg))
-       return E2BIG;
+    if (strlen(cp) >= sizeof(offLineMsg)) {
+       code = E2BIG;
+       goto out;
+    }
     strcpy(offLineMsg, cp);
     cp += strlen(offLineMsg) + 1;
-    if (strlen(cp) >= sizeof(motd))
-       return E2BIG;
+    if (strlen(cp) >= sizeof(motd)) {
+       code = E2BIG;
+       goto out;
+    }
     strcpy(motd, cp);
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
@@ -1621,7 +1679,7 @@ DECL_PIOCTL(PFlush)
     AFS_STATCNT(PFlush);
     if (!avc)
        return EINVAL;
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
     afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
     ObtainWriteLock(&avc->lock, 225);
@@ -1632,13 +1690,12 @@ DECL_PIOCTL(PFlush)
     /* now find the disk cache entries */
     afs_TryToSmush(avc, *acred, 1);
     osi_dnlc_purgedp(avc);
-    afs_symhint_inval(avc);
     if (avc->linkData && !(avc->states & CCore)) {
        afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
        avc->linkData = NULL;
     }
     ReleaseWriteLock(&avc->lock);
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
     afs_BozonUnlock(&avc->pvnLock, avc);
 #endif
     return 0;
@@ -1669,7 +1726,7 @@ DECL_PIOCTL(PNewStatMount)
     Check_AtSys(avc, ain, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
-       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+       code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);                /* we're done with the data */
@@ -1888,12 +1945,12 @@ DECL_PIOCTL(PCheckServers)
        pcheck = (struct chservinfo *)ain;
        if (pcheck->tinterval >= 0) {
            cp = aout;
-           memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
+           memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
            *aoutSize = sizeof(afs_int32);
            if (pcheck->tinterval > 0) {
                if (!afs_osi_suser(*acred))
                    return EACCES;
-               PROBE_INTERVAL = pcheck->tinterval;
+               afs_probe_interval = pcheck->tinterval;
            }
            return 0;
        }
@@ -2118,11 +2175,51 @@ DECL_PIOCTL(PSetCacheSize)
 DECL_PIOCTL(PGetCacheSize)
 {
     afs_int32 results[MAXGCSTATS];
-
+    afs_int32 flags;
+    register struct dcache * tdc;
+    int i, size;
+    
     AFS_STATCNT(PGetCacheSize);
+
+    if (sizeof(afs_int32) == ainSize){
+       memcpy((char *)&flags, ain, sizeof(afs_int32));
+    } else if (0 == ainSize){ 
+       flags = 0;
+    } else {
+       return EINVAL;
+    }
+    
     memset((char *)results, 0, sizeof(results));
     results[0] = afs_cacheBlocks;
     results[1] = afs_blocksUsed;
+    results[2] = afs_cacheFiles;
+    
+    if (1 == flags){
+        for (i = 0; i < afs_cacheFiles; i++) {
+           if (afs_indexFlags[i] & IFFree) results[3]++;
+       }
+    } else if (2 == flags){
+        for (i = 0; i < afs_cacheFiles; i++) {
+           if (afs_indexFlags[i] & IFFree) results[3]++;
+           if (afs_indexFlags[i] & IFEverUsed) results[4]++;
+           if (afs_indexFlags[i] & IFDataMod) results[5]++;
+           if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
+           if (afs_indexFlags[i] & IFAnyPages) results[7]++;
+           if (afs_indexFlags[i] & IFDiscarded) results[8]++;
+
+           tdc = afs_indexTable[i];
+           if (tdc){
+               results[9]++;
+               size = tdc->validPos;
+               if ( 0 < size && size < (1<<12) ) results[10]++;
+               else if (size < (1<<14) ) results[11]++;
+               else if (size < (1<<16) ) results[12]++;
+               else if (size < (1<<18) ) results[13]++;
+               else if (size < (1<<20) ) results[14]++;
+               else if (size >= (1<<20) ) results[15]++;
+           }
+        }
+    }
     memcpy(aout, (char *)results, sizeof(results));
     *aoutSize = sizeof(results);
     return 0;
@@ -2349,7 +2446,7 @@ DECL_PIOCTL(PRemoveMount)
     Check_AtSys(avc, ain, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
-       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+       code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
     ReleaseReadLock(&tdc->lock);
     bufp = sysState.name;
@@ -2420,10 +2517,10 @@ DECL_PIOCTL(PRemoveMount)
        ObtainWriteLock(&tdc->lock, 661);
        if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
            /* we can do it locally */
-           code = afs_dir_Delete(&tdc->f.inode, bufp);
+           code = afs_dir_Delete(tdc, bufp);
            if (code) {
                ZapDCE(tdc);    /* surprise error -- invalid value */
-               DZap(&tdc->f.inode);
+               DZap(tdc);
            }
        }
        ReleaseWriteLock(&tdc->lock);
@@ -2491,6 +2588,10 @@ DECL_PIOCTL(PFlushVolumeData)
     register struct vcache *tvc;
     register struct volume *tv;
     afs_int32 cell, volume;
+    struct afs_q *tq, *uq;
+#ifdef AFS_DARWIN80_ENV
+    vnode_t vp;
+#endif
 
     AFS_STATCNT(PFlushVolumeData);
     if (!avc)
@@ -2505,21 +2606,48 @@ DECL_PIOCTL(PFlushVolumeData)
      * Clear stat'd flag from all vnodes from this volume; this will invalidate all
      * the vcaches associated with the volume.
      */
+ loop:
     ObtainReadLock(&afs_xvcache);
-    for (i = 0; i < VCSIZE; i++) {
-       for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
+    i = VCHashV(&avc->fid);
+    for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
+           uq = QPrev(tq);
+           tvc = QTOVH(tq);
            if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
-#if    defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
+               if (tvc->states & CVInit) {
+                   ReleaseReadLock(&afs_xvcache);
+                   afs_osi_Sleep(&tvc->states);
+                   goto loop;
+               }
+#ifdef AFS_DARWIN80_ENV
+               if (tvc->states & CDeadVnode) {
+                   ReleaseReadLock(&afs_xvcache);
+                   afs_osi_Sleep(&tvc->states);
+                   goto loop;
+               }
+#endif
+#if    defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
                VN_HOLD(AFSTOV(tvc));
 #else
+#ifdef AFS_DARWIN80_ENV
+               vp = AFSTOV(tvc);
+               if (vnode_get(vp))
+                   continue;
+               if (vnode_ref(vp)) {
+                   AFS_GUNLOCK();
+                   vnode_put(vp);
+                   AFS_GLOCK();
+                   continue;
+               }
+#else
 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
                osi_vnhold(tvc, 0);
 #else
-               VREFCOUNT_INC(tvc);
+               VREFCOUNT_INC(tvc); /* AIX, apparently */
+#endif
 #endif
 #endif
                ReleaseReadLock(&afs_xvcache);
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
                afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
                ObtainWriteLock(&tvc->lock, 232);
@@ -2532,15 +2660,18 @@ DECL_PIOCTL(PFlushVolumeData)
                    osi_dnlc_purgedp(tvc);
                afs_TryToSmush(tvc, *acred, 1);
                ReleaseWriteLock(&tvc->lock);
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
                afs_BozonUnlock(&tvc->pvnLock, tvc);
 #endif
+#ifdef AFS_DARWIN80_ENV
+               vnode_put(AFSTOV(tvc));
+#endif
                ObtainReadLock(&afs_xvcache);
+               uq = QPrev(tq);
                /* our tvc ptr is still good until now */
                AFS_FAST_RELE(tvc);
            }
        }
-    }
     ReleaseReadLock(&afs_xvcache);
 
 
@@ -2607,6 +2738,8 @@ DECL_PIOCTL(PGetVnodeXStatus)
        mode = PRSFS_READ;
     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
        return EACCES;
+
+    memset(&stat, 0, sizeof(struct vcxstat));
     stat.fid = avc->fid;
     hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
     stat.lock = avc->lock;
@@ -2637,19 +2770,49 @@ DECL_PIOCTL(PGetVnodeXStatus)
 }
 
 
+DECL_PIOCTL(PGetVnodeXStatus2)
+{
+    register afs_int32 code;
+    struct vcxstat2 stat;
+    afs_int32 mode;
+
+    if (!avc)
+        return EINVAL;
+    code = afs_VerifyVCache(avc, areq);
+    if (code)
+        return code;
+    if (vType(avc) == VDIR)
+        mode = PRSFS_LOOKUP;
+    else
+        mode = PRSFS_READ;
+    if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
+        return EACCES;
+
+    memset(&stat, 0, sizeof(struct vcxstat2));
+
+    stat.cbExpires = avc->cbExpires;
+    stat.anyAccess = avc->anyAccess;
+    stat.mvstat = avc->mvstat;
+    stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
+
+    memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
+    *aoutSize = sizeof(struct vcxstat2);
+    return 0;
+}
+
 /* We require root for local sysname changes, but not for remote */
 /* (since we don't really believe remote uids anyway) */
  /* outname[] shouldn't really be needed- this is left as an excercise */
  /* for the reader.  */
 DECL_PIOCTL(PSetSysName)
 {
-    char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
+    char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
     int setsysname, foundname = 0;
     register struct afs_exporter *exporter;
     register struct unixuser *au;
     register afs_int32 pag, error;
-    int t, count;
-
+    int t, count, num = 0;
+    char **sysnamelist[MAXNUMSYSNAMES];
 
     AFS_STATCNT(PSetSysName);
     if (!afs_globalVFS) {
@@ -2668,6 +2831,7 @@ DECL_PIOCTL(PSetSysName)
        /* Check my args */
        if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
            return EINVAL;
+       cp2 = ain;
        for (cp = ain, count = 0; count < setsysname; count++) {
            /* won't go past end of ain since maxsysname*num < ain length */
            t = strlen(cp);
@@ -2680,10 +2844,11 @@ DECL_PIOCTL(PSetSysName)
        }
        /* args ok */
 
-       /* inname gets first entry in case we're being a translater */
+       /* inname gets first entry in case we're being a translator */
        t = strlen(ain);
        memcpy(inname, ain, t + 1);     /* include terminating null */
        ain += t + 1;
+       num = count;
     }
     if ((*acred)->cr_gid == RMTUSER_REQ) {     /* Handles all exporters */
        pag = PagInCred(*acred);
@@ -2697,7 +2862,8 @@ DECL_PIOCTL(PSetSysName)
            afs_PutUser(au, READ_LOCK);
            return EINVAL;      /* Better than panicing */
        }
-       error = EXP_SYSNAME(exporter, (setsysname ? inname : NULL), outname);
+       error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), sysnamelist,
+                           &num);
        if (error) {
            if (error == ENODEV)
                foundname = 0;  /* sysname not set yet! */
@@ -2705,17 +2871,19 @@ DECL_PIOCTL(PSetSysName)
                afs_PutUser(au, READ_LOCK);
                return error;
            }
-       } else
-           foundname = 1;
+       } else {
+           foundname = num;
+           strcpy(outname, (*sysnamelist)[0]);
+       }
        afs_PutUser(au, READ_LOCK);
     } else {
-
        /* Not xlating, so local case */
        if (!afs_sysname)
            osi_Panic("PSetSysName: !afs_sysname\n");
        if (!setsysname) {      /* user just wants the info */
            strcpy(outname, afs_sysname);
            foundname = afs_sysnamecount;
+           *sysnamelist = afs_sysnamelist;
        } else {                /* Local guy; only root can change sysname */
            if (!afs_osi_suser(*acred))
                return EACCES;
@@ -2746,14 +2914,13 @@ DECL_PIOCTL(PSetSysName)
            strcpy(cp, outname);        /* ... the entry, ... */
            cp += strlen(outname) + 1;
            for (count = 1; count < foundname; ++count) {       /* ... or list. */
-               /* Note: we don't support @sys lists for exporters */
-               if (!afs_sysnamelist[count])
+               if (!(*sysnamelist)[count])
                    osi_Panic
                        ("PSetSysName: no afs_sysnamelist entry to read\n");
-               t = strlen(afs_sysnamelist[count]);
+               t = strlen((*sysnamelist)[count]);
                if (t >= MAXSYSNAME)
                    osi_Panic("PSetSysName: sysname entry garbled\n");
-               strcpy(cp, afs_sysnamelist[count]);
+               strcpy(cp, (*sysnamelist)[count]);
                cp += t + 1;
            }
        }
@@ -3288,6 +3455,9 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
        uid = afs_nobody;       /* NFS_NOBODY == -2 */
     }
     newcred = crget();
+#if defined(AFS_LINUX26_ENV)
+    newcred->cr_group_info = groups_alloc(0);
+#endif
 #ifdef AFS_AIX41_ENV
     setuerror(0);
 #endif
@@ -3309,7 +3479,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
        newcred->cr_groups[i] = NOGROUP;
 #endif
 #endif
-#if    !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
+#if    !defined(AFS_OSF_ENV) 
     afs_nfsclient_init();      /* before looking for exporter, ensure one exists */
 #endif
     if (!(exporter = exporter_find(exporter_type))) {
@@ -3451,7 +3621,7 @@ DECL_PIOCTL(PFlushMount)
     Check_AtSys(avc, ain, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
-       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+       code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);                /* we're done with the data */
@@ -3475,7 +3645,7 @@ DECL_PIOCTL(PFlushMount)
        code = EINVAL;
        goto out;
     }
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
     afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
     ObtainWriteLock(&tvc->lock, 649);
@@ -3486,13 +3656,12 @@ DECL_PIOCTL(PFlushMount)
     /* now find the disk cache entries */
     afs_TryToSmush(tvc, *acred, 1);
     osi_dnlc_purgedp(tvc);
-    afs_symhint_inval(tvc);
     if (tvc->linkData && !(tvc->states & CCore)) {
        afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
        tvc->linkData = NULL;
     }
     ReleaseWriteLock(&tvc->lock);
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
     afs_BozonUnlock(&tvc->pvnLock, tvc);
 #endif
     afs_PutVCache(tvc);
@@ -3700,3 +3869,101 @@ DECL_PIOCTL(PResidencyCmd)
     }
     return code;
 }
+
+DECL_PIOCTL(PCallBackAddr)
+{
+#ifndef UKERNEL
+    afs_uint32 addr, code;
+    int srvAddrCount;
+    struct server *ts;
+    struct srvAddr *sa;
+    struct conn *tc;
+    afs_int32 i, j;
+    struct unixuser *tu;
+    struct srvAddr **addrs;
+
+    /*AFS_STATCNT(PCallBackAddr); */
+    if (!afs_resourceinit_flag)        /* afs deamons havn't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    if (!afs_osi_suser(acred))
+       return EACCES;
+
+    if (ainSize < sizeof(afs_int32))
+       return EINVAL;
+
+    memcpy(&addr, ain, sizeof(afs_int32));
+
+    ObtainReadLock(&afs_xinterface);
+    for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
+       if (afs_cb_interface.addr_in[i] == addr)
+           break;
+    }
+
+    ReleaseWriteLock(&afs_xinterface);
+
+    if (afs_cb_interface.addr_in[i] != addr)
+       return EINVAL;
+
+    ObtainReadLock(&afs_xserver);      /* Necessary? */
+    ObtainReadLock(&afs_xsrvAddr);
+
+    srvAddrCount = 0;
+    for (i = 0; i < NSERVERS; i++) {
+       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
+           srvAddrCount++;
+       }
+    }
+
+    addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    j = 0;
+    for (i = 0; i < NSERVERS; i++) {
+       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
+           if (j >= srvAddrCount)
+               break;
+           addrs[j++] = sa;
+       }
+    }
+
+    ReleaseReadLock(&afs_xsrvAddr);
+    ReleaseReadLock(&afs_xserver);
+
+    for (i = 0; i < j; i++) {
+       sa = addrs[i];
+       ts = sa->server;
+       if (!ts)
+           continue;
+
+       /* vlserver has no callback conn */
+       if (sa->sa_portal == AFS_VLPORT) {
+           continue;
+       }
+
+       if (!ts->cell)          /* not really an active server, anyway, it must */
+           continue;           /* have just been added by setsprefs */
+
+       /* get a connection, even if host is down; bumps conn ref count */
+       tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
+       tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
+                         1 /*force */ , 1 /*create */ , SHARED_LOCK);
+       afs_PutUser(tu, SHARED_LOCK);
+       if (!tc)
+           continue;
+
+       if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
+           if (sa->sa_flags & SRVADDR_ISDOWN) {
+               rx_SetConnDeadTime(tc->id, 3);
+           }
+#ifdef RX_ENABLE_LOCKS
+           AFS_GUNLOCK();
+#endif /* RX_ENABLE_LOCKS */
+           code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
+#ifdef RX_ENABLE_LOCKS
+           AFS_GLOCK();
+#endif /* RX_ENABLE_LOCKS */
+       }
+       afs_PutConn(tc, SHARED_LOCK);   /* done with it now */
+    }                          /* Outer loop over addrs */
+#endif /* UKERNEL */
+    return 0;
+}