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