param: lock if_sdio's lbs_helper_name and lbs_fw_name against sysfs changes.
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 12 Aug 2010 05:04:33 +0000 (23:04 -0600)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 11 Aug 2010 13:34:37 +0000 (23:04 +0930)
Since it can be changed via sysfs, we need to make a copy.  This most
generic way of doing this is to keep a flag so we know when to free it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Cc: Dan Williams <dcbw@redhat.com>
Cc: John W. Linville <linville@tuxdriver.com>
Cc: libertas-dev@lists.infradead.org
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
drivers/net/wireless/libertas/if_sdio.c

index 6e71346a75505a4398964a2889eef4803822f5a4..ba854c70ab9455b8e18a63fa254e18671f447232 100644 (file)
@@ -125,6 +125,8 @@ struct if_sdio_card {
 
        const char              *helper;
        const char              *firmware;
+       bool                    helper_allocated;
+       bool                    firmware_allocated;
 
        u8                      buffer[65536];
 
@@ -984,16 +986,34 @@ static int if_sdio_probe(struct sdio_func *func,
        card->helper = if_sdio_models[i].helper;
        card->firmware = if_sdio_models[i].firmware;
 
+       kparam_block_sysfs_write(helper_name);
        if (lbs_helper_name) {
+               char *helper = kstrdup(lbs_helper_name, GFP_KERNEL);
+               if (!helper) {
+                       kparam_unblock_sysfs_write(helper_name);
+                       ret = -ENOMEM;
+                       goto free;
+               }
                lbs_deb_sdio("overriding helper firmware: %s\n",
                        lbs_helper_name);
-               card->helper = lbs_helper_name;
+               card->helper = helper;
+               card->helper_allocated = true;
        }
+       kparam_unblock_sysfs_write(helper_name);
 
+       kparam_block_sysfs_write(fw_name);
        if (lbs_fw_name) {
+               char *fw_name = kstrdup(lbs_fw_name, GFP_KERNEL);
+               if (!fw_name) {
+                       kparam_unblock_sysfs_write(fw_name);
+                       ret = -ENOMEM;
+                       goto free;
+               }
                lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
-               card->firmware = lbs_fw_name;
+               card->firmware = fw_name;
+               card->firmware_allocated = true;
        }
+       kparam_unblock_sysfs_write(fw_name);
 
        sdio_claim_host(func);
 
@@ -1127,6 +1147,10 @@ free:
                kfree(packet);
        }
 
+       if (card->helper_allocated)
+               kfree(card->helper);
+       if (card->firmware_allocated)
+               kfree(card->firmware);
        kfree(card);
 
        goto out;
@@ -1177,6 +1201,10 @@ static void if_sdio_remove(struct sdio_func *func)
                kfree(packet);
        }
 
+       if (card->helper_allocated)
+               kfree(card->helper);
+       if (card->firmware_allocated)
+               kfree(card->firmware);
        kfree(card);
 
        lbs_deb_leave(LBS_DEB_SDIO);