2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-24 21:24:00 +08:00
linux-next/drivers/pcmcia
Russell King 025e4ab3db pcmcia: fix socket refcount decrementing on each resume
This fixes a memory-corrupting bug: not only does it cause the warning,
but as a result of dropping the refcount to zero, it causes the
pcmcia_socket0 device structure to be freed while it still has
references, causing slab caches corruption.  A fatal oops quickly
follows this warning - often even just a 'dmesg' following the warning
causes the kernel to oops.

While testing suspend/resume on an ARM device with PCMCIA support, and a
CF card inserted, I found that after five suspend and resumes, the
kernel would complain, and shortly die after with slab corruption.

  WARNING: at include/linux/kref.h:41 kobject_get+0x28/0x50()

As the message doesn't give a clue about which kobject, and the built-in
debugging in drivers/base/power/main.c happens too late, this was added
right before each get_device():

  printk("%s: %p [%s] %u\n", __func__, dev, kobject_name(&dev->kobj), atomic_read(&dev->kobj.kref.refcount));

and on the 3rd s2ram cycle, the following behaviour observed:

On the 3rd suspend/resume cycle:

  dpm_prepare: c1a0d998 [pcmcia_socket0] 3
  dpm_suspend: c1a0d998 [pcmcia_socket0] 3
  dpm_suspend_noirq: c1a0d998 [pcmcia_socket0] 3
  dpm_resume_noirq: c1a0d998 [pcmcia_socket0] 3
  dpm_resume: c1a0d998 [pcmcia_socket0] 3
  dpm_complete: c1a0d998 [pcmcia_socket0] 2

4th:

  dpm_prepare: c1a0d998 [pcmcia_socket0] 2
  dpm_suspend: c1a0d998 [pcmcia_socket0] 2
  dpm_suspend_noirq: c1a0d998 [pcmcia_socket0] 2
  dpm_resume_noirq: c1a0d998 [pcmcia_socket0] 2
  dpm_resume: c1a0d998 [pcmcia_socket0] 2
  dpm_complete: c1a0d998 [pcmcia_socket0] 1

5th:

  dpm_prepare: c1a0d998 [pcmcia_socket0] 1
  dpm_suspend: c1a0d998 [pcmcia_socket0] 1
  dpm_suspend_noirq: c1a0d998 [pcmcia_socket0] 1
  dpm_resume_noirq: c1a0d998 [pcmcia_socket0] 1
  dpm_resume: c1a0d998 [pcmcia_socket0] 1
  dpm_complete: c1a0d998 [pcmcia_socket0] 0
  ------------[ cut here ]------------
  WARNING: at include/linux/kref.h:41 kobject_get+0x28/0x50()
  Modules linked in: ucb1x00_core
  Backtrace:
  [<c0212090>] (dump_backtrace+0x0/0x110) from [<c04799dc>] (dump_stack+0x18/0x1c)
  [<c04799c4>] (dump_stack+0x0/0x1c) from [<c021cba0>] (warn_slowpath_common+0x50/0x68)
  [<c021cb50>] (warn_slowpath_common+0x0/0x68) from [<c021cbdc>] (warn_slowpath_null+0x24/0x28)
  [<c021cbb8>] (warn_slowpath_null+0x0/0x28) from [<c0335374>] (kobject_get+0x28/0x50)
  [<c033534c>] (kobject_get+0x0/0x50) from [<c03804f4>] (get_device+0x1c/0x24)
  [<c0388c90>] (dpm_complete+0x0/0x1a0) from [<c0389cc0>] (dpm_resume_end+0x1c/0x20)
  ...

Looking at commit 7b24e79882 ("pcmcia: split up central event handler"),
the following change was made to cs.c:

                return 0;
        }
 #endif
-
-       send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+       if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+               skt->callback->early_resume(skt);
        return 0;
 }

And the corresponding change in ds.c is from:

-static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
-{
-       struct pcmcia_socket *s = pcmcia_get_socket(skt);
...
-       switch (event) {
...
-       case CS_EVENT_PM_RESUME:
-               if (verify_cis_cache(skt) != 0) {
-                       dev_dbg(&skt->dev, "cis mismatch - different card\n");
-                       /* first, remove the card */
-                       ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
-                       mutex_lock(&s->ops_mutex);
-                       destroy_cis_cache(skt);
-                       kfree(skt->fake_cis);
-                       skt->fake_cis = NULL;
-                       s->functions = 0;
-                       mutex_unlock(&s->ops_mutex);
-                       /* now, add the new card */
-                       ds_event(skt, CS_EVENT_CARD_INSERTION,
-                                CS_EVENT_PRI_LOW);
-               }
-               break;
...
-    }

-    pcmcia_put_socket(s);

-    return 0;
-} /* ds_event */

to:

+static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
+{
+       if (!verify_cis_cache(skt)) {
+               pcmcia_put_socket(skt);
+               return 0;
+       }

+       dev_dbg(&skt->dev, "cis mismatch - different card\n");

+       /* first, remove the card */
+       pcmcia_bus_remove(skt);
+       mutex_lock(&skt->ops_mutex);
+       destroy_cis_cache(skt);
+       kfree(skt->fake_cis);
+       skt->fake_cis = NULL;
+       skt->functions = 0;
+       mutex_unlock(&skt->ops_mutex);

+       /* now, add the new card */
+       pcmcia_bus_add(skt);
+       return 0;
+}

As can be seen, the original function called pcmcia_get_socket() and
pcmcia_put_socket() around the guts, whereas the replacement code
calls pcmcia_put_socket() only in one path.  This creates an imbalance
in the refcounting.

Testing with pcmcia_put_socket() put removed shows that the bug is gone:

  dpm_suspend: c1a10998 [pcmcia_socket0] 5
  dpm_suspend_noirq: c1a10998 [pcmcia_socket0] 5
  dpm_resume_noirq: c1a10998 [pcmcia_socket0] 5
  dpm_resume: c1a10998 [pcmcia_socket0] 5
  dpm_complete: c1a10998 [pcmcia_socket0] 5

Tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-02-08 19:03:51 -08:00
..
at91_cf.c treewide: Convert uses of struct resource to resource_size(ptr) 2011-06-10 14:55:36 +02:00
bcm63xx_pcmcia.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
bcm63xx_pcmcia.h
bfin_cf_pcmcia.c drivers: Final irq namespace conversion 2011-03-29 14:48:19 +02:00
cardbus.c pcmcia: replace struct irq with uint pcmcia_irq in struct pcmcia_socket 2010-05-10 10:23:12 +02:00
cirrus.h pcmcia: drop already defined PCI_IDs 2009-10-24 17:13:01 +02:00
cistpl.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
cs_internal.h pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
cs.c pcmcia: fix unused function compile warning 2010-10-14 11:47:16 +02:00
db1xxx_ss.c MIPS: Alchemy: Basic support for the DB1300 board. 2011-12-07 22:02:06 +00:00
ds.c pcmcia: fix socket refcount decrementing on each resume 2012-02-08 19:03:51 -08:00
electra_cf.c treewide: Convert uses of struct resource to resource_size(ptr) 2011-06-10 14:55:36 +02:00
i82092.c Fix common misspellings 2011-03-31 11:26:23 -03:00
i82092aa.h
i82365.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
i82365.h pcmcia: honor saved flags in yenta_socket's I365_CSCINT register 2010-03-15 14:50:15 +01:00
Kconfig MIPS: Alchemy: Basic support for the DB1300 board. 2011-12-07 22:02:06 +00:00
m8xx_pcmcia.c dt: Eliminate of_platform_{,un}register_driver 2011-02-28 13:22:46 -07:00
m32r_cfc.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
m32r_cfc.h tree-wide: fix comment/printk typos 2010-11-01 15:38:34 -04:00
m32r_pcc.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
m32r_pcc.h tree-wide: fix comment/printk typos 2010-11-01 15:38:34 -04:00
Makefile MIPS: Alchemy: remove PB1000 support 2011-12-07 22:02:05 +00:00
o2micro.h pcmcia/yenta: guide users in case of problems with O2-bridges 2010-10-15 14:31:47 +02:00
omap_cf.c pcmcia: replace struct irq with uint pcmcia_irq in struct pcmcia_socket 2010-05-10 10:23:12 +02:00
pcmcia_cis.c pcmcia: use autoconfiguration feature for ioports and iomem 2010-09-29 17:20:24 +02:00
pcmcia_resource.c Revert wrong fixes for common misspellings 2011-04-26 23:31:11 -07:00
pd6729.c pd6729: Coding Style fixes 2010-11-10 14:29:09 +01:00
pd6729.h pd6729: Coding Style fixes 2010-11-10 14:29:09 +01:00
pxa2xx_balloon3.c ARM: pxa: use correct __iomem annotations 2011-10-08 21:03:07 +08:00
pxa2xx_base.c ARM: PXA: fix lubbock PCMCIA driver build error 2011-11-05 19:09:40 +00:00
pxa2xx_base.h pcmcia vs. MECR on pxa25x/sa1111 2011-02-19 12:22:35 +01:00
pxa2xx_cm_x2xx.c ARM: PXA: fix includes in pxa2xx_cm_x2xx PCMCIA driver 2011-11-05 22:26:46 +00:00
pxa2xx_cm_x255.c driver: pcmcia: replace IRQ_GPIO() with gpio_to_irq() 2011-11-15 19:09:56 +08:00
pxa2xx_cm_x270.c driver: pcmcia: replace IRQ_GPIO() with gpio_to_irq() 2011-11-15 19:09:56 +08:00
pxa2xx_colibri.c pcmcia: pxa2xx: remove empty socket_init / socket_resume functions. 2011-07-29 17:55:13 +02:00
pxa2xx_e740.c pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() 2011-12-28 10:14:04 +00:00
pxa2xx_lubbock.c Fix common misspellings 2011-03-31 11:26:23 -03:00
pxa2xx_mainstone.c pcmcia: pxa2xx: remove empty socket_init / socket_resume functions. 2011-07-29 17:55:13 +02:00
pxa2xx_palmld.c pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() 2011-12-28 10:14:04 +00:00
pxa2xx_palmtc.c pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() 2011-12-28 10:14:04 +00:00
pxa2xx_palmtx.c pcmcia: pxa2xx: remove empty socket_init / socket_resume functions. 2011-07-29 17:55:13 +02:00
pxa2xx_sharpsl.c ARM: scoop: drop pcmcia_init callback 2011-07-11 14:43:32 +08:00
pxa2xx_stargate2.c pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() 2011-12-28 10:14:04 +00:00
pxa2xx_trizeps4.c pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() 2011-12-28 10:14:04 +00:00
pxa2xx_viper.c pcmcia: pxa2xx: remove empty socket_init / socket_resume functions. 2011-07-29 17:55:13 +02:00
pxa2xx_vpac270.c pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() 2011-12-28 10:14:04 +00:00
ricoh.h
rsrc_iodyn.c treewide: Convert uses of struct resource to resource_size(ptr) 2011-06-10 14:55:36 +02:00
rsrc_mgr.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
rsrc_nonstatic.c treewide: Convert uses of struct resource to resource_size(ptr) 2011-06-10 14:55:36 +02:00
sa11xx_base.c fix typos concerning "initiali[zs]e" 2010-06-16 18:05:05 +02:00
sa11xx_base.h PCMCIA: sa1111: wrap soc_pcmcia_socket to contain sa1111 specific data 2009-11-09 08:30:11 +01:00
sa1100_assabet.c pcmcia/sa1100: don't put machine specific init functions in .init.text 2010-11-10 14:30:01 +01:00
sa1100_badge4.c PCMCIA: sa1111: remove duplicated initializers 2009-11-09 08:30:12 +01:00
sa1100_cerf.c pcmcia/sa1100: don't put machine specific init functions in .init.text 2010-11-10 14:30:01 +01:00
sa1100_generic.c pcmcia/sa1100: put sa11x0_pcmcia_hw_init[] to .devinit.data 2011-05-06 07:46:11 +02:00
sa1100_generic.h ARM: 6458/1: pcmcia: Adds nanoEngine PCMCIA support. 2010-12-21 14:53:45 +00:00
sa1100_h3600.c pcmcia/sa1100: don't put machine specific init functions in .init.text 2010-11-10 14:30:01 +01:00
sa1100_jornada720.c PCMCIA: sa1111: remove duplicated initializers 2009-11-09 08:30:12 +01:00
sa1100_nanoengine.c drivers: Final irq namespace conversion 2011-03-29 14:48:19 +02:00
sa1100_neponset.c PCMCIA: sa1111: remove duplicated initializers 2009-11-09 08:30:12 +01:00
sa1100_shannon.c pcmcia/sa1100: don't put machine specific init functions in .init.text 2010-11-10 14:30:01 +01:00
sa1100_simpad.c ARM: 7024/1: simpad: Cleanup CS3 accessors. 2011-10-17 09:12:42 +01:00
sa1111_generic.c PCMCIA: fix sa1111 oops on remove 2012-01-24 21:33:26 +00:00
sa1111_generic.h PCMCIA: sa1111: remove duplicated initializers 2009-11-09 08:30:12 +01:00
soc_common.c drivers:pcmcia:soc_common: make socket_init and socket_suspend optional 2011-07-29 17:55:10 +02:00
soc_common.h ARM: pxa: remove get_memclk_frequency_10khz() 2010-12-16 14:31:19 +08:00
socket_sysfs.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
tcic.c pcmcia: convert pcmcia_request_configuration to pcmcia_enable_device 2010-09-29 17:20:23 +02:00
tcic.h
ti113x.h Fix common misspellings 2011-03-31 11:26:23 -03:00
topic.h pcmcia: correct handling for Zoomed Video registers in topic.h 2009-11-11 19:34:27 +01:00
vg468.h
vrc4171_card.c pcmcia: use dev_pm_ops for class pcmcia_socket_class 2010-03-24 11:00:11 +01:00
vrc4173_cardu.c pcmcia: vrc4173_cardu: Fix error path for pci_release_regions and pci_disable_device 2010-10-05 15:49:51 +02:00
vrc4173_cardu.h
xxs1500_ss.c drivers: Final irq namespace conversion 2011-03-29 14:48:19 +02:00
yenta_socket.c module_param: make bool parameters really bool (drivers & misc) 2012-01-13 09:32:20 +10:30
yenta_socket.h