]> git.neil.brown.name Git - history.git/commitdiff
ISDN: Protect ipc_head list
authorKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
Wed, 18 Jun 2003 18:57:08 +0000 (13:57 -0500)
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
Wed, 18 Jun 2003 18:57:08 +0000 (13:57 -0500)
Make sure that the ipc_head list cannot change under us by
protecting it with a spin lock.

drivers/isdn/i4l/isdn_ppp_ccp.c

index ad58aaf27d64bf575d7287ba2ecd9b54627cc697..6e559e89d01e91794e744f21200071d9602ffb77 100644 (file)
@@ -557,6 +557,7 @@ ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb)
 }
 
 static LIST_HEAD(ipc_head);
+static spinlock_t ipc_head_lock;
 
 int
 ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit,
@@ -571,43 +572,48 @@ ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit,
                printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit,
                       data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num);
 
+       spin_lock(&ipc_head_lock);
        list_for_each_entry(ipc, &ipc_head, list) {
-               if (ipc->num != num)
-                       continue;
-               
-               if (!try_module_get(ipc->owner))
-                       continue;
-
-               stat = ipc->alloc(data);
-               if (!stat) {
-                       printk(KERN_ERR "Can't alloc (de)compression!\n");
-                       module_put(ipc->owner);
-                       break;
-               }
-               ret = ipc->init(stat, data, unit, 0);
-               if(!ret) {
-                       printk(KERN_ERR "Can't init (de)compression!\n");
-                       ipc->free(stat);
-                       module_put(ipc->owner);
-                       break;
+               if (ipc->num == num &&
+                   try_module_get(ipc->owner))
+                       goto found;
+       }
+       spin_unlock(&ipc_head_lock);
+       return -EINVAL;
+
+ found:
+       spin_unlock(&ipc_head_lock);
+
+       stat = ipc->alloc(data);
+       if (!stat) {
+               printk(KERN_ERR "Can't alloc (de)compression!\n");
+               goto err;
+       }
+       ret = ipc->init(stat, data, unit, 0);
+       if(!ret) {
+               printk(KERN_ERR "Can't init (de)compression!\n");
+               ipc->free(stat);
+               goto err;
+       }
+       if (data->flags & IPPP_COMP_FLAG_XMIT) {
+               if (ccp->comp_stat) {
+                       ccp->compressor->free(ccp->comp_stat);
+                       module_put(ccp->compressor->owner);
                }
-               if (data->flags & IPPP_COMP_FLAG_XMIT) {
-                       if (ccp->comp_stat) {
-                               ccp->compressor->free(ccp->comp_stat);
-                               module_put(ccp->compressor->owner);
-                       }
                        ccp->comp_stat = stat;
                        ccp->compressor = ipc;
-               } else {
-                       if (ccp->decomp_stat) {
-                               ccp->decompressor->free(ccp->decomp_stat);
-                               module_put(ccp->decompressor->owner);
-                       }
-                       ccp->decomp_stat = stat;
-                       ccp->decompressor = ipc;
+       } else {
+               if (ccp->decomp_stat) {
+                       ccp->decompressor->free(ccp->decomp_stat);
+                       module_put(ccp->decompressor->owner);
                }
-               return 0;
+               ccp->decomp_stat = stat;
+               ccp->decompressor = ipc;
        }
+       return 0;
+
+ err:
+       module_put(ipc->owner);
        return -EINVAL;
 }
 
@@ -618,25 +624,34 @@ ippp_ccp_get_compressors(unsigned long protos[8])
        int i, j;
 
        memset(protos, 0, sizeof(unsigned long) * 8);
+
+       spin_lock(&ipc_head_lock);
        list_for_each_entry(ipc, &ipc_head, list) {
                j = ipc->num / (sizeof(long)*8);
                i = ipc->num % (sizeof(long)*8);
                if (j < 8)
                        protos[j] |= 1 << i;
        }
+       spin_unlock(&ipc_head_lock);
 }
 
 int
 isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
+       spin_lock(&ipc_head_lock);
        list_add_tail(&ipc->list, &ipc_head);
+       spin_unlock(&ipc_head_lock);
+
        return 0;
 }
 
 int
 isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
 {
+       spin_lock(&ipc_head_lock);
        list_del(&ipc->list);
+       spin_unlock(&ipc_head_lock);
+
        return 0;
 }