diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h index d3ae3c32635d..b14a829025d1 100644 --- a/sys/cddl/boot/zfs/zfsimpl.h +++ b/sys/cddl/boot/zfs/zfsimpl.h @@ -904,6 +904,16 @@ typedef enum pool_state { POOL_STATE_POTENTIALLY_ACTIVE /* Internal libzfs state */ } pool_state_t; +/* + * Send TRIM commands in-line during normal pool operation while deleting. + * OFF: no + * ON: yes + */ +typedef enum { + SPA_AUTOTRIM_OFF = 0, + SPA_AUTOTRIM_ON, +} spa_autotrim_t; + /* * The uberblock version is incremented whenever an incompatible on-disk * format change is made to the SPA, DMU, or ZAP. diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8 index e165702813ae..47c7bf50df5a 100644 --- a/usr.sbin/makefs/makefs.8 +++ b/usr.sbin/makefs/makefs.8 @@ -33,7 +33,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd August 12, 2026 +.Dd October 7, 2026 .Dt MAKEFS 8 .Os .Sh NAME @@ -535,6 +535,15 @@ The following keywords are supported: The base-2 logarithm of the minimum block size. Typical values are 9 (512B blocks) and 12 (4KB blocks). The default value is 12. +.It Cm autotrim +The value of the +.Ql autotrim +pool property, either +.Ql on +or +.Ql off . +The default is +.Ql off . .It Cm bootfs The name of the bootable dataset for the pool. Specifying this option causes the diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh index 22adfda00d2b..fe27c62ab765 100644 --- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh +++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh @@ -107,6 +107,64 @@ autoexpand_cleanup() common_cleanup } +# +# Test setting the autotrim pool property. +# +atf_test_case autotrim cleanup +autotrim_body() +{ + local src val + + create_test_inputs + + atf_check -s exit:1 -e match:"invalid value .foo. for autotrim" \ + $MAKEFS -s 1g -o rootpath=/ -o poolname=$ZFS_POOL_NAME \ + -o autotrim=foo $TEST_IMAGE $TEST_INPUTS_DIR + + for val in on off; do + atf_check $MAKEFS -s 1g -o rootpath=/ \ + -o poolname=$ZFS_POOL_NAME \ + -o autotrim=$val \ + $TEST_IMAGE $TEST_INPUTS_DIR + + import_image + + check_image_contents + + # OpenZFS reports a pool property whose value equals the + # default as coming from the default, even if it was set. + if [ $val = off ]; then + src=default + else + src=local + fi + atf_check -o inline:$val\\n \ + zpool get -H -o value autotrim $ZFS_POOL_NAME + atf_check -o inline:$src\\n \ + zpool get -H -o source autotrim $ZFS_POOL_NAME + + atf_check zpool destroy ${ZFS_POOL_NAME} + atf_check rm -f ${TEST_ZFS_POOL_NAME} + atf_check mdconfig -d -u $(cat ${TEST_MD_DEVICE_FILE}) + atf_check rm -f ${TEST_MD_DEVICE_FILE} + done + + # Without the option the property keeps its default value. + atf_check $MAKEFS -s 1g -o rootpath=/ -o poolname=$ZFS_POOL_NAME \ + $TEST_IMAGE $TEST_INPUTS_DIR + + import_image + + atf_check -o inline:off\\n \ + zpool get -H -o value autotrim $ZFS_POOL_NAME + atf_check -o inline:default\\n \ + zpool get -H -o source autotrim $ZFS_POOL_NAME +} +autotrim_cleanup() +{ + common_cleanup +} + # # Test with some default layout defined by the common code. # @@ -1110,6 +1168,7 @@ T_flag_mtree_cleanup() atf_init_test_cases() { atf_add_test_case autoexpand + atf_add_test_case autotrim atf_add_test_case basic atf_add_test_case compression atf_add_test_case dataset_removal diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c index 1288c52141ab..9e304202fb4f 100644 --- a/usr.sbin/makefs/zfs.c +++ b/usr.sbin/makefs/zfs.c @@ -82,6 +82,8 @@ zfs_prep_opts(fsinfo_t *fsopts) memset(zfs, 0, sizeof(*zfs)); const option_t zfs_options[] = { + { '\0', "autotrim", &zfs->autotrim, OPT_STRPTR, + 0, 0, "Automatic TRIM (on or off)" }, { '\0', "bootfs", &zfs->bootfs, OPT_STRPTR, 0, 0, "Bootable dataset" }, { '\0', "mssize", &zfs->mssize, OPT_INT64, @@ -247,6 +249,17 @@ zfs_check_opts(fsinfo_t *fsopts) if (zfs->vdevpath[0] != '/') errx(1, "path `%s' must be absolute", zfs->vdevpath); + zfs->autotrimval = SPA_AUTOTRIM_OFF; + if (zfs->autotrim != NULL) { + if (strcmp(zfs->autotrim, "on") == 0) + zfs->autotrimval = SPA_AUTOTRIM_ON; + else if (strcmp(zfs->autotrim, "off") == 0) + zfs->autotrimval = SPA_AUTOTRIM_OFF; + else + errx(1, "invalid value `%s' for autotrim", + zfs->autotrim); + } + if (zfs->ashift == 0) zfs->ashift = 12; @@ -262,6 +275,7 @@ zfs_cleanup_opts(fsinfo_t *fsopts) zfs = fsopts->fs_specific; free(zfs->rootpath); free(zfs->vdevpath); + free(zfs->autotrim); free(zfs->bootfs); free(__DECONST(void *, zfs->poolname)); STAILQ_FOREACH_SAFE(d, &zfs->datasetdescs, next, tmp) { @@ -474,6 +488,9 @@ pool_init_objdir_poolprops(zfs_opt_t *zfs, zfs_zap_t *objdir) zap_add_uint64(objdir, DMU_POOL_PROPS, id); zfs->poolprops = zap_alloc(zfs->mos, dnode); + + if (zfs->autotrim != NULL) + zap_add_uint64(zfs->poolprops, "autotrim", zfs->autotrimval); } /* diff --git a/usr.sbin/makefs/zfs/zfs.h b/usr.sbin/makefs/zfs/zfs.h index 13f2ece43c69..ebc54caad8e9 100644 --- a/usr.sbin/makefs/zfs/zfs.h +++ b/usr.sbin/makefs/zfs/zfs.h @@ -80,6 +80,8 @@ typedef struct { const char *poolname; char *rootpath; /* implicit mount point prefix */ char *vdevpath; /* vdev path, pool property */ + char *autotrim; /* "on" or "off", pool property */ + spa_autotrim_t autotrimval; /* parsed autotrim value */ char *bootfs; /* bootable dataset, pool property */ int ashift; /* vdev block size */ uint64_t mssize; /* metaslab size */