diff -up util-linux-2.23.2/sys-utils/blkdiscard.8.kzak util-linux-2.23.2/sys-utils/blkdiscard.8 --- util-linux-2.23.2/sys-utils/blkdiscard.8.kzak 2013-06-13 09:46:10.532651579 +0200 +++ util-linux-2.23.2/sys-utils/blkdiscard.8 2014-10-27 10:03:13.650011708 +0100 @@ -1,5 +1,5 @@ .\" -*- nroff -*- -.TH BLKDISCARD 8 "October 2012" "util-linux" "System Administration" +.TH BLKDISCARD 8 "July 2014" "util-linux" "System Administration" .SH NAME blkdiscard \- discard sectors on a device .SH SYNOPSIS @@ -15,7 +15,7 @@ blkdiscard \- discard sectors on a devic .B blkdiscard is used to discard device sectors. This is useful for solid-state drivers (SSDs) and thinly-provisioned storage. Unlike -.BR fstrim (8) +.BR fstrim (8) , this command is used directly on the block device. .PP By default, @@ -33,32 +33,44 @@ The .I offset and .I length -arguments may be followed by the multiplicative suffixes KiB=1024, -MiB=1024*1024, and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is +arguments may be followed by the multiplicative suffixes KiB (=1024), +MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is optional, e.g., "K" has the same meaning as "KiB") or the suffixes -KB=1000, MB=1000*1000, and so on for GB, TB, PB, EB, ZB and YB. -.IP "\fB\-h, \-\-help\fP" -Print help and exit. -.IP "\fB\-o, \-\-offset\fP \fIoffset\fP" -Byte offset in the device from which to discard. Provided value will be -aligned to the device sector size. Default value is zero. -.IP "\fB\-l, \-\-length\fP \fIlength\fP" -Number of bytes after starting point to discard. Provided value will be -aligned to the device sector size. If the specified value extends past +KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB. +.TP +.BR \-o , " \-\-offset \fIoffset" +Byte offset into the device from which to start discarding. The provided value +will be aligned to the device sector size. The default value is zero. +.TP +.BR \-l , " \-\-length \fIlength" +The number of bytes to discard (counting from the starting point). The provided value +will be aligned to the device sector size. If the specified value extends past the end of the device, .B blkdiscard -will stop at the device size boundary. Default value extends to the end +will stop at the device size boundary. The default value extends to the end of the device. -.IP "\fB\-s, \-\-secure\fP" -Perform secure discard. Secure discard is the same as regular discard -except all copies of the discarded blocks possibly created by garbage -collection must also be erased. It has to be supported by the device. -.IP "\fB\-v, \-\-verbose\fP" -Print aligned +.TP +.BR \-p , " \-\-step \fIlength" +The number of bytes to discard within one iteration. The default is to discard +all by one ioctl call. +.TP +.BR \-s , " \-\-secure" +Perform a secure discard. A secure discard is the same as a regular discard +except that all copies of the discarded blocks that were possibly created by +garbage collection must also be erased. This requires support from the device. +.TP +.BR \-v , " \-\-verbose" +Display the aligned values of .I offset and -.I length -arguments. +.IR length . +If the option \fB\-\-step\fR specified than it prints discard progress every second. +.TP +.BR \-V , " \-\-version" +Display version information and exit. +.TP +.BR \-h , " \-\-help" +Display help text and exit. .SH AUTHOR .MT lczerner@redhat.com Lukas Czerner diff -up util-linux-2.23.2/sys-utils/blkdiscard.c.kzak util-linux-2.23.2/sys-utils/blkdiscard.c --- util-linux-2.23.2/sys-utils/blkdiscard.c.kzak 2013-07-30 10:39:26.337739534 +0200 +++ util-linux-2.23.2/sys-utils/blkdiscard.c 2014-10-27 10:03:20.981088614 +0100 @@ -31,9 +31,11 @@ #include #include #include +#include #include #include +#include #include #include "nls.h" @@ -49,6 +51,10 @@ #define BLKSECDISCARD _IO(0x12,125) #endif +#define print_stats(path, stats) \ + printf(_("%s: Discarded %" PRIu64 " bytes from the " \ + "offset %" PRIu64"\n"), path, stats[1], stats[0]); + static void __attribute__((__noreturn__)) usage(FILE *out) { fputs(USAGE_HEADER, out); @@ -57,6 +63,7 @@ static void __attribute__((__noreturn__) fputs(USAGE_OPTIONS, out); fputs(_(" -o, --offset offset in bytes to discard from\n" " -l, --length length of bytes to discard from the offset\n" + " -p, --step size of the discard iterations within the offset\n" " -s, --secure perform secure discard\n" " -v, --verbose print aligned length and offset\n"), out); @@ -70,15 +77,17 @@ static void __attribute__((__noreturn__) int main(int argc, char **argv) { char *path; - int c, fd, verbose = 0, secure = 0; - uint64_t end, blksize, secsize, range[2]; + int c, fd, verbose = 0, secure = 0, secsize; + uint64_t end, blksize, step, range[2], stats[2]; struct stat sb; + struct timespec now, last; static const struct option longopts[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, { "offset", 1, 0, 'o' }, { "length", 1, 0, 'l' }, + { "step", 1, 0, 'p' }, { "secure", 0, 0, 's' }, { "verbose", 0, 0, 'v' }, { NULL, 0, 0, 0 } @@ -91,8 +100,9 @@ int main(int argc, char **argv) range[0] = 0; range[1] = ULLONG_MAX; + step = 0; - while ((c = getopt_long(argc, argv, "hVsvo:l:", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVsvo:l:p:", longopts, NULL)) != -1) { switch(c) { case 'h': usage(stdout); @@ -108,6 +118,10 @@ int main(int argc, char **argv) range[0] = strtosize_or_err(optarg, _("failed to parse offset")); break; + case 'p': + step = strtosize_or_err(optarg, + _("failed to parse step")); + break; case 's': secure = 1; break; @@ -121,7 +135,7 @@ int main(int argc, char **argv) } if (optind == argc) - errx(EXIT_FAILURE, _("no device specified.")); + errx(EXIT_FAILURE, _("no device specified")); path = argv[optind++]; @@ -130,43 +144,69 @@ int main(int argc, char **argv) usage(stderr); } - if (stat(path, &sb) == -1) - err(EXIT_FAILURE, _("stat failed %s"), path); - if (!S_ISBLK(sb.st_mode)) - errx(EXIT_FAILURE, _("%s: not a block device"), path); - fd = open(path, O_WRONLY); if (fd < 0) err(EXIT_FAILURE, _("cannot open %s"), path); + if (fstat(fd, &sb) == -1) + err(EXIT_FAILURE, _("stat failed %s"), path); + if (!S_ISBLK(sb.st_mode)) + errx(EXIT_FAILURE, _("%s: not a block device"), path); + if (ioctl(fd, BLKGETSIZE64, &blksize)) err(EXIT_FAILURE, _("%s: BLKGETSIZE64 ioctl failed"), path); - if (ioctl(fd, BLKSSZGET, &secsize)) err(EXIT_FAILURE, _("%s: BLKSSZGET ioctl failed"), path); - /* align range to the sector size */ - range[0] = (range[0] + secsize - 1) & ~(secsize - 1); - range[1] &= ~(secsize - 1); + /* check offset alignment to the sector size */ + if (range[0] % secsize) + errx(EXIT_FAILURE, _("%s: offset %" PRIu64 " is not aligned " + "to sector size %i"), path, range[0], secsize); /* is the range end behind the end of the device ?*/ + if (range[0] > blksize) + errx(EXIT_FAILURE, _("%s: offset is greater than device size"), path); end = range[0] + range[1]; if (end < range[0] || end > blksize) - range[1] = blksize - range[0]; + end = blksize; + + range[1] = (step > 0) ? step : end - range[0]; + + /* check length alignment to the sector size */ + if (range[1] % secsize) + errx(EXIT_FAILURE, _("%s: length %" PRIu64 " is not aligned " + "to sector size %i"), path, range[1], secsize); + + stats[0] = range[0], stats[1] = 0; + clock_gettime(CLOCK_MONOTONIC, &last); + + for (range[0] = range[0]; range[0] < end; range[0] += range[1]) { + if (range[0] + range[1] > end) + range[1] = end - range[0]; + + if (secure) { + if (ioctl(fd, BLKSECDISCARD, &range)) + err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path); + } else { + if (ioctl(fd, BLKDISCARD, &range)) + err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path); + } + + /* reporting progress */ + if (verbose && step) { + clock_gettime(CLOCK_MONOTONIC, &now); + if (last.tv_sec < now.tv_sec) { + print_stats(path, stats); + stats[0] = range[0], stats[1] = 0; + last = now; + } + } - if (secure) { - if (ioctl(fd, BLKSECDISCARD, &range)) - err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path); - } else { - if (ioctl(fd, BLKDISCARD, &range)) - err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path); + stats[1] += range[1]; } if (verbose) - /* TRANSLATORS: The standard value here is a very large number. */ - printf(_("%s: Discarded %" PRIu64 " bytes from the " - "offset %" PRIu64"\n"), path, - (uint64_t) range[1], (uint64_t) range[0]); + print_stats(path, stats); close(fd); return EXIT_SUCCESS;