From owner-svn-src-head@freebsd.org Thu Nov 29 18:36:22 2018 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C602F114897C for ; Thu, 29 Nov 2018 18:36:21 +0000 (UTC) (envelope-from sobomax@sippysoft.com) Received: from mail-ot1-f44.google.com (mail-ot1-f44.google.com [209.85.210.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id CBCD47C2DB for ; Thu, 29 Nov 2018 18:36:20 +0000 (UTC) (envelope-from sobomax@sippysoft.com) Received: by mail-ot1-f44.google.com with SMTP id u16so2700515otk.8 for ; Thu, 29 Nov 2018 10:36:20 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=zYITn0rfyjDUchjHibYdFZP36AuTbJKkKsyWXm5J0P4=; b=MlQ3OuH1RBNOXzP59zQRkMaOLAK6HfH+CYxmQaPRRo4eH4QXI1FGqAWFLqz7nEmsAQ lk+BA9Sby63eBklVj9P84o3XtdY8eFRqY4agBKHjqk5034dOpjwLrKwoWLg0/cpUZh0w d6ReZECfW2IXuhtUtmLoBQkt59jSUispdgn7qI6ssXxjDOe7ijHaQ2iLEsLk7sH8yHfl lRtZx9bRa/TGMEB3sTebdYyLsrhreN4+yP6N4YVSS3fvC7B/lpv/uD3qn3VCwDBgrgg+ 4hfybwmSt7Ev7Ug//1qwg7UJM8Nvtbt7XHS3+ehUBHW8YSriO2J4kJSlDzrVMaX7wR/3 wjxQ== X-Gm-Message-State: AA+aEWbIVyfgNUs/1OThj8ZJ02l9LRkffkivPFVA2I9a2z7VligFKaAF xX1GGx30xVPDTQRtu9Pn756t15HzSsJjqbCl8KCT2S8JjpQ= X-Google-Smtp-Source: AFSGD/XRNhePHXZ7vn3whkpPtk/10TS6BkyK6qnn83k3EYLrEgwFpXQ4tuu8h5QwSwlqxritr5ccngWBOTTDFwUDI7c= X-Received: by 2002:a9d:3387:: with SMTP id u7mr1716866otc.81.1543516573989; Thu, 29 Nov 2018 10:36:13 -0800 (PST) MIME-Version: 1.0 References: <201811291421.wATELQbx059318@repo.freebsd.org> In-Reply-To: <201811291421.wATELQbx059318@repo.freebsd.org> From: Maxim Sobolev Date: Thu, 29 Nov 2018 10:36:02 -0800 Message-ID: Subject: Re: svn: head/usr.bin: . trim To: eugen@freebsd.org Cc: src-committers , svn-src-all@freebsd.org, svn-src-head@freebsd.org X-Rspamd-Queue-Id: CBCD47C2DB X-Spamd-Result: default: False [-3.96 / 15.00]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-0.997,0]; FROM_HAS_DN(0.00)[]; RWL_MAILSPIKE_GOOD(0.00)[44.210.85.209.rep.mailspike.net : 127.0.0.18]; R_SPF_ALLOW(-0.20)[+ip4:209.85.128.0/17]; RCPT_COUNT_THREE(0.00)[4]; MIME_GOOD(-0.10)[multipart/alternative,text/plain]; PREVIOUSLY_DELIVERED(0.00)[svn-src-head@freebsd.org]; DMARC_NA(0.00)[freebsd.org]; TO_DN_SOME(0.00)[]; NEURAL_HAM_LONG(-1.00)[-0.999,0]; TO_MATCH_ENVRCPT_SOME(0.00)[]; MX_GOOD(-0.01)[cached: alt1.aspmx.l.google.com]; NEURAL_HAM_SHORT(-0.98)[-0.979,0]; RCVD_IN_DNSWL_NONE(0.00)[44.210.85.209.list.dnswl.org : 127.0.5.0]; IP_SCORE(-0.97)[ipnet: 209.85.128.0/17(-3.46), asn: 15169(-1.32), country: US(-0.09)]; FORGED_SENDER(0.30)[sobomax@freebsd.org,sobomax@sippysoft.com]; R_DKIM_NA(0.00)[]; RCVD_TLS_LAST(0.00)[]; ASN(0.00)[asn:15169, ipnet:209.85.128.0/17, country:US]; FROM_NEQ_ENVFROM(0.00)[sobomax@freebsd.org,sobomax@sippysoft.com]; RCVD_COUNT_TWO(0.00)[2] X-Rspamd-Server: mx1.freebsd.org Content-Type: text/plain; charset="UTF-8" X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 Nov 2018 18:36:22 -0000 Interesting. I have a similar functionality implemented as an option for the dd utility in my pipeline (conv=erase). -Max On Thu, Nov 29, 2018 at 6:21 AM Eugene Grosbein wrote: > Author: eugen > Date: Thu Nov 29 14:21:26 2018 > New Revision: 341232 > URL: https://svnweb.freebsd.org/changeset/base/341232 > > Log: > Add new small tool trim(1) to delete contents for blocks on flash > based storage devices that use wear-leveling algorithms. > > Reviewed by: hackers@ > MFC after: 1 month > > Added: > head/usr.bin/trim/ > head/usr.bin/trim/Makefile (contents, props changed) > head/usr.bin/trim/trim.1 (contents, props changed) > head/usr.bin/trim/trim.c (contents, props changed) > Modified: > head/usr.bin/Makefile > > Modified: head/usr.bin/Makefile > > ============================================================================== > --- head/usr.bin/Makefile Thu Nov 29 14:21:01 2018 (r341231) > +++ head/usr.bin/Makefile Thu Nov 29 14:21:26 2018 (r341232) > @@ -159,6 +159,7 @@ SUBDIR= alias \ > touch \ > tput \ > tr \ > + trim \ > true \ > truncate \ > tset \ > > Added: head/usr.bin/trim/Makefile > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/trim/Makefile Thu Nov 29 14:21:26 2018 (r341232) > @@ -0,0 +1,6 @@ > +# $FreeBSD$ > + > +PROG= trim > +LIBADD= util > + > +.include > > Added: head/usr.bin/trim/trim.1 > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/trim/trim.1 Thu Nov 29 14:21:26 2018 (r341232) > @@ -0,0 +1,166 @@ > +.\" > +.\" Copyright (c) 2018 Eugene Grosbein . > +.\" All rights reserved. > +.\" > +.\" Redistribution and use in source and binary forms, with or without > +.\" modification, are permitted provided that the following conditions > +.\" are met: > +.\" 1. Redistributions of source code must retain the above copyright > +.\" notice, this list of conditions and the following disclaimer. > +.\" 2. Redistributions in binary form must reproduce the above copyright > +.\" notice, this list of conditions and the following disclaimer in the > +.\" documentation and/or other materials provided with the > distribution. > +.\" > +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE > LIABLE > +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > CONSEQUENTIAL > +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE > GOODS > +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > STRICT > +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY > WAY > +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > +.\" SUCH DAMAGE. > +.\" > +.\" $FreeBSD$ > +.\" > +.Dd November 29, 2018 > +.Dt TRIM 1 > +.Os > +.Sh NAME > +.Nm trim > +.Nd erase device blocks that have no needed contents > +.Sh SYNOPSIS > +.Nm > +.Op Fl Nfqv > +.Fl [ [lo] Xo > +.Bk -words > +.Sm off > +.Ar offset > +.Op Cm K | k | M | m | G | g | T | t ] > +.Sm on > +.Xc > +.Ek > +.Bk -words > +.Op Fl r Ar rfile > +.Ek > +.Ar device ... > +.Sh DESCRIPTION > +The > +.Nm > +utility erases specified region of the device. > +It is only relevant for flash based storage devices that use wear-leveling > +algorithms. > +.Sy All erased data is lost. > +.Pp > +The following options are available: > +.Bl -tag -width indent > +.It Fl N > +Do not actually erase anything but show what it would do (dry run). > +Implies > +.Fl v . > +This is the default. Overrides > +.Fl f . > +.It Fl f > +Perform the operation. Overrides > +.Fl N . > +.It Fl l Xo > +.Sm off > +.Ar offset > +.Op Cm K | k | M | m | G | g | T | t > +.Sm on > +.Xc > +.It Fl o Xo > +.Sm off > +.Ar offset > +.Op Cm K | k | M | m | G | g | T | t > +.Sm on > +.Xc > +Specify the length > +.Fl l > +of the region to trim or its offset > +.Fl o > +from the beginning of the device. > +.Sy The whole device is erased by default > +unless one or both of these options are presented. > +.Pp > +The argument may be suffixed with one of > +.Cm K , > +.Cm M , > +.Cm G > +or > +.Cm T > +(either upper or lower case) to indicate a multiple of > +Kilobytes, Megabytes, Gigabytes or Terabytes > +respectively. > +.It Fl q > +Do not output anything except of possible error messages (quiet mode). > +Overrides > +.Fl v . > +.It Fl r Ar rfile > +Uses the length of given > +.Ar rfile > +as length of the region to erase. > +.Sy The whole device is erased by default. > +.It Fl v > +Show offset and length of actual region being erased, in bytes. > +.El > +.Pp > +Later options override previous ones. > +.Pp > +Note that actual success of the operation depends of underlying > +device driver such as > +.Xr ada 4 , > +.Xr da 4 > +and others. > +Refer to corresponding manual pages for detail on possible caveats > +in low level support for ATA TRIM or SCSI UNMAP commands. > +.Sh EXIT STATUS > +.Ex -std > +If the final erase operation fails for an argument, the > +.Nm > +utility returns exit code 1. > +It can also return one of the exit codes defined in > +.Xr sysexits 3 , > +as follows: > +.Bl -tag -width ".Dv EX_UNAVAILABLE" > +.It Dv EX_USAGE > +The specified offset or length of the region is incorrect. > +.It Dv EX_OSERR > +There is no enough memory to proceed. > +.It Dv EX_NOINPUT > +The specified > +.Ar rfile > +cannot be opened (perhaps, it does not exist). > +.It Dv EX_IOERR > +The specified > +.Ar rfile > +cannot be examined for its size due to some system input/output error. > +.It Dv EX_DATAERR > +The specified > +.Ar rfile > +is not regular file, directory nor special device, so its size > +cannot be examined. > +.It Dv EX_UNAVAILABLE > +The specified > +.Ar rfile > +is special device file not supporting DIOCGMEDIASIZE > +.Xr ioctl 2 > +(probably not a disk), so its size cannot be examined. > +.El > +.Sh SEE ALSO > +.Xr ada 4 , > +.Xr da 4 , > +.Xr ioctl 2 , > +.Xr sysexits 3 > +.Sh HISTORY > +The > +.Nm > +utility first appeared in > +.Fx 12.0 . > +.Sh AUTHORS > +The > +.Nm > +utility was written by > +.An Eugene Grosbein Aq Mt eugen@FreeBSD.org . > > Added: head/usr.bin/trim/trim.c > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/trim/trim.c Thu Nov 29 14:21:26 2018 (r341232) > @@ -0,0 +1,211 @@ > +/*- > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD > + * > + * Copyright (c) 2018 Eugene Grosbein . > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY > WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + * > + */ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +static const char rcsid[] = > + "$FreeBSD$"; > + > +static int trim(char *path, off_t offset, off_t length, int dryrun, > int verbose); > +static off_t getsize(char *path); > +static void usage(char *name) __dead2; > + > +int > +main(int argc, char **argv) > +{ > + off_t offset, length; > + uint64_t usz; > + int dryrun, error, verbose; > + char *fname, *name; > + char ch; > + > + error = 0; > + length = offset = 0; > + name = argv[0]; > + dryrun = verbose = 1; > + > + while ((ch = getopt(argc, argv, "Nfl:o:qr:v")) != -1) > + switch (ch) { > + case 'N': > + dryrun = 1; > + verbose = 1; > + break; > + case 'f': > + dryrun = 0; > + break; > + case 'l': > + case 'o': > + if (expand_number(optarg, &usz) == -1 || > + (off_t)usz < 0 || > + (usz == 0 && ch == 'l')) > + errx(EX_USAGE, > + "invalid %s of the region: `%s'", > + ch == 'o' ? "offset" : "length", > + optarg); > + if (ch == 'o') > + offset = (off_t)usz; > + else > + length = (off_t)usz; > + break; > + case 'q': > + verbose = 0; > + break; > + case 'r': > + if ((length = getsize(optarg)) == 0) > + errx(EX_USAGE, > + "invalid zero length reference > file" > + " for the region: `%s'", optarg); > + break; > + case 'v': > + verbose = 1; > + break; > + default: > + usage(name); > + /* NOTREACHED */ > + } > + > + argv += optind; > + argc -= optind; > + > + if (argc < 1) > + usage(name); > + > + while ((fname = *argv++) != NULL) > + if (trim(fname, offset, length, dryrun, verbose) < 0) > + error++; > + > + return (error ? EXIT_FAILURE : EXIT_SUCCESS); > +} > + > +static off_t > +getsize(char *path) > +{ > + struct stat sb; > + char *tstr; > + off_t mediasize; > + int fd; > + > + if ((fd = open(path, O_RDONLY | O_DIRECT)) < 0) { > + if (errno == ENOENT && path[0] != '/') { > + if (asprintf(&tstr, "%s%s", _PATH_DEV, path) < 0) > + errx(EX_OSERR, "no memory"); > + fd = open(tstr, O_RDONLY | O_DIRECT); > + free(tstr); > + } > + } > + > + if (fd < 0) > + err(EX_NOINPUT, "`%s'", path); > + > + if (fstat(fd, &sb) < 0) > + err(EX_IOERR, "`%s'", path); > + > + if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode)) { > + close(fd); > + return (sb.st_size); > + } > + > + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) > + errx(EX_DATAERR, > + "invalid type of the file " > + "(not regular, directory nor special device): > `%s'", > + path); > + > + if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) > + errx(EX_UNAVAILABLE, > + "ioctl(DIOCGMEDIASIZE) failed, probably not a > disk: " > + "`%s'", path); > + close(fd); > + > + return (mediasize); > +} > + > +static int > +trim(char *path, off_t offset, off_t length, int dryrun, int verbose) > +{ > + off_t arg[2]; > + char *tstr; > + int error, fd; > + > + if (length == 0) > + length = getsize(path); > + > + if (verbose) > + printf("trim `%s' offset %ju length %ju\n", > + path, (uintmax_t)offset, (uintmax_t)length); > + > + if (dryrun) { > + printf("dry run: add -f to actually perform the > operation\n"); > + return (0); > + } > + > + if ((fd = open(path, O_WRONLY | O_DIRECT)) < 0) { > + if (errno == ENOENT && path[0] != '/') { > + if (asprintf(&tstr, "%s%s", _PATH_DEV, path) < 0) > + errx(EX_OSERR, "no memory"); > + fd = open(tstr, O_WRONLY | O_DIRECT); > + free(tstr); > + } > + } > + > + if (fd < 0) > + err(EX_NOINPUT, "`%s'", path); > + > + arg[0] = offset; > + arg[1] = length; > + > + error = ioctl(fd, DIOCGDELETE, arg); > + if (error < 0) > + warn("ioctl(DIOCGDELETE) failed for `%s'", path); > + > + close(fd); > + return (error); > +} > + > +static void > +usage(char *name) > +{ > + (void)fprintf(stderr, > + "usage: %s [-[lo] offset[K|k|M|m|G|g|T|t]] [-r rfile] [-Nfqv] > device ...\n", > + name); > + exit(EX_USAGE); > +} > >