There isn’t an existing command – you’ll need to issue the DKIOCFREE ioctl..
I’ve attached a program that’ll do it – I wrote this while testing some of the
TRIM support (but obviously use at your own risk). While it was originally used
w/ zvols (hence the name), it should work for any block device that supports
the DKIOCFREE ioctl.
Either call it with -a /dev/rdsk/… to do the whole disk, or you can give it a
list of LBA + lengths to TRIM specific portions of a disk..
From: Marcel Telka <[email protected]>
Date: Wednesday, August 4, 2021 at 8:49 AM
To: [email protected] <[email protected]>
Subject: [discuss] Disk TRIM without zfs?
Hi,
Is there a way to TRIM a disk without creating a zfs pool on it?
Thanks.
--
+-------------------------------------------+
| Marcel Telka e-mail: [email protected] |
| homepage: http://telka.sk/ |
+-------------------------------------------+
------------------------------------------
illumos: illumos-discuss
Permalink:
https://illumos.topicbox.com/groups/discuss/Tb82006464e3b5173-Mfc3d2ddcba605a7a052fca73
Delivery options: https://illumos.topicbox.com/groups/discuss/subscription
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2020 Joyent, Inc.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/dkio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <err.h>
#include <unistd.h>
static uint64_t
get_size(const char *dev, int fd)
{
struct dk_minfo dkm = { 0 };
int bit = 0;
if (ioctl(fd, DKIOCGMEDIAINFO, &dkm) < 0)
err(EXIT_FAILURE, "ioctl(%s, DKIOCGMEDIAINFO) failed", dev);
if (dkm.dki_lbsize > 0)
bit = ffs((int)dkm.dki_lbsize) - 1;
return ((uint64_t)dkm.dki_capacity << (uint_t)bit);
}
static uint64_t
get_num(const char *str)
{
uint64_t val;
errno = 0;
val = strtoull(str, NULL, 0);
if (errno != 0)
err(EXIT_FAILURE, "could not parse '%s'", str);
return (val);
}
static void
usage(void)
{
fprintf(stderr,
"Usage: %s [-aw] dev\n"
" %s [-w] dev [offset length] [offset length...]\n",
getprogname(), getprogname());
exit(2);
}
static dkioc_free_list_t *
make_list(int argc, char **argv)
{
dkioc_free_list_t *dfl = NULL;
if (argc % 2 == 1)
errx(EXIT_FAILURE, "odd number of parameters given");
if ((dfl = calloc(1, DFL_SZ(argc / 2))) == NULL)
err(EXIT_FAILURE, "no memory");
dfl->dfl_num_exts = argc / 2;
for (size_t i = 0; i < argc / 2; i++) {
dfl->dfl_exts[i].dfle_start = get_num(argv[i * 2]);
dfl->dfl_exts[i].dfle_length = get_num(argv[(i * 2) + 1]);
}
return (dfl);
}
static dkioc_free_list_t *
make_all(const char *dev, int fd)
{
dkioc_free_list_t *dfl = NULL;
uint64_t len = get_size(dev, fd);
if ((dfl = calloc(1, DFL_SZ(1))) == NULL)
err(EXIT_FAILURE, "no memory");
dfl->dfl_num_exts = 1;
dfl->dfl_exts[0].dfle_start = 0;
dfl->dfl_exts[0].dfle_length = len;
return (dfl);
}
/*
* This issues a DKIOCFREE ioctl for a block device for the entire
* size of the device. Use with caution!.
*/
int
main(int argc, char **argv)
{
const char *devname = NULL;
dkioc_free_list_t *dfl;
boolean_t all = B_FALSE;
boolean_t wait = B_FALSE;
int fd = -1;
int c;
while ((c = getopt(argc, argv, "aw")) != -1) {
switch (c) {
case 'a':
all = B_TRUE;
break;
case 'w':
wait = B_TRUE;
break;
case '?':
fprintf(stderr, "Invalid option -%c\n", optopt);
usage();
}
}
if (argc == optind)
usage();
devname = argv[optind];
argc -= optind + 1;
argv += optind + 1;
if ((fd = open(devname, O_RDWR)) < 0)
err(EXIT_FAILURE, "open %s failed", devname);
dfl = all ? make_all(devname, fd) : make_list(argc, argv);
printf("%s:\n", devname);
for (size_t i = 0; i < dfl->dfl_num_exts; i++) {
printf(" [%zu] start = %llu length = %llu\n", i,
dfl->dfl_exts[i].dfle_start,
dfl->dfl_exts[i].dfle_length);
}
if (wait)
dfl->dfl_flags |= DF_WAIT_SYNC;
if (ioctl(fd, DKIOCFREE, dfl) < 0)
err(EXIT_FAILURE, "ioctl(%s, DKIOCFREE) failed", devname);
(void) close(fd);
return (0);
}