Skip to content
  • Jason Yan's avatar
    scsi: libsas: dynamically allocate and free ata host · 2fa4a326
    Jason Yan authored
    Commit 2623c7a5 ("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: b6240a4d
    
     ("scsi: libsas: add transport class for ATA devices")
    Signed-off-by: default avatarJason 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: default avatarTejun Heo <tj@kernel.org>
    Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
    2fa4a326