]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
blkzone: Report all zones if length is not specified
authorDamien Le Moal <damien.lemoal@wdc.com>
Fri, 24 Feb 2017 03:36:08 +0000 (12:36 +0900)
committerKarel Zak <kzak@redhat.com>
Fri, 24 Feb 2017 10:53:45 +0000 (11:53 +0100)
Report all zones of the block device when length is not specified
on the command line. To do this, introduce an inner loop in
blkzone_report to repeatedly issue report zone ioctl to the
device.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
sys-utils/blkzone.c

index 1c3a7ef7daf0a70192944b1f22446a7e77fcee2f..c9d65dc236975043f326492c2937c24887107aea 100644 (file)
@@ -107,11 +107,37 @@ static int init_device(struct blkzone_control *ctl, int mode)
        return fd;
 }
 
+/*
+ * Get the device zone size indicated by chunk sectors).
+ */
+static unsigned long blkdev_chunk_sectors(const char *dname)
+{
+       struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
+       dev_t devno = sysfs_devname_to_devno(dname, NULL);
+       int major_no = major(devno);
+       int block_no = minor(devno) & ~0x0f;
+       uint64_t sz;
+       int rc;
+
+       /*
+        * Mapping /dev/sdXn -> /sys/block/sdX to read the chunk_size entry.
+        * This method masks off the partition specified by the minor device
+        * component.
+        */
+       devno = makedev(major_no, block_no);
+       if (sysfs_init(&cxt, devno, NULL))
+               return 0;
+
+       rc = sysfs_read_u64(&cxt, "queue/chunk_sectors", &sz);
+
+       sysfs_deinit(&cxt);
+       return rc == 0 ? sz : 0;
+}
+
 /*
  * blkzone report
  */
-#define DEF_REPORT_LEN         (1 << 12) /* 4k zones (256k kzalloc) */
-#define MAX_REPORT_LEN         (1 << 16) /* 64k zones */
+#define DEF_REPORT_LEN         (1 << 12) /* 4k zones per report (256k kzalloc) */
 
 static const char *type_text[] = {
        "RESERVED",
@@ -135,6 +161,7 @@ static const char *condition_str[] = {
 static int blkzone_report(struct blkzone_control *ctl)
 {
        struct blk_zone_report *zi;
+       unsigned long zonesize;
        uint32_t i;
        int fd;
 
@@ -142,43 +169,58 @@ static int blkzone_report(struct blkzone_control *ctl)
 
        if (ctl->offset > ctl->total_sectors)
                errx(EXIT_FAILURE, _("%s: offset is greater than device size"), ctl->devname);
-       if (ctl->length < 1)
-               ctl->length = 1;
-       if (ctl->length > MAX_REPORT_LEN) {
-               ctl->length = MAX_REPORT_LEN;
-               warnx(_("limiting report to %" PRIu64 " entries"), ctl->length);
+       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;
        }
 
-       zi = xmalloc(sizeof(struct blk_zone_report)
-                    + (ctl->length * sizeof(struct blk_zone)));
-       zi->nr_zones = ctl->length;
-       zi->sector = ctl->offset;               /* maybe shift 4Kn -> 512e */
+       zi = xmalloc(sizeof(struct blk_zone_report) +
+                    (DEF_REPORT_LEN * sizeof(struct blk_zone)));
 
-       if (ioctl(fd, BLKREPORTZONE, zi) == -1)
-               err(EXIT_FAILURE, _("%s: BLKREPORTZONE ioctl failed"), ctl->devname);
+       while (ctl->length && ctl->offset < ctl->total_sectors) {
 
-       if (ctl->verbose)
-               printf(_("Found %d zones\n"), zi->nr_zones);
+               zi->nr_zones = min(ctl->length, (uint64_t)DEF_REPORT_LEN);
+               zi->sector = ctl->offset;
 
-       printf(_("Zones returned: %u\n"), zi->nr_zones);
+               if (ioctl(fd, BLKREPORTZONE, zi) == -1)
+                       err(EXIT_FAILURE, _("%s: BLKREPORTZONE ioctl failed"), ctl->devname);
 
-       for (i = 0; i < zi->nr_zones; i++) {
-               const struct blk_zone *entry = &zi->zones[i];
-               unsigned int type = entry->type;
-               uint64_t start = entry->start;
-               uint64_t wp = entry->wp;
-               uint8_t cond = entry->cond;
-               uint64_t len = entry->len;
+               if (ctl->verbose)
+                       printf(_("Found %d zones from %lx\n"),
+                               zi->nr_zones, ctl->offset);
 
-               if (!len)
+               if (!zi->nr_zones) {
+                       ctl->length = 0;
                        break;
+               }
+
+               for (i = 0; i < zi->nr_zones; i++) {
+                       const struct blk_zone *entry = &zi->zones[i];
+                       unsigned int type = entry->type;
+                       uint64_t start = entry->start;
+                       uint64_t wp = entry->wp;
+                       uint8_t cond = entry->cond;
+                       uint64_t len = entry->len;
+
+                       if (!len) {
+                               ctl->length = 0;
+                               break;
+                       }
+
+                       printf(_("  start: %9lx, len %6lx, wptr %6lx"
+                               " reset:%u non-seq:%u, zcond:%2u(%s) [type: %u(%s)]\n"),
+                               start, len, wp - start,
+                               entry->reset, entry->non_seq,
+                               cond, condition_str[cond & ARRAY_SIZE(condition_str)],
+                               type, type_text[type]);
+
+                       ctl->length--;
+                       ctl->offset = start + len;
+
+               }
 
-               printf(_("  start: %9lx, len %6lx, wptr %6lx"
-                        " reset:%u non-seq:%u, zcond:%2u(%s) [type: %u(%s)]\n"),
-                       start, len, wp - start,
-                       entry->reset, entry->non_seq,
-                       cond, condition_str[cond & ARRAY_SIZE(condition_str)],
-                       type, type_text[type]);
        }
 
        free(zi);
@@ -190,30 +232,6 @@ static int blkzone_report(struct blkzone_control *ctl)
 /*
  * blkzone reset
  */
-static unsigned long blkdev_chunk_sectors(const char *dname)
-{
-       struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
-       dev_t devno = sysfs_devname_to_devno(dname, NULL);
-       int major_no = major(devno);
-       int block_no = minor(devno) & ~0x0f;
-       uint64_t sz;
-       int rc;
-
-       /*
-        * Mapping /dev/sdXn -> /sys/block/sdX to read the chunk_size entry.
-        * This method masks off the partition specified by the minor device
-        * component.
-        */
-       devno = makedev(major_no, block_no);
-       if (sysfs_init(&cxt, devno, NULL))
-               return 0;
-
-       rc = sysfs_read_u64(&cxt, "queue/chunk_sectors", &sz);
-
-       sysfs_deinit(&cxt);
-       return rc == 0 ? sz : 0;
-}
-
 static int blkzone_reset(struct blkzone_control *ctl)
 {
        struct blk_zone_range za = { .sector = 0 };