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 <[email protected]>
> ---
> 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 <[email protected]>
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
[email protected] +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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html