From d6d1b650ae6acce73d55dd0246de22180303ae73 Mon Sep 17 00:00:00 2001
From: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed, 11 Aug 2010 23:04:27 -0600
Subject: param: simple locking for sysfs-writable charp parameters

Since the writing to sysfs can free the old one, we need to block that
when we access the charp variables.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Tested-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Dan Williams <dcbw@redhat.com>
Cc: John W. Linville <linville@tuxdriver.com>
Cc: Jing Huang <huangj@brocade.com>
Cc: James E.J. Bottomley <James.Bottomley@suse.de>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: user-mode-linux-devel@lists.sourceforge.net
Cc: libertas-dev@lists.infradead.org
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-scsi@vger.kernel.org
Cc: linux-usb@vger.kernel.org
---
 drivers/net/wireless/libertas/if_usb.c    | 3 +++
 drivers/net/wireless/libertas_tf/if_usb.c | 3 +++
 2 files changed, 6 insertions(+)

(limited to 'drivers/net/wireless')

diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 07ece9d26c63..3ff61063671a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -289,10 +289,13 @@ static int if_usb_probe(struct usb_interface *intf,
 	}
 
 	/* Upload firmware */
+	kparam_block_sysfs_write(fw_name);
 	if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
+		kparam_unblock_sysfs_write(fw_name);
 		lbs_deb_usbd(&udev->dev, "FW upload failed\n");
 		goto err_prog_firmware;
 	}
+	kparam_unblock_sysfs_write(fw_name);
 
 	if (!(priv = lbs_add_card(cardp, &udev->dev)))
 		goto err_prog_firmware;
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index b172f5d87a3b..41a4f214ade1 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -811,12 +811,15 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
 
 	lbtf_deb_enter(LBTF_DEB_USB);
 
+	kparam_block_sysfs_write(fw_name);
 	ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
 	if (ret < 0) {
 		pr_err("request_firmware() failed with %#x\n", ret);
 		pr_err("firmware %s not found\n", lbtf_fw_name);
+		kparam_unblock_sysfs_write(fw_name);
 		goto done;
 	}
+	kparam_unblock_sysfs_write(fw_name);
 
 	if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
 		goto release_fw;
-- 
cgit v1.2.1


From 886275ce41a9751117367fb387ed171049eb6148 Mon Sep 17 00:00:00 2001
From: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed, 11 Aug 2010 23:04:33 -0600
Subject: param: lock if_sdio's lbs_helper_name and lbs_fw_name against sysfs
 changes.

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 | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

(limited to 'drivers/net/wireless')

diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 6e71346a7550..ba854c70ab94 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -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);
-- 
cgit v1.2.1