lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Sun, 22 Oct 2006 17:49:14 +0200 (CEST)
From:	Jiri Slaby <jirislaby@...il.com>
To:	Andrew Morton <akpm@...l.org>
Cc:	Alan Cox <alan@...rguk.ukuu.org.uk>
Subject: [PATCH 3/4] Char: stallion, implement fail paths

stallion, implement fail paths

Huh, this driver expect everything to work. Implement fail paths logic
to release regions, irq hangler, memory... if something is in bad state.

Signed-off-by: Jiri Slaby <jirislaby@...il.com>

---
commit 193f82ab45ee71c37cac356fd1afed8295d80b1e
tree cb1d6b1802555cc6f888ded01702134f2e3367a8
parent d69255dafff0fbf775d8ec4de1479cf3cc31b977
author Jiri Slaby <ku@...lona.localdomain> Sun, 22 Oct 2006 17:19:05 +0159
committer Jiri Slaby <ku@...lona.localdomain> Sun, 22 Oct 2006 17:19:05 +0159

 drivers/char/stallion.c |  199 ++++++++++++++++++++++++++++++-----------------
 1 files changed, 128 insertions(+), 71 deletions(-)

diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 884a578..73312c3 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -779,7 +779,8 @@ static void __init stl_argbrds(void)
 		brdp->ioaddr2 = conf.ioaddr2;
 		brdp->irq = conf.irq;
 		brdp->irqtype = conf.irqtype;
-		stl_brdinit(brdp);
+		if (stl_brdinit(brdp))
+			kfree(brdp);
 	}
 }
 
@@ -1967,6 +1968,29 @@ static int __init stl_initports(struct s
 	return(0);
 }
 
+static void stl_cleanup_panels(struct stlbrd *brdp)
+{
+	struct stlpanel *panelp;
+	struct stlport *portp;
+	unsigned int j, k;
+
+	for (j = 0; j < STL_MAXPANELS; j++) {
+		panelp = brdp->panels[j];
+		if (panelp == NULL)
+			continue;
+		for (k = 0; k < STL_PORTSPERPANEL; k++) {
+			portp = panelp->ports[k];
+			if (portp == NULL)
+				continue;
+			if (portp->tty != NULL)
+				stl_hangup(portp->tty);
+			kfree(portp->tx.buf);
+			kfree(portp);
+		}
+		kfree(panelp);
+	}
+}
+
 /*****************************************************************************/
 
 /*
@@ -1978,7 +2002,7 @@ static int __init stl_initeio(struct stl
 	struct stlpanel	*panelp;
 	unsigned int	status;
 	char		*name;
-	int		rc;
+	int		retval;
 
 	pr_debug("stl_initeio(brdp=%p)\n", brdp);
 
@@ -2005,18 +2029,20 @@ static int __init stl_initeio(struct stl
 		    (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
 			printk("STALLION: invalid irq=%d for brd=%d\n",
 				brdp->irq, brdp->brdnr);
-			return(-EINVAL);
+			retval = -EINVAL;
+			goto err;
 		}
 		outb((stl_vecmap[brdp->irq] | EIO_0WS |
 			((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
 			brdp->ioctrl);
 	}
 
+	retval = -EBUSY;
 	if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
 		printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
 			"%x conflicts with another device\n", brdp->brdnr, 
 			brdp->ioaddr1);
-		return(-EBUSY);
+		goto err;
 	}
 	
 	if (brdp->iosize2 > 0)
@@ -2027,8 +2053,7 @@ static int __init stl_initeio(struct stl
 			printk(KERN_WARNING "STALLION: Warning, also "
 				"releasing board %d I/O address %x \n", 
 				brdp->brdnr, brdp->ioaddr1);
-			release_region(brdp->ioaddr1, brdp->iosize1);
-        		return(-EBUSY);
+			goto err_rel1;
 		}
 
 /*
@@ -2037,6 +2062,7 @@ static int __init stl_initeio(struct stl
 	brdp->clk = CD1400_CLK;
 	brdp->isr = stl_eiointr;
 
+	retval = -ENODEV;
 	switch (status & EIO_IDBITMASK) {
 	case EIO_8PORTM:
 		brdp->clk = CD1400_CLK8M;
@@ -2060,11 +2086,11 @@ static int __init stl_initeio(struct stl
 			brdp->nrports = 16;
 			break;
 		default:
-			return(-ENODEV);
+			goto err_rel2;
 		}
 		break;
 	default:
-		return(-ENODEV);
+		goto err_rel2;
 	}
 
 /*
@@ -2076,7 +2102,8 @@ static int __init stl_initeio(struct stl
 	if (!panelp) {
 		printk(KERN_WARNING "STALLION: failed to allocate memory "
 			"(size=%Zd)\n", sizeof(struct stlpanel));
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto err_rel2;
 	}
 
 	panelp->magic = STL_PANELMAGIC;
@@ -2100,11 +2127,20 @@ static int __init stl_initeio(struct stl
 	if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
 		printk("STALLION: failed to register interrupt "
 		    "routine for %s irq=%d\n", name, brdp->irq);
-		rc = -ENODEV;
-	} else {
-		rc = 0;
+		retval = -ENODEV;
+		goto err_fr;
 	}
-	return rc;
+
+	return 0;
+err_fr:
+	stl_cleanup_panels(brdp);
+err_rel2:
+	if (brdp->iosize2 > 0)
+		release_region(brdp->ioaddr2, brdp->iosize2);
+err_rel1:
+	release_region(brdp->ioaddr1, brdp->iosize1);
+err:
+	return retval;
 }
 
 /*****************************************************************************/
@@ -2118,7 +2154,7 @@ static int __init stl_initech(struct stl
 {
 	struct stlpanel	*panelp;
 	unsigned int	status, nxtid, ioaddr, conflict;
-	int		panelnr, banknr, i;
+	int		panelnr, banknr, i, retval;
 	char		*name;
 
 	pr_debug("stl_initech(brdp=%p)\n", brdp);
@@ -2138,13 +2174,16 @@ static int __init stl_initech(struct stl
 		brdp->ioctrl = brdp->ioaddr1 + 1;
 		brdp->iostatus = brdp->ioaddr1 + 1;
 		status = inb(brdp->iostatus);
-		if ((status & ECH_IDBITMASK) != ECH_ID)
-			return(-ENODEV);
+		if ((status & ECH_IDBITMASK) != ECH_ID) {
+			retval = -ENODEV;
+			goto err;
+		}
 		if ((brdp->irq < 0) || (brdp->irq > 15) ||
 		    (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
 			printk("STALLION: invalid irq=%d for brd=%d\n",
 				brdp->irq, brdp->brdnr);
-			return(-EINVAL);
+			retval = -EINVAL;
+			goto err;
 		}
 		status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
 		status |= (stl_vecmap[brdp->irq] << 1);
@@ -2164,13 +2203,16 @@ static int __init stl_initech(struct stl
 		brdp->ioctrl = brdp->ioaddr1 + 0x20;
 		brdp->iostatus = brdp->ioctrl;
 		status = inb(brdp->iostatus);
-		if ((status & ECH_IDBITMASK) != ECH_ID)
-			return(-ENODEV);
+		if ((status & ECH_IDBITMASK) != ECH_ID) {
+			retval = -ENODEV;
+			goto err;
+		}
 		if ((brdp->irq < 0) || (brdp->irq > 15) ||
 		    (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
 			printk("STALLION: invalid irq=%d for brd=%d\n",
 				brdp->irq, brdp->brdnr);
-			return(-EINVAL);
+			retval = -EINVAL;
+			goto err;
 		}
 		outb(ECHMC_BRDRESET, brdp->ioctrl);
 		outb(ECHMC_INTENABLE, brdp->ioctrl);
@@ -2197,19 +2239,20 @@ static int __init stl_initech(struct stl
 
 	default:
 		printk("STALLION: unknown board type=%d\n", brdp->brdtype);
-		return(-EINVAL);
-		break;
+		retval = -EINVAL;
+		goto err;
 	}
 
 /*
  *	Check boards for possible IO address conflicts and return fail status 
  * 	if an IO conflict found.
  */
+	retval = -EBUSY;
 	if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
 		printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
 			"%x conflicts with another device\n", brdp->brdnr, 
 			brdp->ioaddr1);
-		return(-EBUSY);
+		goto err;
 	}
 	
 	if (brdp->iosize2 > 0)
@@ -2220,8 +2263,7 @@ static int __init stl_initech(struct stl
 			printk(KERN_WARNING "STALLION: Warning, also "
 				"releasing board %d I/O address %x \n", 
 				brdp->brdnr, brdp->ioaddr1);
-			release_region(brdp->ioaddr1, brdp->iosize1);
-			return(-EBUSY);
+			goto err_rel1;
 		}
 
 /*
@@ -2243,12 +2285,12 @@ static int __init stl_initech(struct stl
 		}
 		status = inb(ioaddr + ECH_PNLSTATUS);
 		if ((status & ECH_PNLIDMASK) != nxtid)
-			break;
+			goto err_fr;
 		panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
 		if (!panelp) {
 			printk("STALLION: failed to allocate memory "
 				"(size=%Zd)\n", sizeof(struct stlpanel));
-			break;
+			goto err_fr;
 		}
 		panelp->magic = STL_PANELMAGIC;
 		panelp->brdnr = brdp->brdnr;
@@ -2296,7 +2338,7 @@ static int __init stl_initech(struct stl
 		brdp->panels[panelnr++] = panelp;
 		if ((brdp->brdtype != BRD_ECHPCI) &&
 		    (ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
-			break;
+			goto err_fr;
 	}
 
 	brdp->nrpanels = panelnr;
@@ -2308,12 +2350,19 @@ static int __init stl_initech(struct stl
 	if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
 		printk("STALLION: failed to register interrupt "
 		    "routine for %s irq=%d\n", name, brdp->irq);
-		i = -ENODEV;
-	} else {
-		i = 0;
+		retval = -ENODEV;
+		goto err_fr;
 	}
 
-	return(i);
+	return 0;
+err_fr:
+	stl_cleanup_panels(brdp);
+	if (brdp->iosize2 > 0)
+		release_region(brdp->ioaddr2, brdp->iosize2);
+err_rel1:
+	release_region(brdp->ioaddr1, brdp->iosize1);
+err:
+	return retval;
 }
 
 /*****************************************************************************/
@@ -2327,25 +2376,30 @@ static int __init stl_initech(struct stl
 
 static int __init stl_brdinit(struct stlbrd *brdp)
 {
-	int	i;
+	int i, retval;
 
 	pr_debug("stl_brdinit(brdp=%p)\n", brdp);
 
 	switch (brdp->brdtype) {
 	case BRD_EASYIO:
 	case BRD_EASYIOPCI:
-		stl_initeio(brdp);
+		retval = stl_initeio(brdp);
+		if (retval)
+			goto err;
 		break;
 	case BRD_ECH:
 	case BRD_ECHMC:
 	case BRD_ECHPCI:
 	case BRD_ECH64PCI:
-		stl_initech(brdp);
+		retval = stl_initech(brdp);
+		if (retval)
+			goto err;
 		break;
 	default:
 		printk("STALLION: board=%d is unknown board type=%d\n",
 			brdp->brdnr, brdp->brdtype);
-		return(ENODEV);
+		retval = -ENODEV;
+		goto err;
 	}
 
 	stl_brds[brdp->brdnr] = brdp;
@@ -2353,7 +2407,7 @@ static int __init stl_brdinit(struct stl
 		printk("STALLION: %s board not found, board=%d io=%x irq=%d\n",
 			stl_brdnames[brdp->brdtype], brdp->brdnr,
 			brdp->ioaddr1, brdp->irq);
-		return(ENODEV);
+		goto err_free;
 	}
 
 	for (i = 0; (i < STL_MAXPANELS); i++)
@@ -2364,7 +2418,20 @@ static int __init stl_brdinit(struct stl
 		"nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
 		brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
 		brdp->nrports);
-	return(0);
+
+	return 0;
+err_free:
+	free_irq(brdp->irq, brdp);
+
+	stl_cleanup_panels(brdp);
+
+	release_region(brdp->ioaddr1, brdp->iosize1);
+	if (brdp->iosize2 > 0)
+		release_region(brdp->ioaddr2, brdp->iosize2);
+
+	stl_brds[brdp->brdnr] = NULL;
+err:
+	return retval;
 }
 
 /*****************************************************************************/
@@ -2387,29 +2454,6 @@ static int __init stl_getbrdnr(void)
 	return(-1);
 }
 
-static void stl_cleanup_panels(struct stlbrd *brdp)
-{
-	struct stlpanel *panelp;
-	struct stlport *portp;
-	unsigned int j, k;
-
-	for (j = 0; j < STL_MAXPANELS; j++) {
-		panelp = brdp->panels[j];
-		if (panelp == NULL)
-			continue;
-		for (k = 0; k < STL_PORTSPERPANEL; k++) {
-			portp = panelp->ports[k];
-			if (portp == NULL)
-				continue;
-			if (portp->tty != NULL)
-				stl_hangup(portp->tty);
-			kfree(portp->tx.buf);
-			kfree(portp);
-		}
-		kfree(panelp);
-	}
-}
-
 /*****************************************************************************/
 /*
  *	We have a Stallion board. Allocate a board structure and
@@ -2422,21 +2466,27 @@ static int __devinit stl_pciprobe(struct
 {
 	struct stlbrd *brdp;
 	unsigned int brdtype = ent->driver_data;
+	int retval = -ENODEV;
 
 	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
-		return -ENODEV;
+		goto err;
 
 	dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n",
 			pdev->vendor, pdev->device, pdev->class);
 
-	if (pci_enable_device(pdev))
-		return(-EIO);
-	if ((brdp = stl_allocbrd()) == NULL)
-		return(-ENOMEM);
-	if ((brdp->brdnr = stl_getbrdnr()) < 0) {
+	retval = pci_enable_device(pdev);
+	if (retval)
+		goto err;
+	brdp = stl_allocbrd();
+	if (brdp == NULL) {
+		retval = -ENOMEM;
+		goto err;
+	}
+	brdp->brdnr = stl_getbrdnr();
+	if (brdp->brdnr < 0) {
 		dev_err(&pdev->dev, "too many boards found, "
 			"maximum supported %d\n", STL_MAXBRDS);
-		return(0);
+		goto err_fr;
 	}
 	brdp->brdtype = brdtype;
 
@@ -2463,11 +2513,17 @@ static int __devinit stl_pciprobe(struct
 	}
 
 	brdp->irq = pdev->irq;
-	stl_brdinit(brdp);
+	retval = stl_brdinit(brdp);
+	if (retval)
+		goto err_fr;
 
 	pci_set_drvdata(pdev, brdp);
 
-	return(0);
+	return 0;
+err_fr:
+	kfree(brdp);
+err:
+	return retval;
 }
 
 static void __devexit stl_pciremove(struct pci_dev *pdev)
@@ -2530,7 +2586,8 @@ static int __init stl_initbrds(void)
 		brdp->ioaddr2 = confp->ioaddr2;
 		brdp->irq = confp->irq;
 		brdp->irqtype = confp->irqtype;
-		stl_brdinit(brdp);
+		if (stl_brdinit(brdp))
+			kfree(brdp);
 	}
 
 /*
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ