From 881f65f84efe837d2bb914d1f06682f0bc7580a1 Mon Sep 17 00:00:00 2001 From: Meng Zhang Date: Mon, 27 Feb 2012 08:24:19 +0100 Subject: USB: option: Add MediaTek MT6276M modem&app interfaces commit 0d8520a1d7f43328bc7085d4244d93c595064157 upstream. Add MEDIATEK products to Option driver Signed-off-by: Meng Zhang Signed-off-by: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 68fa8c7c162c..547c9b9ad19f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -484,6 +484,9 @@ static void option_instat_callback(struct urb *urb); #define LG_VENDOR_ID 0x1004 #define LG_PRODUCT_L02C 0x618f +/* MediaTek products */ +#define MEDIATEK_VENDOR_ID 0x0e8d + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1198,6 +1201,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) }, { USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */ + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3 From bbd5d3840cf705d141e6af6888b3aa14bee127ee Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Wed, 29 Feb 2012 15:32:05 +0100 Subject: USB: option driver: adding support for Telit CC864-SINGLE, CC864-DUAL and DE910-DUAL modems commit 7204cf584836c24b4b06e4ad4a8e6bb8ea84908e upstream. Adding PID for Telit CC864-SINGLE, CC864-DUAL and DE910-DUAL modems Signed-off-by: Daniele Palmas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 547c9b9ad19f..3c4b7df057a1 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -307,6 +307,9 @@ static void option_instat_callback(struct urb *urb); #define TELIT_VENDOR_ID 0x1bc7 #define TELIT_PRODUCT_UC864E 0x1003 #define TELIT_PRODUCT_UC864G 0x1004 +#define TELIT_PRODUCT_CC864_DUAL 0x1005 +#define TELIT_PRODUCT_CC864_SINGLE 0x1006 +#define TELIT_PRODUCT_DE910_DUAL 0x1010 /* ZTE PRODUCTS */ #define ZTE_VENDOR_ID 0x19d2 @@ -771,6 +774,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, -- cgit v1.2.3 From d86147440f519b20bdb78749f921edfe5620b589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 16 Mar 2012 12:56:44 +0100 Subject: USB: option: make interface blacklist work again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 963940cf472d76eca2d36296e461202cc6997352 upstream. commit 0d905fd "USB: option: convert Huawei K3765, K4505, K4605 reservered interface to blacklist" accidentally ANDed two blacklist tests by leaving out a return. This was not noticed because the two consecutive bracketless if statements made it syntactically correct. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 3c4b7df057a1..64109350420a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1373,6 +1373,7 @@ static int option_probe(struct usb_serial *serial, serial->interface->cur_altsetting->desc.bInterfaceNumber, OPTION_BLACKLIST_RESERVED_IF, (const struct option_blacklist_info *) id->driver_info)) + return -ENODEV; /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && -- cgit v1.2.3 From 0bd61423aaaa167455003c48b8c3d1f2b9dcc19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 16 Mar 2012 15:41:26 +0100 Subject: USB: option: add ZTE MF820D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5889d3d4209c1050b4a3c96c41faf6c0976a4acf upstream. This device presents a total of 5 interfaces with ff/ff/ff class/subclass/protocol. The last one of these is verified to be a QMI/wwan combined interface which should be handled by the qmi_wwan driver, so we blacklist it here. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 64109350420a..54898c995afb 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -901,6 +901,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, -- cgit v1.2.3 From 32c5edbdda0e9737b0667036ef1210eb0284c54b Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Mon, 20 Feb 2012 13:11:49 +0100 Subject: staging: zcache: avoid AB-BA deadlock condition commit cfbc6a92212e74b07aa76c9e2f20c542e36077fb upstream. Commit 9256a47 fixed a deadlock condition, being sure that the buddy list spinlock is always taken before the page spinlock. However in zbud_free_and_delist() locking order is the opposite (page lock -> list lock). Possible unsafe locking scenario (reported by lockdep): CPU0 CPU1 ---- ---- lock(&(&zbpg->lock)->rlock); lock(zbud_budlists_spinlock); lock(&(&zbpg->lock)->rlock); lock(zbud_budlists_spinlock); Fix by grabbing the locks in opposite order in zbud_free_and_delist(). Signed-off-by: Andrea Righi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/zcache/zcache-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index f5e469d588d3..16ad9febf298 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -299,10 +299,12 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) struct zbud_page *zbpg = container_of(zh, struct zbud_page, buddy[budnum]); + spin_lock(&zbud_budlists_spinlock); spin_lock(&zbpg->lock); if (list_empty(&zbpg->bud_list)) { /* ignore zombie page... see zbud_evict_pages() */ spin_unlock(&zbpg->lock); + spin_unlock(&zbud_budlists_spinlock); return; } size = zbud_free(zh); @@ -310,7 +312,6 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0]; if (zh_other->size == 0) { /* was unbuddied: unlist and free */ chunks = zbud_size_to_chunks(size) ; - spin_lock(&zbud_budlists_spinlock); BUG_ON(list_empty(&zbud_unbuddied[chunks].list)); list_del_init(&zbpg->bud_list); zbud_unbuddied[chunks].count--; @@ -318,7 +319,6 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) zbud_free_raw_page(zbpg); } else { /* was buddied: move remaining buddy to unbuddied list */ chunks = zbud_size_to_chunks(zh_other->size) ; - spin_lock(&zbud_budlists_spinlock); list_del_init(&zbpg->bud_list); zcache_zbud_buddied_count--; list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list); -- cgit v1.2.3 From 63b9e81c411c2221260124d4a167aab4c24ff603 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 28 Feb 2012 09:20:09 -0800 Subject: USB: ftdi_sio: fix problem when the manufacture is a NULL string commit 656d2b3964a9d0f9864d472f8dfa2dd7dd42e6c0 upstream. On some misconfigured ftdi_sio devices, if the manufacturer string is NULL, the kernel will oops when the device is plugged in. This patch fixes the problem. Reported-by: Wojciech M Zabolotny Tested-by: Wojciech M Zabolotny Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f030471363e1..d170b2ad11a2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1763,7 +1763,8 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) dbg("%s", __func__); - if (strcmp(udev->manufacturer, "CALAO Systems") == 0) + if ((udev->manufacturer) && + (strcmp(udev->manufacturer, "CALAO Systems") == 0)) return ftdi_jtag_probe(serial); return 0; -- cgit v1.2.3 From 65ad87ff57ca0150596d7bf1349f42392d40ebda Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 29 Feb 2012 10:05:37 +0100 Subject: USB: ftdi_sio: add support for BeagleBone rev A5+ commit 444aa7fa9bd752d19ce472d3e02558b987c3cc67 upstream. BeagleBone changed to the default FTDI 0403:6010 id in rev A5 to make life easier for Windows users, so we need a similar workaround as the Calao board to support it. Signed-off-by: Peter Korsgaard Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d170b2ad11a2..30839d4cd7f7 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1763,8 +1763,8 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) dbg("%s", __func__); - if ((udev->manufacturer) && - (strcmp(udev->manufacturer, "CALAO Systems") == 0)) + if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || + (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) return ftdi_jtag_probe(serial); return 0; -- cgit v1.2.3 From 59df038acf5b2687e401b42cb524dc472d554e3d Mon Sep 17 00:00:00 2001 From: Bruno Thomsen Date: Sun, 4 Mar 2012 15:19:14 +0100 Subject: USB: Microchip VID mislabeled as Hornby VID in ftdi_sio. commit c1cee1d84001815a1b4321c49b995254c0df3100 upstream. Microchip VID (0x04d8) was mislabeled as Hornby VID according to USB-IDs. A Full Speed USB Demo Board PID (0x000a) was mislabeled as Hornby Elite (an Digital Command Controller Console for model railways). Most likely the Hornby based their design on PIC18F87J50 Full Speed USB Demo Board. Signed-off-by: Bruno Thomsen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 +- drivers/usb/serial/ftdi_sio_ids.h | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 30839d4cd7f7..363e99556767 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -797,7 +797,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(HORNBY_VID, HORNBY_ELITE_PID) }, + { USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 4eb77150f035..df87939be32e 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -532,10 +532,14 @@ #define ADI_GNICEPLUS_PID 0xF001 /* - * Hornby Elite + * Microchip Technology, Inc. + * + * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by: + * Hornby Elite - Digital Command Control Console + * http://www.hornby.com/hornby-dcc/controllers/ */ -#define HORNBY_VID 0x04D8 -#define HORNBY_ELITE_PID 0x000A +#define MICROCHIP_VID 0x04D8 +#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */ /* * RATOC REX-USB60F -- cgit v1.2.3 From fe9d085752d475f02bb377bc5d3e191f31482344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Wr=C3=B3bel?= Date: Fri, 9 Mar 2012 14:40:18 +0100 Subject: USB: ftdi_sio: new PID: Distortec JTAG-lock-pick MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 47594d5528f28a4c025c2955c68104c75815637c upstream. Signed-off-by: Michał Wróbel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 363e99556767..a319eaae03e6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -846,6 +846,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, + { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index df87939be32e..bed1b1f37e89 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -97,6 +97,8 @@ #define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ #define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ +#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8 + /* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ /* the VID is the standard ftdi vid (FTDI_VID) */ #define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ -- cgit v1.2.3 From 73cd08ed12d435ee5c50af6dc684036e6d7b7e29 Mon Sep 17 00:00:00 2001 From: Jim Paris Date: Wed, 14 Mar 2012 17:54:25 -0400 Subject: USB: ftdi_sio: add support for FT-X series devices commit dc0827c128c0ee5a58b822b99d662b59f4b8e970 upstream. Add PID 0x6015, corresponding to the new series of FT-X chips (FT220XD, FT201X, FT220X, FT221X, FT230X, FT231X, FT240X). They all appear as serial devices, and seem indistinguishable except for the default product string stored in their EEPROM. The baudrate generation matches FT232RL devices. Tested with a FT201X and FT230X at various baudrates (100 - 3000000). Sample dmesg: ftdi_sio: v1.6.0:USB FTDI Serial Converters Driver usb 2-1: new full-speed USB device number 6 using ohci_hcd usb 2-1: New USB device found, idVendor=0403, idProduct=6015 usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 2-1: Product: FT230X USB Half UART usb 2-1: Manufacturer: FTDI usb 2-1: SerialNumber: DC001WI6 ftdi_sio 2-1:1.0: FTDI USB Serial Device converter detected drivers/usb/serial/ftdi_sio.c: ftdi_sio_port_probe drivers/usb/serial/ftdi_sio.c: ftdi_determine_type: bcdDevice = 0x1000, bNumInterfaces = 1 usb 2-1: Detected FT-X usb 2-1: Number of endpoints 2 usb 2-1: Endpoint 1 MaxPacketSize 64 usb 2-1: Endpoint 2 MaxPacketSize 64 usb 2-1: Setting MaxPacketSize 64 drivers/usb/serial/ftdi_sio.c: read_latency_timer drivers/usb/serial/ftdi_sio.c: write_latency_timer: setting latency timer = 1 drivers/usb/serial/ftdi_sio.c: create_sysfs_attrs drivers/usb/serial/ftdi_sio.c: sysfs attributes for FT-X usb 2-1: FTDI USB Serial Device converter now attached to ttyUSB0 Signed-off-by: Jim Paris Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 20 +++++++++++++++----- drivers/usb/serial/ftdi_sio.h | 3 ++- drivers/usb/serial/ftdi_sio_ids.h | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a319eaae03e6..b64fddcf8913 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -188,6 +188,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk }, { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -870,7 +871,8 @@ static const char *ftdi_chip_name[] = { [FT232RL] = "FT232RL", [FT2232H] = "FT2232H", [FT4232H] = "FT4232H", - [FT232H] = "FT232H" + [FT232H] = "FT232H", + [FTX] = "FT-X" }; @@ -1171,7 +1173,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, break; case FT232BM: /* FT232BM chip */ case FT2232C: /* FT2232C chip */ - case FT232RL: + case FT232RL: /* FT232RL chip */ + case FTX: /* FT-X series */ if (baud <= 3000000) { __u16 product_id = le16_to_cpu( port->serial->dev->descriptor.idProduct); @@ -1460,10 +1463,14 @@ static void ftdi_determine_type(struct usb_serial_port *port) } else if (version < 0x900) { /* Assume it's an FT232RL */ priv->chip_type = FT232RL; - } else { + } else if (version < 0x1000) { /* Assume it's an FT232H */ priv->chip_type = FT232H; + } else { + /* Assume it's an FT-X series device */ + priv->chip_type = FTX; } + dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); } @@ -1591,7 +1598,8 @@ static int create_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT232RL || priv->chip_type == FT2232H || priv->chip_type == FT4232H || - priv->chip_type == FT232H)) { + priv->chip_type == FT232H || + priv->chip_type == FTX)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } @@ -1613,7 +1621,8 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT232RL || priv->chip_type == FT2232H || priv->chip_type == FT4232H || - priv->chip_type == FT232H) { + priv->chip_type == FT232H || + priv->chip_type == FTX) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2287,6 +2296,7 @@ static int ftdi_tiocmget(struct tty_struct *tty) case FT2232H: case FT4232H: case FT232H: + case FTX: len = 2; break; default: diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 19584faa86f9..ed58c6fa8dbe 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -157,7 +157,8 @@ enum ftdi_chip_type { FT232RL = 5, FT2232H = 6, FT4232H = 7, - FT232H = 8 + FT232H = 8, + FTX = 9, }; enum ftdi_sio_baudrate { diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index bed1b1f37e89..ac1c42ee679e 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -23,6 +23,7 @@ #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ #define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ +#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ -- cgit v1.2.3 From 4c9da75cb251ae99c5afe98b79c5a56b17fa0a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Wr=C3=B3bel?= Date: Thu, 15 Mar 2012 17:24:04 +0100 Subject: USB: ftdi_sio: new PID: LUMEL PD12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 57e596f3af88ef52dea9640ed5e34ecd38893a02 upstream. Signed-off-by: Michał Wróbel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b64fddcf8913..3f3ccf63bb2c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -849,6 +849,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index ac1c42ee679e..abf6bbcdaf4f 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -30,6 +30,8 @@ /*** third-party PIDs (using FTDI_VID) ***/ +#define FTDI_LUMEL_PD12_PID 0x6002 + /* * Marvell OpenRD Base, Client * http://www.open-rd.org -- cgit v1.2.3 From 5856307bd35ec6586ee6fa513ee32516cacb7ff6 Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Thu, 16 Feb 2012 18:02:20 +0800 Subject: powerpc/usb: fix bug of kernel hang when initializing usb commit 28c56ea1431421dec51b7b229369e991481453df upstream. If USB UTMI PHY is not enable, writing to portsc register will lead to kernel hang during boot up. Signed-off-by: Shengzhou Liu Reported-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 4 ++++ drivers/usb/host/ehci-fsl.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b556a72264d1..da487fde475f 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -216,6 +216,8 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, unsigned int port_offset) { u32 portsc; + struct usb_hcd *hcd = ehci_to_hcd(ehci); + void __iomem *non_ehci = hcd->regs; portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); @@ -231,6 +233,8 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + /* enable UTMI PHY */ + setbits32(non_ehci + FSL_SOC_USB_CTRL, CTRL_UTMI_PHY_EN); portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 491806221165..bea5013ab7f5 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -45,5 +45,6 @@ #define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */ #define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */ #define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */ +#define CTRL_UTMI_PHY_EN (1<<9) #define SNOOP_SIZE_2GB 0x1e #endif /* _EHCI_FSL_H */ -- cgit v1.2.3 From 35e95b11598a156121aa2d35cdec7e2994eafa83 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 9 Feb 2012 16:37:17 -0600 Subject: staging: r8712u: Add missing initialization and remove configuration parameter CONFIG_R8712_AP commit 073863432f7eaa23c7c09733414d4be2eabf5eef upstream. When this driver was upgraded to the vendor 20100831 version in commit 93c55dda092c7 et al,, one listhead initialization was missed. This broke complete operation of the driver whenever AP mode was enabled. This fixes https://bugs.archlinux.org/task/27996. The configuration parameter R8712_AP is misleading as the driver cannot function as an AP without a heavily hacked version of hostapd. Thus, it makes sense to remove the parameter; however the code and data configured for the option is left in. Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/Kconfig | 7 ------- drivers/staging/rtl8712/rtl871x_sta_mgt.c | 5 +---- drivers/staging/rtl8712/sta_info.h | 4 ---- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/staging/rtl8712/Kconfig b/drivers/staging/rtl8712/Kconfig index ea37473f71e5..6a43312380e0 100644 --- a/drivers/staging/rtl8712/Kconfig +++ b/drivers/staging/rtl8712/Kconfig @@ -9,13 +9,6 @@ config R8712U This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130. If built as a module, it will be called r8712u. -config R8712_AP - bool "Realtek RTL8712U AP code" - depends on R8712U - default N - ---help--- - This option allows the Realtek RTL8712 USB device to be an Access Point. - config R8712_TX_AGGR bool "Realtek RTL8712U Transmit Aggregation code" depends on R8712U && BROKEN diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c index 64f569618839..1247b3d9719d 100644 --- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c +++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c @@ -42,9 +42,8 @@ static void _init_stainfo(struct sta_info *psta) _init_listhead(&psta->hash_list); _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); _r8712_init_sta_recv_priv(&psta->sta_recvpriv); -#ifdef CONFIG_R8712_AP + _init_listhead(&psta->asoc_list); _init_listhead(&psta->auth_list); -#endif } u32 _r8712_init_sta_priv(struct sta_priv *pstapriv) @@ -71,10 +70,8 @@ u32 _r8712_init_sta_priv(struct sta_priv *pstapriv) get_list_head(&pstapriv->free_sta_queue)); psta++; } -#ifdef CONFIG_R8712_AP _init_listhead(&pstapriv->asoc_list); _init_listhead(&pstapriv->auth_list); -#endif return _SUCCESS; } diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h index 48d6a14c8f5f..f8016e9abffd 100644 --- a/drivers/staging/rtl8712/sta_info.h +++ b/drivers/staging/rtl8712/sta_info.h @@ -90,7 +90,6 @@ struct sta_info { * curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO * sta_info: (AP & STA) CAP/INFO */ -#ifdef CONFIG_R8712_AP struct list_head asoc_list; struct list_head auth_list; unsigned int expire_to; @@ -98,7 +97,6 @@ struct sta_info { unsigned int authalg; unsigned char chg_txt[128]; unsigned int tx_ra_bitmap; -#endif }; struct sta_priv { @@ -111,13 +109,11 @@ struct sta_priv { struct __queue sleep_q; struct __queue wakeup_q; struct _adapter *padapter; -#ifdef CONFIG_R8712_AP struct list_head asoc_list; struct list_head auth_list; unsigned int auth_to; /* sec, time to expire in authenticating. */ unsigned int assoc_to; /* sec, time to expire before associating. */ unsigned int expire_to; /* sec , time to expire after associated. */ -#endif }; static inline u32 wifi_mac_hash(u8 *mac) -- cgit v1.2.3 From 4399750de90017d366ae688b3e4ba86e5dfe6d25 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 25 Feb 2012 18:10:20 -0600 Subject: staging: r8712u: Fix regression introduced by commit a5ee652 commit 9f4bc8cf3fe750ed093856a5f5d41c11cc12ad22 upstream. In commit a5ee652 "staging: r8712u: Interface-state not fully tracked", the private boolean "bup" was set false when the interface was brought down, as that seemed appropriate. This change has not caused any problems when using NetworkManager or manual control of the device; however, when wicd control is used, there is a locking problem in wpa_supplicant, as shown in https://bugzilla.kernel.org/show_bug.cgi?id=42818. This fix reverts the only code change in commit a5ee652. My analysis is that "bup" is badly named. In its present form, it seems to indicate the up/down state of the device, but its usage is more consistent with an initialized/uninitialized state. That problem will be addressed in a later patch. Note: Commit 8c213fa, which introdued asynchronous firmware loading for this driver, exposed this bug to a greater extent. That bug is addressed in the next patch in this series. This bug is also responsible for the bug in https://bugzilla.kernel.org/show_bug.cgi?id=42815. and this bug is also part of the problems discussed at https://bugs.archlinux.org/task/27996#comment89950. Tested-by: Alberto Lago Ballesteros Tested-by: Adrian Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/os_intfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c index 98a3d684f9b2..fb117430acda 100644 --- a/drivers/staging/rtl8712/os_intfs.c +++ b/drivers/staging/rtl8712/os_intfs.c @@ -476,8 +476,6 @@ static int netdev_close(struct net_device *pnetdev) r8712_free_assoc_resources(padapter); /*s2-4.*/ r8712_free_network_queue(padapter); - /* The interface is no longer Up: */ - padapter->bup = false; release_firmware(padapter->fw); /* never exit with a firmware callback pending */ wait_for_completion(&padapter->rtl8712_fw_ready); -- cgit v1.2.3 From 6fc05c7f2cfbc2ec7e5c82b65b64c27ec2a764b0 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 26 Feb 2012 22:08:36 -0600 Subject: staging: r8712u: Fix regression in signal level after commit c6dc001 commit da3e6ec2f443ac00aa623c5921e3521f5f38efe4 upstream. In commit c6dc001 "staging: r8712u: Merging Realtek's latest (v2.6.6). Various fixes", the returned qual.qual member of the iw_statistics struct was changed. For strong signals, this change made no difference; however for medium and weak signals it results in a low signal that shows considerable fluctuation, When using wicd for a medium-strength AP, the value reported in the status line is reduced from 100% to 60% by this bug. This problem is reported in https://bugzilla.kernel.org/show_bug.cgi?id=42826. Reported-and-tested-by: Robert Crawford Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_ioctl_linux.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 507584b837c3..ef35bc29a3fa 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -2380,13 +2380,7 @@ static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev) tmp_qual = padapter->recvpriv.signal; tmp_noise = padapter->recvpriv.noise; piwstats->qual.level = tmp_level; - /*piwstats->qual.qual = tmp_qual; - * The NetworkManager of Fedora 10, 13 will use the link - * quality for its display. - * So, use the fw_rssi on link quality variable because - * fw_rssi will be updated per 2 seconds. - */ - piwstats->qual.qual = tmp_level; + piwstats->qual.qual = tmp_qual; piwstats->qual.noise = tmp_noise; } piwstats->qual.updated = IW_QUAL_ALL_UPDATED; -- cgit v1.2.3 From 8b2c433eb4ca5df49724fc77cef209ab2a3b54d1 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 17 Feb 2012 14:10:16 -0800 Subject: usb: dwc3: fix bogus test in dwc3_gadget_start_isoc commit 9bafa56c7cee5c6fa68de5924220abb220c7e229 upstream. Zero is a valid value for a microframe number. So remove the bogus test for non-zero in dwc3_gadget_start_isoc(). Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25dbd8614e72..8a2eb4d291fb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1405,7 +1405,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, static void dwc3_gadget_start_isoc(struct dwc3 *dwc, struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { - u32 uf; + u32 uf, mask; if (list_empty(&dep->request_list)) { dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", @@ -1413,16 +1413,10 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc, return; } - if (event->parameters) { - u32 mask; - - mask = ~(dep->interval - 1); - uf = event->parameters & mask; - /* 4 micro frames in the future */ - uf += dep->interval * 4; - } else { - uf = 0; - } + mask = ~(dep->interval - 1); + uf = event->parameters & mask; + /* 4 micro frames in the future */ + uf += dep->interval * 4; __dwc3_gadget_kick_transfer(dep, uf, 1); } -- cgit v1.2.3 From 289bd26e44bc08df86466f7bdf5257d28765b5b1 Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 23 Feb 2012 15:38:46 +0900 Subject: usb: dwc3: use proper function for setting endpoint name commit 27a78d6a283d6782438f72306746afe4bf44c215 upstream. It's wrong to use the size of array as an argument for strncat. Memory corruption is possible. strlcat is exactly what we need here. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8a2eb4d291fb..3700aa6ba7bf 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -449,16 +449,16 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: - strncat(dep->name, "-control", sizeof(dep->name)); + strlcat(dep->name, "-control", sizeof(dep->name)); break; case USB_ENDPOINT_XFER_ISOC: - strncat(dep->name, "-isoc", sizeof(dep->name)); + strlcat(dep->name, "-isoc", sizeof(dep->name)); break; case USB_ENDPOINT_XFER_BULK: - strncat(dep->name, "-bulk", sizeof(dep->name)); + strlcat(dep->name, "-bulk", sizeof(dep->name)); break; case USB_ENDPOINT_XFER_INT: - strncat(dep->name, "-int", sizeof(dep->name)); + strlcat(dep->name, "-int", sizeof(dep->name)); break; default: dev_err(dwc->dev, "invalid endpoint transfer type\n"); -- cgit v1.2.3 From 28e0c4cc0c55bea990c7ed35e4e07afb6cb485e0 Mon Sep 17 00:00:00 2001 From: Supriya Karanth Date: Fri, 17 Feb 2012 14:54:52 +0530 Subject: usb: musb: Reselect index reg in interrupt context commit 39287076e46d2c19aaceaa6f0a44168ae4d257ec upstream. musb INDEX register is getting modified/corrupted during temporary un-locking in a SMP system. Set this register with proper value after re-acquiring the lock Scenario: --------- CPU1 is handling a data transfer completion interrupt received for the CLASS1 EP CPU2 is handling a CLASS2 thread which is queuing data to musb for transfer Below is the error sequence: CPU1 | CPU2 -------------------------------------------------------------------- Data transfer completion inter- | rupt recieved. | | musb INDEX reg set to CLASS1 EP | | musb LOCK is acquired. | | | CLASS2 thread queues data. | | CLASS2 thread tries to acquire musb | LOCK but lock is already taken by | CLASS1, so CLASS2 thread is | spinning. | From Interrupt Context musb | giveback function is called | | The giveback function releases | CLASS2 thread now acquires LOCK LOCK | | ClASS1 Request's completion cal-| ClASS2 schedules the data transfer and lback is called | sets the MUSB INDEX to Class2 EP number | Interrupt handler for CLASS1 EP | tries to acquire LOCK and is | spinning | | Interrupt for Class1 EP acquires| Class2 completes the scheduling etc and the MUSB LOCK | releases the musb LOCK | Interrupt for Class1 EP schedul-| es the next data transfer | but musb INDEX register is still| set to CLASS2 EP | Since the MUSB INDEX register is set to a different endpoint, we read and modify the wrong registers. Hence data transfer will not happen properly. This results in unpredictable behavior So, the MUSB INDEX register is set to proper value again when interrupt re-acquires the lock Signed-off-by: Supriya Karanth Signed-off-by: Praveena Nadahally Reviewed-by: srinidhi kasagar Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 922148ff8d29..c860597eeb3a 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -576,6 +576,15 @@ void musb_g_tx(struct musb *musb, u8 epnum) if (request->actual == request->length) { musb_g_giveback(musb_ep, request, 0); + /* + * In the giveback function the MUSB lock is + * released and acquired after sometime. During + * this time period the INDEX register could get + * changed by the gadget_queue function especially + * on SMP systems. Reselect the INDEX to be sure + * we are reading/modifying the right registers + */ + musb_ep_select(mbase, epnum); req = musb_ep->desc ? next_request(musb_ep) : NULL; if (!req) { dev_dbg(musb->controller, "%s idle now\n", @@ -985,6 +994,15 @@ void musb_g_rx(struct musb *musb, u8 epnum) } #endif musb_g_giveback(musb_ep, request, 0); + /* + * In the giveback function the MUSB lock is + * released and acquired after sometime. During + * this time period the INDEX register could get + * changed by the gadget_queue function especially + * on SMP systems. Reselect the INDEX to be sure + * we are reading/modifying the right registers + */ + musb_ep_select(mbase, epnum); req = next_request(musb_ep); if (!req) -- cgit v1.2.3 From b94e22b626e2ba1e73bea71998c769624279b958 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 20 Feb 2012 17:35:50 -0800 Subject: usb: renesas_usbhs: bugfix: add .release function to gpriv->gadget.dev commit 3b2a2e47174cd978258bbb0fdf2e2b1b5ec2144c upstream. This patch fixup below warning on device_unregister() renesas_usbhs renesas_usbhs.1: host probed renesas_usbhs renesas_usbhs.1: gadget probed renesas_usbhs renesas_usbhs.1: irq request err ------------[ cut here ]------------ WARNING: at ${LINUX}/drivers/base/core.c:1) Device 'gadget' does not have a release() function, it is broken and must be fi. Modules linked in: [] (unwind_backtrace+0x0/0xe4) from [] (warn_slowpath_commo) [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_) [] (warn_slowpath_fmt+0x2c/0x3c) from [] (device_release+0x) [] (device_release+0x70/0x84) from [] (kobject_cleanup+0x58) [] (kobject_cleanup+0x58/0x6c) from [] (usbhs_mod_gadget_re) [] (usbhs_mod_gadget_remove+0x3c/0x6c) from [] (usbhs_mod_p) [] (usbhs_mod_probe+0x68/0x80) from [] (usbhs_probe+0x1cc/0) ... Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 7f4e80338570..aa0d183236c9 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -816,6 +816,11 @@ static int usbhsg_stop(struct usbhs_priv *priv) return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); } +static void usbhs_mod_gadget_release(struct device *pdev) +{ + /* do nothing */ +} + int usbhs_mod_gadget_probe(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv; @@ -864,6 +869,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) */ dev_set_name(&gpriv->gadget.dev, "gadget"); gpriv->gadget.dev.parent = dev; + gpriv->gadget.dev.release = usbhs_mod_gadget_release; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; gpriv->gadget.is_dualspeed = 1; -- cgit v1.2.3 From d8808b35aaac220884881a5b11a57ef65d2eb45d Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Fri, 2 Mar 2012 09:41:50 +0100 Subject: usb: gadgetfs: return number of bytes on ep0 read request commit 85b4b3c8c189e0159101f7628a71411af072ff69 upstream. A read from GadgetFS endpoint 0 during the data stage of a control request would always return 0 on success (as returned by wait_event_interruptible) despite having written data into the user buffer. This patch makes it correctly set the return value to the number of bytes read. Signed-off-by: Thomas Faber Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 6ccae2707e59..71385402f4c1 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1043,6 +1043,8 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) // FIXME don't call this with the spinlock held ... if (copy_to_user (buf, dev->req->buf, len)) retval = -EFAULT; + else + retval = len; clean_req (dev->gadget->ep0, dev->req); /* NOTE userspace can't yet choose to stall */ } -- cgit v1.2.3 From fe7951d72fe43d52e28f4e0ec1f1de2d0a12e5b0 Mon Sep 17 00:00:00 2001 From: Orjan Friberg Date: Wed, 7 Mar 2012 17:16:14 +0100 Subject: USB: gadget: Make g_hid device class conform to spec. commit 33d2832ab0149a26418d360af3c444969a63fb28 upstream. HID devices should specify this in their interface descriptors, not in the device descriptor. This fixes a "missing hardware id" bug under Windows 7 with a VIA VL800 (3.0) controller. Signed-off-by: Orjan Friberg Cc: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/hid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index f888c3ede860..3493adf064f5 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -60,9 +60,9 @@ static struct usb_device_descriptor device_desc = { /* .bDeviceClass = USB_CLASS_COMM, */ /* .bDeviceSubClass = 0, */ /* .bDeviceProtocol = 0, */ - .bDeviceClass = 0xEF, - .bDeviceSubClass = 2, - .bDeviceProtocol = 1, + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, /* .bMaxPacketSize0 = f(hardware) */ /* Vendor and product id can be overridden by module parameters. */ -- cgit v1.2.3 From 29bfcea07745737f385b0d092e71527051c29029 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 15 Feb 2012 12:08:34 +0100 Subject: futex: Cover all PI opcodes with cmpxchg enabled check commit 59263b513c11398cd66a52d4c5b2b118ce1e0359 upstream. Some of the newer futex PI opcodes do not check the cmpxchg enabled variable and call unconditionally into the handling functions. Cover all PI opcodes in a separate check. Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Darren Hart Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 1614be20173d..067702335762 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2640,6 +2640,16 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, return -ENOSYS; } + switch (cmd) { + case FUTEX_LOCK_PI: + case FUTEX_UNLOCK_PI: + case FUTEX_TRYLOCK_PI: + case FUTEX_WAIT_REQUEUE_PI: + case FUTEX_CMP_REQUEUE_PI: + if (!futex_cmpxchg_enabled) + return -ENOSYS; + } + switch (cmd) { case FUTEX_WAIT: val3 = FUTEX_BITSET_MATCH_ANY; @@ -2661,16 +2671,13 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, ret = futex_wake_op(uaddr, flags, uaddr2, val, val2, val3); break; case FUTEX_LOCK_PI: - if (futex_cmpxchg_enabled) - ret = futex_lock_pi(uaddr, flags, val, timeout, 0); + ret = futex_lock_pi(uaddr, flags, val, timeout, 0); break; case FUTEX_UNLOCK_PI: - if (futex_cmpxchg_enabled) - ret = futex_unlock_pi(uaddr, flags); + ret = futex_unlock_pi(uaddr, flags); break; case FUTEX_TRYLOCK_PI: - if (futex_cmpxchg_enabled) - ret = futex_lock_pi(uaddr, flags, 0, timeout, 1); + ret = futex_lock_pi(uaddr, flags, 0, timeout, 1); break; case FUTEX_WAIT_REQUEUE_PI: val3 = FUTEX_BITSET_MATCH_ANY; -- cgit v1.2.3 From cbdbd450211dd493262c0573e7143e1bb0bf7892 Mon Sep 17 00:00:00 2001 From: Masami Ichikawa Date: Tue, 21 Feb 2012 07:43:50 +0900 Subject: sysfs: Fix memory leak in sysfs_sd_setsecdata(). commit 93518dd2ebafcc761a8637b2877008cfd748c202 upstream. This patch fixies follwing two memory leak patterns that reported by kmemleak. sysfs_sd_setsecdata() is called during sys_lsetxattr() operation. It checks sd->s_iattr is NULL or not. Then if it is NULL, it calls sysfs_init_inode_attrs() to allocate memory. That code is this. iattrs = sd->s_iattr; if (!iattrs) iattrs = sysfs_init_inode_attrs(sd); The iattrs recieves sysfs_init_inode_attrs()'s result, but sd->s_iattr doesn't know the address. so it needs to set correct address to sd->s_iattr to free memory in other function. unreferenced object 0xffff880250b73e60 (size 32): comm "systemd", pid 1, jiffies 4294683888 (age 94.553s) hex dump (first 32 bytes): 73 79 73 74 65 6d 5f 75 3a 6f 62 6a 65 63 74 5f system_u:object_ 72 3a 73 79 73 66 73 5f 74 3a 73 30 00 00 00 00 r:sysfs_t:s0.... backtrace: [] kmemleak_alloc+0x73/0x98 [] __kmalloc+0x100/0x12c [] context_struct_to_string+0x106/0x210 [] security_sid_to_context_core+0x10b/0x129 [] security_sid_to_context+0x10/0x12 [] selinux_inode_getsecurity+0x7d/0xa8 [] selinux_inode_getsecctx+0x22/0x2e [] security_inode_getsecctx+0x16/0x18 [] sysfs_setxattr+0x96/0x117 [] __vfs_setxattr_noperm+0x73/0xd9 [] vfs_setxattr+0x83/0xa1 [] setxattr+0xcf/0x101 [] sys_lsetxattr+0x6a/0x8f [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff unreferenced object 0xffff88024163c5a0 (size 96): comm "systemd", pid 1, jiffies 4294683888 (age 94.553s) hex dump (first 32 bytes): 00 00 00 00 ed 41 00 00 00 00 00 00 00 00 00 00 .....A.......... 00 00 00 00 00 00 00 00 0c 64 42 4f 00 00 00 00 .........dBO.... backtrace: [] kmemleak_alloc+0x73/0x98 [] kmem_cache_alloc_trace+0xc4/0xee [] sysfs_init_inode_attrs+0x2a/0x83 [] sysfs_setxattr+0xbf/0x117 [] __vfs_setxattr_noperm+0x73/0xd9 [] vfs_setxattr+0x83/0xa1 [] setxattr+0xcf/0x101 [] sys_lsetxattr+0x6a/0x8f [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff ` Signed-off-by: Masami Ichikawa Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/inode.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index deb804bec9df..9db61a41c1ad 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -136,12 +136,13 @@ static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *sec void *old_secdata; size_t old_secdata_len; - iattrs = sd->s_iattr; - if (!iattrs) - iattrs = sysfs_init_inode_attrs(sd); - if (!iattrs) - return -ENOMEM; + if (!sd->s_iattr) { + sd->s_iattr = sysfs_init_inode_attrs(sd); + if (!sd->s_iattr) + return -ENOMEM; + } + iattrs = sd->s_iattr; old_secdata = iattrs->ia_secdata; old_secdata_len = iattrs->ia_secdata_len; -- cgit v1.2.3 From 676ba4178125f06e9bd1d0b539f5644f1cea31a5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 7 Mar 2012 13:05:00 +0300 Subject: tty: moxa: fix bit test in moxa_start() commit 58112dfbfe02d803566a2c6c8bd97b5fa3c62cdc upstream. This is supposed to be doing a shift before the comparison instead of just doing a bitwise AND directly. The current code means the start() just returns without doing anything. Signed-off-by: Dan Carpenter Acked-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/moxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index d15a071b1a54..0174d2d2a483 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1331,7 +1331,7 @@ static void moxa_start(struct tty_struct *tty) if (ch == NULL) return; - if (!(ch->statusflags & TXSTOPPED)) + if (!test_bit(TXSTOPPED, &ch->statusflags)) return; MoxaPortTxEnable(ch); -- cgit v1.2.3 From 9d7203a1946813100a0623289df8c2bbbe832831 Mon Sep 17 00:00:00 2001 From: Liz Clark Date: Thu, 15 Mar 2012 10:33:29 -0700 Subject: TTY: Wrong unicode value copied in con_set_unimap() commit 4a4c61b7ce26bfc9d49ea4bd121d52114bad9f99 upstream. Bugzilla 40012: PIO_UNIMAP bug: error updating Unicode-to-font map https://bugzilla.kernel.org/show_bug.cgi?id=40012 The unicode font map for the virtual console is a 32x32x64 table which allocates rows dynamically as entries are added. The unicode value increases sequentially and should count all entries even in empty rows. The defect is when copying the unicode font map in con_set_unimap(), the unicode value is not incremented properly. The wrong unicode value is entered in the new font map. Signed-off-by: Liz Clark Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 51 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 45d3e80156d4..f3438083a285 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -516,6 +516,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) int err = 0, err1, i; struct uni_pagedir *p, *q; + /* Save original vc_unipagdir_loc in case we allocate a new one */ p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p->readonly) return -EIO; @@ -528,26 +529,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) err1 = con_clear_unimap(vc, NULL); if (err1) return err1; + /* + * Since refcount was > 1, con_clear_unimap() allocated a + * a new uni_pagedir for this vc. Re: p != q + */ q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - for (i = 0, l = 0; i < 32; i++) + + /* + * uni_pgdir is a 32*32*64 table with rows allocated + * when its first entry is added. The unicode value must + * still be incremented for empty rows. We are copying + * entries from "p" (old) to "q" (new). + */ + l = 0; /* unicode value */ + for (i = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) - if ((p2 = p1[j])) + if ((p2 = p1[j])) { for (k = 0; k < 64; k++, l++) if (p2[k] != 0xffff) { + /* + * Found one, copy entry for unicode + * l with fontpos value p2[k]. + */ err1 = con_insert_unipair(q, l, p2[k]); if (err1) { p->refcount++; *vc->vc_uni_pagedir_loc = (unsigned long)p; con_release_unimap(q); kfree(q); - return err1; + return err1; } - } - p = q; - } else if (p == dflt) + } + } else { + /* Account for row of 64 empty entries */ + l += 64; + } + else + /* Account for empty table */ + l += 32 * 64; + + /* + * Finished copying font table, set vc_uni_pagedir to new table + */ + p = q; + } else if (p == dflt) { dflt = NULL; - + } + + /* + * Insert user specified unicode pairs into new table. + */ while (ct--) { unsigned short unicode, fontpos; __get_user(unicode, &list->unicode); @@ -557,11 +589,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) list++; } + /* + * Merge with fontmaps of any other virtual consoles. + */ if (con_unify_unimap(vc, p)) return err; for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update all inverse translations */ + set_inverse_transl(vc, p, i); /* Update inverse translations */ set_inverse_trans_unicode(vc, p); return err; -- cgit v1.2.3 From 77131893c0287a7736171b97ef69b989bbeaba62 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 10 Feb 2012 13:20:49 +0100 Subject: USB: serial: fix console error reporting commit 548dd4b6da8a8e428453d55f7fa7b8a46498d147 upstream. Do not report errors in write path if port is used as a console as this may trigger the same error (and error report) resulting in a loop. Reported-by: Stephen Hemminger Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e4db5ad2bc55..9f0b2bff8ee4 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -215,8 +215,10 @@ retry: clear_bit(i, &port->write_urbs_free); result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, "%s - error submitting urb: %d\n", + if (!port->port.console) { + dev_err(&port->dev, "%s - error submitting urb: %d\n", __func__, result); + } set_bit(i, &port->write_urbs_free); spin_lock_irqsave(&port->lock, flags); port->tx_bytes -= count; -- cgit v1.2.3 From 8d272f9af55e8900fc96886bd72b158482ed55d0 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 12 Feb 2012 06:00:41 +0000 Subject: cdc-wdm: Fix more races on the read path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 711c68b3c0f7a924ffbee4aa962d8f62b85188ff upstream. We must not allow the input buffer length to change while we're shuffling the buffer contents. We also mustn't clear the WDM_READ flag after more data might have arrived. Therefore move both of these into the spinlocked region at the bottom of wdm_read(). When reading desc->length without holding the iuspin lock, use ACCESS_ONCE() to ensure the compiler doesn't re-read it with inconsistent results. Signed-off-by: Ben Hutchings Tested-by: Bjørn Mork Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index fd4aee188fe9..eb650b78ee4f 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -397,7 +397,7 @@ outnl: static ssize_t wdm_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - int rv, cntr = 0; + int rv, cntr; int i = 0; struct wdm_device *desc = file->private_data; @@ -406,7 +406,8 @@ static ssize_t wdm_read if (rv < 0) return -ERESTARTSYS; - if (desc->length == 0) { + cntr = ACCESS_ONCE(desc->length); + if (cntr == 0) { desc->read = 0; retry: if (test_bit(WDM_DISCONNECTING, &desc->flags)) { @@ -457,25 +458,30 @@ retry: goto retry; } clear_bit(WDM_READ, &desc->flags); + cntr = desc->length; spin_unlock_irq(&desc->iuspin); } - cntr = count > desc->length ? desc->length : count; + if (cntr > count) + cntr = count; rv = copy_to_user(buffer, desc->ubuf, cntr); if (rv > 0) { rv = -EFAULT; goto err; } + spin_lock_irq(&desc->iuspin); + for (i = 0; i < desc->length - cntr; i++) desc->ubuf[i] = desc->ubuf[i + cntr]; - spin_lock_irq(&desc->iuspin); desc->length -= cntr; - spin_unlock_irq(&desc->iuspin); /* in case we had outstanding data */ if (!desc->length) clear_bit(WDM_READ, &desc->flags); + + spin_unlock_irq(&desc->iuspin); + rv = cntr; err: -- cgit v1.2.3 From 3d8e1c65555c758475a005c287f1c4b69296b226 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 12 Feb 2012 06:02:43 +0000 Subject: cdc-wdm: Don't clear WDM_READ unless entire read buffer is emptied MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b7a205545345578712611106b371538992e142ff upstream. The WDM_READ flag is cleared later iff desc->length is reduced to 0. Signed-off-by: Ben Hutchings Tested-by: Bjørn Mork Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index eb650b78ee4f..9eb71d8e1a27 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -457,7 +457,6 @@ retry: spin_unlock_irq(&desc->iuspin); goto retry; } - clear_bit(WDM_READ, &desc->flags); cntr = desc->length; spin_unlock_irq(&desc->iuspin); } -- cgit v1.2.3 From 8bfc26d2e9978d70eef8b03b9495045425c23f22 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 16 Feb 2012 09:36:25 +0800 Subject: usb: fsl_udc_core: Fix scheduling while atomic dump message commit c5cc5ed86667d4ae74fe40ee4ed893f4b46aba05 upstream. When loading g_ether gadget, there is below message: Backtrace: [<80012248>] (dump_backtrace+0x0/0x10c) from [<803cb42c>] (dump_stack+0x18/0x1c) r7:00000000 r6:80512000 r5:8052bef8 r4:80513f30 [<803cb414>] (dump_stack+0x0/0x1c) from [<8000feb4>] (show_regs+0x44/0x50) [<8000fe70>] (show_regs+0x0/0x50) from [<8004c840>] (__schedule_bug+0x68/0x84) r5:8052bef8 r4:80513f30 [<8004c7d8>] (__schedule_bug+0x0/0x84) from [<803cd0e4>] (__schedule+0x4b0/0x528) r5:8052bef8 r4:809aad00 [<803ccc34>] (__schedule+0x0/0x528) from [<803cd214>] (_cond_resched+0x44/0x58) [<803cd1d0>] (_cond_resched+0x0/0x58) from [<800a9488>] (dma_pool_alloc+0x184/0x250) r5:9f9b4000 r4:9fb4fb80 [<800a9304>] (dma_pool_alloc+0x0/0x250) from [<802a8ad8>] (fsl_req_to_dtd+0xac/0x180) [<802a8a2c>] (fsl_req_to_dtd+0x0/0x180) from [<802a8ce4>] (fsl_ep_queue+0x138/0x274) [<802a8bac>] (fsl_ep_queue+0x0/0x274) from [<7f004328>] (composite_setup+0x2d4/0xfac [g_ether]) [<7f004054>] (composite_setup+0x0/0xfac [g_ether]) from [<802a9bb4>] (fsl_udc_irq+0x8dc/0xd38) [<802a92d8>] (fsl_udc_irq+0x0/0xd38) from [<800704f8>] (handle_irq_event_percpu+0x54/0x188) [<800704a4>] (handle_irq_event_percpu+0x0/0x188) from [<80070674>] (handle_irq_event+0x48/0x68) [<8007062c>] (handle_irq_event+0x0/0x68) from [<800738ec>] (handle_level_irq+0xb4/0x138) r5:80514f94 r4:80514f40 [<80073838>] (handle_level_irq+0x0/0x138) from [<8006ffa4>] (generic_handle_irq+0x38/0x44) r7:00000012 r6:80510b1c r5:80529860 r4:80512000 [<8006ff6c>] (generic_handle_irq+0x0/0x44) from [<8000f4c4>] (handle_IRQ+0x54/0xb4) [<8000f470>] (handle_IRQ+0x0/0xb4) from [<800085b8>] (tzic_handle_irq+0x64/0x94) r9:412fc085 r8:00000000 r7:80513f30 r6:00000001 r5:00000000 r4:00000000 [<80008554>] (tzic_handle_irq+0x0/0x94) from [<8000e680>] (__irq_svc+0x40/0x60) The reason of above dump message is calling dma_poll_alloc with can-schedule mem_flags at atomic context. To fix this problem, below changes are made: - fsl_req_to_dtd doesn't need to be protected by spin_lock_irqsave, as struct usb_request can be access at process context. Move lock to beginning of hardware visit (fsl_queue_td). - Change the memory flag which using to allocate dTD descriptor buffer, the memory flag can be from gadget layer. It is tested at i.mx51 bbg board with g_mass_storage, g_ether, g_serial. Signed-off-by: Peter Chen Acked-by: Li Yang Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_udc_core.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index dd28ef3def71..8e3e509f3a53 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -768,7 +768,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) * @is_last: return flag if it is the last dTD of the request * return: pointer to the built dTD */ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, - dma_addr_t *dma, int *is_last) + dma_addr_t *dma, int *is_last, gfp_t gfp_flags) { u32 swap_temp; struct ep_td_struct *dtd; @@ -777,7 +777,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, *length = min(req->req.length - req->req.actual, (unsigned)EP_MAX_LENGTH_TRANSFER); - dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma); + dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma); if (dtd == NULL) return dtd; @@ -827,7 +827,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, } /* Generate dtd chain for a request */ -static int fsl_req_to_dtd(struct fsl_req *req) +static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags) { unsigned count; int is_last; @@ -836,7 +836,7 @@ static int fsl_req_to_dtd(struct fsl_req *req) dma_addr_t dma; do { - dtd = fsl_build_dtd(req, &count, &dma, &is_last); + dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags); if (dtd == NULL) return -ENOMEM; @@ -910,13 +910,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req->req.actual = 0; req->dtd_count = 0; - spin_lock_irqsave(&udc->lock, flags); - /* build dtds and push them to device queue */ - if (!fsl_req_to_dtd(req)) { + if (!fsl_req_to_dtd(req, gfp_flags)) { + spin_lock_irqsave(&udc->lock, flags); fsl_queue_td(ep, req); } else { - spin_unlock_irqrestore(&udc->lock, flags); return -ENOMEM; } @@ -1295,7 +1293,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->mapped = 1; - if (fsl_req_to_dtd(req) == 0) + if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0) fsl_queue_td(ep, req); else return -ENOMEM; @@ -1379,7 +1377,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, req->mapped = 1; /* prime the data phase */ - if ((fsl_req_to_dtd(req) == 0)) + if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0)) fsl_queue_td(ep, req); else /* no mem */ goto stall; -- cgit v1.2.3 From 727414186307fa88c9240f32cfe45a11b672274e Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 16 Feb 2012 09:41:52 +0800 Subject: usb: Fix build error due to dma_mask is not at pdev_archdata at ARM commit e90fc3cb087ce5c5f81e814358222cd6d197b5db upstream. When build i.mx platform with imx_v6_v7_defconfig, and after adding USB Gadget support, it has below build error: CC drivers/usb/host/fsl-mph-dr-of.o drivers/usb/host/fsl-mph-dr-of.c: In function 'fsl_usb2_device_register': drivers/usb/host/fsl-mph-dr-of.c:97: error: 'struct pdev_archdata' has no member named 'dma_mask' It has discussed at: http://www.spinics.net/lists/linux-usb/msg57302.html For PowerPC, there is dma_mask at struct pdev_archdata, but there is no dma_mask at struct pdev_archdata for ARM. The pdev_archdata is related to specific platform, it should NOT be accessed by cross platform drivers, like USB. The code for pdev_archdata should be useless, as for PowerPC, it has already gotten the value for pdev->dev.dma_mask at function arch_setup_pdev_archdata of arch/powerpc/kernel/setup-common.c. Tested-by: Ramneek Mehresh Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fsl-mph-dr-of.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 9037035ad1e4..5a42cf0c9bb6 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -94,7 +94,6 @@ struct platform_device * __devinit fsl_usb2_device_register( pdev->dev.parent = &ofdev->dev; pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask; - pdev->dev.dma_mask = &pdev->archdata.dma_mask; *pdev->dev.dma_mask = *ofdev->dev.dma_mask; retval = platform_device_add_data(pdev, pdata, sizeof(*pdata)); -- cgit v1.2.3 From 61849d8278208ab8445e6143387b5cfe0219c21d Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Feb 2012 15:34:34 -0500 Subject: USB: ums_realtek: do not use stack memory for DMA in __do_config_autodelink commit 4898e07174b79013afd2b422ef6c4336ef8e6783 upstream. __do_config_autodelink passes the data variable to the transport function. If the calling functions pass a stack variable, this will eventually trigger a DMA-API debug backtrace for mapping stack memory in the DMA buffer. Fix this by calling kmemdup for the passed data instead. Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/realtek_cr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 32c93d78d660..e39b1885f517 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -509,9 +509,14 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len) int retval; u16 addr = 0xFE47; u8 cmnd[12] = {0}; + u8 *buf; US_DEBUGP("%s, addr = 0x%x, len = %d\n", __FUNCTION__, addr, len); + buf = kmemdup(data, len, GFP_NOIO); + if (!buf) + return USB_STOR_TRANSPORT_ERROR; + cmnd[0] = 0xF0; cmnd[1] = 0x0E; cmnd[2] = (u8)(addr >> 8); @@ -519,7 +524,8 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len) cmnd[4] = (u8)(len >> 8); cmnd[5] = (u8)len; - retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, data, len, DMA_TO_DEVICE, NULL); + retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL); + kfree(buf); if (retval != USB_STOR_TRANSPORT_GOOD) { return -EIO; } -- cgit v1.2.3 From 4a39b3bd2582ccb1d3ca6fea5fc15b43a66c0b3a Mon Sep 17 00:00:00 2001 From: Thomas Tuttle Date: Wed, 1 Feb 2012 16:07:17 -0500 Subject: USB: qcserial: add several new serial devices commit 2db4d87070e87d198ab630e66a898b45eff316d9 upstream. Signed-off-by: Thomas Tuttle Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index aa9367f5b421..1e87d49da976 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -36,6 +36,11 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x413c, 0x8171)}, /* Dell Gobi QDL device */ {USB_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ {USB_DEVICE(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ + {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi QDL device */ + {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi QDL device */ + {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi QDL device */ + {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi QDL device */ + {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi QDL device */ {USB_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ {USB_DEVICE(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ {USB_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ @@ -86,7 +91,16 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ + + {USB_DEVICE(0x05c6, 0x920c)}, /* Gobi 3000 QDL */ + {USB_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */ + {USB_DEVICE(0x1410, 0xa020)}, /* Novatel Gobi 3000 QDL */ + {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ + {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ + {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ + {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ + {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v1.2.3 From b951f1a7f9727ad427088ed4c36f364144945202 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 24 Feb 2012 13:08:43 -0600 Subject: USB: qcserial: don't grab QMI port on Gobi 1000 devices commit c192c8e71a2ded01170c1a992cd21aaedc822756 upstream. Gobi 1000 devices have a different port layout, which wasn't respected by the current driver, and thus it grabbed the QMI/net port. In the near future we'll be attaching another driver to the QMI/net port for these devices (cdc-wdm and qmi_wwan) so make sure the qcserial driver doesn't claim them. This patch also prevents qcserial from binding to interfaces 0 and 1 on 1K devices because those interfaces do not respond. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 105 +++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 1e87d49da976..3187d8b97bfb 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -24,39 +24,44 @@ static int debug; +#define DEVICE_G1K(v, p) \ + USB_DEVICE(v, p), .driver_info = 1 + static const struct usb_device_id id_table[] = { - {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ - {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ - {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ - {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ - {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ - {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ - {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ - {USB_DEVICE(0x413c, 0x8171)}, /* Dell Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ - {USB_DEVICE(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ - {USB_DEVICE(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ - {USB_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ - {USB_DEVICE(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ - {USB_DEVICE(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + /* Gobi 1000 devices */ + {DEVICE_G1K(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ + {DEVICE_G1K(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ + {DEVICE_G1K(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ + {DEVICE_G1K(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ + {DEVICE_G1K(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ + {DEVICE_G1K(0x413c, 0x8172)}, /* Dell Gobi Modem device */ + {DEVICE_G1K(0x413c, 0x8171)}, /* Dell Gobi QDL device */ + {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ + {DEVICE_G1K(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ + {DEVICE_G1K(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ + {DEVICE_G1K(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ + {DEVICE_G1K(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ + {DEVICE_G1K(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + + /* Gobi 2000 devices */ + {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi 2000 QDL device */ {USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */ {USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ {USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */ @@ -92,6 +97,8 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ + /* Gobi 3000 devices */ + {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Gobi 3000 QDL */ {USB_DEVICE(0x05c6, 0x920c)}, /* Gobi 3000 QDL */ {USB_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */ {USB_DEVICE(0x1410, 0xa020)}, /* Novatel Gobi 3000 QDL */ @@ -122,8 +129,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) int retval = -ENODEV; __u8 nintf; __u8 ifnum; + bool is_gobi1k = id->driver_info ? true : false; dbg("%s", __func__); + dbg("Is Gobi 1000 = %d", is_gobi1k); nintf = serial->dev->actconfig->desc.bNumInterfaces; dbg("Num Interfaces = %d", nintf); @@ -171,15 +180,25 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) case 3: case 4: - /* Composite mode */ - /* ifnum == 0 is a broadband network adapter */ - if (ifnum == 1) { - /* - * Diagnostics Monitor (serial line 9600 8N1) - * Qualcomm DM protocol - * use "libqcdm" (ModemManager) for communication - */ - dbg("Diagnostics Monitor found"); + /* Composite mode; don't bind to the QMI/net interface as that + * gets handled by other drivers. + */ + + /* Gobi 1K USB layout: + * 0: serial port (doesn't respond) + * 1: serial port (doesn't respond) + * 2: AT-capable modem port + * 3: QMI/net + * + * Gobi 2K+ USB layout: + * 0: QMI/net + * 1: DM/DIAG (use libqcdm from ModemManager for communication) + * 2: AT-capable modem port + * 3: NMEA + */ + + if (ifnum == 1 && !is_gobi1k) { + dbg("Gobi 2K+ DM/DIAG interface found"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { dev_err(&serial->dev->dev, @@ -198,13 +217,13 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) retval = -ENODEV; kfree(data); } - } else if (ifnum==3) { + } else if (ifnum==3 && !is_gobi1k) { /* * NMEA (serial line 9600 8N1) * # echo "\$GPS_START" > /dev/ttyUSBx * # echo "\$GPS_STOP" > /dev/ttyUSBx */ - dbg("NMEA GPS interface found"); + dbg("Gobi 2K+ NMEA GPS interface found"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { dev_err(&serial->dev->dev, -- cgit v1.2.3 From 39531b9566659b87cc585807e797eaf2dde4d563 Mon Sep 17 00:00:00 2001 From: Scott Dial Date: Fri, 24 Feb 2012 19:04:09 -0500 Subject: usb-serial: Add support for the Sealevel SeaLINK+8 2038-ROHS device commit 6d161b99f875269ad4ffa44375e1e54bca6fd02e upstream. This patch adds new device IDs to the ftdi_sio module to support the new Sealevel SeaLINK+8 2038-ROHS device. Signed-off-by: Scott Dial Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 4 ++++ drivers/usb/serial/ftdi_sio_ids.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3f3ccf63bb2c..f2c9ef780b18 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -537,6 +537,10 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) }, { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, { USB_DEVICE(OCT_VID, OCT_US101_PID) }, { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index abf6bbcdaf4f..c6dd18e346b6 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -689,6 +689,10 @@ #define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ #define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ #define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ +#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */ +#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */ +#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */ +#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */ /* * JETI SPECTROMETER SPECBOS 1201 -- cgit v1.2.3 From 30f0518605762cf1dbf3379acc573cf129cbf593 Mon Sep 17 00:00:00 2001 From: Preston Fick Date: Fri, 24 Feb 2012 13:42:39 -0600 Subject: usb: cp210x: Update to support CP2105 and multiple interface devices commit a5360a53a7ccad5ed9ccef210b94fef13c6e5529 upstream. This patch updates the cp210x driver to support CP210x multiple interface devices devices from Silicon Labs. The existing driver always sends control requests to interface 0, which is hardcoded in the usb_control_msg function calls. This only allows for single interface devices to be used, and causes a bug when using ports on an interface other than 0 in the multiple interface devices. Here are the changes included in this patch: - Updated the device list to contain the Silicon Labs factory default VID/PID for multiple interface CP210x devices - Created a cp210x_port_private struct created for each port on startup, this struct holds the interface number - Added a cp210x_release function to clean up the cp210x_port_private memory created on startup - Modified usb_get_config and usb_set_config to get a pointer to the cp210x_port_private struct, and use the interface number there in the usb_control_message wIndex param Signed-off-by: Preston Fick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 33d25d4e6807..4c12404963e8 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -49,6 +49,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); +static void cp210x_release(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); static int debug; @@ -121,6 +122,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ @@ -149,6 +152,10 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); +struct cp210x_port_private { + __u8 bInterfaceNumber; +}; + static struct usb_driver cp210x_driver = { .name = "cp210x", .probe = usb_serial_probe, @@ -174,6 +181,7 @@ static struct usb_serial_driver cp210x_device = { .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, .attach = cp210x_startup, + .release = cp210x_release, .dtr_rts = cp210x_dtr_rts }; @@ -261,6 +269,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); __le32 *buf; int result, i, length; @@ -276,7 +285,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, /* Issue the request, attempting to read 'size' bytes */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), request, REQTYPE_DEVICE_TO_HOST, 0x0000, - 0, buf, size, 300); + port_priv->bInterfaceNumber, buf, size, 300); /* Convert data into an array of integers */ for (i = 0; i < length; i++) @@ -304,6 +313,7 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); __le32 *buf; int result, i, length; @@ -325,12 +335,12 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), request, REQTYPE_HOST_TO_DEVICE, 0x0000, - 0, buf, size, 300); + port_priv->bInterfaceNumber, buf, size, 300); } else { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), request, REQTYPE_HOST_TO_DEVICE, data[0], - 0, NULL, 0, 300); + port_priv->bInterfaceNumber, NULL, 0, 300); } kfree(buf); @@ -830,11 +840,39 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state) static int cp210x_startup(struct usb_serial *serial) { + struct cp210x_port_private *port_priv; + int i; + /* cp210x buffers behave strangely unless device is reset */ usb_reset_device(serial->dev); + + for (i = 0; i < serial->num_ports; i++) { + port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); + if (!port_priv) + return -ENOMEM; + + memset(port_priv, 0x00, sizeof(*port_priv)); + port_priv->bInterfaceNumber = + serial->interface->cur_altsetting->desc.bInterfaceNumber; + + usb_set_serial_port_data(serial->port[i], port_priv); + } + return 0; } +static void cp210x_release(struct usb_serial *serial) +{ + struct cp210x_port_private *port_priv; + int i; + + for (i = 0; i < serial->num_ports; i++) { + port_priv = usb_get_serial_port_data(serial->port[i]); + kfree(port_priv); + usb_set_serial_port_data(serial->port[i], NULL); + } +} + static int __init cp210x_init(void) { int retval; -- cgit v1.2.3 From 7b2a7db9fd2de45d1be277679d89f6bf8c56fd32 Mon Sep 17 00:00:00 2001 From: Donald Lee Date: Wed, 14 Mar 2012 15:26:33 +0800 Subject: USB: serial: mos7840: Fixed MCS7820 device attach problem commit 093ea2d3a766cb8a4c4de57efec6c0a127a58792 upstream. A MCS7820 device supports two serial ports and a MCS7840 device supports four serial ports. Both devices use the same driver, but the attach function in driver was unable to correctly handle the port numbers for MCS7820 device. This problem has been fixed in this patch and this fix has been verified on x86 Linux kernel 3.2.9 with both MCS7820 and MCS7840 devices. Signed-off-by: Donald Lee Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 83 ++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c72abd524983..5c7d6540053f 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -174,6 +174,7 @@ #define CLK_MULTI_REGISTER ((__u16)(0x02)) #define CLK_START_VALUE_REGISTER ((__u16)(0x03)) +#define GPIO_REGISTER ((__u16)(0x07)) #define SERIAL_LCR_DLAB ((__u16)(0x0080)) @@ -1103,14 +1104,25 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) mos7840_port->read_urb = port->read_urb; /* set up our bulk in urb */ - - usb_fill_bulk_urb(mos7840_port->read_urb, - serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->bulk_in_buffer, - mos7840_port->read_urb->transfer_buffer_length, - mos7840_bulk_in_callback, mos7840_port); + if ((serial->num_ports == 2) + && ((((__u16)port->number - + (__u16)(port->serial->minor)) % 2) != 0)) { + usb_fill_bulk_urb(mos7840_port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + (port->bulk_in_endpointAddress) + 2), + port->bulk_in_buffer, + mos7840_port->read_urb->transfer_buffer_length, + mos7840_bulk_in_callback, mos7840_port); + } else { + usb_fill_bulk_urb(mos7840_port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, + mos7840_port->read_urb->transfer_buffer_length, + mos7840_bulk_in_callback, mos7840_port); + } dbg("mos7840_open: bulkin endpoint is %d", port->bulk_in_endpointAddress); @@ -1521,13 +1533,25 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, memcpy(urb->transfer_buffer, current_position, transfer_size); /* fill urb with data and submit */ - usb_fill_bulk_urb(urb, - serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, - transfer_size, - mos7840_bulk_out_data_callback, mos7840_port); + if ((serial->num_ports == 2) + && ((((__u16)port->number - + (__u16)(port->serial->minor)) % 2) != 0)) { + usb_fill_bulk_urb(urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + (port->bulk_out_endpointAddress) + 2), + urb->transfer_buffer, + transfer_size, + mos7840_bulk_out_data_callback, mos7840_port); + } else { + usb_fill_bulk_urb(urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, + transfer_size, + mos7840_bulk_out_data_callback, mos7840_port); + } data1 = urb->transfer_buffer; dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); @@ -1840,7 +1864,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, } else { #ifdef HW_flow_control - / *setting h/w flow control bit to 0 */ + /* setting h/w flow control bit to 0 */ Data = 0xb; mos7840_port->shadowMCR = Data; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, @@ -2309,19 +2333,26 @@ static int mos7840_ioctl(struct tty_struct *tty, static int mos7840_calc_num_ports(struct usb_serial *serial) { - int mos7840_num_ports = 0; - - dbg("numberofendpoints: cur %d, alt %d", - (int)serial->interface->cur_altsetting->desc.bNumEndpoints, - (int)serial->interface->altsetting->desc.bNumEndpoints); - if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) { - mos7840_num_ports = serial->num_ports = 2; - } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) { + __u16 Data = 0x00; + int ret = 0; + int mos7840_num_ports; + + ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + + if ((Data & 0x01) == 0) { + mos7840_num_ports = 2; + serial->num_bulk_in = 2; + serial->num_bulk_out = 2; + serial->num_ports = 2; + } else { + mos7840_num_ports = 4; serial->num_bulk_in = 4; serial->num_bulk_out = 4; - mos7840_num_ports = serial->num_ports = 4; + serial->num_ports = 4; } - dbg ("mos7840_num_ports = %d", mos7840_num_ports); + return mos7840_num_ports; } -- cgit v1.2.3 From 81a142cabdaa962f2541c3497cd08d39432602df Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 11 Feb 2012 21:58:09 +0100 Subject: rt2x00: Add support for D-Link DWA-127 to rt2800usb. commit d42a179b941a9e4cc6cf41d0f3cbadd75fc48a89 upstream. This is an RT3070 based device. Reported-by: Mikhail Kryshen Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3265b341e96d..cb71e882aae5 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -935,6 +935,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c0f) }, { USB_DEVICE(0x07d1, 0x3c11) }, { USB_DEVICE(0x07d1, 0x3c16) }, + { USB_DEVICE(0x2001, 0x3c1b) }, /* Draytek */ { USB_DEVICE(0x07fa, 0x7712) }, /* DVICO */ -- cgit v1.2.3 From de886abb2cdce855f6badbd4d77f100df62499a7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 7 Jan 2012 20:46:40 -0600 Subject: rtlwifi: rtl8192c_common: rtl8192de: Check for allocation failures commit 76a92be537f1c8c259e393632301446257ca3ea9 upstream. In https://bugzilla.redhat.com/show_bug.cgi?id=771656, a kernel bug was triggered due to a failed skb allocation that was not checked. This event lead to an audit of all memory allocations in the complete rtlwifi family of drivers. This patch fixes the rest. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/pci.c | 2 ++ drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | 2 ++ drivers/net/wireless/rtlwifi/rtl8192de/fw.c | 14 +++++++++----- drivers/net/wireless/rtlwifi/usb.c | 12 +++++++----- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index eb61061821e4..19bb550dd396 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -657,6 +657,8 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb, return; uskb = dev_alloc_skb(skb->len + 128); + if (!uskb) + return; /* exit if allocation failed */ memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); pdata = (u8 *)skb_put(uskb, skb->len); memcpy(pdata, skb->data, skb->len); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 950c65a15b8a..13fc0f90b598 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -752,6 +752,8 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) skb = dev_alloc_skb(totalpacketlen); + if (!skb) + return; memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c index 82f060bdbc0b..c44757f31389 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c @@ -763,12 +763,16 @@ void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", u1RsvdPageLoc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, - totalpacketlen); - rtstatus = _rtl92d_cmd_send_packet(hw, skb); + if (!skb) { + dlok = false; + } else { + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + rtstatus = _rtl92d_cmd_send_packet(hw, skb); - if (rtstatus) - dlok = true; + if (rtstatus) + dlok = true; + } if (dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Set RSVD page location to Fw.\n")); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 54cb8a60514d..2b7bcc825775 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -481,12 +481,14 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, u8 *pdata; uskb = dev_alloc_skb(skb->len + 128); - memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, - sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, skb->len); - memcpy(pdata, skb->data, skb->len); + if (uskb) { /* drop packet on allocation failure */ + memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, + sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, skb->len); + memcpy(pdata, skb->data, skb->len); + ieee80211_rx_irqsafe(hw, uskb); + } dev_kfree_skb_any(skb); - ieee80211_rx_irqsafe(hw, uskb); } else { dev_kfree_skb_any(skb); } -- cgit v1.2.3 From 4d804674785319b3ef7544575139402e80190a30 Mon Sep 17 00:00:00 2001 From: Simon Graham Date: Tue, 7 Feb 2012 18:07:38 -0600 Subject: rtlwifi: Handle previous allocation failures when freeing device memory commit 7f66c2f93e5779625c10d262c84537427a2673ca upstream. Handle previous allocation failures when freeing device memory Signed-off-by: Simon Graham Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/pci.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 19bb550dd396..9afcad3c6cd6 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1155,10 +1155,12 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, ring->idx = (ring->idx + 1) % ring->entries; } - pci_free_consistent(rtlpci->pdev, - sizeof(*ring->desc) * ring->entries, - ring->desc, ring->dma); - ring->desc = NULL; + if (ring->desc) { + pci_free_consistent(rtlpci->pdev, + sizeof(*ring->desc) * ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; + } } static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci) @@ -1182,12 +1184,14 @@ static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci) kfree_skb(skb); } - pci_free_consistent(rtlpci->pdev, + if (rtlpci->rx_ring[rx_queue_idx].desc) { + pci_free_consistent(rtlpci->pdev, sizeof(*rtlpci->rx_ring[rx_queue_idx]. desc) * rtlpci->rxringcount, rtlpci->rx_ring[rx_queue_idx].desc, rtlpci->rx_ring[rx_queue_idx].dma); - rtlpci->rx_ring[rx_queue_idx].desc = NULL; + rtlpci->rx_ring[rx_queue_idx].desc = NULL; + } } } -- cgit v1.2.3 From a6ce707abde542b876d685e1f031453442dc2b13 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 2 Mar 2012 15:23:36 -0600 Subject: rtlwifi: rtl8192c: Prevent sleeping from invalid context in rtl8192cu commit ebecdcc12fed5d3c81853dea61a0a78a5aefab52 upstream. When driver rtl8192cu is used with the debug level set to 3 or greater, the result is "sleeping function called from invalid context" due to an rcu_read_lock() call in the DM refresh routine in driver rtl8192c. This lock is not necessary as the USB driver does not use the struct being protected, thus the lock is set only when a PCI interface is active. This bug is reported in https://bugzilla.kernel.org/show_bug.cgi?id=42775. Reported-by: Ronald Wahl Tested-by: Ronald Wahl Signed-off-by: Larry Finger Cc: Ronald Wahl Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 72a98cab6f69..4de6b788066e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -1219,13 +1219,18 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) ("PreState = %d, CurState = %d\n", p_ra->pre_ratr_state, p_ra->ratr_state)); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); + /* Only the PCI card uses sta in the update rate table + * callback routine */ + if (rtlhal->interface == INTF_PCI) { + rcu_read_lock(); + sta = ieee80211_find_sta(mac->vif, mac->bssid); + } rtlpriv->cfg->ops->update_rate_tbl(hw, sta, p_ra->ratr_state); p_ra->pre_ratr_state = p_ra->ratr_state; - rcu_read_unlock(); + if (rtlhal->interface == INTF_PCI) + rcu_read_unlock(); } } } -- cgit v1.2.3 From 67fd437fd75067e8f5fd02a4cabdc2da3b65abeb Mon Sep 17 00:00:00 2001 From: Jingjun Wu Date: Fri, 2 Mar 2012 20:52:14 -0600 Subject: rtlwifi: rtl8192ce: Fix loss of receive performance commit a9b89e2567c743483e6354f64d7a7e3a8c101e9e upstream. Driver rtl8192ce when used with the RTL8188CE device would start at about 20 Mbps on a 54 Mbps connection, but quickly drop to 1 Mbps. One of the symptoms is that the AP would need to retransmit each packet 4 of 5 times before the driver would acknowledge it. Recovery is possible only by unloading and reloading the driver. This problem was reported at https://bugzilla.redhat.com/show_bug.cgi?id=770207. The problem is due to a missing update of the gain setting. Signed-off-by: Jingjun Wu Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 4de6b788066e..a004ad75d568 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -524,6 +524,10 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw) dm_digtable.cur_igvalue, dm_digtable.pre_igvalue, dm_digtable.backoff_val)); + dm_digtable.cur_igvalue += 2; + if (dm_digtable.cur_igvalue > 0x3f) + dm_digtable.cur_igvalue = 0x3f; + if (dm_digtable.pre_igvalue != dm_digtable.cur_igvalue) { rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, dm_digtable.cur_igvalue); -- cgit v1.2.3 From c8fe46316175840b3a0c2d5f5ad7c9d2c837e58f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Mar 2012 08:50:46 -0800 Subject: iwlwifi: always monitor for stuck queues commit 342bbf3fee2fa9a18147e74b2e3c4229a4564912 upstream. If we only monitor while associated, the following can happen: - we're associated, and the queue stuck check runs, setting the queue "touch" time to X - we disassociate, stopping the monitoring, which leaves the time set to X - almost 2s later, we associate, and enqueue a frame - before the frame is transmitted, we monitor for stuck queues, and find the time set to X, although it is now later than X + 2000ms, so we decide that the queue is stuck and erroneously restart the device It happens more with P2P because there we can go between associated/unassociated frequently. Reported-by: Ben Cahill Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-core.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fcf54160e4ed..3d75d4c45e25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1787,20 +1787,10 @@ void iwl_bg_watchdog(unsigned long data) if (timeout == 0) return; - /* monitor and check for stuck cmd queue */ - if (iwl_check_stuck_queue(priv, priv->shrd->cmd_queue)) - return; - - /* monitor and check for other stuck queues */ - if (iwl_is_any_associated(priv)) { - for (cnt = 0; cnt < hw_params(priv).max_txq_num; cnt++) { - /* skip as we already checked the command queue */ - if (cnt == priv->shrd->cmd_queue) - continue; - if (iwl_check_stuck_queue(priv, cnt)) - return; - } - } + /* monitor and check for stuck queues */ + for (cnt = 0; cnt < hw_params(priv).max_txq_num; cnt++) + if (iwl_check_stuck_queue(priv, cnt)) + return; mod_timer(&priv->watchdog, jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); -- cgit v1.2.3 From c2b033667cb7080061978656681a6ba2108e51bb Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 15 Mar 2012 12:36:13 -0400 Subject: math: Introduce div64_long commit f910381a55cdaa097030291f272f6e6e4380c39a upstream. Add a div64_long macro which is used to devide a 64bit number by a long (which can be 4 bytes on 32bit systems and 8 bytes on 64bit systems). Suggested-by: Thomas Gleixner Signed-off-by: Sasha Levin Cc: johnstul@us.ibm.com Link: http://lkml.kernel.org/r/1331829374-31543-1-git-send-email-levinsasha928@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/linux/math64.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/math64.h b/include/linux/math64.h index 23fcdfcba81b..b8ba85544721 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -6,6 +6,8 @@ #if BITS_PER_LONG == 64 +#define div64_long(x,y) div64_s64((x),(y)) + /** * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder * @@ -45,6 +47,8 @@ static inline s64 div64_s64(s64 dividend, s64 divisor) #elif BITS_PER_LONG == 32 +#define div64_long(x,y) div_s64((x),(y)) + #ifndef div_u64_rem static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) { -- cgit v1.2.3 From 1f2c44df43fef14718d2713f89b1ce1fada45577 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 15 Mar 2012 12:36:14 -0400 Subject: ntp: Fix integer overflow when setting time commit a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33 upstream. 'long secs' is passed as divisor to div_s64, which accepts a 32bit divisor. On 64bit machines that value is trimmed back from 8 bytes back to 4, causing a divide by zero when the number is bigger than (1 << 32) - 1 and all 32 lower bits are 0. Use div64_long() instead. Signed-off-by: Sasha Levin Cc: johnstul@us.ibm.com Link: http://lkml.kernel.org/r/1331829374-31543-2-git-send-email-levinsasha928@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/time/ntp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index f6117a4c7cb8..4b85a7a72526 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -275,7 +275,7 @@ static inline s64 ntp_update_offset_fll(s64 offset64, long secs) time_status |= STA_MODE; - return div_s64(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs); + return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs); } static void ntp_update_offset(long offset) -- cgit v1.2.3 From 1a24aa6ec745d87b9dcac87ebb45959ae19117dc Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Wed, 7 Mar 2012 14:49:56 +0400 Subject: uevent: send events in correct order according to seqnum (v3) commit 7b60a18da393ed70db043a777fd9e6d5363077c4 upstream. The queue handling in the udev daemon assumes that the events are ordered. Before this patch uevent_seqnum is incremented under sequence_lock, than an event is send uner uevent_sock_mutex. I want to say that code contained a window between incrementing seqnum and sending an event. This patch locks uevent_sock_mutex before incrementing uevent_seqnum. v2: delete sequence_lock, uevent_seqnum is protected by uevent_sock_mutex v3: unlock the mutex before the goto exit Thanks for Kay for the comments. Signed-off-by: Andrew Vagin Tested-By: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- lib/kobject_uevent.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index ad72a03ce5e9..6d40244e8010 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -29,16 +29,17 @@ u64 uevent_seqnum; char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; -static DEFINE_SPINLOCK(sequence_lock); #ifdef CONFIG_NET struct uevent_sock { struct list_head list; struct sock *sk; }; static LIST_HEAD(uevent_sock_list); -static DEFINE_MUTEX(uevent_sock_mutex); #endif +/* This lock protects uevent_seqnum and uevent_sock_list */ +static DEFINE_MUTEX(uevent_sock_mutex); + /* the strings here must match the enum in include/linux/kobject.h */ static const char *kobject_actions[] = { [KOBJ_ADD] = "add", @@ -136,7 +137,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, struct kobject *top_kobj; struct kset *kset; const struct kset_uevent_ops *uevent_ops; - u64 seq; int i = 0; int retval = 0; #ifdef CONFIG_NET @@ -243,17 +243,16 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, else if (action == KOBJ_REMOVE) kobj->state_remove_uevent_sent = 1; + mutex_lock(&uevent_sock_mutex); /* we will send an event, so request a new sequence number */ - spin_lock(&sequence_lock); - seq = ++uevent_seqnum; - spin_unlock(&sequence_lock); - retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); - if (retval) + retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum); + if (retval) { + mutex_unlock(&uevent_sock_mutex); goto exit; + } #if defined(CONFIG_NET) /* send netlink message */ - mutex_lock(&uevent_sock_mutex); list_for_each_entry(ue_sk, &uevent_sock_list, list) { struct sock *uevent_sock = ue_sk->sk; struct sk_buff *skb; @@ -287,8 +286,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, } else retval = -ENOMEM; } - mutex_unlock(&uevent_sock_mutex); #endif + mutex_unlock(&uevent_sock_mutex); /* call uevent_helper, usually only enabled during early boot */ if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { -- cgit v1.2.3 From 4e6c04eca71ab6cf9fbec301783540fd773a7536 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Mar 2012 15:07:25 -0800 Subject: genirq: Fix long-term regression in genirq irq_set_irq_type() handling commit a09b659cd68c10ec6a30cb91ebd2c327fcd5bfe5 upstream. In 2008, commit 0c5d1eb77a8be ("genirq: record trigger type") modified the way set_irq_type() handles the 'no trigger' condition. However, this has an adverse effect on PCMCIA support on Intel StrongARM and probably PXA platforms. PCMCIA has several status signals on the socket which can trigger interrupts; some of these status signals depend on the card's mode (whether it is configured in memory or IO mode). For example, cards have a 'Ready/IRQ' signal: in memory mode, this provides an indication to PCMCIA that the card has finished its power up initialization. In IO mode, it provides the device interrupt signal. Other status signals switch between on-board battery status and loud speaker output. In classical PCMCIA implementations, where you have a specific socket controller, the controller provides a method to mask interrupts from the socket, and importantly ignore any state transitions on the pins which correspond with interrupts once masked. This masking prevents unwanted events caused by the removal and application of socket power being forwarded. However, on platforms where there is no socket controller, the PCMCIA status and interrupt signals are routed to standard edge-triggered GPIOs. These GPIOs can be configured to interrupt on rising edge, falling edge, or never. This is where the problems start. Edge triggered interrupts are required to record events while disabled via the usual methods of {free,request,disable,enable}_irq() to prevent problems with dropped interrupts (eg, the 8390 driver uses disable_irq() to defer the delivery of interrupts). As a result, these interfaces can not be used to implement the desired behaviour. The side effect of this is that if the 'Ready/IRQ' GPIO is disabled via disable_irq() on suspend, and enabled via enable_irq() after resume, we will record the state transitions caused by powering events as valid interrupts, and foward them to the card driver, which may attempt to access a card which is not powered up. This leads delays resume while drivers spin in their interrupt handlers, and complaints from drivers before they realize what's happened. Moreover, in the case of the 'Ready/IRQ' signal, this is requested and freed by the card driver itself; the PCMCIA core has no idea whether the interrupt is requested, and, therefore, whether a call to disable_irq() would be valid. (We tried this around 2.4.17 / 2.5.1 kernel era, and ended up throwing it out because of this problem.) Therefore, it was decided back in around 2002 to disable the edge triggering instead, resulting in all state transitions on the GPIO being ignored. That's what we actually need the hardware to do. The commit above changes this behaviour; it explicitly prevents the 'no trigger' state being selected. The reason that request_irq() does not accept the 'no trigger' state is for compatibility with existing drivers which do not provide their desired triggering configuration. The set_irq_type() function is 'new' and not used by non-trigger aware drivers. Therefore, revert this change, and restore previously working platforms back to their former state. Signed-off-by: Russell King Cc: linux@arm.linux.org.uk Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/chip.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index fb7db75ee0c8..25784d630a12 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -61,8 +61,7 @@ int irq_set_irq_type(unsigned int irq, unsigned int type) return -EINVAL; type &= IRQ_TYPE_SENSE_MASK; - if (type != IRQ_TYPE_NONE) - ret = __irq_set_trigger(desc, irq, type); + ret = __irq_set_trigger(desc, irq, type); irq_put_desc_busunlock(desc, flags); return ret; } -- cgit v1.2.3 From d06ce542311192cc20921f22848960e66e110dee Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Fri, 9 Mar 2012 14:59:13 +0100 Subject: genirq: Fix incorrect check for forced IRQ thread handler commit 540b60e24f3f4781d80e47122f0c4486a03375b8 upstream. We do not want a bitwise AND between boolean operands Signed-off-by: Alexander Gordeev Cc: Oleg Nesterov Link: http://lkml.kernel.org/r/20120309135912.GA2114@dhcp-26-207.brq.redhat.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ae95cd2ce0cb..76000927da3f 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -773,7 +773,7 @@ static int irq_thread(void *data) struct irqaction *action); int wake; - if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD, + if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD, &action->thread_flags)) handler_fn = irq_forced_thread_fn; else -- cgit v1.2.3 From 63d1c8663a622c8861b65d89b6f24578cb485655 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 22 Nov 2011 11:03:14 +0100 Subject: rtc: Disable the alarm in the hardware (v2) commit 41c7f7424259ff11009449f87c95656f69f9b186 upstream. Currently, the RTC code does not disable the alarm in the hardware. This means that after a sequence such as the one below (the files are in the RTC sysfs), the box will boot up after 2 minutes even though we've asked for the alarm to be turned off. # echo $((`cat since_epoch`)+120) > wakealarm # echo 0 > wakealarm # poweroff Fix this by disabling the alarm when there are no timers to run. The original version of this patch was reverted. This version disables the irq directly instead of setting a disabled timer in the future. Cc: John Stultz Signed-off-by: Rabin Vincent [Merged in the second revision from Rabin] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8a1c031391d6..c1edbf819652 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -763,6 +763,14 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) return 0; } +static void rtc_alarm_disable(struct rtc_device *rtc) +{ + if (!rtc->ops || !rtc->ops->alarm_irq_enable) + return; + + rtc->ops->alarm_irq_enable(rtc->dev.parent, false); +} + /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device @@ -784,8 +792,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) struct rtc_wkalrm alarm; int err; next = timerqueue_getnext(&rtc->timerqueue); - if (!next) + if (!next) { + rtc_alarm_disable(rtc); return; + } alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); @@ -847,7 +857,8 @@ again: err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; - } + } else + rtc_alarm_disable(rtc); mutex_unlock(&rtc->ops_lock); } -- cgit v1.2.3 From 0abe0c69f3f07313c6f9eaa60b2a760a9a5c94f5 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 1 Mar 2012 00:40:08 +0400 Subject: p54spi: Release GPIO lines and IRQ on error in p54spi_probe commit 62ebeed8d00aef75eac4fd6c161cae75a41965ca upstream. This makes it possible to reload driver if insmod has failed due to missing firmware. Signed-off-by: Max Filippov Acked-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54spi.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 78d0d6988553..428401b3b3a6 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -622,19 +622,19 @@ static int __devinit p54spi_probe(struct spi_device *spi) ret = spi_setup(spi); if (ret < 0) { dev_err(&priv->spi->dev, "spi_setup failed"); - goto err_free_common; + goto err_free; } ret = gpio_request(p54spi_gpio_power, "p54spi power"); if (ret < 0) { dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret); - goto err_free_common; + goto err_free; } ret = gpio_request(p54spi_gpio_irq, "p54spi irq"); if (ret < 0) { dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret); - goto err_free_common; + goto err_free_gpio_power; } gpio_direction_output(p54spi_gpio_power, 0); @@ -645,7 +645,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) priv->spi); if (ret < 0) { dev_err(&priv->spi->dev, "request_irq() failed"); - goto err_free_common; + goto err_free_gpio_irq; } irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); @@ -677,6 +677,12 @@ static int __devinit p54spi_probe(struct spi_device *spi) return 0; err_free_common: + free_irq(gpio_to_irq(p54spi_gpio_irq), spi); +err_free_gpio_irq: + gpio_free(p54spi_gpio_irq); +err_free_gpio_power: + gpio_free(p54spi_gpio_power); +err_free: p54_free_common(priv->hw); return ret; } -- cgit v1.2.3 From 2e4d3c51483d1272acb34db75695423a7e2f8163 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Wed, 8 Feb 2012 00:45:00 +0000 Subject: rtnetlink: Fix VF IFLA policy commit 48752f6513012a1b078da08b145d5c40a644f058 upstream. Add VF spoof check to IFLA policy. The original patch I submitted to add the spoof checking feature to rtnl failed to add the proper policy rule that identifies the data type and len. This patch corrects that oversight. No bugs have been reported against this but it may cause some problem for the netlink message parsing that uses the policy table. Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman --- net/core/rtnetlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 9083e82bdae5..2ef859a94587 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1116,6 +1116,8 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { .len = sizeof(struct ifla_vf_vlan) }, [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, .len = sizeof(struct ifla_vf_tx_rate) }, + [IFLA_VF_SPOOFCHK] = { .type = NLA_BINARY, + .len = sizeof(struct ifla_vf_spoofchk) }, }; static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = { -- cgit v1.2.3 From 9af865fc7d42e347f679405000fc22ecbfbf2653 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 5 Mar 2012 18:21:44 +0200 Subject: IB/iser: Post initial receive buffers before sending the final login request commit 89e984e2c2cd14f77ccb26c47726ac7f13b70ae8 upstream. An iser target may send iscsi NO-OP PDUs as soon as it marks the iSER iSCSI session as fully operative. This means that there is window where there are no posted receive buffers on the initiator side, so it's possible for the iSER RC connection to break because of RNR NAK / retry errors. To fix this, rely on the flags bits in the login request to have FFP (0x3) in the lower nibble as a marker for the final login request, and post an initial chunk of receive buffers before sending that login request instead of after getting the login response. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/iser/iscsi_iser.c | 18 ++++------------- drivers/infiniband/ulp/iser/iscsi_iser.h | 1 + drivers/infiniband/ulp/iser/iser_initiator.c | 30 ++++++++++++++++------------ 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 7e7373a700e6..d5f3b692cdd0 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -364,6 +364,9 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, } ib_conn = ep->dd_data; + if (iser_alloc_rx_descriptors(ib_conn)) + return -ENOMEM; + /* binds the iSER connection retrieved from the previously * connected ep_handle to the iSCSI layer connection. exchanges * connection pointers */ @@ -398,19 +401,6 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) iser_conn->ib_conn = NULL; } -static int -iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - int err; - - err = iser_conn_set_full_featured_mode(conn); - if (err) - return err; - - return iscsi_conn_start(cls_conn); -} - static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) { struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); @@ -724,7 +714,7 @@ static struct iscsi_transport iscsi_iser_transport = { .get_conn_param = iscsi_conn_get_param, .get_ep_param = iscsi_iser_get_ep_param, .get_session_param = iscsi_session_get_param, - .start_conn = iscsi_iser_conn_start, + .start_conn = iscsi_conn_start, .stop_conn = iscsi_iser_conn_stop, /* iscsi host params */ .get_host_param = iscsi_host_get_param, diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index db7ea3704da7..296be431a0e9 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -366,4 +366,5 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); int iser_initialize_task_headers(struct iscsi_task *task, struct iser_tx_desc *tx_desc); +int iser_alloc_rx_descriptors(struct iser_conn *ib_conn); #endif diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index a607542fc796..738a1499812b 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -170,7 +170,7 @@ static void iser_create_send_desc(struct iser_conn *ib_conn, } -static int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) +int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) { int i, j; u64 dma_addr; @@ -242,23 +242,24 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn) kfree(ib_conn->rx_descs); } -/** - * iser_conn_set_full_featured_mode - (iSER API) - */ -int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) +static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req) { struct iscsi_iser_conn *iser_conn = conn->dd_data; - iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX); - - /* Check that there is no posted recv or send buffers left - */ - /* they must be consumed during the login phase */ - BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0); - BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); + iser_dbg("req op %x flags %x\n", req->opcode, req->flags); + /* check if this is the last login - going to full feature phase */ + if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE) + return 0; - if (iser_alloc_rx_descriptors(iser_conn->ib_conn)) - return -ENOMEM; + /* + * Check that there is one posted recv buffer (for the last login + * response) and no posted send buffers left - they must have been + * consumed during previous login phases. + */ + WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1); + WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); + iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX); /* Initial post receive buffers */ if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX)) return -ENOMEM; @@ -438,6 +439,9 @@ int iser_send_control(struct iscsi_conn *conn, err = iser_post_recvl(iser_conn->ib_conn); if (err) goto send_control_error; + err = iser_post_rx_bufs(conn, task->hdr); + if (err) + goto send_control_error; } err = iser_post_send(iser_conn->ib_conn, mdesc); -- cgit v1.2.3 From 4a02744bb48ce0d1ea3470c5f791382786a02ee9 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 5 Jan 2012 12:49:54 -0200 Subject: ima: fix Kconfig dependencies commit f4a0391dfa91155bd961673b31eb42d9d45c799d upstream. Fix the following build warning: warning: (IMA) selects TCG_TPM which has unmet direct dependencies (HAS_IOMEM && EXPERIMENTAL) Suggested-by: Rajiv Andrade Signed-off-by: Fabio Estevam Signed-off-by: Rajiv Andrade Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/Kconfig | 1 - security/integrity/ima/Kconfig | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index fa567f1158c2..c9e045cfa631 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -5,7 +5,6 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM - depends on EXPERIMENTAL select SECURITYFS ---help--- If you have a TPM security chip in your system, which diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 4f554f20dc97..063298a797e8 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -9,7 +9,7 @@ config IMA select CRYPTO_HMAC select CRYPTO_MD5 select CRYPTO_SHA1 - select TCG_TPM if !S390 && !UML + select TCG_TPM if HAS_IOMEM && !UML select TCG_TIS if TCG_TPM help The Trusted Computing Group(TCG) runtime Integrity -- cgit v1.2.3 From 273fb194e86b795b08a724c7646d0f694949070b Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 12 Mar 2012 11:36:33 -0700 Subject: x86/ioapic: Add register level checks to detect bogus io-apic entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 73d63d038ee9f769f5e5b46792d227fe20e442c5 upstream. With the recent changes to clear_IO_APIC_pin() which tries to clear remoteIRR bit explicitly, some of the users started to see "Unable to reset IRR for apic .." messages. Close look shows that these are related to bogus IO-APIC entries which return's all 1's for their io-apic registers. And the above mentioned error messages are benign. But kernel should have ignored such io-apic's in the first place. Check if register 0, 1, 2 of the listed io-apic are all 1's and ignore such io-apic. Reported-by: Álvaro Castillo Tested-by: Jon Dufresne Signed-off-by: Suresh Siddha Cc: yinghai@kernel.org Cc: kernel-team@fedoraproject.org Cc: Josh Boyer Link: http://lkml.kernel.org/r/1331577393.31585.94.camel@sbsiddha-desk.sc.intel.com [ Performed minor cleanup of affected code. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/apic/io_apic.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 6d939d7847e2..a25e276bf41e 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3963,18 +3963,36 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi) static __init int bad_ioapic(unsigned long address) { if (nr_ioapics >= MAX_IO_APICS) { - printk(KERN_WARNING "WARNING: Max # of I/O APICs (%d) exceeded " - "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics); + pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n", + MAX_IO_APICS, nr_ioapics); return 1; } if (!address) { - printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address" - " found in table, skipping!\n"); + pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n"); return 1; } return 0; } +static __init int bad_ioapic_register(int idx) +{ + union IO_APIC_reg_00 reg_00; + union IO_APIC_reg_01 reg_01; + union IO_APIC_reg_02 reg_02; + + reg_00.raw = io_apic_read(idx, 0); + reg_01.raw = io_apic_read(idx, 1); + reg_02.raw = io_apic_read(idx, 2); + + if (reg_00.raw == -1 && reg_01.raw == -1 && reg_02.raw == -1) { + pr_warn("I/O APIC 0x%x registers return all ones, skipping!\n", + mpc_ioapic_addr(idx)); + return 1; + } + + return 0; +} + void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) { int idx = 0; @@ -3991,6 +4009,12 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) ioapics[idx].mp_config.apicaddr = address; set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); + + if (bad_ioapic_register(idx)) { + clear_fixmap(FIX_IO_APIC_BASE_0 + idx); + return; + } + ioapics[idx].mp_config.apicid = io_apic_unique_id(id); ioapics[idx].mp_config.apicver = io_apic_get_version(idx); @@ -4011,10 +4035,10 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) if (gsi_cfg->gsi_end >= gsi_top) gsi_top = gsi_cfg->gsi_end + 1; - printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " - "GSI %d-%d\n", idx, mpc_ioapic_id(idx), - mpc_ioapic_ver(idx), mpc_ioapic_addr(idx), - gsi_cfg->gsi_base, gsi_cfg->gsi_end); + pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n", + idx, mpc_ioapic_id(idx), + mpc_ioapic_ver(idx), mpc_ioapic_addr(idx), + gsi_cfg->gsi_base, gsi_cfg->gsi_end); nr_ioapics++; } -- cgit v1.2.3 From c6cf24ba30c7225667827245cfd2bc98f7f5ed2b Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 21 Mar 2012 16:33:42 -0700 Subject: mm: thp: fix pmd_bad() triggering in code paths holding mmap_sem read mode commit 1a5a9906d4e8d1976b701f889d8f35d54b928f25 upstream. In some cases it may happen that pmd_none_or_clear_bad() is called with the mmap_sem hold in read mode. In those cases the huge page faults can allocate hugepmds under pmd_none_or_clear_bad() and that can trigger a false positive from pmd_bad() that will not like to see a pmd materializing as trans huge. It's not khugepaged causing the problem, khugepaged holds the mmap_sem in write mode (and all those sites must hold the mmap_sem in read mode to prevent pagetables to go away from under them, during code review it seems vm86 mode on 32bit kernels requires that too unless it's restricted to 1 thread per process or UP builds). The race is only with the huge pagefaults that can convert a pmd_none() into a pmd_trans_huge(). Effectively all these pmd_none_or_clear_bad() sites running with mmap_sem in read mode are somewhat speculative with the page faults, and the result is always undefined when they run simultaneously. This is probably why it wasn't common to run into this. For example if the madvise(MADV_DONTNEED) runs zap_page_range() shortly before the page fault, the hugepage will not be zapped, if the page fault runs first it will be zapped. Altering pmd_bad() not to error out if it finds hugepmds won't be enough to fix this, because zap_pmd_range would then proceed to call zap_pte_range (which would be incorrect if the pmd become a pmd_trans_huge()). The simplest way to fix this is to read the pmd in the local stack (regardless of what we read, no need of actual CPU barriers, only compiler barrier needed), and be sure it is not changing under the code that computes its value. Even if the real pmd is changing under the value we hold on the stack, we don't care. If we actually end up in zap_pte_range it means the pmd was not none already and it was not huge, and it can't become huge from under us (khugepaged locking explained above). All we need is to enforce that there is no way anymore that in a code path like below, pmd_trans_huge can be false, but pmd_none_or_clear_bad can run into a hugepmd. The overhead of a barrier() is just a compiler tweak and should not be measurable (I only added it for THP builds). I don't exclude different compiler versions may have prevented the race too by caching the value of *pmd on the stack (that hasn't been verified, but it wouldn't be impossible considering pmd_none_or_clear_bad, pmd_bad, pmd_trans_huge, pmd_none are all inlines and there's no external function called in between pmd_trans_huge and pmd_none_or_clear_bad). if (pmd_trans_huge(*pmd)) { if (next-addr != HPAGE_PMD_SIZE) { VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem)); split_huge_page_pmd(vma->vm_mm, pmd); } else if (zap_huge_pmd(tlb, vma, pmd, addr)) continue; /* fall through */ } if (pmd_none_or_clear_bad(pmd)) Because this race condition could be exercised without special privileges this was reported in CVE-2012-1179. The race was identified and fully explained by Ulrich who debugged it. I'm quoting his accurate explanation below, for reference. ====== start quote ======= mapcount 0 page_mapcount 1 kernel BUG at mm/huge_memory.c:1384! At some point prior to the panic, a "bad pmd ..." message similar to the following is logged on the console: mm/memory.c:145: bad pmd ffff8800376e1f98(80000000314000e7). The "bad pmd ..." message is logged by pmd_clear_bad() before it clears the page's PMD table entry. 143 void pmd_clear_bad(pmd_t *pmd) 144 { -> 145 pmd_ERROR(*pmd); 146 pmd_clear(pmd); 147 } After the PMD table entry has been cleared, there is an inconsistency between the actual number of PMD table entries that are mapping the page and the page's map count (_mapcount field in struct page). When the page is subsequently reclaimed, __split_huge_page() detects this inconsistency. 1381 if (mapcount != page_mapcount(page)) 1382 printk(KERN_ERR "mapcount %d page_mapcount %d\n", 1383 mapcount, page_mapcount(page)); -> 1384 BUG_ON(mapcount != page_mapcount(page)); The root cause of the problem is a race of two threads in a multithreaded process. Thread B incurs a page fault on a virtual address that has never been accessed (PMD entry is zero) while Thread A is executing an madvise() system call on a virtual address within the same 2 MB (huge page) range. virtual address space .---------------------. | | | | .-|---------------------| | | | | | |<-- B(fault) | | | 2 MB | |/////////////////////|-. huge < |/////////////////////| > A(range) page | |/////////////////////|-' | | | | | | '-|---------------------| | | | | '---------------------' - Thread A is executing an madvise(..., MADV_DONTNEED) system call on the virtual address range "A(range)" shown in the picture. sys_madvise // Acquire the semaphore in shared mode. down_read(¤t->mm->mmap_sem) ... madvise_vma switch (behavior) case MADV_DONTNEED: madvise_dontneed zap_page_range unmap_vmas unmap_page_range zap_pud_range zap_pmd_range // // Assume that this huge page has never been accessed. // I.e. content of the PMD entry is zero (not mapped). // if (pmd_trans_huge(*pmd)) { // We don't get here due to the above assumption. } // // Assume that Thread B incurred a page fault and .---------> // sneaks in here as shown below. | // | if (pmd_none_or_clear_bad(pmd)) | { | if (unlikely(pmd_bad(*pmd))) | pmd_clear_bad | { | pmd_ERROR | // Log "bad pmd ..." message here. | pmd_clear | // Clear the page's PMD entry. | // Thread B incremented the map count | // in page_add_new_anon_rmap(), but | // now the page is no longer mapped | // by a PMD entry (-> inconsistency). | } | } | v - Thread B is handling a page fault on virtual address "B(fault)" shown in the picture. ... do_page_fault __do_page_fault // Acquire the semaphore in shared mode. down_read_trylock(&mm->mmap_sem) ... handle_mm_fault if (pmd_none(*pmd) && transparent_hugepage_enabled(vma)) // We get here due to the above assumption (PMD entry is zero). do_huge_pmd_anonymous_page alloc_hugepage_vma // Allocate a new transparent huge page here. ... __do_huge_pmd_anonymous_page ... spin_lock(&mm->page_table_lock) ... page_add_new_anon_rmap // Here we increment the page's map count (starts at -1). atomic_set(&page->_mapcount, 0) set_pmd_at // Here we set the page's PMD entry which will be cleared // when Thread A calls pmd_clear_bad(). ... spin_unlock(&mm->page_table_lock) The mmap_sem does not prevent the race because both threads are acquiring it in shared mode (down_read). Thread B holds the page_table_lock while the page's map count and PMD table entry are updated. However, Thread A does not synchronize on that lock. ====== end quote ======= [akpm@linux-foundation.org: checkpatch fixes] Reported-by: Ulrich Obergfell Signed-off-by: Andrea Arcangeli Acked-by: Johannes Weiner Cc: Mel Gorman Cc: Hugh Dickins Cc: Dave Jones Acked-by: Larry Woodman Acked-by: Rik van Riel Cc: Mark Salter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/vm86_32.c | 2 ++ fs/proc/task_mmu.c | 9 +++++++ include/asm-generic/pgtable.h | 61 +++++++++++++++++++++++++++++++++++++++++++ mm/memcontrol.c | 4 +++ mm/memory.c | 16 +++++++++--- mm/mempolicy.c | 2 +- mm/mincore.c | 2 +- mm/pagewalk.c | 2 +- mm/swapfile.c | 4 +-- 9 files changed, 92 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 863f8753ab0a..04b87269edfb 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -172,6 +172,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) spinlock_t *ptl; int i; + down_write(&mm->mmap_sem); pgd = pgd_offset(mm, 0xA0000); if (pgd_none_or_clear_bad(pgd)) goto out; @@ -190,6 +191,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) } pte_unmap_unlock(pte, ptl); out: + up_write(&mm->mmap_sem); flush_tlb(); } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7dcd2a250495..3efa7253523e 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -409,6 +409,9 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, } else { spin_unlock(&walk->mm->page_table_lock); } + + if (pmd_trans_unstable(pmd)) + return 0; /* * The mmap_sem held all the way back in m_start() is what * keeps khugepaged out of here and from collapsing things @@ -507,6 +510,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, struct page *page; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) { @@ -670,6 +675,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, int err = 0; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; /* find the first VMA at or above 'addr' */ vma = find_vma(walk->mm, addr); @@ -961,6 +968,8 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, spin_unlock(&walk->mm->page_table_lock); } + if (pmd_trans_unstable(pmd)) + return 0; orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); do { struct page *page = can_gather_numa_stats(*pte, md->vma, addr); diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 76bff2bff15e..a03c098b0cce 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -425,6 +425,8 @@ extern void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn, unsigned long size); #endif +#ifdef CONFIG_MMU + #ifndef CONFIG_TRANSPARENT_HUGEPAGE static inline int pmd_trans_huge(pmd_t pmd) { @@ -441,7 +443,66 @@ static inline int pmd_write(pmd_t pmd) return 0; } #endif /* __HAVE_ARCH_PMD_WRITE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +/* + * This function is meant to be used by sites walking pagetables with + * the mmap_sem hold in read mode to protect against MADV_DONTNEED and + * transhuge page faults. MADV_DONTNEED can convert a transhuge pmd + * into a null pmd and the transhuge page fault can convert a null pmd + * into an hugepmd or into a regular pmd (if the hugepage allocation + * fails). While holding the mmap_sem in read mode the pmd becomes + * stable and stops changing under us only if it's not null and not a + * transhuge pmd. When those races occurs and this function makes a + * difference vs the standard pmd_none_or_clear_bad, the result is + * undefined so behaving like if the pmd was none is safe (because it + * can return none anyway). The compiler level barrier() is critically + * important to compute the two checks atomically on the same pmdval. + */ +static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) +{ + /* depend on compiler for an atomic pmd read */ + pmd_t pmdval = *pmd; + /* + * The barrier will stabilize the pmdval in a register or on + * the stack so that it will stop changing under the code. + */ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + barrier(); +#endif + if (pmd_none(pmdval)) + return 1; + if (unlikely(pmd_bad(pmdval))) { + if (!pmd_trans_huge(pmdval)) + pmd_clear_bad(pmd); + return 1; + } + return 0; +} + +/* + * This is a noop if Transparent Hugepage Support is not built into + * the kernel. Otherwise it is equivalent to + * pmd_none_or_trans_huge_or_clear_bad(), and shall only be called in + * places that already verified the pmd is not none and they want to + * walk ptes while holding the mmap sem in read mode (write mode don't + * need this). If THP is not enabled, the pmd can't go away under the + * code even if MADV_DONTNEED runs, but if THP is enabled we need to + * run a pmd_trans_unstable before walking the ptes after + * split_huge_page_pmd returns (because it may have run when the pmd + * become null, but then a page fault can map in a THP and not a + * regular page). + */ +static inline int pmd_trans_unstable(pmd_t *pmd) +{ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + return pmd_none_or_trans_huge_or_clear_bad(pmd); +#else + return 0; #endif +} + +#endif /* CONFIG_MMU */ #endif /* !__ASSEMBLY__ */ diff --git a/mm/memcontrol.c b/mm/memcontrol.c index de67e916a960..778554ffd639 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5237,6 +5237,8 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd, spinlock_t *ptl; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) @@ -5398,6 +5400,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd, spinlock_t *ptl; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; retry: pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; addr += PAGE_SIZE) { diff --git a/mm/memory.c b/mm/memory.c index 829d43735402..1b1ca176397e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1228,16 +1228,24 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, do { next = pmd_addr_end(addr, end); if (pmd_trans_huge(*pmd)) { - if (next-addr != HPAGE_PMD_SIZE) { + if (next - addr != HPAGE_PMD_SIZE) { VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem)); split_huge_page_pmd(vma->vm_mm, pmd); } else if (zap_huge_pmd(tlb, vma, pmd)) - continue; + goto next; /* fall through */ } - if (pmd_none_or_clear_bad(pmd)) - continue; + /* + * Here there can be other concurrent MADV_DONTNEED or + * trans huge page faults running, and if the pmd is + * none or trans huge it can change under us. This is + * because MADV_DONTNEED holds the mmap_sem in read + * mode. + */ + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) + goto next; next = zap_pte_range(tlb, vma, pmd, addr, next, details); +next: cond_resched(); } while (pmd++, addr = next, addr != end); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index c3fdbcb17658..b26aae28d9d9 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -512,7 +512,7 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, do { next = pmd_addr_end(addr, end); split_huge_page_pmd(vma->vm_mm, pmd); - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) continue; if (check_pte_range(vma, pmd, addr, next, nodes, flags, private)) diff --git a/mm/mincore.c b/mm/mincore.c index 636a86876ff2..936b4cee8cb1 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -164,7 +164,7 @@ static void mincore_pmd_range(struct vm_area_struct *vma, pud_t *pud, } /* fall through */ } - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) mincore_unmapped_range(vma, addr, next, vec); else mincore_pte_range(vma, pmd, addr, next, vec); diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 2f5cf10ff660..aa9701e12714 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -59,7 +59,7 @@ again: continue; split_huge_page_pmd(walk->mm, pmd); - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) goto again; err = walk_pte_range(pmd, addr, next, walk); if (err) diff --git a/mm/swapfile.c b/mm/swapfile.c index b1cd12060723..2015a1e42dc0 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -931,9 +931,7 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud, pmd = pmd_offset(pud, addr); do { next = pmd_addr_end(addr, end); - if (unlikely(pmd_trans_huge(*pmd))) - continue; - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) continue; ret = unuse_pte_range(vma, pmd, addr, next, entry, page); if (ret) -- cgit v1.2.3 From 923da1e9e292633437c35fd870d47f18b0ee197f Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Tue, 6 Dec 2011 11:29:20 -0700 Subject: TPM: Zero buffer whole after copying to userspace commit 3ab1aff89477dafb1aaeafe8c8669114a02b7226 upstream. Commit 3321c07ae5068568cd61ac9f4ba749006a7185c9 correctly clears the TPM buffer if the user specified read length is >= the TPM buffer length. However, if the user specified read length is < the TPM buffer length, then part of the TPM buffer is left uncleared. Reported-by: Seth Forshee Cc: Debora Velarde Cc: Rajiv Andrade Cc: Marcel Selhorst Cc: tpmdd-devel@lists.sourceforge.net Signed-off-by: Tim Gardner Signed-off-by: Rajiv Andrade Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 361a1dff8f77..b366b34c8549 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1115,12 +1115,13 @@ ssize_t tpm_read(struct file *file, char __user *buf, ret_size = atomic_read(&chip->data_pending); atomic_set(&chip->data_pending, 0); if (ret_size > 0) { /* relay data */ + ssize_t orig_ret_size = ret_size; if (size < ret_size) ret_size = size; mutex_lock(&chip->buffer_mutex); rc = copy_to_user(buf, chip->data_buffer, ret_size); - memset(chip->data_buffer, 0, ret_size); + memset(chip->data_buffer, 0, orig_ret_size); if (rc) ret_size = -EFAULT; -- cgit v1.2.3 From 5c6156fac087f551cbd57499f4bed2fc614d70cd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 13 Mar 2012 22:39:31 +0100 Subject: PM / Domains: Fix handling of wakeup devices during system resume commit cc85b20780562d404e18a47b9b55b4a5102ae53e upstream. During system suspend pm_genpd_suspend_noirq() checks if the given device is in a wakeup path (i.e. it appears to be needed for one or more wakeup devices to work or is a wakeup device itself) and if it needs to be "active" for wakeup to work. If that is the case, the function returns 0 without incrementing the device domain's counter of suspended devices and without executing genpd_stop_dev() for the device. In consequence, the device is not stopped (e.g. its clock isn't disabled) and power is always supplied to its domain in the resulting system sleep state. However, pm_genpd_resume_noirq() doesn't repeat that check and it runs genpd_start_dev() and decrements the domain's counter of suspended devices even for the wakeup device that weren't stopped by pm_genpd_suspend_noirq(). As a result, the start callback may be run unnecessarily for them and their domains' counters of suspended devices may become negative. Both outcomes aren't desirable, so fix pm_genpd_resume_noirq() to look for wakeup devices that might not be stopped by during system suspend. Signed-off-by: Rafael J. Wysocki Tested-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/domain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6790cf7eba5a..79038e50cb2a 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -751,7 +751,8 @@ static int pm_genpd_resume_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off) + if (genpd->suspend_power_off + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) return 0; /* -- cgit v1.2.3 From 9565cb71a1c0fbeab977cc346063873319f1953d Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Wed, 21 Mar 2012 16:34:07 -0700 Subject: bootmem/sparsemem: remove limit constraint in alloc_bootmem_section commit f5bf18fa22f8c41a13eb8762c7373eb3a93a7333 upstream. While testing AMS (Active Memory Sharing) / CMO (Cooperative Memory Overcommit) on powerpc, we tripped the following: kernel BUG at mm/bootmem.c:483! cpu 0x0: Vector: 700 (Program Check) at [c000000000c03940] pc: c000000000a62bd8: .alloc_bootmem_core+0x90/0x39c lr: c000000000a64bcc: .sparse_early_usemaps_alloc_node+0x84/0x29c sp: c000000000c03bc0 msr: 8000000000021032 current = 0xc000000000b0cce0 paca = 0xc000000001d80000 pid = 0, comm = swapper kernel BUG at mm/bootmem.c:483! enter ? for help [c000000000c03c80] c000000000a64bcc .sparse_early_usemaps_alloc_node+0x84/0x29c [c000000000c03d50] c000000000a64f10 .sparse_init+0x12c/0x28c [c000000000c03e20] c000000000a474f4 .setup_arch+0x20c/0x294 [c000000000c03ee0] c000000000a4079c .start_kernel+0xb4/0x460 [c000000000c03f90] c000000000009670 .start_here_common+0x1c/0x2c This is BUG_ON(limit && goal + size > limit); and after some debugging, it seems that goal = 0x7ffff000000 limit = 0x80000000000 and sparse_early_usemaps_alloc_node -> sparse_early_usemaps_alloc_pgdat_section calls return alloc_bootmem_section(usemap_size() * count, section_nr); This is on a system with 8TB available via the AMS pool, and as a quirk of AMS in firmware, all of that memory shows up in node 0. So, we end up with an allocation that will fail the goal/limit constraints. In theory, we could "fall-back" to alloc_bootmem_node() in sparse_early_usemaps_alloc_node(), but since we actually have HOTREMOVE defined, we'll BUG_ON() instead. A simple solution appears to be to unconditionally remove the limit condition in alloc_bootmem_section, meaning allocations are allowed to cross section boundaries (necessary for systems of this size). Johannes Weiner pointed out that if alloc_bootmem_section() no longer guarantees section-locality, we need check_usemap_section_nr() to print possible cross-dependencies between node descriptors and the usemaps allocated through it. That makes the two loops in sparse_early_usemaps_alloc_node() identical, so re-factor the code a bit. [akpm@linux-foundation.org: code simplification] Signed-off-by: Nishanth Aravamudan Cc: Dave Hansen Cc: Anton Blanchard Cc: Paul Mackerras Cc: Ben Herrenschmidt Cc: Robert Jennings Acked-by: Johannes Weiner Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/bootmem.c | 5 ++--- mm/sparse.c | 30 +++++++++++------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/mm/bootmem.c b/mm/bootmem.c index 1a77012ecdb3..b8638224c5dd 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -768,14 +768,13 @@ void * __init alloc_bootmem_section(unsigned long size, unsigned long section_nr) { bootmem_data_t *bdata; - unsigned long pfn, goal, limit; + unsigned long pfn, goal; pfn = section_nr_to_pfn(section_nr); goal = pfn << PAGE_SHIFT; - limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT; bdata = &bootmem_node_data[early_pfn_to_nid(pfn)]; - return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit); + return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, 0); } #endif diff --git a/mm/sparse.c b/mm/sparse.c index 61d7cde23111..a8bc7d364deb 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -353,29 +353,21 @@ static void __init sparse_early_usemaps_alloc_node(unsigned long**usemap_map, usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid), usemap_count); - if (usemap) { - for (pnum = pnum_begin; pnum < pnum_end; pnum++) { - if (!present_section_nr(pnum)) - continue; - usemap_map[pnum] = usemap; - usemap += size; + if (!usemap) { + usemap = alloc_bootmem_node(NODE_DATA(nodeid), size * usemap_count); + if (!usemap) { + printk(KERN_WARNING "%s: allocation failed\n", __func__); + return; } - return; } - usemap = alloc_bootmem_node(NODE_DATA(nodeid), size * usemap_count); - if (usemap) { - for (pnum = pnum_begin; pnum < pnum_end; pnum++) { - if (!present_section_nr(pnum)) - continue; - usemap_map[pnum] = usemap; - usemap += size; - check_usemap_section_nr(nodeid, usemap_map[pnum]); - } - return; + for (pnum = pnum_begin; pnum < pnum_end; pnum++) { + if (!present_section_nr(pnum)) + continue; + usemap_map[pnum] = usemap; + usemap += size; + check_usemap_section_nr(nodeid, usemap_map[pnum]); } - - printk(KERN_WARNING "%s: allocation failed\n", __func__); } #ifndef CONFIG_SPARSEMEM_VMEMMAP -- cgit v1.2.3 From fe4e2fab7a5efb7352985a195d0a7d95816a698b Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 21 Mar 2012 16:34:08 -0700 Subject: hugetlbfs: avoid taking i_mutex from hugetlbfs_read() commit a05b0855fd15504972dba2358e5faa172a1e50ba upstream. Taking i_mutex in hugetlbfs_read() can result in deadlock with mmap as explained below Thread A: read() on hugetlbfs hugetlbfs_read() called i_mutex grabbed hugetlbfs_read_actor() called __copy_to_user() called page fault is triggered Thread B, sharing address space with A: mmap() the same file ->mmap_sem is grabbed on task_B->mm->mmap_sem hugetlbfs_file_mmap() is called attempt to grab ->i_mutex and block waiting for A to give it up Thread A: pagefault handled blocked on attempt to grab task_A->mm->mmap_sem, which happens to be the same thing as task_B->mm->mmap_sem. Block waiting for B to give it up. AFAIU the i_mutex locking was added to hugetlbfs_read() as per http://lkml.indiana.edu/hypermail/linux/kernel/0707.2/3066.html to take care of the race between truncate and read. This patch fixes this by looking at page->mapping under lock_page() (find_lock_page()) to ensure that the inode didn't get truncated in the range during a parallel read. Ideally we can extend the patch to make sure we don't increase i_size in mmap. But that will break userspace, because applications will now have to use truncate(2) to increase i_size in hugetlbfs. Based on the original patch from Hillf Danton. Signed-off-by: Aneesh Kumar K.V Cc: Hillf Danton Cc: KAMEZAWA Hiroyuki Cc: Al Viro Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/hugetlbfs/inode.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0be5a78598d0..2d0ca246a508 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -238,17 +238,10 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, loff_t isize; ssize_t retval = 0; - mutex_lock(&inode->i_mutex); - /* validate length */ if (len == 0) goto out; - isize = i_size_read(inode); - if (!isize) - goto out; - - end_index = (isize - 1) >> huge_page_shift(h); for (;;) { struct page *page; unsigned long nr, ret; @@ -256,18 +249,21 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, /* nr is the maximum number of bytes to copy from this page */ nr = huge_page_size(h); + isize = i_size_read(inode); + if (!isize) + goto out; + end_index = (isize - 1) >> huge_page_shift(h); if (index >= end_index) { if (index > end_index) goto out; nr = ((isize - 1) & ~huge_page_mask(h)) + 1; - if (nr <= offset) { + if (nr <= offset) goto out; - } } nr = nr - offset; /* Find the page */ - page = find_get_page(mapping, index); + page = find_lock_page(mapping, index); if (unlikely(page == NULL)) { /* * We have a HOLE, zero out the user-buffer for the @@ -279,17 +275,18 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, else ra = 0; } else { + unlock_page(page); + /* * We have the page, copy it to user space buffer. */ ra = hugetlbfs_read_actor(page, offset, buf, len, nr); ret = ra; + page_cache_release(page); } if (ra < 0) { if (retval == 0) retval = ra; - if (page) - page_cache_release(page); goto out; } @@ -299,16 +296,12 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, index += offset >> huge_page_shift(h); offset &= ~huge_page_mask(h); - if (page) - page_cache_release(page); - /* short read or no more work */ if ((ret != nr) || (len == 0)) break; } out: *ppos = ((loff_t)index << huge_page_shift(h)) + offset; - mutex_unlock(&inode->i_mutex); return retval; } -- cgit v1.2.3 From 34ef160b39875c7f823f29b8925e1331d940148c Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 16 Mar 2012 16:32:52 -0500 Subject: ASoC: fsl: p1022ds: tell the WM8776 codec driver that it's the master commit 70ac07bb633dee75ac554195b9a4d69adfa7803c upstream. The WM8776 codec driver requires the machine driver to set one of the SND_SOC_DAIFMT_CBx_xxx values. The P1022DS machine driver should be setting SND_SOC_DAIFMT_CBM_CFM, but since that value was zero, no one noticed. Commit 75d9ac46 ("ASoC: Allow DAI formats to be specified in the dai_link"), however, changed the value of SND_SOC_DAIFMT_CBM_CFM from zero to a non-zero value, which means that it now needs to be specifically set by the machine driver. We also set SND_SOC_DAIFMT_NB_NF, for the same reason. Signed-off-by: Timur Tabi Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/fsl/p1022_ds.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 2c064a9824ad..075677cc7793 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -392,7 +392,8 @@ static int p1022_ds_probe(struct platform_device *pdev) } if (strcasecmp(sprop, "i2s-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_I2S; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; @@ -409,31 +410,38 @@ static int p1022_ds_probe(struct platform_device *pdev) } mdata->clk_frequency = be32_to_cpup(iprop); } else if (strcasecmp(sprop, "i2s-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_I2S; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "lj-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_LEFT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "lj-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_LEFT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "rj-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "rj-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "ac97-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_AC97; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "ac97-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_AC97; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else { -- cgit v1.2.3 From 0f813454b313d17992a2c8ec7483c733ce5107b3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 19 Mar 2012 09:12:53 +0100 Subject: ASoC: pxa-ssp: atomically set stream active masks commit 273b72c8ce6b28df6b49423d775c3e59072c73c5 upstream. PXA's SSP engine fails to take its current channel phase into account when enabling a stream while the engine is already running. This results in randomly swapped left/right channels on either the record or the playback side, depending on which one was enabled first. The following patch fixes this by factoring out the bit field modifications in question to a separate function that pauses the engine temporarily, modifies the bits and kicks it off again afterwards. Appearantly, a transition of SSCR0_SSE syncs both directions properly. The patch has been rolled out to quite a number of devices over the last weeks and seems to fix the issue reliably. Signed-off-by: Daniel Mack Reported-and-tested-by: Sven Neumann Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/pxa/pxa-ssp.c | 61 +++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 8ad93ee2e92b..b583e604a1ea 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -668,6 +668,38 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, return 0; } +static void pxa_ssp_set_running_bit(struct snd_pcm_substream *substream, + struct ssp_device *ssp, int value) +{ + uint32_t sscr0 = pxa_ssp_read_reg(ssp, SSCR0); + uint32_t sscr1 = pxa_ssp_read_reg(ssp, SSCR1); + uint32_t sspsp = pxa_ssp_read_reg(ssp, SSPSP); + uint32_t sssr = pxa_ssp_read_reg(ssp, SSSR); + + if (value && (sscr0 & SSCR0_SSE)) + pxa_ssp_write_reg(ssp, SSCR0, sscr0 & ~SSCR0_SSE); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (value) + sscr1 |= SSCR1_TSRE; + else + sscr1 &= ~SSCR1_TSRE; + } else { + if (value) + sscr1 |= SSCR1_RSRE; + else + sscr1 &= ~SSCR1_RSRE; + } + + pxa_ssp_write_reg(ssp, SSCR1, sscr1); + + if (value) { + pxa_ssp_write_reg(ssp, SSSR, sssr); + pxa_ssp_write_reg(ssp, SSPSP, sspsp); + pxa_ssp_write_reg(ssp, SSCR0, sscr0 | SSCR0_SSE); + } +} + static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { @@ -681,42 +713,21 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, pxa_ssp_enable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 1); val = pxa_ssp_read_reg(ssp, SSSR); pxa_ssp_write_reg(ssp, SSSR, val); break; case SNDRV_PCM_TRIGGER_START: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); - pxa_ssp_enable(ssp); + pxa_ssp_set_running_bit(substream, ssp, 1); break; case SNDRV_PCM_TRIGGER_STOP: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 0); break; case SNDRV_PCM_TRIGGER_SUSPEND: pxa_ssp_disable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 0); break; default: -- cgit v1.2.3 From bb9ed4f099c534078357b549b53749a55dfd1c97 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 14 Feb 2012 15:30:31 -0800 Subject: tcm_loop: Set residual field for SCSI commands commit 6cf3fa6918baab0c447f1206f1cef9166ad04864 upstream. If the target core signals an over- or under-run, tcm_loop should call scsi_set_resid() to tell the SCSI midlayer about the residual data length. The difference can be seen by doing something like strace -eioctl sg_raw -r 1024 /dev/sda 8 0 0 0 1 0 > /dev/null and looking at the "resid=" part of the SG_IO ioctl -- after this patch, the field is correctly reported as 512. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/loopback/tcm_loop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 81d5832fbbd5..5d1d4f207f52 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -866,6 +866,9 @@ static int tcm_loop_queue_data_in(struct se_cmd *se_cmd) sc->result = SAM_STAT_GOOD; set_host_byte(sc, DID_OK); + if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) || + (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)) + scsi_set_resid(sc, se_cmd->residual_count); sc->scsi_done(sc); return 0; } @@ -891,6 +894,9 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd) sc->result = se_cmd->scsi_status; set_host_byte(sc, DID_OK); + if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) || + (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)) + scsi_set_resid(sc, se_cmd->residual_count); sc->scsi_done(sc); return 0; } -- cgit v1.2.3 From 05ea4968dcc95650e2d1e1b67102018cdbd80e65 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 23 Feb 2012 17:28:43 -0800 Subject: iscsi-target: Fix iscsit_alloc_buffs() failure cases commit d335e6054db616bce3f040e659fa38440518ad1d upstream. Make iscsit_alloc_buffs() failure case for page_alloc_failed use correct __free_page() SGL pointer, and return -ENOMEM for iscsit_allocate_iovecs failure to push se_cmd->t_mem_sg release into iscsit_release_cmd() callback during iscsit_add_reject_from_cmd() connection reset. Also drop cmd->t_mem_sg = NULL assignment from page_alloc_failed failure case. Reported-by: Roland Dreier Cc: Andy Grover Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 03d35286365d..0842cc74a053 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -781,7 +781,7 @@ static int iscsit_alloc_buffs(struct iscsi_cmd *cmd) struct scatterlist *sgl; u32 length = cmd->se_cmd.data_length; int nents = DIV_ROUND_UP(length, PAGE_SIZE); - int i = 0, ret; + int i = 0, j = 0, ret; /* * If no SCSI payload is present, allocate the default iovecs used for * iSCSI PDU Header @@ -822,17 +822,15 @@ static int iscsit_alloc_buffs(struct iscsi_cmd *cmd) */ ret = iscsit_allocate_iovecs(cmd); if (ret < 0) - goto page_alloc_failed; + return -ENOMEM; return 0; page_alloc_failed: - while (i >= 0) { - __free_page(sg_page(&sgl[i])); - i--; - } - kfree(cmd->t_mem_sg); - cmd->t_mem_sg = NULL; + while (j < i) + __free_page(sg_page(&sgl[j++])); + + kfree(sgl); return -ENOMEM; } -- cgit v1.2.3 From abd8ea073d7438c42004aac75d4bbb46e7a8c054 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 26 Feb 2012 22:16:07 -0800 Subject: iscsi-target: Fix dynamic -> explict NodeACL pointer reference commit d06283341aee9e48eff1b068779d340785c635ce upstream. This patch fixes a free after use in lio_target_make_nodeacl() where iscsi_node_acl was referenced from the original se_nacl_new allocation, instead of from core_tpg_add_initiator_node_acl() in the case of dynamic -> explict NodeACL conversion. Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target_configfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index db327845e46b..83dcf4939fa4 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -816,9 +816,6 @@ static struct se_node_acl *lio_target_make_nodeacl( if (!se_nacl_new) return ERR_PTR(-ENOMEM); - acl = container_of(se_nacl_new, struct iscsi_node_acl, - se_node_acl); - cmdsn_depth = ISCSI_TPG_ATTRIB(tpg)->default_cmdsn_depth; /* * se_nacl_new may be released by core_tpg_add_initiator_node_acl() @@ -829,7 +826,8 @@ static struct se_node_acl *lio_target_make_nodeacl( if (IS_ERR(se_nacl)) return se_nacl; - stats_cg = &acl->se_node_acl.acl_fabric_stat_group; + acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); + stats_cg = &se_nacl->acl_fabric_stat_group; stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, GFP_KERNEL); -- cgit v1.2.3 From d8b8c61ff79f4edc8ef979a9fcb94b79beb77cdf Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 13 Mar 2012 17:43:02 +0200 Subject: ALSA: hda - fix printing of high HDMI sample rates commit 25dc16f69892182192b1234594fd3cf342ad4195 upstream. A previous commit af65cbf296 (ALSA: hdmi: fix printout of SAD sampling rates) fixed the sample rates shown in /proc/asound/cardX/eldY and kernel log to not be entirely wrong. However, a missing rate from the array added in the patch causes HDMI rates 88.2 kHz, 96 kHz, 176.4 kHz, and 192 kHz to be shown as 96 kHz, 176.4 kHz, 192 kHz, and 384 kHz, respectively. Fix the reporting by adding the ALSA rate 64 kHz into the conversion array between 48 kHz and 88.2 kHz. Signed-off-by: Anssi Hannula Cc: Pierre-Louis Bossart Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_eld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index c1da422e085a..b58b4b1687fa 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -385,8 +385,8 @@ error: static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) { static unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000, 384000 }; int i, j; -- cgit v1.2.3 From 3b6df5f6f4c6398dde02581ed559c5520674979f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Sun, 11 Mar 2012 15:08:46 +0100 Subject: usb gadget: fix a section mismatch when compiling g_ffs with CONFIG_USB_FUNCTIONFS_ETH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8d0698428822ce63f7269e7fe81fc4580807b9ac upstream. commit 28824b18ac4705e876a282a15ea0de8fc957551f: |Author: Michal Nazarewicz |Date: Wed May 5 12:53:13 2010 +0200 | | USB: gadget: __init and __exit tags removed | | __init, __initdata and __exit tags have have been removed from | various files to make it possible for gadgets that do not use | the __init/__exit tags to use those. obviously missed (at least) this case leading to a section mismatch in g_ffs.c when compiling with CONFIG_USB_FUNCTIONFS_ETH enabled. Signed-off-by: Lothar Waßmann Acked-by: Michal Nazarewicz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_subset.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index c1540648125a..21ab474aca07 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -74,7 +74,7 @@ static inline struct f_gether *func_to_geth(struct usb_function *f) /* interface descriptor: */ -static struct usb_interface_descriptor subset_data_intf __initdata = { +static struct usb_interface_descriptor subset_data_intf = { .bLength = sizeof subset_data_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -87,7 +87,7 @@ static struct usb_interface_descriptor subset_data_intf __initdata = { /* .iInterface = DYNAMIC */ }; -static struct usb_cdc_header_desc mdlm_header_desc __initdata = { +static struct usb_cdc_header_desc mdlm_header_desc = { .bLength = sizeof mdlm_header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, @@ -95,7 +95,7 @@ static struct usb_cdc_header_desc mdlm_header_desc __initdata = { .bcdCDC = cpu_to_le16(0x0110), }; -static struct usb_cdc_mdlm_desc mdlm_desc __initdata = { +static struct usb_cdc_mdlm_desc mdlm_desc = { .bLength = sizeof mdlm_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_MDLM_TYPE, @@ -111,7 +111,7 @@ static struct usb_cdc_mdlm_desc mdlm_desc __initdata = { * can't really use its struct. All we do here is say that we're using * the submode of "SAFE" which directly matches the CDC Subset. */ -static u8 mdlm_detail_desc[] __initdata = { +static u8 mdlm_detail_desc[] = { 6, USB_DT_CS_INTERFACE, USB_CDC_MDLM_DETAIL_TYPE, @@ -121,7 +121,7 @@ static u8 mdlm_detail_desc[] __initdata = { 0, /* network data capabilities ("raw" encapsulation) */ }; -static struct usb_cdc_ether_desc ether_desc __initdata = { +static struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, @@ -136,7 +136,7 @@ static struct usb_cdc_ether_desc ether_desc __initdata = { /* full speed support: */ -static struct usb_endpoint_descriptor fs_subset_in_desc __initdata = { +static struct usb_endpoint_descriptor fs_subset_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -144,7 +144,7 @@ static struct usb_endpoint_descriptor fs_subset_in_desc __initdata = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor fs_subset_out_desc __initdata = { +static struct usb_endpoint_descriptor fs_subset_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -152,7 +152,7 @@ static struct usb_endpoint_descriptor fs_subset_out_desc __initdata = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_descriptor_header *fs_eth_function[] __initdata = { +static struct usb_descriptor_header *fs_eth_function[] = { (struct usb_descriptor_header *) &subset_data_intf, (struct usb_descriptor_header *) &mdlm_header_desc, (struct usb_descriptor_header *) &mdlm_desc, @@ -165,7 +165,7 @@ static struct usb_descriptor_header *fs_eth_function[] __initdata = { /* high speed support: */ -static struct usb_endpoint_descriptor hs_subset_in_desc __initdata = { +static struct usb_endpoint_descriptor hs_subset_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -173,7 +173,7 @@ static struct usb_endpoint_descriptor hs_subset_in_desc __initdata = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = { +static struct usb_endpoint_descriptor hs_subset_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -181,7 +181,7 @@ static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_descriptor_header *hs_eth_function[] __initdata = { +static struct usb_descriptor_header *hs_eth_function[] = { (struct usb_descriptor_header *) &subset_data_intf, (struct usb_descriptor_header *) &mdlm_header_desc, (struct usb_descriptor_header *) &mdlm_desc, @@ -194,7 +194,7 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = { /* super speed support: */ -static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = { +static struct usb_endpoint_descriptor ss_subset_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -202,7 +202,7 @@ static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = { .wMaxPacketSize = cpu_to_le16(1024), }; -static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = { +static struct usb_endpoint_descriptor ss_subset_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -210,7 +210,7 @@ static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = { .wMaxPacketSize = cpu_to_le16(1024), }; -static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = { +static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = { .bLength = sizeof ss_subset_bulk_comp_desc, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, @@ -219,7 +219,7 @@ static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = { /* .bmAttributes = 0, */ }; -static struct usb_descriptor_header *ss_eth_function[] __initdata = { +static struct usb_descriptor_header *ss_eth_function[] = { (struct usb_descriptor_header *) &subset_data_intf, (struct usb_descriptor_header *) &mdlm_header_desc, (struct usb_descriptor_header *) &mdlm_desc, @@ -290,7 +290,7 @@ static void geth_disable(struct usb_function *f) /* serial function driver setup/binding */ -static int __init +static int geth_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; @@ -404,7 +404,7 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f) * Caller must have called @gether_setup(). Caller is also responsible * for calling @gether_cleanup() before module unload. */ -int __init geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) { struct f_gether *geth; int status; -- cgit v1.2.3 From ee7d30aab7663d796c13f3d7e8e80068f922a334 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 28 Jan 2012 19:57:46 +0000 Subject: udlfb: remove sysfs framebuffer device with USB .disconnect() commit ce880cb860f36694d2cdebfac9e6ae18176fe4c4 upstream. The USB graphics card driver delays the unregistering of the framebuffer device to a workqueue, which breaks the userspace visible remove uevent sequence. Recent userspace tools started to support USB graphics card hotplug out-of-the-box and rely on proper events sent by the kernel. The framebuffer device is a direct child of the USB interface which is removed immediately after the USB .disconnect() callback. But the fb device in /sys stays around until its final cleanup, at a time where all the parent devices have been removed already. To work around that, we remove the sysfs fb device directly in the USB .disconnect() callback and leave only the cleanup of the internal fb data to the delayed work. Before: add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/graphics/fb0 (graphics) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) remove /2-1.2:1.0/graphics/fb0 (graphics) After: add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/graphics/fb1 (graphics) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/graphics/fb1 (graphics) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) Tested-by: Bernie Thompson Acked-by: Bernie Thompson Signed-off-by: Kay Sievers Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbmem.c | 18 +++++++++++++++++- drivers/video/udlfb.c | 2 +- include/linux/fb.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ad936295d8f4..7a41220aebdd 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1651,6 +1651,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) if (ret) return -EINVAL; + unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); @@ -1658,7 +1659,6 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) registered_fb[i] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); - device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); @@ -1667,6 +1667,22 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) return 0; } +int unlink_framebuffer(struct fb_info *fb_info) +{ + int i; + + i = fb_info->node; + if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) + return -EINVAL; + + if (fb_info->dev) { + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); + fb_info->dev = NULL; + } + return 0; +} +EXPORT_SYMBOL(unlink_framebuffer); + void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) { diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 3473e75ce785..41746bbe5c0e 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -1739,7 +1739,7 @@ static void dlfb_usb_disconnect(struct usb_interface *interface) for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) device_remove_file(info->dev, &fb_device_attrs[i]); device_remove_bin_file(info->dev, &edid_attr); - + unlink_framebuffer(info); usb_set_intfdata(interface, NULL); /* if clients still have us open, will be freed on last close */ diff --git a/include/linux/fb.h b/include/linux/fb.h index 1d6836c498dd..73845ce3f44c 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -997,6 +997,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, /* drivers/video/fbmem.c */ extern int register_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info); +extern int unlink_framebuffer(struct fb_info *fb_info); extern void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary); extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); -- cgit v1.2.3 From 9a0aae0c2e37ed923640e8646a392814a76bed6a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 9 Mar 2012 23:45:38 -0800 Subject: tcm_fc: Fix fc_exch memory leak in ft_send_resp_status commit 031ed4d565b31880a4136bb7366bc89f5b1dba7d upstream. This patch fixes a bug in tcm_fc where fc_exch memory from fc_exch_mgr->ep_pool is currently being leaked by ft_send_resp_status() usage. Following current code in ft_queue_status() response path, using lport->tt.seq_send() needs to be followed by a lport->tt.exch_done() in order to release fc_exch memory back into libfc_em kmem_cache. ft_send_resp_status() code is currently used in pre submit se_cmd ft_send_work() error exceptions, TM request setup exceptions, and main TM response callback path in ft_queue_tm_resp(). This bugfix addresses the leak in these cases. Cc: Mark D Rustad Cc: Kiran Patil Cc: Robert Love Cc: Andy Grover Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/tcm_fc/tfc_cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 71fc9cea5dc9..754b669f796e 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -329,10 +329,12 @@ static void ft_send_resp_status(struct fc_lport *lport, fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); sp = fr_seq(fp); - if (sp) + if (sp) { lport->tt.seq_send(lport, sp, fp); - else + lport->tt.exch_done(sp); + } else { lport->tt.frame_send(lport, fp); + } } /* -- cgit v1.2.3 From aae19423e23df33f18e49f7558cb660aa485df90 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 19 Mar 2012 12:46:37 +1100 Subject: md/bitmap: ensure to load bitmap when creating via sysfs. commit 4474ca42e2577563a919fd3ed782e2ec55bf11a2 upstream. When commit 69e51b449d383e (md/bitmap: separate out loading a bitmap...) created bitmap_load, it missed calling it after bitmap_create when a bitmap is created through the sysfs interface. So if a bitmap is added this way, we don't allocate memory properly and can crash. This is suitable for any -stable release since 2.6.35. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/bitmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 6d03774b176e..2a8722b9f91b 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1904,6 +1904,8 @@ location_store(struct mddev *mddev, const char *buf, size_t len) if (mddev->pers) { mddev->pers->quiesce(mddev, 1); rv = bitmap_create(mddev); + if (!rv) + rv = bitmap_load(mddev); if (rv) { bitmap_destroy(mddev); mddev->bitmap_info.offset = 0; -- cgit v1.2.3 From 6bd620a44f7fdb2755101517e878c17b0b730332 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 19 Mar 2012 12:46:37 +1100 Subject: md: don't set md arrays to readonly on shutdown. commit c744a65c1e2d59acc54333ce80a5b0702a98010b upstream. It seems that with recent kernel, writeback can still be happening while shutdown is happening, and consequently data can be written after the md reboot notifier switches all arrays to read-only. This causes a BUG. So don't switch them to read-only - just mark them clean and set 'safemode' to '2' which mean that immediately after any write the array will be switch back to 'clean'. This could result in the shutdown happening when array is marked dirty, thus forcing a resync on reboot. However if you reboot without performing a "sync" first, you get to keep both halves. This is suitable for any stable kernel (though there might be some conflicts with obvious fixes in earlier kernels). Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index f47f1f8ac44b..65d552a514bb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8097,30 +8097,23 @@ static int md_notify_reboot(struct notifier_block *this, struct mddev *mddev; int need_delay = 0; - if ((code == SYS_DOWN) || (code == SYS_HALT) || (code == SYS_POWER_OFF)) { - - printk(KERN_INFO "md: stopping all md devices.\n"); - - for_each_mddev(mddev, tmp) { - if (mddev_trylock(mddev)) { - /* Force a switch to readonly even array - * appears to still be in use. Hence - * the '100'. - */ - md_set_readonly(mddev, 100); - mddev_unlock(mddev); - } - need_delay = 1; + for_each_mddev(mddev, tmp) { + if (mddev_trylock(mddev)) { + __md_stop_writes(mddev); + mddev->safemode = 2; + mddev_unlock(mddev); } - /* - * certain more exotic SCSI devices are known to be - * volatile wrt too early system reboots. While the - * right place to handle this issue is the given - * driver, we do want to have a safe RAID driver ... - */ - if (need_delay) - mdelay(1000*1); + need_delay = 1; } + /* + * certain more exotic SCSI devices are known to be + * volatile wrt too early system reboots. While the + * right place to handle this issue is the given + * driver, we do want to have a safe RAID driver ... + */ + if (need_delay) + mdelay(1000*1); + return NOTIFY_DONE; } -- cgit v1.2.3 From 0b5216e57f491984c6833eeb699cb1ba3895e305 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 19 Mar 2012 12:46:38 +1100 Subject: md/raid1,raid10: avoid deadlock during resync/recovery. commit d6b42dcb995e6acd7cc276774e751ffc9f0ef4bf upstream. If RAID1 or RAID10 is used under LVM or some other stacking block device, it is possible to enter a deadlock during resync or recovery. This can happen if the upper level block device creates two requests to the RAID1 or RAID10. The first request gets processed, blocks recovery and queue requests for underlying requests in current->bio_list. A resync request then starts which will wait for those requests and block new IO. But then the second request to the RAID1/10 will be attempted and it cannot progress until the resync request completes, which cannot progress until the underlying device requests complete, which are on a queue behind that second request. So allow that second request to proceed even though there is a resync request about to start. This is suitable for any -stable kernel. Reported-by: Ray Morris Tested-by: Ray Morris Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 17 +++++++++++++++-- drivers/md/raid10.c | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 7d9e071f2304..7af60ec98c60 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -731,9 +731,22 @@ static void wait_barrier(struct r1conf *conf) spin_lock_irq(&conf->resync_lock); if (conf->barrier) { conf->nr_waiting++; - wait_event_lock_irq(conf->wait_barrier, !conf->barrier, + /* Wait for the barrier to drop. + * However if there are already pending + * requests (preventing the barrier from + * rising completely), and the + * pre-process bio queue isn't empty, + * then don't wait, as we need to empty + * that queue to get the nr_pending + * count down. + */ + wait_event_lock_irq(conf->wait_barrier, + !conf->barrier || + (conf->nr_pending && + current->bio_list && + !bio_list_empty(current->bio_list)), conf->resync_lock, - ); + ); conf->nr_waiting--; } conf->nr_pending++; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 685ddf325ee4..b2194494f5f3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -790,9 +790,22 @@ static void wait_barrier(struct r10conf *conf) spin_lock_irq(&conf->resync_lock); if (conf->barrier) { conf->nr_waiting++; - wait_event_lock_irq(conf->wait_barrier, !conf->barrier, + /* Wait for the barrier to drop. + * However if there are already pending + * requests (preventing the barrier from + * rising completely), and the + * pre-process bio queue isn't empty, + * then don't wait, as we need to empty + * that queue to get the nr_pending + * count down. + */ + wait_event_lock_irq(conf->wait_barrier, + !conf->barrier || + (conf->nr_pending && + current->bio_list && + !bio_list_empty(current->bio_list)), conf->resync_lock, - ); + ); conf->nr_waiting--; } conf->nr_pending++; -- cgit v1.2.3 From b7715ffd670153926766a6b7419c306591f20676 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 19 Mar 2012 12:46:41 +1100 Subject: md: fix clearing of the 'changed' flags for the bad blocks list. commit d0962936bff659d20522555b517582a2715fd23f upstream. In super_1_sync (the first hunk) we need to clear 'changed' before checking read_seqretry(), otherwise we might race with other code adding a bad block and so won't retry later. In md_update_sb (the second hunk), in the case where there is no metadata (neither persistent nor external), we treat any bad blocks as an error. However we need to clear the 'changed' flag before calling md_ack_all_badblocks, else it won't do anything. This patch is suitable for -stable release 3.0 and later. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 65d552a514bb..6f37aa48c075 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1801,13 +1801,13 @@ retry: | BB_LEN(internal_bb)); *bbp++ = cpu_to_le64(store_bb); } + bb->changed = 0; if (read_seqretry(&bb->lock, seq)) goto retry; bb->sector = (rdev->sb_start + (int)le32_to_cpu(sb->bblog_offset)); bb->size = le16_to_cpu(sb->bblog_size); - bb->changed = 0; } } @@ -2362,6 +2362,7 @@ repeat: clear_bit(MD_CHANGE_PENDING, &mddev->flags); list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->badblocks.changed) { + rdev->badblocks.changed = 0; md_ack_all_badblocks(&rdev->badblocks); md_error(mddev, rdev); } -- cgit v1.2.3 From 89df7051aab3884a734fc1eb666322643519c9c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 14 Dec 2011 13:57:23 +0100 Subject: drm/i915: Only clear the GPU domains upon a successful finish commit c501ae7f332cdaf42e31af30b72b4b66cbbb1604 upstream. By clearing the GPU read domains before waiting upon the buffer, we run the risk of the wait being interrupted and the domains prematurely cleared. The next time we attempt to wait upon the buffer (after userspace handles the signal), we believe that the buffer is idle and so skip the wait. There are a number of bugs across all generations which show signs of an overly haste reuse of active buffers. Such as: https://bugs.freedesktop.org/show_bug.cgi?id=29046 https://bugs.freedesktop.org/show_bug.cgi?id=35863 https://bugs.freedesktop.org/show_bug.cgi?id=38952 https://bugs.freedesktop.org/show_bug.cgi?id=40282 https://bugs.freedesktop.org/show_bug.cgi?id=41098 https://bugs.freedesktop.org/show_bug.cgi?id=41102 https://bugs.freedesktop.org/show_bug.cgi?id=41284 https://bugs.freedesktop.org/show_bug.cgi?id=42141 A couple of those pre-date i915_gem_object_finish_gpu(), so may be unrelated (such as a wild write from a userspace command buffer), but this does look like a convincing cause for most of those bugs. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Reviewed-by: Eugeni Dodonov Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_gem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8359dc777041..3e7c4788585f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3084,10 +3084,13 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj) return ret; } + ret = i915_gem_object_wait_rendering(obj); + if (ret) + return ret; + /* Ensure that we invalidate the GPU's caches and TLBs. */ obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; - - return i915_gem_object_wait_rendering(obj); + return 0; } /** -- cgit v1.2.3 From c59359dcec7e50ad725069c93e574a1e4eb6de89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 14 Mar 2012 17:12:41 +0100 Subject: drm/radeon: Restrict offset for legacy hardware cursor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c4353016dac10133fa5d8535af83f0c4845a2915 upstream. The hardware only takes 27 bits for the offset, so larger offsets are truncated, and the hardware cursor shows random bits other than the intended ones. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=46796 Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cursor.c | 13 +++++++++++-- drivers/gpu/drm/radeon/radeon_object.c | 18 +++++++++++++++++- drivers/gpu/drm/radeon/radeon_object.h | 2 ++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index fde25c0d65a0..986d608002a3 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -151,7 +151,9 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, uint32_t height) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; struct drm_gem_object *obj; + struct radeon_bo *robj; uint64_t gpu_addr; int ret; @@ -173,7 +175,15 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, return -ENOENT; } - ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + robj = gem_to_radeon_bo(obj); + ret = radeon_bo_reserve(robj, false); + if (unlikely(ret != 0)) + goto fail; + /* Only 27 bit offset for legacy cursor */ + ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, + &gpu_addr); + radeon_bo_unreserve(robj); if (ret) goto fail; @@ -181,7 +191,6 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, radeon_crtc->cursor_height = height; radeon_lock_cursor(crtc, true); - /* XXX only 27 bit offset for legacy cursor */ radeon_set_cursor(crtc, obj, gpu_addr); radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 1c851521f458..f3ae60759c5f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -204,7 +204,8 @@ void radeon_bo_unref(struct radeon_bo **bo) *bo = NULL; } -int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) +int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, + u64 *gpu_addr) { int r, i; @@ -212,6 +213,7 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) bo->pin_count++; if (gpu_addr) *gpu_addr = radeon_bo_gpu_offset(bo); + WARN_ON_ONCE(max_offset != 0); return 0; } radeon_ttm_placement_from_domain(bo, domain); @@ -219,6 +221,15 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) /* force to pin into visible video ram */ bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; } + if (max_offset) { + u64 lpfn = max_offset >> PAGE_SHIFT; + + if (!bo->placement.lpfn) + bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT; + + if (lpfn < bo->placement.lpfn) + bo->placement.lpfn = lpfn; + } for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false); @@ -232,6 +243,11 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) return r; } +int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) +{ + return radeon_bo_pin_restricted(bo, domain, 0, gpu_addr); +} + int radeon_bo_unpin(struct radeon_bo *bo) { int r, i; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index b07f0f9b8627..fb3f433a7bb5 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -108,6 +108,8 @@ extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); extern void radeon_bo_unref(struct radeon_bo **bo); extern int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr); +extern int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, + u64 max_offset, u64 *gpu_addr); extern int radeon_bo_unpin(struct radeon_bo *bo); extern int radeon_bo_evict_vram(struct radeon_device *rdev); extern void radeon_bo_force_delete(struct radeon_device *rdev); -- cgit v1.2.3 From 16d4db3ec3dfdd10bbafef9a4f62fc9374592d2e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Mar 2012 12:22:09 -0400 Subject: drm/radeon/kms: fix analog load detection on DVI-I connectors commit e00e8b5e760cbbe9067daeae5454d67c44c8d035 upstream. We digital encoders have a detect function as well (for DP to VGA bridges), so we make sure we choose the analog one here. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=47007 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index e7cb3ab09243..f7d39ac1862a 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -946,6 +946,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) encoder = obj_to_encoder(obj); + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC || + encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) + continue; + encoder_funcs = encoder->helper_private; if (encoder_funcs->detect) { if (ret != connector_status_connected) { -- cgit v1.2.3 From dc64052e954f7b2658fc194108eaac53d0828190 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Mar 2012 12:22:10 -0400 Subject: drm/radeon/kms: add connector quirk for Fujitsu D3003-S2 board commit 4c1b2d2da3451f5c8dd59bd7e05bd9729d2aee05 upstream. vbios lists DVI-I port as VGA and DVI-D. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=47007 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_atombios.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 5082d17d14dc..8e1532f35ca3 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -442,6 +442,20 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, struct radeon_device *rdev = dev->dev_private; *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); } + + /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ + if ((dev->pdev->device == 0x9802) && + (dev->pdev->subsystem_vendor == 0x1734) && + (dev->pdev->subsystem_device == 0x11bd)) { + if (*connector_type == DRM_MODE_CONNECTOR_VGA) { + *connector_type = DRM_MODE_CONNECTOR_DVII; + *line_mux = 0x3103; + } else if (*connector_type == DRM_MODE_CONNECTOR_DVID) { + *connector_type = DRM_MODE_CONNECTOR_DVII; + } + } + + return true; } -- cgit v1.2.3 From 9a99a9592a98270e37b08574e2ed17b11ae741c3 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 13 Feb 2012 16:18:16 -0800 Subject: target: Don't set WBUS16 or SYNC bits in INQUIRY response commit effc6cc8828257c32c37635e737f14fd6e19ecd7 upstream. SPC-4 says about the WBUS16 and SYNC bits: The meanings of these fields are specific to SPI-5 (see 6.4.3). For SCSI transport protocols other than the SCSI Parallel Interface, these fields are reserved. We don't have a SPI fabric module, so we should never set these bits. (The comment was misleading, since it only mentioned Sync but the actual code set WBUS16 too). Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 8facd330cc3f..65ea65a18ea3 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -116,7 +116,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) goto out; } - buf[7] = 0x32; /* Sync=1 and CmdQue=1 */ + buf[7] = 0x2; /* CmdQue=1 */ /* * Do not include vendor, product, reversion info in INQUIRY -- cgit v1.2.3 From f18009c7acc4efa72c6bb36f8be1db8b08582dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Engel?= Date: Wed, 15 Feb 2012 16:51:32 -0500 Subject: target: fix use after free in target_report_luns commit 382436f8804fe1cb20b9a2a811a10eb2d8554721 upstream. Fix possible NULL pointer dereference in target_report_luns failure path. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 19f8aca08098..097178b83b3a 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -696,12 +696,12 @@ int target_report_luns(struct se_task *se_task) * See SPC3 r07, page 159. */ done: - transport_kunmap_data_sg(se_cmd); lun_count *= 8; buf[0] = ((lun_count >> 24) & 0xff); buf[1] = ((lun_count >> 16) & 0xff); buf[2] = ((lun_count >> 8) & 0xff); buf[3] = (lun_count & 0xff); + transport_kunmap_data_sg(se_cmd); se_task->task_scsi_status = GOOD; transport_complete_task(se_task, 1); -- cgit v1.2.3 From b794073eb1f5574b35c5de89ce81f108742a9879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Engel?= Date: Wed, 15 Feb 2012 16:52:11 -0500 Subject: target: prevent NULL pointer dereference in target_report_luns commit 47f1b8803e1e358ebbf4f82bfdb98971c912a2c3 upstream. transport_kmap_data_sg can return NULL. I never saw this trigger, but returning -ENOMEM seems better than a crash. Also removes a pointless case while at it. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 097178b83b3a..f8773aec5965 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -658,7 +658,9 @@ int target_report_luns(struct se_task *se_task) unsigned char *buf; u32 cdb_offset = 0, lun_count = 0, offset = 8, i; - buf = (unsigned char *) transport_kmap_data_sg(se_cmd); + buf = transport_kmap_data_sg(se_cmd); + if (!buf) + return -ENOMEM; /* * If no struct se_session pointer is present, this struct se_cmd is -- cgit v1.2.3 From fbd49ca445e92374ddb1d43ab43d527c489905a1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 23 Feb 2012 17:22:12 -0800 Subject: target: Fix 16-bit target ports for SET TARGET PORT GROUPS emulation commit 33395fb8a13731c7ef7b175dbf5a4d8a6738fe6c upstream. The old code did (MSB << 8) & 0xff, which always evaluates to 0. Just use get_unaligned_be16() so we don't have to worry about whether our open-coded version is correct or not. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_alua.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 1d24512f1731..5b0574484f55 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -268,8 +269,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) * changed. */ if (primary) { - tg_pt_id = ((ptr[2] << 8) & 0xff); - tg_pt_id |= (ptr[3] & 0xff); + tg_pt_id = get_unaligned_be16(ptr + 2); /* * Locate the matching target port group ID from * the global tg_pt_gp list @@ -313,8 +313,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) * the Target Port in question for the the incoming * SET_TARGET_PORT_GROUPS op. */ - rtpi = ((ptr[2] << 8) & 0xff); - rtpi |= (ptr[3] & 0xff); + rtpi = get_unaligned_be16(ptr + 2); /* * Locate the matching relative target port identifer * for the struct se_device storage object. -- cgit v1.2.3 From ef5cf6b5cfaac10c6ad1cb6547c977efcddce7db Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Wed, 30 Nov 2011 18:32:37 +0800 Subject: Bluetooth: Add AR30XX device ID on Asus laptops commit 6b6ba88b5bb8779156b21bb957520a448c3642e2 upstream. The ID is found on Asus K54HR and K53U. Blacklist the AR3011-based device ID [0489:e03d] and add to ath3k.c for firmware loading. Below is the output of usb-devices script: Before the fiwmware loading: T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e03d Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb After the fiwmware loading: T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3005 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Keng-Yu Lin Signed-off-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/ath3k.c | 1 + drivers/bluetooth/btusb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 106beb194f3c..db811d2936d3 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -64,6 +64,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x13d3, 0x3304) }, { USB_DEVICE(0x0930, 0x0215) }, + { USB_DEVICE(0x0489, 0xE03D) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index eabc437ce500..11a925c9ed1d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -119,6 +119,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, -- cgit v1.2.3 From c2040a53ad769fd0f12678feaf73ffa1d4ff124d Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Thu, 2 Feb 2012 10:31:26 +0100 Subject: HID: add extra hotkeys in Asus AIO keyboards commit 3596bb929f2abd3433c2eaa5755fad48ac207af1 upstream. The Asus All-In-One PC has a wireless keyboard with wifi toggle, brightness up, brightness down and display off hotkeys. This patch adds suppoort for these hotkeys. Signed-off-by: Keng-Yu Lin Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-chicony.c | 5 +++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + 3 files changed, 7 insertions(+) diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index 8965ad93d510..4162505793c5 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -45,6 +45,10 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, case 0xff09: ch_map_key_clear(BTN_9); break; case 0xff0a: ch_map_key_clear(BTN_A); break; case 0xff0b: ch_map_key_clear(BTN_B); break; + case 0x00f1: ch_map_key_clear(KEY_WLAN); break; + case 0x00f2: ch_map_key_clear(KEY_BRIGHTNESSDOWN); break; + case 0x00f3: ch_map_key_clear(KEY_BRIGHTNESSUP); break; + case 0x00f4: ch_map_key_clear(KEY_DISPLAY_OFF); break; default: return 0; } @@ -53,6 +57,7 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, static const struct hid_device_id ch_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { } }; MODULE_DEVICE_TABLE(hid, ch_devices); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bb656d824b9e..c27b4024725a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1394,6 +1394,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3c3daecd5d0e..fba3fc43afd6 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -192,6 +192,7 @@ #define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 +#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 #define USB_VENDOR_ID_CHUNGHWAT 0x2247 #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 -- cgit v1.2.3 From 5cd9c9621c2c3cf16bf0a308bd87e7d7aeb78160 Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Mon, 30 Jan 2012 14:25:45 +0800 Subject: HID: add more hotkeys in Asus AIO keyboards commit 6c30d5a53229aad22bb675e0bd6eb518ecaa4316 upstream. Add support for the camera key. The hotkey for Asus S.H.E(Super Hybrid Engine) mode is mapped to KEY_KEY_PROG1 just for notifying the userspace. Signed-off-by: Keng-Yu Lin Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-chicony.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index 4162505793c5..b99af346fdff 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -49,6 +49,8 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, case 0x00f2: ch_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x00f3: ch_map_key_clear(KEY_BRIGHTNESSUP); break; case 0x00f4: ch_map_key_clear(KEY_DISPLAY_OFF); break; + case 0x00f7: ch_map_key_clear(KEY_CAMERA); break; + case 0x00f8: ch_map_key_clear(KEY_PROG1); break; default: return 0; } -- cgit v1.2.3 From ae72c6c317b0c2fd455c131b45e290b9acf6b354 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 19 Jan 2012 19:09:56 +0300 Subject: pata_legacy: correctly mask recovery field for HT6560B commit 9716387311c790de381214c03e7f1b72b91a8189 upstream. According to the HT6560H datasheet, the recovery timing field is 4-bit wide, with a value of 0 meaning 16 cycles. Correct obvious thinko in the recovery field mask. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/pata_legacy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 35aca7d1a3eb..4fe9d2138d48 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -401,8 +401,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); active = clamp_val(t.active, 2, 15); - recover = clamp_val(t.recover, 2, 16); - recover &= 0x15; + recover = clamp_val(t.recover, 2, 16) & 0x0F; inb(0x3E6); inb(0x3E6); -- cgit v1.2.3 From 74b7bd47282eb4729509c1adad27e05cb77a3837 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 12 Mar 2012 21:45:47 +0100 Subject: firewire: ohci: fix too-early completion of IR multichannel buffers commit 0c0efbacab8d70700d13301e0ae7975783c0cb0a upstream. handle_ir_buffer_fill() assumed that a completed descriptor would be indicated by a non-zero transfer_status (as in most other descriptors). However, this field is written by the controller as soon as (the end of) the first packet has been written into the buffer. As a consequence, if we happen to run into such a descriptor when the interrupt handler is executed after such a packet has completed, the descriptor would be taken out of the list of active descriptors as soon as the buffer had been partially filled, so the event for the buffer being completely filled would never be sent. To fix this, handle descriptors only when they have been completely filled, i.e., when res_count == 0. (This also matches the condition that is reported by the controller with an interrupt.) Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/ohci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 7f5f0da726da..0a0225a34b76 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2748,7 +2748,7 @@ static int handle_ir_buffer_fill(struct context *context, container_of(context, struct iso_context, context); u32 buffer_dma; - if (!last->transfer_status) + if (last->res_count != 0) /* Descriptor(s) not done yet, stop iteration */ return 0; @@ -2762,8 +2762,7 @@ static int handle_ir_buffer_fill(struct context *context, if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) ctx->base.callback.mc(&ctx->base, le32_to_cpu(last->data_address) + - le16_to_cpu(last->req_count) - - le16_to_cpu(last->res_count), + le16_to_cpu(last->req_count), ctx->base.callback_data); return 1; -- cgit v1.2.3 From 90509a557798a023b3f5c46bebae62aa00e5da2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= Date: Thu, 12 Jan 2012 16:43:03 +0100 Subject: KVM: x86: extend "struct x86_emulate_ops" with "get_cpuid" commit bdb42f5afebe208eae90406959383856ae2caf2b upstream. In order to be able to proceed checks on CPU-specific properties within the emulator, function "get_cpuid" is introduced. With "get_cpuid" it is possible to virtually call the guests "cpuid"-opcode without changing the VM's context. [mtosatti: cleanup/beautify code] Signed-off-by: Stephan Baerwolf Signed-off-by: Marcelo Tosatti Signed-off-by: Stefan Bader Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/kvm_emulate.h | 3 +++ arch/x86/kvm/x86.c | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index a026507893e9..a440a7f3648c 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -189,6 +189,9 @@ struct x86_emulate_ops { int (*intercept)(struct x86_emulate_ctxt *ctxt, struct x86_instruction_info *info, enum x86_intercept_stage stage); + + bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt, + u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); }; typedef u32 __attribute__((vector_size(16))) sse128_t; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4c938da2ba00..e04cae195e10 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4655,6 +4655,28 @@ static int emulator_intercept(struct x86_emulate_ctxt *ctxt, return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage); } +static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, + u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) +{ + struct kvm_cpuid_entry2 *cpuid = NULL; + + if (eax && ecx) + cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt), + *eax, *ecx); + + if (cpuid) { + *eax = cpuid->eax; + *ecx = cpuid->ecx; + if (ebx) + *ebx = cpuid->ebx; + if (edx) + *edx = cpuid->edx; + return true; + } + + return false; +} + static struct x86_emulate_ops emulate_ops = { .read_std = kvm_read_guest_virt_system, .write_std = kvm_write_guest_virt_system, @@ -4685,6 +4707,7 @@ static struct x86_emulate_ops emulate_ops = { .get_fpu = emulator_get_fpu, .put_fpu = emulator_put_fpu, .intercept = emulator_intercept, + .get_cpuid = emulator_get_cpuid, }; static void cache_all_regs(struct kvm_vcpu *vcpu) -- cgit v1.2.3 From c401f604a75970a1e5c2718232b3c4c2060a3ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= Date: Thu, 12 Jan 2012 16:43:04 +0100 Subject: KVM: x86: fix missing checks in syscall emulation commit c2226fc9e87ba3da060e47333657cd6616652b84 upstream. On hosts without this patch, 32bit guests will crash (and 64bit guests may behave in a wrong way) for example by simply executing following nasm-demo-application: [bits 32] global _start SECTION .text _start: syscall (I tested it with winxp and linux - both always crashed) Disassembly of section .text: 00000000 <_start>: 0: 0f 05 syscall The reason seems a missing "invalid opcode"-trap (int6) for the syscall opcode "0f05", which is not available on Intel CPUs within non-longmodes, as also on some AMD CPUs within legacy-mode. (depending on CPU vendor, MSR_EFER and cpuid) Because previous mentioned OSs may not engage corresponding syscall target-registers (STAR, LSTAR, CSTAR), they remain NULL and (non trapping) syscalls are leading to multiple faults and finally crashs. Depending on the architecture (AMD or Intel) pretended by guests, various checks according to vendor's documentation are implemented to overcome the current issue and behave like the CPUs physical counterparts. [mtosatti: cleanup/beautify code] Signed-off-by: Stephan Baerwolf Signed-off-by: Marcelo Tosatti Signed-off-by: Stefan Bader Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/kvm_emulate.h | 13 ++++++++++ arch/x86/kvm/emulate.c | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index a440a7f3648c..70ea6fd69c1b 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -300,6 +300,19 @@ struct x86_emulate_ctxt { #define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \ X86EMUL_MODE_PROT64) +/* CPUID vendors */ +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541 +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163 +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65 + +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41 +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574 +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273 + +#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547 +#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e +#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69 + enum x86_intercept_stage { X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */ X86_ICPT_PRE_EXCEPT, diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index f1e3be18a08f..f5302da9af21 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1877,6 +1877,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, ss->p = 1; } +static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) +{ + struct x86_emulate_ops *ops = ctxt->ops; + u32 eax, ebx, ecx, edx; + + /* + * syscall should always be enabled in longmode - so only become + * vendor specific (cpuid) if other modes are active... + */ + if (ctxt->mode == X86EMUL_MODE_PROT64) + return true; + + eax = 0x00000000; + ecx = 0x00000000; + if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) { + /* + * Intel ("GenuineIntel") + * remark: Intel CPUs only support "syscall" in 64bit + * longmode. Also an 64bit guest with a + * 32bit compat-app running will #UD !! While this + * behaviour can be fixed (by emulating) into AMD + * response - CPUs of AMD can't behave like Intel. + */ + if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx && + ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx && + edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx) + return false; + + /* AMD ("AuthenticAMD") */ + if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx && + ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx && + edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx) + return true; + + /* AMD ("AMDisbetter!") */ + if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx && + ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx && + edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx) + return true; + } + + /* default: (not Intel, not AMD), apply Intel's stricter rules... */ + return false; +} + static int em_syscall(struct x86_emulate_ctxt *ctxt) { struct x86_emulate_ops *ops = ctxt->ops; @@ -1890,9 +1935,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) ctxt->mode == X86EMUL_MODE_VM86) return emulate_ud(ctxt); + if (!(em_syscall_is_enabled(ctxt))) + return emulate_ud(ctxt); + ops->get_msr(ctxt, MSR_EFER, &efer); setup_syscalls_segments(ctxt, &cs, &ss); + if (!(efer & EFER_SCE)) + return emulate_ud(ctxt); + ops->get_msr(ctxt, MSR_STAR, &msr_data); msr_data >>= 32; cs_sel = (u16)(msr_data & 0xfffc); -- cgit v1.2.3 From 7be1e5fdc0b3932ab0882820f69e27769bfd9d70 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 Mar 2012 19:56:44 -0500 Subject: NFS: Properly handle the case where the delegation is revoked commit a1d0b5eebc4fd6e0edb02688b35f17f67f42aea5 upstream. If we know that the delegation stateid is bad or revoked, we need to remove that delegation as soon as possible, and then mark all the stateids that relied on that delegation for recovery. We cannot use the delegation as part of the recovery process. Also note that NFSv4.1 uses a different error code (NFS4ERR_DELEG_REVOKED) to indicate that the delegation was revoked. Finally, ensure that setlk() and setattr() can both recover safely from a revoked delegation. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/delegation.c | 11 +++++++++++ fs/nfs/delegation.h | 1 + fs/nfs/nfs4_fs.h | 2 ++ fs/nfs/nfs4proc.c | 18 ++++++++++++++++-- fs/nfs/nfs4state.c | 29 +++++++++++++++++++++++++++-- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 7f2654069806..ac889af8ccf5 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -466,6 +466,17 @@ static void nfs_delegation_run_state_manager(struct nfs_client *clp) nfs4_schedule_state_manager(clp); } +void nfs_remove_bad_delegation(struct inode *inode) +{ + struct nfs_delegation *delegation; + + delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode)); + if (delegation) { + nfs_inode_find_state_and_recover(inode, &delegation->stateid); + nfs_free_delegation(delegation); + } +} + /** * nfs_expire_all_delegation_types * @clp: client to process diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index d9322e490c56..691a79609184 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -45,6 +45,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp); void nfs_handle_cb_pathdown(struct nfs_client *clp); int nfs_client_return_marked_delegations(struct nfs_client *clp); int nfs_delegations_present(struct nfs_client *clp); +void nfs_remove_bad_delegation(struct inode *inode); void nfs_delegation_mark_reclaim(struct nfs_client *clp); void nfs_delegation_reap_unclaimed(struct nfs_client *clp); diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 693ae22f8731..d6ba137f185b 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -324,6 +324,8 @@ extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_close_state(struct nfs4_state *, fmode_t); extern void nfs4_close_sync(struct nfs4_state *, fmode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); +extern void nfs_inode_find_state_and_recover(struct inode *inode, + const nfs4_stateid *stateid); extern void nfs4_schedule_lease_recovery(struct nfs_client *); extern void nfs4_schedule_state_manager(struct nfs_client *); extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e52703080c6d..a51e1ddb0a23 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -263,8 +263,11 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc switch(errorcode) { case 0: return 0; + case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_BAD_STATEID: + if (state != NULL) + nfs_remove_bad_delegation(state->inode); case -NFS4ERR_OPENMODE: if (state == NULL) break; @@ -1316,8 +1319,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state * The show must go on: exit, but mark the * stateid as needing recovery. */ + case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_BAD_STATEID: + nfs_inode_find_state_and_recover(state->inode, + stateid); nfs4_schedule_stateid_recovery(server, state); case -EKEYEXPIRED: /* @@ -1893,7 +1899,9 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = { + .state = state, + }; int err; do { err = nfs4_handle_exception(server, @@ -3707,8 +3715,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, if (task->tk_status >= 0) return 0; switch(task->tk_status) { + case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_BAD_STATEID: + if (state != NULL) + nfs_remove_bad_delegation(state->inode); case -NFS4ERR_OPENMODE: if (state == NULL) break; @@ -4526,7 +4537,9 @@ out: static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = { + .state = state, + }; int err; do { @@ -4619,6 +4632,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) * The show must go on: exit, but mark the * stateid as needing recovery. */ + case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_BAD_STATEID: case -NFS4ERR_OPENMODE: diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a58eed784aed..0596fd65b884 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1071,12 +1071,37 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4 { struct nfs_client *clp = server->nfs_client; - if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags)) - nfs_async_inode_return_delegation(state->inode, &state->stateid); nfs4_state_mark_reclaim_nograce(clp, state); nfs4_schedule_state_manager(clp); } +void nfs_inode_find_state_and_recover(struct inode *inode, + const nfs4_stateid *stateid) +{ + struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; + struct nfs_inode *nfsi = NFS_I(inode); + struct nfs_open_context *ctx; + struct nfs4_state *state; + bool found = false; + + spin_lock(&inode->i_lock); + list_for_each_entry(ctx, &nfsi->open_files, list) { + state = ctx->state; + if (state == NULL) + continue; + if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) + continue; + if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0) + continue; + nfs4_state_mark_reclaim_nograce(clp, state); + found = true; + } + spin_unlock(&inode->i_lock); + if (found) + nfs4_schedule_state_manager(clp); +} + + static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) { struct inode *inode = state->inode; -- cgit v1.2.3 From 12a2bb2225a1636d291af1714ac6da2b2947ced8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 7 Mar 2012 16:39:06 -0500 Subject: NFSv4: Return the delegation if the server returns NFS4ERR_OPENMODE commit 3114ea7a24d3264c090556a2444fc6d2c06176d4 upstream. If a setattr() fails because of an NFS4ERR_OPENMODE error, it is probably due to us holding a read delegation. Ensure that the recovery routines return that delegation in this case. Reported-by: Miklos Szeredi Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index d6ba137f185b..0983b2581ea3 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -191,6 +191,7 @@ struct nfs4_exception { long timeout; int retry; struct nfs4_state *state; + struct inode *inode; }; struct nfs4_state_recovery_ops { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a51e1ddb0a23..758e8096caa7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -257,18 +257,28 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc { struct nfs_client *clp = server->nfs_client; struct nfs4_state *state = exception->state; + struct inode *inode = exception->inode; int ret = errorcode; exception->retry = 0; switch(errorcode) { case 0: return 0; + case -NFS4ERR_OPENMODE: + if (nfs_have_delegation(inode, FMODE_READ)) { + nfs_inode_return_delegation(inode); + exception->retry = 1; + return 0; + } + if (state == NULL) + break; + nfs4_schedule_stateid_recovery(server, state); + goto wait_on_recovery; case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_BAD_STATEID: if (state != NULL) nfs_remove_bad_delegation(state->inode); - case -NFS4ERR_OPENMODE: if (state == NULL) break; nfs4_schedule_stateid_recovery(server, state); @@ -1901,6 +1911,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, struct nfs_server *server = NFS_SERVER(inode); struct nfs4_exception exception = { .state = state, + .inode = inode, }; int err; do { -- cgit v1.2.3 From cebef762efaa200ad00134a14c88374c6faaac6d Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 7 Mar 2012 04:50:25 +0000 Subject: xfs: fix inode lookup race commit f30d500f809eca67a21704347ab14bb35877b5ee upstream. When we get concurrent lookups of the same inode that is not in the per-AG inode cache, there is a race condition that triggers warnings in unlock_new_inode() indicating that we are initialising an inode that isn't in a the correct state for a new inode. When we do an inode lookup via a file handle or a bulkstat, we don't serialise lookups at a higher level through the dentry cache (i.e. pathless lookup), and so we can get concurrent lookups of the same inode. The race condition is between the insertion of the inode into the cache in the case of a cache miss and a concurrently lookup: Thread 1 Thread 2 xfs_iget() xfs_iget_cache_miss() xfs_iread() lock radix tree radix_tree_insert() rcu_read_lock radix_tree_lookup lock inode flags XFS_INEW not set igrab() unlock inode flags rcu_read_unlock use uninitialised inode ..... lock inode flags set XFS_INEW unlock inode flags unlock radix tree xfs_setup_inode() inode flags = I_NEW unlock_new_inode() WARNING as inode flags != I_NEW This can lead to inode corruption, inode list corruption, etc, and is generally a bad thing to occur. Fix this by setting XFS_INEW before inserting the inode into the radix tree. This will ensure any concurrent lookup will find the new inode with XFS_INEW set and that forces the lookup to wait until the XFS_INEW flag is removed before allowing the lookup to succeed. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_iget.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 0fa98b1c70ea..cfc4277ebda3 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -353,9 +353,20 @@ xfs_iget_cache_miss( BUG(); } - spin_lock(&pag->pag_ici_lock); + /* + * These values must be set before inserting the inode into the radix + * tree as the moment it is inserted a concurrent lookup (allowed by the + * RCU locking mechanism) can find it and that lookup must see that this + * is an inode currently under construction (i.e. that XFS_INEW is set). + * The ip->i_flags_lock that protects the XFS_INEW flag forms the + * memory barrier that ensures this detection works correctly at lookup + * time. + */ + ip->i_udquot = ip->i_gdquot = NULL; + xfs_iflags_set(ip, XFS_INEW); /* insert the new inode */ + spin_lock(&pag->pag_ici_lock); error = radix_tree_insert(&pag->pag_ici_root, agino, ip); if (unlikely(error)) { WARN_ON(error != -EEXIST); @@ -363,11 +374,6 @@ xfs_iget_cache_miss( error = EAGAIN; goto out_preload_end; } - - /* These values _must_ be set before releasing the radix tree lock! */ - ip->i_udquot = ip->i_gdquot = NULL; - xfs_iflags_set(ip, XFS_INEW); - spin_unlock(&pag->pag_ici_lock); radix_tree_preload_end(); -- cgit v1.2.3 From a3f7edf2fcb8e3e9c530c596a6c07479aeed418b Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 20 Mar 2012 12:55:09 +0300 Subject: CIFS: Respect negotiated MaxMpxCount commit 10b9b98e41ba248a899f6175ce96ee91431b6194 upstream. Some servers sets this value less than 50 that was hardcoded and we lost the connection if when we exceed this limit. Fix this by respecting this value - not sending more than the server allows. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsfs.c | 8 ++++---- fs/cifs/cifsglob.h | 10 +++------- fs/cifs/cifssmb.c | 9 +++++++-- fs/cifs/connect.c | 11 ++++------- fs/cifs/dir.c | 6 ++++-- fs/cifs/file.c | 4 ++-- fs/cifs/transport.c | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8f1fe324162b..b4c2c998acdd 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -76,7 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " unsigned int cifs_max_pending = CIFS_MAX_REQ; module_param(cifs_max_pending, int, 0444); MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " - "Default: 50 Range: 2 to 256"); + "Default: 32767 Range: 2 to 32767."); unsigned short echo_retries = 5; module_param(echo_retries, ushort, 0644); MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " @@ -1116,9 +1116,9 @@ init_cifs(void) if (cifs_max_pending < 2) { cifs_max_pending = 2; cFYI(1, "cifs_max_pending set to min of 2"); - } else if (cifs_max_pending > 256) { - cifs_max_pending = 256; - cFYI(1, "cifs_max_pending set to max of 256"); + } else if (cifs_max_pending > CIFS_MAX_REQ) { + cifs_max_pending = CIFS_MAX_REQ; + cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ); } rc = cifs_fscache_register(); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8238aa13e01c..c467ac89a821 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -55,14 +55,9 @@ /* * MAX_REQ is the maximum number of requests that WE will send - * on one socket concurrently. It also matches the most common - * value of max multiplex returned by servers. We may - * eventually want to use the negotiated value (in case - * future servers can handle more) when we are more confident that - * we will not have problems oveloading the socket with pending - * write data. + * on one socket concurrently. */ -#define CIFS_MAX_REQ 50 +#define CIFS_MAX_REQ 32767 #define RFC1001_NAME_LEN 15 #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1) @@ -263,6 +258,7 @@ struct TCP_Server_Info { bool session_estab; /* mark when very first sess is established */ u16 dialect; /* dialect index that server chose */ enum securityEnum secType; + bool oplocks:1; /* enable oplocks */ unsigned int maxReq; /* Clients should submit no more */ /* than maxReq distinct unanswered SMBs to the server when using */ /* multiplexed reads or writes */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6600aa2d2ef3..0e6adac01f11 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) goto neg_err_exit; } server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode); - server->maxReq = le16_to_cpu(rsp->MaxMpxCount); + server->maxReq = min_t(unsigned int, + le16_to_cpu(rsp->MaxMpxCount), + cifs_max_pending); + server->oplocks = server->maxReq > 1 ? enable_oplocks : false; server->maxBuf = le16_to_cpu(rsp->MaxBufSize); server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); /* even though we do not use raw we might as well set this @@ -564,7 +567,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ - server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), + cifs_max_pending); + server->oplocks = server->maxReq > 1 ? enable_oplocks : false; /* probably no need to store and check maxvcs */ server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 720edf52dbf8..a26b98f5e7ea 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -625,14 +625,10 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); wake_up_all(&server->response_q); - /* - * Check if we have blocked requests that need to free. Note that - * cifs_max_pending is normally 50, but can be set at module install - * time to as little as two. - */ + /* Check if we have blocked requests that need to free. */ spin_lock(&GlobalMid_Lock); - if (atomic_read(&server->inFlight) >= cifs_max_pending) - atomic_set(&server->inFlight, cifs_max_pending - 1); + if (atomic_read(&server->inFlight) >= server->maxReq) + atomic_set(&server->inFlight, server->maxReq - 1); /* * We do not want to set the max_pending too low or we could end up * with the counter going negative. @@ -1890,6 +1886,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->noautotune = volume_info->noautotune; tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; atomic_set(&tcp_ses->inFlight, 0); + tcp_ses->maxReq = 1; /* enough to send negotiate request */ init_waitqueue_head(&tcp_ses->response_q); init_waitqueue_head(&tcp_ses->request_q); INIT_LIST_HEAD(&tcp_ses->pending_mid_q); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index bf68b4fc9512..6937e7c19ee3 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, } tcon = tlink_tcon(tlink); - if (enable_oplocks) + if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; if (nd) @@ -492,7 +492,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, { int xid; int rc = 0; /* to get around spurious gcc warning, set to zero here */ - __u32 oplock = enable_oplocks ? REQ_OPLOCK : 0; + __u32 oplock; __u16 fileHandle = 0; bool posix_open = false; struct cifs_sb_info *cifs_sb; @@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } pTcon = tlink_tcon(tlink); + oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; + /* * Don't allow the separator character in a path component. * The VFS will not allow "/", but "\" is allowed by posix. diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5e64748a2917..4aa6080e95bc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -380,7 +380,7 @@ int cifs_open(struct inode *inode, struct file *file) cFYI(1, "inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags, full_path); - if (enable_oplocks) + if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; else oplock = 0; @@ -505,7 +505,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, pCifsFile->f_flags, full_path); - if (enable_oplocks) + if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; else oplock = 0; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0cc9584f5889..99a27cfa6cd2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -265,12 +265,12 @@ static int wait_for_free_request(struct TCP_Server_Info *server, spin_lock(&GlobalMid_Lock); while (1) { - if (atomic_read(&server->inFlight) >= cifs_max_pending) { + if (atomic_read(&server->inFlight) >= server->maxReq) { spin_unlock(&GlobalMid_Lock); cifs_num_waiters_inc(server); wait_event(server->request_q, atomic_read(&server->inFlight) - < cifs_max_pending); + < server->maxReq); cifs_num_waiters_dec(server); spin_lock(&GlobalMid_Lock); } else { -- cgit v1.2.3 From b38efc0924987777790559e4ec34cc693ce02c0b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 21 Mar 2012 06:30:40 -0400 Subject: cifs: fix issue mounting of DFS ROOT when redirecting from one domain controller to the next commit 1daaae8fa4afe3df78ca34e724ed7e8187e4eb32 upstream. This patch fixes an issue when cifs_mount receives a STATUS_BAD_NETWORK_NAME error during cifs_get_tcon but is able to continue after an DFS ROOT referral. In this case, the return code variable is not reset prior to trying to mount from the system referred to. Thus, is_path_accessible is not executed and the final DFS referral is not performed causing a mount error. Use case: In DNS, example.com resolves to the secondary AD server ad2.example.com Our primary domain controller is ad1.example.com and has a DFS redirection set up from \\ad1\share\Users to \\files\share\Users. Mounting \\example.com\share\Users fails. Regression introduced by commit 724d9f1. Reviewed-by: Pavel Shilovsky Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a26b98f5e7ea..9e0675a74cf2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3217,7 +3217,7 @@ cifs_ra_pages(struct cifs_sb_info *cifs_sb) int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) { - int rc = 0; + int rc; int xid; struct cifs_ses *pSesInfo; struct cifs_tcon *tcon; @@ -3244,6 +3244,7 @@ try_mount_again: FreeXid(xid); } #endif + rc = 0; tcon = NULL; pSesInfo = NULL; srvTcp = NULL; -- cgit v1.2.3 From 81555664cb1238f44c7363061d1a48f0761b2dd8 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Sat, 17 Mar 2012 09:46:55 +0300 Subject: CIFS: Fix a spurious error in cifs_push_posix_locks commit ce85852b90a214cf577fc1b4f49d99fd7e98784a upstream. Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Reported-by: Ben Hutchings Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/file.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 4aa6080e95bc..159fcc56dc2d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -960,9 +960,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) INIT_LIST_HEAD(&locks_to_send); /* - * Allocating count locks is enough because no locks can be added to - * the list while we are holding cinode->lock_mutex that protects - * locking operations of this inode. + * Allocating count locks is enough because no FL_POSIX locks can be + * added to the list while we are holding cinode->lock_mutex that + * protects locking operations of this inode. */ for (; i < count; i++) { lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); @@ -973,18 +973,20 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) list_add_tail(&lck->llist, &locks_to_send); } - i = 0; el = locks_to_send.next; lock_flocks(); cifs_for_each_lock(cfile->dentry->d_inode, before) { + flock = *before; + if ((flock->fl_flags & FL_POSIX) == 0) + continue; if (el == &locks_to_send) { - /* something is really wrong */ + /* + * The list ended. We don't have enough allocated + * structures - something is really wrong. + */ cERROR(1, "Can't push all brlocks!"); break; } - flock = *before; - if ((flock->fl_flags & FL_POSIX) == 0) - continue; length = 1 + flock->fl_end - flock->fl_start; if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) type = CIFS_RDLCK; @@ -996,7 +998,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) lck->length = length; lck->type = type; lck->offset = flock->fl_start; - i++; el = el->next; } unlock_flocks(); -- cgit v1.2.3 From ab053f76fec843ab4db48390319de701d654e9a1 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 30 Jan 2012 18:20:13 +0100 Subject: UBI: fix error handling in ubi_scan() commit a29852be492d61001d86c6ebf5fff9b93d7b4be9 upstream. Two bad things can happen in ubi_scan(): 1. If kmem_cache_create() fails we jump to out_si and call ubi_scan_destroy_si() which calls kmem_cache_destroy(). But si->scan_leb_slab is NULL. 2. If process_eb() fails we jump to out_vidh, call kmem_cache_destroy() and ubi_scan_destroy_si() which calls again kmem_cache_destroy(). Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/scan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 0cb17d936b5a..b99318ed51e6 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -1174,7 +1174,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); if (!ech) - goto out_slab; + goto out_si; vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vidh) @@ -1235,8 +1235,6 @@ out_vidh: ubi_free_vid_hdr(ubi, vidh); out_ech: kfree(ech); -out_slab: - kmem_cache_destroy(si->scan_leb_slab); out_si: ubi_scan_destroy_si(si); return ERR_PTR(err); @@ -1325,7 +1323,9 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) } } - kmem_cache_destroy(si->scan_leb_slab); + if (si->scan_leb_slab) + kmem_cache_destroy(si->scan_leb_slab); + kfree(si); } -- cgit v1.2.3 From 8617e195f2213c885c5aae3578c545a5ace9477b Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 7 Mar 2012 19:08:36 +0200 Subject: UBI: fix eraseblock picking criteria commit 7eb3aa65853e1b223bfc786b023b702018cb76c0 upstream. The 'find_wl_entry()' function expects the maximum difference as the second argument, not the maximum absolute value. So the "unknown" eraseblock picking was incorrect, as Shmulik Ladkani spotted. This patch fixes the issue. Reported-by: Shmulik Ladkani Signed-off-by: Artem Bityutskiy Reviewed-by: Shmulik Ladkani Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/wl.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 0696e36b0539..cf429716494a 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -389,7 +389,7 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max) */ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) { - int err, medium_ec; + int err; struct ubi_wl_entry *e, *first, *last; ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM || @@ -427,7 +427,7 @@ retry: * For unknown data we pick a physical eraseblock with medium * erase counter. But we by no means can pick a physical * eraseblock with erase counter greater or equivalent than the - * lowest erase counter plus %WL_FREE_MAX_DIFF. + * lowest erase counter plus %WL_FREE_MAX_DIFF/2. */ first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb); @@ -436,10 +436,8 @@ retry: if (last->ec - first->ec < WL_FREE_MAX_DIFF) e = rb_entry(ubi->free.rb_node, struct ubi_wl_entry, u.rb); - else { - medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2; - e = find_wl_entry(&ubi->free, medium_ec); - } + else + e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2); break; case UBI_SHORTTERM: /* -- cgit v1.2.3 From b8d535ac89519bda67bc3cab419a29953b1eb74e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 19 Mar 2012 13:39:35 -0400 Subject: SUNRPC: We must not use list_for_each_entry_safe() in rpc_wake_up() commit 540a0f7584169651f485e8ab67461fcb06934e38 upstream. The problem is that for the case of priority queues, we have to assume that __rpc_remove_wait_queue_priority will move new elements from the tk_wait.links lists into the queue->tasks[] list. We therefore cannot use list_for_each_entry_safe() on queue->tasks[], since that will skip these new tasks that __rpc_remove_wait_queue_priority is adding. Without this fix, rpc_wake_up and rpc_wake_up_status will both fail to wake up all functions on priority wait queues, which can result in some nasty hangs. Reported-by: Andy Adamson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/sched.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 00a1a2acd587..4e2b3b454aba 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -500,14 +500,18 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_next); */ void rpc_wake_up(struct rpc_wait_queue *queue) { - struct rpc_task *task, *next; struct list_head *head; spin_lock_bh(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { - list_for_each_entry_safe(task, next, head, u.tk_wait.list) + while (!list_empty(head)) { + struct rpc_task *task; + task = list_first_entry(head, + struct rpc_task, + u.tk_wait.list); rpc_wake_up_task_queue_locked(queue, task); + } if (head == &queue->tasks[0]) break; head--; @@ -525,13 +529,16 @@ EXPORT_SYMBOL_GPL(rpc_wake_up); */ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) { - struct rpc_task *task, *next; struct list_head *head; spin_lock_bh(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { - list_for_each_entry_safe(task, next, head, u.tk_wait.list) { + while (!list_empty(head)) { + struct rpc_task *task; + task = list_first_entry(head, + struct rpc_task, + u.tk_wait.list); task->tk_status = status; rpc_wake_up_task_queue_locked(queue, task); } -- cgit v1.2.3 From 0cc3dc325e20418548edc6571c80d4ae4bffb153 Mon Sep 17 00:00:00 2001 From: "tom.leiming@gmail.com" Date: Thu, 22 Mar 2012 03:22:18 +0000 Subject: usbnet: increase URB reference count before usb_unlink_urb commit 0956a8c20b23d429e79ff86d4325583fc06f9eb4 upstream. Commit 4231d47e6fe69f061f96c98c30eaf9fb4c14b96d(net/usbnet: avoid recursive locking in usbnet_stop()) fixes the recursive locking problem by releasing the skb queue lock, but it makes usb_unlink_urb racing with defer_bh, and the URB to being unlinked may be freed before or during calling usb_unlink_urb, so use-after-free problem may be triggerd inside usb_unlink_urb. The patch fixes the use-after-free problem by increasing URB reference count with skb queue lock held before calling usb_unlink_urb, so the URB won't be freed until return from usb_unlink_urb. Cc: Sebastian Andrzej Siewior Cc: Alan Stern Cc: Oliver Neukum Reported-by: Dave Jones Signed-off-by: Ming Lei Acked-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 81b96e303757..cf6a5154c72a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -589,6 +589,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) entry = (struct skb_data *) skb->cb; urb = entry->urb; + /* + * Get reference count of the URB to avoid it to be + * freed during usb_unlink_urb, which may trigger + * use-after-free problem inside usb_unlink_urb since + * usb_unlink_urb is always racing with .complete + * handler(include defer_bh). + */ + usb_get_urb(urb); spin_unlock_irqrestore(&q->lock, flags); // during some PM-driven resume scenarios, // these (async) unlinks complete immediately @@ -597,6 +605,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) netdev_dbg(dev->net, "unlink urb err, %d\n", retval); else count++; + usb_put_urb(urb); spin_lock_irqsave(&q->lock, flags); } spin_unlock_irqrestore (&q->lock, flags); -- cgit v1.2.3 From 4f68ac2aaf52ed31f7d97a6542571f0f7efd7d2e Mon Sep 17 00:00:00 2001 From: "tom.leiming@gmail.com" Date: Thu, 22 Mar 2012 03:22:38 +0000 Subject: usbnet: don't clear urb->dev in tx_complete commit 5d5440a835710d09f0ef18da5000541ec98b537a upstream. URB unlinking is always racing with its completion and tx_complete may be called before or during running usb_unlink_urb, so tx_complete must not clear urb->dev since it will be used in unlink path, otherwise invalid memory accesses or usb device leak may be caused inside usb_unlink_urb. Cc: Alan Stern Cc: Oliver Neukum Signed-off-by: Ming Lei Acked-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index cf6a5154c72a..750e33099cc1 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1037,7 +1037,6 @@ static void tx_complete (struct urb *urb) } usb_autopm_put_interface_async(dev->intf); - urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); } -- cgit v1.2.3 From eafb50b40d5fc72ad3e31ff07dab4f98dd76027e Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 18 Nov 2011 14:25:00 +0000 Subject: e1000e: Avoid wrong check on TX hang commit 09357b00255c233705b1cf6d76a8d147340545b8 upstream. Based on the original patch submitted my Michael Wang . Descriptors may not be write-back while checking TX hang with flag FLAG2_DMA_BURST on. So when we detect hang, we just flush the descriptor and detect again for once. -v2 change 1 to true and 0 to false and remove extra () CC: Michael Wang CC: Flavio Leitner Acked-by: Jesse Brandeburg Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/netdev.c | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 9fe18d1d53d8..f478a22ed577 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -309,6 +309,7 @@ struct e1000_adapter { u32 txd_cmd; bool detect_tx_hung; + bool tx_hang_recheck; u8 tx_timeout_factor; u32 tx_int_delay; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index a855db1ad249..4e933d1ab3f1 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1030,6 +1030,7 @@ static void e1000_print_hw_hang(struct work_struct *work) struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, print_hang_task); + struct net_device *netdev = adapter->netdev; struct e1000_ring *tx_ring = adapter->tx_ring; unsigned int i = tx_ring->next_to_clean; unsigned int eop = tx_ring->buffer_info[i].next_to_watch; @@ -1041,6 +1042,21 @@ static void e1000_print_hw_hang(struct work_struct *work) if (test_bit(__E1000_DOWN, &adapter->state)) return; + if (!adapter->tx_hang_recheck && + (adapter->flags2 & FLAG2_DMA_BURST)) { + /* May be block on write-back, flush and detect again + * flush pending descriptor writebacks to memory + */ + ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); + /* execute the writes immediately */ + e1e_flush(); + adapter->tx_hang_recheck = true; + return; + } + /* Real hang detected */ + adapter->tx_hang_recheck = false; + netif_stop_queue(netdev); + e1e_rphy(hw, PHY_STATUS, &phy_status); e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status); e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status); @@ -1154,10 +1170,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) if (tx_ring->buffer_info[i].time_stamp && time_after(jiffies, tx_ring->buffer_info[i].time_stamp + (adapter->tx_timeout_factor * HZ)) && - !(er32(STATUS) & E1000_STATUS_TXOFF)) { + !(er32(STATUS) & E1000_STATUS_TXOFF)) schedule_work(&adapter->print_hang_task); - netif_stop_queue(netdev); - } + else + adapter->tx_hang_recheck = false; } adapter->total_tx_bytes += total_tx_bytes; adapter->total_tx_packets += total_tx_packets; @@ -3782,6 +3798,7 @@ static int e1000_open(struct net_device *netdev) e1000_irq_enable(adapter); + adapter->tx_hang_recheck = false; netif_start_queue(netdev); adapter->idle_check = true; -- cgit v1.2.3 From c0bea34d0e5acbca09db615a3a9ea891c2ff0a4f Mon Sep 17 00:00:00 2001 From: Dmitry Adamushko Date: Thu, 22 Mar 2012 21:39:25 +0100 Subject: x86-32: Fix endless loop when processing signals for kernel tasks commit 29a2e2836ff9ea65a603c89df217f4198973a74f upstream. The problem occurs on !CONFIG_VM86 kernels [1] when a kernel-mode task returns from a system call with a pending signal. A real-life scenario is a child of 'khelper' returning from a failed kernel_execve() in ____call_usermodehelper() [ kernel/kmod.c ]. kernel_execve() fails due to a pending SIGKILL, which is the result of "kill -9 -1" (at least, busybox's init does it upon reboot). The loop is as follows: * syscall_exit_work: - work_pending: // start_of_the_loop - work_notify_sig: - do_notify_resume() - do_signal() - if (!user_mode(regs)) return; - resume_userspace // TIF_SIGPENDING is still set - work_pending // so we call work_pending => goto // start_of_the_loop More information can be found in another LKML thread: http://www.serverphorums.com/read.php?12,457826 [1] the problem was also seen on MIPS. Signed-off-by: Dmitry Adamushko Link: http://lkml.kernel.org/r/1332448765.2299.68.camel@dimm Cc: Oleg Nesterov Cc: Roland McGrath Cc: Andrew Morton Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/entry_32.S | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index f3f6f5344001..bcda8163bb00 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -99,12 +99,6 @@ #endif .endm -#ifdef CONFIG_VM86 -#define resume_userspace_sig check_userspace -#else -#define resume_userspace_sig resume_userspace -#endif - /* * User gs save/restore * @@ -328,10 +322,19 @@ ret_from_exception: preempt_stop(CLBR_ANY) ret_from_intr: GET_THREAD_INFO(%ebp) -check_userspace: +resume_userspace_sig: +#ifdef CONFIG_VM86 movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS movb PT_CS(%esp), %al andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax +#else + /* + * We can be coming here from a syscall done in the kernel space, + * e.g. a failed kernel_execve(). + */ + movl PT_CS(%esp), %eax + andl $SEGMENT_RPL_MASK, %eax +#endif cmpl $USER_RPL, %eax jb resume_kernel # not returning to v8086 or userspace -- cgit v1.2.3 From 4177c3642343a0a3ada8a8ee54628daa4b2d065d Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Fri, 23 Mar 2012 15:02:55 -0700 Subject: proc-ns: use d_set_d_op() API to set dentry ops in proc_ns_instantiate(). commit 1b26c9b334044cff6d1d2698f2be41bc7d9a0864 upstream. The namespace cleanup path leaks a dentry which holds a reference count on a network namespace. Keeping that network namespace from being freed when the last user goes away. Leaving things like vlan devices in the leaked network namespace. If you use ip netns add for much real work this problem becomes apparent pretty quickly. It light testing the problem hides because frequently you simply don't notice the leak. Use d_set_d_op() so that DCACHE_OP_* flags are set correctly. This issue exists back to 3.0. Acked-by: "Eric W. Biederman" Reported-by: Justin Pettit Signed-off-by: Pravin B Shelar Signed-off-by: Jesse Gross Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/namespaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index be177f702acb..d6c078ea1489 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -54,7 +54,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir, ei->ns_ops = ns_ops; ei->ns = ns; - dentry->d_op = &pid_dentry_operations; + d_set_d_op(dentry, &pid_dentry_operations); d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (pid_revalidate(dentry, NULL)) -- cgit v1.2.3 From ab153f21e011985dbe056f8780c31d823db8948e Mon Sep 17 00:00:00 2001 From: Steffen Persvold Date: Thu, 15 Mar 2012 15:20:29 +0100 Subject: iommu/amd: Fix section warning for prealloc_protection_domains commit cebd5fa4d3046d5b43ce1836a0120612822a7fb0 upstream. Fix the following section warning in drivers/iommu/amd_iommu.c : WARNING: vmlinux.o(.text+0x526e77): Section mismatch in reference from the function prealloc_protection_domains() to the function .init.text:alloc_passthrough_domain() The function prealloc_protection_domains() references the function __init alloc_passthrough_domain(). This is often because prealloc_protection_domains lacks a __init annotation or the annotation of alloc_passthrough_domain is wrong. Signed-off-by: Steffen Persvold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index e0b3e335fefc..966a6e7ee139 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2432,7 +2432,7 @@ static int amd_iommu_dma_supported(struct device *dev, u64 mask) * we don't need to preallocate the protection domains anymore. * For now we have to. */ -static void prealloc_protection_domains(void) +static void __init prealloc_protection_domains(void) { struct pci_dev *dev = NULL; struct dma_ops_domain *dma_dom; -- cgit v1.2.3 From eebfd5e734d12b915ebff75690e63e80678f3609 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 22 Mar 2012 14:42:22 -0700 Subject: sysctl: protect poll() in entries that may go away commit 4e474a00d7ff746ed177ddae14fa8b2d4bad7a00 upstream. Protect code accessing ctl_table by grabbing the header with grab_header() and after releasing with sysctl_head_finish(). This is needed if poll() is called in entries created by modules: currently only hostname and domainname support poll(), but this bug may be triggered when/if modules use it and if user called poll() in a file that doesn't support it. Dave Jones reported the following when using a syscall fuzzer while hibernating/resuming: RIP: 0010:[] [] proc_sys_poll+0x4e/0x90 RAX: 0000000000000145 RBX: ffff88020cab6940 RCX: 0000000000000000 RDX: ffffffff81233df0 RSI: 6b6b6b6b6b6b6b6b RDI: ffff88020cab6940 [ ... ] Code: 00 48 89 fb 48 89 f1 48 8b 40 30 4c 8b 60 e8 b8 45 01 00 00 49 83 7c 24 28 00 74 2e 49 8b 74 24 30 48 85 f6 74 24 48 85 c9 75 32 <8b> 16 b8 45 01 00 00 48 63 d2 49 39 d5 74 10 8b 06 48 98 48 89 If an entry goes away while we are polling() it, ctl_table may not exist anymore. Reported-by: Dave Jones Signed-off-by: Lucas De Marchi Cc: Al Viro Cc: Linus Torvalds Cc: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- fs/proc/proc_sysctl.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index a6b62173d4c3..53c3bcea56cf 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -188,20 +188,32 @@ static ssize_t proc_sys_write(struct file *filp, const char __user *buf, static int proc_sys_open(struct inode *inode, struct file *filp) { + struct ctl_table_header *head = grab_header(inode); struct ctl_table *table = PROC_I(inode)->sysctl_entry; + /* sysctl was unregistered */ + if (IS_ERR(head)) + return PTR_ERR(head); + if (table->poll) filp->private_data = proc_sys_poll_event(table->poll); + sysctl_head_finish(head); + return 0; } static unsigned int proc_sys_poll(struct file *filp, poll_table *wait) { struct inode *inode = filp->f_path.dentry->d_inode; + struct ctl_table_header *head = grab_header(inode); struct ctl_table *table = PROC_I(inode)->sysctl_entry; - unsigned long event = (unsigned long)filp->private_data; unsigned int ret = DEFAULT_POLLMASK; + unsigned long event; + + /* sysctl was unregistered */ + if (IS_ERR(head)) + return POLLERR | POLLHUP; if (!table->proc_handler) goto out; @@ -209,6 +221,7 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait) if (!table->poll) goto out; + event = (unsigned long)filp->private_data; poll_wait(filp, &table->poll->wait, wait); if (event != atomic_read(&table->poll->event)) { @@ -217,6 +230,8 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait) } out: + sysctl_head_finish(head); + return ret; } -- cgit v1.2.3 From e60a74019cd11c51dce802a60a5c604b4f7735a1 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 23 Mar 2012 10:02:17 +0100 Subject: hwmon: (fam15h_power) Correct sign extension of running_avg_capture commit fc0900cbda9243957d812cd6b4cc87965f9fe75f upstream. Wrong bit was used for sign extension which caused wrong end results. Thanks to Andre for spotting this bug. Reported-by: Andre Przywara Signed-off-by: Andreas Herrmann Acked-by: Guenter Roeck Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/fam15h_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 523f8fb9e7d9..930370de5201 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -60,7 +60,7 @@ static ssize_t show_power(struct device *dev, pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), REG_TDP_RUNNING_AVERAGE, &val); running_avg_capture = (val >> 4) & 0x3fffff; - running_avg_capture = sign_extend32(running_avg_capture, 22); + running_avg_capture = sign_extend32(running_avg_capture, 21); running_avg_range = val & 0xf; pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), -- cgit v1.2.3 From 13c7e19eac321c1a19ab723b17e215d8e61a6c13 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Tue, 14 Feb 2012 14:32:41 -0300 Subject: lgdt330x: fix signedness error in i2c_read_demod_bytes() commit 34817174fca0c5512c2d5b6ea0fc37a0337ce1d8 upstream. The error handling in lgdt3303_read_status() and lgdt330x_read_ucblocks() doesn't work, because i2c_read_demod_bytes() returns a u8 and (err < 0) is always false. err = i2c_read_demod_bytes(state, 0x58, buf, 1); if (err < 0) return err; Change the return type of i2c_read_demod_bytes() to int. Also change the return value on error to -EIO to make (err < 0) work. Signed-off-by: Xi Wang Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/frontends/lgdt330x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 43971e63baa7..aa63d687d276 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -104,8 +104,8 @@ static int i2c_write_demod_bytes (struct lgdt330x_state* state, * then reads the data returned for (len) bytes. */ -static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, - enum I2C_REG reg, u8* buf, int len) +static int i2c_read_demod_bytes(struct lgdt330x_state *state, + enum I2C_REG reg, u8 *buf, int len) { u8 wr [] = { reg }; struct i2c_msg msg [] = { @@ -118,6 +118,8 @@ static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) { printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret); + if (ret >= 0) + ret = -EIO; } else { ret = 0; } -- cgit v1.2.3 From 58f3dcce144cf88dedeb89250545ae242532b3c9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 7 Feb 2012 13:28:33 -0300 Subject: pvrusb2: fix 7MHz & 8MHz DVB-T tuner support for HVR1900 rev D1F5 commit 9ab2393fc3e460cd2040de1483918eb17abb822f upstream. The D1F5 revision of the WinTV HVR-1900 uses a tda18271c2 tuner instead of a tda18271c1 tuner as used in revision D1E9. To account for this, we must hardcode the frontend configuration to use the same IF frequency configuration for both revisions of the device. 6MHz DVB-T is unaffected by this issue, as the recommended IF Frequency configuration for 6MHz DVB-T is the same on both c1 and c2 revisions of the tda18271 tuner. Signed-off-by: Michael Krufky Cc: Mike Isely Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index c6da8f77e1a2..d8c898278e8c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -320,7 +320,17 @@ static struct tda829x_config tda829x_no_probe = { .probe_tuner = TDA829X_DONT_PROBE, }; +static struct tda18271_std_map hauppauge_tda18271_dvbt_std_map = { + .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, +}; + static struct tda18271_config hauppauge_tda18271_dvb_config = { + .std_map = &hauppauge_tda18271_dvbt_std_map, .gate = TDA18271_GATE_ANALOG, .output_opt = TDA18271_OUTPUT_LT_OFF, }; -- cgit v1.2.3 From 25c67995203d092a3ab6860ddb84050cab745efe Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 18 Mar 2012 14:35:57 -0300 Subject: mxl111sf: fix error on stream stop in mxl111sf_ep6_streaming_ctrl() commit 3be5bb71fbf18f83cb88b54a62a78e03e5a4f30a upstream. Remove unnecessary register access in mxl111sf_ep6_streaming_ctrl() This code breaks driver operation in kernel 3.3 and later, although it works properly in 3.2 Disable register access to 0x12 for now. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/dvb-usb/mxl111sf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index b5c98da5d9e2..bc6ea9fadb18 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -351,15 +351,13 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) adap_state->ep6_clockphase, 0, 0); mxl_fail(ret); +#if 0 } else { ret = mxl111sf_disable_656_port(state); mxl_fail(ret); +#endif } - mxl111sf_read_reg(state, 0x12, &tmp); - tmp &= ~0x04; - mxl111sf_write_reg(state, 0x12, tmp); - return ret; } -- cgit v1.2.3 From 49341010d998c15e7fa18b473ea7af6d7b9f3571 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Mar 2012 18:01:48 -0400 Subject: NFSv4: Rate limit the state manager warning messages commit 9a3ba432330e504ac61ff0043dbdaba7cea0e35a upstream. Prevent the state manager from filling up system logs when recovery fails on the server. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/callback_xdr.c | 4 +++- fs/nfs/nfs4proc.c | 2 +- fs/nfs/nfs4state.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 726e59a9e50f..168cb932db22 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include "nfs4_fs.h" @@ -167,7 +169,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound if (hdr->minorversion <= 1) { hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ } else { - printk(KERN_WARNING "%s: NFSv4 server callback with " + pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " "illegal minor version %u!\n", __func__, hdr->minorversion); return htonl(NFS4ERR_MINOR_VERS_MISMATCH); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 758e8096caa7..c9e2d9ee3242 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1838,7 +1838,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, * the user though... */ if (status == -NFS4ERR_BAD_SEQID) { - printk(KERN_WARNING "NFS: v4 server %s " + pr_warn_ratelimited("NFS: v4 server %s " " returned a bad sequence-id error!\n", NFS_SERVER(dir)->nfs_client->cl_hostname); exception.retry = 1; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0596fd65b884..66020acf2ecd 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -935,7 +935,7 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) case -NFS4ERR_BAD_SEQID: if (seqid->sequence->flags & NFS_SEQID_CONFIRMED) return; - printk(KERN_WARNING "NFS: v4 server returned a bad" + pr_warn_ratelimited("NFS: v4 server returned a bad" " sequence-id error on an" " unconfirmed sequence %p!\n", seqid->sequence); @@ -1764,7 +1764,7 @@ static void nfs4_state_manager(struct nfs_client *clp) } while (atomic_read(&clp->cl_count) > 1); return; out_error: - printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" + pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s" " with error %d\n", clp->cl_hostname, -status); nfs4_end_drain_session(clp); nfs4_clear_state_manager_bit(clp); -- cgit v1.2.3 From 4b952bf66061416f9da18ce8ff54d01808220480 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Fri, 17 Feb 2012 23:39:51 +0100 Subject: PM / Hibernate: Enable usermodehelpers in hibernate() error path commit 05b4877f6a4f1ba4952d1222213d262bf8c132b7 upstream. If create_basic_memory_bitmaps() fails, usermodehelpers are not re-enabled before returning. Fix this. And while at it, reword the goto labels so that they look more meaningful. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- kernel/power/hibernate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 624538a0e491..7c0d5786940b 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -648,7 +648,7 @@ int hibernate(void) /* Allocate memory management structures */ error = create_basic_memory_bitmaps(); if (error) - goto Exit; + goto Enable_umh; printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); @@ -656,7 +656,7 @@ int hibernate(void) error = prepare_processes(); if (error) - goto Finish; + goto Free_bitmaps; error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); if (error) @@ -689,8 +689,9 @@ int hibernate(void) Thaw: thaw_processes(); - Finish: + Free_bitmaps: free_basic_memory_bitmaps(); + Enable_umh: usermodehelper_enable(); Exit: pm_notifier_call_chain(PM_POST_HIBERNATION); -- cgit v1.2.3 From 146af184d533e62fc55ecd2cca925d3c072b5afc Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 20 Feb 2012 17:53:01 -0500 Subject: jbd2: clear BH_Delay & BH_Unwritten in journal_unmap_buffer commit 15291164b22a357cb211b618adfef4fa82fc0de3 upstream. journal_unmap_buffer()'s zap_buffer: code clears a lot of buffer head state ala discard_buffer(), but does not touch _Delay or _Unwritten as discard_buffer() does. This can be problematic in some areas of the ext4 code which assume that if they have found a buffer marked unwritten or delay, then it's a live one. Perhaps those spots should check whether it is mapped as well, but if jbd2 is going to tear down a buffer, let's really tear it down completely. Without this I get some fsx failures on sub-page-block filesystems up until v3.2, at which point 4e96b2dbbf1d7e81f22047a50f862555a6cb87cb and 189e868fa8fdca702eb9db9d8afc46b5cb9144c9 make the failures go away, because buried within that large change is some more flag clearing. I still think it's worth doing in jbd2, since ->invalidatepage leads here directly, and it's the right place to clear away these flags. Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index a0e41a4c080e..8267de588982 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1948,6 +1948,8 @@ zap_buffer_unlocked: clear_buffer_mapped(bh); clear_buffer_req(bh); clear_buffer_new(bh); + clear_buffer_delay(bh); + clear_buffer_unwritten(bh); bh->b_bdev = NULL; return may_free; } -- cgit v1.2.3 From 0b9af6daefb3de24ba6c32df234cca448ec76b18 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Mon, 20 Feb 2012 17:53:00 -0500 Subject: ext4: ignore EXT4_INODE_JOURNAL_DATA flag with delalloc commit 3d2b158262826e8b75bbbfb7b97010838dd92ac7 upstream. Ext4 does not support data journalling with delayed allocation enabled. We even do not allow to mount the file system with delayed allocation and data journalling enabled, however it can be set via FS_IOC_SETFLAGS so we can hit the inode with EXT4_INODE_JOURNAL_DATA set even on file system mounted with delayed allocation (default) and that's where problem arises. The easies way to reproduce this problem is with the following set of commands: mkfs.ext4 /dev/sdd mount /dev/sdd /mnt/test1 dd if=/dev/zero of=/mnt/test1/file bs=1M count=4 chattr +j /mnt/test1/file dd if=/dev/zero of=/mnt/test1/file bs=1M count=4 conv=notrunc chattr -j /mnt/test1/file Additionally it can be reproduced quite reliably with xfstests 272 and 269. In fact the above reproducer is a part of test 272. To fix this we should ignore the EXT4_INODE_JOURNAL_DATA inode flag if the file system is mounted with delayed allocation. This can be easily done by fixing ext4_should_*_data() functions do ignore data journal flag when delalloc is set (suggested by Ted). We also have to set the appropriate address space operations for the inode (again, ignoring data journal flag if delalloc enabled). Additionally this commit introduces ext4_inode_journal_mode() function because ext4_should_*_data() has already had a lot of common code and this change is putting it all into one function so it is easier to read. Successfully tested with xfstests in following configurations: delalloc + data=ordered delalloc + data=writeback data=journal nodelalloc + data=ordered nodelalloc + data=writeback nodelalloc + data=journal Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4_jbd2.h | 56 +++++++++++++++++++++++++++-------------------------- fs/ext4/inode.c | 36 ++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index 5802fa1dab18..95af6f878501 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h @@ -261,43 +261,45 @@ static inline void ext4_update_inode_fsync_trans(handle_t *handle, /* super.c */ int ext4_force_commit(struct super_block *sb); -static inline int ext4_should_journal_data(struct inode *inode) +/* + * Ext4 inode journal modes + */ +#define EXT4_INODE_JOURNAL_DATA_MODE 0x01 /* journal data mode */ +#define EXT4_INODE_ORDERED_DATA_MODE 0x02 /* ordered data mode */ +#define EXT4_INODE_WRITEBACK_DATA_MODE 0x04 /* writeback data mode */ + +static inline int ext4_inode_journal_mode(struct inode *inode) { if (EXT4_JOURNAL(inode) == NULL) - return 0; - if (!S_ISREG(inode->i_mode)) - return 1; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) - return 1; - if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA)) - return 1; - return 0; + return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ + /* We do not support data journalling with delayed allocation */ + if (!S_ISREG(inode->i_mode) || + test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) + return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ + if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) && + !test_opt(inode->i_sb, DELALLOC)) + return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) + return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) + return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ + else + BUG(); +} + +static inline int ext4_should_journal_data(struct inode *inode) +{ + return ext4_inode_journal_mode(inode) & EXT4_INODE_JOURNAL_DATA_MODE; } static inline int ext4_should_order_data(struct inode *inode) { - if (EXT4_JOURNAL(inode) == NULL) - return 0; - if (!S_ISREG(inode->i_mode)) - return 0; - if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA)) - return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) - return 1; - return 0; + return ext4_inode_journal_mode(inode) & EXT4_INODE_ORDERED_DATA_MODE; } static inline int ext4_should_writeback_data(struct inode *inode) { - if (EXT4_JOURNAL(inode) == NULL) - return 1; - if (!S_ISREG(inode->i_mode)) - return 0; - if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA)) - return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) - return 1; - return 0; + return ext4_inode_journal_mode(inode) & EXT4_INODE_WRITEBACK_DATA_MODE; } /* diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 92655fd89657..0b401f8c3281 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2480,13 +2480,14 @@ static int ext4_da_write_end(struct file *file, int write_mode = (int)(unsigned long)fsdata; if (write_mode == FALL_BACK_TO_NONDELALLOC) { - if (ext4_should_order_data(inode)) { + switch (ext4_inode_journal_mode(inode)) { + case EXT4_INODE_ORDERED_DATA_MODE: return ext4_ordered_write_end(file, mapping, pos, len, copied, page, fsdata); - } else if (ext4_should_writeback_data(inode)) { + case EXT4_INODE_WRITEBACK_DATA_MODE: return ext4_writeback_write_end(file, mapping, pos, len, copied, page, fsdata); - } else { + default: BUG(); } } @@ -3084,18 +3085,25 @@ static const struct address_space_operations ext4_da_aops = { void ext4_set_aops(struct inode *inode) { - if (ext4_should_order_data(inode) && - test_opt(inode->i_sb, DELALLOC)) - inode->i_mapping->a_ops = &ext4_da_aops; - else if (ext4_should_order_data(inode)) - inode->i_mapping->a_ops = &ext4_ordered_aops; - else if (ext4_should_writeback_data(inode) && - test_opt(inode->i_sb, DELALLOC)) - inode->i_mapping->a_ops = &ext4_da_aops; - else if (ext4_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext4_writeback_aops; - else + switch (ext4_inode_journal_mode(inode)) { + case EXT4_INODE_ORDERED_DATA_MODE: + if (test_opt(inode->i_sb, DELALLOC)) + inode->i_mapping->a_ops = &ext4_da_aops; + else + inode->i_mapping->a_ops = &ext4_ordered_aops; + break; + case EXT4_INODE_WRITEBACK_DATA_MODE: + if (test_opt(inode->i_sb, DELALLOC)) + inode->i_mapping->a_ops = &ext4_da_aops; + else + inode->i_mapping->a_ops = &ext4_writeback_aops; + break; + case EXT4_INODE_JOURNAL_DATA_MODE: inode->i_mapping->a_ops = &ext4_journalled_aops; + break; + default: + BUG(); + } } -- cgit v1.2.3 From 8608fb78b2cbf9eb8794e592bf43a8b1884c5a85 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Mon, 20 Feb 2012 17:59:24 -0500 Subject: ext4: fix race between unwritten extent conversion and truncate commit 266991b13890049ee1a6bb95b9817f06339ee3d7 upstream. The following comment in ext4_end_io_dio caught my attention: /* XXX: probably should move into the real I/O completion handler */ inode_dio_done(inode); The truncate code takes i_mutex, then calls inode_dio_wait. Because the ext4 code path above will end up dropping the mutex before it is reacquired by the worker thread that does the extent conversion, it seems to me that the truncate can happen out of order. Jan Kara mentioned that this might result in error messages in the system logs, but that should be the extent of the "damage." The fix is pretty straight-forward: don't call inode_dio_done until the extent conversion is complete. Reviewed-by: Jan Kara Signed-off-by: Jeff Moyer Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4.h | 1 + fs/ext4/inode.c | 10 +++++----- fs/ext4/page-io.c | 2 ++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 5b0e26a1272d..655d9425eba8 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -184,6 +184,7 @@ struct mpage_da_data { #define EXT4_IO_END_UNWRITTEN 0x0001 #define EXT4_IO_END_ERROR 0x0002 #define EXT4_IO_END_QUEUED 0x0004 +#define EXT4_IO_END_DIRECT 0x0008 struct ext4_io_page { struct page *p_page; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0b401f8c3281..3ce761373241 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2794,9 +2794,6 @@ out: /* queue the work to convert unwritten extents to written */ queue_work(wq, &io_end->work); - - /* XXX: probably should move into the real I/O completion handler */ - inode_dio_done(inode); } static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) @@ -2920,9 +2917,12 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, iocb->private = NULL; EXT4_I(inode)->cur_aio_dio = NULL; if (!is_sync_kiocb(iocb)) { - iocb->private = ext4_init_io_end(inode, GFP_NOFS); - if (!iocb->private) + ext4_io_end_t *io_end = + ext4_init_io_end(inode, GFP_NOFS); + if (!io_end) return -ENOMEM; + io_end->flag |= EXT4_IO_END_DIRECT; + iocb->private = io_end; /* * we save the io structure for current async * direct IO, so that later ext4_map_blocks() diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 7e106c810c62..924298a8a923 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -111,6 +111,8 @@ int ext4_end_io_nolock(ext4_io_end_t *io) if (io->iocb) aio_complete(io->iocb, io->result, 0); + if (io->flag & EXT4_IO_END_DIRECT) + inode_dio_done(inode); /* Wake up anyone waiting on unwritten extent conversion */ if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten)) wake_up_all(ext4_ioend_wq(io->inode)); -- cgit v1.2.3 From 3b9dbd4b410c4b2dc27c71fab78e4dff9b29e14c Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Mon, 5 Mar 2012 10:29:52 -0500 Subject: ext4: fix race between sync and completed io work commit 491caa43639abcffaa645fbab372a7ef4ce2975c upstream. The following command line will leave the aio-stress process unkillable on an ext4 file system (in my case, mounted on /mnt/test): aio-stress -t 20 -s 10 -O -S -o 2 -I 1000 /mnt/test/aiostress.3561.4 /mnt/test/aiostress.3561.4.20 /mnt/test/aiostress.3561.4.19 /mnt/test/aiostress.3561.4.18 /mnt/test/aiostress.3561.4.17 /mnt/test/aiostress.3561.4.16 /mnt/test/aiostress.3561.4.15 /mnt/test/aiostress.3561.4.14 /mnt/test/aiostress.3561.4.13 /mnt/test/aiostress.3561.4.12 /mnt/test/aiostress.3561.4.11 /mnt/test/aiostress.3561.4.10 /mnt/test/aiostress.3561.4.9 /mnt/test/aiostress.3561.4.8 /mnt/test/aiostress.3561.4.7 /mnt/test/aiostress.3561.4.6 /mnt/test/aiostress.3561.4.5 /mnt/test/aiostress.3561.4.4 /mnt/test/aiostress.3561.4.3 /mnt/test/aiostress.3561.4.2 This is using the aio-stress program from the xfstests test suite. That particular command line tells aio-stress to do random writes to 20 files from 20 threads (one thread per file). The files are NOT preallocated, so you will get writes to random offsets within the file, thus creating holes and extending i_size. It also opens the file with O_DIRECT and O_SYNC. On to the problem. When an I/O requires unwritten extent conversion, it is queued onto the completed_io_list for the ext4 inode. Two code paths will pull work items from this list. The first is the ext4_end_io_work routine, and the second is ext4_flush_completed_IO, which is called via the fsync path (and O_SYNC handling, as well). There are two issues I've found in these code paths. First, if the fsync path beats the work routine to a particular I/O, the work routine will free the io_end structure! It does not take into account the fact that the io_end may still be in use by the fsync path. I've fixed this issue by adding yet another IO_END flag, indicating that the io_end is being processed by the fsync path. The second problem is that the work routine will make an assignment to io->flag outside of the lock. I have witnessed this result in a hang at umount. Moving the flag setting inside the lock resolved that problem. The problem was introduced by commit b82e384c7b ("ext4: optimize locking for end_io extent conversion"), which first appeared in 3.2. As such, the fix should be backported to that release (probably along with the unwritten extent conversion race fix). Signed-off-by: Jeff Moyer Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4.h | 1 + fs/ext4/fsync.c | 2 ++ fs/ext4/page-io.c | 9 +++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 655d9425eba8..dbae4d98dab0 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -185,6 +185,7 @@ struct mpage_da_data { #define EXT4_IO_END_ERROR 0x0002 #define EXT4_IO_END_QUEUED 0x0004 #define EXT4_IO_END_DIRECT 0x0008 +#define EXT4_IO_END_IN_FSYNC 0x0010 struct ext4_io_page { struct page *p_page; diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 00a2cb753efd..bb6c7d811313 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -89,6 +89,7 @@ int ext4_flush_completed_IO(struct inode *inode) io = list_entry(ei->i_completed_io_list.next, ext4_io_end_t, list); list_del_init(&io->list); + io->flag |= EXT4_IO_END_IN_FSYNC; /* * Calling ext4_end_io_nolock() to convert completed * IO to written. @@ -108,6 +109,7 @@ int ext4_flush_completed_IO(struct inode *inode) if (ret < 0) ret2 = ret; spin_lock_irqsave(&ei->i_completed_io_lock, flags); + io->flag &= ~EXT4_IO_END_IN_FSYNC; } spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); return (ret2 < 0) ? ret2 : 0; diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 924298a8a923..24feb1ced3fd 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -130,12 +130,18 @@ static void ext4_end_io_work(struct work_struct *work) unsigned long flags; spin_lock_irqsave(&ei->i_completed_io_lock, flags); + if (io->flag & EXT4_IO_END_IN_FSYNC) + goto requeue; if (list_empty(&io->list)) { spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); goto free; } if (!mutex_trylock(&inode->i_mutex)) { + bool was_queued; +requeue: + was_queued = !!(io->flag & EXT4_IO_END_QUEUED); + io->flag |= EXT4_IO_END_QUEUED; spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); /* * Requeue the work instead of waiting so that the work @@ -148,9 +154,8 @@ static void ext4_end_io_work(struct work_struct *work) * yield the cpu if it sees an end_io request that has already * been requeued. */ - if (io->flag & EXT4_IO_END_QUEUED) + if (was_queued) yield(); - io->flag |= EXT4_IO_END_QUEUED; return; } list_del_init(&io->list); -- cgit v1.2.3 From ac35405d20c0bd438cea6e9dddd84335370c739e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 11 Mar 2012 23:30:16 -0400 Subject: ext4: check for zero length extent commit 31d4f3a2f3c73f279ff96a7135d7202ef6833f12 upstream. Explicitly test for an extent whose length is zero, and flag that as a corrupted extent. This avoids a kernel BUG_ON assertion failure. Tested: Without this patch, the file system image found in tests/f_ext_zero_len/image.gz in the latest e2fsprogs sources causes a kernel panic. With this patch, an ext4 file system error is noted instead, and the file system is marked as being corrupted. https://bugzilla.kernel.org/show_bug.cgi?id=42859 Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 607b1557d292..75070365f479 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -301,6 +301,8 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext) ext4_fsblk_t block = ext4_ext_pblock(ext); int len = ext4_ext_get_actual_len(ext); + if (len == 0) + return 0; return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len); } -- cgit v1.2.3 From d27e4c282e8445be329e4e3544ea5e9d4dfdc953 Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Mon, 26 Mar 2012 17:32:44 -0700 Subject: vfs: fix d_ancestor() case in d_materialize_unique commit b18dafc86bb879d2f38a1743985d7ceb283c2f4d upstream. In d_materialise_unique() there are 3 subcases to the 'aliased dentry' case; in two subcases the inode i_lock is properly released but this does not occur in the -ELOOP subcase. This seems to have been introduced by commit 1836750115f2 ("fix loop checks in d_materialise_unique()"). Signed-off-by: Michel Lespinasse [ Added a comment, and moved the unlock to where we generate the -ELOOP, which seems to be more natural. You probably can't actually trigger this without a buggy network file server - d_materialize_unique() is for finding aliases on non-local filesystems, and the d_ancestor() case is for a hardlinked directory loop. But we should be robust in the case of such buggy servers anyway. ] Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index f7908aef484a..eb723d317043 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2357,6 +2357,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) if (d_ancestor(alias, dentry)) { /* Check for loops */ actual = ERR_PTR(-ELOOP); + spin_unlock(&inode->i_lock); } else if (IS_ROOT(alias)) { /* Is this an anonymous mountpoint that we * could splice into our tree? */ @@ -2366,7 +2367,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) goto found; } else { /* Nope, but we must(!) avoid directory - * aliasing */ + * aliasing. This drops inode->i_lock */ actual = __d_unalias(inode, dentry, alias); } write_sequnlock(&rename_lock); -- cgit v1.2.3 From 83e41946441048f5d30f2022dda519b4b58c9ad8 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 14 Feb 2012 13:39:39 -0700 Subject: ARM: tegra: select required CPU and L2 errata options commit f35b431dde39fb40944d1024f08d88fbf04a3193 upstream. The ARM IP revisions in Tegra are: Tegra20: CPU r1p1, PL310 r2p0 Tegra30: CPU A01=r2p7/>=A02=r2p9, NEON r2p3-50, PL310 r3p1-50 Based on work by Olof Johansson, although the actual list of errata is somewhat different here, since I added a bunch more and removed one PL310 erratum that doesn't seem applicable. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-tegra/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 91aff7cb8284..dbc59fafd1be 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -13,6 +13,13 @@ config ARCH_TEGRA_2x_SOC select USB_ARCH_HAS_EHCI if USB_SUPPORT select USB_ULPI if USB_SUPPORT select USB_ULPI_VIEWPORT if USB_SUPPORT + select ARM_ERRATA_720789 + select ARM_ERRATA_742230 + select ARM_ERRATA_751472 + select ARM_ERRATA_754327 + select ARM_ERRATA_764369 + select PL310_ERRATA_727915 if CACHE_L2X0 + select PL310_ERRATA_769419 if CACHE_L2X0 help Support for NVIDIA Tegra AP20 and T20 processors, based on the ARM CortexA9MP CPU and the ARM PL310 L2 cache controller @@ -54,6 +61,11 @@ config MACH_SEABOARD config MACH_TEGRA_DT bool "Generic Tegra board (FDT support)" select USE_OF + select ARM_ERRATA_743622 + select ARM_ERRATA_751472 + select ARM_ERRATA_754322 + select ARM_ERRATA_764369 + select PL310_ERRATA_769419 if CACHE_L2X0 help Support for generic nVidia Tegra boards using Flattened Device Tree -- cgit v1.2.3 From 712f04ff3aea5f7cc284df68f93b1eacb5cb0fa2 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 20 Feb 2012 17:49:56 +0100 Subject: udf: Fix deadlock in udf_release_file() commit a0391a3ae91d301c0e59368531a4de5f0b122bcf upstream. udf_release_file() can be called from munmap() path with mmap_sem held. Thus we cannot take i_mutex there because that ranks above mmap_sem. Luckily, i_mutex is not needed in udf_release_file() anymore since protection by i_data_sem is enough to protect from races with write and truncate. Reported-by: Al Viro Reviewed-by: Namjae Jeon Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/file.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/udf/file.c b/fs/udf/file.c index dca0c3881e82..d567b8448dfc 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -201,12 +201,10 @@ out: static int udf_release_file(struct inode *inode, struct file *filp) { if (filp->f_mode & FMODE_WRITE) { - mutex_lock(&inode->i_mutex); down_write(&UDF_I(inode)->i_data_sem); udf_discard_prealloc(inode); udf_truncate_tail_extent(inode); up_write(&UDF_I(inode)->i_data_sem); - mutex_unlock(&inode->i_mutex); } return 0; } -- cgit v1.2.3 From c43d4b949b856e428d4c1f3c7d4533e40d3bbe67 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Fri, 25 Nov 2011 15:27:37 +0530 Subject: gpio/omap: fix _set_gpio_irqenable implementation commit 8276536cec38bc6bde30d0aa67716f22b9b9705a upstream. This function should be capable of both enabling and disabling interrupts based upon the *enable* parameter. Right now the function only enables the interrupt and *enable* is not used at all. So add the interrupt disable capability also using the parameter. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Acked-by: Felipe Balbi Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-omap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0b0562979171..a6c10e849e61 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -508,7 +508,10 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) { - _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + if (enable) + _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + else + _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); } /* -- cgit v1.2.3 From 9e4e8ae49a74dbbc69b4e923ecf387154e34da8a Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Sun, 11 Mar 2012 18:16:11 +0530 Subject: gpio/davinci: fix oops on unbanked gpio irq request commit ab2dde9924dd1ddb791fa8b14aa52e1df681e20c upstream. Unbanked GPIO irq setup code was overwriting chip_data leading to the following oops on request_irq() Unable to handle kernel paging request at virtual address febfffff pgd = c22dc000 [febfffff] *pgd=00000000 Internal error: Oops: 801 [#1] PREEMPT Modules linked in: mcu(+) edmak irqk cmemk CPU: 0 Not tainted (3.0.0-rc7+ #93) PC is at irq_gc_mask_set_bit+0x68/0x7c LR is at vprintk+0x22c/0x484 pc : [] lr : [] psr: 60000093 sp : c33e3ba0 ip : c33e3af0 fp : c33e3bc4 r10: c04555bc r9 : c33d4340 r8 : 60000013 r7 : 0000002d r6 : c04555bc r5 : fec67010 r4 : 00000000 r3 : c04734c8 r2 : fec00000 r1 : ffffffff r0 : 00000026 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005317f Table: 822dc000 DAC: 00000015 Process modprobe (pid: 526, stack limit = 0xc33e2270) Stack: (0xc33e3ba0 to 0xc33e4000) 3ba0: 00000000 c007d3d4 c33e3bcc c04555bc c04555bc c33d4340 c33e3bdc c33e3bc8 3bc0: c007f5f8 c0080bb4 00000000 c04555bc c33e3bf4 c33e3be0 c007f654 c007f5c0 3be0: 00000000 c04555bc c33e3c24 c33e3bf8 c007e6e8 c007f618 c01f2284 c0350af8 3c00: c0405214 bf016c98 00000001 00000000 c33dc008 0000002d c33e3c54 c33e3c28 3c20: c007e888 c007e408 00000001 c23ef880 c33dc000 00000000 c33dc080 c25caa00 3c40: c0487498 bf017078 c33e3c94 c33e3c58 bf016b44 c007e7d4 bf017078 c33dc008 3c60: c25caa08 c33dc008 c33e3c84 bf017484 c25caa00 c25caa00 c01f5f48 c25caa08 3c80: c0496d60 bf017484 c33e3ca4 c33e3c98 c022a698 bf01692c c33e3cd4 c33e3ca8 3ca0: c01f5d88 c022a688 00000000 bf017484 c25caa00 c25caa00 c01f5f48 c25caa08 3cc0: c0496d60 00000000 c33e3cec c33e3cd8 c01f5f8c c01f5d10 00000000 c33e3cf0 3ce0: c33e3d14 c33e3cf0 c01f5210 c01f5f58 c303cb48 c25ecf94 c25caa00 c25caa00 3d00: c25caa34 c33e3dd8 c33e3d34 c33e3d18 c01f6044 c01f51b8 c0496d3c c25caa00 3d20: c044e918 c33e3dd8 c33e3d44 c33e3d38 c01f4ff4 c01f5fcc c33e3d94 c33e3d48 3d40: c01f3d10 c01f4fd8 00000000 c044e918 00000000 00000000 c01f52c0 c034d570 3d60: c33e3d84 c33e3d70 c022bf84 c25caa00 00000000 c044e918 c33e3dd8 c25c2e00 3d80: c0496d60 bf01763c c33e3db4 c33e3d98 c022b1a0 c01f384c c25caa00 c33e3dd8 3da0: 00000000 c33e3dd8 c33e3dd4 c33e3db8 c022b27c c022b0e8 00000000 bf01763c 3dc0: c0451c80 c33e3dd8 c33e3e34 c33e3dd8 bf016f60 c022b210 5f75636d 746e6f63 3de0: 006c6f72 00000000 00000000 00000000 00000000 00000000 00000000 bf0174bc 3e00: 00000000 00989680 00000000 00000020 c0451c80 c0451c80 bf0174dc c01f5eb0 3e20: c33f0f00 bf0174dc c33e3e44 c33e3e38 c01f72f4 bf016e2c c33e3e74 c33e3e48 3e40: c01f5d88 c01f72e4 00000000 c0451c80 c0451cb4 bf0174dc c01f5eb0 c33f0f00 3e60: c0473100 00000000 c33e3e94 c33e3e78 c01f5f44 c01f5d10 00000000 c33e3e98 3e80: bf0174dc c01f5eb0 c33e3ebc c33e3e98 c01f5534 c01f5ec0 c303c038 c3061c30 3ea0: 00003cd8 00098258 bf0174dc c0462ac8 c33e3ecc c33e3ec0 c01f5bec c01f54dc 3ec0: c33e3efc c33e3ed0 c01f4d30 c01f5bdc bf0173a0 c33e2000 00003cd8 00098258 3ee0: bf0174dc c33e2000 c00301a4 bf019000 c33e3f1c c33e3f00 c01f6588 c01f4c8c 3f00: 00003cd8 00098258 00000000 c33e2000 c33e3f2c c33e3f20 c01f777c c01f6524 3f20: c33e3f3c c33e3f30 bf019014 c01f7740 c33e3f7c c33e3f40 c002f3ec bf019010 3f40: 00000000 00003cd8 00098258 bf017518 00000000 00003cd8 00098258 bf017518 3f60: 00000000 c00301a4 c33e2000 00000000 c33e3fa4 c33e3f80 c007b934 c002f3c4 3f80: c00b307c c00b2f48 00003cd8 00000000 00000003 00000080 00000000 c33e3fa8 3fa0: c0030020 c007b8b8 00003cd8 00000000 00098288 00003cd8 00098258 00098240 3fc0: 00003cd8 00000000 00000003 00000080 00098008 00098028 00098288 00000001 3fe0: be892998 be892988 00013d7c 40178740 60000010 00098288 09089041 00200845 Backtrace: [] (irq_gc_mask_set_bit+0x0/0x7c) from [] (irq_enable+0x48/0x58) r6:c33d4340 r5:c04555bc r4:c04555bc [] (irq_enable+0x0/0x58) from [] (irq_startup+0x4c/0x54) r5:c04555bc r4:00000000 [] (irq_startup+0x0/0x54) from [] (__setup_irq+0x2f0/0x3cc) r5:c04555bc r4:00000000 [] (__setup_irq+0x0/0x3cc) from [] (request_threaded_irq+0xc4/0x110) r8:0000002d r7:c33dc008 r6:00000000 r5:00000001 r4:bf016c98 [] (request_threaded_irq+0x0/0x110) from [] (mcu_spi_probe+0x228/0x37c [mcu]) [] (mcu_spi_probe+0x0/0x37c [mcu]) from [] (spi_drv_probe+0x20/0x24) [] (spi_drv_probe+0x0/0x24) from [] (driver_probe_device+0x88/0x1b0) [] (driver_probe_device+0x0/0x1b0) from [] (__device_attach+0x44/0x48) [] (__device_attach+0x0/0x48) from [] (bus_for_each_drv+0x68/0x94) r5:c33e3cf0 r4:00000000 [] (bus_for_each_drv+0x0/0x94) from [] (device_attach+0x88/0xa0) r7:c33e3dd8 r6:c25caa34 r5:c25caa00 r4:c25caa00 [] (device_attach+0x0/0xa0) from [] (bus_probe_device+0x2c/0x4c) r7:c33e3dd8 r6:c044e918 r5:c25caa00 r4:c0496d3c [] (bus_probe_device+0x0/0x4c) from [] (device_add+0x4d4/0x648) [] (device_add+0x0/0x648) from [] (spi_add_device+0xc8/0x128) [] (spi_add_device+0x0/0x128) from [] (spi_new_device+0x7c/0xb4) r7:c33e3dd8 r6:00000000 r5:c33e3dd8 r4:c25caa00 [] (spi_new_device+0x0/0xb4) from [] (mcu_probe+0x144/0x224 [mcu]) r7:c33e3dd8 r6:c0451c80 r5:bf01763c r4:00000000 [] (mcu_probe+0x0/0x224 [mcu]) from [] (platform_drv_probe+0x20/0x24) [] (platform_drv_probe+0x0/0x24) from [] (driver_probe_device+0x88/0x1b0) [] (driver_probe_device+0x0/0x1b0) from [] (__driver_attach+0x94/0x98) [] (__driver_attach+0x0/0x98) from [] (bus_for_each_dev+0x68/0x94) r7:c01f5eb0 r6:bf0174dc r5:c33e3e98 r4:00000000 [] (bus_for_each_dev+0x0/0x94) from [] (driver_attach+0x20/0x28) r7:c0462ac8 r6:bf0174dc r5:00098258 r4:00003cd8 [] (driver_attach+0x0/0x28) from [] (bus_add_driver+0xb4/0x258) [] (bus_add_driver+0x0/0x258) from [] (driver_register+0x74/0x158) [] (driver_register+0x0/0x158) from [] (platform_driver_register+0x4c/0x60) r7:c33e2000 r6:00000000 r5:00098258 r4:00003cd8 [] (platform_driver_register+0x0/0x60) from [] (mcu_init+0x14/0x20 [mcu]) [] (mcu_init+0x0/0x20 [mcu]) from [] (do_one_initcall+0x38/0x170) [] (do_one_initcall+0x0/0x170) from [] (sys_init_module+0x8c/0x1a4) [] (sys_init_module+0x0/0x1a4) from [] (ret_fast_syscall+0x0/0x2c) r7:00000080 r6:00000003 r5:00000000 r4:00003cd8 Code: e1844003 e585400c e596300c e5932064 (e7814002) Fix the issue. Reported-by: Jon Povey Signed-off-by: Sekhar Nori Signed-off-by: Grant Likely Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-davinci.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index df0d59570a84..a6777e5e0ced 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -313,10 +313,16 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) return -ENODEV; } -static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger) +static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); - u32 mask = (u32) irq_data_get_irq_handler_data(d); + struct davinci_gpio_controller *d; + struct davinci_gpio_regs __iomem *g; + struct davinci_soc_info *soc_info = &davinci_soc_info; + u32 mask; + + d = (struct davinci_gpio_controller *)data->handler_data; + g = (struct davinci_gpio_regs __iomem *)d->regs; + mask = __gpio_mask(data->irq - soc_info->gpio_irq); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; @@ -400,8 +406,7 @@ static int __init davinci_gpio_irq_setup(void) /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { irq_set_chip(irq, &gpio_irqchip_unbanked); - irq_set_handler_data(irq, (void *)__gpio_mask(gpio)); - irq_set_chip_data(irq, (__force void *)g); + irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } -- cgit v1.2.3 From 7c2d80c67d367b9a1131de67ddd8088df3541273 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Sun, 11 Mar 2012 18:16:12 +0530 Subject: gpio/davinci: fix enabling unbanked GPIO IRQs commit 81b279d80a63628e580c71a31d30a8c3b3047ad4 upstream. Unbanked GPIO IRQ handling code made a copy of just the irq_chip structure for GPIO IRQ lines which caused problems after the generic IRQ chip conversion because there was no valid irq_chip_type structure with the right "regs" populated. irq_gc_mask_set_bit() was therefore accessing random addresses. Fix it by making a copy of irq_chip_type structure instead. This will ensure sane register offsets. Reported-by: Jon Povey Tested-by: Jon Povey Signed-off-by: Sekhar Nori Signed-off-by: Grant Likely Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-davinci.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index a6777e5e0ced..3d000169285d 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -386,7 +386,7 @@ static int __init davinci_gpio_irq_setup(void) * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (soc_info->gpio_unbanked) { - static struct irq_chip gpio_irqchip_unbanked; + static struct irq_chip_type gpio_unbanked; /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; @@ -394,9 +394,10 @@ static int __init davinci_gpio_irq_setup(void) /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; - gpio_irqchip_unbanked = *irq_get_chip(irq); - gpio_irqchip_unbanked.name = "GPIO-AINTC"; - gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked; + gpio_unbanked = *container_of(irq_get_chip(irq), + struct irq_chip_type, chip); + gpio_unbanked.chip.name = "GPIO-AINTC"; + gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); @@ -405,7 +406,7 @@ static int __init davinci_gpio_irq_setup(void) /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, &gpio_irqchip_unbanked); + irq_set_chip(irq, &gpio_unbanked.chip); irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } -- cgit v1.2.3 From 16c69b101a905588160514815f6285be4547f998 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 28 Mar 2012 18:41:22 +0100 Subject: dm crypt: fix mempool deadlock commit aeb2deae2660a1773c83d3c6e9e6575daa3855d6 upstream. This patch fixes a possible deadlock in dm-crypt's mempool use. Currently, dm-crypt reserves a mempool of MIN_BIO_PAGES reserved pages. It allocates first MIN_BIO_PAGES with non-failing allocation (the allocation cannot fail and waits until the mempool is refilled). Further pages are allocated with different gfp flags that allow failing. Because allocations may be done in parallel, this code can deadlock. Example: There are two processes, each tries to allocate MIN_BIO_PAGES and the processes run simultaneously. It may end up in a situation where each process allocates (MIN_BIO_PAGES / 2) pages. The mempool is exhausted. Each process waits for more pages to be freed to the mempool, which never happens. To avoid this deadlock scenario, this patch changes the code so that only the first page is allocated with non-failing gfp mask. Allocation of further pages may fail. Signed-off-by: Mikulas Patocka Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-crypt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 8c2a000cf3f5..c75d947436dd 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -176,7 +176,6 @@ struct crypt_config { #define MIN_IOS 16 #define MIN_POOL_PAGES 32 -#define MIN_BIO_PAGES 8 static struct kmem_cache *_crypt_io_pool; @@ -848,12 +847,11 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size, } /* - * if additional pages cannot be allocated without waiting, - * return a partially allocated bio, the caller will then try - * to allocate additional bios while submitting this partial bio + * If additional pages cannot be allocated without waiting, + * return a partially-allocated bio. The caller will then try + * to allocate more bios while submitting this partial bio. */ - if (i == (MIN_BIO_PAGES - 1)) - gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT; + gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT; len = (size > PAGE_SIZE) ? PAGE_SIZE : size; -- cgit v1.2.3 From 33eb514c949a81198867cebfd34153f98d308b79 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 28 Mar 2012 18:41:22 +0100 Subject: dm crypt: add missing error handling commit 72c6e7afc43e19f68a31dea204fc366624d6eee9 upstream. Always set io->error to -EIO when an error is detected in dm-crypt. There were cases where an error code would be set only if we finish processing the last sector. If there were other encryption operations in flight, the error would be ignored and bio would be returned with success as if no error happened. This bug is present in kcryptd_crypt_write_convert, kcryptd_crypt_read_convert and kcryptd_async_done. Signed-off-by: Mikulas Patocka Reviewed-by: Milan Broz Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-crypt.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index c75d947436dd..58d8c6dfb085 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1044,16 +1044,14 @@ static void kcryptd_queue_io(struct dm_crypt_io *io) queue_work(cc->io_queue, &io->work); } -static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, - int error, int async) +static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async) { struct bio *clone = io->ctx.bio_out; struct crypt_config *cc = io->target->private; - if (unlikely(error < 0)) { + if (unlikely(io->error < 0)) { crypt_free_buffer_pages(cc, clone); bio_put(clone); - io->error = -EIO; crypt_dec_pending(io); return; } @@ -1104,12 +1102,16 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) sector += bio_sectors(clone); crypt_inc_pending(io); + r = crypt_convert(cc, &io->ctx); + if (r < 0) + io->error = -EIO; + crypt_finished = atomic_dec_and_test(&io->ctx.pending); /* Encryption was already finished, submit io now */ if (crypt_finished) { - kcryptd_crypt_write_io_submit(io, r, 0); + kcryptd_crypt_write_io_submit(io, 0); /* * If there was an error, do not try next fragments. @@ -1160,11 +1162,8 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) crypt_dec_pending(io); } -static void kcryptd_crypt_read_done(struct dm_crypt_io *io, int error) +static void kcryptd_crypt_read_done(struct dm_crypt_io *io) { - if (unlikely(error < 0)) - io->error = -EIO; - crypt_dec_pending(io); } @@ -1179,9 +1178,11 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io) io->sector); r = crypt_convert(cc, &io->ctx); + if (r < 0) + io->error = -EIO; if (atomic_dec_and_test(&io->ctx.pending)) - kcryptd_crypt_read_done(io, r); + kcryptd_crypt_read_done(io); crypt_dec_pending(io); } @@ -1202,15 +1203,18 @@ static void kcryptd_async_done(struct crypto_async_request *async_req, if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post) error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq); + if (error < 0) + io->error = -EIO; + mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool); if (!atomic_dec_and_test(&ctx->pending)) return; if (bio_data_dir(io->base_bio) == READ) - kcryptd_crypt_read_done(io, error); + kcryptd_crypt_read_done(io); else - kcryptd_crypt_write_io_submit(io, error, 1); + kcryptd_crypt_write_io_submit(io, 1); } static void kcryptd_crypt(struct work_struct *work) -- cgit v1.2.3 From e6958f1facf6b5369b6020a7b123a278407d25c5 Mon Sep 17 00:00:00 2001 From: Andrei Warkentin Date: Wed, 28 Mar 2012 18:41:22 +0100 Subject: dm exception store: fix init error path commit aadbe266f2f89ccc68b52f4effc7b3a8b29521ef upstream. Call the correct exit function on failure in dm_exception_store_init. Signed-off-by: Andrei Warkentin Acked-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-exception-store.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index 042e71996569..aa70f7d43a1a 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -283,7 +283,7 @@ int dm_exception_store_init(void) return 0; persistent_fail: - dm_persistent_snapshot_exit(); + dm_transient_snapshot_exit(); transient_fail: return r; } -- cgit v1.2.3 From e9decde494c0960caaad20f6d5cd92d99a29dae2 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 28 Mar 2012 18:41:23 +0100 Subject: dm persistent data: fix btree rebalancing after remove commit b0988900bae9ecf968a8a8d086a9eec671a9517a upstream. When we remove an entry from a node we sometimes rebalance with it's two neighbours. This wasn't being done correctly; in some cases entries have to move all the way from the right neighbour to the left neighbour, or vice versa. This patch pretty much re-writes the balancing code to fix it. This code is barely used currently; only when you delete a thin device, and then only if you have hundreds of them in the same pool. Once we have discard support, which removes mappings, this will be used much more heavily. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/persistent-data/dm-btree-remove.c | 174 +++++++++++++++------------ 1 file changed, 99 insertions(+), 75 deletions(-) diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 023fbc2d389e..1a35caf2563d 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -128,18 +128,9 @@ static void delete_at(struct node *n, unsigned index) n->header.nr_entries = cpu_to_le32(nr_entries - 1); } -static unsigned del_threshold(struct node *n) -{ - return le32_to_cpu(n->header.max_entries) / 3; -} - static unsigned merge_threshold(struct node *n) { - /* - * The extra one is because we know we're potentially going to - * delete an entry. - */ - return 2 * (le32_to_cpu(n->header.max_entries) / 3) + 1; + return le32_to_cpu(n->header.max_entries) / 3; } struct child { @@ -188,6 +179,15 @@ static int exit_child(struct dm_btree_info *info, struct child *c) static void shift(struct node *left, struct node *right, int count) { + uint32_t nr_left = le32_to_cpu(left->header.nr_entries); + uint32_t nr_right = le32_to_cpu(right->header.nr_entries); + uint32_t max_entries = le32_to_cpu(left->header.max_entries); + uint32_t r_max_entries = le32_to_cpu(right->header.max_entries); + + BUG_ON(max_entries != r_max_entries); + BUG_ON(nr_left - count > max_entries); + BUG_ON(nr_right + count > max_entries); + if (!count) return; @@ -199,13 +199,8 @@ static void shift(struct node *left, struct node *right, int count) node_shift(right, count); } - left->header.nr_entries = - cpu_to_le32(le32_to_cpu(left->header.nr_entries) - count); - BUG_ON(le32_to_cpu(left->header.nr_entries) > le32_to_cpu(left->header.max_entries)); - - right->header.nr_entries = - cpu_to_le32(le32_to_cpu(right->header.nr_entries) + count); - BUG_ON(le32_to_cpu(right->header.nr_entries) > le32_to_cpu(right->header.max_entries)); + left->header.nr_entries = cpu_to_le32(nr_left - count); + right->header.nr_entries = cpu_to_le32(nr_right + count); } static void __rebalance2(struct dm_btree_info *info, struct node *parent, @@ -215,8 +210,9 @@ static void __rebalance2(struct dm_btree_info *info, struct node *parent, struct node *right = r->n; uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t nr_right = le32_to_cpu(right->header.nr_entries); + unsigned threshold = 2 * merge_threshold(left) + 1; - if (nr_left + nr_right <= merge_threshold(left)) { + if (nr_left + nr_right < threshold) { /* * Merge */ @@ -234,9 +230,6 @@ static void __rebalance2(struct dm_btree_info *info, struct node *parent, * Rebalance. */ unsigned target_left = (nr_left + nr_right) / 2; - unsigned shift_ = nr_left - target_left; - BUG_ON(le32_to_cpu(left->header.max_entries) <= nr_left - shift_); - BUG_ON(le32_to_cpu(right->header.max_entries) <= nr_right + shift_); shift(left, right, nr_left - target_left); *key_ptr(parent, r->index) = right->keys[0]; } @@ -272,6 +265,84 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info, return exit_child(info, &right); } +/* + * We dump as many entries from center as possible into left, then the rest + * in right, then rebalance2. This wastes some cpu, but I want something + * simple atm. + */ +static void delete_center_node(struct dm_btree_info *info, struct node *parent, + struct child *l, struct child *c, struct child *r, + struct node *left, struct node *center, struct node *right, + uint32_t nr_left, uint32_t nr_center, uint32_t nr_right) +{ + uint32_t max_entries = le32_to_cpu(left->header.max_entries); + unsigned shift = min(max_entries - nr_left, nr_center); + + BUG_ON(nr_left + shift > max_entries); + node_copy(left, center, -shift); + left->header.nr_entries = cpu_to_le32(nr_left + shift); + + if (shift != nr_center) { + shift = nr_center - shift; + BUG_ON((nr_right + shift) > max_entries); + node_shift(right, shift); + node_copy(center, right, shift); + right->header.nr_entries = cpu_to_le32(nr_right + shift); + } + *key_ptr(parent, r->index) = right->keys[0]; + + delete_at(parent, c->index); + r->index--; + + dm_tm_dec(info->tm, dm_block_location(c->block)); + __rebalance2(info, parent, l, r); +} + +/* + * Redistributes entries among 3 sibling nodes. + */ +static void redistribute3(struct dm_btree_info *info, struct node *parent, + struct child *l, struct child *c, struct child *r, + struct node *left, struct node *center, struct node *right, + uint32_t nr_left, uint32_t nr_center, uint32_t nr_right) +{ + int s; + uint32_t max_entries = le32_to_cpu(left->header.max_entries); + unsigned target = (nr_left + nr_center + nr_right) / 3; + BUG_ON(target > max_entries); + + if (nr_left < nr_right) { + s = nr_left - target; + + if (s < 0 && nr_center < -s) { + /* not enough in central node */ + shift(left, center, nr_center); + s = nr_center - target; + shift(left, right, s); + nr_right += s; + } else + shift(left, center, s); + + shift(center, right, target - nr_right); + + } else { + s = target - nr_right; + if (s > 0 && nr_center < s) { + /* not enough in central node */ + shift(center, right, nr_center); + s = target - nr_center; + shift(left, right, s); + nr_left -= s; + } else + shift(center, right, s); + + shift(left, center, nr_left - target); + } + + *key_ptr(parent, c->index) = center->keys[0]; + *key_ptr(parent, r->index) = right->keys[0]; +} + static void __rebalance3(struct dm_btree_info *info, struct node *parent, struct child *l, struct child *c, struct child *r) { @@ -282,62 +353,18 @@ static void __rebalance3(struct dm_btree_info *info, struct node *parent, uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t nr_center = le32_to_cpu(center->header.nr_entries); uint32_t nr_right = le32_to_cpu(right->header.nr_entries); - uint32_t max_entries = le32_to_cpu(left->header.max_entries); - unsigned target; + unsigned threshold = merge_threshold(left) * 4 + 1; BUG_ON(left->header.max_entries != center->header.max_entries); BUG_ON(center->header.max_entries != right->header.max_entries); - if (((nr_left + nr_center + nr_right) / 2) < merge_threshold(center)) { - /* - * Delete center node: - * - * We dump as many entries from center as possible into - * left, then the rest in right, then rebalance2. This - * wastes some cpu, but I want something simple atm. - */ - unsigned shift = min(max_entries - nr_left, nr_center); - - BUG_ON(nr_left + shift > max_entries); - node_copy(left, center, -shift); - left->header.nr_entries = cpu_to_le32(nr_left + shift); - - if (shift != nr_center) { - shift = nr_center - shift; - BUG_ON((nr_right + shift) >= max_entries); - node_shift(right, shift); - node_copy(center, right, shift); - right->header.nr_entries = cpu_to_le32(nr_right + shift); - } - *key_ptr(parent, r->index) = right->keys[0]; - - delete_at(parent, c->index); - r->index--; - - dm_tm_dec(info->tm, dm_block_location(c->block)); - __rebalance2(info, parent, l, r); - - return; - } - - /* - * Rebalance - */ - target = (nr_left + nr_center + nr_right) / 3; - BUG_ON(target > max_entries); - - /* - * Adjust the left node - */ - shift(left, center, nr_left - target); - - /* - * Adjust the right node - */ - shift(center, right, target - nr_right); - *key_ptr(parent, c->index) = center->keys[0]; - *key_ptr(parent, r->index) = right->keys[0]; + if ((nr_left + nr_center + nr_right) < threshold) + delete_center_node(info, parent, l, c, r, left, center, right, + nr_left, nr_center, nr_right); + else + redistribute3(info, parent, l, c, r, left, center, right, + nr_left, nr_center, nr_right); } static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info, @@ -441,9 +468,6 @@ static int rebalance_children(struct shadow_spine *s, if (r) return r; - if (child_entries > del_threshold(n)) - return 0; - has_left_sibling = i > 0; has_right_sibling = i < (le32_to_cpu(n->header.nr_entries) - 1); -- cgit v1.2.3 From 08c4bc38d68c073671068eb6fe54cbaa0a116b8c Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 28 Mar 2012 18:41:23 +0100 Subject: dm thin: fix stacked bi_next usage commit 6f94a4c45a6f744383f9f695dde019998db3df55 upstream. Avoid using the bi_next field for the holder of a cell when deferring bios because a stacked device below might change it. Store the holder in a new field in struct cell instead. When a cell is created, the bio that triggered creation (the holder) was added to the same bio list as subsequent bios. In some cases we pass this holder bio directly to devices underneath. If those devices use the bi_next field there will be trouble... This also simplifies some code that had to work out which bio was the holder. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-thin.c | 124 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index c3087575fef0..da2f0217df66 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -124,7 +124,7 @@ struct cell { struct hlist_node list; struct bio_prison *prison; struct cell_key key; - unsigned count; + struct bio *holder; struct bio_list bios; }; @@ -220,55 +220,60 @@ static struct cell *__search_bucket(struct hlist_head *bucket, * This may block if a new cell needs allocating. You must ensure that * cells will be unlocked even if the calling thread is blocked. * - * Returns the number of entries in the cell prior to the new addition - * or < 0 on failure. + * Returns 1 if the cell was already held, 0 if @inmate is the new holder. */ static int bio_detain(struct bio_prison *prison, struct cell_key *key, struct bio *inmate, struct cell **ref) { - int r; + int r = 1; unsigned long flags; uint32_t hash = hash_key(prison, key); - struct cell *uninitialized_var(cell), *cell2 = NULL; + struct cell *cell, *cell2; BUG_ON(hash > prison->nr_buckets); spin_lock_irqsave(&prison->lock, flags); + cell = __search_bucket(prison->cells + hash, key); + if (cell) { + bio_list_add(&cell->bios, inmate); + goto out; + } - if (!cell) { - /* - * Allocate a new cell - */ - spin_unlock_irqrestore(&prison->lock, flags); - cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO); - spin_lock_irqsave(&prison->lock, flags); + /* + * Allocate a new cell + */ + spin_unlock_irqrestore(&prison->lock, flags); + cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO); + spin_lock_irqsave(&prison->lock, flags); - /* - * We've been unlocked, so we have to double check that - * nobody else has inserted this cell in the meantime. - */ - cell = __search_bucket(prison->cells + hash, key); + /* + * We've been unlocked, so we have to double check that + * nobody else has inserted this cell in the meantime. + */ + cell = __search_bucket(prison->cells + hash, key); + if (cell) { + mempool_free(cell2, prison->cell_pool); + bio_list_add(&cell->bios, inmate); + goto out; + } + + /* + * Use new cell. + */ + cell = cell2; - if (!cell) { - cell = cell2; - cell2 = NULL; + cell->prison = prison; + memcpy(&cell->key, key, sizeof(cell->key)); + cell->holder = inmate; + bio_list_init(&cell->bios); + hlist_add_head(&cell->list, prison->cells + hash); - cell->prison = prison; - memcpy(&cell->key, key, sizeof(cell->key)); - cell->count = 0; - bio_list_init(&cell->bios); - hlist_add_head(&cell->list, prison->cells + hash); - } - } + r = 0; - r = cell->count++; - bio_list_add(&cell->bios, inmate); +out: spin_unlock_irqrestore(&prison->lock, flags); - if (cell2) - mempool_free(cell2, prison->cell_pool); - *ref = cell; return r; @@ -283,8 +288,8 @@ static void __cell_release(struct cell *cell, struct bio_list *inmates) hlist_del(&cell->list); - if (inmates) - bio_list_merge(inmates, &cell->bios); + bio_list_add(inmates, cell->holder); + bio_list_merge(inmates, &cell->bios); mempool_free(cell, prison->cell_pool); } @@ -305,22 +310,44 @@ static void cell_release(struct cell *cell, struct bio_list *bios) * bio may be in the cell. This function releases the cell, and also does * a sanity check. */ +static void __cell_release_singleton(struct cell *cell, struct bio *bio) +{ + hlist_del(&cell->list); + BUG_ON(cell->holder != bio); + BUG_ON(!bio_list_empty(&cell->bios)); +} + static void cell_release_singleton(struct cell *cell, struct bio *bio) { - struct bio_prison *prison = cell->prison; - struct bio_list bios; - struct bio *b; unsigned long flags; - - bio_list_init(&bios); + struct bio_prison *prison = cell->prison; spin_lock_irqsave(&prison->lock, flags); - __cell_release(cell, &bios); + __cell_release_singleton(cell, bio); spin_unlock_irqrestore(&prison->lock, flags); +} + +/* + * Sometimes we don't want the holder, just the additional bios. + */ +static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates) +{ + struct bio_prison *prison = cell->prison; - b = bio_list_pop(&bios); - BUG_ON(b != bio); - BUG_ON(!bio_list_empty(&bios)); + hlist_del(&cell->list); + bio_list_merge(inmates, &cell->bios); + + mempool_free(cell, prison->cell_pool); +} + +static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates) +{ + unsigned long flags; + struct bio_prison *prison = cell->prison; + + spin_lock_irqsave(&prison->lock, flags); + __cell_release_no_holder(cell, inmates); + spin_unlock_irqrestore(&prison->lock, flags); } static void cell_error(struct cell *cell) @@ -800,21 +827,16 @@ static void cell_defer(struct thin_c *tc, struct cell *cell, * Same as cell_defer above, except it omits one particular detainee, * a write bio that covers the block and has already been processed. */ -static void cell_defer_except(struct thin_c *tc, struct cell *cell, - struct bio *exception) +static void cell_defer_except(struct thin_c *tc, struct cell *cell) { struct bio_list bios; - struct bio *bio; struct pool *pool = tc->pool; unsigned long flags; bio_list_init(&bios); - cell_release(cell, &bios); spin_lock_irqsave(&pool->lock, flags); - while ((bio = bio_list_pop(&bios))) - if (bio != exception) - bio_list_add(&pool->deferred_bios, bio); + cell_release_no_holder(cell, &pool->deferred_bios); spin_unlock_irqrestore(&pool->lock, flags); wake_worker(pool); @@ -854,7 +876,7 @@ static void process_prepared_mapping(struct new_mapping *m) * the bios in the cell. */ if (bio) { - cell_defer_except(tc, m->cell, bio); + cell_defer_except(tc, m->cell); bio_endio(bio, 0); } else cell_defer(tc, m->cell, m->data_block); -- cgit v1.2.3 From 2cbfe1645597e81c6f6af0b5245ab67cac6db027 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 28 Mar 2012 14:42:56 -0700 Subject: backlight: fix typo in tosa_lcd.c commit 8da00edc1069f01c34510fa405dc15d96c090a3f upstream. Fix typo in drivers/video/backlight/tosa_lcd.c "tosa_lcd_reume" should be "tosa_lcd_resume". Signed-off-by: Masanari Iida Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/tosa_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 772f6015219a..6f54f7436a97 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -271,7 +271,7 @@ static int tosa_lcd_resume(struct spi_device *spi) } #else #define tosa_lcd_suspend NULL -#define tosa_lcd_reume NULL +#define tosa_lcd_resume NULL #endif static struct spi_driver tosa_lcd_driver = { -- cgit v1.2.3 From c45247fdfb2ddf4a96574f8dd3b6857056c20c91 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 15 Mar 2012 09:34:02 +0000 Subject: xfs: Fix oops on IO error during xlog_recover_process_iunlinks() commit d97d32edcd732110758799ae60af725e5110b3dc upstream. When an IO error happens during inode deletion run from xlog_recover_process_iunlinks() filesystem gets shutdown. Thus any subsequent attempt to read buffers fails. Code in xlog_recover_process_iunlinks() does not count with the fact that read of a buffer which was read a while ago can really fail which results in the oops on agi = XFS_BUF_TO_AGI(agibp); Fix the problem by cleaning up the buffer handling in xlog_recover_process_iunlinks() as suggested by Dave Chinner. We release buffer lock but keep buffer reference to AG buffer. That is enough for buffer to stay pinned in memory and we don't have to call xfs_read_agi() all the time. Signed-off-by: Jan Kara Reviewed-by: Dave Chinner Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_log_recover.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 541a508adea1..4f5d0ce7854d 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3161,37 +3161,26 @@ xlog_recover_process_iunlinks( */ continue; } + /* + * Unlock the buffer so that it can be acquired in the normal + * course of the transaction to truncate and free each inode. + * Because we are not racing with anyone else here for the AGI + * buffer, we don't even need to hold it locked to read the + * initial unlinked bucket entries out of the buffer. We keep + * buffer reference though, so that it stays pinned in memory + * while we need the buffer. + */ agi = XFS_BUF_TO_AGI(agibp); + xfs_buf_unlock(agibp); for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) { agino = be32_to_cpu(agi->agi_unlinked[bucket]); while (agino != NULLAGINO) { - /* - * Release the agi buffer so that it can - * be acquired in the normal course of the - * transaction to truncate and free the inode. - */ - xfs_buf_relse(agibp); - agino = xlog_recover_process_one_iunlink(mp, agno, agino, bucket); - - /* - * Reacquire the agibuffer and continue around - * the loop. This should never fail as we know - * the buffer was good earlier on. - */ - error = xfs_read_agi(mp, NULL, agno, &agibp); - ASSERT(error == 0); - agi = XFS_BUF_TO_AGI(agibp); } } - - /* - * Release the buffer for the current agi so we can - * go on to the next one. - */ - xfs_buf_relse(agibp); + xfs_buf_rele(agibp); } mp->m_dmevmask = mp_dmevmask; -- cgit v1.2.3 From 8a9de9cde83d1c913bcbe5bd8c6291f5536a576c Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 17 Jan 2012 09:27:31 -0600 Subject: slub: Do not hold slub_lock when calling sysfs_slab_add() commit 66c4c35c6bc5a1a452b024cf0364635b28fd94e4 upstream. sysfs_slab_add() calls various sysfs functions that actually may end up in userspace doing all sorts of things. Release the slub_lock after adding the kmem_cache structure to the list. At that point the address of the kmem_cache is not known so we are guaranteed exlusive access to the following modifications to the kmem_cache structure. If the sysfs_slab_add fails then reacquire the slub_lock to remove the kmem_cache structure from the list. Reported-by: Sasha Levin Acked-by: Eric Dumazet Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index 1a919f0150f5..a99c785828c6 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3911,13 +3911,14 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, if (kmem_cache_open(s, n, size, align, flags, ctor)) { list_add(&s->list, &slab_caches); + up_write(&slub_lock); if (sysfs_slab_add(s)) { + down_write(&slub_lock); list_del(&s->list); kfree(n); kfree(s); goto err; } - up_write(&slub_lock); return s; } kfree(n); -- cgit v1.2.3 From e5267d1f1cc43a481a599fe1e2d8256016e18825 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 27 Mar 2012 18:13:02 -0400 Subject: NFSv4: Fix two infinite loops in the mount code commit 05e9cfb408b24debb3a85fd98edbfd09dd148881 upstream. We can currently loop forever in nfs4_lookup_root() and in nfs41_proc_secinfo_no_name(), if the first iteration returns a NFS4ERR_DELAY or something else that causes exception.retry to get set. Reported-by: Weston Andros Adamson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c9e2d9ee3242..6db09728b220 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2242,11 +2242,12 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, switch (err) { case 0: case -NFS4ERR_WRONGSEC: - break; + goto out; default: err = nfs4_handle_exception(server, err, &exception); } } while (exception.retry); +out: return err; } @@ -6099,11 +6100,12 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, case 0: case -NFS4ERR_WRONGSEC: case -NFS4ERR_NOTSUPP: - break; + goto out; default: err = nfs4_handle_exception(server, err, &exception); } } while (exception.retry); +out: return err; } -- cgit v1.2.3 From 04cf7f7a565f0d2d2f5f3be56ceb6d680cba0f71 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 27 Mar 2012 18:22:19 -0400 Subject: NFSv4.1: Fix layoutcommit error handling commit e59d27e05a6435f8c04d5ad843f37fa795f2eaaa upstream. Firstly, task->tk_status will always return negative error values, so the current tests for 'NFS4ERR_DELEG_REVOKED' etc. are all being ignored. Secondly, clean up the code so that we only need to test task->tk_status once! Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6db09728b220..d9457002ca04 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5983,21 +5983,22 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) return; switch (task->tk_status) { /* Just ignore these failures */ - case NFS4ERR_DELEG_REVOKED: /* layout was recalled */ - case NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */ - case NFS4ERR_BADLAYOUT: /* no layout */ - case NFS4ERR_GRACE: /* loca_recalim always false */ + case -NFS4ERR_DELEG_REVOKED: /* layout was recalled */ + case -NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */ + case -NFS4ERR_BADLAYOUT: /* no layout */ + case -NFS4ERR_GRACE: /* loca_recalim always false */ task->tk_status = 0; - } - - if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { - rpc_restart_call_prepare(task); - return; - } - - if (task->tk_status == 0) + break; + case 0: nfs_post_op_update_inode_force_wcc(data->args.inode, data->res.fattr); + break; + default: + if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { + rpc_restart_call_prepare(task); + return; + } + } } static void nfs4_layoutcommit_release(void *calldata) -- cgit v1.2.3 From c88e98e32e1709e8cd765b701dd6fdeb08612819 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 30 Jan 2012 23:07:22 -0500 Subject: module: Remove module size limit commit f946eeb9313ff1470758e171a60fe7438a2ded3f upstream. Module size was limited to 64MB, this was legacy limitation due to vmalloc() which was removed a while ago. Limiting module size to 64MB is both pointless and affects real world use cases. Cc: Tim Abbott Signed-off-by: Sasha Levin Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 178333c48d1e..6969ef05d2d7 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2341,8 +2341,7 @@ static int copy_and_check(struct load_info *info, return -ENOEXEC; /* Suck in entire file: we'll want most of it. */ - /* vmalloc barfs on "unusual" numbers. Check here */ - if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL) + if ((hdr = vmalloc(len)) == NULL) return -ENOMEM; if (copy_from_user(hdr, umod, len) != 0) { -- cgit v1.2.3 From 6ea96a4a90a5f2e1119df30180d851296e72032f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 20 Dec 2011 18:19:00 -0800 Subject: Bluetooth: btusb: fix bInterval for high/super speed isochronous endpoints commit fa0fb93f2ac308a76fa64eb57c18511dadf97089 upstream. For high-speed/super-speed isochronous endpoints, the bInterval value is used as exponent, 2^(bInterval-1). Luckily we have usb_fill_int_urb() function that handles it correctly. So we just call this function to fill in the RX URB. Cc: Marcel Holtmann Signed-off-by: Bing Zhao Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 11a925c9ed1d..c16c7509f1ad 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -507,15 +507,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); - urb->dev = data->udev; - urb->pipe = pipe; - urb->context = hdev; - urb->complete = btusb_isoc_complete; - urb->interval = data->isoc_rx_ep->bInterval; + usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete, + hdev, data->isoc_rx_ep->bInterval); urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; - urb->transfer_buffer = buf; - urb->transfer_buffer_length = size; __fill_isoc_descriptor(urb, size, le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); -- cgit v1.2.3 From 982b8bf53d1b4a8ab091d9218ce71b817a19fbb4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 28 Mar 2012 10:48:49 +0100 Subject: drm/i915: suspend fbdev device around suspend/hibernate commit 3fa016a0b5c5237e9c387fc3249592b2cb5391c6 upstream. Looking at hibernate overwriting I though it looked like a cursor, so I tracked down this missing piece to stop the cursor blink timer. I've no idea if this is sufficient to fix the hibernate problems people are seeing, but please test it. Both radeon and nouveau have done this for a long time. I've run this personally all night hib/resume cycles with no fails. Reviewed-by: Keith Packard Reported-by: Petr Tesarik Reported-by: Stanislaw Gruszka Reported-by: Lots of misc segfaults after hibernate across the world. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=37142 Tested-by: Dave Airlie Tested-by: Bojan Smojver Tested-by: Andreas Hartmann Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.c | 7 +++++++ drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_fb.c | 10 ++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e2d85a9d3663..d04597dfa52c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -442,6 +442,10 @@ static int i915_drm_freeze(struct drm_device *dev) /* Modeset on resume, not lid events */ dev_priv->modeset_on_lid = 0; + console_lock(); + intel_fbdev_set_suspend(dev, 1); + console_unlock(); + return 0; } @@ -514,6 +518,9 @@ static int i915_drm_thaw(struct drm_device *dev) dev_priv->modeset_on_lid = 0; + console_lock(); + intel_fbdev_set_suspend(dev, 0); + console_unlock(); return error; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a1b4343814e8..83e820ea95b3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -364,7 +364,7 @@ extern int intel_framebuffer_init(struct drm_device *dev, struct drm_i915_gem_object *obj); extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); - +extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); extern void intel_prepare_page_flip(struct drm_device *dev, int plane); extern void intel_finish_page_flip(struct drm_device *dev, int pipe); extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ec49bae73382..d0ce34b78cc7 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -257,6 +257,16 @@ void intel_fbdev_fini(struct drm_device *dev) kfree(dev_priv->fbdev); dev_priv->fbdev = NULL; } + +void intel_fbdev_set_suspend(struct drm_device *dev, int state) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + if (!dev_priv->fbdev) + return; + + fb_set_suspend(dev_priv->fbdev->helper.fbdev, state); +} + MODULE_LICENSE("GPL and additional rights"); void intel_fb_output_poll_changed(struct drm_device *dev) -- cgit v1.2.3 From 9ec476d98f2ee3e851549e2a926a3db9477f4807 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 20 Mar 2012 03:57:54 +0000 Subject: Fix pppol2tp getsockname() [ Upstream commit bbdb32cb5b73597386913d052165423b9d736145 ] While testing L2TP functionality, I came across a bug in getsockname(). The IP address returned within the pppol2tp_addr's addr memember was not being set to the IP address in use. This bug is caused by using inet_sk() on the wrong socket (the L2TP socket rather than the underlying UDP socket), and was likely introduced during the addition of L2TPv3 support. Signed-off-by: Benjamin LaHaise Signed-off-by: James Chapman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_ppp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 8a90d756c904..b1bd16f142bd 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -915,7 +915,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, goto end_put_sess; } - inet = inet_sk(sk); + inet = inet_sk(tunnel->sock); if (tunnel->version == 2) { struct sockaddr_pppol2tp sp; len = sizeof(sp); -- cgit v1.2.3 From 0cff40794bd89b8218f64f8fe058fbf67835fc2f Mon Sep 17 00:00:00 2001 From: Gao feng Date: Mon, 19 Mar 2012 22:36:10 +0000 Subject: ipv6: fix incorrent ipv6 ipsec packet fragment [ Upstream commit 1f85851e17b64cabd089a8a8839dddebc627948c ] Since commit 299b0767(ipv6: Fix IPsec slowpath fragmentation problem) In func ip6_append_data,after call skb_put(skb, fraglen + dst_exthdrlen) the skb->len contains dst_exthdrlen,and we don't reduce dst_exthdrlen at last This will make fraggap>0 in next "while cycle",and cause the size of skb incorrent Fix this by reserve headroom for dst_exthdrlen. Signed-off-by: Gao feng Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ec562713db9b..f7f07e2e7c1a 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1411,8 +1411,9 @@ alloc_new_skb: */ skb->ip_summed = csummode; skb->csum = 0; - /* reserve for fragmentation */ - skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); + /* reserve for fragmentation and ipsec header */ + skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + + dst_exthdrlen); if (sk->sk_type == SOCK_DGRAM) skb_shinfo(skb)->tx_flags = tx_flags; @@ -1420,9 +1421,9 @@ alloc_new_skb: /* * Find where to start putting bytes */ - data = skb_put(skb, fraglen + dst_exthdrlen); - skb_set_network_header(skb, exthdrlen + dst_exthdrlen); - data += fragheaderlen + dst_exthdrlen; + data = skb_put(skb, fraglen); + skb_set_network_header(skb, exthdrlen); + data += fragheaderlen; skb->transport_header = (skb->network_header + fragheaderlen); if (fraggap) { -- cgit v1.2.3 From 8a9ecfa63e8113306420f60832b0b9631e26ec57 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 18 Mar 2012 02:40:48 +0000 Subject: net: bpf_jit: fix BPF_S_LDX_B_MSH compilation [ Upstream commit dc72d99dabb870ca5bd6d9fff674be853bb4a88d ] Matt Evans spotted that x86 bpf_jit was incorrectly handling negative constant offsets in BPF_S_LDX_B_MSH instruction. We need to abort JIT compilation like we do in common_load so that filter uses the interpreter code and can call __load_pointer() Reference: http://lists.openwall.net/netdev/2011/07/19/11 Thanks to Indan Zupancic to bring back this issue. Reported-by: Matt Evans Reported-by: Indan Zupancic Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/x86/net/bpf_jit_comp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7c1b765ecc59..5671752f8d9c 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -475,8 +475,10 @@ void bpf_jit_compile(struct sk_filter *fp) case BPF_S_LD_W_ABS: func = sk_load_word; common_load: seen |= SEEN_DATAREF; - if ((int)K < 0) + if ((int)K < 0) { + /* Abort the JIT because __load_pointer() is needed. */ goto out; + } t_offset = func - (image + addrs[i]); EMIT1_off32(0xbe, K); /* mov imm32,%esi */ EMIT1_off32(0xe8, t_offset); /* call */ @@ -489,14 +491,8 @@ common_load: seen |= SEEN_DATAREF; goto common_load; case BPF_S_LDX_B_MSH: if ((int)K < 0) { - if (pc_ret0 > 0) { - /* addrs[pc_ret0 - 1] is the start address */ - EMIT_JMP(addrs[pc_ret0 - 1] - addrs[i]); - break; - } - CLEAR_A(); - EMIT_JMP(cleanup_addr - addrs[i]); - break; + /* Abort the JIT because __load_pointer() is needed. */ + goto out; } seen |= SEEN_DATAREF | SEEN_XREG; t_offset = sk_load_byte_msh - (image + addrs[i]); -- cgit v1.2.3 From beadbcb483a11bb6f4964d5525fef22dd573505a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Mar 2012 09:53:52 +0000 Subject: net: fix a potential rcu_read_lock() imbalance in rt6_fill_node() [ Upstream commit 94f826b8076e2cb92242061e92f21b5baa3eccc2 ] Commit f2c31e32b378 (net: fix NULL dereferences in check_peer_redir() ) added a regression in rt6_fill_node(), leading to rcu_read_lock() imbalance. Thats because NLA_PUT() can make a jump to nla_put_failure label. Fix this by using nla_put() Many thanks to Ben Greear for his help Reported-by: Ben Greear Reported-by: Dave Jones Signed-off-by: Eric Dumazet Tested-by: Ben Greear Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b582a0a0f1c5..059b9d990ab1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2446,8 +2446,12 @@ static int rt6_fill_node(struct net *net, rcu_read_lock(); n = dst_get_neighbour(&rt->dst); - if (n) - NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); + if (n) { + if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) { + rcu_read_unlock(); + goto nla_put_failure; + } + } rcu_read_unlock(); if (rt->dst.dev) -- cgit v1.2.3 From 905c221ccf34bd7be7947cab38b2b1296fe9243b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Mar 2012 06:58:03 +0000 Subject: net: fix napi_reuse_skb() skb reserve [ Upstream commit 2a2a459eeeff48640dc557548ce576d666ab06ed ] napi->skb is allocated in napi_get_frags() using netdev_alloc_skb_ip_align(), with a reserve of NET_SKB_PAD + NET_IP_ALIGN bytes. However, when such skb is recycled in napi_reuse_skb(), it ends with a reserve of NET_IP_ALIGN which is suboptimal. Signed-off-by: Eric Dumazet Cc: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index c56cacfe2a64..55cd370724c3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3634,7 +3634,8 @@ EXPORT_SYMBOL(napi_gro_receive); static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) { __skb_pull(skb, skb_headlen(skb)); - skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb)); + /* restore the reserve we had after netdev_alloc_skb_ip_align() */ + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb)); skb->vlan_tci = 0; skb->dev = napi->dev; skb->skb_iif = 0; -- cgit v1.2.3 From 8dd1b45065052ea3bddbb58368dfdbef5c4bc80d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 19 Mar 2012 13:01:07 +0000 Subject: Remove printk from rds_sendmsg [ Upstream commit a6506e1486181975d318344143aca722b2b91621 ] no socket layer outputs a message for this error and neither should rds. Signed-off-by: Dave Jones Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/send.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/rds/send.c b/net/rds/send.c index e2d63c59e7c2..96531d4033a2 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -935,7 +935,6 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, /* Mirror Linux UDP mirror of BSD error message compatibility */ /* XXX: Perhaps MSG_MORE someday */ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) { - printk(KERN_INFO "msg_flags 0x%08X\n", msg->msg_flags); ret = -EOPNOTSUPP; goto out; } -- cgit v1.2.3 From 9b1ad27f4e59445a6e52deb25956b28a84509361 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 21 Mar 2012 05:32:05 +0000 Subject: sky2: override for PCI legacy power management [ Upstream commit 5676cc7bfe1e388e87843f71daa229610385b41e ] Some BIOS's don't setup power management correctly (what else is new) and don't allow use of PCI Express power control. Add a special exception module parameter to allow working around this issue. Based on slightly different patch by Knut Petersen. Reported-by: Arkadiusz Miskiewicz Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/sky2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 7803efa46eb2..f612b35c08ac 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -95,6 +95,10 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); +static int legacy_pme = 0; +module_param(legacy_pme, int, 0); +MODULE_PARM_DESC(legacy_pme, "Legacy power management"); + static DEFINE_PCI_DEVICE_TABLE(sky2_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */ @@ -867,6 +871,13 @@ static void sky2_wol_init(struct sky2_port *sky2) /* Disable PiG firmware */ sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF); + /* Needed by some broken BIOSes, use PCI rather than PCI-e for WOL */ + if (legacy_pme) { + u32 reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + reg1 |= PCI_Y2_PME_LEGACY; + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + } + /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_read32(hw, B0_CTST); -- cgit v1.2.3 From 9b5796b841ae7be468c39e88a9c723269651f57c Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 21 Mar 2012 23:36:13 +0000 Subject: xfrm: Access the replay notify functions via the registered callbacks [ Upstream commit 1265fd616782ef03b98fd19f65c2b47fcd4ea11f ] We call the wrong replay notify function when we use ESN replay handling. This leads to the fact that we don't send notifications if we use ESN. Fix this by calling the registered callbacks instead of xfrm_replay_notify(). Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_replay.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 39e02c54ed26..2f6d11d04a2b 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -167,7 +167,7 @@ static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) } if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb) @@ -279,7 +279,7 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq) replay_esn->bmp[nr] |= (1U << bitnr); if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event) @@ -473,7 +473,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) replay_esn->bmp[nr] |= (1U << bitnr); if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static struct xfrm_replay xfrm_replay_legacy = { -- cgit v1.2.3 From eaadbfbf85875c76259c93e7ba51aebe2cad2138 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 7 Feb 2012 15:35:42 +1100 Subject: lockd: fix arg parsing for grace_period and timeout. commit de5b8e8e047534aac6bc9803f96e7257436aef9c upstream. If you try to set grace_period or timeout via a module parameter to lockd, and do this on a big-endian machine where sizeof(int) != sizeof(unsigned long) it won't work. This number given will be effectively shifted right by the difference in those two sizes. So cast kp->arg properly to get correct result. Signed-off-by: NeilBrown Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index c061b9aa7ddb..2444780f5cfa 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -440,7 +440,7 @@ static int param_set_##name(const char *val, struct kernel_param *kp) \ __typeof__(type) num = which_strtol(val, &endp, 0); \ if (endp == val || *endp || num < (min) || num > (max)) \ return -EINVAL; \ - *((int *) kp->arg) = num; \ + *((type *) kp->arg) = num; \ return 0; \ } -- cgit v1.2.3 From 94e75cfe69ac1d91bae5998ac0f21e355ce93a8b Mon Sep 17 00:00:00 2001 From: Alok Kataria Date: Tue, 21 Feb 2012 18:19:55 -0800 Subject: x86, tsc: Skip refined tsc calibration on systems with reliable TSC commit 57779dc2b3b75bee05ef5d1ada47f615f7a13932 upstream. While running the latest Linux as guest under VMware in highly over-committed situations, we have seen cases when the refined TSC algorithm fails to get a valid tsc_start value in tsc_refine_calibration_work from multiple attempts. As a result the kernel keeps on scheduling the tsc_irqwork task for later. Subsequently after several attempts when it gets a valid start value it goes through the refined calibration and either bails out or uses the new results. Given that the kernel originally read the TSC frequency from the platform, which is the best it can get, I don't think there is much value in refining it. So for systems which get the TSC frequency from the platform we should skip the refined tsc algorithm. We can use the TSC_RELIABLE cpu cap flag to detect this, right now it is set only on VMware and for Moorestown Penwell both of which have there own TSC calibration methods. Signed-off-by: Alok N Kataria Cc: John Stultz Cc: Dirk Brandewie Cc: Alan Cox [jstultz: Reworked to simply not schedule the refining work, rather then scheduling the work and bombing out later] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/tsc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index db483369f10b..3fe298abc7cf 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -934,6 +934,16 @@ static int __init init_tsc_clocksource(void) clocksource_tsc.rating = 0; clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS; } + + /* + * Trust the results of the earlier calibration on systems + * exporting a reliable TSC. + */ + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { + clocksource_register_khz(&clocksource_tsc, tsc_khz); + return 0; + } + schedule_delayed_work(&tsc_irqwork, 0); return 0; } -- cgit v1.2.3 From d88f3015285a3845d7330452865f763f16bda726 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 24 Mar 2012 10:52:50 +0300 Subject: x86, tls: Off by one limit check commit 8f0750f19789cf352d7e24a6cc50f2ab1b4f1372 upstream. These are used as offsets into an array of GDT_ENTRY_TLS_ENTRIES members so GDT_ENTRY_TLS_ENTRIES is one past the end of the array. Signed-off-by: Dan Carpenter Link: http://lkml.kernel.org/r/20120324075250.GA28258@elgon.mountain Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/tls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 6bb7b8579e70..bcfec2d23769 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -163,7 +163,7 @@ int regset_tls_get(struct task_struct *target, const struct user_regset *regset, { const struct desc_struct *tls; - if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || + if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || (pos % sizeof(struct user_desc)) != 0 || (count % sizeof(struct user_desc)) != 0) return -EINVAL; @@ -198,7 +198,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES]; const struct user_desc *info; - if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || + if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || (pos % sizeof(struct user_desc)) != 0 || (count % sizeof(struct user_desc)) != 0) return -EINVAL; -- cgit v1.2.3 From acff5ccd7dfccb0c28f367a2a684a7e8e3ee0112 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Mon, 26 Mar 2012 16:26:12 -0400 Subject: compat: use sys_sendfile64() implementation for sendfile syscall commit 1631fcea8399da5e80a80084b3b8c5bfd99d21e7 upstream. was set up to use sys_sendfile() for the 32-bit compat API instead of sys_sendfile64(), but in fact the right thing to do is to use sys_sendfile64() in all cases. The 32-bit sendfile64() API in glibc uses the sendfile64 syscall, so it has to be capable of doing full 64-bit operations. But the sys_sendfile() kernel implementation has a MAX_NON_LFS test in it which explicitly limits the offset to 2^32. So, we need to use the sys_sendfile64() implementation in the kernel for this case. Acked-by: Arnd Bergmann Signed-off-by: Chris Metcalf Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/unistd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h index 2292d1af9d70..991ef01cd77e 100644 --- a/include/asm-generic/unistd.h +++ b/include/asm-generic/unistd.h @@ -218,7 +218,7 @@ __SC_COMP(__NR_pwritev, sys_pwritev, compat_sys_pwritev) /* fs/sendfile.c */ #define __NR3264_sendfile 71 -__SC_3264(__NR3264_sendfile, sys_sendfile64, sys_sendfile) +__SYSCALL(__NR3264_sendfile, sys_sendfile64) /* fs/select.c */ #define __NR_pselect6 72 -- cgit v1.2.3 From 61d38cd909ad35ff497bf1a84cd57b2baf6d9c49 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 6 Mar 2012 17:16:09 -0800 Subject: rtc: Provide flag for rtc devices that don't support UIE commit 4a649903f91232d02284d53724b0a45728111767 upstream. Richard Weinberger noticed that on some RTC hardware that doesn't support UIE mode, due to coarse granular alarms (like 1minute resolution), the current virtualized RTC support doesn't properly error out when UIE is enabled. Instead the current code queues an alarm for the next second, but it won't fire until up to a miniute later. This patch provides a generic way to flag this sort of hardware and fixes the issue on the mpc5121 where Richard noticed the problem. Reported-by: Richard Weinberger Tested-by: Richard Weinberger Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 5 +++++ drivers/rtc/rtc-mpc5121.c | 2 ++ include/linux/rtc.h | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index c1edbf819652..565742b9f0d0 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -445,6 +445,11 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (rtc->uie_rtctimer.enabled == enabled) goto out; + if (rtc->uie_unsupported) { + err = -EINVAL; + goto out; + } + if (enabled) { struct rtc_time tm; ktime_t now, onesec; diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index da60915818b6..0fc2d221bc8b 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -360,6 +360,8 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op) &mpc5200_rtc_ops, THIS_MODULE); } + rtc->rtc->uie_unsupported = 1; + if (IS_ERR(rtc->rtc)) { err = PTR_ERR(rtc->rtc); goto out_free_irq; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 93f4d035076b..fcabfb4873c8 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -202,7 +202,8 @@ struct rtc_device struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */ int pie_enabled; struct work_struct irqwork; - + /* Some hardware can't support UIE mode */ + int uie_unsupported; #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL struct work_struct uie_task; -- cgit v1.2.3 From b43188de0cd27787a75c79856e72c649d4ee9035 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Jan 2012 12:56:02 +0300 Subject: nfsd: don't allow zero length strings in cache_parse() commit 6d8d17499810479eabd10731179c04b2ca22152f upstream. There is no point in passing a zero length string here and quite a few of that cache_parse() implementations will Oops if count is zero. Signed-off-by: Dan Carpenter Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/cache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 72ad836e4fe0..4530a912b8b0 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -828,6 +828,8 @@ static ssize_t cache_do_downcall(char *kaddr, const char __user *buf, { ssize_t ret; + if (count == 0) + return -EINVAL; if (copy_from_user(kaddr, buf, count)) return -EFAULT; kaddr[count] = '\0'; -- cgit v1.2.3 From 46979bfe3c1c2435f7f8190ff0c0994de3cfc471 Mon Sep 17 00:00:00 2001 From: Yoshii Takashi Date: Wed, 14 Mar 2012 16:14:43 +0900 Subject: serial: sh-sci: fix a race of DMA submit_tx on transfer commit 49d4bcaddca977fffdea8b0b71f6e5da96dac78e upstream. When DMA is enabled, sh-sci transfer begins with uart_start() sci_start_tx() if (cookie_tx < 0) schedule_work() Then, starts DMA when wq scheduled, -- (A) process_one_work() work_fn_rx() cookie_tx = desc->submit_tx() And finishes when DMA transfer ends, -- (B) sci_dma_tx_complete() async_tx_ack() cookie_tx = -EINVAL (possible another schedule_work()) This A to B sequence is not reentrant, since controlling variables (for example, cookie_tx above) are not queues nor lists. So, they must be invoked as A B A B..., otherwise results in kernel crash. To ensure the sequence, sci_start_tx() seems to test if cookie_tx < 0 (represents "not used") to call schedule_work(). But cookie_tx will not be set (to a cookie, also means "used") until in the middle of work queue scheduled function work_fn_tx(). This gap between the test and set allows the breakage of the sequence under the very frequently call of uart_start(). Another gap between async_tx_ack() and another schedule_work() results in the same issue, too. This patch introduces a new condition "cookie_tx == 0" just to mark it is "busy" and assign it within spin-locked region to fill the gaps. Signed-off-by: Takashi Yoshii Reviewed-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index aff9d612dff0..829e51a20eee 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1123,17 +1123,20 @@ static void sci_dma_tx_complete(void *arg) port->icount.tx += sg_dma_len(&s->sg_tx); async_tx_ack(s->desc_tx); - s->cookie_tx = -EINVAL; s->desc_tx = NULL; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (!uart_circ_empty(xmit)) { + s->cookie_tx = 0; schedule_work(&s->work_tx); - } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = sci_in(port, SCSCR); - sci_out(port, SCSCR, ctrl & ~SCSCR_TIE); + } else { + s->cookie_tx = -EINVAL; + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = sci_in(port, SCSCR); + sci_out(port, SCSCR, ctrl & ~SCSCR_TIE); + } } spin_unlock_irqrestore(&port->lock, flags); @@ -1395,8 +1398,10 @@ static void sci_start_tx(struct uart_port *port) } if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && - s->cookie_tx < 0) + s->cookie_tx < 0) { + s->cookie_tx = 0; schedule_work(&s->work_tx); + } #endif if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { -- cgit v1.2.3 From e277a09f64ac659407582c2182b245afa66dcebc Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 27 Mar 2012 10:17:41 -0400 Subject: ASPM: Fix pcie devices with non-pcie children commit c9651e70ad0aa499814817cbf3cc1d0b806ed3a1 upstream. Since 3.2.12 and 3.3, some systems are failing to boot with a BUG_ON. Some other systems using the pata_jmicron driver fail to boot because no disks are detected. Passing pcie_aspm=force on the kernel command line works around it. The cause: commit 4949be16822e ("PCI: ignore pre-1.1 ASPM quirking when ASPM is disabled") changed the behaviour of pcie_aspm_sanity_check() to always return 0 if aspm is disabled, in order to avoid cases where we changed ASPM state on pre-PCIe 1.1 devices. This skipped the secondary function of pcie_aspm_sanity_check which was to avoid us enabling ASPM on devices that had non-PCIe children, causing trouble later on. Move the aspm_disabled check so we continue to honour that scenario. Addresses https://bugzilla.kernel.org/show_bug.cgi?id=42979 and http://bugs.debian.org/665420 Reported-by: Romain Francoise # kernel panic Reported-by: Chris Holland # disk detection trouble Signed-off-by: Matthew Garrett Tested-by: Hatem Masmoudi # Dell Latitude E5520 Tested-by: janek # pata_jmicron with JMB362/JMB363 [jn: with more symptoms in log message] Signed-off-by: Jonathan Nieder Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/aspm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 24f049e73952..22751622568f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -500,9 +500,6 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) int pos; u32 reg32; - if (aspm_disabled) - return 0; - /* * Some functions in a slot might not all be PCIe functions, * very strange. Disable ASPM for the whole slot @@ -511,6 +508,16 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) pos = pci_pcie_cap(child); if (!pos) return -EINVAL; + + /* + * If ASPM is disabled then we're not going to change + * the BIOS state. It's safe to continue even if it's a + * pre-1.1 device + */ + + if (aspm_disabled) + continue; + /* * Disable ASPM for pre-1.1 PCIe device, we follow MS to use * RBER bit to determine if a function is 1.1 version device -- cgit v1.2.3 From 23d8c3f8f494c8516c9b4c05529e118e6a485956 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 2 Apr 2012 09:53:31 -0700 Subject: Linux 3.2.14 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 172e041a4241..afe4c7da42a1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 2 -SUBLEVEL = 13 +SUBLEVEL = 14 EXTRAVERSION = NAME = Saber-toothed Squirrel -- cgit v1.2.3