From 5568ea814a504429817736a37d9d979bd7b30f81 Mon Sep 17 00:00:00 2001 From: mlelstv Date: Sat, 29 Feb 2020 17:03:33 +0000 Subject: [PATCH] Fix disk geometry calculation. Add DIOCGPARTINFO to support getdisksize() used by other drivers, filesystems and specfs. --- .../cddl/osnet/dist/uts/common/fs/zfs/zvol.c | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/zvol.c b/external/cddl/osnet/dist/uts/common/fs/zfs/zvol.c index dad2d5fb489d..048f6ce5eb22 100644 --- a/external/cddl/osnet/dist/uts/common/fs/zfs/zvol.c +++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zvol.c @@ -72,6 +72,9 @@ #include #include #include +#ifdef __NetBSD__ +#include +#endif #include #include #include @@ -316,12 +319,17 @@ zvol_size_changed(zvol_state_t *zv, uint64_t volsize) #endif /* __FreeBSD__ */ #ifdef __NetBSD__ struct disk_geom *dg = &zv->zv_dk.dk_geom; + objset_t *os = zv->zv_objset; + spa_t *spa = dmu_objset_spa(os); + unsigned secsize; zv->zv_volsize = volsize; + secsize = MAX(DEV_BSIZE, 1U << spa->spa_max_ashift); + memset(dg, 0, sizeof(*dg)); - dg->dg_secsize = DEV_BSIZE; /* XXX 512? */ - dg->dg_secperunit = zv->zv_volsize / dg->dg_secsize;; + dg->dg_secsize = secsize; + dg->dg_secperunit = volsize / secsize; disk_set_info(NULL, &zv->zv_dk, "ZVOL"); #endif } @@ -3589,19 +3597,47 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) case DIOCGWEDGEINFO: { struct dkwedge_info *dkw = (void *) arg; - + struct disk_geom *dg = &zv->zv_dk.dk_geom; + memset(dkw, 0, sizeof(*dkw)); strlcpy(dkw->dkw_devname, zv->zv_name, sizeof(dkw->dkw_devname)); + + /* + * dkw_parent is interpreted as disk device name by the kernel + * to locate the disk driver and its geometry data. The faked + * name "ZFS" must never match a device name. The kernel will + * then call DIOCGPARTINFO below to retrieve the missing + * information. + * + * Userland will also be confused, but it can use the + * proplib based DIOCGDISKINFO to get the geometry + * information. + */ strlcpy(dkw->dkw_parent, "ZFS", sizeof(dkw->dkw_parent)); - + dkw->dkw_offset = 0; - dkw->dkw_size = zv->zv_volsize / DEV_BSIZE; + dkw->dkw_size = dg->dg_secperunit; strcpy(dkw->dkw_ptype, DKW_PTYPE_FFS); break; } + case DIOCGPARTINFO: + { + struct partinfo *pi = (void *) arg; + struct disk_geom *dg = &zv->zv_dk.dk_geom; + + memset(pi, 0, sizeof(*pi)); + pi->pi_offset = 0; + pi->pi_secsize = dg->dg_secsize; + pi->pi_size = dg->dg_secperunit; + pi->pi_fstype = FS_OTHER; + pi->pi_bsize = MAX(BLKDEV_IOSIZE, pi->pi_secsize); + + break; + } + default: dprintf("unknown disk_ioctl called\n"); error = ENOTTY;