summaryrefslogtreecommitdiffstats
path: root/sys-utils
diff options
context:
space:
mode:
authorDamien Le Moal2017-02-24 07:45:31 +0100
committerKarel Zak2017-02-24 11:53:45 +0100
commitf1b8b84d3476ac910d922c63a50a4129adbaf584 (patch)
treefa23bbc3dface8fd942ca77acec72036be92fad9 /sys-utils
parentblkzone: Improve zone information print (diff)
downloadkernel-qcow2-util-linux-f1b8b84d3476ac910d922c63a50a4129adbaf584.tar.gz
kernel-qcow2-util-linux-f1b8b84d3476ac910d922c63a50a4129adbaf584.tar.xz
kernel-qcow2-util-linux-f1b8b84d3476ac910d922c63a50a4129adbaf584.zip
blkzone: Add --count option
The length option is used to specify the number of zones to operate on. To be more consistent with other tools, have this option use a number of sectors and introduce the --count option to allow users to specify a number of zones. The --count and --length options cannot be used together on the command line. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Diffstat (limited to 'sys-utils')
-rw-r--r--sys-utils/blkzone.839
-rw-r--r--sys-utils/blkzone.c76
2 files changed, 76 insertions, 39 deletions
diff --git a/sys-utils/blkzone.8 b/sys-utils/blkzone.8
index 24b0cc7bd..983b04411 100644
--- a/sys-utils/blkzone.8
+++ b/sys-utils/blkzone.8
@@ -10,7 +10,7 @@ blkzone \- run zone command on a device
.B blkzone
is used to run zone command on device that support the Zoned Block Commands
(ZBC) or Zoned-device ATA Commands (ZAC). The zones to operate on can be
-specified using the offset and length options.
+specified using the offset, count and length options.
.PP
The
.I device
@@ -19,8 +19,8 @@ argument is the pathname of the block device.
.SS report
The command \fBblkzone report\fP is used to report device zone information.
.PP
-By default, the command will report on up to 4k zones from the start of the
-block device. Options may be used to modify this behavior, changing the
+By default, the command will report all zones from the start of the
+block device. Options may be used to modify this behavior, changing the
starting zone or the size of the report, as explained below.
.B Report output
@@ -52,34 +52,43 @@ x?:Reserved conditions (should not be reported)
.TE
.SS reset
-The command \fBblkzone reset\fP is used to reset one or more zones. Unlike
-.BR sg_reset_wp (8) ,
+The command \fBblkzone reset\fP is used to reset one or more zones. Unlike
+.BR sg_reset_wp (8),
this command operates from the block layer and can reset a range of zones.
.PP
-By default, the command will operate from the zone at device logical
+By default, the command will operate from the zone at device
sector 0 and reset all zones. Options may be used to modify this behavior
as well as specify the operation to be performed on the zone, as explained below.
-.PP
-The default number of zones (option \fB\-\-length\fP) is all zones.
.SH OPTIONS
The
.I offset
-option argument may be followed by the multiplicative suffixes KiB (=1024),
+and
+.I length
+option 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.
-Additionally, the 0x prefix can be used to specify \fIoffset\fR in hex.
+Additionally, the 0x prefix can be used to specify \fIoffset\fR and
+\fIlength\fR in hex.
.TP
.BR \-o , " \-\-offset "\fIsector\fP
-The starting zone specified as a sector offset. The provided offset in sector
-units (512 bytes) should match the start of a zone. The default value is zero.
+The starting zone specified as a sector offset. The provided offset in sector
+units (512 bytes) should match the start of a zone. The default value is zero.
+.TP
+.BR \-l , " \-\-length "\fIsectors\fP
+The maximum number of sectors the command should operate on. The default value
+is the number of sectors remaining after \fIoffset\fR. This option cannot be
+used together with the option \fB\-\-count\fP.
.TP
-.BR \-l , " \-\-length "\fIcount\fP
-The maximum number of zones to be used for the command.
+.BR \-l , " \-\-count "\fIcount\fP
+The maximum number of zones the command should operate on. The default value
+is the nuber of zones starting from \fIoffset\fR. This option cannot be
+used together with the option \fB\-\-length\fP.
.TP
.BR \-v , " \-\-verbose"
-Display the number of zones returned in the report.
+Display the number of zones returned in the report or the range of sectors
+reset..
.TP
.BR \-V , " \-\-version"
Display version information and exit.
diff --git a/sys-utils/blkzone.c b/sys-utils/blkzone.c
index 2d6a76015..b9f1ed752 100644
--- a/sys-utils/blkzone.c
+++ b/sys-utils/blkzone.c
@@ -63,6 +63,7 @@ struct blkzone_control {
uint64_t offset;
uint64_t length;
+ uint32_t count;
unsigned int verbose : 1;
};
@@ -137,7 +138,7 @@ static unsigned long blkdev_chunk_sectors(const char *dname)
/*
* blkzone report
*/
-#define DEF_REPORT_LEN (1 << 12) /* 4k zones per report (256k kzalloc) */
+#define DEF_REPORT_LEN (1U << 12) /* 4k zones per report (256k kzalloc) */
static const char *type_text[] = {
"RESERVED",
@@ -162,26 +163,31 @@ static int blkzone_report(struct blkzone_control *ctl)
{
struct blk_zone_report *zi;
unsigned long zonesize;
- uint32_t i;
+ uint32_t i, nr_zones;
int fd;
fd = init_device(ctl, O_RDONLY);
if (ctl->offset > ctl->total_sectors)
errx(EXIT_FAILURE, _("%s: offset is greater than device size"), ctl->devname);
- if (ctl->length < 1) {
- zonesize = blkdev_chunk_sectors(ctl->devname);
- if (!zonesize)
- errx(EXIT_FAILURE, _("%s: unable to determine zone size"), ctl->devname);
- ctl->length = 1 + (ctl->total_sectors - ctl->offset) / zonesize;
- }
+
+ zonesize = blkdev_chunk_sectors(ctl->devname);
+ if (!zonesize)
+ errx(EXIT_FAILURE, _("%s: unable to determine zone size"), ctl->devname);
+
+ if (ctl->count)
+ nr_zones = ctl->count;
+ else if (ctl->length)
+ nr_zones = (ctl->length + zonesize - 1) / zonesize;
+ else
+ nr_zones = 1 + (ctl->total_sectors - ctl->offset) / zonesize;
zi = xmalloc(sizeof(struct blk_zone_report) +
(DEF_REPORT_LEN * sizeof(struct blk_zone)));
- while (ctl->length && ctl->offset < ctl->total_sectors) {
+ while (nr_zones && ctl->offset < ctl->total_sectors) {
- zi->nr_zones = min(ctl->length, (uint64_t)DEF_REPORT_LEN);
+ zi->nr_zones = min(nr_zones, DEF_REPORT_LEN);
zi->sector = ctl->offset;
if (ioctl(fd, BLKREPORTZONE, zi) == -1)
@@ -192,7 +198,7 @@ static int blkzone_report(struct blkzone_control *ctl)
zi->nr_zones, ctl->offset);
if (!zi->nr_zones) {
- ctl->length = 0;
+ nr_zones = 0;
break;
}
@@ -205,7 +211,7 @@ static int blkzone_report(struct blkzone_control *ctl)
uint64_t len = entry->len;
if (!len) {
- ctl->length = 0;
+ nr_zones = 0;
break;
}
@@ -216,7 +222,7 @@ static int blkzone_report(struct blkzone_control *ctl)
cond, condition_str[cond & ARRAY_SIZE(condition_str)],
type, type_text[type]);
- ctl->length--;
+ nr_zones--;
ctl->offset = start + len;
}
@@ -246,31 +252,39 @@ static int blkzone_reset(struct blkzone_control *ctl)
fd = init_device(ctl, O_WRONLY);
if (ctl->offset & (zonesize - 1))
- errx(EXIT_FAILURE, _("%s: zone %" PRIu64 " is not aligned "
+ errx(EXIT_FAILURE, _("%s: offset %" PRIu64 " is not aligned "
"to zone size %" PRIu64),
ctl->devname, ctl->offset, zonesize);
if (ctl->offset > ctl->total_sectors)
errx(EXIT_FAILURE, _("%s: offset is greater than device size"), ctl->devname);
- if (!ctl->length)
- zlen = ctl->total_sectors;
+ if (ctl->count)
+ zlen = ctl->count * zonesize;
+ else if (ctl->length)
+ zlen = ctl->length;
else
- zlen = ctl->length * zonesize;
+ zlen = ctl->total_sectors;
if (ctl->offset + zlen > ctl->total_sectors)
zlen = ctl->total_sectors - ctl->offset;
+ if (ctl->length &&
+ (zlen & (zonesize - 1)) &&
+ ctl->offset + zlen != ctl->total_sectors)
+ errx(EXIT_FAILURE, _("%s: number of sectors %" PRIu64 " is not aligned "
+ "to zone size %" PRIu64),
+ ctl->devname, ctl->length, zonesize);
+
za.sector = ctl->offset;
za.nr_sectors = zlen;
if (ioctl(fd, BLKRESETZONE, &za) == -1)
err(EXIT_FAILURE, _("%s: BLKRESETZONE ioctl failed"), ctl->devname);
-
else if (ctl->verbose)
printf(_("%s: successfully reset in range from %" PRIu64 ", to %" PRIu64),
ctl->devname,
ctl->offset,
- zlen);
+ ctl->offset + zlen);
close(fd);
return 0;
}
@@ -291,7 +305,8 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
fputs(USAGE_OPTIONS, out);
fputs(_(" -o, --offset <sector> start sector of zone to act (in 512-byte sectors)\n"), out);
- fputs(_(" -l, --length <number> maximum number of zones\n"), out);
+ fputs(_(" -l, --length <sectors> maximum sectors to act (in 512-byte sectors)\n"), out);
+ fputs(_(" -c, --count <number> maximum number of zones\n"), out);
fputs(_(" -v, --verbose display more details\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
@@ -304,11 +319,17 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
int main(int argc, char **argv)
{
int c;
- struct blkzone_control ctl = { .devname = NULL };
+ struct blkzone_control ctl = {
+ .devname = NULL,
+ .offset = 0,
+ .count = 0,
+ .length = 0
+ };
static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
- { "length", required_argument, NULL, 'l' }, /* max #of zones (entries) for result */
+ { "count", required_argument, NULL, 'c' }, /* max #of zones to operate on */
+ { "length", required_argument, NULL, 'l' }, /* max of sectors to operate on */
{ "offset", required_argument, NULL, 'o' }, /* starting LBA */
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
@@ -328,14 +349,18 @@ int main(int argc, char **argv)
argc--;
}
- while ((c = getopt_long(argc, argv, "hl:o:vV", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "hc:l:o:vV", longopts, NULL)) != -1) {
switch (c) {
case 'h':
usage(stdout);
break;
+ case 'c':
+ ctl.count = strtou32_or_err(optarg,
+ _("failed to parse number of zones"));
+ break;
case 'l':
ctl.length = strtosize_or_err(optarg,
- _("failed to parse number of zones"));
+ _("failed to parse number of sectors"));
break;
case 'o':
ctl.offset = strtosize_or_err(optarg,
@@ -355,6 +380,9 @@ int main(int argc, char **argv)
if (!ctl.command)
errx(EXIT_FAILURE, _("no command specified"));
+ if (ctl.count && ctl.length)
+ errx(EXIT_FAILURE, _("zone count and number of sectors cannot be specified together"));
+
if (optind == argc)
errx(EXIT_FAILURE, _("no device specified"));
ctl.devname = argv[optind++];