From 18a36a3f624755fbcaee776102177f47e26711b7 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Fri, 23 May 2008 15:57:18 +0000 Subject: [PATCH] disconnected-20080523 LICENSE IPL10 add readonly disconnected support --- acinclude.m4 | 6 ++ src/afs/UKERNEL/afsincludes.h | 1 + src/afs/VNOPS/afs_vnop_access.c | 18 +++++ src/afs/VNOPS/afs_vnop_attrs.c | 46 ++++++++---- src/afs/VNOPS/afs_vnop_create.c | 21 +++++- src/afs/VNOPS/afs_vnop_dirops.c | 23 +++++- src/afs/VNOPS/afs_vnop_flock.c | 149 +++++++++++++++++++++++---------------- src/afs/VNOPS/afs_vnop_link.c | 9 +++ src/afs/VNOPS/afs_vnop_lookup.c | 65 +++++++++++------ src/afs/VNOPS/afs_vnop_open.c | 19 +++++ src/afs/VNOPS/afs_vnop_read.c | 22 ++++++ src/afs/VNOPS/afs_vnop_readdir.c | 7 ++ src/afs/VNOPS/afs_vnop_remove.c | 45 +++++++----- src/afs/VNOPS/afs_vnop_rename.c | 13 +++- src/afs/VNOPS/afs_vnop_symlink.c | 18 ++++- src/afs/VNOPS/afs_vnop_write.c | 3 + src/afs/afs_analyze.c | 14 ++++ src/afs/afs_conn.c | 12 ++++ src/afs/afs_daemons.c | 2 + src/afs/afs_dcache.c | 84 +++++++++++++++++++++- src/afs/afs_disconnected.c | 18 +++++ src/afs/afs_init.c | 6 ++ src/afs/afs_pioctl.c | 51 ++++++++++++++ src/afs/afs_prototypes.h | 5 +- src/afs/afs_segments.c | 8 ++- src/afs/afs_server.c | 47 ++++++++++++ src/afs/afs_vcache.c | 52 ++++++++++++-- src/afs/afs_volume.c | 3 + src/afs/afsincludes.h | 1 + src/afs/discon.h | 22 ++++++ src/libafs/Makefile.common.in | 3 + src/libuafs/Makefile.common.in | 10 +++ src/venus/fs.c | 8 +-- 33 files changed, 683 insertions(+), 128 deletions(-) create mode 100644 src/afs/afs_disconnected.c create mode 100644 src/afs/discon.h diff --git a/acinclude.m4 b/acinclude.m4 index 4dbe71f..e5acb84 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -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" diff --git a/src/afs/UKERNEL/afsincludes.h b/src/afs/UKERNEL/afsincludes.h index 049475d..9ae9a17 100644 --- a/src/afs/UKERNEL/afsincludes.h +++ b/src/afs/UKERNEL/afsincludes.h @@ -26,3 +26,4 @@ #include "afs/icl.h" #include "afs/afs_stats.h" #include "afs/afs_prototypes.h" +#include "afs/discon.h" diff --git a/src/afs/VNOPS/afs_vnop_access.c b/src/afs/VNOPS/afs_vnop_access.c index 7e2cd73..74f4050 100644 --- a/src/afs/VNOPS/afs_vnop_access.c +++ b/src/afs/VNOPS/afs_vnop_access.c @@ -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 { diff --git a/src/afs/VNOPS/afs_vnop_attrs.c b/src/afs/VNOPS/afs_vnop_attrs.c index 3f85e6c..26f4dfb 100644 --- a/src/afs/VNOPS/afs_vnop_attrs.c +++ b/src/afs/VNOPS/afs_vnop_attrs.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_create.c b/src/afs/VNOPS/afs_vnop_create.c index bdf35a9..95eb550 100644 --- a/src/afs/VNOPS/afs_vnop_create.c +++ b/src/afs/VNOPS/afs_vnop_create.c @@ -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); diff --git a/src/afs/VNOPS/afs_vnop_dirops.c b/src/afs/VNOPS/afs_vnop_dirops.c index 5e73dd0..a0a0b03 100644 --- a/src/afs/VNOPS/afs_vnop_dirops.c +++ b/src/afs/VNOPS/afs_vnop_dirops.c @@ -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: diff --git a/src/afs/VNOPS/afs_vnop_flock.c b/src/afs/VNOPS/afs_vnop_flock.c index 5e4b0e6..7be73e7 100644 --- a/src/afs/VNOPS/afs_vnop_flock.c +++ b/src/afs/VNOPS/afs_vnop_flock.c @@ -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 diff --git a/src/afs/VNOPS/afs_vnop_link.c b/src/afs/VNOPS/afs_vnop_link.c index 04c08a6..4350af4 100644 --- a/src/afs/VNOPS/afs_vnop_link.c +++ b/src/afs/VNOPS/afs_vnop_link.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index 6389263..fa2727f 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_open.c b/src/afs/VNOPS/afs_vnop_open.c index 998cf32..037cc8e 100644 --- a/src/afs/VNOPS/afs_vnop_open.c +++ b/src/afs/VNOPS/afs_vnop_open.c @@ -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, diff --git a/src/afs/VNOPS/afs_vnop_read.c b/src/afs/VNOPS/afs_vnop_read.c index 77af418..7ffbc6d 100644 --- a/src/afs/VNOPS/afs_vnop_read.c +++ b/src/afs/VNOPS/afs_vnop_read.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_readdir.c b/src/afs/VNOPS/afs_vnop_readdir.c index 2d41c3d..025c8b9 100644 --- a/src/afs/VNOPS/afs_vnop_readdir.c +++ b/src/afs/VNOPS/afs_vnop_readdir.c @@ -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; diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index 98ea57f..6f8238a 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -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) diff --git a/src/afs/VNOPS/afs_vnop_rename.c b/src/afs/VNOPS/afs_vnop_rename.c index 02c67f9..58f2a69 100644 --- a/src/afs/VNOPS/afs_vnop_rename.c +++ b/src/afs/VNOPS/afs_vnop_rename.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_symlink.c b/src/afs/VNOPS/afs_vnop_symlink.c index 22aa636..8f532fc 100644 --- a/src/afs/VNOPS/afs_vnop_symlink.c +++ b/src/afs/VNOPS/afs_vnop_symlink.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_write.c b/src/afs/VNOPS/afs_vnop_write.c index 5971871..8f467e2 100644 --- a/src/afs/VNOPS/afs_vnop_write.c +++ b/src/afs/VNOPS/afs_vnop_write.c @@ -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; diff --git a/src/afs/afs_analyze.c b/src/afs/afs_analyze.c index 6ee02e1..44745cc 100644 --- a/src/afs/afs_analyze.c +++ b/src/afs/afs_analyze.c @@ -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, diff --git a/src/afs/afs_conn.c b/src/afs/afs_conn.c index bae3f01..24e30c5 100644 --- a/src/afs/afs_conn.c +++ b/src/afs/afs_conn.c @@ -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 diff --git a/src/afs/afs_daemons.c b/src/afs/afs_daemons.c index 051d017..b5e21b3 100644 --- a/src/afs/afs_daemons.c +++ b/src/afs/afs_daemons.c @@ -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; } diff --git a/src/afs/afs_dcache.c b/src/afs/afs_dcache.c index beac6cd..1316f91 100644 --- a/src/afs/afs_dcache.c +++ b/src/afs/afs_dcache.c @@ -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 index 0000000..5d8e330 --- /dev/null +++ b/src/afs/afs_disconnected.c @@ -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 +#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 diff --git a/src/afs/afs_init.c b/src/afs/afs_init.c index 87b2b73..8364770 100644 --- a/src/afs/afs_init.c +++ b/src/afs/afs_init.c @@ -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(); /* diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index d533096..83a8288 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -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; diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 0bd4077..ed9116c 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -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 */ diff --git a/src/afs/afs_segments.c b/src/afs/afs_segments.c index d6d21c7..81b403e 100644 --- a/src/afs/afs_segments.c +++ b/src/afs/afs_segments.c @@ -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); /* diff --git a/src/afs/afs_server.c b/src/afs/afs_server.c index abf485e..33cae8e 100644 --- a/src/afs/afs_server.c +++ b/src/afs/afs_server.c @@ -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() { diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 9c67dfd..9f33f88 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -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 diff --git a/src/afs/afs_volume.c b/src/afs/afs_volume.c index 95dde56..0453f0a 100644 --- a/src/afs/afs_volume.c +++ b/src/afs/afs_volume.c @@ -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); } diff --git a/src/afs/afsincludes.h b/src/afs/afsincludes.h index 72c68db..898b1d0 100644 --- a/src/afs/afsincludes.h +++ b/src/afs/afsincludes.h @@ -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 index 0000000..6107f41 --- /dev/null +++ b/src/afs/discon.h @@ -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 */ diff --git a/src/libafs/Makefile.common.in b/src/libafs/Makefile.common.in index 53338f5..87dd84e 100644 --- a/src/libafs/Makefile.common.in +++ b/src/libafs/Makefile.common.in @@ -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 diff --git a/src/libuafs/Makefile.common.in b/src/libuafs/Makefile.common.in index 7340183..0d3f2c6 100644 --- a/src/libuafs/Makefile.common.in +++ b/src/libuafs/Makefile.common.in @@ -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 diff --git a/src/venus/fs.c b/src/venus/fs.c index 4651742..693a482 100644 --- a/src/venus/fs.c +++ b/src/venus/fs.c @@ -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"); -- 1.9.4