disconnected-20080523
authorSimon Wilkinson <sxw@inf.ed.ac.uk>
Fri, 23 May 2008 15:57:18 +0000 (15:57 +0000)
committerDerrick Brashear <shadow@dementia.org>
Fri, 23 May 2008 15:57:18 +0000 (15:57 +0000)
LICENSE IPL10

add readonly disconnected support

33 files changed:
acinclude.m4
src/afs/UKERNEL/afsincludes.h
src/afs/VNOPS/afs_vnop_access.c
src/afs/VNOPS/afs_vnop_attrs.c
src/afs/VNOPS/afs_vnop_create.c
src/afs/VNOPS/afs_vnop_dirops.c
src/afs/VNOPS/afs_vnop_flock.c
src/afs/VNOPS/afs_vnop_link.c
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/VNOPS/afs_vnop_open.c
src/afs/VNOPS/afs_vnop_read.c
src/afs/VNOPS/afs_vnop_readdir.c
src/afs/VNOPS/afs_vnop_remove.c
src/afs/VNOPS/afs_vnop_rename.c
src/afs/VNOPS/afs_vnop_symlink.c
src/afs/VNOPS/afs_vnop_write.c
src/afs/afs_analyze.c
src/afs/afs_conn.c
src/afs/afs_daemons.c
src/afs/afs_dcache.c
src/afs/afs_disconnected.c [new file with mode: 0644]
src/afs/afs_init.c
src/afs/afs_pioctl.c
src/afs/afs_prototypes.h
src/afs/afs_segments.c
src/afs/afs_server.c
src/afs/afs_vcache.c
src/afs/afs_volume.c
src/afs/afsincludes.h
src/afs/discon.h [new file with mode: 0644]
src/libafs/Makefile.common.in
src/libuafs/Makefile.common.in
src/venus/fs.c

index 4dbe71f..e5acb84 100644 (file)
@@ -33,6 +33,8 @@ AC_ARG_ENABLE( bitmap-later,
 [  --enable-bitmap-later               enable fast startup of file server by not reading bitmap till needed],, enable_bitmap_later="no")
 AC_ARG_ENABLE( demand-attach-fs,
 [  --enable-demand-attach-fs           enable Demand Attach Fileserver (please see documentation)],, enable_demand_attach_fs="no")
+AC_ARG_ENABLE( disconnected,
+[  --enable-disconnected               enable disconnected support in cache manager (experimental)],, enable_disconnected="no")
 AC_ARG_ENABLE( unix-sockets,
 [  --enable-unix-sockets               enable use of unix domain sockets for fssync],, enable_unix_sockets="yes")
 AC_ARG_ENABLE( full-vos-listvol-switch,
@@ -1155,6 +1157,10 @@ else
 fi
 AC_SUBST(DEMAND_ATTACH)
 
+if test "$enable_disconnected" = "yes"; then
+       AC_DEFINE(AFS_DISCON_ENV, 1, [define if you want support for disconnected operation])
+fi
+
 if test "$enable_unix_sockets" = "yes"; then
        AC_DEFINE(USE_UNIX_SOCKETS, 1, [define if you want to use UNIX sockets for fssync.])
        USE_UNIX_SOCKETS="yes"
index 049475d..9ae9a17 100644 (file)
@@ -26,3 +26,4 @@
 #include "afs/icl.h"
 #include "afs/afs_stats.h"
 #include "afs/afs_prototypes.h"
+#include "afs/discon.h"
index 7e2cd73..74f4050 100644 (file)
@@ -209,10 +209,13 @@ afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
     if ((code = afs_InitReq(&treq, acred)))
        return code;
 
+    AFS_DISCON_LOCK();
+
     if (afs_fakestat_enable && avc->mvstat == 1) {
        code = afs_TryEvalFakeStat(&avc, &fakestate, &treq);
         if (code == 0 && avc->mvstat == 1) {
            afs_PutFakeStat(&fakestate);
+           AFS_DISCON_UNLOCK();
            return 0;
         }
     } else {
@@ -221,6 +224,7 @@ afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
 
     if (code) {
        afs_PutFakeStat(&fakestate);
+       AFS_DISCON_UNLOCK();
        return code;
     }
 
@@ -228,6 +232,7 @@ afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
        code = afs_VerifyVCache(avc, &treq);
        if (code) {
            afs_PutFakeStat(&fakestate);
+           AFS_DISCON_UNLOCK();
            code = afs_CheckCode(code, &treq, 16);
            return code;
        }
@@ -236,8 +241,18 @@ afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
     /* if we're looking for write access and we have a read-only file system, report it */
     if ((amode & VWRITE) && (avc->states & CRO)) {
        afs_PutFakeStat(&fakestate);
+       AFS_DISCON_UNLOCK();
        return EROFS;
     }
+    
+    /* If we're looking for write access, and we're disconnected without logging, forget it */
+    if ((amode & VWRITE) && (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING)) {
+        afs_PutFakeStat(&fakestate);
+       AFS_DISCON_UNLOCK();
+       /*printf("Network is down in afs_vnop_access\n");*/
+        return ENETDOWN;
+    }
+    
     code = 1;                  /* Default from here on in is access ok. */
     if (avc->states & CForeign) {
        /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
@@ -316,6 +331,9 @@ afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
        }
     }
     afs_PutFakeStat(&fakestate);
+
+    AFS_DISCON_UNLOCK();
+    
     if (code) {
        return 0;               /* if access is ok */
     } else {
index 3f85e6c..26f4dfb 100644 (file)
@@ -230,6 +230,8 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, struct AFS_UCRED *acred)
     }
 #endif
 
+    AFS_DISCON_LOCK();
+
 #ifdef AFS_BOZONLOCK_ENV
     afs_BozonLock(&avc->pvnLock, avc);
 #endif
@@ -328,6 +330,9 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, struct AFS_UCRED *acred)
            }
        }
     }
+
+    AFS_DISCON_UNLOCK();
+
     if (!code)
        return 0;
     code = afs_CheckCode(code, &treq, 14);
@@ -463,6 +468,8 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
     if ((code = afs_InitReq(&treq, acred)))
        return code;
 
+    AFS_DISCON_LOCK();
+
     afs_InitFakeStat(&fakestate);
     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
     if (code)
@@ -502,6 +509,11 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
        }
     }
 
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+        code = ENETDOWN;
+        goto done;
+    }
+
     afs_VAttrToAS(avc, attrs, &astat); /* interpret request */
     code = 0;
 #ifdef AFS_BOZONLOCK_ENV
@@ -551,19 +563,25 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
        hzero(avc->flushDV);
        osi_FlushText(avc);     /* do this after releasing all locks */
     }
-    if (code == 0) {
-       ObtainSharedLock(&avc->lock, 16);       /* lock entry */
-       code = afs_WriteVCache(avc, &astat, &treq);     /* send request */
-       ReleaseSharedLock(&avc->lock);  /* release lock */
-    }
-    if (code) {
-       ObtainWriteLock(&afs_xcbhash, 487);
-       afs_DequeueCallback(avc);
-       avc->states &= ~CStatd;
-       ReleaseWriteLock(&afs_xcbhash);
-       if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
-           osi_dnlc_purgedp(avc);
-       /* error?  erase any changes we made to vcache entry */
+    
+    if (!AFS_IS_DISCONNECTED) {
+        if (code == 0) {
+           ObtainSharedLock(&avc->lock, 16);   /* lock entry */
+           code = afs_WriteVCache(avc, &astat, &treq); /* send request */
+           ReleaseSharedLock(&avc->lock);      /* release lock */
+        }
+        if (code) {
+           ObtainWriteLock(&afs_xcbhash, 487);
+           afs_DequeueCallback(avc);
+           avc->states &= ~CStatd;
+           ReleaseWriteLock(&afs_xcbhash);
+           if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
+               osi_dnlc_purgedp(avc);
+           /* error?  erase any changes we made to vcache entry */
+        }
+    } else {
+        /* Must be logging - but not implemented yet ... */
+        code = ENETDOWN;
     }
 #if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (AFS_NFSXLATORREQ(acred)) {
@@ -578,6 +596,8 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
 #endif
   done:
     afs_PutFakeStat(&fakestate);
+
+    AFS_DISCON_UNLOCK();
     code = afs_CheckCode(code, &treq, 15);
     return code;
 }
index bdf35a9..95eb550 100644 (file)
@@ -84,12 +84,12 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
 
     if (strlen(aname) > AFSNAMEMAX) {
        code = ENAMETOOLONG;
-       goto done;
+       goto done3;
     }
 
     if (!afs_ENameOK(aname)) {
        code = EINVAL;
-       goto done;
+       goto done3;
     }
     switch (attrs->va_type) {
     case VBLK:
@@ -100,10 +100,12 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
     case VFIFO:
        /* We don't support special devices or FIFOs */
        code = EINVAL;
-       goto done;
+       goto done3;
     default:
        ;
     }
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
     if (code)
        goto done;
@@ -120,6 +122,11 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
        goto done;
     }
 
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+        code = ENETDOWN;
+        goto done;
+    }
+
     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
     ObtainWriteLock(&adp->lock, 135);
     if (tdc)
@@ -252,6 +259,11 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
            goto done;
        }
     }
+    
+    if (AFS_IS_DISCONNECTED) {
+        /* XXX - If we get here, logging must be enabled (as we bypassed the
+         * earlier check. So - do that logging thang, then return */
+    }       
 
     /* if we create the file, we don't do any access checks, since
      * that's how O_CREAT is supposed to work */
@@ -447,6 +459,9 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
     ReleaseWriteLock(&afs_xvcache);
 
   done:
+    AFS_DISCON_UNLOCK();
+
+  done3:
     if (volp)
        afs_PutVolume(volp, READ_LOCK);
 
index 5e73dd0..a0a0b03 100644 (file)
@@ -65,13 +65,16 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
 
     if (strlen(aname) > AFSNAMEMAX) {
        code = ENAMETOOLONG;
-       goto done;
+       goto done3;
     }
 
     if (!afs_ENameOK(aname)) {
        code = EINVAL;
-       goto done;
+       goto done3;
     }
+    
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
     if (code)
        goto done;
@@ -86,6 +89,11 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
        code = EROFS;
        goto done;
     }
+   
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+       /*printf("Network is down in afs_mkdir\n");*/
+       code = ENETDOWN;
+    }
 
     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
     InStatus.ClientModTime = osi_Time();
@@ -156,6 +164,8 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
     } else
        code = ENOENT;
   done:
+    AFS_DISCON_UNLOCK();
+  done3:
     afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 26);
   done2:
@@ -198,6 +208,8 @@ afs_rmdir(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
        goto done;
     }
 
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
     if (code)
        goto done;
@@ -214,6 +226,11 @@ afs_rmdir(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
        goto done;
     }
 
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+        code = ENETDOWN;
+        goto done;
+    }
+    
     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
     ObtainWriteLock(&adp->lock, 154);
     if (tdc)
@@ -304,6 +321,8 @@ afs_rmdir(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
     code = 0;
 
   done:
+    AFS_DISCON_UNLOCK();
+  done3:
     afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 27);
   done2:
index 5e4b0e6..7be73e7 100644 (file)
@@ -219,6 +219,9 @@ lockIdcmp2(struct AFS_FLOCK *flock1, struct vcache *vp,
     94.04.13 add "force" parameter.  If a child explicitly unlocks a
     file, I guess we'll permit it.  however, we don't want simple,
     innocent closes by children to unlock files in the parent process.
+
+    If called when disconnected support is unabled, the discon_lock must
+    be held
 */
 /* clid - nonzero on sgi sunos osf1 only */
 int
@@ -295,20 +298,25 @@ HandleFlock(register struct vcache *avc, int acom, struct vrequest *areq,
            avc->slocks = 0;
        }
        if (avc->flockCount == 0) {
-           do {
-               tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
-               if (tc) {
-                   XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
-                   RX_AFS_GUNLOCK();
-                   code = RXAFS_ReleaseLock(tc->id, (struct AFSFid *)
-                                            &avc->fid.Fid, &tsync);
-                   RX_AFS_GLOCK();
-                   XSTATS_END_TIME;
-               } else
+           if (!AFS_IS_DISCONNECTED) {
+               do {
+                   tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+                   if (tc) {
+                       XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
+                       RX_AFS_GUNLOCK();
+                       code = RXAFS_ReleaseLock(tc->id, (struct AFSFid *)
+                                                &avc->fid.Fid, &tsync);
+                       RX_AFS_GLOCK();
+                       XSTATS_END_TIME;
+                   } else
                    code = -1;
-           } while (afs_Analyze
-                    (tc, code, &avc->fid, areq,
-                     AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK, NULL));
+               } while (afs_Analyze
+                        (tc, code, &avc->fid, areq,
+                         AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK, NULL));
+           } else {
+               /*printf("Network is dooooooowwwwwwwnnnnnnn\n");*/
+              code = ENETDOWN;
+           }
        }
     } else {
        while (1) {             /* set a new lock */
@@ -348,24 +356,26 @@ HandleFlock(register struct vcache *avc, int acom, struct vrequest *areq,
                    }
                }
                if (!code && avc->flockCount == 0) {
-                   do {
-                       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
-                       if (tc) {
-                           XSTATS_START_TIME
-                               (AFS_STATS_FS_RPCIDX_RELEASELOCK);
-                           RX_AFS_GUNLOCK();
-                           code =
-                               RXAFS_ReleaseLock(tc->id,
-                                                 (struct AFSFid *)&avc->fid.
-                                                 Fid, &tsync);
-                           RX_AFS_GLOCK();
-                           XSTATS_END_TIME;
-                       } else
-                           code = -1;
-                   } while (afs_Analyze
-                            (tc, code, &avc->fid, areq,
-                             AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK,
-                             NULL));
+                   if (!AFS_IS_DISCONNECTED) {
+                       do {
+                           tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+                           if (tc) {
+                               XSTATS_START_TIME
+                                   (AFS_STATS_FS_RPCIDX_RELEASELOCK);
+                               RX_AFS_GUNLOCK();
+                               code =
+                                   RXAFS_ReleaseLock(tc->id,
+                                                     (struct AFSFid *)&avc->
+                                                     fid.Fid, &tsync);
+                               RX_AFS_GLOCK();
+                              XSTATS_END_TIME;
+                           } else
+                               code = -1;
+                       } while (afs_Analyze
+                                (tc, code, &avc->fid, areq,
+                                 AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK,
+                                 NULL));
+                   }
                }
            } else if (avc->flockCount == -1 && (acom & LOCK_EX)) {
                if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
@@ -381,22 +391,28 @@ HandleFlock(register struct vcache *avc, int acom, struct vrequest *areq,
                if (avc->flockCount == 0) {
                    /* we're the first on our block, send the call through */
                    lockType = ((acom & LOCK_EX) ? LockWrite : LockRead);
-                   do {
-                       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
-                       if (tc) {
-                           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
-                           RX_AFS_GUNLOCK();
-                           code = RXAFS_SetLock(tc->id, (struct AFSFid *)
-                                                &avc->fid.Fid, lockType,
-                                                &tsync);
-                           RX_AFS_GLOCK();
-                           XSTATS_END_TIME;
-                       } else
-                           code = -1;
-                   } while (afs_Analyze
-                            (tc, code, &avc->fid, areq,
-                             AFS_STATS_FS_RPCIDX_SETLOCK, SHARED_LOCK,
-                             NULL));
+                   if (!AFS_IS_DISCONNECTED) {
+                       do {
+                           tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+                           if (tc) {
+                               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
+                               RX_AFS_GUNLOCK();
+                               code = RXAFS_SetLock(tc->id, (struct AFSFid *)
+                                                    &avc->fid.Fid, lockType,
+                                                    &tsync);
+                               RX_AFS_GLOCK();
+                               XSTATS_END_TIME;
+                           } else
+                               code = -1;
+                       } while (afs_Analyze
+                                (tc, code, &avc->fid, areq,
+                                 AFS_STATS_FS_RPCIDX_SETLOCK, SHARED_LOCK,
+                                 NULL));
+                   } else
+                       /* XXX - Should probably try and log this when we're
+                        * XXX - running with logging enabled. But it's horrid
+                        */
+                       code = 0; /* pretend we worked - ick!!! */
                } else
                    code = 0;   /* otherwise, pretend things worked */
            }
@@ -497,15 +513,17 @@ int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
     if ((code = afs_InitReq(&treq, acred)))
        return code;
     afs_InitFakeStat(&fakestate);
+
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
     if (code) {
-       afs_PutFakeStat(&fakestate);
-       return code;
+       goto done;
     }
 #ifdef AFS_OSF_ENV
     if (flag & VNOFLCK) {
-       afs_PutFakeStat(&fakestate);
-       return 0;
+       code = 0;
+       goto done;
     }
     if (flag & CLNFLCK) {
        acmd = LOCK_UN;
@@ -521,15 +539,14 @@ int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
     if (acmd == F_GETLK) {
 #endif
        if (af->l_type == F_UNLCK) {
-           afs_PutFakeStat(&fakestate);
-           return 0;
+           code = 0;
+           goto done;
        }
 #ifndef        AFS_OSF_ENV             /* getlock is a no-op for osf (for now) */
        code = HandleGetLock(avc, af, &treq, clid);
 #endif
        code = afs_CheckCode(code, &treq, 2);   /* defeat buggy AIX optimz */
-       afs_PutFakeStat(&fakestate);
-       return code;
+       goto done;
     } else if ((acmd == F_SETLK) || (acmd == F_SETLKW)
 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
               || (acmd == F_RSETLK) || (acmd == F_RSETLKW)) {
@@ -559,8 +576,8 @@ int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
      * even when they should block */
     if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
        DoLockWarning();
-       afs_PutFakeStat(&fakestate);
-       return 0;
+       code = 0;
+       goto done;
     }
     /* otherwise we can turn this into a whole-file flock */
     if (af->l_type == F_RDLCK)
@@ -589,11 +606,13 @@ int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
     code = HandleFlock(avc, code, &treq, 0, 0 /*!onlymine */ );
 #endif
     code = afs_CheckCode(code, &treq, 3);      /* defeat AIX -O bug */
-    afs_PutFakeStat(&fakestate);
-    return code;
+    goto done;
     }
+    code = EINVAL;
+done:
     afs_PutFakeStat(&fakestate);
-    return EINVAL;
+    AFS_DISCON_UNLOCK();
+    return code;
 }
 
 
@@ -819,6 +838,10 @@ GetFlockCount(struct vcache *avc, struct vrequest *areq)
     temp = areq->flags & O_NONBLOCK;
     areq->flags |= O_NONBLOCK;
 
+    /* If we're disconnected, lie and say that we've got no locks. Ick */
+    if (AFS_IS_DISCONNECTED)
+        return 0;
+        
     do {
        tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
        if (tc) {
@@ -889,6 +912,9 @@ afs_xflock(void)
        afs_PutFakeStat(&fakestate);
        return flockDone;
     }
+
+    AFS_DISCON_LOCK();
+    
     /* first determine whether this is any sort of vnode */
     if (fd->f_type == DTYPE_VNODE) {
        /* good, this is a vnode; next see if it is an AFS vnode */
@@ -897,6 +923,7 @@ afs_xflock(void)
            /* This is an AFS vnode, so do the work */
            code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
            if (code) {
+               AFS_DISCON_UNLOCK();
                afs_PutFakeStat(&fakestate);
                return code;
            }
@@ -950,11 +977,13 @@ afs_xflock(void)
 #else
     FP_UNREF(fd);
 #endif
+    AFS_DISCON_UNLOCK();
     afs_PutFakeStat(&fakestate);
     return code;
 #else /* AFS_OSF_ENV */
     if (!flockDone)
        flock();
+    AFS_DISCON_UNLOCK();
     afs_PutFakeStat(&fakestate);
     return;
 #endif
index 04c08a6..4350af4 100644 (file)
@@ -62,6 +62,9 @@ afs_link(avc, OSI_VC_ARG(adp), aname, acred)
 
     afs_InitFakeStat(&vfakestate);
     afs_InitFakeStat(&dfakestate);
+    
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&avc, &vfakestate, &treq);
     if (code)
        goto done;
@@ -89,6 +92,11 @@ afs_link(avc, OSI_VC_ARG(adp), aname, acred)
        code = EROFS;
        goto done;
     }
+    
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+        code = ENETDOWN;
+        goto done;
+    }
 
     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
     ObtainWriteLock(&adp->lock, 145);
@@ -161,6 +169,7 @@ afs_link(avc, OSI_VC_ARG(adp), aname, acred)
     code = afs_CheckCode(code, &treq, 24);
     afs_PutFakeStat(&vfakestate);
     afs_PutFakeStat(&dfakestate);
+    AFS_DISCON_UNLOCK();
   done2:
     return code;
 }
index 6389263..fa2727f 100644 (file)
@@ -87,10 +87,14 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
        volnamep = data;
        tcell = afs_GetCell(cellnum, READ_LOCK);
     } else {
+       /*printf("No cellname %s , or cellnum %d , returning ENODEV\n", 
+              data, cellnum);*/
        return ENODEV;
     }
-    if (!tcell)
+    if (!tcell) {
+       /*printf("Lookup failed, returning ENODEV\n");*/
        return ENODEV;
+    }
 
     cellidx = tcell->cellIndex;
     mtptCell = tcell->cellNum; /* The cell for the mountpoint */
@@ -143,8 +147,10 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
        tfid.Fid.Volume = volid;        /* remember BK volume */
        tfid.Cell = mtptCell;
        tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK);   /* get the new one */
-       if (!tvp)
+       if (!tvp) {
+           /*printf("afs_GetVolume failed - returning ENODEV");*/
            return ENODEV;      /* oops, can't do it */
+       }
        goto done;
     }
 
@@ -179,6 +185,7 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
      * ".backup" in it, this will get the volume struct for the RW volume.
      * The RO volume will be prefetched if requested (but not returned).
      */
+    /*printf("Calling GetVolumeByName\n");*/
     tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetch, areq, WRITE_LOCK);
 
     /* If no volume was found in this cell, try the associated linked cell */
@@ -207,8 +214,10 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
        osi_FreeSmallSpace(buf);
     }
 
-    if (!tvp)
+    if (!tvp) {
+       /*printf("Couldn't find the volume\n");*/
        return ENODEV;          /* Couldn't find the volume */
+    }
 
     /* Don't cross mountpoint from a BK to a BK volume */
     if ((states & CBackup) && (tvp->states & VBackup)) {
@@ -1222,6 +1231,10 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
     AFS_STATCNT(afs_lookup);
     afs_InitFakeStat(&fakestate);
 
+    AFS_DISCON_LOCK();
+
+    /*printf("Looking up %s\n", aname);*/
+    
     if ((code = afs_InitReq(&treq, acred)))
        goto done;
 
@@ -1250,6 +1263,9 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
        code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
     else
        code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+
+    /*printf("Code is %d\n", code);*/
+    
     if (tryEvalOnly && adp->mvstat == 1)
        code = ENOENT;
     if (code)
@@ -1291,6 +1307,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
            goto done;
        }
        /* otherwise we have the fid here, so we use it */
+       /*printf("Getting vcache\n");*/
        tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
        afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid,
                   ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, code);
@@ -1550,7 +1567,8 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
        /* prefetch some entries, if the dir is currently open.  The variable
         * dirCookie tells us where to start prefetching from.
         */
-       if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)
+       if (!AFS_IS_DISCONNECTED && 
+           AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)
            && !afs_IsDynroot(adp) && !afs_InReadDir(adp)) {
            afs_int32 retry;
            /* if the entry is not in the cache, or is in the cache,
@@ -1697,25 +1715,30 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
         * be located (a Multics "connection failure").  If the volume is
         * read-only, we try flushing this entry from the cache and trying
         * again. */
-       if (pass == 0) {
-           struct volume *tv;
-           tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
-           if (tv) {
-               if (tv->states & VRO) {
-                   pass = 1;   /* try this *once* */
-                   ObtainWriteLock(&afs_xcbhash, 495);
-                   afs_DequeueCallback(adp);
-                   /* re-stat to get later version */
-                   adp->states &= ~CStatd;
-                   ReleaseWriteLock(&afs_xcbhash);
-                   osi_dnlc_purgedp(adp);
+       if (!AFS_IS_DISCONNECTED) {
+           if (pass == 0) {
+               struct volume *tv;
+               tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
+               if (tv) {
+                   if (tv->states & VRO) {
+                       pass = 1;       /* try this *once* */
+                       ObtainWriteLock(&afs_xcbhash, 495);
+                       afs_DequeueCallback(adp);
+                       /* re-stat to get later version */
+                       adp->states &= ~CStatd;
+                       ReleaseWriteLock(&afs_xcbhash);
+                       osi_dnlc_purgedp(adp);
+                       afs_PutVolume(tv, READ_LOCK);
+                       goto redo;
+                   }
                    afs_PutVolume(tv, READ_LOCK);
-                   goto redo;
-               }
-               afs_PutVolume(tv, READ_LOCK);
+               }
            }
+           code = ENOENT;
+       } else {
+           /*printf("Network down in afs_lookup\n");*/
+           code = ENETDOWN;
        }
-       code = ENOENT;
     }
 
   done:
@@ -1753,6 +1776,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
                code = afs_VerifyVCache(tvc, &treq);
 #else
                afs_PutFakeStat(&fakestate);
+               AFS_DISCON_UNLOCK();
                return 0;       /* can't have been any errors if hit and !code */
 #endif
            }
@@ -1769,5 +1793,6 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED
     }
 
     afs_PutFakeStat(&fakestate);
+    AFS_DISCON_UNLOCK();
     return code;
 }
index 998cf32..037cc8e 100644 (file)
@@ -59,12 +59,29 @@ afs_open(struct vcache **avcp, afs_int32 aflags, struct AFS_UCRED *acred)
     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
               ICL_TYPE_INT32, aflags);
     afs_InitFakeStat(&fakestate);
+
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
     if (code)
        goto done;
     code = afs_VerifyVCache(tvc, &treq);
     if (code)
        goto done;
+
+    ObtainReadLock(&tvc->lock);
+
+#ifdef AFS_DISCON_ENV
+    if (AFS_IS_DISCONNECTED && (afs_DCacheMissingChunks(tvc) != 0)) {
+       ReleaseReadLock(&tvc->lock);
+       /*printf("Network is down in afs_open: missing chunks\n");*/
+       code = ENETDOWN;
+       goto done;
+    }
+#endif
+
+    ReleaseReadLock(&tvc->lock);
+
     if (aflags & (FWRITE | FTRUNC))
        writing = 1;
     else
@@ -181,6 +198,8 @@ afs_open(struct vcache **avcp, afs_int32 aflags, struct AFS_UCRED *acred)
     }  
   done:
     afs_PutFakeStat(&fakestate);
+    AFS_DISCON_UNLOCK();
+
     code = afs_CheckCode(code, &treq, 4);      /* avoid AIX -O bug */
 
     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
index 77af418..7ffbc6d 100644 (file)
@@ -443,6 +443,15 @@ afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
        ReleaseReadLock(&adc->lock);
 
        tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2);    /* type 2 never returns 0 */
+#ifdef AFS_DISCON_ENV
+        /*
+         * In disconnected mode, type 2 can return 0 because it doesn't
+         * make any sense to allocate a dcache we can never fill
+         */
+         if (tdc == NULL)
+             return;
+#endif /* AFS_DISCON_ENV */
+
        ObtainSharedLock(&tdc->mflock, 651);
        if (!(tdc->mflags & DFFetchReq)) {
            /* ask the daemon to do the work */
@@ -512,6 +521,8 @@ afs_UFSRead(register struct vcache *avc, struct uio *auio,
     if (avc && avc->vc_error)
        return EIO;
 
+    AFS_DISCON_LOCK();
+    
     /* check that we have the latest status info in the vnode cache */
     if ((code = afs_InitReq(&treq, acred)))
        return code;
@@ -522,6 +533,7 @@ afs_UFSRead(register struct vcache *avc, struct uio *auio,
            code = afs_VerifyVCache(avc, &treq);
            if (code) {
                code = afs_CheckCode(code, &treq, 11);  /* failed to get it */
+               AFS_DISCON_UNLOCK();
                return code;
            }
        }
@@ -531,6 +543,7 @@ afs_UFSRead(register struct vcache *avc, struct uio *auio,
        if (!afs_AccessOK
            (avc, PRSFS_READ, &treq,
             CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
+           AFS_DISCON_UNLOCK();
            return afs_CheckCode(EACCES, &treq, 12);
        }
     }
@@ -621,6 +634,14 @@ afs_UFSRead(register struct vcache *avc, struct uio *auio,
                afs_PutDCache(tdc);     /* before reusing tdc */
            }
            tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
+#ifdef AFS_DISCON_ENV
+           if (!tdc) {
+               /*printf("Network down in afs_read");*/
+               error = ENETDOWN;
+               break;
+           }
+#endif /* AFS_DISCON_ENV */
+
            ObtainReadLock(&tdc->lock);
            /* now, first try to start transfer, if we'll need the data.  If
             * data already coming, we don't need to do this, obviously.  Type
@@ -952,6 +973,7 @@ afs_UFSRead(register struct vcache *avc, struct uio *auio,
 #else
     osi_FreeSmallSpace(tvec);
 #endif
+    AFS_DISCON_UNLOCK();
     error = afs_CheckCode(error, &treq, 13);
     return error;
 }
index 2d41c3d..025c8b9 100644 (file)
@@ -648,6 +648,9 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
     }
     /* update the cache entry */
     afs_InitFakeStat(&fakestate);
+
+    AFS_DISCON_LOCK();
+
     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
     if (code)
        goto done;
@@ -910,6 +913,7 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #ifdef AFS_HPUX_ENV
     osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+    AFS_DISCON_UNLOCK();
     afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 28);
     return code;
@@ -957,11 +961,13 @@ afs1_readdir(avc, auio, acred)
        return code;
     }
     afs_InitFakeStat(&fakestate);
+    AFS_DISCON_LOCK();
     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
     if (code) {
 #ifdef AFS_HPUX_ENV
        osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+       AFS_DISCON_UNLOCK();
        afs_PutFakeStat(&fakestate);
        return code;
     }
@@ -1177,6 +1183,7 @@ afs1_readdir(avc, auio, acred)
 #if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
     osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+    AFS_DISCON_UNLOCK();
     afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 29);
     return code;
index 98ea57f..6f8238a 100644 (file)
@@ -104,26 +104,29 @@ afsremove(register struct vcache *adp, register struct dcache *tdc,
          register struct vcache *tvc, char *aname, struct AFS_UCRED *acred,
          struct vrequest *treqp)
 {
-    register afs_int32 code;
+    register afs_int32 code = 0;
     register struct conn *tc;
     struct AFSFetchStatus OutDirStatus;
     struct AFSVolSync tsync;
     XSTATS_DECLS;
-    do {
-       tc = afs_Conn(&adp->fid, treqp, SHARED_LOCK);
-       if (tc) {
-           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
-           RX_AFS_GUNLOCK();
-           code =
-               RXAFS_RemoveFile(tc->id, (struct AFSFid *)&adp->fid.Fid,
-                                aname, &OutDirStatus, &tsync);
-           RX_AFS_GLOCK();
-           XSTATS_END_TIME;
-       } else
-           code = -1;
-    } while (afs_Analyze
-            (tc, code, &adp->fid, treqp, AFS_STATS_FS_RPCIDX_REMOVEFILE,
-             SHARED_LOCK, NULL));
+    
+    if (!AFS_IS_DISCONNECTED) {
+        do {
+           tc = afs_Conn(&adp->fid, treqp, SHARED_LOCK);
+           if (tc) {
+               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
+               RX_AFS_GUNLOCK();
+               code =
+                   RXAFS_RemoveFile(tc->id, (struct AFSFid *)&adp->fid.Fid,
+                                    aname, &OutDirStatus, &tsync);
+               RX_AFS_GLOCK();
+               XSTATS_END_TIME;
+           } else
+               code = -1;
+        } while (afs_Analyze
+                (tc, code, &adp->fid, treqp, AFS_STATS_FS_RPCIDX_REMOVEFILE,
+                 SHARED_LOCK, NULL));
+    }
 
     osi_dnlc_remove(adp, aname, tvc);
 
@@ -304,6 +307,16 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
        return code;
     }
 
+    /* If we're running disconnected without logging, go no further... */
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+#ifdef  AFS_OSF_ENV
+        afs_PutVCache(tvc);
+#endif
+        code = ENETDOWN;
+        afs_PutFakeStat(&fakestate);
+        return code;
+    }
+    
     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
     ObtainWriteLock(&adp->lock, 142);
     if (tdc)
index 02c67f9..58f2a69 100644 (file)
@@ -82,6 +82,12 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
            code = 0;
            goto done;
        }
+       
+       if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+           code = ENETDOWN;
+           goto done;
+       }
+       
        ObtainWriteLock(&andp->lock, 147);
        tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
        if (!tdc1) {
@@ -161,7 +167,6 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
        goto done;
     }
 
-    /* locks are now set, proceed to do the real work */
     do {
        tc = afs_Conn(&aodp->fid, areq, SHARED_LOCK);
        if (tc) {
@@ -376,6 +381,9 @@ afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, s
        return code;
     afs_InitFakeStat(&ofakestate);
     afs_InitFakeStat(&nfakestate);
+
+    AFS_DISCON_LOCK();
+    
     code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
     if (code)
        goto done;
@@ -386,6 +394,9 @@ afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, s
   done:
     afs_PutFakeStat(&ofakestate);
     afs_PutFakeStat(&nfakestate);
+
+    AFS_DISCON_UNLOCK();
+    
     code = afs_CheckCode(code, &treq, 25);
     return code;
 }
index 22aa636..8f532fc 100644 (file)
@@ -76,6 +76,9 @@ int afs_symlink
        goto done2;
 
     afs_InitFakeStat(&fakestate);
+
+    AFS_DISCON_LOCK();
+    
     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
     if (code)
        goto done;
@@ -108,6 +111,11 @@ int afs_symlink
        goto done;
     }
 
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
+        code = ENETDOWN;
+        goto done;
+    }
+    
     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
     InStatus.ClientModTime = osi_Time();
     alen = strlen(atargetName);        /* we want it to include the null */
@@ -235,6 +243,7 @@ int afs_symlink
     afs_PutFakeStat(&fakestate);
     if (volp)
        afs_PutVolume(volp, READ_LOCK);
+    AFS_DISCON_UNLOCK();
     code = afs_CheckCode(code, &treq, 31);
   done2:
     return code;
@@ -310,7 +319,10 @@ afs_UFSHandleLink(register struct vcache *avc, struct vrequest *areq)
                   ICL_TYPE_POINTER, tdc, ICL_TYPE_OFFSET,
                   ICL_HANDLE_OFFSET(avc->m.Length));
        if (!tdc) {
-           return EIO;
+           if (AFS_IS_DISCONNECTED)
+               return ENETDOWN;
+           else
+               return EIO;
        }
        /* otherwise we have the data loaded, go for it */
        if (len > 1024) {
@@ -360,6 +372,9 @@ afs_readlink(OSI_VC_ARG(avc), auio, acred)
     if ((code = afs_InitReq(&treq, acred)))
        return code;
     afs_InitFakeStat(&fakestat);
+
+    AFS_DISCON_LOCK();
+    
     code = afs_EvalFakeStat(&avc, &fakestat, &treq);
     if (code)
        goto done;
@@ -384,6 +399,7 @@ afs_readlink(OSI_VC_ARG(avc), auio, acred)
     ReleaseWriteLock(&avc->lock);
   done:
     afs_PutFakeStat(&fakestat);
+    AFS_DISCON_UNLOCK();
     code = afs_CheckCode(code, &treq, 32);
     return code;
 }
index 5971871..8f467e2 100644 (file)
@@ -382,6 +382,9 @@ afs_UFSWrite(register struct vcache *avc, struct uio *auio, int aio,
     if (avc->vc_error)
        return avc->vc_error;
 
+    if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING)
+       return ENETDOWN;
+    
     startDate = osi_Time();
     if ((code = afs_InitReq(&treq, acred)))
        return code;
index 6ee02e1..44745cc 100644 (file)
@@ -318,6 +318,20 @@ afs_Analyze(register struct conn *aconn, afs_int32 acode,
     struct afs_stats_RPCErrors *aerrP;
     afs_int32 markeddown;
 
+    if (AFS_IS_DISCONNECTED) {
+        /* SXW - This may get very tired after a while. We should try and
+        *       intercept all RPCs before they get here ... */
+       /*printf("afs_Analyze: disconnected\n");*/
+       afs_FinalizeReq(areq);
+       if (aconn) {
+           /* SXW - I suspect that this will _never_ happen - we shouldn't
+            *       get a connection because we're disconnected !!!*/
+           afs_PutConn(aconn, locktype);
+       }
+       return 0;
+    }
+    
     AFS_STATCNT(afs_Analyze);
     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
               ICL_TYPE_POINTER, aconn, ICL_TYPE_INT32, acode, ICL_TYPE_LONG,
index bae3f01..24e30c5 100644 (file)
@@ -158,6 +158,12 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
        ReleaseSharedLock(&afs_xconn);
        return NULL;
     }
+    
+    if (AFS_IS_DISCONNECTED) {
+        afs_warnuser("afs_ConnBySA: disconnected\n");
+        ReleaseSharedLock(&afs_xconn);
+        return NULL;
+    }
 
     if (!tc) {
        /* No such connection structure exists.  Create one and splice it in.
@@ -269,6 +275,12 @@ afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
     struct srvAddr *sa = 0;
 
     AFS_STATCNT(afs_ConnByHost);
+
+    if (AFS_IS_DISCONNECTED) {
+        afs_warnuser("afs_ConnByHost: disconnected\n");
+        return NULL;
+    }
+
 /* 
   1.  look for an existing connection
   2.  create a connection at an address believed to be up
index 051d017..b5e21b3 100644 (file)
@@ -195,9 +195,11 @@ afs_Daemon(void)
            afs_FlushReclaimedVcaches();
            ReleaseWriteLock(&afs_xvcache);
            afs_FlushActiveVcaches(1);  /* keep flocks held & flush nfs writes */
+#if 0
 #ifdef AFS_DISCON_ENV
            afs_StoreDirtyVcaches();
 #endif
+#endif
            afs_CheckRXEpoch();
            last1MinCheck = now;
        }
index beac6cd..1316f91 100644 (file)
@@ -1292,13 +1292,67 @@ afs_TryToSmush(register struct vcache *avc, struct AFS_UCRED *acred, int sync)
 #endif
     MReleaseWriteLock(&afs_xdcache);
     /*
-     * It's treated like a callback so that when we do lookups we'll invalidate the unique bit if any
+     * It's treated like a callback so that when we do lookups we'll 
+     * invalidate the unique bit if any
      * trytoSmush occured during the lookup call
      */
     afs_allCBs++;
 }
 
 /*
+ * afs_DCacheMissingChunks
+ *
+ * Description
+ *     Given the cached info for a file, return the number of chunks that
+ *     are not available from the dcache.
+ * 
+ * Parameters:
+ *     avc:    Pointer to the (held) vcache entry to look in.
+ * 
+ * Returns:
+ *     The number of chunks which are not currently cached.
+ * 
+ * Environment:
+ *     The vcache entry is held upon entry.
+ */
+
+int
+afs_DCacheMissingChunks(struct vcache *avc)
+{
+    int i, index;
+    afs_size_t totalLength;
+    afs_uint32 totalChunks;
+    struct dcache *tdc;
+
+    totalLength = avc->m.Length;
+    if (avc->truncPos < totalLength)
+        totalLength = avc->truncPos;
+
+    totalChunks = AFS_CHUNK(totalLength) + 1;
+
+    /*printf("Should have %d chunks for %d bytes\n", totalChunks, totalLength);*/
+    
+    i = DVHash(&avc->fid);
+    MObtainWriteLock(&afs_xdcache, 1001);
+    for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
+        i = afs_dvnextTbl[index];
+        if (afs_indexUnique[index] == avc->fid.Fid.Unique) {
+            tdc = afs_GetDSlot(index, NULL);
+            if (!FidCmp(&tdc->f.fid, &avc->fid)) {
+               totalChunks--;
+            }
+            ReleaseReadLock(&tdc->tlock);
+            afs_PutDCache(tdc);
+        }
+    }
+    MReleaseWriteLock(&afs_xdcache);
+
+    /*printf("Missing %d chunks\n", totalChunks);*/
+
+    return (totalChunks);
+}
+
+/*
  * afs_FindDCache
  *
  * Description:
@@ -1815,6 +1869,17 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
         * If we didn't find the entry, we'll create one.
         */
        if (index == NULLIDX) {
+           /* If we're disconnected, we can't do anything */
+            if (AFS_IS_DISCONNECTED) {
+                MReleaseWriteLock(&afs_xdcache);
+                if (setLocks) {
+                    if (slowPass)
+                       ReleaseWriteLock(&avc->lock);
+                   else
+                       ReleaseReadLock(&avc->lock);
+                }
+                return NULL;
+            }
            /*
             * Locks held:
             * avc->lock(R) if setLocks
@@ -2059,6 +2124,23 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
        /*
         * Version number mismatch.
         */
+        /*
+         * If we are disconnected, then we can't do much of anything
+         * because the data doesn't match the file.
+         */
+        if (AFS_IS_DISCONNECTED) {
+            ReleaseSharedLock(&tdc->lock);
+            if (setLocks) {
+                if (slowPass)
+                    ReleaseWriteLock(&avc->lock);
+                else
+                    ReleaseReadLock(&avc->lock);
+            }
+            /* Flush the Dcache */
+            afs_PutDCache(tdc);
+                
+            return NULL;
+        }
        UpgradeSToWLock(&tdc->lock, 609);
 
        /*
diff --git a/src/afs/afs_disconnected.c b/src/afs/afs_disconnected.c
new file mode 100644 (file)
index 0000000..5d8e330
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+RCSID("$Header$");
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#ifdef AFS_DISCON_ENV
+
+/* Nothing here any more. Remove from the build unless stuff comes back! */
+#endif
index 87b2b73..8364770 100644 (file)
@@ -45,6 +45,9 @@ int afs_memvolumes = 0;
 #if defined(AFS_XBSD_ENV)
 static struct vnode *volumeVnode;
 #endif
+#if defined(AFS_DISCON_ENV)
+afs_rwlock_t afs_discon_lock;
+#endif
 
 /*
  * Initialization order is important.  Must first call afs_CacheInit,
@@ -110,6 +113,9 @@ afs_CacheInit(afs_int32 astatSize, afs_int32 afiles, afs_int32 ablocks,
 
     LOCK_INIT(&afs_ftf, "afs_ftf");
     RWLOCK_INIT(&afs_xaxs, "afs_xaxs");
+#ifdef AFS_DISCON_ENV
+    RWLOCK_INIT(&afs_discon_lock, "afs_discon_lock");
+#endif
     osi_dnlc_init();
 
     /* 
index d533096..83a8288 100644 (file)
@@ -30,6 +30,11 @@ afs_int32 afs_waitForever = 0;
 short afs_waitForeverCount = 0;
 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE;        /* show all messages */
 
+#ifdef AFS_DISCON_ENV
+afs_int32 afs_is_disconnected;
+afs_int32 afs_is_logging;
+#endif
+
 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
        char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
        struct AFS_UCRED **acred)
@@ -3991,6 +3996,52 @@ DECL_PIOCTL(PDiscon)
 #endif
 }
 
+DECL_PIOCTL(PDiscon)
+{
+#ifdef AFS_DISCON_ENV
+    static afs_int32 mode = 4; /* Start up in 'full' */
+
+    if (ainSize == sizeof(afs_int32)) {
+
+       if (!afs_osi_suser(*acred))
+           return EPERM;
+
+       memcpy(&mode, ain, sizeof(afs_int32));
+
+       /*
+        * All of these numbers are hard coded in fs.c. If they
+        * change here, they should change there and vice versa
+        */
+       switch (mode) {
+       case 0: /* Disconnect, breaking all callbacks */
+           if (!AFS_IS_DISCONNECTED) {
+               ObtainWriteLock(&afs_discon_lock, 999);
+               afs_DisconGiveUpCallbacks();
+               afs_RemoveAllConns();
+               afs_is_disconnected = 1;
+               ReleaseWriteLock(&afs_discon_lock);
+           }
+           break;
+       case 4: /* Fully connected */
+           ObtainWriteLock(&afs_discon_lock, 998);
+           afs_is_disconnected = 0;
+           ReleaseWriteLock(&afs_discon_lock);
+           break;
+       default:
+           return EINVAL;
+       }
+    } else {
+       return EINVAL;
+    }
+
+    memcpy(aout, &mode, sizeof(afs_int32));
+    *aoutSize = sizeof(afs_int32);
+    return 0;
+#else
+    return EINVAL;
+#endif
+}
+
 DECL_PIOCTL(PNFSNukeCreds)
 {
     afs_uint32 addr, code;
index 0bd4077..ed9116c 100644 (file)
@@ -269,7 +269,9 @@ extern struct dcache *afs_UFSGetDSlot(register afs_int32 aslot,
 extern int afs_WriteDCache(register struct dcache *adc, int atime);
 extern int afs_wakeup(register struct vcache *avc);
 extern int afs_InitCacheFile(char *afile, ino_t ainode);
+extern int afs_DCacheHasAllChunks(struct vcache *avc);
 
+/* afs_disconnected.c */
 
 /* afs_dynroot.c */
 extern int afs_IsDynrootFid(struct VenusFid *fid);
@@ -769,7 +771,7 @@ void afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa);
 #endif
 extern int afs_HaveCallBacksFrom(struct server *aserver);
 extern void shutdown_server(void);
-
+extern void afs_RemoveAllConns(void);
 
 
 /* afs_osidnlc.c */
@@ -939,6 +941,7 @@ extern afs_int32 afs_NFSFindVCache(struct vcache **avcp,
                                   struct VenusFid *afid);
 extern void afs_vcacheInit(int astatSize);
 extern void shutdown_vcache(void);
+extern void afs_DisconGiveUpCallbacks(void);
 
 
 /* VNOPS/afs_vnop_access.c */
index d6d21c7..81b403e 100644 (file)
@@ -215,7 +215,13 @@ afs_StoreAllSegments(register struct vcache *avc, struct vrequest *areq,
 #endif
            osi_VM_StoreAllSegments(avc);
     }
-
+    if (AFS_IS_DISCONNECTED) {
+        if (!AFS_IS_LOGGING) {
+            /* This will probably make someone sad ... */
+           /*printf("Net down in afs_StoreSegments\n");*/
+            return ENETDOWN;
+        }
+    }
     ConvertWToSLock(&avc->lock);
 
     /*
index abf485e..33cae8e 100644 (file)
@@ -547,6 +547,13 @@ afs_CheckServers(int adown, struct cell *acellp)
 
     AFS_STATCNT(afs_CheckServers);
 
+    /* 
+     * No sense in doing the server checks if we are running in disconnected
+     * mode
+     */
+    if (AFS_IS_DISCONNECTED)
+        return;
+
     conns = (struct conn **)0;
     rxconns = (struct rx_connection **) 0;
     conntimer = 0;
@@ -1845,6 +1852,46 @@ void afs_ActivateServer(struct srvAddr *sap) {
     }
 }
 
+#ifdef AFS_DISCON_ENV
+
+void afs_RemoveAllConns()
+{
+    int i;
+    struct server *ts, *nts;
+    struct srvAddr *sa;
+    struct conn *tc, *ntc;
+
+    ObtainReadLock(&afs_xserver);
+    ObtainWriteLock(&afs_xconn, 1001);
+    
+    /*printf("Destroying connections ... ");*/
+    for (i = 0; i < NSERVERS; i++) {
+        for (ts = afs_servers[i]; ts; ts = nts) {
+            nts = ts->next;
+            for (sa = ts->addr; sa; sa = sa->next_sa) {
+                if (sa->conns) {
+                    tc = sa->conns;
+                    while (tc) {
+                        ntc = tc->next;
+                        AFS_GUNLOCK();
+                        rx_DestroyConnection(tc->id);
+                        AFS_GLOCK();
+                        afs_osi_Free(tc, sizeof(struct conn));
+                        tc = ntc;
+                    }
+                    sa->conns = NULL;
+                }
+            }
+        }
+    }
+    /*printf("done\n");*/
+
+    ReleaseWriteLock(&afs_xconn);
+    ReleaseReadLock(&afs_xserver);
+    
+}
+
+#endif /* AFS_DISCON_ENV */
 
 void shutdown_server()
 {
index 9c67dfd..9f33f88 100644 (file)
@@ -1658,7 +1658,7 @@ afs_RemoteLookup(register struct VenusFid *afid, struct vrequest *areq,
     struct AFSFetchStatus OutDirStatus;
     XSTATS_DECLS;
     if (!name)
-       name = "";              /* XXX */
+       name = "";              /* XXX */    
     do {
        tc = afs_Conn(afid, areq, SHARED_LOCK);
        if (tc) {
@@ -1899,7 +1899,15 @@ afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq,
            tvc->parentUnique = OutStatus.ParentUnique;
            code = 0;
        } else {
-           code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
+           /* If we've got here and we're disconnected, then we can go
+            * no further
+            */
+           if (AFS_IS_DISCONNECTED) {
+               code = ENETDOWN;
+               /*printf("Network is down in afs_GetCache");*/
+           } 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
@@ -1986,9 +1994,14 @@ afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
     nfid = *afid;
     now = osi_Time();
     origCBs = afs_allCBs;      /* if anything changes, we don't have a cb */
-    code =
-       afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, &CallBack,
-                        &serverp, &tsync);
+    
+    if (AFS_IS_DISCONNECTED) {
+       /*printf("Network is down in afs_LookupVcache\n");*/
+        code = ENETDOWN;
+    } else 
+        code =
+           afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, 
+                            &CallBack, &serverp, &tsync);
 
 #if    defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
   loop2:
@@ -3103,3 +3116,32 @@ shutdown_vcache(void)
     for(i = 0; i < VCSIZE; ++i)
        QInit(&afs_vhashTV[i]);
 }
+
+#ifdef AFS_DISCON_ENV
+void afs_DisconGiveUpCallbacks() {
+    int i;
+    struct vcache *tvc;
+    int nq=0;
+            
+    ObtainWriteLock(&afs_xvcache, 1002); /* XXX - should be a unique number */
+    
+    /* Somehow, walk the set of vcaches, with each one coming out as tvc */
+    for (i = 0; i < VCSIZE; i++) {
+        for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
+            if ((tvc->states & CRO) == 0 && tvc->callback) {
+                /* XXX - should we check if the callback has expired here? */
+                afs_QueueVCB(tvc);
+                tvc->callback = NULL;
+                tvc->states &- ~(CStatd | CUnique);
+                nq++;
+            }
+        }
+    }
+    /*printf("%d callbacks to be discarded. queued ... ", nq);*/
+    afs_FlushVCBs(0);
+    
+    ReleaseWriteLock(&afs_xvcache);
+    /*printf("gone\n");*/
+}
+
+#endif
index 95dde56..0453f0a 100644 (file)
@@ -578,6 +578,9 @@ afs_GetVolumeByName(register char *aname, afs_int32 acell, int agood,
 
     ReleaseWriteLock(&afs_xvolume);
 
+    if (AFS_IS_DISCONNECTED)
+        return NULL;
+
     tv = afs_NewVolumeByName(aname, acell, agood, areq, locktype);
     return (tv);
 }
index 72c68db..898b1d0 100644 (file)
@@ -51,6 +51,7 @@
 #include "afs/icl.h"
 #include "afs/afs_stats.h"
 #include "afs/afs_prototypes.h"
+#include "afs/discon.h"
 #if defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
 #include "osi_machdep.h"
 #endif
diff --git a/src/afs/discon.h b/src/afs/discon.h
new file mode 100644 (file)
index 0000000..6107f41
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _DISCON_H
+#define _DISCON_H
+
+#ifndef AFS_DISCON_ENV
+#define AFS_IS_DISCONNECTED 0
+#define AFS_IS_LOGGING 0
+#define AFS_DISCON_LOCK()
+#define AFS_DISCON_UNLOCK()
+
+#else
+
+extern afs_int32    afs_is_disconnected;
+extern afs_int32    afs_is_logging;
+extern afs_rwlock_t afs_discon_lock;
+
+#define AFS_IS_DISCONNECTED (afs_is_disconnected)
+#define AFS_IS_LOGGING (afs_is_logging)
+#define AFS_DISCON_LOCK() ObtainReadLock(&afs_discon_lock)
+#define AFS_DISCON_UNLOCK() ReleaseReadLock(&afs_discon_lock)
+
+#endif /* AFS_DISCON_ENV */
+#endif /* _DISCON_H */
index 53338f5..87dd84e 100644 (file)
@@ -85,6 +85,7 @@ AFSAOBJS = \
        afs_daemons.o   \
        afs_dcache.o \
        afs_dir.o               \
+       afs_disconnected.o      \
        afs_dynroot.o           \
        afs_error.o \
        afs_icl.o \
@@ -245,6 +246,8 @@ afs_conn.o: $(TOP_SRC_AFS)/afs_conn.c
        $(CRULE_OPT)
 afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c
        $(CRULE_OPT)
+afs_disconnected.o: $(TOP_SRC_AFS)/afs_disconnected.c
+       $(CRULE_OPT)
 afs_dynroot.o:         $(TOP_SRC_AFS)/afs_dynroot.c
        $(CRULE_OPT)
 afs_error.o: $(TOP_SRC_AFS)/afs_error.c
index 7340183..0d3f2c6 100644 (file)
@@ -95,6 +95,7 @@ UAFSOBJ = \
        $(UOBJ)/afs_daemons.o   \
        $(UOBJ)/afs_dcache.o \
        $(UOBJ)/afs_dir.o               \
+       $(UOBJ)/afs_disconnected.o      \
        $(UOBJ)/afs_dynroot.o \
        $(UOBJ)/afs_icl.o \
        $(UOBJ)/afs_init.o \
@@ -220,6 +221,7 @@ AFSWEBOBJ = \
        $(WEBOBJ)/afs_daemons.o \
        $(WEBOBJ)/afs_dcache.o \
        $(WEBOBJ)/afs_dir.o \
+       $(WEBOBJ)/afs_disconnected.o \
        $(WEBOBJ)/afs_dynroot.o \
        $(WEBOBJ)/afs_icl.o \
        $(WEBOBJ)/afs_init.o \
@@ -347,6 +349,7 @@ AFSWEBOBJKRB = \
        $(WEBOBJ)/afs_dcache.o \
        $(WEBOBJ)/afs_dir.o \
        $(WEBOBJ)/afs_dynroot.o \
+       $(WEBOBJ)/afs_disconnected.o \
        $(WEBOBJ)/afs_icl.o \
        $(WEBOBJ)/afs_init.o \
        $(WEBOBJ)/afs_lock.o \
@@ -468,6 +471,7 @@ JUAFSOBJ = \
        $(JUAFS)/afs_dcache.o \
        $(JUAFS)/afs_dir.o \
        $(JUAFS)/afs_dynroot.o \
+       $(JUAFS)/afs_disconnected.o \
        $(JUAFS)/afs_icl.o \
        $(JUAFS)/afs_init.o \
        $(JUAFS)/afs_lock.o     \
@@ -597,6 +601,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_disconnected.o: $(TOP_SRC_AFS)/afs_disconnected.c
+       $(CRULE1)
 $(UOBJ)/afs_error.o: $(TOP_SRC_AFS)/afs_error.c
        $(CRULE1)
 $(UOBJ)/afs_init.o: $(TOP_SRC_AFS)/afs_init.c
@@ -852,6 +858,8 @@ $(WEBOBJ)/afs_conn.o: $(TOP_SRC_AFS)/afs_conn.c
        $(CRULE2)
 $(WEBOBJ)/afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c
        $(CRULE2)
+$(WEBOBJ)/afs_disconnected.o: $(TOP_SRC_AFS)/afs_disconnected.c
+       $(CRULE2)
 $(WEBOBJ)/afs_dynroot.o: $(TOP_SRC_AFS)/afs_dynroot.c
        $(CRULE2)
 $(WEBOBJ)/afs_error.o: $(TOP_SRC_AFS)/afs_error.c
@@ -1113,6 +1121,8 @@ $(JUAFS)/afs_conn.o: $(TOP_SRC_AFS)/afs_conn.c
        $(CRULE1)
 $(JUAFS)/afs_dcache.o: $(TOP_SRC_AFS)/afs_dcache.c
        $(CRULE1)
+$(JUAFS)/afs_disconnected.o: $(TOP_SRC_AFS)/afs_disconnected.c
+       $(CRULE1)
 $(JUAFS)/afs_dynroot.o: $(TOP_SRC_AFS)/afs_dynroot.c
        $(CRULE1)
 $(JUAFS)/afs_error.o: $(TOP_SRC_AFS)/afs_error.c
index 4651742..693a482 100644 (file)
@@ -3308,9 +3308,9 @@ GetCryptCmd(struct cmd_syndesc *as, void *arock)
 
 #ifdef AFS_DISCON_ENV
 static char *modenames[] = {
-    "discon",
-    "fetchonly",
-    "partial",
+    "readonly",
+    "fetchonly", /* Not currently supported */
+    "partial",   /* Not currently supported */
     "nat",
     "full",
     NULL
@@ -3681,7 +3681,7 @@ defect 3069
 #ifdef AFS_DISCON_ENV
     ts = cmd_CreateSyntax("discon", DisconCmd, NULL,
                          "disconnection mode");
-    cmd_AddParm(ts, "-mode", CMD_SINGLE, CMD_OPTIONAL, "nat | full");
+    cmd_AddParm(ts, "-mode", CMD_SINGLE, CMD_OPTIONAL, "readonly | nat | full");
 #endif
 
     ts = cmd_CreateSyntax("nukenfscreds", NukeNFSCredsCmd, NULL, "nuke credentials for NFS client");