From: Greg Kroah-Hartman Date: Tue, 4 Feb 2014 18:13:29 +0000 (-0800) Subject: 3.12-stable patches X-Git-Tag: v3.4.79~1^2~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=67fcb08acca44c625aa6c4208f7253ce6661eec2;p=thirdparty%2Fkernel%2Fstable-queue.git 3.12-stable patches added patches: hpfs-remember-free-space.patch iscsi-target-pre-allocate-more-tags-to-avoid-ack-starvation.patch scsi-bfa-chinook-quad-port-16g-fc-hba-claim-issue.patch target-iscsi-fix-network-portal-creation-race.patch usb-core-get-config-and-string-descriptors-for-unauthorized-devices.patch virtio-scsi-fix-hotcpu_notifier-use-after-free-with-virtscsi_freeze.patch --- diff --git a/queue-3.12/hpfs-remember-free-space.patch b/queue-3.12/hpfs-remember-free-space.patch new file mode 100644 index 00000000000..9ebb4445164 --- /dev/null +++ b/queue-3.12/hpfs-remember-free-space.patch @@ -0,0 +1,232 @@ +From 2cbe5c76fc5e38e9af4b709593146e4b8272b69e Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Wed, 29 Jan 2014 00:10:44 +0100 +Subject: hpfs: remember free space + +From: Mikulas Patocka + +commit 2cbe5c76fc5e38e9af4b709593146e4b8272b69e upstream. + +Previously, hpfs scanned all bitmaps each time the user asked for free +space using statfs. This patch changes it so that hpfs scans the +bitmaps only once, remembes the free space and on next invocation of +statfs it returns the value instantly. + +New versions of wine are hammering on the statfs syscall very heavily, +making some games unplayable when they're stored on hpfs, with load +times in minutes. + +This should be backported to the stable kernels because it fixes +user-visible problem (excessive level load times in wine). + +Signed-off-by: Mikulas Patocka +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/hpfs/alloc.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- + fs/hpfs/hpfs_fn.h | 2 - + fs/hpfs/super.c | 29 ++++++++++++++++++----- + 3 files changed, 87 insertions(+), 10 deletions(-) + +--- a/fs/hpfs/alloc.c ++++ b/fs/hpfs/alloc.c +@@ -8,6 +8,58 @@ + + #include "hpfs_fn.h" + ++static void hpfs_claim_alloc(struct super_block *s, secno sec) ++{ ++ struct hpfs_sb_info *sbi = hpfs_sb(s); ++ if (sbi->sb_n_free != (unsigned)-1) { ++ if (unlikely(!sbi->sb_n_free)) { ++ hpfs_error(s, "free count underflow, allocating sector %08x", sec); ++ sbi->sb_n_free = -1; ++ return; ++ } ++ sbi->sb_n_free--; ++ } ++} ++ ++static void hpfs_claim_free(struct super_block *s, secno sec) ++{ ++ struct hpfs_sb_info *sbi = hpfs_sb(s); ++ if (sbi->sb_n_free != (unsigned)-1) { ++ if (unlikely(sbi->sb_n_free >= sbi->sb_fs_size)) { ++ hpfs_error(s, "free count overflow, freeing sector %08x", sec); ++ sbi->sb_n_free = -1; ++ return; ++ } ++ sbi->sb_n_free++; ++ } ++} ++ ++static void hpfs_claim_dirband_alloc(struct super_block *s, secno sec) ++{ ++ struct hpfs_sb_info *sbi = hpfs_sb(s); ++ if (sbi->sb_n_free_dnodes != (unsigned)-1) { ++ if (unlikely(!sbi->sb_n_free_dnodes)) { ++ hpfs_error(s, "dirband free count underflow, allocating sector %08x", sec); ++ sbi->sb_n_free_dnodes = -1; ++ return; ++ } ++ sbi->sb_n_free_dnodes--; ++ } ++} ++ ++static void hpfs_claim_dirband_free(struct super_block *s, secno sec) ++{ ++ struct hpfs_sb_info *sbi = hpfs_sb(s); ++ if (sbi->sb_n_free_dnodes != (unsigned)-1) { ++ if (unlikely(sbi->sb_n_free_dnodes >= sbi->sb_dirband_size / 4)) { ++ hpfs_error(s, "dirband free count overflow, freeing sector %08x", sec); ++ sbi->sb_n_free_dnodes = -1; ++ return; ++ } ++ sbi->sb_n_free_dnodes++; ++ } ++} ++ + /* + * Check if a sector is allocated in bitmap + * This is really slow. Turned on only if chk==2 +@@ -203,9 +255,15 @@ secno hpfs_alloc_sector(struct super_blo + } + sec = 0; + ret: ++ if (sec) { ++ i = 0; ++ do ++ hpfs_claim_alloc(s, sec + i); ++ while (unlikely(++i < n)); ++ } + if (sec && f_p) { + for (i = 0; i < forward; i++) { +- if (!hpfs_alloc_if_possible(s, sec + i + 1)) { ++ if (!hpfs_alloc_if_possible(s, sec + n + i)) { + hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i); + sec = 0; + break; +@@ -228,6 +286,7 @@ static secno alloc_in_dirband(struct sup + nr >>= 2; + sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0); + if (!sec) return 0; ++ hpfs_claim_dirband_alloc(s, sec); + return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start; + } + +@@ -242,6 +301,7 @@ int hpfs_alloc_if_possible(struct super_ + bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f))); + hpfs_mark_4buffers_dirty(&qbh); + hpfs_brelse4(&qbh); ++ hpfs_claim_alloc(s, sec); + return 1; + } + hpfs_brelse4(&qbh); +@@ -275,6 +335,7 @@ void hpfs_free_sectors(struct super_bloc + return; + } + bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f)); ++ hpfs_claim_free(s, sec); + if (!--n) { + hpfs_mark_4buffers_dirty(&qbh); + hpfs_brelse4(&qbh); +@@ -359,6 +420,7 @@ void hpfs_free_dnode(struct super_block + bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f)); + hpfs_mark_4buffers_dirty(&qbh); + hpfs_brelse4(&qbh); ++ hpfs_claim_dirband_free(s, dno); + } + } + +@@ -366,7 +428,7 @@ struct dnode *hpfs_alloc_dnode(struct su + dnode_secno *dno, struct quad_buffer_head *qbh) + { + struct dnode *d; +- if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) { ++ if (hpfs_get_free_dnodes(s) > FREE_DNODES_ADD) { + if (!(*dno = alloc_in_dirband(s, near))) + if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL; + } else { +--- a/fs/hpfs/hpfs_fn.h ++++ b/fs/hpfs/hpfs_fn.h +@@ -311,7 +311,7 @@ static inline struct hpfs_sb_info *hpfs_ + __printf(2, 3) + void hpfs_error(struct super_block *, const char *, ...); + int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); +-unsigned hpfs_count_one_bitmap(struct super_block *, secno); ++unsigned hpfs_get_free_dnodes(struct super_block *); + + /* + * local time (HPFS) to GMT (Unix) +--- a/fs/hpfs/super.c ++++ b/fs/hpfs/super.c +@@ -115,7 +115,7 @@ static void hpfs_put_super(struct super_ + kfree(sbi); + } + +-unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) ++static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) + { + struct quad_buffer_head qbh; + unsigned long *bits; +@@ -123,7 +123,7 @@ unsigned hpfs_count_one_bitmap(struct su + + bits = hpfs_map_4sectors(s, secno, &qbh, 0); + if (!bits) +- return 0; ++ return (unsigned)-1; + count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); + hpfs_brelse4(&qbh); + return count; +@@ -138,30 +138,45 @@ static unsigned count_bitmaps(struct sup + hpfs_prefetch_bitmap(s, n); + } + for (n = 0; n < n_bands; n++) { ++ unsigned c; + hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD); +- count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); ++ c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); ++ if (c != (unsigned)-1) ++ count += c; + } + return count; + } + ++unsigned hpfs_get_free_dnodes(struct super_block *s) ++{ ++ struct hpfs_sb_info *sbi = hpfs_sb(s); ++ if (sbi->sb_n_free_dnodes == (unsigned)-1) { ++ unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap); ++ if (c == (unsigned)-1) ++ return 0; ++ sbi->sb_n_free_dnodes = c; ++ } ++ return sbi->sb_n_free_dnodes; ++} ++ + static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) + { + struct super_block *s = dentry->d_sb; + struct hpfs_sb_info *sbi = hpfs_sb(s); + u64 id = huge_encode_dev(s->s_bdev->bd_dev); ++ + hpfs_lock(s); + +- /*if (sbi->sb_n_free == -1) {*/ ++ if (sbi->sb_n_free == (unsigned)-1) + sbi->sb_n_free = count_bitmaps(s); +- sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap); +- /*}*/ ++ + buf->f_type = s->s_magic; + buf->f_bsize = 512; + buf->f_blocks = sbi->sb_fs_size; + buf->f_bfree = sbi->sb_n_free; + buf->f_bavail = sbi->sb_n_free; + buf->f_files = sbi->sb_dirband_size / 4; +- buf->f_ffree = sbi->sb_n_free_dnodes; ++ buf->f_ffree = hpfs_get_free_dnodes(s); + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); + buf->f_namelen = 254; diff --git a/queue-3.12/iscsi-target-pre-allocate-more-tags-to-avoid-ack-starvation.patch b/queue-3.12/iscsi-target-pre-allocate-more-tags-to-avoid-ack-starvation.patch new file mode 100644 index 00000000000..4c1f4c7ac21 --- /dev/null +++ b/queue-3.12/iscsi-target-pre-allocate-more-tags-to-avoid-ack-starvation.patch @@ -0,0 +1,44 @@ +From 4a4caa29f1abcb14377e05d57c0793d338fb945d Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Fri, 10 Jan 2014 02:06:59 +0000 +Subject: iscsi-target: Pre-allocate more tags to avoid ack starvation + +From: Nicholas Bellinger + +commit 4a4caa29f1abcb14377e05d57c0793d338fb945d upstream. + +This patch addresses an traditional iscsi-target fabric ack starvation +issue where iscsit_allocate_cmd() -> percpu_ida_alloc_state() ends up +hitting slow path percpu-ida code, because iscsit_ack_from_expstatsn() +is expected to free ack'ed tags after tag allocation. + +This is done to take into account the tags waiting to be acknowledged +and released in iscsit_ack_from_expstatsn(), but who's number are not +directly limited by the CmdSN Window queue_depth being enforced by +the target. + +So that said, this patch bumps up the pre-allocated number of +per session tags to: + + (max(queue_depth, ISCSIT_MIN_TAGS) * 2) + ISCSIT_EXTRA_TAGS + +for good measure to avoid the percpu_ida_alloc_state() slow path. + +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/iscsi/iscsi_target_nego.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/target/iscsi/iscsi_target_nego.c ++++ b/drivers/target/iscsi/iscsi_target_nego.c +@@ -1192,7 +1192,7 @@ get_target: + */ + alloc_tags: + tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth); +- tag_num += (tag_num / 2) + ISCSIT_EXTRA_TAGS; ++ tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS; + tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; + + ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size); diff --git a/queue-3.12/scsi-bfa-chinook-quad-port-16g-fc-hba-claim-issue.patch b/queue-3.12/scsi-bfa-chinook-quad-port-16g-fc-hba-claim-issue.patch new file mode 100644 index 00000000000..02a6980f19e --- /dev/null +++ b/queue-3.12/scsi-bfa-chinook-quad-port-16g-fc-hba-claim-issue.patch @@ -0,0 +1,54 @@ +From dcaf9aed995c2b2a49fb86bbbcfa2f92c797ab5d Mon Sep 17 00:00:00 2001 +From: Vijaya Mohan Guvva +Date: Wed, 4 Dec 2013 05:43:58 -0800 +Subject: SCSI: bfa: Chinook quad port 16G FC HBA claim issue + +From: Vijaya Mohan Guvva + +commit dcaf9aed995c2b2a49fb86bbbcfa2f92c797ab5d upstream. + +Bfa driver crash is observed while pushing the firmware on to chinook +quad port card due to uninitialized bfi_image_ct2 access which gets +initialized only for CT2 ASIC based cards after request_firmware(). +For quard port chinook (CT2 ASIC based), bfi_image_ct2 is not getting +initialized as there is no check for chinook PCI device ID before +request_firmware and instead bfi_image_cb is initialized as it is the +default case for card type check. + +This patch includes changes to read the right firmware for quad port chinook. + +Signed-off-by: Vijaya Mohan Guvva +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/bfa/bfad.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/bfa/bfad.c ++++ b/drivers/scsi/bfa/bfad.c +@@ -1832,7 +1832,7 @@ out: + static u32 * + bfad_load_fwimg(struct pci_dev *pdev) + { +- if (pdev->device == BFA_PCI_DEVICE_ID_CT2) { ++ if (bfa_asic_id_ct2(pdev->device)) { + if (bfi_image_ct2_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct2, + &bfi_image_ct2_size, BFAD_FW_FILE_CT2); +@@ -1842,12 +1842,14 @@ bfad_load_fwimg(struct pci_dev *pdev) + bfad_read_firmware(pdev, &bfi_image_ct, + &bfi_image_ct_size, BFAD_FW_FILE_CT); + return bfi_image_ct; +- } else { ++ } else if (bfa_asic_id_cb(pdev->device)) { + if (bfi_image_cb_size == 0) + bfad_read_firmware(pdev, &bfi_image_cb, + &bfi_image_cb_size, BFAD_FW_FILE_CB); + return bfi_image_cb; + } ++ ++ return NULL; + } + + static void diff --git a/queue-3.12/series b/queue-3.12/series index 67bbeaf7734..25d47c660cc 100644 --- a/queue-3.12/series +++ b/queue-3.12/series @@ -121,3 +121,9 @@ kvm-ppc-e500-fix-bad-address-type-in-deliver_tlb_misss.patch alsa-hda-don-t-set-indep_hp-flag-for-old-ad-codecs.patch alsa-hda-hdmi-introduce-patch_nvhdmi.patch alsa-hda-hdmi-allow-pin_out-to-be-dynamically-enabled.patch +hpfs-remember-free-space.patch +usb-core-get-config-and-string-descriptors-for-unauthorized-devices.patch +scsi-bfa-chinook-quad-port-16g-fc-hba-claim-issue.patch +virtio-scsi-fix-hotcpu_notifier-use-after-free-with-virtscsi_freeze.patch +iscsi-target-pre-allocate-more-tags-to-avoid-ack-starvation.patch +target-iscsi-fix-network-portal-creation-race.patch diff --git a/queue-3.12/target-iscsi-fix-network-portal-creation-race.patch b/queue-3.12/target-iscsi-fix-network-portal-creation-race.patch new file mode 100644 index 00000000000..048e9ea63c1 --- /dev/null +++ b/queue-3.12/target-iscsi-fix-network-portal-creation-race.patch @@ -0,0 +1,150 @@ +From ee291e63293146db64668e8d65eb35c97e8324f4 Mon Sep 17 00:00:00 2001 +From: Andy Grover +Date: Fri, 24 Jan 2014 16:18:54 -0800 +Subject: target/iscsi: Fix network portal creation race + +From: Andy Grover + +commit ee291e63293146db64668e8d65eb35c97e8324f4 upstream. + +When creating network portals rapidly, such as when restoring a +configuration, LIO's code to reuse existing portals can return a false +negative if the thread hasn't run yet and set np_thread_state to +ISCSI_NP_THREAD_ACTIVE. This causes an error in the network stack +when attempting to bind to the same address/port. + +This patch sets NP_THREAD_ACTIVE before the np is placed on g_np_list, +so even if the thread hasn't run yet, iscsit_get_np will return the +existing np. + +Also, convert np_lock -> np_mutex + hold across adding new net portal +to g_np_list to prevent a race where two threads may attempt to create +the same network portal, resulting in one of them failing. + +(nab: Add missing mutex_unlocks in iscsit_add_np failure paths) +(DanC: Fix incorrect spin_unlock -> spin_unlock_bh) + +Signed-off-by: Andy Grover +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/iscsi/iscsi_target.c | 34 +++++++++++++++++++++------------- + 1 file changed, 21 insertions(+), 13 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -52,7 +52,7 @@ + static LIST_HEAD(g_tiqn_list); + static LIST_HEAD(g_np_list); + static DEFINE_SPINLOCK(tiqn_lock); +-static DEFINE_SPINLOCK(np_lock); ++static DEFINE_MUTEX(np_lock); + + static struct idr tiqn_idr; + struct idr sess_idr; +@@ -307,6 +307,9 @@ bool iscsit_check_np_match( + return false; + } + ++/* ++ * Called with mutex np_lock held ++ */ + static struct iscsi_np *iscsit_get_np( + struct __kernel_sockaddr_storage *sockaddr, + int network_transport) +@@ -314,11 +317,10 @@ static struct iscsi_np *iscsit_get_np( + struct iscsi_np *np; + bool match; + +- spin_lock_bh(&np_lock); + list_for_each_entry(np, &g_np_list, np_list) { +- spin_lock(&np->np_thread_lock); ++ spin_lock_bh(&np->np_thread_lock); + if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { +- spin_unlock(&np->np_thread_lock); ++ spin_unlock_bh(&np->np_thread_lock); + continue; + } + +@@ -330,13 +332,11 @@ static struct iscsi_np *iscsit_get_np( + * while iscsi_tpg_add_network_portal() is called. + */ + np->np_exports++; +- spin_unlock(&np->np_thread_lock); +- spin_unlock_bh(&np_lock); ++ spin_unlock_bh(&np->np_thread_lock); + return np; + } +- spin_unlock(&np->np_thread_lock); ++ spin_unlock_bh(&np->np_thread_lock); + } +- spin_unlock_bh(&np_lock); + + return NULL; + } +@@ -350,16 +350,22 @@ struct iscsi_np *iscsit_add_np( + struct sockaddr_in6 *sock_in6; + struct iscsi_np *np; + int ret; ++ ++ mutex_lock(&np_lock); ++ + /* + * Locate the existing struct iscsi_np if already active.. + */ + np = iscsit_get_np(sockaddr, network_transport); +- if (np) ++ if (np) { ++ mutex_unlock(&np_lock); + return np; ++ } + + np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL); + if (!np) { + pr_err("Unable to allocate memory for struct iscsi_np\n"); ++ mutex_unlock(&np_lock); + return ERR_PTR(-ENOMEM); + } + +@@ -382,6 +388,7 @@ struct iscsi_np *iscsit_add_np( + ret = iscsi_target_setup_login_socket(np, sockaddr); + if (ret != 0) { + kfree(np); ++ mutex_unlock(&np_lock); + return ERR_PTR(ret); + } + +@@ -390,6 +397,7 @@ struct iscsi_np *iscsit_add_np( + pr_err("Unable to create kthread: iscsi_np\n"); + ret = PTR_ERR(np->np_thread); + kfree(np); ++ mutex_unlock(&np_lock); + return ERR_PTR(ret); + } + /* +@@ -400,10 +408,10 @@ struct iscsi_np *iscsit_add_np( + * point because iscsi_np has not been added to g_np_list yet. + */ + np->np_exports = 1; ++ np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; + +- spin_lock_bh(&np_lock); + list_add_tail(&np->np_list, &g_np_list); +- spin_unlock_bh(&np_lock); ++ mutex_unlock(&np_lock); + + pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", + np->np_ip, np->np_port, np->np_transport->name); +@@ -470,9 +478,9 @@ int iscsit_del_np(struct iscsi_np *np) + + np->np_transport->iscsit_free_np(np); + +- spin_lock_bh(&np_lock); ++ mutex_lock(&np_lock); + list_del(&np->np_list); +- spin_unlock_bh(&np_lock); ++ mutex_unlock(&np_lock); + + pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", + np->np_ip, np->np_port, np->np_transport->name); diff --git a/queue-3.12/usb-core-get-config-and-string-descriptors-for-unauthorized-devices.patch b/queue-3.12/usb-core-get-config-and-string-descriptors-for-unauthorized-devices.patch new file mode 100644 index 00000000000..2d82ba5b1f6 --- /dev/null +++ b/queue-3.12/usb-core-get-config-and-string-descriptors-for-unauthorized-devices.patch @@ -0,0 +1,127 @@ +From 83e83ecb79a8225e79bc8e54e9aff3e0e27658a2 Mon Sep 17 00:00:00 2001 +From: Thomas Pugliese +Date: Mon, 9 Dec 2013 13:40:29 -0600 +Subject: usb: core: get config and string descriptors for unauthorized devices + +From: Thomas Pugliese + +commit 83e83ecb79a8225e79bc8e54e9aff3e0e27658a2 upstream. + +There is no need to skip querying the config and string descriptors for +unauthorized WUSB devices when usb_new_device is called. It is allowed +by WUSB spec. The only action that needs to be delayed until +authorization time is the set config. This change allows user mode +tools to see the config and string descriptors earlier in enumeration +which is needed for some WUSB devices to function properly on Android +systems. It also reduces the amount of divergent code paths needed +for WUSB devices. + +Signed-off-by: Thomas Pugliese +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/config.c | 7 ------- + drivers/usb/core/hub.c | 40 +++++++--------------------------------- + 2 files changed, 7 insertions(+), 40 deletions(-) + +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -651,10 +651,6 @@ void usb_destroy_configuration(struct us + * + * hub-only!! ... and only in reset path, or usb_new_device() + * (used by real hubs and virtual root hubs) +- * +- * NOTE: if this is a WUSB device and is not authorized, we skip the +- * whole thing. A non-authorized USB device has no +- * configurations. + */ + int usb_get_configuration(struct usb_device *dev) + { +@@ -666,8 +662,6 @@ int usb_get_configuration(struct usb_dev + struct usb_config_descriptor *desc; + + cfgno = 0; +- if (dev->authorized == 0) /* Not really an error */ +- goto out_not_authorized; + result = -ENOMEM; + if (ncfg > USB_MAXCONFIG) { + dev_warn(ddev, "too many configurations: %d, " +@@ -751,7 +745,6 @@ int usb_get_configuration(struct usb_dev + + err: + kfree(desc); +-out_not_authorized: + dev->descriptor.bNumConfigurations = cfgno; + err2: + if (result == -ENOMEM) +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2242,18 +2242,13 @@ static int usb_enumerate_device(struct u + return err; + } + } +- if (udev->wusb == 1 && udev->authorized == 0) { +- udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- } +- else { +- /* read the standard strings and cache them if present */ +- udev->product = usb_cache_string(udev, udev->descriptor.iProduct); +- udev->manufacturer = usb_cache_string(udev, +- udev->descriptor.iManufacturer); +- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); +- } ++ ++ /* read the standard strings and cache them if present */ ++ udev->product = usb_cache_string(udev, udev->descriptor.iProduct); ++ udev->manufacturer = usb_cache_string(udev, ++ udev->descriptor.iManufacturer); ++ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); ++ + err = usb_enumerate_device_otg(udev); + if (err < 0) + return err; +@@ -2435,16 +2430,6 @@ int usb_deauthorize_device(struct usb_de + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + +- kfree(usb_dev->product); +- usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- kfree(usb_dev->manufacturer); +- usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- kfree(usb_dev->serial); +- usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- +- usb_destroy_configuration(usb_dev); +- usb_dev->descriptor.bNumConfigurations = 0; +- + out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +@@ -2472,17 +2457,7 @@ int usb_authorize_device(struct usb_devi + goto error_device_descriptor; + } + +- kfree(usb_dev->product); +- usb_dev->product = NULL; +- kfree(usb_dev->manufacturer); +- usb_dev->manufacturer = NULL; +- kfree(usb_dev->serial); +- usb_dev->serial = NULL; +- + usb_dev->authorized = 1; +- result = usb_enumerate_device(usb_dev); +- if (result < 0) +- goto error_enumerate; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ +@@ -2498,7 +2473,6 @@ int usb_authorize_device(struct usb_devi + } + dev_info(&usb_dev->dev, "authorized to connect\n"); + +-error_enumerate: + error_device_descriptor: + usb_autosuspend_device(usb_dev); + error_autoresume: diff --git a/queue-3.12/virtio-scsi-fix-hotcpu_notifier-use-after-free-with-virtscsi_freeze.patch b/queue-3.12/virtio-scsi-fix-hotcpu_notifier-use-after-free-with-virtscsi_freeze.patch new file mode 100644 index 00000000000..663871b870b --- /dev/null +++ b/queue-3.12/virtio-scsi-fix-hotcpu_notifier-use-after-free-with-virtscsi_freeze.patch @@ -0,0 +1,58 @@ +From f466f75385369a181409e46da272db3de6f5c5cb Mon Sep 17 00:00:00 2001 +From: Asias He +Date: Thu, 16 Jan 2014 10:18:48 +1030 +Subject: virtio-scsi: Fix hotcpu_notifier use-after-free with virtscsi_freeze + +From: Asias He + +commit f466f75385369a181409e46da272db3de6f5c5cb upstream. + +vqs are freed in virtscsi_freeze but the hotcpu_notifier is not +unregistered. We will have a use-after-free usage when the notifier +callback is called after virtscsi_freeze. + +Fixes: 285e71ea6f3583a85e27cb2b9a7d8c35d4c0d558 +("virtio-scsi: reset virtqueue affinity when doing cpu hotplug") + +Signed-off-by: Asias He +Reviewed-by: Paolo Bonzini +Signed-off-by: Jason Wang +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/virtio_scsi.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/virtio_scsi.c ++++ b/drivers/scsi/virtio_scsi.c +@@ -957,6 +957,10 @@ static void virtscsi_remove(struct virti + #ifdef CONFIG_PM + static int virtscsi_freeze(struct virtio_device *vdev) + { ++ struct Scsi_Host *sh = virtio_scsi_host(vdev); ++ struct virtio_scsi *vscsi = shost_priv(sh); ++ ++ unregister_hotcpu_notifier(&vscsi->nb); + virtscsi_remove_vqs(vdev); + return 0; + } +@@ -965,8 +969,17 @@ static int virtscsi_restore(struct virti + { + struct Scsi_Host *sh = virtio_scsi_host(vdev); + struct virtio_scsi *vscsi = shost_priv(sh); ++ int err; ++ ++ err = virtscsi_init(vdev, vscsi); ++ if (err) ++ return err; ++ ++ err = register_hotcpu_notifier(&vscsi->nb); ++ if (err) ++ vdev->config->del_vqs(vdev); + +- return virtscsi_init(vdev, vscsi); ++ return err; + } + #endif +