Solaris: prevent AFS umount while busy

Return EBUSY from unmount if someone still references stuff in AFS.
This prevents kernel panics that can occur on shutdown if we umount
while there is a file in AFS open. Normally a process can hold a file
in AFS open, AFS is unmounted, and the file is closed, triggering our
code which explodes if called after we're unmounted.

This adds VFS_HOLD/VFS_RELE calls whenever we 'create' a vcache, or
retire an old one, to keep track if anyone has an open reference to
us.

Change-Id: I95d8cf7e7e4d32a05bee97e06832a530b40af217
Reviewed-on: http://gerrit.openafs.org/1880
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>
This commit is contained in:
Andrew Deason 2010-04-29 17:47:15 -05:00 committed by Derrick Brashear
parent 34b7fd4a49
commit fc8ab5cfd6
4 changed files with 43 additions and 1 deletions

View File

@ -56,7 +56,23 @@ local_osi_Time()
#undef afs_osi_Alloc_NoSleep #undef afs_osi_Alloc_NoSleep
extern void *afs_osi_Alloc_NoSleep(size_t size); extern void *afs_osi_Alloc_NoSleep(size_t size);
#define osi_vnhold(avc, r) do { VN_HOLD(AFSTOV(avc)); } while(0) #ifdef AFS_SUN58_ENV
# define osi_vnhold(avc, r) do { \
struct vnode *vp = AFSTOV(avc); \
uint_t prevcount; \
\
mutex_enter(&vp->v_lock); \
prevcount = vp->v_count++; \
mutex_exit(&vp->v_lock); \
\
if (prevcount == 0) { \
VFS_HOLD(afs_globalVFS); \
} \
} while(0)
#else /* !AFS_SUN58_ENV */
# define osi_vnhold(avc, r) do { VN_HOLD(AFSTOV(avc)); } while(0)
#endif /* !AFS_SUN58_ENV */
#define gop_rdwr(rw,gp,base,len,offset,segflg,ioflag,ulimit,cr,aresid) \ #define gop_rdwr(rw,gp,base,len,offset,segflg,ioflag,ulimit,cr,aresid) \
vn_rdwr((rw),(gp),(base),(len),(offset),(segflg),(ioflag),(ulimit),(cr),(aresid)) vn_rdwr((rw),(gp),(base),(len),(offset),(segflg),(ioflag),(ulimit),(cr),(aresid))
#define gop_lookupname(fnamep,segflg,followlink,compvpp) \ #define gop_lookupname(fnamep,segflg,followlink,compvpp) \

View File

@ -67,4 +67,11 @@ osi_PostPopulateVCache(struct vcache *avc) {
AFSTOV(avc)->v_op = afs_ops; AFSTOV(avc)->v_op = afs_ops;
AFSTOV(avc)->v_vfsp = afs_globalVFS; AFSTOV(avc)->v_vfsp = afs_globalVFS;
vSetType(avc, VREG); vSetType(avc, VREG);
#ifdef AFS_SUN58_ENV
/* Normally we do this in osi_vnhold when we notice the ref count went from
* 0 -> 1. But if we just setup or reused a vcache, we set the refcount to
* 1 directly. So, we must explicitly VFS_HOLD here. */
VFS_HOLD(afs_globalVFS);
#endif
} }

View File

@ -96,6 +96,20 @@ afs_unmount(struct vfs *afsp, afs_ucred_t *credp)
AFS_GUNLOCK(); AFS_GUNLOCK();
return ENOTSUP; return ENOTSUP;
} }
/* We should have one reference from the caller, and one reference for the
* root vnode; any more and someone is still referencing something */
if (afsp->vfs_count > 2) {
AFS_GUNLOCK();
return EBUSY;
}
/* The root vnode should have one ref for the mount; any more, and someone
* else is using the root vnode */
if (afs_globalVp && VREFCOUNT_GT(afs_globalVp, 1)) {
AFS_GUNLOCK();
return EBUSY;
}
#endif /* AFS_SUN58_ENV */ #endif /* AFS_SUN58_ENV */
afs_globalVFS = 0; afs_globalVFS = 0;

View File

@ -1815,6 +1815,11 @@ afs_inactive(struct vcache *avc, afs_ucred_t *acred)
avc->opens = avc->execsOrWriters = 0; avc->opens = avc->execsOrWriters = 0;
afs_InactiveVCache(avc, acred); afs_InactiveVCache(avc, acred);
#ifdef AFS_SUN58_ENV
VFS_RELE(afs_globalVFS);
#endif
return 0; return 0;
} }