diff --git a/Makefile b/Makefile
index 63a173e41f22..22c320078a98 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 3
 PATCHLEVEL = 18
-SUBLEVEL = 75
+SUBLEVEL = 76
 EXTRAVERSION =
 NAME = Diseased Newt
 
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index dd3ca375bfdf..a9ca10baf936 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -8904,7 +8904,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
         * (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask();
         */
        vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK);
-       kvm_set_cr4(vcpu, vmcs12->host_cr4);
+       vmx_set_cr4(vcpu, vmcs12->host_cr4);
 
        nested_ept_uninit_mmu_context(vcpu);
 
diff --git a/block/bio.c b/block/bio.c
index 78803e99c154..140c45b2b717 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1338,6 +1338,7 @@ static struct bio *__bio_map_user_iov(struct 
request_queue *q,
                offset = uaddr & ~PAGE_MASK;
                for (j = cur_page; j < page_limit; j++) {
                        unsigned int bytes = PAGE_SIZE - offset;
+                       unsigned short prev_bi_vcnt = bio->bi_vcnt;
 
                        if (len <= 0)
                                break;
@@ -1352,6 +1353,13 @@ static struct bio *__bio_map_user_iov(struct 
request_queue *q,
                                            bytes)
                                break;
 
+                       /*
+                        * check if vector was merged with previous
+                        * drop page reference if needed
+                        */
+                       if (bio->bi_vcnt == prev_bi_vcnt)
+                               put_page(pages[j]);
+
                        len -= bytes;
                        offset = 0;
                }
diff --git a/crypto/shash.c b/crypto/shash.c
index 03fbcd4a82c4..17510eaf0a36 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -274,12 +274,14 @@ static int shash_async_finup(struct ahash_request *req)
 
 int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc)
 {
-       struct scatterlist *sg = req->src;
-       unsigned int offset = sg->offset;
        unsigned int nbytes = req->nbytes;
+       struct scatterlist *sg;
+       unsigned int offset;
        int err;
 
-       if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
+       if (nbytes &&
+           (sg = req->src, offset = sg->offset,
+            nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) {
                void *data;
 
                data = kmap_atomic(sg_page(sg));
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index d3fd973e8776..c96fbb8c8046 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -959,6 +959,8 @@ static int usbhid_parse(struct hid_device *hid)
        unsigned int rsize = 0;
        char *rdesc;
        int ret, n;
+       int num_descriptors;
+       size_t offset = offsetof(struct hid_descriptor, desc);
 
        quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
                        le16_to_cpu(dev->descriptor.idProduct));
@@ -981,10 +983,18 @@ static int usbhid_parse(struct hid_device *hid)
                return -ENODEV;
        }
 
+       if (hdesc->bLength < sizeof(struct hid_descriptor)) {
+               dbg_hid("hid descriptor is too short\n");
+               return -EINVAL;
+       }
+
        hid->version = le16_to_cpu(hdesc->bcdHID);
        hid->country = hdesc->bCountryCode;
 
-       for (n = 0; n < hdesc->bNumDescriptors; n++)
+       num_descriptors = min_t(int, hdesc->bNumDescriptors,
+              (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
+
+       for (n = 0; n < num_descriptors; n++)
                if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
                        rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
 
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index af3daf89c77d..5cf388ad1555 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3381,6 +3381,7 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, 
unsigned long iova,
        mutex_unlock(&domain->api_lock);
 
        domain_flush_tlb_pde(domain);
+       domain_flush_complete(domain);
 
        return unmap_size;
 }
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7b2ba34cf5e7..f24adf48b0cc 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1806,6 +1806,8 @@ static DEVICE_ATTR_RO(suspended);
 static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 {
        struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       struct usb_gadget_strings       *gstr = cdev->driver->strings[0];
+       struct usb_string               *dev_str = gstr->strings;
 
        /* composite_disconnect() must already have been called
         * by the underlying peripheral controller driver!
@@ -1825,6 +1827,9 @@ static void __composite_unbind(struct usb_gadget *gadget, 
bool unbind_driver)
 
        composite_dev_cleanup(cdev);
 
+       if (dev_str[USB_GADGET_MANUFACTURER_IDX].s == cdev->def_manufacturer)
+               dev_str[USB_GADGET_MANUFACTURER_IDX].s = "";
+
        kfree(cdev->def_manufacturer);
        kfree(cdev);
        set_gadget_data(gadget, NULL);
diff --git a/drivers/usb/gadget/legacy/inode.c 
b/drivers/usb/gadget/legacy/inode.c
index 352c59cff5b6..368d07937848 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1231,10 +1231,11 @@ ep0_write (struct file *fd, const char __user *buf, 
size_t len, loff_t *ptr)
                                                dev->gadget->ep0, dev->req,
                                                GFP_KERNEL);
                                }
-                               spin_lock_irq(&dev->lock);
                                --dev->udc_usage;
                                if (retval < 0) {
+                                       spin_lock_irq (&dev->lock);
                                        clean_req (dev->gadget->ep0, dev->req);
+                                       spin_unlock_irq (&dev->lock);
                                } else
                                        retval = len;
 
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 75d9ba91e7c5..a8230472d66c 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -880,9 +880,9 @@ static void xfer_work(struct work_struct *work)
                fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
 
        usbhs_pipe_running(pipe, 1);
-       usbhsf_dma_start(pipe, fifo);
        usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
        dma_async_issue_pending(chan);
+       usbhsf_dma_start(pipe, fifo);
        usbhs_pipe_enable(pipe);
 
 xfer_work_end:
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 29fa1c3d0089..926c1f2dc962 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -187,6 +187,7 @@ static int usb_console_setup(struct console *co, char 
*options)
        tty_kref_put(tty);
  reset_open_count:
        port->port.count = 0;
+       info->port = NULL;
        usb_autopm_put_interface(serial->interface);
  error_get_interface:
        usb_serial_put(serial);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index a8051aad885c..c454c2fec2f7 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -168,6 +168,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
        { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
        { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
+       { USB_DEVICE(0x18EF, 0xE032) }, /* ELV TFD500 Data Logger */
        { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
        { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
        { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index fdd5eff72c31..71d032822cd9 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -515,6 +515,7 @@ static void option_instat_callback(struct urb *urb);
 
 /* TP-LINK Incorporated products */
 #define TPLINK_VENDOR_ID                       0x2357
+#define TPLINK_PRODUCT_LTE                     0x000D
 #define TPLINK_PRODUCT_MA180                   0x0201
 
 /* Changhong products */
@@ -2006,6 +2007,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
        { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
        { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
+       { USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, TPLINK_PRODUCT_LTE, 
0xff, 0x00, 0x00) },      /* TP-Link LTE Module */
        { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000),                                 
/* TP-Link MA260 */
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index ec8d1410fe5a..2a2ff0ba9f7f 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -168,6 +168,10 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x413c, 0x81b3)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE 
Mobile Broadband Card (rev3) */
        {DEVICE_SWI(0x413c, 0x81b5)},   /* Dell Wireless 5811e QDL */
        {DEVICE_SWI(0x413c, 0x81b6)},   /* Dell Wireless 5811e QDL */
+       {DEVICE_SWI(0x413c, 0x81cf)},   /* Dell Wireless 5819 */
+       {DEVICE_SWI(0x413c, 0x81d0)},   /* Dell Wireless 5819 */
+       {DEVICE_SWI(0x413c, 0x81d1)},   /* Dell Wireless 5818 */
+       {DEVICE_SWI(0x413c, 0x81d2)},   /* Dell Wireless 5818 */
 
        /* Huawei devices */
        {DEVICE_HWI(0x03f0, 0x581d)},   /* HP lt4112 LTE/HSPA+ Gobi 4G Modem 
(Huawei me906e) */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 99745da9cd90..0a359af59dd8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -347,6 +347,8 @@ struct smb_version_operations {
        unsigned int (*calc_smb_size)(void *);
        /* check for STATUS_PENDING and process it in a positive case */
        bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
+       /* check for STATUS_NETWORK_SESSION_EXPIRED */
+       bool (*is_session_expired)(char *);
        /* send oplock break response */
        int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
                               struct cifsInodeInfo *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 8e1a17c64ddd..b2218b755dab 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1458,6 +1458,13 @@ cifs_readv_receive(struct TCP_Server_Info *server, 
struct mid_q_entry *mid)
                return length;
        server->total_read += length;
 
+       if (server->ops->is_session_expired &&
+           server->ops->is_session_expired(buf)) {
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return -1;
+       }
+
        if (server->ops->is_status_pending &&
            server->ops->is_status_pending(buf, server, 0)) {
                discard_remaining_data(server);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 43df8c3e026c..43bb9e2c81a5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -839,6 +839,13 @@ standard_receive3(struct TCP_Server_Info *server, struct 
mid_q_entry *mid)
                cifs_dump_mem("Bad SMB: ", buf,
                        min_t(unsigned int, server->total_read, 48));
 
+       if (server->ops->is_session_expired &&
+           server->ops->is_session_expired(buf)) {
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return -1;
+       }
+
        if (server->ops->is_status_pending &&
            server->ops->is_status_pending(buf, server, length))
                return -1;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 881af94ac68f..d23a41652b4c 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -896,6 +896,18 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info 
*server, int length)
        return true;
 }
 
+static bool
+smb2_is_session_expired(char *buf)
+{
+       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+
+       if (hdr->Status != STATUS_NETWORK_SESSION_EXPIRED)
+               return false;
+
+       cifs_dbg(FYI, "Session expired\n");
+       return true;
+}
+
 static int
 smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
                     struct cifsInodeInfo *cinode)
@@ -1424,6 +1436,7 @@ struct smb_version_operations smb20_operations = {
        .close_dir = smb2_close_dir,
        .calc_smb_size = smb2_calc_size,
        .is_status_pending = smb2_is_status_pending,
+       .is_session_expired = smb2_is_session_expired,
        .oplock_response = smb2_oplock_response,
        .queryfs = smb2_queryfs,
        .mand_lock = smb2_mand_lock,
@@ -1505,6 +1518,7 @@ struct smb_version_operations smb21_operations = {
        .close_dir = smb2_close_dir,
        .calc_smb_size = smb2_calc_size,
        .is_status_pending = smb2_is_status_pending,
+       .is_session_expired = smb2_is_session_expired,
        .oplock_response = smb2_oplock_response,
        .queryfs = smb2_queryfs,
        .mand_lock = smb2_mand_lock,
@@ -1587,6 +1601,7 @@ struct smb_version_operations smb30_operations = {
        .close_dir = smb2_close_dir,
        .calc_smb_size = smb2_calc_size,
        .is_status_pending = smb2_is_status_pending,
+       .is_session_expired = smb2_is_session_expired,
        .oplock_response = smb2_oplock_response,
        .queryfs = smb2_queryfs,
        .mand_lock = smb2_mand_lock,
diff --git a/fs/direct-io.c b/fs/direct-io.c
index e181b6b2e297..a325d8c5ec2d 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -812,7 +812,8 @@ out:
         */
        if (sdio->boundary) {
                ret = dio_send_cur_page(dio, sdio, map_bh);
-               dio_bio_submit(dio, sdio);
+               if (sdio->bio)
+                       dio_bio_submit(dio, sdio);
                page_cache_release(sdio->cur_page);
                sdio->cur_page = NULL;
        }
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 9dfb324de119..64623537f3b0 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -399,7 +399,7 @@ static loff_t ext4_seek_data(struct file *file, loff_t 
offset, loff_t maxsize)
        mutex_lock(&inode->i_mutex);
 
        isize = i_size_read(inode);
-       if (offset >= isize) {
+       if (offset < 0 || offset >= isize) {
                mutex_unlock(&inode->i_mutex);
                return -ENXIO;
        }
@@ -472,7 +472,7 @@ static loff_t ext4_seek_hole(struct file *file, loff_t 
offset, loff_t maxsize)
        mutex_lock(&inode->i_mutex);
 
        isize = i_size_read(inode);
-       if (offset >= isize) {
+       if (offset < 0 || offset >= isize) {
                mutex_unlock(&inode->i_mutex);
                return -ENXIO;
        }
diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h
index a03acd0d398a..695257ae64ac 100644
--- a/include/sound/seq_virmidi.h
+++ b/include/sound/seq_virmidi.h
@@ -60,6 +60,7 @@ struct snd_virmidi_dev {
        int port;                       /* created/attached port */
        unsigned int flags;             /* SNDRV_VIRMIDI_* */
        rwlock_t filelist_lock;
+       struct rw_semaphore filelist_sem;
        struct list_head filelist;
 };
 
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 4a240416b830..a3988a4bcfd6 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1260,6 +1260,7 @@ static int snd_seq_ioctl_create_port(struct 
snd_seq_client *client,
        struct snd_seq_client_port *port;
        struct snd_seq_port_info info;
        struct snd_seq_port_callback *callback;
+       int port_idx;
 
        if (copy_from_user(&info, arg, sizeof(info)))
                return -EFAULT;
@@ -1273,7 +1274,9 @@ static int snd_seq_ioctl_create_port(struct 
snd_seq_client *client,
                return -ENOMEM;
 
        if (client->type == USER_CLIENT && info.kernel) {
-               snd_seq_delete_port(client, port->addr.port);
+               port_idx = port->addr.port;
+               snd_seq_port_unlock(port);
+               snd_seq_delete_port(client, port_idx);
                return -EINVAL;
        }
        if (client->type == KERNEL_CLIENT) {
@@ -1295,6 +1298,7 @@ static int snd_seq_ioctl_create_port(struct 
snd_seq_client *client,
 
        snd_seq_set_port_info(port, &info);
        snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
+       snd_seq_port_unlock(port);
 
        if (copy_to_user(arg, &info, sizeof(info)))
                return -EFAULT;
@@ -1966,7 +1970,7 @@ static int snd_seq_ioctl_remove_events(struct 
snd_seq_client *client,
                 * No restrictions so for a user client we can clear
                 * the whole fifo
                 */
-               if (client->type == USER_CLIENT)
+               if (client->type == USER_CLIENT && client->data.user.fifo)
                        snd_seq_fifo_clear(client->data.user.fifo);
        }
 
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 9c1c8d50f593..1ddae911255c 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -122,7 +122,9 @@ static void port_subs_info_init(struct 
snd_seq_port_subs_info *grp)
 }
 
 
-/* create a port, port number is returned (-1 on failure) */
+/* create a port, port number is returned (-1 on failure);
+ * the caller needs to unref the port via snd_seq_port_unlock() appropriately
+ */
 struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
                                                int port)
 {
@@ -151,6 +153,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct 
snd_seq_client *client,
        snd_use_lock_init(&new_port->use_lock);
        port_subs_info_init(&new_port->c_src);
        port_subs_info_init(&new_port->c_dest);
+       snd_use_lock_use(&new_port->use_lock);
 
        num = port >= 0 ? port : 0;
        mutex_lock(&client->ports_mutex);
@@ -165,9 +168,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct 
snd_seq_client *client,
        list_add_tail(&new_port->list, &p->list);
        client->num_ports++;
        new_port->addr.port = num;      /* store the port number in the port */
+       sprintf(new_port->name, "port-%d", num);
        write_unlock_irqrestore(&client->ports_lock, flags);
        mutex_unlock(&client->ports_mutex);
-       sprintf(new_port->name, "port-%d", num);
 
        return new_port;
 }
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 81134e067184..3b126af4a026 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -77,13 +77,17 @@ static void snd_virmidi_init_event(struct snd_virmidi 
*vmidi,
  * decode input event and put to read buffer of each opened file
  */
 static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
-                                        struct snd_seq_event *ev)
+                                        struct snd_seq_event *ev,
+                                        bool atomic)
 {
        struct snd_virmidi *vmidi;
        unsigned char msg[4];
        int len;
 
-       read_lock(&rdev->filelist_lock);
+       if (atomic)
+               read_lock(&rdev->filelist_lock);
+       else
+               down_read(&rdev->filelist_sem);
        list_for_each_entry(vmidi, &rdev->filelist, list) {
                if (!vmidi->trigger)
                        continue;
@@ -97,7 +101,10 @@ static int snd_virmidi_dev_receive_event(struct 
snd_virmidi_dev *rdev,
                                snd_rawmidi_receive(vmidi->substream, msg, len);
                }
        }
-       read_unlock(&rdev->filelist_lock);
+       if (atomic)
+               read_unlock(&rdev->filelist_lock);
+       else
+               up_read(&rdev->filelist_sem);
 
        return 0;
 }
@@ -115,7 +122,7 @@ int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct 
snd_seq_event *ev)
        struct snd_virmidi_dev *rdev;
 
        rdev = rmidi->private_data;
-       return snd_virmidi_dev_receive_event(rdev, ev);
+       return snd_virmidi_dev_receive_event(rdev, ev, true);
 }
 #endif  /*  0  */
 
@@ -130,7 +137,7 @@ static int snd_virmidi_event_input(struct snd_seq_event 
*ev, int direct,
        rdev = private_data;
        if (!(rdev->flags & SNDRV_VIRMIDI_USE))
                return 0; /* ignored */
-       return snd_virmidi_dev_receive_event(rdev, ev);
+       return snd_virmidi_dev_receive_event(rdev, ev, atomic);
 }
 
 /*
@@ -209,7 +216,6 @@ static int snd_virmidi_input_open(struct 
snd_rawmidi_substream *substream)
        struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
        struct snd_virmidi *vmidi;
-       unsigned long flags;
 
        vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
        if (vmidi == NULL)
@@ -223,9 +229,11 @@ static int snd_virmidi_input_open(struct 
snd_rawmidi_substream *substream)
        vmidi->client = rdev->client;
        vmidi->port = rdev->port;       
        runtime->private_data = vmidi;
-       write_lock_irqsave(&rdev->filelist_lock, flags);
+       down_write(&rdev->filelist_sem);
+       write_lock_irq(&rdev->filelist_lock);
        list_add_tail(&vmidi->list, &rdev->filelist);
-       write_unlock_irqrestore(&rdev->filelist_lock, flags);
+       write_unlock_irq(&rdev->filelist_lock);
+       up_write(&rdev->filelist_sem);
        vmidi->rdev = rdev;
        return 0;
 }
@@ -264,9 +272,11 @@ static int snd_virmidi_input_close(struct 
snd_rawmidi_substream *substream)
        struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
        struct snd_virmidi *vmidi = substream->runtime->private_data;
 
+       down_write(&rdev->filelist_sem);
        write_lock_irq(&rdev->filelist_lock);
        list_del(&vmidi->list);
        write_unlock_irq(&rdev->filelist_lock);
+       up_write(&rdev->filelist_sem);
        snd_midi_event_free(vmidi->parser);
        substream->runtime->private_data = NULL;
        kfree(vmidi);
@@ -520,6 +530,7 @@ int snd_virmidi_new(struct snd_card *card, int device, 
struct snd_rawmidi **rrmi
        rdev->rmidi = rmidi;
        rdev->device = device;
        rdev->client = -1;
+       init_rwsem(&rdev->filelist_sem);
        rwlock_init(&rdev->filelist_lock);
        INIT_LIST_HEAD(&rdev->filelist);
        rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index b871ba407e4e..4458190149d1 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -469,10 +469,12 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
 
        err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 
0);
        if (err)
-               return err;
+               goto err_kill_urb;
 
-       if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ))
-               return -ENODEV;
+       if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ)) 
{
+               err = -ENODEV;
+               goto err_kill_urb;
+       }
 
        usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
                   cdev->vendor_name, CAIAQ_USB_STR_LEN);
@@ -507,6 +509,10 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
 
        setup_card(cdev);
        return 0;
+
+ err_kill_urb:
+       usb_kill_urb(&cdev->ep1_in_urb);
+       return err;
 }
 
 static int snd_probe(struct usb_interface *intf,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 1ceeb9e875a4..d0bbc7b32190 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -2157,6 +2157,9 @@ static int parse_audio_unit(struct mixer_build *state, 
int unitid)
 
 static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
 {
+       /* kill pending URBs */
+       snd_usb_mixer_disconnect(&mixer->list);
+
        kfree(mixer->id_elems);
        if (mixer->urb) {
                kfree(mixer->urb->transfer_buffer);
@@ -2493,8 +2496,13 @@ void snd_usb_mixer_disconnect(struct list_head *p)
        struct usb_mixer_interface *mixer;
 
        mixer = list_entry(p, struct usb_mixer_interface, list);
-       usb_kill_urb(mixer->urb);
-       usb_kill_urb(mixer->rc_urb);
+       if (mixer->disconnected)
+               return;
+       if (mixer->urb)
+               usb_kill_urb(mixer->urb);
+       if (mixer->rc_urb)
+               usb_kill_urb(mixer->rc_urb);
+       mixer->disconnected = true;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 73b1f649447b..cdff31de12d4 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -23,6 +23,7 @@ struct usb_mixer_interface {
 
        u8 audigy2nx_leds[3];
        u8 xonar_u1_status;
+       bool disconnected;
 };
 
 #define MAX_CHANNELS   16      /* max logical channels */

Reply via email to