From ca291153ff2c696696c1406aca6433aab6e412a1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 24 Jun 2016 13:36:32 +0200 Subject: [PATCH 79/84] blkdiscard: backport --zeroout support The patch also includes upstream cleanups. Upstream: http://github.com/karelzak/util-linux/commit/0e765365798c54d412e355798ad584a52035f228 Upstream: http://github.com/karelzak/util-linux/commit/a3e91e26467a0f644ee568bb0b3d481591834015 Upstream: http://github.com/karelzak/util-linux/commit/eeae448805c0eb2ef130a6ac301750706bb80420 Upstream: http://github.com/karelzak/util-linux/commit/7154cc892688f3c58cbbcdc2055f2635c1d0ef5b Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1327886 Signed-off-by: Karel Zak --- bash-completion/blkdiscard | 2 +- sys-utils/blkdiscard.8 | 7 +-- sys-utils/blkdiscard.c | 122 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 98 insertions(+), 33 deletions(-) diff --git a/bash-completion/blkdiscard b/bash-completion/blkdiscard index 310cdfb..fb3cb1e 100644 --- a/bash-completion/blkdiscard +++ b/bash-completion/blkdiscard @@ -15,7 +15,7 @@ _blkdiscard_module() esac case $cur in -*) - OPTS="--offset --length --secure --verbose --help --version" + OPTS="--offset --length --secure --zeroout --verbose --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; diff --git a/sys-utils/blkdiscard.8 b/sys-utils/blkdiscard.8 index 5e094d4..71180e9 100644 --- a/sys-utils/blkdiscard.8 +++ b/sys-utils/blkdiscard.8 @@ -1,15 +1,13 @@ -.\" -*- nroff -*- .TH BLKDISCARD 8 "July 2014" "util-linux" "System Administration" .SH NAME blkdiscard \- discard sectors on a device .SH SYNOPSIS .B blkdiscard +[options] .RB [ \-o .IR offset ] .RB [ \-l .IR length ] -.RB [ \-s ] -.RB [ \-v ] .I device .SH DESCRIPTION .B blkdiscard @@ -59,6 +57,9 @@ 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 \-z , " \-\-zeroout" +Zero-fill rather than discard. +.TP .BR \-v , " \-\-verbose" Display the aligned values of .I offset diff --git a/sys-utils/blkdiscard.c b/sys-utils/blkdiscard.c index 92ca52a..0ba99ee 100644 --- a/sys-utils/blkdiscard.c +++ b/sys-utils/blkdiscard.c @@ -44,43 +44,95 @@ #include "closestream.h" #ifndef BLKDISCARD -#define BLKDISCARD _IO(0x12,119) +# define BLKDISCARD _IO(0x12,119) #endif #ifndef BLKSECDISCARD -#define BLKSECDISCARD _IO(0x12,125) +# 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]); +#ifndef BLKZEROOUT +# define BLKZEROOUT _IO(0x12,127) +#endif + +enum { + ACT_DISCARD = 0, /* default */ + ACT_ZEROOUT, + ACT_SECURE +}; + +/* RHEL: backport from upstream lib/monotonic.c */ +static int gettime_monotonic(struct timeval *tv) +{ +#ifdef CLOCK_MONOTONIC + /* Can slew only by ntp and adjtime */ + int ret; + struct timespec ts; + +# ifdef CLOCK_MONOTONIC_RAW + /* Linux specific, can't slew */ + if (!(ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts))) { +# else + if (!(ret = clock_gettime(CLOCK_MONOTONIC, &ts))) { +# endif + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + } + return ret; +#else + return gettimeofday(tv, NULL); +#endif +} + +static void print_stats(int act, char *path, uint64_t stats[]) +{ + switch (act) { + case ACT_ZEROOUT: + printf(_("%s: Zero-filled %" PRIu64 " bytes from the offset %" PRIu64"\n"), \ + path, stats[1], stats[0]); + break; + case ACT_SECURE: + case ACT_DISCARD: + printf(_("%s: Discarded %" PRIu64 " bytes from the offset %" PRIu64"\n"), \ + path, stats[1], stats[0]); + break; + } +} static void __attribute__((__noreturn__)) usage(FILE *out) { fputs(USAGE_HEADER, out); fprintf(out, _(" %s [options] \n"), program_invocation_short_name); + + fputs(USAGE_SEPARATOR, out); + fputs(_("Discard the content of sectors on a device.\n"), out); + 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); + fputs(_(" -o, --offset offset in bytes to discard from\n"), out); + fputs(_(" -l, --length length of bytes to discard from the offset\n"), out); + fputs(_(" -p, --step size of the discard iterations within the offset\n"), out); + fputs(_(" -s, --secure perform secure discard\n"), out); + fputs(_(" -z, --zeroout zero-fill rather than discard\n"), out); + fputs(_(" -v, --verbose print aligned length and offset\n"), out); + fputs(USAGE_SEPARATOR, out); fputs(USAGE_HELP, out); fputs(USAGE_VERSION, out); + fprintf(out, USAGE_MAN_TAIL("blkdiscard(8)")); exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } + int main(int argc, char **argv) { char *path; - int c, fd, verbose = 0, secure = 0, secsize; + int c, fd, verbose = 0, secsize; uint64_t end, blksize, step, range[2], stats[2]; struct stat sb; - struct timespec now, last; + struct timeval now, last; + int act = ACT_DISCARD; static const struct option longopts[] = { { "help", 0, 0, 'h' }, @@ -90,6 +142,7 @@ int main(int argc, char **argv) { "step", 1, 0, 'p' }, { "secure", 0, 0, 's' }, { "verbose", 0, 0, 'v' }, + { "zeroout", 0, 0, 'z' }, { NULL, 0, 0, 0 } }; @@ -102,7 +155,7 @@ int main(int argc, char **argv) range[1] = ULLONG_MAX; step = 0; - while ((c = getopt_long(argc, argv, "hVsvo:l:p:", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVsvo:l:p:z", longopts, NULL)) != -1) { switch(c) { case 'h': usage(stdout); @@ -123,11 +176,14 @@ int main(int argc, char **argv) _("failed to parse step")); break; case 's': - secure = 1; + act = ACT_SECURE; break; case 'v': verbose = 1; break; + case 'z': + act = ACT_ZEROOUT; + break; default: usage(stderr); break; @@ -149,7 +205,7 @@ int main(int argc, char **argv) err(EXIT_FAILURE, _("cannot open %s"), path); if (fstat(fd, &sb) == -1) - err(EXIT_FAILURE, _("stat failed %s"), path); + err(EXIT_FAILURE, _("stat of %s failed"), path); if (!S_ISBLK(sb.st_mode)) errx(EXIT_FAILURE, _("%s: not a block device"), path); @@ -178,35 +234,43 @@ int main(int argc, char **argv) "to sector size %i"), path, range[1], secsize); stats[0] = range[0], stats[1] = 0; - clock_gettime(CLOCK_MONOTONIC, &last); + gettime_monotonic(&last); - for (range[0] = range[0]; range[0] < end; range[0] += range[1]) { + for (/* nothing */; range[0] < end; range[0] += range[1]) { if (range[0] + range[1] > end) range[1] = end - range[0]; - if (secure) { + switch (act) { + case ACT_ZEROOUT: + if (ioctl(fd, BLKZEROOUT, &range)) + err(EXIT_FAILURE, _("%s: BLKZEROOUT ioctl failed"), path); + break; + case ACT_SECURE: if (ioctl(fd, BLKSECDISCARD, &range)) err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path); - } else { + break; + case ACT_DISCARD: if (ioctl(fd, BLKDISCARD, &range)) err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path); + break; } - /* reporting progress */ + stats[1] += range[1]; + + /* reporting progress at most once per second */ 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; + gettime_monotonic(&now); + if (now.tv_sec > last.tv_sec && + (now.tv_usec >= last.tv_usec || now.tv_sec > last.tv_sec + 1)) { + print_stats(act, path, stats); + stats[0] += stats[1], stats[1] = 0; last = now; } } - - stats[1] += range[1]; } - if (verbose) - print_stats(path, stats); + if (verbose && stats[1]) + print_stats(act, path, stats); close(fd); return EXIT_SUCCESS; -- 2.7.4