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’.
Change-Id: Iffa89d82278b0df5fb90fc35608af66d8e8db29e
Reviewed-on: http://gerrit.openafs.org/12016
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Chas Williams <3chas3@gmail.com>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
* 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;
* 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;
{
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))
* 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;
* 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;
struct vnode *vp = AFSTOV(avc);
ulong_t context;
lock_t *sv_lock;
- if (afs_shuttingdown)
+ if (afs_shuttingdown != AFS_RUNNING)
return;
/*
* 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;
* 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;
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;
cred_t *credp;
int code;
- if (afs_shuttingdown)
+ if (afs_shuttingdown != AFS_RUNNING)
return EIO;
AFS_GLOCK();
* 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;
* 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;
* 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;
afs_inactive(struct vcache *avc, afs_ucred_t *acred)
{
struct vnode *vp = AFSTOV(avc);
- if (afs_shuttingdown)
+ if (afs_shuttingdown != AFS_RUNNING)
return 0;
/*
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);
AFS_DISCON_LOCK();
- if (afs_shuttingdown) {
+ if (afs_shuttingdown != AFS_RUNNING) {
AFS_DISCON_UNLOCK();
return EIO;
}
AFS_STATCNT(afs_fid);
- if (afs_shuttingdown)
+ if (afs_shuttingdown != AFS_RUNNING)
return EIO;
if (afs_NFSRootOnly && (avc == afs_globalVp))
/* 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
return code;
}
-int afs_shuttingdown = 0;
+enum afs_shutdown_state afs_shuttingdown = AFS_RUNNING;
void
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 ");
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 */
/* Imported variables */
-extern int afs_shuttingdown;
+extern enum afs_shutdown_state afs_shuttingdown;
/* Exported variables */
afs_uint32 pag_epoch;
AFS_STATCNT(afs_InitReq);
memset(av, 0, sizeof(*av));
- if (afs_shuttingdown)
+ if (afs_shuttingdown == AFS_SHUTDOWN)
return EIO;
#ifdef AFS_LINUX26_ENV
int code;
struct vrequest *treq = NULL;
- if (afs_shuttingdown) {
+ if (afs_shuttingdown == AFS_SHUTDOWN) {
return EIO;
}
if (!avpp || !acred) {
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;
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)
* via which someone could try to use the vcache. It is okay to drop
* afs_xvcache at this point (if *slept is set). */
- if (!afs_shuttingdown)
+ if (afs_shuttingdown == AFS_RUNNING)
afs_QueueVCB(avc, slept);
/*
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;
}