diff mbox series

[PATCHv2] virtio_mmio: fix devm cleanup

Message ID 20171212134550.18378-1-mark.rutland@arm.com
State Accepted
Commit c2e90800aef22e7ea14ea7560ba99993f11d3616
Headers show
Series [PATCHv2] virtio_mmio: fix devm cleanup | expand

Commit Message

Mark Rutland Dec. 12, 2017, 1:45 p.m. UTC
Recent rework of the virtio_mmio probe/remove paths balanced a
devm_ioremap() with an iounmap() rather than its devm variant. This ends
up corrupting the devm datastructures, and results in the following
boot-time splat on arm64 under QEMU 2.9.0:

[    3.450397] ------------[ cut here ]------------
[    3.453822] Trying to vfree() nonexistent vm area (00000000c05b4844)
[    3.460534] WARNING: CPU: 1 PID: 1 at mm/vmalloc.c:1525 __vunmap+0x1b8/0x220
[    3.475898] Kernel panic - not syncing: panic_on_warn set ...
[    3.475898]
[    3.493933] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc3 #1
[    3.513109] Hardware name: linux,dummy-virt (DT)
[    3.525382] Call trace:
[    3.531683]  dump_backtrace+0x0/0x368
[    3.543921]  show_stack+0x20/0x30
[    3.547767]  dump_stack+0x108/0x164
[    3.559584]  panic+0x25c/0x51c
[    3.569184]  __warn+0x29c/0x31c
[    3.576023]  report_bug+0x1d4/0x290
[    3.586069]  bug_handler.part.2+0x40/0x100
[    3.597820]  bug_handler+0x4c/0x88
[    3.608400]  brk_handler+0x11c/0x218
[    3.613430]  do_debug_exception+0xe8/0x318
[    3.627370]  el1_dbg+0x18/0x78
[    3.634037]  __vunmap+0x1b8/0x220
[    3.648747]  vunmap+0x6c/0xc0
[    3.653864]  __iounmap+0x44/0x58
[    3.659771]  devm_ioremap_release+0x34/0x68
[    3.672983]  release_nodes+0x404/0x880
[    3.683543]  devres_release_all+0x6c/0xe8
[    3.695692]  driver_probe_device+0x250/0x828
[    3.706187]  __driver_attach+0x190/0x210
[    3.717645]  bus_for_each_dev+0x14c/0x1f0
[    3.728633]  driver_attach+0x48/0x78
[    3.740249]  bus_add_driver+0x26c/0x5b8
[    3.752248]  driver_register+0x16c/0x398
[    3.757211]  __platform_driver_register+0xd8/0x128
[    3.770860]  virtio_mmio_init+0x1c/0x24
[    3.782671]  do_one_initcall+0xe0/0x398
[    3.791890]  kernel_init_freeable+0x594/0x660
[    3.798514]  kernel_init+0x18/0x190
[    3.810220]  ret_from_fork+0x10/0x18

To fix this, we can simply rip out the explicit cleanup that the devm
infrastructure will do for us when our probe function returns an error
code, or when our remove function returns.

We only need to ensure that we call put_device() if a call to
register_virtio_device() fails in the probe path.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>

Fixes: 7eb781b1bbb7136f ("virtio_mmio: add cleanup for virtio_mmio_probe")
Fixes: 25f32223bce5c580 ("virtio_mmio: add cleanup for virtio_mmio_remove")
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: weiping zhang <zhangweiping@didichuxing.com>
Cc: virtualization@lists.linux-foundation.org
---
 drivers/virtio/virtio_mmio.c | 43 +++++++++----------------------------------
 1 file changed, 9 insertions(+), 34 deletions(-)

Since v1 [1]:
* Fix cleanup in virtio_mmio_remove

Mark.

[1] https://lkml.kernel.org/r/20171212125302.6846-1-mark.rutland@arm.com

-- 
2.11.0

Comments

weiping zhang Dec. 12, 2017, 2:26 p.m. UTC | #1
2017-12-12 21:45 GMT+08:00 Mark Rutland <mark.rutland@arm.com>:
> Recent rework of the virtio_mmio probe/remove paths balanced a

> devm_ioremap() with an iounmap() rather than its devm variant. This ends

> up corrupting the devm datastructures, and results in the following

> boot-time splat on arm64 under QEMU 2.9.0:

>

> [    3.450397] ------------[ cut here ]------------

> [    3.453822] Trying to vfree() nonexistent vm area (00000000c05b4844)

> [    3.460534] WARNING: CPU: 1 PID: 1 at mm/vmalloc.c:1525 __vunmap+0x1b8/0x220

> [    3.475898] Kernel panic - not syncing: panic_on_warn set ...

> [    3.475898]

> [    3.493933] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc3 #1

> [    3.513109] Hardware name: linux,dummy-virt (DT)

> [    3.525382] Call trace:

> [    3.531683]  dump_backtrace+0x0/0x368

> [    3.543921]  show_stack+0x20/0x30

> [    3.547767]  dump_stack+0x108/0x164

> [    3.559584]  panic+0x25c/0x51c

> [    3.569184]  __warn+0x29c/0x31c

> [    3.576023]  report_bug+0x1d4/0x290

> [    3.586069]  bug_handler.part.2+0x40/0x100

> [    3.597820]  bug_handler+0x4c/0x88

> [    3.608400]  brk_handler+0x11c/0x218

> [    3.613430]  do_debug_exception+0xe8/0x318

> [    3.627370]  el1_dbg+0x18/0x78

> [    3.634037]  __vunmap+0x1b8/0x220

> [    3.648747]  vunmap+0x6c/0xc0

> [    3.653864]  __iounmap+0x44/0x58

> [    3.659771]  devm_ioremap_release+0x34/0x68

> [    3.672983]  release_nodes+0x404/0x880

> [    3.683543]  devres_release_all+0x6c/0xe8

> [    3.695692]  driver_probe_device+0x250/0x828

> [    3.706187]  __driver_attach+0x190/0x210

> [    3.717645]  bus_for_each_dev+0x14c/0x1f0

> [    3.728633]  driver_attach+0x48/0x78

> [    3.740249]  bus_add_driver+0x26c/0x5b8

> [    3.752248]  driver_register+0x16c/0x398

> [    3.757211]  __platform_driver_register+0xd8/0x128

> [    3.770860]  virtio_mmio_init+0x1c/0x24

> [    3.782671]  do_one_initcall+0xe0/0x398

> [    3.791890]  kernel_init_freeable+0x594/0x660

> [    3.798514]  kernel_init+0x18/0x190

> [    3.810220]  ret_from_fork+0x10/0x18

>

> To fix this, we can simply rip out the explicit cleanup that the devm

> infrastructure will do for us when our probe function returns an error

> code, or when our remove function returns.

>

> We only need to ensure that we call put_device() if a call to

> register_virtio_device() fails in the probe path.

>

> Signed-off-by: Mark Rutland <mark.rutland@arm.com>

> Fixes: 7eb781b1bbb7136f ("virtio_mmio: add cleanup for virtio_mmio_probe")

> Fixes: 25f32223bce5c580 ("virtio_mmio: add cleanup for virtio_mmio_remove")

> Cc: Cornelia Huck <cohuck@redhat.com>

> Cc: Michael S. Tsirkin <mst@redhat.com>

> Cc: weiping zhang <zhangweiping@didichuxing.com>

> Cc: virtualization@lists.linux-foundation.org

> ---

>  drivers/virtio/virtio_mmio.c | 43 +++++++++----------------------------------

>  1 file changed, 9 insertions(+), 34 deletions(-)

>

> Since v1 [1]:

> * Fix cleanup in virtio_mmio_remove

>

> Mark.

>

> [1] https://lkml.kernel.org/r/20171212125302.6846-1-mark.rutland@arm.com

>

> diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c

> index a9192fe4f345..c92131edfaba 100644

> --- a/drivers/virtio/virtio_mmio.c

> +++ b/drivers/virtio/virtio_mmio.c

> @@ -522,10 +522,8 @@ static int virtio_mmio_probe(struct platform_device *pdev)

>                 return -EBUSY;

>

>         vm_dev = devm_kzalloc(&pdev->dev, sizeof(*vm_dev), GFP_KERNEL);

> -       if (!vm_dev) {

> -               rc = -ENOMEM;

> -               goto free_mem;

> -       }

> +       if (!vm_dev)

> +               return -ENOMEM;

>

>         vm_dev->vdev.dev.parent = &pdev->dev;

>         vm_dev->vdev.dev.release = virtio_mmio_release_dev;

> @@ -535,17 +533,14 @@ static int virtio_mmio_probe(struct platform_device *pdev)

>         spin_lock_init(&vm_dev->lock);

>

>         vm_dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));

> -       if (vm_dev->base == NULL) {

> -               rc = -EFAULT;

> -               goto free_vmdev;

> -       }

> +       if (vm_dev->base == NULL)

> +               return -EFAULT;

>

>         /* Check magic value */

>         magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE);

>         if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {

>                 dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic);

> -               rc = -ENODEV;

> -               goto unmap;

> +               return -ENODEV;

>         }

>

>         /* Check device version */

> @@ -553,8 +548,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)

>         if (vm_dev->version < 1 || vm_dev->version > 2) {

>                 dev_err(&pdev->dev, "Version %ld not supported!\n",

>                                 vm_dev->version);

> -               rc = -ENXIO;

> -               goto unmap;

> +               return -ENXIO;

>         }

>

>         vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);

> @@ -563,8 +557,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)

>                  * virtio-mmio device with an ID 0 is a (dummy) placeholder

>                  * with no function. End probing now with no error reported.

>                  */

> -               rc = -ENODEV;

> -               goto unmap;

> +               return -ENODEV;

>         }

>         vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);

>

> @@ -590,33 +583,15 @@ static int virtio_mmio_probe(struct platform_device *pdev)

>         platform_set_drvdata(pdev, vm_dev);

>

>         rc = register_virtio_device(&vm_dev->vdev);

> -       if (rc) {

> -               iounmap(vm_dev->base);

> -               devm_release_mem_region(&pdev->dev, mem->start,

> -                                       resource_size(mem));

> +       if (rc)

>                 put_device(&vm_dev->vdev.dev);

> -       }

> -       return rc;

> -unmap:

> -       iounmap(vm_dev->base);

> -free_mem:

> -       devm_release_mem_region(&pdev->dev, mem->start,

> -                       resource_size(mem));

> -free_vmdev:

> -       devm_kfree(&pdev->dev, vm_dev);

> +

>         return rc;

>  }

>

>  static int virtio_mmio_remove(struct platform_device *pdev)

>  {

>         struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev);

> -       struct resource *mem;

> -

> -       iounmap(vm_dev->base);

> -       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

> -       if (mem)

> -               devm_release_mem_region(&pdev->dev, mem->start,

> -                       resource_size(mem));

>         unregister_virtio_device(&vm_dev->vdev);

>

>         return 0;

> --

> 2.11.0

>

> _______________________________________________

> Virtualization mailing list

> Virtualization@lists.linux-foundation.org

> https://lists.linuxfoundation.org/mailman/listinfo/virtualization

Hi Mark,
thanks your patch, I dig into these three devm_xxx funciton,
all of them represented by a struct devres as following,

struct devres_node {
        struct list_head                entry;
        dr_release_t                    release;
#ifdef CONFIG_DEBUG_DEVRES
        const char                      *name;
        size_t                          size;
#endif

};

struct devres {
        struct devres_node              node;
        /* -- 3 pointers */
        unsigned long long              data[]; /* guarantee ull alignment */
};

1) devm_request_mem_region -> __devm_request_region

dr = devres_alloc(devm_region_release, sizeof(struct region_devres),
"devm_region_release" will call __release_region to release resource

2) devm_kzalloc -> devm_kmalloc

dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));
"devm_kmalloc_release" is noop, do nothing.

3) devm_ioremap -> ... -> __devres_alloc_node

ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
devm_ioremap_release do iounmap

so for case 2) above, we need a devm_kfree() before call register_virtio_device
Mark Rutland Dec. 12, 2017, 2:45 p.m. UTC | #2
On Tue, Dec 12, 2017 at 10:26:24PM +0800, weiping zhang wrote:
> 2017-12-12 21:45 GMT+08:00 Mark Rutland <mark.rutland@arm.com>:

> Hi Mark,


Hi,

> thanks your patch, I dig into these three devm_xxx funciton,

> all of them represented by a struct devres as following,

> 

> struct devres_node {

>         struct list_head                entry;

>         dr_release_t                    release;

> #ifdef CONFIG_DEBUG_DEVRES

>         const char                      *name;

>         size_t                          size;

> #endif

> 

> };

> 

> struct devres {

>         struct devres_node              node;

>         /* -- 3 pointers */

>         unsigned long long              data[]; /* guarantee ull alignment */

> };


> 2) devm_kzalloc -> devm_kmalloc

> 

> dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));

> "devm_kmalloc_release" is noop, do nothing.


Please note that the release function is there to perform cleanup prior
to the devm infrastructure releasing the memory.

The devm_kmalloc_release function is a no-op since nothing has to be
done prior to memory being freed, but the memory itself is still freed.

In alloc_dr(), the struct devres is allocated together with the memory,
since alloc_dr() does:

	size_t tot_size = sizeof(struct devres) + size; 
	struct devres *dr;

	dr = kmalloc_node_track_caller(tot_size, gfp, nid);

	return dr->data;

... where dr->data points at the memory after the struct devres.

Later, in release_nodes() we do:

	list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {
		devres_log(dev, &dr->node, "REL");
		dr->node.release(dev, dr->data);
		kfree(dr);
	}    

... which will invoke the no-op devm_kmalloc_release, then free the
devres allocation, including the dr->data memory the user requested.

> so for case 2) above, we need a devm_kfree() before call

> register_virtio_device


As above, I do not believe that is the case.

Thanks,
Mark.
weiping zhang Dec. 12, 2017, 3:04 p.m. UTC | #3
2017-12-12 22:45 GMT+08:00 Mark Rutland <mark.rutland@arm.com>:
> On Tue, Dec 12, 2017 at 10:26:24PM +0800, weiping zhang wrote:

>> 2017-12-12 21:45 GMT+08:00 Mark Rutland <mark.rutland@arm.com>:

>> Hi Mark,

>

> Hi,

>

>> thanks your patch, I dig into these three devm_xxx funciton,

>> all of them represented by a struct devres as following,

>>

>> struct devres_node {

>>         struct list_head                entry;

>>         dr_release_t                    release;

>> #ifdef CONFIG_DEBUG_DEVRES

>>         const char                      *name;

>>         size_t                          size;

>> #endif

>>

>> };

>>

>> struct devres {

>>         struct devres_node              node;

>>         /* -- 3 pointers */

>>         unsigned long long              data[]; /* guarantee ull alignment */

>> };

>

>> 2) devm_kzalloc -> devm_kmalloc

>>

>> dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));

>> "devm_kmalloc_release" is noop, do nothing.

>

> Please note that the release function is there to perform cleanup prior

> to the devm infrastructure releasing the memory.

>

> The devm_kmalloc_release function is a no-op since nothing has to be

> done prior to memory being freed, but the memory itself is still freed.

>

> In alloc_dr(), the struct devres is allocated together with the memory,

> since alloc_dr() does:

>

>         size_t tot_size = sizeof(struct devres) + size;

>         struct devres *dr;

>

>         dr = kmalloc_node_track_caller(tot_size, gfp, nid);

>

>         return dr->data;

>

> ... where dr->data points at the memory after the struct devres.

>

> Later, in release_nodes() we do:

>

>         list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {

>                 devres_log(dev, &dr->node, "REL");

>                 dr->node.release(dev, dr->data);

>                 kfree(dr);

>         }

>

> ... which will invoke the no-op devm_kmalloc_release, then free the

> devres allocation, including the dr->data memory the user requested.

>

>> so for case 2) above, we need a devm_kfree() before call

>> register_virtio_device

>

> As above, I do not believe that is the case.

>

Oh I see, thanks your detail explanation. Thanks a lot.
> Thanks,

> Mark.
Cornelia Huck Dec. 12, 2017, 5:02 p.m. UTC | #4
On Tue, 12 Dec 2017 13:45:50 +0000
Mark Rutland <mark.rutland@arm.com> wrote:

> Recent rework of the virtio_mmio probe/remove paths balanced a

> devm_ioremap() with an iounmap() rather than its devm variant. This ends

> up corrupting the devm datastructures, and results in the following

> boot-time splat on arm64 under QEMU 2.9.0:

> 

> [    3.450397] ------------[ cut here ]------------

> [    3.453822] Trying to vfree() nonexistent vm area (00000000c05b4844)

> [    3.460534] WARNING: CPU: 1 PID: 1 at mm/vmalloc.c:1525 __vunmap+0x1b8/0x220

> [    3.475898] Kernel panic - not syncing: panic_on_warn set ...

> [    3.475898]

> [    3.493933] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc3 #1

> [    3.513109] Hardware name: linux,dummy-virt (DT)

> [    3.525382] Call trace:

> [    3.531683]  dump_backtrace+0x0/0x368

> [    3.543921]  show_stack+0x20/0x30

> [    3.547767]  dump_stack+0x108/0x164

> [    3.559584]  panic+0x25c/0x51c

> [    3.569184]  __warn+0x29c/0x31c

> [    3.576023]  report_bug+0x1d4/0x290

> [    3.586069]  bug_handler.part.2+0x40/0x100

> [    3.597820]  bug_handler+0x4c/0x88

> [    3.608400]  brk_handler+0x11c/0x218

> [    3.613430]  do_debug_exception+0xe8/0x318

> [    3.627370]  el1_dbg+0x18/0x78

> [    3.634037]  __vunmap+0x1b8/0x220

> [    3.648747]  vunmap+0x6c/0xc0

> [    3.653864]  __iounmap+0x44/0x58

> [    3.659771]  devm_ioremap_release+0x34/0x68

> [    3.672983]  release_nodes+0x404/0x880

> [    3.683543]  devres_release_all+0x6c/0xe8

> [    3.695692]  driver_probe_device+0x250/0x828

> [    3.706187]  __driver_attach+0x190/0x210

> [    3.717645]  bus_for_each_dev+0x14c/0x1f0

> [    3.728633]  driver_attach+0x48/0x78

> [    3.740249]  bus_add_driver+0x26c/0x5b8

> [    3.752248]  driver_register+0x16c/0x398

> [    3.757211]  __platform_driver_register+0xd8/0x128

> [    3.770860]  virtio_mmio_init+0x1c/0x24

> [    3.782671]  do_one_initcall+0xe0/0x398

> [    3.791890]  kernel_init_freeable+0x594/0x660

> [    3.798514]  kernel_init+0x18/0x190

> [    3.810220]  ret_from_fork+0x10/0x18

> 

> To fix this, we can simply rip out the explicit cleanup that the devm

> infrastructure will do for us when our probe function returns an error

> code, or when our remove function returns.

> 

> We only need to ensure that we call put_device() if a call to

> register_virtio_device() fails in the probe path.

> 

> Signed-off-by: Mark Rutland <mark.rutland@arm.com>

> Fixes: 7eb781b1bbb7136f ("virtio_mmio: add cleanup for virtio_mmio_probe")

> Fixes: 25f32223bce5c580 ("virtio_mmio: add cleanup for virtio_mmio_remove")

> Cc: Cornelia Huck <cohuck@redhat.com>

> Cc: Michael S. Tsirkin <mst@redhat.com>

> Cc: weiping zhang <zhangweiping@didichuxing.com>

> Cc: virtualization@lists.linux-foundation.org

> ---

>  drivers/virtio/virtio_mmio.c | 43 +++++++++----------------------------------

>  1 file changed, 9 insertions(+), 34 deletions(-)


In the hope that I have grokked the devm_* interface by now,

Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Mark Rutland Dec. 13, 2017, 2:34 p.m. UTC | #5
On Tue, Dec 12, 2017 at 06:02:23PM +0100, Cornelia Huck wrote:
> On Tue, 12 Dec 2017 13:45:50 +0000

> Mark Rutland <mark.rutland@arm.com> wrote:

> 

> > Recent rework of the virtio_mmio probe/remove paths balanced a

> > devm_ioremap() with an iounmap() rather than its devm variant. This ends

> > up corrupting the devm datastructures, and results in the following

> > boot-time splat on arm64 under QEMU 2.9.0:

> > 

> > [    3.450397] ------------[ cut here ]------------

> > [    3.453822] Trying to vfree() nonexistent vm area (00000000c05b4844)

> > [    3.460534] WARNING: CPU: 1 PID: 1 at mm/vmalloc.c:1525 __vunmap+0x1b8/0x220

> > [    3.475898] Kernel panic - not syncing: panic_on_warn set ...

> > [    3.475898]

> > [    3.493933] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc3 #1

> > [    3.513109] Hardware name: linux,dummy-virt (DT)

> > [    3.525382] Call trace:

> > [    3.531683]  dump_backtrace+0x0/0x368

> > [    3.543921]  show_stack+0x20/0x30

> > [    3.547767]  dump_stack+0x108/0x164

> > [    3.559584]  panic+0x25c/0x51c

> > [    3.569184]  __warn+0x29c/0x31c

> > [    3.576023]  report_bug+0x1d4/0x290

> > [    3.586069]  bug_handler.part.2+0x40/0x100

> > [    3.597820]  bug_handler+0x4c/0x88

> > [    3.608400]  brk_handler+0x11c/0x218

> > [    3.613430]  do_debug_exception+0xe8/0x318

> > [    3.627370]  el1_dbg+0x18/0x78

> > [    3.634037]  __vunmap+0x1b8/0x220

> > [    3.648747]  vunmap+0x6c/0xc0

> > [    3.653864]  __iounmap+0x44/0x58

> > [    3.659771]  devm_ioremap_release+0x34/0x68

> > [    3.672983]  release_nodes+0x404/0x880

> > [    3.683543]  devres_release_all+0x6c/0xe8

> > [    3.695692]  driver_probe_device+0x250/0x828

> > [    3.706187]  __driver_attach+0x190/0x210

> > [    3.717645]  bus_for_each_dev+0x14c/0x1f0

> > [    3.728633]  driver_attach+0x48/0x78

> > [    3.740249]  bus_add_driver+0x26c/0x5b8

> > [    3.752248]  driver_register+0x16c/0x398

> > [    3.757211]  __platform_driver_register+0xd8/0x128

> > [    3.770860]  virtio_mmio_init+0x1c/0x24

> > [    3.782671]  do_one_initcall+0xe0/0x398

> > [    3.791890]  kernel_init_freeable+0x594/0x660

> > [    3.798514]  kernel_init+0x18/0x190

> > [    3.810220]  ret_from_fork+0x10/0x18

> > 

> > To fix this, we can simply rip out the explicit cleanup that the devm

> > infrastructure will do for us when our probe function returns an error

> > code, or when our remove function returns.

> > 

> > We only need to ensure that we call put_device() if a call to

> > register_virtio_device() fails in the probe path.

> > 

> > Signed-off-by: Mark Rutland <mark.rutland@arm.com>

> > Fixes: 7eb781b1bbb7136f ("virtio_mmio: add cleanup for virtio_mmio_probe")

> > Fixes: 25f32223bce5c580 ("virtio_mmio: add cleanup for virtio_mmio_remove")

> > Cc: Cornelia Huck <cohuck@redhat.com>

> > Cc: Michael S. Tsirkin <mst@redhat.com>

> > Cc: weiping zhang <zhangweiping@didichuxing.com>

> > Cc: virtualization@lists.linux-foundation.org

> > ---

> >  drivers/virtio/virtio_mmio.c | 43 +++++++++----------------------------------

> >  1 file changed, 9 insertions(+), 34 deletions(-)

> 

> In the hope that I have grokked the devm_* interface by now,

> 

> Reviewed-by: Cornelia Huck <cohuck@redhat.com>


Thanks!

Michael, could you please queue this as a fix for v4.15?

This regressed arm64 VMs booting between v4.15-rc1 and v4-15-rc2,
impacting our automated regression testing, and I'd very much like to
get back to testing pure mainline rather than mainline + local fixes.

Thanks,
Mark.
Michael S. Tsirkin Dec. 14, 2017, 6:48 p.m. UTC | #6
On Wed, Dec 13, 2017 at 02:34:14PM +0000, Mark Rutland wrote:
> On Tue, Dec 12, 2017 at 06:02:23PM +0100, Cornelia Huck wrote:

> > On Tue, 12 Dec 2017 13:45:50 +0000

> > Mark Rutland <mark.rutland@arm.com> wrote:

> > 

> > > Recent rework of the virtio_mmio probe/remove paths balanced a

> > > devm_ioremap() with an iounmap() rather than its devm variant. This ends

> > > up corrupting the devm datastructures, and results in the following

> > > boot-time splat on arm64 under QEMU 2.9.0:

> > > 

> > > [    3.450397] ------------[ cut here ]------------

> > > [    3.453822] Trying to vfree() nonexistent vm area (00000000c05b4844)

> > > [    3.460534] WARNING: CPU: 1 PID: 1 at mm/vmalloc.c:1525 __vunmap+0x1b8/0x220

> > > [    3.475898] Kernel panic - not syncing: panic_on_warn set ...

> > > [    3.475898]

> > > [    3.493933] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc3 #1

> > > [    3.513109] Hardware name: linux,dummy-virt (DT)

> > > [    3.525382] Call trace:

> > > [    3.531683]  dump_backtrace+0x0/0x368

> > > [    3.543921]  show_stack+0x20/0x30

> > > [    3.547767]  dump_stack+0x108/0x164

> > > [    3.559584]  panic+0x25c/0x51c

> > > [    3.569184]  __warn+0x29c/0x31c

> > > [    3.576023]  report_bug+0x1d4/0x290

> > > [    3.586069]  bug_handler.part.2+0x40/0x100

> > > [    3.597820]  bug_handler+0x4c/0x88

> > > [    3.608400]  brk_handler+0x11c/0x218

> > > [    3.613430]  do_debug_exception+0xe8/0x318

> > > [    3.627370]  el1_dbg+0x18/0x78

> > > [    3.634037]  __vunmap+0x1b8/0x220

> > > [    3.648747]  vunmap+0x6c/0xc0

> > > [    3.653864]  __iounmap+0x44/0x58

> > > [    3.659771]  devm_ioremap_release+0x34/0x68

> > > [    3.672983]  release_nodes+0x404/0x880

> > > [    3.683543]  devres_release_all+0x6c/0xe8

> > > [    3.695692]  driver_probe_device+0x250/0x828

> > > [    3.706187]  __driver_attach+0x190/0x210

> > > [    3.717645]  bus_for_each_dev+0x14c/0x1f0

> > > [    3.728633]  driver_attach+0x48/0x78

> > > [    3.740249]  bus_add_driver+0x26c/0x5b8

> > > [    3.752248]  driver_register+0x16c/0x398

> > > [    3.757211]  __platform_driver_register+0xd8/0x128

> > > [    3.770860]  virtio_mmio_init+0x1c/0x24

> > > [    3.782671]  do_one_initcall+0xe0/0x398

> > > [    3.791890]  kernel_init_freeable+0x594/0x660

> > > [    3.798514]  kernel_init+0x18/0x190

> > > [    3.810220]  ret_from_fork+0x10/0x18

> > > 

> > > To fix this, we can simply rip out the explicit cleanup that the devm

> > > infrastructure will do for us when our probe function returns an error

> > > code, or when our remove function returns.

> > > 

> > > We only need to ensure that we call put_device() if a call to

> > > register_virtio_device() fails in the probe path.

> > > 

> > > Signed-off-by: Mark Rutland <mark.rutland@arm.com>

> > > Fixes: 7eb781b1bbb7136f ("virtio_mmio: add cleanup for virtio_mmio_probe")

> > > Fixes: 25f32223bce5c580 ("virtio_mmio: add cleanup for virtio_mmio_remove")

> > > Cc: Cornelia Huck <cohuck@redhat.com>

> > > Cc: Michael S. Tsirkin <mst@redhat.com>

> > > Cc: weiping zhang <zhangweiping@didichuxing.com>

> > > Cc: virtualization@lists.linux-foundation.org

> > > ---

> > >  drivers/virtio/virtio_mmio.c | 43 +++++++++----------------------------------

> > >  1 file changed, 9 insertions(+), 34 deletions(-)

> > 

> > In the hope that I have grokked the devm_* interface by now,

> > 

> > Reviewed-by: Cornelia Huck <cohuck@redhat.com>

> 

> Thanks!

> 

> Michael, could you please queue this as a fix for v4.15?

> 

> This regressed arm64 VMs booting between v4.15-rc1 and v4-15-rc2,

> impacting our automated regression testing, and I'd very much like to

> get back to testing pure mainline rather than mainline + local fixes.

> 

> Thanks,

> Mark.


Yep, plan to.
Thanks!
weiping zhang Dec. 15, 2017, 1:48 a.m. UTC | #7
2017-12-15 2:48 GMT+08:00 Michael S. Tsirkin <mst@redhat.com>:
> On Wed, Dec 13, 2017 at 02:34:14PM +0000, Mark Rutland wrote:

>> On Tue, Dec 12, 2017 at 06:02:23PM +0100, Cornelia Huck wrote:

>> > On Tue, 12 Dec 2017 13:45:50 +0000

>> > Mark Rutland <mark.rutland@arm.com> wrote:

>> >

>> > > Recent rework of the virtio_mmio probe/remove paths balanced a

>> > > devm_ioremap() with an iounmap() rather than its devm variant. This ends

>> > > up corrupting the devm datastructures, and results in the following

>> > > boot-time splat on arm64 under QEMU 2.9.0:

>> > >

>> > > [    3.450397] ------------[ cut here ]------------

>> > > [    3.453822] Trying to vfree() nonexistent vm area (00000000c05b4844)

>> > > [    3.460534] WARNING: CPU: 1 PID: 1 at mm/vmalloc.c:1525 __vunmap+0x1b8/0x220

>> > > [    3.475898] Kernel panic - not syncing: panic_on_warn set ...

>> > > [    3.475898]

>> > > [    3.493933] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc3 #1

>> > > [    3.513109] Hardware name: linux,dummy-virt (DT)

>> > > [    3.525382] Call trace:

>> > > [    3.531683]  dump_backtrace+0x0/0x368

>> > > [    3.543921]  show_stack+0x20/0x30

>> > > [    3.547767]  dump_stack+0x108/0x164

>> > > [    3.559584]  panic+0x25c/0x51c

>> > > [    3.569184]  __warn+0x29c/0x31c

>> > > [    3.576023]  report_bug+0x1d4/0x290

>> > > [    3.586069]  bug_handler.part.2+0x40/0x100

>> > > [    3.597820]  bug_handler+0x4c/0x88

>> > > [    3.608400]  brk_handler+0x11c/0x218

>> > > [    3.613430]  do_debug_exception+0xe8/0x318

>> > > [    3.627370]  el1_dbg+0x18/0x78

>> > > [    3.634037]  __vunmap+0x1b8/0x220

>> > > [    3.648747]  vunmap+0x6c/0xc0

>> > > [    3.653864]  __iounmap+0x44/0x58

>> > > [    3.659771]  devm_ioremap_release+0x34/0x68

>> > > [    3.672983]  release_nodes+0x404/0x880

>> > > [    3.683543]  devres_release_all+0x6c/0xe8

>> > > [    3.695692]  driver_probe_device+0x250/0x828

>> > > [    3.706187]  __driver_attach+0x190/0x210

>> > > [    3.717645]  bus_for_each_dev+0x14c/0x1f0

>> > > [    3.728633]  driver_attach+0x48/0x78

>> > > [    3.740249]  bus_add_driver+0x26c/0x5b8

>> > > [    3.752248]  driver_register+0x16c/0x398

>> > > [    3.757211]  __platform_driver_register+0xd8/0x128

>> > > [    3.770860]  virtio_mmio_init+0x1c/0x24

>> > > [    3.782671]  do_one_initcall+0xe0/0x398

>> > > [    3.791890]  kernel_init_freeable+0x594/0x660

>> > > [    3.798514]  kernel_init+0x18/0x190

>> > > [    3.810220]  ret_from_fork+0x10/0x18

>> > >

>> > > To fix this, we can simply rip out the explicit cleanup that the devm

>> > > infrastructure will do for us when our probe function returns an error

>> > > code, or when our remove function returns.

>> > >

>> > > We only need to ensure that we call put_device() if a call to

>> > > register_virtio_device() fails in the probe path.

>> > >

>> > > Signed-off-by: Mark Rutland <mark.rutland@arm.com>

>> > > Fixes: 7eb781b1bbb7136f ("virtio_mmio: add cleanup for virtio_mmio_probe")

>> > > Fixes: 25f32223bce5c580 ("virtio_mmio: add cleanup for virtio_mmio_remove")

>> > > Cc: Cornelia Huck <cohuck@redhat.com>

>> > > Cc: Michael S. Tsirkin <mst@redhat.com>

>> > > Cc: weiping zhang <zhangweiping@didichuxing.com>

>> > > Cc: virtualization@lists.linux-foundation.org

>> > > ---

>> > >  drivers/virtio/virtio_mmio.c | 43 +++++++++----------------------------------

>> > >  1 file changed, 9 insertions(+), 34 deletions(-)

>> >

>> > In the hope that I have grokked the devm_* interface by now,

>> >

>> > Reviewed-by: Cornelia Huck <cohuck@redhat.com>

>>

>> Thanks!

>>

>> Michael, could you please queue this as a fix for v4.15?

>>

>> This regressed arm64 VMs booting between v4.15-rc1 and v4-15-rc2,

>> impacting our automated regression testing, and I'd very much like to

>> get back to testing pure mainline rather than mainline + local fixes.

>>

>> Thanks,

>> Mark.

>

> Yep, plan to.

> Thanks!


Sorry to bother again,
As we know if we call device_register we should keep vdev alive until
dev.release be called. As discuss with Cornelia before,

> - return register_virtio_device(&vm_dev->vdev);

> + rc = register_virtio_device(&vm_dev->vdev);

> + if (rc)

> + goto put_dev;

> + return 0;

> +put_dev:

> + put_device(&vm_dev->vdev.dev);


> Here you give up the extra reference from device_initialize(), which

> may or may not be the last reference (since you don't know if

> device_add() had already exposed the struct device to other code that

> might have acquired a reference). As the device has an empty release

> function, touching the device structure after that is not a real

> problem, but...


cuase devm_ interface will free vdev if probe fail, even dev.ref count not
dev to 0. So devm_ interface, may be not very suitable for device_register.

______________________________________________
> Virtualization mailing list

> Virtualization@lists.linux-foundation.org

> https://lists.linuxfoundation.org/mailman/listinfo/virtualization
diff mbox series

Patch

diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index a9192fe4f345..c92131edfaba 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -522,10 +522,8 @@  static int virtio_mmio_probe(struct platform_device *pdev)
 		return -EBUSY;
 
 	vm_dev = devm_kzalloc(&pdev->dev, sizeof(*vm_dev), GFP_KERNEL);
-	if (!vm_dev) {
-		rc = -ENOMEM;
-		goto free_mem;
-	}
+	if (!vm_dev)
+		return -ENOMEM;
 
 	vm_dev->vdev.dev.parent = &pdev->dev;
 	vm_dev->vdev.dev.release = virtio_mmio_release_dev;
@@ -535,17 +533,14 @@  static int virtio_mmio_probe(struct platform_device *pdev)
 	spin_lock_init(&vm_dev->lock);
 
 	vm_dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
-	if (vm_dev->base == NULL) {
-		rc = -EFAULT;
-		goto free_vmdev;
-	}
+	if (vm_dev->base == NULL)
+		return -EFAULT;
 
 	/* Check magic value */
 	magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE);
 	if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
 		dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic);
-		rc = -ENODEV;
-		goto unmap;
+		return -ENODEV;
 	}
 
 	/* Check device version */
@@ -553,8 +548,7 @@  static int virtio_mmio_probe(struct platform_device *pdev)
 	if (vm_dev->version < 1 || vm_dev->version > 2) {
 		dev_err(&pdev->dev, "Version %ld not supported!\n",
 				vm_dev->version);
-		rc = -ENXIO;
-		goto unmap;
+		return -ENXIO;
 	}
 
 	vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);
@@ -563,8 +557,7 @@  static int virtio_mmio_probe(struct platform_device *pdev)
 		 * virtio-mmio device with an ID 0 is a (dummy) placeholder
 		 * with no function. End probing now with no error reported.
 		 */
-		rc = -ENODEV;
-		goto unmap;
+		return -ENODEV;
 	}
 	vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
 
@@ -590,33 +583,15 @@  static int virtio_mmio_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, vm_dev);
 
 	rc = register_virtio_device(&vm_dev->vdev);
-	if (rc) {
-		iounmap(vm_dev->base);
-		devm_release_mem_region(&pdev->dev, mem->start,
-					resource_size(mem));
+	if (rc)
 		put_device(&vm_dev->vdev.dev);
-	}
-	return rc;
-unmap:
-	iounmap(vm_dev->base);
-free_mem:
-	devm_release_mem_region(&pdev->dev, mem->start,
-			resource_size(mem));
-free_vmdev:
-	devm_kfree(&pdev->dev, vm_dev);
+
 	return rc;
 }
 
 static int virtio_mmio_remove(struct platform_device *pdev)
 {
 	struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev);
-	struct resource *mem;
-
-	iounmap(vm_dev->base);
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (mem)
-		devm_release_mem_region(&pdev->dev, mem->start,
-			resource_size(mem));
 	unregister_virtio_device(&vm_dev->vdev);
 
 	return 0;