nvme: fix memory leak caused by incorrect subsystem free
When freeing the subsystem after finding another match with
__nvme_find_get_subsystem(), use put_device() instead of
__nvme_release_subsystem() which calls kfree() directly.
Per the documentation, put_device() should always be used
after device_initialization() is called. Otherwise, leaks
like the one below which was detected by kmemleak may occur.
Once the call of __nvme_release_subsystem() is removed it no
longer makes sense to keep the helper, so fold it back
into nvme_release_subsystem().
unreferenced object 0xffff8883d12bfbc0 (size 16):
comm "nvme", pid 2635, jiffies 4294933602 (age 739.952s)
hex dump (first 16 bytes):
6e 76 6d 65 2d 73 75 62 73 79 73 32 00 88 ff ff nvme-subsys2....
backtrace:
[<000000007d8fc208>] __kmalloc_track_caller+0x16d/0x2a0
[<0000000081169e5f>] kvasprintf+0xad/0x130
[<0000000025626f25>] kvasprintf_const+0x47/0x120
[<00000000fa66ad36>] kobject_set_name_vargs+0x44/0x120
[<000000004881f8b3>] dev_set_name+0x98/0xc0
[<000000007124dae3>] nvme_init_identify+0x1995/0x38e0
[<000000009315020a>] nvme_loop_configure_admin_queue+0x4fa/0x5e0
[<000000001a63e766>] nvme_loop_create_ctrl+0x489/0xf80
[<00000000a46ecc23>] nvmf_dev_write+0x1a12/0x2220
[<000000002259b3d5>] __vfs_write+0x66/0x120
[<000000002f6df81e>] vfs_write+0x154/0x490
[<000000007e8cfc19>] ksys_write+0x10a/0x240
[<00000000ff5c7b85>] __x64_sys_write+0x73/0xb0
[<00000000fee6d692>] do_syscall_64+0xaa/0x470
[<00000000997e1ede>] entry_SYSCALL_64_after_hwframe+0x49/0xbe
Fixes: ab9e00cc72
("nvme: track subsystems")
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
08b903b5fd
commit
e654dfd38c
|
@ -2311,15 +2311,13 @@ static void nvme_init_subnqn(struct nvme_subsystem *subsys, struct nvme_ctrl *ct
|
||||||
memset(subsys->subnqn + off, 0, sizeof(subsys->subnqn) - off);
|
memset(subsys->subnqn + off, 0, sizeof(subsys->subnqn) - off);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __nvme_release_subsystem(struct nvme_subsystem *subsys)
|
|
||||||
{
|
|
||||||
ida_simple_remove(&nvme_subsystems_ida, subsys->instance);
|
|
||||||
kfree(subsys);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nvme_release_subsystem(struct device *dev)
|
static void nvme_release_subsystem(struct device *dev)
|
||||||
{
|
{
|
||||||
__nvme_release_subsystem(container_of(dev, struct nvme_subsystem, dev));
|
struct nvme_subsystem *subsys =
|
||||||
|
container_of(dev, struct nvme_subsystem, dev);
|
||||||
|
|
||||||
|
ida_simple_remove(&nvme_subsystems_ida, subsys->instance);
|
||||||
|
kfree(subsys);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvme_destroy_subsystem(struct kref *ref)
|
static void nvme_destroy_subsystem(struct kref *ref)
|
||||||
|
@ -2477,7 +2475,7 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
|
||||||
mutex_lock(&nvme_subsystems_lock);
|
mutex_lock(&nvme_subsystems_lock);
|
||||||
found = __nvme_find_get_subsystem(subsys->subnqn);
|
found = __nvme_find_get_subsystem(subsys->subnqn);
|
||||||
if (found) {
|
if (found) {
|
||||||
__nvme_release_subsystem(subsys);
|
put_device(&subsys->dev);
|
||||||
subsys = found;
|
subsys = found;
|
||||||
|
|
||||||
if (!nvme_validate_cntlid(subsys, ctrl, id)) {
|
if (!nvme_validate_cntlid(subsys, ctrl, id)) {
|
||||||
|
|
Loading…
Reference in New Issue