From: Andrew Deason Date: Thu, 29 Apr 2010 22:47:15 +0000 (-0500) Subject: Solaris: prevent AFS umount while busy X-Git-Tag: openafs-devel-1_5_75~321 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=fc8ab5cfd6592f9a9df24706a8f5dcc1e41f2b33;p=packages%2Fo%2Fopenafs.git 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 Tested-by: Derrick Brashear --- diff --git a/src/afs/SOLARIS/osi_machdep.h b/src/afs/SOLARIS/osi_machdep.h index 1e1774880..9027a0e7c 100644 --- a/src/afs/SOLARIS/osi_machdep.h +++ b/src/afs/SOLARIS/osi_machdep.h @@ -56,7 +56,23 @@ local_osi_Time() #undef afs_osi_Alloc_NoSleep 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) \ vn_rdwr((rw),(gp),(base),(len),(offset),(segflg),(ioflag),(ulimit),(cr),(aresid)) #define gop_lookupname(fnamep,segflg,followlink,compvpp) \ diff --git a/src/afs/SOLARIS/osi_vcache.c b/src/afs/SOLARIS/osi_vcache.c index 14a382868..7435ed3ec 100644 --- a/src/afs/SOLARIS/osi_vcache.c +++ b/src/afs/SOLARIS/osi_vcache.c @@ -67,4 +67,11 @@ osi_PostPopulateVCache(struct vcache *avc) { AFSTOV(avc)->v_op = afs_ops; AFSTOV(avc)->v_vfsp = afs_globalVFS; 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 } diff --git a/src/afs/SOLARIS/osi_vfsops.c b/src/afs/SOLARIS/osi_vfsops.c index c474f8aea..31e9007cf 100644 --- a/src/afs/SOLARIS/osi_vfsops.c +++ b/src/afs/SOLARIS/osi_vfsops.c @@ -96,6 +96,20 @@ afs_unmount(struct vfs *afsp, afs_ucred_t *credp) AFS_GUNLOCK(); 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 */ afs_globalVFS = 0; diff --git a/src/afs/SOLARIS/osi_vnodeops.c b/src/afs/SOLARIS/osi_vnodeops.c index f02d19f12..0ec2e09b0 100644 --- a/src/afs/SOLARIS/osi_vnodeops.c +++ b/src/afs/SOLARIS/osi_vnodeops.c @@ -1815,6 +1815,11 @@ afs_inactive(struct vcache *avc, afs_ucred_t *acred) avc->opens = avc->execsOrWriters = 0; afs_InactiveVCache(avc, acred); + +#ifdef AFS_SUN58_ENV + VFS_RELE(afs_globalVFS); +#endif + return 0; }