[PATCH] ioremap balanced with iounmap for drivers/serial

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ioremap must be balanced by an iounmap and failing to do so can result
in a memory leak.

Tested (compilation only) with:
- Modifying drivers/serial/Kconfig to make sure that the changed file is
compiling without error/warning (due to my changes)

Signed-off-by: Amol Lad <[email protected]>
---
Forwarding to lkml as got no response from linux-serial. (Please CC me)
---
 8250_acorn.c   |    9 +++++----
 8250_gsc.c     |    1 +
 ioc4_serial.c  |    3 +++
 ip22zilog.c    |   16 +++++++++++++++-
 mpc52xx_uart.c |   11 ++++++++++-
 mpsc.c         |   12 ++++++++++++
 mux.c          |    2 ++
 sunsu.c        |    3 +++
 8 files changed, 51 insertions(+), 6 deletions(-)
---
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/8250_acorn.c linux-2.6.18/drivers/serial/8250_acorn.c
--- linux-2.6.18-orig/drivers/serial/8250_acorn.c	2006-08-24 02:46:33.000000000 +0530
+++ linux-2.6.18/drivers/serial/8250_acorn.c	2006-09-26 15:26:09.000000000 +0530
@@ -35,6 +35,7 @@ struct serial_card_type {
 struct serial_card_info {
 	unsigned int	num_ports;
 	int		ports[MAX_PORTS];
+	void __iomem *vaddr;
 };
 
 static int __devinit
@@ -44,7 +45,6 @@ serial_card_probe(struct expansion_card 
 	struct serial_card_type *type = id->data;
 	struct uart_port port;
 	unsigned long bus_addr;
-	unsigned char __iomem *virt_addr;
 	unsigned int i;
 
 	info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL);
@@ -55,8 +55,8 @@ serial_card_probe(struct expansion_card 
 	info->num_ports = type->num_ports;
 
 	bus_addr = ecard_resource_start(ec, type->type);
-	virt_addr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
-	if (!virt_addr) {
+	info->vaddr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
+	if (!info->vaddr) {
 		kfree(info);
 		return -ENOMEM;
 	}
@@ -72,7 +72,7 @@ serial_card_probe(struct expansion_card 
 	port.dev	= &ec->dev;
 
 	for (i = 0; i < info->num_ports; i ++) {
-		port.membase = virt_addr + type->offset[i];
+		port.membase = info->vaddr + type->offset[i];
 		port.mapbase = bus_addr + type->offset[i];
 
 		info->ports[i] = serial8250_register_port(&port);
@@ -92,6 +92,7 @@ static void __devexit serial_card_remove
 		if (info->ports[i] > 0)
 			serial8250_unregister_port(info->ports[i]);
 
+	iounmap(info->vaddr);
 	kfree(info);
 }
 
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/8250_gsc.c linux-2.6.18/drivers/serial/8250_gsc.c
--- linux-2.6.18-orig/drivers/serial/8250_gsc.c	2006-08-24 02:46:33.000000000 +0530
+++ linux-2.6.18/drivers/serial/8250_gsc.c	2006-09-26 17:06:16.000000000 +0530
@@ -64,6 +64,7 @@ serial_init_chip(struct parisc_device *d
 	err = serial8250_register_port(&port);
 	if (err < 0) {
 		printk(KERN_WARNING "serial8250_register_port returned error %d\n", err);
+		iounmap(port.membase);
 		return err;
 	}
         
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/ioc4_serial.c linux-2.6.18/drivers/serial/ioc4_serial.c
--- linux-2.6.18-orig/drivers/serial/ioc4_serial.c	2006-09-21 10:15:41.000000000 +0530
+++ linux-2.6.18/drivers/serial/ioc4_serial.c	2006-09-26 15:35:30.000000000 +0530
@@ -2685,6 +2685,7 @@ static int ioc4_serial_remove_one(struct
 	if (soft) {
 		free_irq(control->ic_irq, soft);
 		if (soft->is_ioc4_serial_addr) {
+			iounmap(soft->is_ioc4_serial_addr);
 			release_region((unsigned long)
 			     soft->is_ioc4_serial_addr,
 				sizeof(struct ioc4_serial));
@@ -2887,6 +2888,8 @@ out4:
 out3:
 	kfree(control);
 out2:
+	if (serial)
+		iounmap(serial);
 	release_region(tmp_addr1, sizeof(struct ioc4_serial));
 out1:
 
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/ip22zilog.c linux-2.6.18/drivers/serial/ip22zilog.c
--- linux-2.6.18-orig/drivers/serial/ip22zilog.c	2006-09-21 10:15:41.000000000 +0530
+++ linux-2.6.18/drivers/serial/ip22zilog.c	2006-09-26 16:42:35.000000000 +0530
@@ -1229,13 +1229,27 @@ static int __init ip22zilog_init(void)
 static void __exit ip22zilog_exit(void)
 {
 	int i;
+	struct uart_ip22zilog_port *up;
 
 	for (i = 0; i < NUM_CHANNELS; i++) {
-		struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+		up = &ip22zilog_port_table[i];
 
 		uart_remove_one_port(&ip22zilog_reg, &up->port);
 	}
 
+	/* Free IO mem */
+	up = &ip22zilog_port_table[0];
+	for (i = 0; i < NUM_IP22ZILOG; i++) {
+		if (up[(i * 2) + 0].port.mapbase) {
+		   iounmap((void*)up[(i * 2) + 0].port.mapbase);
+		   up[(i * 2) + 0].port.mapbase = 0;
+		}
+		if (up[(i * 2) + 1].port.mapbase) {
+			iounmap((void*)up[(i * 2) + 1].port.mapbase);
+			up[(i * 2) + 1].port.mapbase = 0;
+		}
+	}
+
 	uart_unregister_driver(&ip22zilog_reg);
 }
 
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/mpc52xx_uart.c linux-2.6.18/drivers/serial/mpc52xx_uart.c
--- linux-2.6.18-orig/drivers/serial/mpc52xx_uart.c	2006-09-21 10:15:41.000000000 +0530
+++ linux-2.6.18/drivers/serial/mpc52xx_uart.c	2006-09-26 16:01:14.000000000 +0530
@@ -338,14 +338,23 @@ mpc52xx_uart_release_port(struct uart_po
 static int
 mpc52xx_uart_request_port(struct uart_port *port)
 {
+	int err;
+	
 	if (port->flags & UPF_IOREMAP) /* Need to remap ? */
 		port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
 
 	if (!port->membase)
 		return -EINVAL;
 
-	return request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
+	err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
 			"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
+
+	if (err && (port->flags & UPF_IOREMAP)) {
+		iounmap(port->membase);
+		port->membase = NULL;
+	}
+
+	return err;
 }
 
 static void
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/mpsc.c linux-2.6.18/drivers/serial/mpsc.c
--- linux-2.6.18-orig/drivers/serial/mpsc.c	2006-09-21 10:15:41.000000000 +0530
+++ linux-2.6.18/drivers/serial/mpsc.c	2006-09-26 16:08:19.000000000 +0530
@@ -1893,6 +1893,10 @@ mpsc_drv_map_regs(struct mpsc_port_info 
 	}
 	else {
 		mpsc_resource_err("SDMA base");
+		if (pi->mpsc_base) {
+			iounmap(pi->mpsc_base);
+			pi->mpsc_base = NULL;
+		}
 		return -ENOMEM;
 	}
 
@@ -1905,6 +1909,14 @@ mpsc_drv_map_regs(struct mpsc_port_info 
 	}
 	else {
 		mpsc_resource_err("BRG base");
+		if (pi->mpsc_base) {
+			iounmap(pi->mpsc_base);
+			pi->mpsc_base = NULL;
+		}
+		if (pi->sdma_base) {
+			iounmap(pi->sdma_base);
+			pi->sdma_base = NULL;
+		}
 		return -ENOMEM;
 	}
 
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/mux.c linux-2.6.18/drivers/serial/mux.c
--- linux-2.6.18-orig/drivers/serial/mux.c	2006-09-21 10:15:41.000000000 +0530
+++ linux-2.6.18/drivers/serial/mux.c	2006-09-26 16:12:37.000000000 +0530
@@ -521,6 +521,8 @@ static void __exit mux_exit(void)
 
 	for (i = 0; i < port_cnt; i++) {
 		uart_remove_one_port(&mux_driver, &mux_ports[i]);
+		if (mux_ports[i].membase)
+			iounmap(mux_ports[i].membase);
 	}
 
 	uart_unregister_driver(&mux_driver);
diff -uprN -X linux-2.6.18-orig/Documentation/dontdiff linux-2.6.18-orig/drivers/serial/sunsu.c linux-2.6.18/drivers/serial/sunsu.c
--- linux-2.6.18-orig/drivers/serial/sunsu.c	2006-09-21 10:15:41.000000000 +0530
+++ linux-2.6.18/drivers/serial/sunsu.c	2006-09-26 16:22:42.000000000 +0530
@@ -1499,6 +1499,9 @@ static int __devexit su_remove(struct of
 		uart_remove_one_port(&sunsu_reg, &up->port);
 	}
 
+	if (up->port.membase)
+		of_iounmap(up->port.membase, up->reg_size);
+
 	dev_set_drvdata(&dev->dev, NULL);
 
 	return 0;


_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.osdl.org/mailman/listinfo/kernel-janitors



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux