Hey,

On Thu, Jan 07, 2010 at 09:56:59PM +0900, Komuro wrote:
> I got the kernel-oops by pcmcia-check-broken-cis
> at kernel 2.6.33-rc3.
> 
> Do you think this is the same as CIS problem?

I have a bad feeling about this... might it be that cistpl.c isn't thread
safe at all?

Could you test out this patch, please?

Thanks,
        Dominik


diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 25b1cd2..b7eec6e 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -64,6 +64,7 @@ module_param(cis_width, int, 0444);
 
 void release_cis_mem(struct pcmcia_socket *s)
 {
+    mutex_lock(&s->card_mutex);
     if (s->cis_mem.flags & MAP_ACTIVE) {
        s->cis_mem.flags &= ~MAP_ACTIVE;
        s->ops->set_mem_map(s, &s->cis_mem);
@@ -75,6 +76,7 @@ void release_cis_mem(struct pcmcia_socket *s)
        iounmap(s->cis_virt);
        s->cis_virt = NULL;
     }
+    mutex_unlock(&s->card_mutex);
 }
 EXPORT_SYMBOL(release_cis_mem);
 
@@ -89,11 +91,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int 
card_offset, unsigned int flag
        pccard_mem_map *mem = &s->cis_mem;
        int ret;
 
+       mutex_lock(&s->card_mutex);
        if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
                mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 
0, s);
                if (mem->res == NULL) {
                        dev_printk(KERN_NOTICE, &s->dev,
                                   "cs: unable to map card memory!\n");
+                       mutex_unlock(&s->card_mutex);
                        return NULL;
                }
                s->cis_virt = NULL;
@@ -109,6 +113,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int 
card_offset, unsigned int flag
        if (ret) {
                iounmap(s->cis_virt);
                s->cis_virt = NULL;
+               mutex_unlock(&s->card_mutex);
                return NULL;
        }
 
@@ -117,6 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int 
card_offset, unsigned int flag
                        iounmap(s->cis_virt);
                s->cis_virt = ioremap(mem->static_start, s->map_size);
        }
+       mutex_unlock(&s->card_mutex);
 
        return s->cis_virt;
 }
@@ -271,27 +277,34 @@ static void read_cis_cache(struct pcmcia_socket *s, int 
attr, u_int addr,
     struct cis_cache_entry *cis;
     int ret;
 
+    mutex_lock(&s->card_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->card_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->card_mutex);
            return;
        }
     }
+    mutex_unlock(&s->card_mutex);
 
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS)
        ret = read_cb_mem(s, attr, addr, len, ptr);
     else
 #endif
+    {
+       mutex_lock(&s->card_mutex);
        ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
+    }
 
        if (ret == 0) {
                /* Copy data into the cache */
@@ -304,6 +317,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int 
attr, u_int addr,
                        list_add(&cis->node, &s->cis_cache);
                }
        }
+       mutex_unlock(&s->card_mutex);
 }
 
 static void
@@ -311,24 +325,28 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int 
addr, u_int len)
 {
        struct cis_cache_entry *cis;
 
+       mutex_lock(&s->card_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->card_mutex);
 }
 
 void destroy_cis_cache(struct pcmcia_socket *s)
 {
        struct list_head *l, *n;
 
+       mutex_lock(&s->card_mutex);
        list_for_each_safe(l, n, &s->cis_cache) {
                struct cis_cache_entry *cis = list_entry(l, struct 
cis_cache_entry, node);
 
                list_del(&cis->node);
                kfree(cis);
        }
+       mutex_unlock(&s->card_mutex);
 
        /*
         * If there was a fake CIS, destroy that as well.
@@ -356,6 +374,7 @@ int verify_cis_cache(struct pcmcia_socket *s)
                           "no memory for verifying CIS\n");
                return -ENOMEM;
        }
+       mutex_lock(&s->card_mutex);
        list_for_each_entry(cis, &s->cis_cache, node) {
                int len = cis->len;
 
@@ -369,10 +388,12 @@ int verify_cis_cache(struct pcmcia_socket *s)
                        pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
 
                if (memcmp(buf, cis->cache, len) != 0) {
+                       mutex_unlock(&s->card_mutex);
                        kfree(buf);
                        return -1;
                }
        }
+       mutex_unlock(&s->card_mutex);
        kfree(buf);
        return 0;
 }
@@ -391,14 +412,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->card_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->card_mutex);
                return -ENOMEM;
        }
        s->fake_cis_len = len;
        memcpy(s->fake_cis, data, len);
+       mutex_unlock(&s->card_mutex);
        return 0;
 }
 EXPORT_SYMBOL(pcmcia_replace_cis);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 6d6f82b..0b694b5 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -228,6 +228,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
        init_completion(&socket->socket_released);
        init_completion(&socket->thread_done);
        mutex_init(&socket->skt_mutex);
+       mutex_init(&socket->card_mutex);
        spin_lock_init(&socket->thread_lock);
 
        if (socket->resource_ops->init) {
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index cbfba88..fa76a6b 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -237,6 +237,9 @@ struct pcmcia_socket {
        /* for adding further pseudo-multifunction devices */
        struct work_struct              device_add;
 
+       /* protects card h/w state */
+       struct mutex                    card_mutex;
+
 #ifdef CONFIG_PCMCIA_IOCTL
        struct user_info_t              *user;
        wait_queue_head_t               queue;

_______________________________________________
Linux PCMCIA reimplementation list
http://lists.infradead.org/mailman/listinfo/linux-pcmcia

Reply via email to