diff mbox series

[09/30] mtd_blkdevs: use blk_mq_alloc_disk

Message ID 20210602065345.355274-10-hch@lst.de
State New
Headers show
Series None | expand

Commit Message

Christoph Hellwig June 2, 2021, 6:53 a.m. UTC
Use the blk_mq_alloc_disk API to simplify the gendisk and request_queue
allocation.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 drivers/mtd/mtd_blkdevs.c | 48 ++++++++++++++++++---------------------
 1 file changed, 22 insertions(+), 26 deletions(-)

Comments

Marek Szyprowski June 15, 2021, 3:47 p.m. UTC | #1
Hi,

On 02.06.2021 08:53, Christoph Hellwig wrote:
> Use the blk_mq_alloc_disk API to simplify the gendisk and request_queue

> allocation.

>

> Signed-off-by: Christoph Hellwig <hch@lst.de>


This patch landed in linux-next as commit 6966bb921def ("mtd_blkdevs: 
use blk_mq_alloc_disk"). It causes the following regression on my QEMU 
arm64 setup:

  Using buffer write method
  Concatenating MTD devices:
  (0): "0.flash"
  (1): "0.flash"
  into device "0.flash"
  Unable to handle kernel NULL pointer dereference at virtual address 
0000000000000068
  Mem abort info:
    ESR = 0x96000004
    EC = 0x25: DABT (current EL), IL = 32 bits
    SET = 0, FnV = 0
    EA = 0, S1PTW = 0
  Data abort info:
    ISV = 0, ISS = 0x00000004
    CM = 0, WnR = 0
  [0000000000000068] user address but active_mm is swapper
  Internal error: Oops: 96000004 [#1] PREEMPT SMP
  Modules linked in:
  CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.13.0-rc3+ #10492
  Hardware name: linux,dummy-virt (DT)
  pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--)
  pc : blk_finish_plug+0x5c/0x268
  lr : blk_queue_write_cache+0x28/0x70
...
  Call trace:
   blk_finish_plug+0x5c/0x268
   add_mtd_blktrans_dev+0x270/0x420
   mtdblock_add_mtd+0x68/0x98
   blktrans_notify_add+0x44/0x70
   add_mtd_device+0x41c/0x490
   mtd_device_parse_register+0xf4/0x1c8
   physmap_flash_probe+0x44c/0x780
   platform_probe+0x90/0xd8
   really_probe+0x108/0x3c0
   driver_probe_device+0x60/0xc0
   device_driver_attach+0x6c/0x78
   __driver_attach+0xc0/0x100
   bus_for_each_dev+0x68/0xc8
   driver_attach+0x20/0x28
   bus_add_driver+0x168/0x1f8
   driver_register+0x60/0x110
   __platform_driver_register+0x24/0x30
   physmap_init+0x18/0x20
   do_one_initcall+0x84/0x450
   kernel_init_freeable+0x2dc/0x334
   kernel_init+0x10/0x110
   ret_from_fork+0x10/0x18
  Code: 88027c01 35ffffa2 17fff079 f9800031 (c85f7c22)
  ---[ end trace b774518e0766cc92 ]---
  Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
  SMP: stopping secondary CPUs
  Kernel Offset: 0x594d1fa00000 from 0xffff800010000000
  PHYS_OFFSET: 0xffffea7300000000
  CPU features: 0x11000671,00000846
  Memory Limit: none
  ---[ end Kernel panic - not syncing: Attempted to kill init! 
exitcode=0x0000000b ]---

> ---

>   drivers/mtd/mtd_blkdevs.c | 48 ++++++++++++++++++---------------------

>   1 file changed, 22 insertions(+), 26 deletions(-)

>

> diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c

> index fb8e12d590a1..5dc4c966ea73 100644

> --- a/drivers/mtd/mtd_blkdevs.c

> +++ b/drivers/mtd/mtd_blkdevs.c

> @@ -30,11 +30,9 @@ static void blktrans_dev_release(struct kref *kref)

>   	struct mtd_blktrans_dev *dev =

>   		container_of(kref, struct mtd_blktrans_dev, ref);

>   

> -	dev->disk->private_data = NULL;

> -	blk_cleanup_queue(dev->rq);

> +	blk_cleanup_disk(dev->disk);

>   	blk_mq_free_tag_set(dev->tag_set);

>   	kfree(dev->tag_set);

> -	put_disk(dev->disk);

>   	list_del(&dev->list);

>   	kfree(dev);

>   }

> @@ -354,7 +352,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)

>   	if (new->devnum > (MINORMASK >> tr->part_bits) ||

>   	    (tr->part_bits && new->devnum >= 27 * 26)) {

>   		mutex_unlock(&blktrans_ref_mutex);

> -		goto error1;

> +		return ret;

>   	}

>   

>   	list_add_tail(&new->list, &tr->devs);

> @@ -366,17 +364,28 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)

>   	if (!tr->writesect)

>   		new->readonly = 1;

>   

> -	/* Create gendisk */

>   	ret = -ENOMEM;

> -	gd = alloc_disk(1 << tr->part_bits);

> +	new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);

> +	if (!new->tag_set)

> +		goto out_list_del;

>   

> -	if (!gd)

> -		goto error2;

> +	ret = blk_mq_alloc_sq_tag_set(new->tag_set, &mtd_mq_ops, 2,

> +			BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);

> +	if (ret)

> +		goto out_kfree_tag_set;

> +

> +	/* Create gendisk */

> +	gd = blk_mq_alloc_disk(new->tag_set, new);

> +	if (IS_ERR(gd)) {

> +		ret = PTR_ERR(gd);

> +		goto out_free_tag_set;

> +	}

>   

>   	new->disk = gd;

>   	gd->private_data = new;

>   	gd->major = tr->major;

>   	gd->first_minor = (new->devnum) << tr->part_bits;

> +	gd->minors = 1 << tr->part_bits;

>   	gd->fops = &mtd_block_ops;

>   

>   	if (tr->part_bits)

> @@ -398,22 +407,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)

>   	spin_lock_init(&new->queue_lock);

>   	INIT_LIST_HEAD(&new->rq_list);

>   

> -	new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);

> -	if (!new->tag_set)

> -		goto error3;

> -

> -	new->rq = blk_mq_init_sq_queue(new->tag_set, &mtd_mq_ops, 2,

> -				BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);

> -	if (IS_ERR(new->rq)) {

> -		ret = PTR_ERR(new->rq);

> -		new->rq = NULL;

> -		goto error4;

> -	}

> -

>   	if (tr->flush)

>   		blk_queue_write_cache(new->rq, true, false);

>   

> -	new->rq->queuedata = new;

>   	blk_queue_logical_block_size(new->rq, tr->blksize);

>   

>   	blk_queue_flag_set(QUEUE_FLAG_NONROT, new->rq);

> @@ -437,13 +433,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)

>   		WARN_ON(ret);

>   	}

>   	return 0;

> -error4:

> +

> +out_free_tag_set:

> +	blk_mq_free_tag_set(new->tag_set);

> +out_kfree_tag_set:

>   	kfree(new->tag_set);

> -error3:

> -	put_disk(new->disk);

> -error2:

> +out_list_del:

>   	list_del(&new->list);

> -error1:

>   	return ret;

>   }

>   


Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland
Christoph Hellwig June 15, 2021, 3:58 p.m. UTC | #2
On Tue, Jun 15, 2021 at 05:47:44PM +0200, Marek Szyprowski wrote:
> Hi,

> 

> On 02.06.2021 08:53, Christoph Hellwig wrote:

> > Use the blk_mq_alloc_disk API to simplify the gendisk and request_queue

> > allocation.

> >

> > Signed-off-by: Christoph Hellwig <hch@lst.de>

> 

> This patch landed in linux-next as commit 6966bb921def ("mtd_blkdevs: 

> use blk_mq_alloc_disk"). It causes the following regression on my QEMU 

> arm64 setup:


Please try the patch below:

diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 5dc4c966ea73..6ce4bc57f919 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -382,6 +382,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 	}
 
 	new->disk = gd;
+	new->rq = new->disk->queue;
 	gd->private_data = new;
 	gd->major = tr->major;
 	gd->first_minor = (new->devnum) << tr->part_bits;
Marek Szyprowski June 15, 2021, 4:28 p.m. UTC | #3
Hi Christoph,

On 15.06.2021 17:58, Christoph Hellwig wrote:
> On Tue, Jun 15, 2021 at 05:47:44PM +0200, Marek Szyprowski wrote:

>> On 02.06.2021 08:53, Christoph Hellwig wrote:

>>> Use the blk_mq_alloc_disk API to simplify the gendisk and request_queue

>>> allocation.

>>>

>>> Signed-off-by: Christoph Hellwig <hch@lst.de>

>> This patch landed in linux-next as commit 6966bb921def ("mtd_blkdevs:

>> use blk_mq_alloc_disk"). It causes the following regression on my QEMU

>> arm64 setup:

> Please try the patch below:

>

> diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c

> index 5dc4c966ea73..6ce4bc57f919 100644

> --- a/drivers/mtd/mtd_blkdevs.c

> +++ b/drivers/mtd/mtd_blkdevs.c

> @@ -382,6 +382,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)

>   	}

>   

>   	new->disk = gd;

> +	new->rq = new->disk->queue;

>   	gd->private_data = new;

>   	gd->major = tr->major;

>   	gd->first_minor = (new->devnum) << tr->part_bits;


Right, this fixes the issue, thanks. Feel free to add:

Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>


Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland
diff mbox series

Patch

diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index fb8e12d590a1..5dc4c966ea73 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -30,11 +30,9 @@  static void blktrans_dev_release(struct kref *kref)
 	struct mtd_blktrans_dev *dev =
 		container_of(kref, struct mtd_blktrans_dev, ref);
 
-	dev->disk->private_data = NULL;
-	blk_cleanup_queue(dev->rq);
+	blk_cleanup_disk(dev->disk);
 	blk_mq_free_tag_set(dev->tag_set);
 	kfree(dev->tag_set);
-	put_disk(dev->disk);
 	list_del(&dev->list);
 	kfree(dev);
 }
@@ -354,7 +352,7 @@  int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 	if (new->devnum > (MINORMASK >> tr->part_bits) ||
 	    (tr->part_bits && new->devnum >= 27 * 26)) {
 		mutex_unlock(&blktrans_ref_mutex);
-		goto error1;
+		return ret;
 	}
 
 	list_add_tail(&new->list, &tr->devs);
@@ -366,17 +364,28 @@  int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 	if (!tr->writesect)
 		new->readonly = 1;
 
-	/* Create gendisk */
 	ret = -ENOMEM;
-	gd = alloc_disk(1 << tr->part_bits);
+	new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);
+	if (!new->tag_set)
+		goto out_list_del;
 
-	if (!gd)
-		goto error2;
+	ret = blk_mq_alloc_sq_tag_set(new->tag_set, &mtd_mq_ops, 2,
+			BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
+	if (ret)
+		goto out_kfree_tag_set;
+
+	/* Create gendisk */
+	gd = blk_mq_alloc_disk(new->tag_set, new);
+	if (IS_ERR(gd)) {
+		ret = PTR_ERR(gd);
+		goto out_free_tag_set;
+	}
 
 	new->disk = gd;
 	gd->private_data = new;
 	gd->major = tr->major;
 	gd->first_minor = (new->devnum) << tr->part_bits;
+	gd->minors = 1 << tr->part_bits;
 	gd->fops = &mtd_block_ops;
 
 	if (tr->part_bits)
@@ -398,22 +407,9 @@  int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 	spin_lock_init(&new->queue_lock);
 	INIT_LIST_HEAD(&new->rq_list);
 
-	new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);
-	if (!new->tag_set)
-		goto error3;
-
-	new->rq = blk_mq_init_sq_queue(new->tag_set, &mtd_mq_ops, 2,
-				BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
-	if (IS_ERR(new->rq)) {
-		ret = PTR_ERR(new->rq);
-		new->rq = NULL;
-		goto error4;
-	}
-
 	if (tr->flush)
 		blk_queue_write_cache(new->rq, true, false);
 
-	new->rq->queuedata = new;
 	blk_queue_logical_block_size(new->rq, tr->blksize);
 
 	blk_queue_flag_set(QUEUE_FLAG_NONROT, new->rq);
@@ -437,13 +433,13 @@  int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 		WARN_ON(ret);
 	}
 	return 0;
-error4:
+
+out_free_tag_set:
+	blk_mq_free_tag_set(new->tag_set);
+out_kfree_tag_set:
 	kfree(new->tag_set);
-error3:
-	put_disk(new->disk);
-error2:
+out_list_del:
 	list_del(&new->list);
-error1:
 	return ret;
 }