diff --git a/sys/contrib/openzfs/module/zfs/spa_misc.c b/sys/contrib/openzfs/module/zfs/spa_misc.c index 1a2e5abc5..9a84328bf 100644 --- a/sys/contrib/openzfs/module/zfs/spa_misc.c +++ b/sys/contrib/openzfs/module/zfs/spa_misc.c @@ -2434,30 +2434,182 @@ spa_init(spa_mode_t mode) void spa_fini(void) { + time_t t0, t1; + long int dt; + + if (verbose_shutdown > 1) + printf(" spa_fini() starting.\n"); + + if (verbose_shutdown) + t0 = t1 = time_second; l2arc_stop(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" l2arc_stop() took %lds\n", dt); + t1 = time_second; + } spa_evict_all(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" spa_evict_all() took %lds\n", dt); + t1 = time_second; + } vdev_file_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" vdev_file_fini() took %lds\n", dt); + t1 = time_second; + } + vdev_cache_stat_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" vdev_cache_stat_fini() took %lds\n", dt); + t1 = time_second; + } + vdev_mirror_stat_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" vdev_mirror_stat_fini() took %lds\n", dt); + t1 = time_second; + } + vdev_raidz_math_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" vdev_raidz_math_fini() took %lds\n", dt); + t1 = time_second; + } + zil_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" zil_fini() took %lds\n", dt); + t1 = time_second; + } + dmu_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" dmu_fini() took %lds\n", dt); + t1 = time_second; + } + zio_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" zio_fini() took %lds\n", dt); + t1 = time_second; + } + ddt_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" ddt_fini() took %lds\n", dt); + t1 = time_second; + } + metaslab_stat_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" metaslab_stat_fini() took %lds\n", dt); + t1 = time_second; + } + zfs_btree_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" zfs_btree_fini() took %lds\n", dt); + t1 = time_second; + } + unique_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" unique_fini() took %lds\n", dt); + t1 = time_second; + } + zfs_refcount_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" zfs_refcount_fini() took %lds\n", dt); + t1 = time_second; + } + fm_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" fm_fini() took %lds\n", dt); + t1 = time_second; + } + scan_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" scan_fini() took %lds\n", dt); + t1 = time_second; + } + qat_fini(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" qat_fini() took %lds\n", dt); + t1 = time_second; + } + spa_import_progress_destroy(); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" spa_import_progress_destroy() took %lds\n", dt); + t1 = time_second; + } + avl_destroy(&spa_namespace_avl); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" avl_destroy(spa_namespace_avl) took %lds\n", dt); + t1 = time_second; + } + avl_destroy(&spa_spare_avl); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" avl_destroy(spa_spare_avl) took %lds\n", dt); + t1 = time_second; + } + avl_destroy(&spa_l2cache_avl); + if (verbose_shutdown) { + dt = time_second - t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" avl_destroy(spa_l2cache_avl) took %lds\n", dt); + t1 = time_second; + } cv_destroy(&spa_namespace_cv); mutex_destroy(&spa_namespace_lock); diff --git a/sys/contrib/openzfs/module/zfs/zfs_ioctl.c b/sys/contrib/openzfs/module/zfs/zfs_ioctl.c index 5f291d067..30f908321 100644 --- a/sys/contrib/openzfs/module/zfs/zfs_ioctl.c +++ b/sys/contrib/openzfs/module/zfs/zfs_ioctl.c @@ -7654,8 +7654,14 @@ zfs_kmod_init(void) void zfs_kmod_fini(void) { + time_t t0, t1; + long int dt; + zfsdev_state_t *zs, *zsnext = NULL; + if (verbose_shutdown) + printf("ZFS is shutting down.\n"); + zfsdev_detach(); mutex_destroy(&zfsdev_state_lock); @@ -7670,9 +7676,37 @@ zfs_kmod_fini(void) } zfs_ereport_taskq_fini(); /* run before zfs_fini() on Linux */ + + if (verbose_shutdown) + t0 = time_second; zfs_fini(); + if (verbose_shutdown) { + t1 = time_second; + dt = t1-t0; + if (dt > 1 || verbose_shutdown > 1) + printf(" zfs_fini() took %lds\n", dt); + } + + + if (verbose_shutdown) + t0 = time_second; spa_fini(); + if (verbose_shutdown) { + t1 = time_second; + dt = t1-t0; + if (dt > 1 || verbose_shutdown > 1) + printf(" spa_fini() took %lds\n", dt); + } + + if (verbose_shutdown) + t0 = time_second; zvol_fini(); + if (verbose_shutdown) { + t1 = time_second; + dt = t1-t0; + if (dt > 1 || verbose_shutdown > 1) + printf(" zvol_fini() took %lds\n", dt); + } tsd_destroy(&zfs_fsyncer_key); tsd_destroy(&rrw_tsd_key); diff --git a/sys/contrib/openzfs/module/zfs/zio.c b/sys/contrib/openzfs/module/zfs/zio.c index a7820e756..d532b4bd0 100644 --- a/sys/contrib/openzfs/module/zfs/zio.c +++ b/sys/contrib/openzfs/module/zfs/zio.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -249,7 +250,15 @@ zio_fini(void) { size_t i, j, n; kmem_cache_t *cache; + time_t t0, t1, t2; + long int dt; + + if (verbose_shutdown > 1) { + printf(" zio_fini() starting.\n"); + t0 = time_second; + } + n = SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; #if defined(ZFS_DEBUG) && !defined(_KERNEL) @@ -277,7 +286,16 @@ zio_fini(void) if (cache == zio_data_buf_cache[j]) zio_data_buf_cache[j] = NULL; } + if (verbose_shutdown) + t1 = time_second; kmem_cache_destroy(cache); + if (verbose_shutdown) { + t2 = time_second; + dt = t2-t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" kmem_cache_destroy(zio_buf_cache[%lu]) took %lds\n", + i, dt); + } } for (i = 0; i < n; i++) { @@ -288,7 +306,16 @@ zio_fini(void) if (cache == zio_data_buf_cache[j]) zio_data_buf_cache[j] = NULL; } + if (verbose_shutdown) + t1 = time_second; kmem_cache_destroy(cache); + if (verbose_shutdown) { + t2 = time_second; + dt = t2-t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" kmem_cache_destroy(zio_data_buf_cache[%lu]) took %lds\n", + i, dt); + } } for (i = 0; i < n; i++) { @@ -298,8 +325,25 @@ zio_fini(void) panic("zio_fini: zio_data_buf_cache[%d] != NULL", (int)i); } + if (verbose_shutdown) + t1 = time_second; kmem_cache_destroy(zio_link_cache); + if (verbose_shutdown) { + t2 = time_second; + dt = t2-t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" kmem_cache_destroy(zio_link_cache) took %lds\n", dt); + } + + if (verbose_shutdown) + t1 = time_second; kmem_cache_destroy(zio_cache); + if (verbose_shutdown) { + t2 = time_second; + dt = t2-t1; + if (dt > 1 || verbose_shutdown > 1) + printf(" kmem_cache_destroy(zio_cache) took %lds\n", dt); + } zio_inject_fini(); diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index e200b6d8a..f30205455 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -111,6 +112,7 @@ SYSCTL_INT(_kern, OID_AUTO, panic_reboot_wait_time, CTLFLAG_RWTUN, &panic_reboot_wait_time, 0, "Seconds to wait before rebooting after a panic"); + /* * Note that stdarg.h and the ANSI style va_start macro is used for both * ANSI and traditional C compilers. @@ -179,6 +181,10 @@ int suspend_blocked = 0; SYSCTL_INT(_kern, OID_AUTO, suspend_blocked, CTLFLAG_RW, &suspend_blocked, 0, "Block suspend due to a pending shutdown"); +int verbose_shutdown = 1; +SYSCTL_INT(_kern_shutdown, OID_AUTO, verbose, CTLFLAG_RW, + &verbose_shutdown, 0, "Be more verbose at shutdown/reboot"); + #ifdef EKCD FEATURE(ekcd, "Encrypted kernel crash dumps support"); @@ -428,6 +434,9 @@ kern_reboot(int howto) { static int once = 0; + if (verbose_shutdown) + printf("System is going down.\n"); + /* * Normal paths here don't hold Giant, but we can wind up here * unexpectedly with it held. Drop it now so we don't have to @@ -459,6 +468,8 @@ kern_reboot(int howto) /* We are out of the debugger now. */ kdb_active = 0; + if (verbose_shutdown > 1) + printf("Before shutdown_pre_sync.\n"); /* * Do any callouts that should be done BEFORE syncing the filesystems. */ @@ -468,6 +479,8 @@ kern_reboot(int howto) * Now sync filesystems */ if (!cold && (howto & RB_NOSYNC) == 0 && once == 0) { + if (verbose_shutdown > 1) + printf("Before bufshutdown.\n"); once = 1; bufshutdown(show_busybufs); } @@ -480,11 +493,23 @@ kern_reboot(int howto) * Ok, now do things that assume all filesystem activity has * been completed. */ + if (verbose_shutdown > 1) + printf("Before shutdown_post_sync.\n"); + EVENTHANDLER_INVOKE(shutdown_post_sync, howto); if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping) doadump(TRUE); + if (verbose_shutdown) { + printf("\nI've seen things you people wouldn't believe.\n"); + printf("Attack ships on fire off the shoulder of Orion.\n"); + printf("I watched C-beams glitter in the dark near the\n"); + printf("Tannhäuser Gate. All those moments will be lost\n"); + printf("in time, like tears in rain.\n"); + printf("\nTime to die.\n"); + } + /* Now that we're going to really halt the system... */ EVENTHANDLER_INVOKE(shutdown_final, howto); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 98c97324e..69c9afaec 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -4713,12 +4714,27 @@ void vfs_unmountall(void) { struct mount *mp, *tmp; + unsigned int n, ns, n_fs; + time_t t0, t1, ts, dt; CTR1(KTR_VFS, "%s: unmounting all filesystems", __func__); + /* + * Count the number of filesystems to unmount + */ + n_fs = 0; + TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, tmp) { + ++n_fs; + } + if (verbose_shutdown) { + printf("Unmounting %u filesystems:\n", n_fs); + t0 = ts = time_second; + } + /* * Since this only runs when rebooting, it is not interlocked. */ + ns = n = 0; TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, tmp) { vfs_ref(mp); @@ -4729,11 +4745,41 @@ vfs_unmountall(void) if (mp == rootdevmp) continue; + ++n; + if ((verbose_shutdown && n_fs < 100) || verbose_shutdown > 2) { + printf(" %2u. %s\n", n, mp->mnt_stat.f_mntonname); + } unmount_or_warn(mp); + + if (verbose_shutdown == 1 && n_fs > 99) { + t1 = time_second; + dt = t1-ts; + if (dt > 0) { + printf(" %6u of %u [%u%% done, %ld fs/s (cur), %ld fs/s (avg)] \r", + n, n_fs, n*100/n_fs, (n-ns)/dt, n/(t1-t0)); + ts = t1; + ns = n; + } + } } - if (rootdevmp != NULL) + if (rootdevmp != NULL) { + ++n; + if ((verbose_shutdown && n_fs < 100) || verbose_shutdown > 2) { + printf(" %2u. %s\n", n, rootdevmp->mnt_stat.f_mntonname); + } unmount_or_warn(rootdevmp); + } + + if (verbose_shutdown) { + dt = time_second - t0; + if (dt > 0) + printf("All %u filesystem%s unmounted in %lds (%ld fs/s). \n", + n, n == 1 ? "" : "s", dt, n/dt); + else + printf("All %u filesystem%s unmounted.\n", + n, n == 1 ? "" : "s"); + } } static void diff --git a/sys/sys/systm.h b/sys/sys/systm.h index d13379b0a..527a4412e 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -60,6 +60,7 @@ extern char version[]; /* system version */ extern char compiler_version[]; /* compiler version */ extern char copyright[]; /* system copyright */ extern int kstack_pages; /* number of kernel stack pages */ +extern int verbose_shutdown; /* Be more verbose at shutdown */ extern u_long pagesizes[]; /* supported page sizes */ extern long physmem; /* physical memory */