diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-04 03:42:25 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-04 03:42:25 +0300 |
commit | a23867f1d2de572f84b459651dfe99fa9e79fadf (patch) | |
tree | ae3cecc903408653646986aa03b5361ef5ae1204 /drivers/ata/libata-core.c | |
parent | ef1c4a6fa91bbbe9b09f770d28eba31a9edf770c (diff) | |
parent | 027fa4dee935d25cef5994af1b8864eb00dcffac (diff) | |
download | linux-a23867f1d2de572f84b459651dfe99fa9e79fadf.tar.xz |
Merge branch 'for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata updates from Tejun Heo:
"Nothing too interesting.
The biggest change is refcnting fix for ata_host - the bug is recent
and can only be triggered on controller hotplug, so very few are
hitting it.
There also are a number of trivial license / error message changes and
some hardware specific changes"
* 'for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (23 commits)
ahci: imx: add the imx8qm ahci sata support
libata: ensure host is free'd on error exit paths
ata: ahci-platform: add reset control support
ahci: imx: fix the build warning
ata: add Amiga Gayle PATA controller driver
ahci: imx: add the imx6qp ahci sata support
ata: change Tegra124 to Tegra
ata: ahci_tegra: Add AHCI support for Tegra210
ata: ahci_tegra: disable DIPM
ata: ahci_tegra: disable devslp for Tegra124
ata: ahci_tegra: initialize regulators from soc struct
ata: ahci_tegra: Update initialization sequence
dt-bindings: Tegra210: add binding documentation
libata: add refcounting to ata_host
pata_bk3710: clarify license version and use SPDX header
pata_falcon: clarify license version and use SPDX header
pata_it821x: Delete an error message for a failed memory allocation in it821x_firmware_command()
pata_macio: Delete an error message for a failed memory allocation in two functions
pata_mpc52xx: Delete an error message for a failed memory allocation in mpc52xx_ata_probe()
sata_dwc_460ex: Delete an error message for a failed memory allocation in sata_dwc_port_start()
...
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 728ed4764678..8bc71ca61e7f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6026,7 +6026,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) return ap; } -static void ata_host_release(struct device *gendev, void *res) +static void ata_devres_release(struct device *gendev, void *res) { struct ata_host *host = dev_get_drvdata(gendev); int i; @@ -6040,13 +6040,36 @@ static void ata_host_release(struct device *gendev, void *res) if (ap->scsi_host) scsi_host_put(ap->scsi_host); + } + + dev_set_drvdata(gendev, NULL); + ata_host_put(host); +} + +static void ata_host_release(struct kref *kref) +{ + struct ata_host *host = container_of(kref, struct ata_host, kref); + int i; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + kfree(ap->pmp_link); kfree(ap->slave_link); kfree(ap); host->ports[i] = NULL; } + kfree(host); +} - dev_set_drvdata(gendev, NULL); +void ata_host_get(struct ata_host *host) +{ + kref_get(&host->kref); +} + +void ata_host_put(struct ata_host *host) +{ + kref_put(&host->kref, ata_host_release); } /** @@ -6074,26 +6097,31 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) struct ata_host *host; size_t sz; int i; + void *dr; DPRINTK("ENTER\n"); - if (!devres_open_group(dev, NULL, GFP_KERNEL)) - return NULL; - /* alloc a container for our list of ATA ports (buses) */ sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *); - /* alloc a container for our list of ATA ports (buses) */ - host = devres_alloc(ata_host_release, sz, GFP_KERNEL); + host = kzalloc(sz, GFP_KERNEL); if (!host) + return NULL; + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + goto err_free; + + dr = devres_alloc(ata_devres_release, 0, GFP_KERNEL); + if (!dr) goto err_out; - devres_add(dev, host); + devres_add(dev, dr); dev_set_drvdata(dev, host); spin_lock_init(&host->lock); mutex_init(&host->eh_mutex); host->dev = dev; host->n_ports = max_ports; + kref_init(&host->kref); /* allocate ports bound to this host */ for (i = 0; i < max_ports; i++) { @@ -6112,6 +6140,8 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) err_out: devres_release_group(dev, NULL); + err_free: + kfree(host); return NULL; } |