diff options
author | Jason Yan <yanaijie@huawei.com> | 2018-05-10 11:05:16 +0800 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-06-19 22:02:25 -0400 |
commit | 2fa4a32613c9182b00e46872755b0662374424a7 (patch) | |
tree | 79b70b0062d7c95c9b0eecca9ae8e15c06780b7e /drivers/ata | |
parent | 693ba15c9202fe0283404abe4066e1b986e284eb (diff) |
scsi: libsas: dynamically allocate and free ata host
Commit 2623c7a5f2 ("libata: add refcounting to ata_host") v4.17+ introduced
refcounting to ata_host and will increase or decrease the refcount when
adding or deleting transport ATA port.
Now the ata host for libsas is embedded in domain_device, and the ->kref
member is not initialized. Afer we add ata transport class, ata_host_get()
will be called when adding transport ATA port and a warning will be
triggered as below:
refcount_t: increment on 0; use-after-free.
WARNING: CPU: 2 PID: 103 at
lib/refcount.c:153 refcount_inc+0x40/0x48 ...... Call trace:
refcount_inc+0x40/0x48
ata_host_get+0x10/0x18
ata_tport_add+0x40/0x120
ata_sas_tport_add+0xc/0x14
sas_ata_init+0x7c/0xc8
sas_discover_domain+0x380/0x53c
process_one_work+0x12c/0x288
worker_thread+0x58/0x3f0
kthread+0xfc/0x128
ret_from_fork+0x10/0x18
And also when removing transport ATA port ata_host_put() will be called and
another similar warning will be triggered. If the refcount decreased to
zero, the ata host will be freed. But this ata host is only part of
domain_device, it cannot be freed directly.
So we have to change this embedded static ata host to a dynamically
allocated ata host and initialize the ->kref member. To use ata_host_get()
and ata_host_put() in libsas, we need to move the declaration of these
functions to the public libata.h and export them.
Fixes: b6240a4df018 ("scsi: libsas: add transport class for ATA devices")
Signed-off-by: Jason Yan <yanaijie@huawei.com>
CC: John Garry <john.garry@huawei.com>
CC: Taras Kondratiuk <takondra@cisco.com>
CC: Tejun Heo <tj@kernel.org>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-core.c | 3 | ||||
-rw-r--r-- | drivers/ata/libata.h | 2 |
2 files changed, 3 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 27d15ed7fa3d..89cb4872a09c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6421,6 +6421,7 @@ void ata_host_init(struct ata_host *host, struct device *dev, host->n_tags = ATA_MAX_QUEUE; host->dev = dev; host->ops = ops; + kref_init(&host->kref); } void __ata_port_probe(struct ata_port *ap) @@ -7388,3 +7389,5 @@ EXPORT_SYMBOL_GPL(ata_cable_80wire); EXPORT_SYMBOL_GPL(ata_cable_unknown); EXPORT_SYMBOL_GPL(ata_cable_ignore); EXPORT_SYMBOL_GPL(ata_cable_sata); +EXPORT_SYMBOL_GPL(ata_host_get); +EXPORT_SYMBOL_GPL(ata_host_put);
\ No newline at end of file diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 9e21c49cf6be..f953cb4bb1ba 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -100,8 +100,6 @@ extern int ata_port_probe(struct ata_port *ap); extern void __ata_port_probe(struct ata_port *ap); extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log, u8 page, void *buf, unsigned int sectors); -extern void ata_host_get(struct ata_host *host); -extern void ata_host_put(struct ata_host *host); #define to_ata_port(d) container_of(d, struct ata_port, tdev) |