diff mbox series

block: Fix partition support for host aware zoned block devices

Message ID 20200219042632.819101-1-shinichiro.kawasaki@wdc.com (mailing list archive)
State New, archived
Headers show
Series block: Fix partition support for host aware zoned block devices | expand

Commit Message

Shinichiro Kawasaki Feb. 19, 2020, 4:26 a.m. UTC
Commit b72053072c0b ("block: allow partitions on host aware zone
devices") introduced the helper function disk_has_partitions() to check
if a given disk has valid partitions. However, since this function result
directly depends on the disk partition table length rather than the
actual existence of valid partitions in the table, it returns true even
after all partitions are removed from the disk. For host aware zoned
block devices, this results in zone management support to be kept
disabled even after removing all partitions.

Fix this by changing disk_has_partitions() to walk through the partition
table entries and return true if and only if a valid non-zero size
partition is found.

Fixes: b72053072c0b ("block: allow partitions on host aware zone devices")
Cc: stable@vger.kernel.org # 5.5
Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
---
 block/genhd.c         | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/genhd.h | 13 +------------
 2 files changed, 37 insertions(+), 12 deletions(-)

Comments

Damien Le Moal Feb. 19, 2020, 8:37 a.m. UTC | #1
On 2020/02/19 13:26, Shin'ichiro Kawasaki wrote:
> Commit b72053072c0b ("block: allow partitions on host aware zone
> devices") introduced the helper function disk_has_partitions() to check
> if a given disk has valid partitions. However, since this function result
> directly depends on the disk partition table length rather than the
> actual existence of valid partitions in the table, it returns true even
> after all partitions are removed from the disk. For host aware zoned
> block devices, this results in zone management support to be kept
> disabled even after removing all partitions.
> 
> Fix this by changing disk_has_partitions() to walk through the partition
> table entries and return true if and only if a valid non-zero size
> partition is found.
> 
> Fixes: b72053072c0b ("block: allow partitions on host aware zone devices")
> Cc: stable@vger.kernel.org # 5.5
> Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>

Looks good to me.

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>


> ---
>  block/genhd.c         | 36 ++++++++++++++++++++++++++++++++++++
>  include/linux/genhd.h | 13 +------------
>  2 files changed, 37 insertions(+), 12 deletions(-)
> 
> diff --git a/block/genhd.c b/block/genhd.c
> index ff6268970ddc..ed8cdebc2cf0 100644
> --- a/block/genhd.c
> +++ b/block/genhd.c
> @@ -301,6 +301,42 @@ struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
>  }
>  EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
>  
> +/**
> + * disk_has_partitions
> + * @disk: gendisk of interest
> + *
> + * Walk through the partition table and check if valid partition exists.
> + *
> + * CONTEXT:
> + * Don't care.
> + *
> + * RETURNS:
> + * True if the gendisk has at least one valid non-zero size partition.
> + * Otherwise false.
> + */
> +bool disk_has_partitions(struct gendisk *disk)
> +{
> +	struct disk_part_tbl *ptbl;
> +	int i;
> +	bool ret = false;
> +
> +	rcu_read_lock();
> +	ptbl = rcu_dereference(disk->part_tbl);
> +
> +	/* Iterate partitions skipping the holder device at index 0 */
> +	for (i = 1; i < ptbl->len; i++) {
> +		if (rcu_dereference(ptbl->part[i])) {
> +			ret = true;
> +			break;
> +		}
> +	}
> +
> +	rcu_read_unlock();
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(disk_has_partitions);
> +
>  /*
>   * Can be deleted altogether. Later.
>   *
> diff --git a/include/linux/genhd.h b/include/linux/genhd.h
> index 6fbe58538ad6..f1b5c86b096a 100644
> --- a/include/linux/genhd.h
> +++ b/include/linux/genhd.h
> @@ -245,18 +245,6 @@ static inline bool disk_part_scan_enabled(struct gendisk *disk)
>  		!(disk->flags & GENHD_FL_NO_PART_SCAN);
>  }
>  
> -static inline bool disk_has_partitions(struct gendisk *disk)
> -{
> -	bool ret = false;
> -
> -	rcu_read_lock();
> -	if (rcu_dereference(disk->part_tbl)->len > 1)
> -		ret = true;
> -	rcu_read_unlock();
> -
> -	return ret;
> -}
> -
>  static inline dev_t disk_devt(struct gendisk *disk)
>  {
>  	return MKDEV(disk->major, disk->first_minor);
> @@ -298,6 +286,7 @@ extern void disk_part_iter_exit(struct disk_part_iter *piter);
>  
>  extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
>  					     sector_t sector);
> +extern bool disk_has_partitions(struct gendisk *disk);
>  
>  /*
>   * Macros to operate on percpu disk statistics:
>
Christoph Hellwig Feb. 19, 2020, 4:28 p.m. UTC | #2
On Wed, Feb 19, 2020 at 01:26:32PM +0900, Shin'ichiro Kawasaki wrote:
> +	/* Iterate partitions skipping the holder device at index 0 */

s/holder/whole/ ?

> +extern bool disk_has_partitions(struct gendisk *disk);

No need for externs on function prototypes in headers.
Shinichiro Kawasaki Feb. 20, 2020, 8:36 a.m. UTC | #3
On Feb 19, 2020 / 08:28, Christoph Hellwig wrote:
> On Wed, Feb 19, 2020 at 01:26:32PM +0900, Shin'ichiro Kawasaki wrote:
> > +	/* Iterate partitions skipping the holder device at index 0 */
> 
> s/holder/whole/ ?

Ok, 'whole device' sounds more natural.

> 
> > +extern bool disk_has_partitions(struct gendisk *disk);
> 
> No need for externs on function prototypes in headers.

Thanks. I found that coding-style.rst says "Do not use the extern keyword with
function prototypes".

Will reflect to the v2 patch.

--
Best Regards,
Shin'ichiro Kawasaki
diff mbox series

Patch

diff --git a/block/genhd.c b/block/genhd.c
index ff6268970ddc..ed8cdebc2cf0 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -301,6 +301,42 @@  struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
 }
 EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
 
+/**
+ * disk_has_partitions
+ * @disk: gendisk of interest
+ *
+ * Walk through the partition table and check if valid partition exists.
+ *
+ * CONTEXT:
+ * Don't care.
+ *
+ * RETURNS:
+ * True if the gendisk has at least one valid non-zero size partition.
+ * Otherwise false.
+ */
+bool disk_has_partitions(struct gendisk *disk)
+{
+	struct disk_part_tbl *ptbl;
+	int i;
+	bool ret = false;
+
+	rcu_read_lock();
+	ptbl = rcu_dereference(disk->part_tbl);
+
+	/* Iterate partitions skipping the holder device at index 0 */
+	for (i = 1; i < ptbl->len; i++) {
+		if (rcu_dereference(ptbl->part[i])) {
+			ret = true;
+			break;
+		}
+	}
+
+	rcu_read_unlock();
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(disk_has_partitions);
+
 /*
  * Can be deleted altogether. Later.
  *
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 6fbe58538ad6..f1b5c86b096a 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -245,18 +245,6 @@  static inline bool disk_part_scan_enabled(struct gendisk *disk)
 		!(disk->flags & GENHD_FL_NO_PART_SCAN);
 }
 
-static inline bool disk_has_partitions(struct gendisk *disk)
-{
-	bool ret = false;
-
-	rcu_read_lock();
-	if (rcu_dereference(disk->part_tbl)->len > 1)
-		ret = true;
-	rcu_read_unlock();
-
-	return ret;
-}
-
 static inline dev_t disk_devt(struct gendisk *disk)
 {
 	return MKDEV(disk->major, disk->first_minor);
@@ -298,6 +286,7 @@  extern void disk_part_iter_exit(struct disk_part_iter *piter);
 
 extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
 					     sector_t sector);
+extern bool disk_has_partitions(struct gendisk *disk);
 
 /*
  * Macros to operate on percpu disk statistics: