/* $eterna: fdiscard-stuff.c,v 1.3 2020/12/25 23:40:19 mrg Exp $ */ /* * Copyright (c) 2019, 2020 Matthew R. Green * 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. */ /* fdiscard(2) front-end -- TRIM support. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static void usage(const char* msg) { /* * -f first byte to discard. * -s end offset. total length is end_offset - first_byte. * -R actually run it, default is no-run. * -m max size to pass to fdiscard(2). loops over this. */ fprintf(stderr, "%sUsage: fdiscard [-R] [-f first_byte] [-s end_offset] [-m max_per_call] \n", msg); exit(1); } int main(int argc, char *argv[]) { int norun = 1; off_t first_byte = 0, end_offset = 0; off_t max_per_call = 32 * 1024 * 1024; off_t discard_size; off_t size = 0; char *ep; int64_t val; int i; while ((i = getopt(argc, argv, "f:m:Rs:")) != -1) { switch (i) { case 'R': norun = 0; break; case 'f': if (dehumanize_number(optarg, &val) == -1 || val < 0) usage("bad -f\n"); first_byte = val; break; case 'm': if (dehumanize_number(optarg, &val) == -1 || val < 0) usage("bad -m\n"); max_per_call = val; break; case 's': if (dehumanize_number(optarg, &val) == -1 || val < 0) usage("bad -s\n"); end_offset = val; break; default: usage("bad options\n"); } } argc -= optind; argv += optind; if (argc != 1) usage("not one arg left\n"); char *name = argv[0]; int fd = open(name, O_RDWR); if (fd < 0) err(1, "open on %s", name); if (size == 0) { struct dkwedge_info dkw; if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) { size = dkw.dkw_size * DEV_BSIZE; printf("wedge size is %lld\n", size); } } if (size == 0) { struct disklabel dl; if (ioctl(fd, DIOCGDINFO, &dl) != -1) { char partchar = name[strlen(name)-1]; assert(partchar >= 'a' && partchar <= 'p'); int part = partchar - 'a'; size = (uint64_t)dl.d_partitions[part].p_size * dl.d_secsize; printf("disklabel size is %lld\n", size); } } if (size == 0) { struct stat sb; if (fstat(fd, &sb) != -1) { size = sb.st_size; printf("stat size is %lld\n", size); } } if (size == 0) { fprintf(stderr, "unable to determine size.\n"); exit(1); } printf("size = %lld\n", size); size -= first_byte; if (end_offset) { if (end_offset > size) { fprintf(stderr, "end_offset %lld > size %lld\n", end_offset, size); usage(""); } size = end_offset; } printf("%sgoing to fdiscard on %s from %lld for %lld, %lld at a time\n", norun ? "not " : "", name, first_byte, size, max_per_call); int loop = 0; while (size > 0) { if (size > max_per_call) discard_size = max_per_call; else discard_size = size; if (norun == 0) { if (fdiscard(fd, first_byte, discard_size) == -1) err(1, "fdiscard"); } first_byte += discard_size; size -= discard_size; printf("."); if (loop++ > 100) { loop = 0; printf("\n"); } } if (loop != 0) printf("\n"); return 0; }