]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
blkid: retport block size of a filesystem
authorMikulas Patocka <mpatocka@redhat.com>
Mon, 2 Sep 2019 10:28:39 +0000 (12:28 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 2 Sep 2019 10:55:53 +0000 (12:55 +0200)
This patch extends libblkid, so that it reports filesystem block size.

When blkid returns a specific number in the BLOCK_SIZE attribute, it
guarantees that all the bios submitted by the filesystem are aligned on
this boundary.

We need this because when we want to enable dm-integrity or dm-writecache
on an existing filesystem, we need to know filesystem block size, so that
dm-integrity or dm-writecache is initialized with matching block size.

We could always use block size 512 for dm-integrity and dm-writecache, but
that would cause metadata overhead and performance degradation. On the
other hand, if we used block size 4096, it would fail if the filesystem
has smaller blocksize.

[kzak@redhat.com: - move vfat BLOCK_SIZE to probing function
  - remove unwanted debug fprintf from ZFS prober]

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
27 files changed:
libblkid/src/superblocks/apfs.c
libblkid/src/superblocks/befs.c
libblkid/src/superblocks/btrfs.c
libblkid/src/superblocks/exfat.c
libblkid/src/superblocks/exfs.c
libblkid/src/superblocks/ext.c
libblkid/src/superblocks/f2fs.c
libblkid/src/superblocks/gfs.c
libblkid/src/superblocks/hfs.c
libblkid/src/superblocks/hpfs.c
libblkid/src/superblocks/iso9660.c
libblkid/src/superblocks/jfs.c
libblkid/src/superblocks/minix.c
libblkid/src/superblocks/nilfs.c
libblkid/src/superblocks/ntfs.c
libblkid/src/superblocks/ocfs.c
libblkid/src/superblocks/reiserfs.c
libblkid/src/superblocks/romfs.c
libblkid/src/superblocks/squashfs.c
libblkid/src/superblocks/superblocks.c
libblkid/src/superblocks/superblocks.h
libblkid/src/superblocks/udf.c
libblkid/src/superblocks/ufs.c
libblkid/src/superblocks/vfat.c
libblkid/src/superblocks/vxfs.c
libblkid/src/superblocks/xfs.c
libblkid/src/superblocks/zfs.c

index 67db6eb895067b17fbf6594a50b71132b79d70df..3332ef22870df13b80118623e01ea84c5d37edbe 100644 (file)
@@ -65,6 +65,8 @@ static int probe_apfs(blkid_probe pr, const struct blkid_idmag *mag)
        if (blkid_probe_set_uuid(pr, sb->uuid) < 0)
                return BLKID_PROBE_NONE;
 
+       blkid_probe_set_block_size(pr, le32_to_cpu(sb->block_size));
+
        return BLKID_PROBE_OK;
 }
 
index 14af97217da217aad60fa5a88322e66f1e50a845..516d800939016f114003377df4ce8e58a8b3d905 100644 (file)
@@ -519,6 +519,9 @@ static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag)
                blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id,
                                        sizeof(volume_id), "%016" PRIx64,
                                        FS64_TO_CPU(volume_id, fs_le));
+
+       blkid_probe_set_block_size(pr, block_size);
+
        return BLKID_PROBE_OK;
 }
 
index 7ce3dfff86d643ca52a3fb917a09a4b30606ba2f..f0fde700d8966c7840a647c7243e9e301bf07203 100644 (file)
@@ -74,6 +74,7 @@ static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag)
 
        blkid_probe_set_uuid(pr, bfs->fsid);
        blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB");
+       blkid_probe_set_block_size(pr, le32_to_cpu(bfs->sectorsize));
 
        return 0;
 }
index 4bf92eac80260231a953a0c9da59cf76ea1e4667..7622320d3908d07bb0dc5adc22d9cdf94f4a4dab 100644 (file)
@@ -137,6 +137,8 @@ static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag)
        blkid_probe_sprintf_version(pr, "%u.%u",
                        sb->version.vermaj, sb->version.vermin);
 
+       blkid_probe_set_block_size(pr, BLOCK_SIZE(sb));
+
        return BLKID_PROBE_OK;
 }
 
index f717b65309afb628a8fede8b4ec482d4617f9b97..e0eafafc686be506652f6cca349ff5bffb01a92d 100644 (file)
@@ -170,7 +170,11 @@ static int probe_exfs(blkid_probe pr, const struct blkid_idmag *mag)
        if (*xs->sb_fname != '\0')
                blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
                                sizeof(xs->sb_fname));
+
        blkid_probe_set_uuid(pr, xs->sb_uuid);
+
+       blkid_probe_set_block_size(pr, be32_to_cpu(xs->sb_blocksize));
+
        return 0;
 }
 
index caf82c1710ca879be9d25c22ca34877fd21a2cf9..3870522fadf1ab05e472d641a5f88f4264c6c0af 100644 (file)
@@ -187,6 +187,9 @@ static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es)
        blkid_probe_sprintf_version(pr, "%u.%u",
                le32_to_cpu(es->s_rev_level),
                le16_to_cpu(es->s_minor_rev_level));
+
+       if (le32_to_cpu(es->s_log_block_size) < 32)
+               blkid_probe_set_block_size(pr, 1024U << le32_to_cpu(es->s_log_block_size));
 }
 
 
index d1bf25a3a5cd9a21151b06a9e8ffbbc22318b710..255ef6384fc4f4cc5da80f892ea2042c861590ac 100644 (file)
@@ -78,6 +78,8 @@ static int probe_f2fs(blkid_probe pr, const struct blkid_idmag *mag)
 
        blkid_probe_set_uuid(pr, sb->uuid);
        blkid_probe_sprintf_version(pr, "%u.%u", vermaj, vermin);
+       if (le32_to_cpu(sb->log_blocksize) < 32)
+               blkid_probe_set_block_size(pr, 1U << le32_to_cpu(sb->log_blocksize));
        return 0;
 }
 
index ea6036cb779ae799a5cc4f20e7d07a32da49c556..e22a6a3f953a094f580ba312ce16ca7aa17ba9d3 100644 (file)
@@ -98,6 +98,7 @@ static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag)
                                sizeof(sbd->sb_locktable));
                blkid_probe_set_uuid(pr, sbd->sb_uuid);
                blkid_probe_set_version(pr, "1");
+               blkid_probe_set_block_size(pr, be32_to_cpu(sbd->sb_bsize));
                return 0;
        }
        return 1;
index 6f170a3cd6238612adb3f79ba9cb40a9ccf43022..e537bbbd3cb1480acc65bfecdfb88e14d7097d40 100644 (file)
@@ -241,6 +241,8 @@ static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag)
        if (blocksize < HFSPLUS_SECTOR_SIZE)
                return 1;
 
+       blkid_probe_set_block_size(pr, blocksize);
+
        memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
        cat_block = be32_to_cpu(extents[0].start_block);
 
index 0565d370cf8d16957f96ada330ddcf63e0aa7368..dcf4520b638f69190eecf1d2eea87d5624dd3cb2 100644 (file)
@@ -99,6 +99,7 @@ static int probe_hpfs(blkid_probe pr, const struct blkid_idmag *mag)
                                hbb->vol_serno[1], hbb->vol_serno[0]);
        }
        blkid_probe_sprintf_version(pr, "%u", version);
+       blkid_probe_set_block_size(pr, 512);
 
        return 0;
 }
index 7356754eeb381a5c7d151568cdb88472ac655baa..8dc2e53948f7840ab72dee88dbeb49308d617bbf 100644 (file)
@@ -182,6 +182,8 @@ static int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag)
 
        memcpy(label, iso->volume_id, sizeof(label));
 
+       blkid_probe_set_block_size(pr, 2048);
+
        if (!is_str_empty(iso->system_id, sizeof(iso->system_id)))
                blkid_probe_set_id_label(pr, "SYSTEM_ID",
                                iso->system_id, sizeof(iso->system_id));
index 0f956ef00d242e84281f32c7a1ac333ab50b9ef4..3de8c2e3dfb2c4c3a3a0663817ec8329ecd037ea 100644 (file)
@@ -52,6 +52,7 @@ static int probe_jfs(blkid_probe pr, const struct blkid_idmag *mag)
        if (*((char *) js->js_label) != '\0')
                blkid_probe_set_label(pr, js->js_label, sizeof(js->js_label));
        blkid_probe_set_uuid(pr, js->js_uuid);
+       blkid_probe_set_block_size(pr, le32_to_cpu(js->js_bsize));
        return 0;
 }
 
index d9771ba02f96258dc04eaa48ae74914fc24cc926..a3354f6e7cec89e6e6233e4f03b5a87b2e66dfdf 100644 (file)
@@ -80,6 +80,7 @@ static int probe_minix(blkid_probe pr,
        unsigned long zones, ninodes, imaps, zmaps;
        off_t firstz;
        size_t zone_size;
+       unsigned block_size;
 
        data = blkid_probe_get_buffer(pr, 1024,
                        max(sizeof(struct minix_super_block),
@@ -103,6 +104,7 @@ static int probe_minix(blkid_probe pr,
                zmaps   = minix_swab16(swabme, sb->s_zmap_blocks);
                firstz  = minix_swab16(swabme, sb->s_firstdatazone);
                zone_size = sb->s_log_zone_size;
+               block_size = 1024;
                break;
        }
        case 3: {
@@ -114,6 +116,8 @@ static int probe_minix(blkid_probe pr,
                zmaps   = minix_swab16(swabme, sb->s_zmap_blocks);
                firstz  = minix_swab16(swabme, sb->s_firstdatazone);
                zone_size = sb->s_log_zone_size;
+               block_size = minix_swab16(swabme, sb->s_blocksize);
+
                break;
        }
        default:
@@ -143,6 +147,7 @@ static int probe_minix(blkid_probe pr,
                return 1;
 
        blkid_probe_sprintf_version(pr, "%d", version);
+       blkid_probe_set_block_size(pr, block_size);
        return 0;
 }
 
index 95538ef7bda68c0c81b04ff24875913b80d55919..423bd1ac4e0c43b4cc77a34a43a4e13c0f3c17f5 100644 (file)
@@ -157,6 +157,9 @@ static int probe_nilfs2(blkid_probe pr,
                                (unsigned char *) &sb->s_magic))
                return 1;
 
+       if (le32_to_cpu(sb->s_log_block_size) < 32)
+               blkid_probe_set_block_size(pr, 1024U << le32_to_cpu(sb->s_log_block_size));
+
        return 0;
 }
 
index 90a102f89ef671a98ff18d875bbaf2ad89dc03b8..0e6f6b748b33ee7336332a54df655883a12d6aaf 100644 (file)
@@ -208,6 +208,8 @@ static int __probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag, int save_
                attr_off += attr_len;
        }
 
+       blkid_probe_set_block_size(pr, sector_size);
+
        blkid_probe_sprintf_uuid(pr,
                        (unsigned char *) &ns->volume_serial,
                        sizeof(ns->volume_serial),
index 3fe199d3fe72305e7f4c355825a6e4d9faa38895..463ed7bcffce801f94225ee607308cc2d78e14eb 100644 (file)
@@ -153,6 +153,9 @@ static int probe_ocfs2(blkid_probe pr, const struct blkid_idmag *mag)
                le16_to_cpu(osb->s_major_rev_level),
                le16_to_cpu(osb->s_minor_rev_level));
 
+       if (le32_to_cpu(osb->s_blocksize_bits) < 32)
+               blkid_probe_set_block_size(pr, 1U << le32_to_cpu(osb->s_blocksize_bits));
+
        return 0;
 }
 
index edbaaa9469949e2af37b84f6b7406801faa2b1db..6c5e5b0d7103b96d2b6f5e858ca14f994810916d 100644 (file)
@@ -32,7 +32,8 @@ struct reiserfs_super_block {
 
 struct reiser4_super_block {
        unsigned char   rs4_magic[16];
-       uint16_t        rs4_dummy[2];
+       uint8_t         rs4_dummy[3];
+       uint8_t         rs4_blocksize;
        unsigned char   rs4_uuid[16];
        unsigned char   rs4_label[16];
        uint64_t        rs4_dummy2;
@@ -73,22 +74,29 @@ static int probe_reiser(blkid_probe pr, const struct blkid_idmag *mag)
        else
                blkid_probe_set_version(pr, "3.5");
 
+       blkid_probe_set_block_size(pr, blocksize);
+
        return 0;
 }
 
 static int probe_reiser4(blkid_probe pr, const struct blkid_idmag *mag)
 {
        struct reiser4_super_block *rs4;
+       unsigned int blocksize;
 
        rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block);
        if (!rs4)
                return errno ? -errno : 1;
 
+       blocksize = rs4->rs4_blocksize * 256;
+
        if (*rs4->rs4_label)
                blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label));
        blkid_probe_set_uuid(pr, rs4->rs4_uuid);
        blkid_probe_set_version(pr, "4");
 
+       blkid_probe_set_block_size(pr, blocksize);
+
        return 0;
 }
 
index f3e9f8b05d6eae3b211d26e3e19cfbb065896b8a..1c2ac4315edf8566026b2ca00e7d2fb5edfa1a02 100644 (file)
@@ -34,6 +34,9 @@ static int probe_romfs(blkid_probe pr, const struct blkid_idmag *mag)
        if (*((char *) ros->ros_volume) != '\0')
                blkid_probe_set_label(pr, ros->ros_volume,
                                sizeof(ros->ros_volume));
+
+       blkid_probe_set_block_size(pr, 1024);
+
        return 0;
 }
 
index 7364beca22022e1896d74e2c3643b9d971e63305..4db84249369cf3c10a6eced8d64da9395cf77f8d 100644 (file)
@@ -71,6 +71,8 @@ static int probe_squashfs3(blkid_probe pr, const struct blkid_idmag *mag)
 
        blkid_probe_sprintf_version(pr, "%u.%u", vermaj, vermin);
 
+       blkid_probe_set_block_size(pr, 1024);
+
        return 0;
 }
 
index 277a2c6de38eccd9b735cf3d46ea31203b7cdb46..93d5abd4c7655ce07171a73cbf36012a8c2083db 100644 (file)
@@ -74,6 +74,8 @@
  * @APPLICATION_ID: ISO9660 application identifier
  *
  * @BOOT_SYSTEM_ID: ISO9660 boot system identifier
+ *
+ * @BLOCK_SIZE: block size
  */
 
 static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn);
@@ -553,6 +555,11 @@ int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
        return rc;
 }
 
+int blkid_probe_set_block_size(blkid_probe pr, unsigned block_size)
+{
+       return blkid_probe_sprintf_value(pr, "BLOCK_SIZE", "%u", block_size);
+}
+
 static int blkid_probe_set_usage(blkid_probe pr, int usage)
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
index 59682c86d37b0da71c62465470803dc34e5ca45a..0cd0caccf8a42d651bc03031e6a82fc0c3b67369 100644 (file)
@@ -108,6 +108,8 @@ extern int blkid_probe_set_id_label(blkid_probe pr, const char *name,
 extern int blkid_probe_set_utf8_id_label(blkid_probe pr, const char *name,
                             const unsigned char *data, size_t len, int enc);
 
+int blkid_probe_set_block_size(blkid_probe pr, unsigned block_size);
+
 extern int blkid_probe_is_bitlocker(blkid_probe pr);
 extern int blkid_probe_is_ntfs(blkid_probe pr);
 
index 97e79dab0e4c35a5fd31d1715c2c015f5ada87f1..1ab8a1e2649952d327b714dfc2e8b5230029123c 100644 (file)
@@ -464,6 +464,8 @@ real_blksz:
                 * E.g. number 0x0150 is revision 1.50, number 0x0201 is revision 2.01. */
                blkid_probe_sprintf_version(pr, "%x.%02x", (unsigned int)(udf_rev >> 8), (unsigned int)(udf_rev & 0xFF));
 
+       blkid_probe_set_block_size(pr, bs);
+
        return 0;
 }
 
index 6ef2acddca05fd5b1a627ea2ab3197e9a75b16c4..7a8396c1c4abb07a95245ffe8031285c5391ac68 100644 (file)
@@ -233,6 +233,11 @@ found:
                        (unsigned char *) &ufs->fs_magic))
                return 1;
 
+       if (!is_be)
+               blkid_probe_set_block_size(pr, le32_to_cpu(ufs->fs_fsize));
+       else
+               blkid_probe_set_block_size(pr, be32_to_cpu(ufs->fs_fsize));
+
        return 0;
 }
 
index 5061587ad806276cd66c78245d4cc3d4d47e64fa..7ea35200ffdc4cbb10a30a4f7a35607db8020841 100644 (file)
@@ -438,6 +438,8 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag)
        if (version)
                blkid_probe_set_version(pr, version);
 
+       blkid_probe_set_block_size(pr, sector_size);
+
        return 0;
 }
 
index 19d284cbfef1f6fa5e8b04bbd9284b680deddfd8..d9d26adcfde8dab707df7056aa6e153506fadf18 100644 (file)
 struct vxfs_super_block {
        uint32_t                vs_magic;
        int32_t                 vs_version;
+       uint32_t                vs_ctime;
+       uint32_t                vs_cutime;
+       uint32_t                __unused1;
+       uint32_t                __unused2;
+       uint32_t                vs_old_logstart;
+       uint32_t                vs_old_logend;
+       uint32_t                vs_bsize;
+       uint32_t                vs_size;
+       uint32_t                vs_dsize;
 };
 
 static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag)
@@ -22,7 +31,13 @@ static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag)
        if (!vxs)
                return errno ? -errno : 1;
 
-       blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version);
+       if (le32_to_cpu(vxs->vs_magic) == 0xa501fcf5) {
+               blkid_probe_sprintf_version(pr, "%u", (unsigned int)le32_to_cpu(vxs->vs_version));
+               blkid_probe_set_block_size(pr, le32_to_cpu(vxs->vs_bsize));
+       } else if (be32_to_cpu(vxs->vs_magic) == 0xa501fcf5) {
+               blkid_probe_sprintf_version(pr, "%u", (unsigned int)be32_to_cpu(vxs->vs_version));
+               blkid_probe_set_block_size(pr, be32_to_cpu(vxs->vs_bsize));
+       }
        return 0;
 }
 
@@ -35,6 +50,7 @@ const struct blkid_idinfo vxfs_idinfo =
        .magics         =
        {
                { .magic = "\365\374\001\245", .len = 4, .kboff = 1 },
+               { .magic = "\245\001\374\365", .len = 4, .kboff = 8 },
                { NULL }
        }
 };
index 99848f9004a1bb350d3e0e1629232110b9ce55e7..eb513ac3ec201e91776f8610c45d9cc5193b8f7e 100644 (file)
@@ -173,6 +173,7 @@ static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
                blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
                                sizeof(xs->sb_fname));
        blkid_probe_set_uuid(pr, xs->sb_uuid);
+       blkid_probe_set_block_size(pr, xs->sb_sectsize * 256);
        return 0;
 }
 
index 0af14fb65aa5f8c3c31042f1c65af80aac9d4672..e0c544917d8cccbdf8301717e0671ecb88013312 100644 (file)
@@ -37,6 +37,7 @@ struct zfs_uberblock {
 
 #define DATA_TYPE_UINT64 8
 #define DATA_TYPE_STRING 9
+#define DATA_TYPE_DIRECTORY 19
 
 struct nvpair {
        uint32_t        nvp_size;
@@ -60,32 +61,37 @@ struct nvuint64 {
        uint64_t        nvu_value;
 } __attribute__((packed));
 
+struct nvdirectory {
+       uint32_t        nvd_type;
+       uint32_t        nvd_unknown[3];
+};
+
 struct nvlist {
        uint32_t        nvl_unknown[3];
        struct nvpair   nvl_nvpair;
 };
 
-static int zfs_process_value(blkid_probe pr, char *name, size_t namelen,
-                            void *value, size_t max_value_size)
+static void zfs_process_value(blkid_probe pr, char *name, size_t namelen,
+                            void *value, size_t max_value_size, unsigned directory_level)
 {
        if (strncmp(name, "name", namelen) == 0 &&
-           sizeof(struct nvstring) <= max_value_size) {
+           sizeof(struct nvstring) <= max_value_size &&
+           !directory_level) {
                struct nvstring *nvs = value;
                uint32_t nvs_type = be32_to_cpu(nvs->nvs_type);
                uint32_t nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
 
                if (nvs_type != DATA_TYPE_STRING ||
                    (uint64_t)nvs_strlen + sizeof(*nvs) > max_value_size)
-                       return 0;
+                       return;
 
                DBG(LOWPROBE, ul_debug("nvstring: type %u string %*s\n",
                                       nvs_type, nvs_strlen, nvs->nvs_string));
 
                blkid_probe_set_label(pr, nvs->nvs_string, nvs_strlen);
-
-               return 1;
        } else if (strncmp(name, "guid", namelen) == 0 &&
-                  sizeof(struct nvuint64) <= max_value_size) {
+                  sizeof(struct nvuint64) <= max_value_size &&
+                  !directory_level) {
                struct nvuint64 *nvu = value;
                uint32_t nvu_type = be32_to_cpu(nvu->nvu_type);
                uint64_t nvu_value;
@@ -94,17 +100,16 @@ static int zfs_process_value(blkid_probe pr, char *name, size_t namelen,
                nvu_value = be64_to_cpu(nvu_value);
 
                if (nvu_type != DATA_TYPE_UINT64)
-                       return 0;
+                       return;
 
                DBG(LOWPROBE, ul_debug("nvuint64: type %u value %"PRIu64"\n",
                                       nvu_type, nvu_value));
 
                blkid_probe_sprintf_value(pr, "UUID_SUB",
                                          "%"PRIu64, nvu_value);
-
-               return 1;
        } else if (strncmp(name, "pool_guid", namelen) == 0 &&
-                  sizeof(struct nvuint64) <= max_value_size) {
+                  sizeof(struct nvuint64) <= max_value_size &&
+                  !directory_level) {
                struct nvuint64 *nvu = value;
                uint32_t nvu_type = be32_to_cpu(nvu->nvu_type);
                uint64_t nvu_value;
@@ -113,7 +118,7 @@ static int zfs_process_value(blkid_probe pr, char *name, size_t namelen,
                nvu_value = be64_to_cpu(nvu_value);
 
                if (nvu_type != DATA_TYPE_UINT64)
-                       return 0;
+                       return;
 
                DBG(LOWPROBE, ul_debug("nvuint64: type %u value %"PRIu64"\n",
                                       nvu_type, nvu_value));
@@ -121,10 +126,21 @@ static int zfs_process_value(blkid_probe pr, char *name, size_t namelen,
                blkid_probe_sprintf_uuid(pr, (unsigned char *) &nvu_value,
                                         sizeof(nvu_value),
                                         "%"PRIu64, nvu_value);
-               return 1;
-       }
+       } else if (strncmp(name, "ashift", namelen) == 0 &&
+                  sizeof(struct nvuint64) <= max_value_size) {
+               struct nvuint64 *nvu = value;
+               uint32_t nvu_type = be32_to_cpu(nvu->nvu_type);
+               uint64_t nvu_value;
 
-       return 0;
+               memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
+               nvu_value = be64_to_cpu(nvu_value);
+
+               if (nvu_type != DATA_TYPE_UINT64)
+                       return;
+
+               if (nvu_value < 32)
+                       blkid_probe_set_block_size(pr, 1U << nvu_value);
+       }
 }
 
 static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
@@ -133,7 +149,7 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
        struct nvlist *nvl;
        struct nvpair *nvp;
        size_t left = 4096;
-       int found = 0;
+       unsigned directory_level = 0;
 
        offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR;
 
@@ -152,13 +168,21 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
        nvp = &nvl->nvl_nvpair;
        left -= (unsigned char *)nvp - p; /* Already used up 12 bytes */
 
-       while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) {
+       while (left > sizeof(*nvp)) {
                uint32_t nvp_size = be32_to_cpu(nvp->nvp_size);
                uint32_t nvp_namelen = be32_to_cpu(nvp->nvp_namelen);
                uint64_t namesize = ((uint64_t)nvp_namelen + 3) & ~3;
                size_t max_value_size;
                void *value;
 
+               if (!nvp->nvp_size) {
+                       if (!directory_level)
+                               break;
+                       directory_level--;
+                       nvp_size = 8;
+                       goto cont;
+               }
+
                DBG(LOWPROBE, ul_debug("left %zd nvp_size %u\n",
                                       left, nvp_size));
 
@@ -174,9 +198,21 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
                max_value_size = nvp_size - (namesize + sizeof(*nvp));
                value = nvp->nvp_name + namesize;
 
-               found += zfs_process_value(pr, nvp->nvp_name, nvp_namelen,
-                                          value, max_value_size);
+               if (sizeof(struct nvdirectory) <= max_value_size) {
+                       struct nvdirectory *nvu = value;
+                       if (be32_to_cpu(nvu->nvd_type) == DATA_TYPE_DIRECTORY) {
+                               nvp_size = sizeof(*nvp) + namesize + sizeof(*nvu);
+                               directory_level++;
+                               goto cont;
+                       }
+               }
+
+               zfs_process_value(pr, nvp->nvp_name, nvp_namelen,
+                                 value, max_value_size, directory_level);
 
+cont:
+               if (nvp_size > left)
+                       break;
                left -= nvp_size;
 
                nvp = (struct nvpair *)((char *)nvp + nvp_size);