Module Name: src Committed By: dyoung Date: Fri Jun 26 18:53:07 UTC 2009
Modified Files: src/sys/kern: vfs_subr.c Log Message: Keep a generation number, mountgen, that increases every time a filesystem is mounted. Synchronize access to the number with a mutex. When a struct mount, mp, is allocated, assign the current generation number to mp->mnt_gen. Introduce vfs_unmount_forceone() that forcefully unmounts the most recently mounted filesystem. Refactor: extract vfs_shutdown1() from vfs_shutdown(). Extract vfs_sync_all() from vfs_shutdown1(). Print more progress indications while we're unmounting all of the filesystems during shutdown. We increase the reference count on mp before calling dounmount(mp), but we do not decrease it if dounmount(mp) fails, and neither does dounmount(mp). So decrease the reference count if dounmount(mp) fails. Change the loop terminating condition in vfs_unmountall1() to (mp != (void *)&mountlist) from !CIRCLEQ_EMPTY(&mountlist), because we may not ever empty the list, especially if we're not forcing the filesystems to unmount. To generate a diff of this commit: cvs rdiff -u -r1.381 -r1.382 src/sys/kern/vfs_subr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_subr.c diff -u src/sys/kern/vfs_subr.c:1.381 src/sys/kern/vfs_subr.c:1.382 --- src/sys/kern/vfs_subr.c:1.381 Tue Jun 23 23:04:11 2009 +++ src/sys/kern/vfs_subr.c Fri Jun 26 18:53:07 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_subr.c,v 1.381 2009/06/23 23:04:11 elad Exp $ */ +/* $NetBSD: vfs_subr.c,v 1.382 2009/06/26 18:53:07 dyoung Exp $ */ /*- * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.381 2009/06/23 23:04:11 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.382 2009/06/26 18:53:07 dyoung Exp $"); #include "opt_ddb.h" #include "opt_compat_netbsd.h" @@ -166,6 +166,9 @@ static kcondvar_t vrele_cv; static lwp_t *vrele_lwp; +static uint64_t mountgen = 0; +static kmutex_t mountgen_lock; + kmutex_t mountlist_lock; kmutex_t mntid_lock; kmutex_t mntvnode_lock; @@ -189,6 +192,7 @@ static int getdevvp(dev_t, vnode_t **, enum vtype); static vnode_t *getcleanvnode(void); void vpanic(vnode_t *, const char *); +static void vfs_shutdown1(struct lwp *); #ifdef DEBUG void printlockedvnodes(void); @@ -229,6 +233,7 @@ vntblinit(void) { + mutex_init(&mountgen_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&mountlist_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&mntid_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&mntvnode_lock, MUTEX_DEFAULT, IPL_NONE); @@ -489,6 +494,10 @@ mp->mnt_vnodecovered = vp; mount_initspecific(mp); + mutex_enter(&mountgen_lock); + mp->mnt_gen = mountgen++; + mutex_exit(&mountgen_lock); + return mp; } @@ -2264,25 +2273,71 @@ return vfs_unmountall1(l, true, true); } +static void +vfs_unmount_print(struct mount *mp, const char *pfx) +{ + printf("%sunmounted %s on %s type %s\n", pfx, + mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname, + mp->mnt_stat.f_fstypename); +} + +bool +vfs_unmount_forceone(struct lwp *l) +{ + struct mount *mp, *nmp = NULL; + int error; + + CIRCLEQ_FOREACH_REVERSE(mp, &mountlist, mnt_list) { + if (nmp == NULL || mp->mnt_gen > nmp->mnt_gen) + nmp = mp; + } + + if (nmp == NULL) + return false; + +#ifdef DEBUG + printf("\nforcefully unmounting %s (%s)...", + nmp->mnt_stat.f_mntonname, nmp->mnt_stat.f_mntfromname); +#endif + atomic_inc_uint(&nmp->mnt_refcnt); + if ((error = dounmount(nmp, MNT_FORCE, l)) == 0) { + vfs_unmount_print(nmp, "forcefully "); + return true; + } else + atomic_dec_uint(&nmp->mnt_refcnt); + +#ifdef DEBUG + printf("forceful unmount of %s failed with error %d\n", + nmp->mnt_stat.f_mntonname, error); +#endif + + return false; +} + bool vfs_unmountall1(struct lwp *l, bool force, bool verbose) { struct mount *mp, *nmp; - bool any_error, progress; + bool any_error = false, progress = false; int error; - for (any_error = false, mp = CIRCLEQ_LAST(&mountlist); - !CIRCLEQ_EMPTY(&mountlist); + for (mp = CIRCLEQ_LAST(&mountlist); + mp != (void *)&mountlist; mp = nmp) { nmp = CIRCLEQ_PREV(mp, mnt_list); #ifdef DEBUG - printf("\nunmounting %s (%s)...", - mp->mnt_stat.f_mntonname, mp->mnt_stat.f_mntfromname); + printf("\nunmounting %p %s (%s)...", + (void *)mp, mp->mnt_stat.f_mntonname, + mp->mnt_stat.f_mntfromname); #endif atomic_inc_uint(&mp->mnt_refcnt); - if ((error = dounmount(mp, force ? MNT_FORCE : 0, l)) == 0) + if ((error = dounmount(mp, force ? MNT_FORCE : 0, l)) == 0) { + vfs_unmount_print(mp, ""); progress = true; - else { + } else { +#if 1 + atomic_dec_uint(&mp->mnt_refcnt); +#endif if (verbose) { printf("unmount of %s failed with error %d\n", mp->mnt_stat.f_mntonname, error); @@ -2308,6 +2363,12 @@ /* XXX we're certainly not running in lwp0's context! */ l = (curlwp == NULL) ? &lwp0 : curlwp; + vfs_shutdown1(l); +} + +void +vfs_sync_all(struct lwp *l) +{ printf("syncing disks... "); /* remove user processes from run queue */ @@ -2328,6 +2389,13 @@ return; } else printf("done\n"); +} + +static void +vfs_shutdown1(struct lwp *l) +{ + + vfs_sync_all(l); /* * If we've panic'd, don't make the situation potentially