On 12/01/2016 07:25 AM, Damien Le Moal wrote: > Both blkdev_report_zones and blkdev_reset_zones can operate on a partition of > a zoned block device. However, the first and last zones reported for a > partition make sense only if the partition start sector and size are aligned > on the device zone size. The same applies for zone reset. Resetting the first > or the last zone of a partition straddling zones may impact neighboring > partitions. Finally, if a partition start sector is not at the beginning of a > sequential zone, it will be impossible to write to the first sectors of the > partition on a host-managed device. > Avoid all these problems and incoherencies by ignoring partitions that are not > zone aligned. > > Note: If CONFIG_BLK_DEV_ZONED is disabled, bdev_is_zoned() will still report > the correct disk zoning type (host-aware, host-managed or none) but > bdev_zone_size() will always return 0 for zoned block devices (i.e. the zone > size is unknown). So test this as a way to ensure that a zoned block device is > being handled as such. As a result, for a host-aware devices, unaligned zone > partitions will be accepted with CONFIG_BLK_DEV_ZONED disabled. That is, the > disk will be treated as a regular block device (as it should). If zoned block > device support is enabled, only aligned partitions will be accepted. > > Signed-off-by: Damien Le Moal <damien.lemoal@xxxxxxx> > --- > block/partition-generic.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 66 insertions(+) > > diff --git a/block/partition-generic.c b/block/partition-generic.c > index 71d9ed9..a60ac7f 100644 > --- a/block/partition-generic.c > +++ b/block/partition-generic.c > @@ -430,6 +430,57 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev) > return 0; > } > > +static bool part_zone_aligned(struct gendisk *disk, > + struct block_device *bdev, > + sector_t from, sector_t size) > +{ > + unsigned int zone_size = bdev_zone_size(bdev); > + > + /* > + * If this function is called, then the disk is a zoned block device > + * (host-aware or host-managed). This can be detected even if the > + * zoned block device support is disabled (CONFIG_BLK_DEV_ZONED not > + * set). In this case, however, only host-aware devices will be seen > + * as a block device is not created for host-managed devices. Without > + * zoned block device support, host-aware drives can still be used as > + * regular block devices (no zone operation) and their zone size will > + * be reported as 0. Allow this case. > + */ > + if (!zone_size) > + return true; > + > + /* > + * Check partition start and size alignement. If the drive has a > + * smaller last runt zone, ignore it and allow the partition to > + * use it. Check the zone size too: it should be a power of 2 number > + * of sectors. > + */ > + WARN_ON_ONCE(!is_power_of_2(zone_size)); > + if (!is_power_of_2(zone_size)) { Can be merged into 'if (WARN_ON_ONCE(! ...' > + u32 rem; > + > + div_u64_rem(from, zone_size, &rem); > + if (rem) > + return false; > + if ((from + size) < get_capacity(disk)) { > + div_u64_rem(size, zone_size, &rem); > + if (rem) > + return false; > + } > + > + } else { > + > + if (from & (zone_size - 1)) > + return false; > + if ((from + size) < get_capacity(disk) && > + (size & (zone_size - 1))) > + return false; > + > + } > + > + return true; > +} > + > int rescan_partitions(struct gendisk *disk, struct block_device *bdev) > { > struct parsed_partitions *state = NULL; > @@ -529,6 +580,21 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) > } > } > > + /* > + * On a zoned block device, partitions should be aligned on the > + * device zone size (i.e. zone boundary crossing not allowed). > + * Otherwise, resetting the write pointer of the last zone of > + * one partition may impact the following partition. > + */ > + if (bdev_is_zoned(bdev) && > + !part_zone_aligned(disk, bdev, from, size)) { > + printk(KERN_WARNING > + "%s: p%d start %llu+%llu is not zone aligned\n", > + disk->disk_name, p, (unsigned long long) from, > + (unsigned long long) size); > + continue; > + } > + > part = add_partition(disk, p, from, size, > state->parts[p].flags, > &state->parts[p].info); > Otherwise looks good. Reviewed-by: Hannes Reinecke <hare@xxxxxxxx> Cheers, Hannes -- Dr. Hannes Reinecke Teamlead Storage & Networking hare@xxxxxxx +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton HRB 21284 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-block" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html