summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2006-04-10 10:03:41 +0000
committerpjd <pjd@FreeBSD.org>2006-04-10 10:03:41 +0000
commitca3f23ca3477d7ab916b941037bef1d1928d7804 (patch)
tree63adcc7b220823bdd9c62930b3dd51534108f89f /sys/vm
parent059a4b89f63cf9f6d10ed28f0a3ea3e79134f457 (diff)
downloadFreeBSD-src-ca3f23ca3477d7ab916b941037bef1d1928d7804.zip
FreeBSD-src-ca3f23ca3477d7ab916b941037bef1d1928d7804.tar.gz
On shutdown try to turn off all swap devices. This way GEOM providers are
properly closed on shutdown. Requested by: ru Reviewed by: alc MFC after: 2 weeks
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/swap_pager.c81
-rw-r--r--sys/vm/swap_pager.h1
2 files changed, 63 insertions, 19 deletions
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index e34e336..75400ff 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -265,6 +265,7 @@ SYSCTL_INT(_vm, OID_AUTO, dmmax,
static void swp_sizecheck(void);
static void swp_pager_async_iodone(struct buf *bp);
static int swapongeom(struct thread *, struct vnode *);
+static int swapoff_one(struct swdevt *sp, struct thread *td);
static int swaponvp(struct thread *, struct vnode *, u_long);
/*
@@ -2109,15 +2110,13 @@ swapoff(struct thread *td, struct swapoff_args *uap)
struct vnode *vp;
struct nameidata nd;
struct swdevt *sp;
- u_long nblks, dvbase;
int error;
- mtx_lock(&Giant);
-
error = suser(td);
if (error)
- goto done2;
+ return (error);
+ mtx_lock(&Giant);
while (swdev_syscall_active)
tsleep(&swdev_syscall_active, PUSER - 1, "swpoff", 0);
swdev_syscall_active = 1;
@@ -2132,21 +2131,37 @@ swapoff(struct thread *td, struct swapoff_args *uap)
mtx_lock(&sw_dev_mtx);
TAILQ_FOREACH(sp, &swtailq, sw_list) {
if (sp->sw_vp == vp)
- goto found;
+ break;
}
mtx_unlock(&sw_dev_mtx);
- error = EINVAL;
- goto done;
-found:
- mtx_unlock(&sw_dev_mtx);
+ if (sp == NULL) {
+ error = EINVAL;
+ goto done;
+ }
+ error = swapoff_one(sp, td);
+done:
+ swdev_syscall_active = 0;
+ wakeup_one(&swdev_syscall_active);
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+static int
+swapoff_one(struct swdevt *sp, struct thread *td)
+{
+ u_long nblks, dvbase;
#ifdef MAC
- (void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
- error = mac_check_system_swapoff(td->td_ucred, vp);
- (void) VOP_UNLOCK(vp, 0, td);
+ int error;
+#endif
+
+ mtx_assert(&Giant, MA_OWNED);
+#ifdef MAC
+ (void) vn_lock(sp->sw_vp, LK_EXCLUSIVE | LK_RETRY, td);
+ error = mac_check_system_swapoff(td->td_ucred, sp->sw_vp);
+ (void) VOP_UNLOCK(sp->sw_vp, 0, td);
if (error != 0)
- goto done;
+ return (error);
#endif
-
nblks = sp->sw_nblks;
/*
@@ -2157,8 +2172,7 @@ found:
*/
if (cnt.v_free_count + cnt.v_cache_count + swap_pager_avail <
nblks + nswap_lowat) {
- error = ENOMEM;
- goto done;
+ return (ENOMEM);
}
/*
@@ -2191,13 +2205,42 @@ found:
mtx_unlock(&sw_dev_mtx);
blist_destroy(sp->sw_blist);
free(sp, M_VMPGDATA);
+ return (0);
+}
-done:
+void
+swapoff_all(void)
+{
+ struct swdevt *sp, *spt;
+ const char *devname;
+ int error;
+
+ mtx_lock(&Giant);
+ while (swdev_syscall_active)
+ tsleep(&swdev_syscall_active, PUSER - 1, "swpoff", 0);
+ swdev_syscall_active = 1;
+
+ mtx_lock(&sw_dev_mtx);
+ TAILQ_FOREACH_SAFE(sp, &swtailq, sw_list, spt) {
+ mtx_unlock(&sw_dev_mtx);
+ if (vn_isdisk(sp->sw_vp, NULL))
+ devname = sp->sw_vp->v_rdev->si_name;
+ else
+ devname = "[file]";
+ error = swapoff_one(sp, &thread0);
+ if (error != 0) {
+ printf("Cannot remove swap device %s (error=%d), "
+ "skipping.\n", devname, error);
+ } else if (bootverbose) {
+ printf("Swap device %s removed.\n", devname);
+ }
+ mtx_lock(&sw_dev_mtx);
+ }
+ mtx_unlock(&sw_dev_mtx);
+
swdev_syscall_active = 0;
wakeup_one(&swdev_syscall_active);
-done2:
mtx_unlock(&Giant);
- return (error);
}
void
diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h
index 49a8e6f..a254cc7 100644
--- a/sys/vm/swap_pager.h
+++ b/sys/vm/swap_pager.h
@@ -50,6 +50,7 @@ void swap_pager_swap_init(void);
int swap_pager_isswapped(vm_object_t, struct swdevt *);
int swap_pager_reserve(vm_object_t, vm_pindex_t, vm_size_t);
void swap_pager_status(int *total, int *used);
+void swapoff_all(void);
#endif /* _KERNEL */
#endif /* _VM_SWAP_PAGER_H_ */
OpenPOWER on IntegriCloud