summaryrefslogtreecommitdiff
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 17:42:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 17:42:25 -0700
commita23867f1d2de572f84b459651dfe99fa9e79fadf (patch)
treeae3cecc903408653646986aa03b5361ef5ae1204 /drivers/ata/libata-core.c
parentef1c4a6fa91bbbe9b09f770d28eba31a9edf770c (diff)
parent027fa4dee935d25cef5994af1b8864eb00dcffac (diff)
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.c46
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;
}