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

Reply via email to