From 49a95f7c2bd550436e4bb2b7b4e9843315c0ebba Mon Sep 17 00:00:00 2001 From: Marcio Barbosa Date: Tue, 29 Dec 2015 10:31:43 -0300 Subject: [PATCH] afs: do not allow two shutdown sequences in parallel MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Often, ‘afsd -shutdown’ is called right after ‘umount’. Both commands hold the glock before calling ‘afs_shutdown’. However, one of the functions called by 'afs_shutdown', namely, ‘afs_FlushVCBs’, might drop the glock when the global 'afs_shuttingdown' is still equal to 0. As a result, a scenario with two shutdown sequences proceeding in parallel is possible. To fix the problem, the global ‘afs_shuttingdown’ is used as an enumerated type to make sure that the second thread will not run ‘afs_shutdown’ while the first one is stuck inside ‘afs_FlushVCBs’. Reviewed-on: http://gerrit.openafs.org/12016 Tested-by: BuildBot Reviewed-by: Chas Williams <3chas3@gmail.com> Reviewed-by: Michael Meffie Reviewed-by: Benjamin Kaduk (cherry picked from commit 70fd9bc6dcc79cb25e98cdcfd0f085c4bf4f310a) Change-Id: I073d1914a7daa858a78305ff154074f2a51a9f5f Reviewed-on: https://gerrit.openafs.org/12179 Tested-by: BuildBot Reviewed-by: Marcio Brito Barbosa Reviewed-by: Benjamin Kaduk Reviewed-by: Stephan Wiesand --- src/afs/AIX/osi_file.c | 2 +- src/afs/DARWIN/osi_file.c | 2 +- src/afs/DARWIN/osi_module.c | 2 +- src/afs/FBSD/osi_file.c | 2 +- src/afs/HPUX/osi_file.c | 2 +- src/afs/HPUX/osi_vnodeops.c | 2 +- src/afs/IRIX/osi_file.c | 2 +- src/afs/LINUX/osi_file.c | 4 ++-- src/afs/LINUX/osi_vnodeops.c | 2 +- src/afs/LINUX24/osi_file.c | 4 ++-- src/afs/LINUX24/osi_vnodeops.c | 2 +- src/afs/NBSD/osi_file.c | 2 +- src/afs/OBSD/osi_file.c | 2 +- src/afs/SOLARIS/osi_file.c | 2 +- src/afs/SOLARIS/osi_vnodeops.c | 2 +- src/afs/UKERNEL/osi_vnodeops.c | 2 +- src/afs/VNOPS/afs_vnop_attrs.c | 2 +- src/afs/VNOPS/afs_vnop_fid.c | 2 +- src/afs/afs.h | 8 ++++++-- src/afs/afs_call.c | 14 +++++++------- src/afs/afs_osi_pag.c | 6 +++--- src/afs/afs_pag_call.c | 6 +++--- src/afs/afs_vcache.c | 2 +- src/rx/SOLARIS/rx_knet.c | 2 +- 24 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/afs/AIX/osi_file.c b/src/afs/AIX/osi_file.c index 7ecaaf237..ee9011346 100644 --- a/src/afs/AIX/osi_file.c +++ b/src/afs/AIX/osi_file.c @@ -161,7 +161,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/DARWIN/osi_file.c b/src/afs/DARWIN/osi_file.c index bc271f02f..3448738e6 100644 --- a/src/afs/DARWIN/osi_file.c +++ b/src/afs/DARWIN/osi_file.c @@ -318,7 +318,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/DARWIN/osi_module.c b/src/afs/DARWIN/osi_module.c index 90292532d..046870a7f 100644 --- a/src/afs/DARWIN/osi_module.c +++ b/src/afs/DARWIN/osi_module.c @@ -115,7 +115,7 @@ afs_modunload(struct kmod_info * kmod_info, void *data) { if (afs_globalVFS) return KERN_FAILURE; - if ((afs_initState != 0) || (afs_shuttingdown)) + if ((afs_initState != 0) || (afs_shuttingdown != AFS_RUNNING)) return KERN_FAILURE; #ifdef AFS_DARWIN80_ENV if (vfs_fsremove(afs_vfstable)) diff --git a/src/afs/FBSD/osi_file.c b/src/afs/FBSD/osi_file.c index 7c695d60e..6f7a03ede 100644 --- a/src/afs/FBSD/osi_file.c +++ b/src/afs/FBSD/osi_file.c @@ -167,7 +167,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/HPUX/osi_file.c b/src/afs/HPUX/osi_file.c index 59c2594af..6584b581f 100644 --- a/src/afs/HPUX/osi_file.c +++ b/src/afs/HPUX/osi_file.c @@ -147,7 +147,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/HPUX/osi_vnodeops.c b/src/afs/HPUX/osi_vnodeops.c index efba18053..56da491d7 100644 --- a/src/afs/HPUX/osi_vnodeops.c +++ b/src/afs/HPUX/osi_vnodeops.c @@ -297,7 +297,7 @@ afs_inactive(avc, acred) struct vnode *vp = AFSTOV(avc); ulong_t context; lock_t *sv_lock; - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return; /* diff --git a/src/afs/IRIX/osi_file.c b/src/afs/IRIX/osi_file.c index 86984937d..497c7dd09 100644 --- a/src/afs/IRIX/osi_file.c +++ b/src/afs/IRIX/osi_file.c @@ -141,7 +141,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/LINUX/osi_file.c b/src/afs/LINUX/osi_file.c index c1e52e3cb..ea0ea5d23 100644 --- a/src/afs/LINUX/osi_file.c +++ b/src/afs/LINUX/osi_file.c @@ -219,7 +219,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; @@ -259,7 +259,7 @@ afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr, AFS_STATCNT(osi_Write); if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("afs_osi_Write called with null param"); else return -EIO; diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index 2a83fc055..09393f2e2 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -982,7 +982,7 @@ afs_linux_revalidate(struct dentry *dp) cred_t *credp; int code; - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return EIO; AFS_GLOCK(); diff --git a/src/afs/LINUX24/osi_file.c b/src/afs/LINUX24/osi_file.c index 612db686d..92a674e02 100644 --- a/src/afs/LINUX24/osi_file.c +++ b/src/afs/LINUX24/osi_file.c @@ -200,7 +200,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; @@ -240,7 +240,7 @@ afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr, AFS_STATCNT(osi_Write); if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("afs_osi_Write called with null param"); else return -EIO; diff --git a/src/afs/LINUX24/osi_vnodeops.c b/src/afs/LINUX24/osi_vnodeops.c index c64c42732..3ef8d9b05 100644 --- a/src/afs/LINUX24/osi_vnodeops.c +++ b/src/afs/LINUX24/osi_vnodeops.c @@ -890,7 +890,7 @@ afs_linux_revalidate(struct dentry *dp) cred_t *credp; int code; - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return EIO; #ifdef AFS_LINUX24_ENV diff --git a/src/afs/NBSD/osi_file.c b/src/afs/NBSD/osi_file.c index 6d8746a1c..70bd26204 100644 --- a/src/afs/NBSD/osi_file.c +++ b/src/afs/NBSD/osi_file.c @@ -139,7 +139,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, afs_int32 asize) * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/OBSD/osi_file.c b/src/afs/OBSD/osi_file.c index 72a43ef9f..578dde63a 100644 --- a/src/afs/OBSD/osi_file.c +++ b/src/afs/OBSD/osi_file.c @@ -143,7 +143,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, afs_int32 asize) * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/SOLARIS/osi_file.c b/src/afs/SOLARIS/osi_file.c index a0d38a821..264a81204 100644 --- a/src/afs/SOLARIS/osi_file.c +++ b/src/afs/SOLARIS/osi_file.c @@ -372,7 +372,7 @@ afs_osi_Read(struct osi_file *afile, int offset, void *aptr, * down. No point in crashing when we are already shutting down */ if (!afile) { - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) osi_Panic("osi_Read called with null param"); else return -EIO; diff --git a/src/afs/SOLARIS/osi_vnodeops.c b/src/afs/SOLARIS/osi_vnodeops.c index 478d19625..b31f1a08b 100644 --- a/src/afs/SOLARIS/osi_vnodeops.c +++ b/src/afs/SOLARIS/osi_vnodeops.c @@ -1816,7 +1816,7 @@ int afs_inactive(struct vcache *avc, afs_ucred_t *acred) { struct vnode *vp = AFSTOV(avc); - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return 0; /* diff --git a/src/afs/UKERNEL/osi_vnodeops.c b/src/afs/UKERNEL/osi_vnodeops.c index ecfa51a11..07642b62b 100644 --- a/src/afs/UKERNEL/osi_vnodeops.c +++ b/src/afs/UKERNEL/osi_vnodeops.c @@ -33,7 +33,7 @@ afs_vrdwr(struct usr_vnode *avc, struct usr_uio *uio, int rw, int io, int afs_inactive(struct vcache *avc, afs_ucred_t *acred) { - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return 0; usr_assert(avc->vrefCount == 0); diff --git a/src/afs/VNOPS/afs_vnop_attrs.c b/src/afs/VNOPS/afs_vnop_attrs.c index 2633db3cb..8208728a5 100644 --- a/src/afs/VNOPS/afs_vnop_attrs.c +++ b/src/afs/VNOPS/afs_vnop_attrs.c @@ -245,7 +245,7 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred) afs_BozonLock(&avc->pvnLock, avc); #endif - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return EIO; if (!(avc->f.states & CStatd)) { diff --git a/src/afs/VNOPS/afs_vnop_fid.c b/src/afs/VNOPS/afs_vnop_fid.c index 8dc51506a..258f1d6dc 100644 --- a/src/afs/VNOPS/afs_vnop_fid.c +++ b/src/afs/VNOPS/afs_vnop_fid.c @@ -84,7 +84,7 @@ afs_fid(OSI_VC_DECL(avc), struct fid **fidpp) AFS_STATCNT(afs_fid); - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return EIO; if (afs_NFSRootOnly && (avc == afs_globalVp)) diff --git a/src/afs/afs.h b/src/afs/afs.h index 0dbc11bf8..f03609ca3 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -32,8 +32,12 @@ /* Upper bound on number of iovecs out uio routines will deal with. */ #define AFS_MAXIOVCNT 16 - -extern int afs_shuttingdown; +enum afs_shutdown_state { + AFS_RUNNING = 0, + AFS_FLUSHING_CB = 1, + AFS_SHUTDOWN = 2, +}; +extern enum afs_shutdown_state afs_shuttingdown; /* * Macros to uniquely identify the AFS vfs struct diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 196bc849c..ae589a766 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -1365,7 +1365,7 @@ afs_CheckInit(void) return code; } -int afs_shuttingdown = 0; +enum afs_shutdown_state afs_shuttingdown = AFS_RUNNING; void afs_shutdown(void) { @@ -1380,15 +1380,15 @@ afs_shutdown(void) return; } - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return; - /* Give up all of our callbacks if we can. This must be done before setting - * afs_shuttingdown, since it calls afs_InitReq, which will fail if - * afs_shuttingdown is set. */ + afs_shuttingdown = AFS_FLUSHING_CB; + + /* Give up all of our callbacks if we can. */ afs_FlushVCBs(2); - afs_shuttingdown = 1; + afs_shuttingdown = AFS_SHUTDOWN; if (afs_cold_shutdown) afs_warn("afs: COLD "); @@ -1509,7 +1509,7 @@ afs_shutdown(void) memset(&afs_stats_cmfullperf, 0, sizeof(struct afs_stats_CMFullPerf)); afs_warn(" ALL allocated tables... "); - afs_shuttingdown = 0; + afs_shuttingdown = AFS_RUNNING; afs_warn("done\n"); return; /* Just kill daemons for now */ diff --git a/src/afs/afs_osi_pag.c b/src/afs/afs_osi_pag.c index afbb1cf08..34ca9b2f5 100644 --- a/src/afs/afs_osi_pag.c +++ b/src/afs/afs_osi_pag.c @@ -32,7 +32,7 @@ /* Imported variables */ -extern int afs_shuttingdown; +extern enum afs_shutdown_state afs_shuttingdown; /* Exported variables */ afs_uint32 pag_epoch; @@ -456,7 +456,7 @@ afs_InitReq(struct vrequest *av, afs_ucred_t *acred) AFS_STATCNT(afs_InitReq); memset(av, 0, sizeof(*av)); - if (afs_shuttingdown) + if (afs_shuttingdown == AFS_SHUTDOWN) return EIO; #ifdef AFS_LINUX26_ENV @@ -507,7 +507,7 @@ afs_CreateReq(struct vrequest **avpp, afs_ucred_t *acred) int code; struct vrequest *treq = NULL; - if (afs_shuttingdown) { + if (afs_shuttingdown == AFS_SHUTDOWN) { return EIO; } if (!avpp || !acred) { diff --git a/src/afs/afs_pag_call.c b/src/afs/afs_pag_call.c index 88c0d8f8d..a1f40b580 100644 --- a/src/afs/afs_pag_call.c +++ b/src/afs/afs_pag_call.c @@ -31,7 +31,7 @@ afs_int32 afs_termState = 0; afs_int32 afs_gcpags = AFS_GCPAGS; -int afs_shuttingdown = 0; +enum afs_shutdown_state afs_shuttingdown = AFS_RUNNING; int afs_cold_shutdown = 0; int afs_resourceinit_flag = 0; afs_int32 afs_nfs_server_addr; @@ -163,9 +163,9 @@ afspag_Init(afs_int32 nfs_server_addr) void afspag_Shutdown(void) { - if (afs_shuttingdown) + if (afs_shuttingdown != AFS_RUNNING) return; - afs_shuttingdown = 1; + afs_shuttingdown = AFS_SHUTDOWN; afs_termState = AFSOP_STOP_RXCALLBACK; rx_WakeupServerProcs(); while (afs_termState == AFSOP_STOP_RXCALLBACK) diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index f3b78803b..d751a564c 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -234,7 +234,7 @@ afs_FlushVCache(struct vcache *avc, int *slept) else osi_dnlc_purgevp(avc); - if (!afs_shuttingdown) + if (afs_shuttingdown == AFS_RUNNING) afs_QueueVCB(avc, slept); /* diff --git a/src/rx/SOLARIS/rx_knet.c b/src/rx/SOLARIS/rx_knet.c index 19df875c5..320a38272 100644 --- a/src/rx/SOLARIS/rx_knet.c +++ b/src/rx/SOLARIS/rx_knet.c @@ -765,7 +765,7 @@ osi_NetIfPoller() if (li) (void) ldi_ident_release(li); - if (afs_shuttingdown) { + if (afs_shuttingdown != AFS_RUNNING) { /* do not schedule to run again if we're shutting down */ return; } -- 2.39.5