blkdiscard: use O_EXCL, add --force

Let's make it more robust and safe. O_EXCL is an elegant way how to avoid
unwanted discard on mounted device.

Addresses: https://github.com/karelzak/util-linux/issues/915
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2020-01-09 11:03:51 +01:00
parent e3e7cd659e
commit 34fed3ff17
2 changed files with 13 additions and 3 deletions

View file

@ -36,6 +36,11 @@ 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 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. KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB.
.TP .TP
.BR \-f , " \-\-force"
Disable all checking. Since v2.36 the block device is open in exclusive mode (O_EXCL)
by default to avoid collision with mounted filesystem or another kernel subsystem.
The force option disables the exclusive access mode.
.TP
.BR \-o , " \-\-offset \fIoffset" .BR \-o , " \-\-offset \fIoffset"
Byte offset into the device from which to start discarding. The provided value 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. will be aligned to the device sector size. The default value is zero.

View file

@ -88,6 +88,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_("Discard the content of sectors on a device.\n"), out); fputs(_("Discard the content of sectors on a device.\n"), out);
fputs(USAGE_OPTIONS, out); fputs(USAGE_OPTIONS, out);
fputs(_(" -f, --force disable all checking\n"), out);
fputs(_(" -o, --offset <num> offset in bytes to discard from\n"), out); fputs(_(" -o, --offset <num> offset in bytes to discard from\n"), out);
fputs(_(" -l, --length <num> length of bytes to discard from the offset\n"), out); fputs(_(" -l, --length <num> length of bytes to discard from the offset\n"), out);
fputs(_(" -p, --step <num> size of the discard iterations within the offset\n"), out); fputs(_(" -p, --step <num> size of the discard iterations within the offset\n"), out);
@ -106,7 +107,7 @@ static void __attribute__((__noreturn__)) usage(void)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char *path; char *path;
int c, fd, verbose = 0, secsize; int c, fd, verbose = 0, secsize, force = 0;
uint64_t end, blksize, step, range[2], stats[2]; uint64_t end, blksize, step, range[2], stats[2];
struct stat sb; struct stat sb;
struct timeval now, last; struct timeval now, last;
@ -116,6 +117,7 @@ int main(int argc, char **argv)
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "offset", required_argument, NULL, 'o' }, { "offset", required_argument, NULL, 'o' },
{ "force", no_argument, NULL, 'f' },
{ "length", required_argument, NULL, 'l' }, { "length", required_argument, NULL, 'l' },
{ "step", required_argument, NULL, 'p' }, { "step", required_argument, NULL, 'p' },
{ "secure", no_argument, NULL, 's' }, { "secure", no_argument, NULL, 's' },
@ -133,8 +135,11 @@ int main(int argc, char **argv)
range[1] = ULLONG_MAX; range[1] = ULLONG_MAX;
step = 0; step = 0;
while ((c = getopt_long(argc, argv, "hVsvo:l:p:z", longopts, NULL)) != -1) { while ((c = getopt_long(argc, argv, "hfVsvo:l:p:z", longopts, NULL)) != -1) {
switch(c) { switch(c) {
case 'f':
force = 1;
break;
case 'l': case 'l':
range[1] = strtosize_or_err(optarg, range[1] = strtosize_or_err(optarg,
_("failed to parse length")); _("failed to parse length"));
@ -176,7 +181,7 @@ int main(int argc, char **argv)
errtryhelp(EXIT_FAILURE); errtryhelp(EXIT_FAILURE);
} }
fd = open(path, O_WRONLY); fd = open(path, O_WRONLY | (force ? 0 : O_EXCL));
if (fd < 0) if (fd < 0)
err(EXIT_FAILURE, _("cannot open %s"), path); err(EXIT_FAILURE, _("cannot open %s"), path);