From 8680c4b3faa298dc768c2a78a94a84d89854eca9 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jan 2010 22:05:36 +0100 Subject: pcmcia: also lock fake and cache CIS by ops_mutex Specifically, struct list_head cis_cache; size_t fake_cis_len; u8 *fake_cis; are protected. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 18 +++++++++++++++++- drivers/pcmcia/ds.c | 6 ++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 9ad66c9848e3..14de287a8bf6 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -277,20 +277,24 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, if (s->state & SOCKET_CARDBUS) return; + mutex_lock(&s->ops_mutex); if (s->fake_cis) { if (s->fake_cis_len >= addr+len) memcpy(ptr, s->fake_cis+addr, len); else memset(ptr, 0xff, len); + mutex_unlock(&s->ops_mutex); return; } list_for_each_entry(cis, &s->cis_cache, node) { if (cis->addr == addr && cis->len == len && cis->attr == attr) { memcpy(ptr, cis->cache, len); + mutex_unlock(&s->ops_mutex); return; } } + mutex_unlock(&s->ops_mutex); ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); @@ -302,7 +306,9 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, cis->len = len; cis->attr = attr; memcpy(cis->cache, ptr, len); + mutex_lock(&s->ops_mutex); list_add(&cis->node, &s->cis_cache); + mutex_unlock(&s->ops_mutex); } } } @@ -312,19 +318,22 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) { struct cis_cache_entry *cis; + mutex_lock(&s->ops_mutex); list_for_each_entry(cis, &s->cis_cache, node) if (cis->addr == addr && cis->len == len && cis->attr == attr) { list_del(&cis->node); kfree(cis); break; } + mutex_unlock(&s->ops_mutex); } /** * destroy_cis_cache() - destroy the CIS cache * @s: pcmcia_socket for which CIS cache shall be destroyed * - * This destroys the CIS cache but keeps any fake CIS alive. + * This destroys the CIS cache but keeps any fake CIS alive. Must be + * called with ops_mutex held. */ void destroy_cis_cache(struct pcmcia_socket *s) @@ -391,14 +400,17 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n"); return -EINVAL; } + mutex_lock(&s->ops_mutex); kfree(s->fake_cis); s->fake_cis = kmalloc(len, GFP_KERNEL); if (s->fake_cis == NULL) { dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n"); + mutex_unlock(&s->ops_mutex); return -ENOMEM; } s->fake_cis_len = len; memcpy(s->fake_cis, data, len); + mutex_unlock(&s->ops_mutex); return 0; } @@ -1461,7 +1473,9 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) return -EINVAL; /* We do not want to validate the CIS cache... */ + mutex_lock(&s->ops_mutex); destroy_cis_cache(s); + mutex_unlock(&s->ops_mutex); tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); if (tuple == NULL) { @@ -1518,7 +1532,9 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) done: /* invalidate CIS cache on failure */ if (!dev_ok || !ident_ok || !count) { + mutex_lock(&s->ops_mutex); destroy_cis_cache(s); + mutex_unlock(&s->ops_mutex); ret = -EIO; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 0ab4fe045920..4f7308df22c8 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1241,12 +1241,16 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) s->pcmcia_state.present = 0; pcmcia_card_remove(skt, NULL); handle_event(skt, event); + mutex_lock(&s->ops_mutex); destroy_cis_cache(s); + mutex_unlock(&s->ops_mutex); break; case CS_EVENT_CARD_INSERTION: s->pcmcia_state.present = 1; + mutex_lock(&s->ops_mutex); destroy_cis_cache(s); /* to be on the safe side... */ + mutex_unlock(&s->ops_mutex); pcmcia_card_add(skt); handle_event(skt, event); break; @@ -1259,9 +1263,11 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) 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; + mutex_unlock(&s->ops_mutex); /* now, add the new card */ ds_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); -- cgit v1.2.1