diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1452,16 +1452,21 @@ */ printf("Giving up on %d buffers\n", nbusy); DELAY(5000000); /* 5 seconds */ + swapoff_all(); } else { if (!first_buf_printf) printf("Final sync complete\n"); + /* - * Unmount filesystems + * Unmount filesystems. Swapoff before unmount, + * because file-backed swap is non-operational after unmount + * of the underlying filesystem. */ - if (!KERNEL_PANICKED()) + if (!KERNEL_PANICKED()) { + swapoff_all(); vfs_unmountall(); + } } - swapoff_all(); DELAY(100000); /* wait for console output to finish */ } diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -469,7 +469,8 @@ static void swp_pager_free_empty_swblk(vm_object_t, struct swblk *sb); static int swapongeom(struct vnode *); static int swaponvp(struct thread *, struct vnode *, u_long); -static int swapoff_one(struct swdevt *sp, struct ucred *cred); +static int swapoff_one(struct swdevt *sp, struct ucred *cred, + bool swapoff_syscall); /* * Swap bitmap functions @@ -2523,14 +2524,14 @@ error = EINVAL; goto done; } - error = swapoff_one(sp, td->td_ucred); + error = swapoff_one(sp, td->td_ucred, false); done: sx_xunlock(&swdev_syscall_lock); return (error); } static int -swapoff_one(struct swdevt *sp, struct ucred *cred) +swapoff_one(struct swdevt *sp, struct ucred *cred, bool ignore_check) { u_long nblks; #ifdef MAC @@ -2552,8 +2553,16 @@ * available virtual memory in the system will fit the amount * of data we will have to page back in, plus an epsilon so * the system doesn't become critically low on swap space. + * The vm_free_count() part does not account e.g. for clean + * pages that can be immediately reclaimed without paging, so + * this is a very rough estimation. + * + * On the other hand, not turning swap off on swapoff_all() + * means that we can loose swap data when filesystems go away, + * which is arguably worse. */ - if (vm_free_count() + swap_pager_avail < nblks + nswap_lowat) + if (!ignore_check && + vm_free_count() + swap_pager_avail < nblks + nswap_lowat) return (ENOMEM); /* @@ -2603,7 +2612,7 @@ devname = devtoname(sp->sw_vp->v_rdev); else devname = "[file]"; - error = swapoff_one(sp, thread0.td_ucred); + error = swapoff_one(sp, thread0.td_ucred, true); if (error != 0) { printf("Cannot remove swap device %s (error=%d), " "skipping.\n", devname, error);