commit:     e624fc864e3b04b8f5e32b6a5bd3bb094a537039
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Sat Feb 20 00:06:32 2016 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Sat Feb 20 00:06:32 2016 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=e624fc86

Linux patch 3.10.97

 0000_README              |    4 +
 1096_linux-3.10.97.patch | 2341 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 2345 insertions(+)

diff --git a/0000_README b/0000_README
index 19931f8..f3215a3 100644
--- a/0000_README
+++ b/0000_README
@@ -426,6 +426,10 @@ Patch:  1095_linux-3.10.96.patch
 From:   http://www.kernel.org
 Desc:   Linux 3.10.96
 
+Patch:  1096_linux-3.10.97.patch
+From:   http://www.kernel.org
+Desc:   Linux 3.10.97
+
 Patch:  1500_XATTR_USER_PREFIX.patch
 From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
 Desc:   Support for namespace user.pax.* on tmpfs.

diff --git a/1096_linux-3.10.97.patch b/1096_linux-3.10.97.patch
new file mode 100644
index 0000000..487d76e
--- /dev/null
+++ b/1096_linux-3.10.97.patch
@@ -0,0 +1,2341 @@
+diff --git a/Makefile b/Makefile
+index c88ea5d8d19c..f26470169c70 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 3
+ PATCHLEVEL = 10
+-SUBLEVEL = 96
++SUBLEVEL = 97
+ EXTRAVERSION =
+ NAME = TOSSUG Baby Fish
+ 
+diff --git a/arch/parisc/include/uapi/asm/mman.h 
b/arch/parisc/include/uapi/asm/mman.h
+index 294d251ca7b2..2ae13ce592e8 100644
+--- a/arch/parisc/include/uapi/asm/mman.h
++++ b/arch/parisc/include/uapi/asm/mman.h
+@@ -46,16 +46,6 @@
+ #define MADV_DONTFORK 10              /* don't inherit across fork */
+ #define MADV_DOFORK   11              /* do inherit across fork */
+ 
+-/* The range 12-64 is reserved for page size specification. */
+-#define MADV_4K_PAGES   12              /* Use 4K pages  */
+-#define MADV_16K_PAGES  14              /* Use 16K pages */
+-#define MADV_64K_PAGES  16              /* Use 64K pages */
+-#define MADV_256K_PAGES 18              /* Use 256K pages */
+-#define MADV_1M_PAGES   20              /* Use 1 Megabyte pages */
+-#define MADV_4M_PAGES   22              /* Use 4 Megabyte pages */
+-#define MADV_16M_PAGES  24              /* Use 16 Megabyte pages */
+-#define MADV_64M_PAGES  26              /* Use 64 Megabyte pages */
+-
+ #define MADV_MERGEABLE   65           /* KSM may merge identical pages */
+ #define MADV_UNMERGEABLE 66           /* KSM may not merge identical pages */
+ 
+diff --git a/arch/parisc/include/uapi/asm/siginfo.h 
b/arch/parisc/include/uapi/asm/siginfo.h
+index d7034728f377..1c75565d984b 100644
+--- a/arch/parisc/include/uapi/asm/siginfo.h
++++ b/arch/parisc/include/uapi/asm/siginfo.h
+@@ -1,6 +1,10 @@
+ #ifndef _PARISC_SIGINFO_H
+ #define _PARISC_SIGINFO_H
+ 
++#if defined(__LP64__)
++#define __ARCH_SI_PREAMBLE_SIZE   (4 * sizeof(int))
++#endif
++
+ #include <asm-generic/siginfo.h>
+ 
+ #undef NSIGTRAP
+diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
+index 940188d1942c..ae9aa83854c0 100644
+--- a/arch/parisc/kernel/signal.c
++++ b/arch/parisc/kernel/signal.c
+@@ -449,6 +449,55 @@ handle_signal(unsigned long sig, siginfo_t *info, struct 
k_sigaction *ka,
+               regs->gr[28]);
+ }
+ 
++/*
++ * Check how the syscall number gets loaded into %r20 within
++ * the delay branch in userspace and adjust as needed.
++ */
++
++static void check_syscallno_in_delay_branch(struct pt_regs *regs)
++{
++      u32 opcode, source_reg;
++      u32 __user *uaddr;
++      int err;
++
++      /* Usually we don't have to restore %r20 (the system call number)
++       * because it gets loaded in the delay slot of the branch external
++       * instruction via the ldi instruction.
++       * In some cases a register-to-register copy instruction might have
++       * been used instead, in which case we need to copy the syscall
++       * number into the source register before returning to userspace.
++       */
++
++      /* A syscall is just a branch, so all we have to do is fiddle the
++       * return pointer so that the ble instruction gets executed again.
++       */
++      regs->gr[31] -= 8; /* delayed branching */
++
++      /* Get assembler opcode of code in delay branch */
++      uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4);
++      err = get_user(opcode, uaddr);
++      if (err)
++              return;
++
++      /* Check if delay branch uses "ldi int,%r20" */
++      if ((opcode & 0xffff0000) == 0x34140000)
++              return; /* everything ok, just return */
++
++      /* Check if delay branch uses "nop" */
++      if (opcode == INSN_NOP)
++              return;
++
++      /* Check if delay branch uses "copy %rX,%r20" */
++      if ((opcode & 0xffe0ffff) == 0x08000254) {
++              source_reg = (opcode >> 16) & 31;
++              regs->gr[source_reg] = regs->gr[20];
++              return;
++      }
++
++      pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n",
++              current->comm, task_pid_nr(current), opcode);
++}
++
+ static inline void
+ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+ {
+@@ -471,10 +520,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction 
*ka)
+               }
+               /* fallthrough */
+       case -ERESTARTNOINTR:
+-              /* A syscall is just a branch, so all
+-               * we have to do is fiddle the return pointer.
+-               */
+-              regs->gr[31] -= 8; /* delayed branching */
++              check_syscallno_in_delay_branch(regs);
+               break;
+       }
+ }
+@@ -523,15 +569,9 @@ insert_restart_trampoline(struct pt_regs *regs)
+       }
+       case -ERESTARTNOHAND:
+       case -ERESTARTSYS:
+-      case -ERESTARTNOINTR: {
+-              /* Hooray for delayed branching.  We don't
+-               * have to restore %r20 (the system call
+-               * number) because it gets loaded in the delay
+-               * slot of the branch external instruction.
+-               */
+-              regs->gr[31] -= 8;
++      case -ERESTARTNOINTR:
++              check_syscallno_in_delay_branch(regs);
+               return;
+-      }
+       default:
+               break;
+       }
+diff --git a/arch/sh/include/uapi/asm/unistd_64.h 
b/arch/sh/include/uapi/asm/unistd_64.h
+index e6820c86e8c7..47ebd5b5ed55 100644
+--- a/arch/sh/include/uapi/asm/unistd_64.h
++++ b/arch/sh/include/uapi/asm/unistd_64.h
+@@ -278,7 +278,7 @@
+ #define __NR_fsetxattr                256
+ #define __NR_getxattr         257
+ #define __NR_lgetxattr                258
+-#define __NR_fgetxattr                269
++#define __NR_fgetxattr                259
+ #define __NR_listxattr                260
+ #define __NR_llistxattr               261
+ #define __NR_flistxattr               262
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 6ef6e2ad344e..0ca108f3c840 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -125,6 +125,23 @@ int af_alg_release(struct socket *sock)
+ }
+ EXPORT_SYMBOL_GPL(af_alg_release);
+ 
++void af_alg_release_parent(struct sock *sk)
++{
++      struct alg_sock *ask = alg_sk(sk);
++      bool last;
++
++      sk = ask->parent;
++      ask = alg_sk(sk);
++
++      lock_sock(sk);
++      last = !--ask->refcnt;
++      release_sock(sk);
++
++      if (last)
++              sock_put(sk);
++}
++EXPORT_SYMBOL_GPL(af_alg_release_parent);
++
+ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+ {
+       struct sock *sk = sock->sk;
+@@ -132,6 +149,7 @@ static int alg_bind(struct socket *sock, struct sockaddr 
*uaddr, int addr_len)
+       struct sockaddr_alg *sa = (void *)uaddr;
+       const struct af_alg_type *type;
+       void *private;
++      int err;
+ 
+       if (sock->state == SS_CONNECTED)
+               return -EINVAL;
+@@ -157,16 +175,22 @@ static int alg_bind(struct socket *sock, struct sockaddr 
*uaddr, int addr_len)
+               return PTR_ERR(private);
+       }
+ 
++      err = -EBUSY;
+       lock_sock(sk);
++      if (ask->refcnt)
++              goto unlock;
+ 
+       swap(ask->type, type);
+       swap(ask->private, private);
+ 
++      err = 0;
++
++unlock:
+       release_sock(sk);
+ 
+       alg_do_release(type, private);
+ 
+-      return 0;
++      return err;
+ }
+ 
+ static int alg_setkey(struct sock *sk, char __user *ukey,
+@@ -199,11 +223,15 @@ static int alg_setsockopt(struct socket *sock, int 
level, int optname,
+       struct sock *sk = sock->sk;
+       struct alg_sock *ask = alg_sk(sk);
+       const struct af_alg_type *type;
+-      int err = -ENOPROTOOPT;
++      int err = -EBUSY;
+ 
+       lock_sock(sk);
++      if (ask->refcnt)
++              goto unlock;
++
+       type = ask->type;
+ 
++      err = -ENOPROTOOPT;
+       if (level != SOL_ALG || !type)
+               goto unlock;
+ 
+@@ -247,14 +275,13 @@ int af_alg_accept(struct sock *sk, struct socket 
*newsock)
+       security_sk_clone(sk, sk2);
+ 
+       err = type->accept(ask->private, sk2);
+-      if (err) {
+-              sk_free(sk2);
++      if (err)
+               goto unlock;
+-      }
+ 
+       sk2->sk_family = PF_ALG;
+ 
+-      sock_hold(sk);
++      if (!ask->refcnt++)
++              sock_hold(sk);
+       alg_sk(sk2)->parent = sk;
+       alg_sk(sk2)->type = type;
+ 
+diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
+index 850246206b12..c542c0d88afd 100644
+--- a/crypto/algif_hash.c
++++ b/crypto/algif_hash.c
+@@ -51,7 +51,8 @@ static int hash_sendmsg(struct kiocb *unused, struct socket 
*sock,
+ 
+       lock_sock(sk);
+       if (!ctx->more) {
+-              err = crypto_ahash_init(&ctx->req);
++              err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req),
++                                              &ctx->completion);
+               if (err)
+                       goto unlock;
+       }
+@@ -131,6 +132,7 @@ static ssize_t hash_sendpage(struct socket *sock, struct 
page *page,
+       } else {
+               if (!ctx->more) {
+                       err = crypto_ahash_init(&ctx->req);
++                      err = af_alg_wait_for_completion(err, &ctx->completion);
+                       if (err)
+                               goto unlock;
+               }
+@@ -192,9 +194,14 @@ static int hash_accept(struct socket *sock, struct socket 
*newsock, int flags)
+       struct sock *sk2;
+       struct alg_sock *ask2;
+       struct hash_ctx *ctx2;
++      bool more;
+       int err;
+ 
+-      err = crypto_ahash_export(req, state);
++      lock_sock(sk);
++      more = ctx->more;
++      err = more ? crypto_ahash_export(req, state) : 0;
++      release_sock(sk);
++
+       if (err)
+               return err;
+ 
+@@ -205,7 +212,10 @@ static int hash_accept(struct socket *sock, struct socket 
*newsock, int flags)
+       sk2 = newsock->sk;
+       ask2 = alg_sk(sk2);
+       ctx2 = ask2->private;
+-      ctx2->more = 1;
++      ctx2->more = more;
++
++      if (!more)
++              return err;
+ 
+       err = crypto_ahash_import(&ctx2->req, state);
+       if (err) {
+diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
+index c7666f401381..a3dfc0d83107 100644
+--- a/crypto/crypto_user.c
++++ b/crypto/crypto_user.c
+@@ -477,6 +477,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct 
nlmsghdr *nlh)
+               if (link->dump == NULL)
+                       return -EINVAL;
+ 
++              down_read(&crypto_alg_sem);
+               list_for_each_entry(alg, &crypto_alg_list, cra_list)
+                       dump_alloc += CRYPTO_REPORT_MAXSIZE;
+ 
+@@ -486,8 +487,11 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, 
struct nlmsghdr *nlh)
+                               .done = link->done,
+                               .min_dump_alloc = dump_alloc,
+                       };
+-                      return netlink_dump_start(crypto_nlsk, skb, nlh, &c);
++                      err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
+               }
++              up_read(&crypto_alg_sem);
++
++              return err;
+       }
+ 
+       err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
+diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
+index 9064a2f2760c..cb106934bf1c 100644
+--- a/drivers/ata/ahci.c
++++ b/drivers/ata/ahci.c
+@@ -247,6 +247,26 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+       { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
++      { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index cf5f35877559..d04f5c8dbbdc 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -486,8 +486,8 @@ void ahci_save_initial_config(struct device *dev,
+               }
+       }
+ 
+-      /* fabricate port_map from cap.nr_ports */
+-      if (!port_map) {
++      /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
++      if (!port_map && vers < 0x10300) {
+               port_map = (1 << ahci_nr_ports(cap)) - 1;
+               dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
+ 
+@@ -1244,6 +1244,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, 
int pmp,
+       ata_tf_to_fis(tf, pmp, is_cmd, fis);
+       ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+ 
++      /* set port value for softreset of Port Multiplier */
++      if (pp->fbs_enabled && pp->fbs_last_dev != pmp) {
++              tmp = readl(port_mmio + PORT_FBS);
++              tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
++              tmp |= pmp << PORT_FBS_DEV_OFFSET;
++              writel(tmp, port_mmio + PORT_FBS);
++              pp->fbs_last_dev = pmp;
++      }
++
+       /* issue & wait */
+       writel(1, port_mmio + PORT_CMD_ISSUE);
+ 
+diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
+index a6524c3efdf7..ce854bbd33ef 100644
+--- a/drivers/char/tpm/tpm_ibmvtpm.c
++++ b/drivers/char/tpm/tpm_ibmvtpm.c
+@@ -529,7 +529,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
+                       }
+                       ibmvtpm->rtce_size = be16_to_cpu(crq->len);
+                       ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
+-                                                  GFP_KERNEL);
++                                                  GFP_ATOMIC);
+                       if (!ibmvtpm->rtce_buf) {
+                               dev_err(ibmvtpm->dev, "Failed to allocate 
memory for rtce buffer\n");
+                               return;
+diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
+index de904e6a4ab7..5da58e3899eb 100644
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -490,8 +490,6 @@ static void hid_ctrl(struct urb *urb)
+       struct usbhid_device *usbhid = hid->driver_data;
+       int unplug = 0, status = urb->status;
+ 
+-      spin_lock(&usbhid->lock);
+-
+       switch (status) {
+       case 0:                 /* success */
+               if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+@@ -511,6 +509,8 @@ static void hid_ctrl(struct urb *urb)
+               hid_warn(urb->dev, "ctrl urb status %d received\n", status);
+       }
+ 
++      spin_lock(&usbhid->lock);
++
+       if (unplug) {
+               usbhid->ctrltail = usbhid->ctrlhead;
+       } else {
+diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
+index 0ba21b0f3972..eb7ddb20fd48 100644
+--- a/drivers/md/dm-mpath.c
++++ b/drivers/md/dm-mpath.c
+@@ -1608,11 +1608,8 @@ static int multipath_ioctl(struct dm_target *ti, 
unsigned int cmd,
+       /*
+        * Only pass ioctls through if the device sizes match exactly.
+        */
+-      if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) {
+-              int err = scsi_verify_blk_ioctl(NULL, cmd);
+-              if (err)
+-                      r = err;
+-      }
++      if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
++              r = scsi_verify_blk_ioctl(NULL, cmd);
+ 
+       if (r == -ENOTCONN && !fatal_signal_pending(current))
+               queue_work(kmultipathd, &m->process_queued_ios);
+diff --git a/drivers/md/persistent-data/dm-btree.c 
b/drivers/md/persistent-data/dm-btree.c
+index b53669404cb5..6d7f4d950b8f 100644
+--- a/drivers/md/persistent-data/dm-btree.c
++++ b/drivers/md/persistent-data/dm-btree.c
+@@ -455,8 +455,10 @@ static int btree_split_sibling(struct shadow_spine *s, 
dm_block_t root,
+ 
+       r = insert_at(sizeof(__le64), pn, parent_index + 1,
+                     le64_to_cpu(rn->keys[0]), &location);
+-      if (r)
++      if (r) {
++              unlock_block(s->info, right);
+               return r;
++      }
+ 
+       if (key < le64_to_cpu(rn->keys[0])) {
+               unlock_block(s->info, right);
+diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c 
b/drivers/media/pci/saa7134/saa7134-alsa.c
+index dbcdfbf8aed0..11b0ef3a2858 100644
+--- a/drivers/media/pci/saa7134/saa7134-alsa.c
++++ b/drivers/media/pci/saa7134/saa7134-alsa.c
+@@ -1145,6 +1145,8 @@ static int alsa_device_init(struct saa7134_dev *dev)
+ 
+ static int alsa_device_exit(struct saa7134_dev *dev)
+ {
++      if (!snd_saa7134_cards[dev->nr])
++              return 1;
+ 
+       snd_card_free(snd_saa7134_cards[dev->nr]);
+       snd_saa7134_cards[dev->nr] = NULL;
+@@ -1194,7 +1196,8 @@ static void saa7134_alsa_exit(void)
+       int idx;
+ 
+       for (idx = 0; idx < SNDRV_CARDS; idx++) {
+-              snd_card_free(snd_saa7134_cards[idx]);
++              if (snd_saa7134_cards[idx])
++                      snd_card_free(snd_saa7134_cards[idx]);
+       }
+ 
+       saa7134_dmasound_init = NULL;
+diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c 
b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+index e2b0a0969ebb..35fb8f0cb539 100644
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -264,7 +264,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers 
*kp, struct v4l2_create_
+ 
+ struct v4l2_standard32 {
+       __u32                index;
+-      __u32                id[2]; /* __u64 would get the alignment wrong */
++      compat_u64           id;
+       __u8                 name[24];
+       struct v4l2_fract    frameperiod; /* Frames, not fields */
+       __u32                framelines;
+@@ -284,7 +284,7 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, 
struct v4l2_standard32
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
+               put_user(kp->index, &up->index) ||
+-              copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
++              put_user(kp->id, &up->id) ||
+               copy_to_user(up->name, kp->name, 24) ||
+               copy_to_user(&up->frameperiod, &kp->frameperiod, 
sizeof(kp->frameperiod)) ||
+               put_user(kp->framelines, &up->framelines) ||
+@@ -576,10 +576,10 @@ struct v4l2_input32 {
+       __u32        type;              /*  Type of input */
+       __u32        audioset;          /*  Associated audios (bitfield) */
+       __u32        tuner;             /*  Associated tuner */
+-      v4l2_std_id  std;
++      compat_u64   std;
+       __u32        status;
+       __u32        reserved[4];
+-} __attribute__ ((packed));
++};
+ 
+ /* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+    Otherwise it is identical to the 32-bit version. */
+@@ -719,6 +719,7 @@ static int put_v4l2_ext_controls32(struct 
v4l2_ext_controls *kp, struct v4l2_ext
+ struct v4l2_event32 {
+       __u32                           type;
+       union {
++              compat_s64              value64;
+               __u8                    data[64];
+       } u;
+       __u32                           pending;
+diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
+index fd56f2563201..297fbc59a800 100644
+--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
++++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
+@@ -117,7 +117,8 @@ static void vb2_dc_prepare(void *buf_priv)
+       if (!sgt || buf->db_attach)
+               return;
+ 
+-      dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
++      dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,
++                             buf->dma_dir);
+ }
+ 
+ static void vb2_dc_finish(void *buf_priv)
+@@ -129,7 +130,7 @@ static void vb2_dc_finish(void *buf_priv)
+       if (!sgt || buf->db_attach)
+               return;
+ 
+-      dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
++      dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+ }
+ 
+ /*********************************************/
+diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
+index 301493382cd0..f8013c1d8cd5 100644
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -634,8 +634,10 @@ int add_mtd_partitions(struct mtd_info *master,
+ 
+       for (i = 0; i < nbparts; i++) {
+               slave = allocate_partition(master, parts + i, i, cur_offset);
+-              if (IS_ERR(slave))
++              if (IS_ERR(slave)) {
++                      del_mtd_partitions(master);
+                       return PTR_ERR(slave);
++              }
+ 
+               mutex_lock(&mtd_partitions_mutex);
+               list_add(&slave->list, &mtd_partitions);
+diff --git a/drivers/net/wireless/ti/wlcore/io.h 
b/drivers/net/wireless/ti/wlcore/io.h
+index af7d9f9b3b4d..beed58b0c795 100644
+--- a/drivers/net/wireless/ti/wlcore/io.h
++++ b/drivers/net/wireless/ti/wlcore/io.h
+@@ -203,19 +203,23 @@ static inline int __must_check wlcore_write_reg(struct 
wl1271 *wl, int reg,
+ 
+ static inline void wl1271_power_off(struct wl1271 *wl)
+ {
+-      int ret;
++      int ret = 0;
+ 
+       if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags))
+               return;
+ 
+-      ret = wl->if_ops->power(wl->dev, false);
++      if (wl->if_ops->power)
++              ret = wl->if_ops->power(wl->dev, false);
+       if (!ret)
+               clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+ }
+ 
+ static inline int wl1271_power_on(struct wl1271 *wl)
+ {
+-      int ret = wl->if_ops->power(wl->dev, true);
++      int ret = 0;
++
++      if (wl->if_ops->power)
++              ret = wl->if_ops->power(wl->dev, true);
+       if (ret == 0)
+               set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+ 
+diff --git a/drivers/net/wireless/ti/wlcore/spi.c 
b/drivers/net/wireless/ti/wlcore/spi.c
+index e26447832683..bfb57e671034 100644
+--- a/drivers/net/wireless/ti/wlcore/spi.c
++++ b/drivers/net/wireless/ti/wlcore/spi.c
+@@ -72,7 +72,10 @@
+  */
+ #define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
+ 
+-#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
++/* Maximum number of SPI write chunks */
++#define WSPI_MAX_NUM_OF_CHUNKS \
++      ((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1)
++
+ 
+ struct wl12xx_spi_glue {
+       struct device *dev;
+@@ -270,9 +273,10 @@ static int __must_check wl12xx_spi_raw_write(struct 
device *child, int addr,
+                                            void *buf, size_t len, bool fixed)
+ {
+       struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
+-      struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)];
++      /* SPI write buffers - 2 for each chunk */
++      struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
+       struct spi_message m;
+-      u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
++      u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */
+       u32 *cmd;
+       u32 chunk_len;
+       int i;
+diff --git a/drivers/remoteproc/remoteproc_debugfs.c 
b/drivers/remoteproc/remoteproc_debugfs.c
+index 157a57309601..4ef0dbdcace1 100644
+--- a/drivers/remoteproc/remoteproc_debugfs.c
++++ b/drivers/remoteproc/remoteproc_debugfs.c
+@@ -156,7 +156,7 @@ rproc_recovery_write(struct file *filp, const char __user 
*user_buf,
+       char buf[10];
+       int ret;
+ 
+-      if (count > sizeof(buf))
++      if (count < 1 || count > sizeof(buf))
+               return count;
+ 
+       ret = copy_from_user(buf, user_buf, count);
+diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
+index 380387a47b1d..462af46ceee7 100644
+--- a/drivers/spi/spi-atmel.c
++++ b/drivers/spi/spi-atmel.c
+@@ -594,7 +594,8 @@ static int atmel_spi_next_xfer_dma_submit(struct 
spi_master *master,
+ 
+       *plen = len;
+ 
+-      if (atmel_spi_dma_slave_config(as, &slave_config, 8))
++      if (atmel_spi_dma_slave_config(as, &slave_config,
++                                     xfer->bits_per_word))
+               goto err_exit;
+ 
+       /* Send both scatterlists */
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 7c159634aaae..cc80ab14aa32 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1047,7 +1047,7 @@ struct spi_master *spi_alloc_master(struct device *dev, 
unsigned size)
+       master->bus_num = -1;
+       master->num_chipselect = 1;
+       master->dev.class = &spi_master_class;
+-      master->dev.parent = get_device(dev);
++      master->dev.parent = dev;
+       spi_master_set_devdata(master, &master[1]);
+ 
+       return master;
+diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
+index 2967b6eb4c70..8977eaf24d9f 100644
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -2576,6 +2576,28 @@ static int tiocsetd(struct tty_struct *tty, int __user 
*p)
+ }
+ 
+ /**
++ *    tiocgetd        -       get line discipline
++ *    @tty: tty device
++ *    @p: pointer to user data
++ *
++ *    Retrieves the line discipline id directly from the ldisc.
++ *
++ *    Locking: waits for ldisc reference (in case the line discipline
++ *            is changing or the tty is being hungup)
++ */
++
++static int tiocgetd(struct tty_struct *tty, int __user *p)
++{
++      struct tty_ldisc *ld;
++      int ret;
++
++      ld = tty_ldisc_ref_wait(tty);
++      ret = put_user(ld->ops->num, p);
++      tty_ldisc_deref(ld);
++      return ret;
++}
++
++/**
+  *    send_break      -       performed time break
+  *    @tty: device to break on
+  *    @duration: timeout in mS
+@@ -2789,7 +2811,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, 
unsigned long arg)
+       case TIOCGSID:
+               return tiocgsid(tty, real_tty, p);
+       case TIOCGETD:
+-              return put_user(tty->ldisc->ops->num, (int __user *)p);
++              return tiocgetd(tty, p);
+       case TIOCSETD:
+               return tiocsetd(tty, p);
+       case TIOCVHANGUP:
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 4dc18615cd0f..9dd6fa3a1260 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -4788,6 +4788,9 @@ static int __init xhci_hcd_init(void)
+ {
+       int retval;
+ 
++      if (usb_disabled())
++              return -ENODEV;
++
+       retval = xhci_register_pci();
+       if (retval < 0) {
+               printk(KERN_DEBUG "Problem registering PCI driver.");
+@@ -4816,9 +4819,6 @@ static int __init xhci_hcd_init(void)
+       /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
+       BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+ 
+-      if (usb_disabled())
+-              return -ENODEV;
+-
+       return 0;
+ unreg_pci:
+       xhci_unregister_pci();
+diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
+index 72c14d7d604f..89ba7cfba5bc 100644
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -98,6 +98,7 @@ static const struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
+       { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
+       { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, 
Baby-JTAG */
++      { USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 
Adaptor */
+       { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, 
Baby-LIN */
+       { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
+       { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 514f3117ee2b..4e865664699b 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -840,6 +840,7 @@ static struct usb_device_id id_table_combined [] = {
+       { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
++      { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) },
+       { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
+ 
+       /* Papouch devices based on FTDI chip */
+diff --git a/drivers/usb/serial/ftdi_sio_ids.h 
b/drivers/usb/serial/ftdi_sio_ids.h
+index bfb0ecd98808..3eff1d6a2b17 100644
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -615,6 +615,7 @@
+  */
+ #define RATOC_VENDOR_ID               0x0584
+ #define RATOC_PRODUCT_ID_USB60F       0xb020
++#define RATOC_PRODUCT_ID_SCU18        0xb03a
+ 
+ /*
+  * Infineon Technologies
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index bdbe642e6569..81f6a572f016 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -269,6 +269,8 @@ static void option_instat_callback(struct urb *urb);
+ #define TELIT_PRODUCT_CC864_SINGLE            0x1006
+ #define TELIT_PRODUCT_DE910_DUAL              0x1010
+ #define TELIT_PRODUCT_UE910_V2                        0x1012
++#define TELIT_PRODUCT_LE922_USBCFG0           0x1042
++#define TELIT_PRODUCT_LE922_USBCFG3           0x1043
+ #define TELIT_PRODUCT_LE920                   0x1200
+ #define TELIT_PRODUCT_LE910                   0x1201
+ 
+@@ -623,6 +625,16 @@ static const struct option_blacklist_info 
telit_le920_blacklist = {
+       .reserved = BIT(1) | BIT(5),
+ };
+ 
++static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = {
++      .sendsetup = BIT(2),
++      .reserved = BIT(0) | BIT(1) | BIT(3),
++};
++
++static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = {
++      .sendsetup = BIT(0),
++      .reserved = BIT(1) | BIT(2) | BIT(3),
++};
++
+ static const struct usb_device_id option_ids[] = {
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
+@@ -1168,6 +1180,10 @@ static const struct usb_device_id option_ids[] = {
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
++      { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
++              .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
++      { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3),
++              .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
+               .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
+@@ -1679,7 +1695,7 @@ static const struct usb_device_id option_ids[] = {
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
+               .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+-      { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
++      { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, 
CINTERION_PRODUCT_AHXX, 0xff) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
+               .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, 
+diff --git a/drivers/usb/serial/ti_usb_3410_5052.c 
b/drivers/usb/serial/ti_usb_3410_5052.c
+index 4cc84c0c990d..0a7c68fa5e5e 100644
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -158,7 +158,7 @@ static unsigned int product_5052_count;
+ /* the array dimension is the number of default entries plus */
+ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
+ /* null entry */
+-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
++static struct usb_device_id ti_id_table_3410[16+TI_EXTRA_VID_PID_COUNT+1] = {
+       { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
+       { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
+       { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
+@@ -184,7 +184,7 @@ static struct usb_device_id 
ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
+       { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
+ };
+ 
+-static struct usb_device_id 
ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
++static struct usb_device_id 
ti_id_table_combined[20+2*TI_EXTRA_VID_PID_COUNT+1] = {
+       { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
+       { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
+       { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
+diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
+index 727905de0ba4..605068e6acf2 100644
+--- a/drivers/usb/serial/visor.c
++++ b/drivers/usb/serial/visor.c
+@@ -551,6 +551,11 @@ static int treo_attach(struct usb_serial *serial)
+               (serial->num_interrupt_in == 0))
+               return 0;
+ 
++      if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) {
++              dev_err(&serial->interface->dev, "missing endpoints\n");
++              return -ENODEV;
++      }
++
+       /*
+       * It appears that Treos and Kyoceras want to use the
+       * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
+@@ -604,8 +609,10 @@ static int clie_5_attach(struct usb_serial *serial)
+        */
+ 
+       /* some sanity check */
+-      if (serial->num_ports < 2)
+-              return -1;
++      if (serial->num_bulk_out < 2) {
++              dev_err(&serial->interface->dev, "missing bulk out 
endpoints\n");
++              return -ENODEV;
++      }
+ 
+       /* port 0 now uses the modified endpoint Address */
+       port = serial->port[0];
+diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
+index 618bcc84a09e..948e6f21b594 100644
+--- a/fs/binfmt_elf.c
++++ b/fs/binfmt_elf.c
+@@ -682,16 +682,16 @@ static int load_elf_binary(struct linux_binprm *bprm)
+                        */
+                       would_dump(bprm, interpreter);
+ 
+-                      retval = kernel_read(interpreter, 0, bprm->buf,
+-                                           BINPRM_BUF_SIZE);
+-                      if (retval != BINPRM_BUF_SIZE) {
++                      /* Get the exec headers */
++                      retval = kernel_read(interpreter, 0,
++                                           (void *)&loc->interp_elf_ex,
++                                           sizeof(loc->interp_elf_ex));
++                      if (retval != sizeof(loc->interp_elf_ex)) {
+                               if (retval >= 0)
+                                       retval = -EIO;
+                               goto out_free_dentry;
+                       }
+ 
+-                      /* Get the exec headers */
+-                      loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
+                       break;
+               }
+               elf_ppnt++;
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 2a71466b0115..6f74b8919237 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -26,6 +26,7 @@
+ #include <linux/seqlock.h>
+ #include <linux/mutex.h>
+ #include <linux/timer.h>
++#include <linux/version.h>
+ #include <linux/wait.h>
+ #include <linux/blockgroup_lock.h>
+ #include <linux/percpu_counter.h>
+@@ -728,19 +729,55 @@ struct move_extent {
+       <= (EXT4_GOOD_OLD_INODE_SIZE +                  \
+           (einode)->i_extra_isize))                   \
+ 
++/*
++ * We use an encoding that preserves the times for extra epoch "00":
++ *
++ * extra  msb of                         adjust for signed
++ * epoch  32-bit                         32-bit tv_sec to
++ * bits   time    decoded 64-bit tv_sec  64-bit tv_sec      valid time range
++ * 0 0    1    -0x80000000..-0x00000001  0x000000000 1901-12-13..1969-12-31
++ * 0 0    0    0x000000000..0x07fffffff  0x000000000 1970-01-01..2038-01-19
++ * 0 1    1    0x080000000..0x0ffffffff  0x100000000 2038-01-19..2106-02-07
++ * 0 1    0    0x100000000..0x17fffffff  0x100000000 2106-02-07..2174-02-25
++ * 1 0    1    0x180000000..0x1ffffffff  0x200000000 2174-02-25..2242-03-16
++ * 1 0    0    0x200000000..0x27fffffff  0x200000000 2242-03-16..2310-04-04
++ * 1 1    1    0x280000000..0x2ffffffff  0x300000000 2310-04-04..2378-04-22
++ * 1 1    0    0x300000000..0x37fffffff  0x300000000 2378-04-22..2446-05-10
++ *
++ * Note that previous versions of the kernel on 64-bit systems would
++ * incorrectly use extra epoch bits 1,1 for dates between 1901 and
++ * 1970.  e2fsck will correct this, assuming that it is run on the
++ * affected filesystem before 2242.
++ */
++
+ static inline __le32 ext4_encode_extra_time(struct timespec *time)
+ {
+-       return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
+-                         (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
+-                          ((time->tv_nsec << EXT4_EPOCH_BITS) & 
EXT4_NSEC_MASK));
++      u32 extra = sizeof(time->tv_sec) > 4 ?
++              ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 
0;
++      return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
+ }
+ 
+ static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+ {
+-       if (sizeof(time->tv_sec) > 4)
+-             time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
+-                             << 32;
+-       time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> 
EXT4_EPOCH_BITS;
++      if (unlikely(sizeof(time->tv_sec) > 4 &&
++                      (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
++              /* Handle legacy encoding of pre-1970 dates with epoch
++               * bits 1,1.  We assume that by kernel version 4.20,
++               * everyone will have run fsck over the affected
++               * filesystems to correct the problem.  (This
++               * backwards compatibility may be removed before this
++               * time, at the discretion of the ext4 developers.)
++               */
++              u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK;
++              if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0)
++                      extra_bits = 0;
++              time->tv_sec += extra_bits << 32;
++#else
++              time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 
32;
++#endif
++      }
++      time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> 
EXT4_EPOCH_BITS;
+ }
+ 
+ #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                        \
+diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
+index a69bd74ed390..fa7d2e668c3a 100644
+--- a/fs/ext4/resize.c
++++ b/fs/ext4/resize.c
+@@ -1025,7 +1025,7 @@ exit_free:
+  * do not copy the full number of backups at this time.  The resize
+  * which changed s_groups_count will backup again.
+  */
+-static void update_backups(struct super_block *sb, int blk_off, char *data,
++static void update_backups(struct super_block *sb, sector_t blk_off, char 
*data,
+                          int size, int meta_bg)
+ {
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+@@ -1050,7 +1050,7 @@ static void update_backups(struct super_block *sb, int 
blk_off, char *data,
+               group = ext4_list_backups(sb, &three, &five, &seven);
+               last = sbi->s_groups_count;
+       } else {
+-              group = ext4_meta_bg_first_group(sb, group) + 1;
++              group = ext4_get_group_number(sb, blk_off) + 1;
+               last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2);
+       }
+ 
+diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c
+index e028b8eb1c40..0912b90e05bc 100644
+--- a/fs/fscache/netfs.c
++++ b/fs/fscache/netfs.c
+@@ -45,9 +45,6 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
+       netfs->primary_index->parent            = &fscache_fsdef_index;
+       netfs->primary_index->netfs_data        = netfs;
+ 
+-      atomic_inc(&netfs->primary_index->parent->usage);
+-      atomic_inc(&netfs->primary_index->parent->n_children);
+-
+       spin_lock_init(&netfs->primary_index->lock);
+       INIT_HLIST_HEAD(&netfs->primary_index->backing_objects);
+ 
+@@ -60,6 +57,9 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
+                       goto already_registered;
+       }
+ 
++      atomic_inc(&netfs->primary_index->parent->usage);
++      atomic_inc(&netfs->primary_index->parent->n_children);
++
+       list_add(&netfs->link, &fscache_netfs_list);
+       ret = 0;
+ 
+@@ -70,8 +70,7 @@ already_registered:
+       up_write(&fscache_addremove_sem);
+ 
+       if (ret < 0) {
+-              netfs->primary_index->parent = NULL;
+-              __fscache_cookie_put(netfs->primary_index);
++              kmem_cache_free(fscache_cookie_jar, netfs->primary_index);
+               netfs->primary_index = NULL;
+       }
+ 
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index ec34e11d6854..21b828c713cc 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1936,6 +1936,7 @@ static int journal_unmap_buffer(journal_t *journal, 
struct buffer_head *bh,
+ 
+               if (!buffer_dirty(bh)) {
+                       /* bdflush has written it.  We can drop it now */
++                      __jbd2_journal_remove_checkpoint(jh);
+                       goto zap_buffer;
+               }
+ 
+@@ -1965,6 +1966,7 @@ static int journal_unmap_buffer(journal_t *journal, 
struct buffer_head *bh,
+                               /* The orphan record's transaction has
+                                * committed.  We can cleanse this buffer */
+                               clear_buffer_jbddirty(bh);
++                              __jbd2_journal_remove_checkpoint(jh);
+                               goto zap_buffer;
+                       }
+               }
+diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
+index 2c119d5d04c9..d084200dbc4e 100644
+--- a/fs/ocfs2/dlm/dlmmaster.c
++++ b/fs/ocfs2/dlm/dlmmaster.c
+@@ -2456,6 +2456,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
+       spin_lock(&dlm->master_lock);
+       ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name,
+                                   namelen, target, dlm->node_num);
++      /* get an extra reference on the mle.
++       * otherwise the assert_master from the new
++       * master will destroy this.
++       */
++      dlm_get_mle_inuse(mle);
+       spin_unlock(&dlm->master_lock);
+       spin_unlock(&dlm->spinlock);
+ 
+@@ -2491,6 +2496,7 @@ fail:
+               if (mle_added) {
+                       dlm_mle_detach_hb_events(dlm, mle);
+                       dlm_put_mle(mle);
++                      dlm_put_mle_inuse(mle);
+               } else if (mle) {
+                       kmem_cache_free(dlm_mle_cache, mle);
+                       mle = NULL;
+@@ -2508,17 +2514,6 @@ fail:
+        * ensure that all assert_master work is flushed. */
+       flush_workqueue(dlm->dlm_worker);
+ 
+-      /* get an extra reference on the mle.
+-       * otherwise the assert_master from the new
+-       * master will destroy this.
+-       * also, make sure that all callers of dlm_get_mle
+-       * take both dlm->spinlock and dlm->master_lock */
+-      spin_lock(&dlm->spinlock);
+-      spin_lock(&dlm->master_lock);
+-      dlm_get_mle_inuse(mle);
+-      spin_unlock(&dlm->master_lock);
+-      spin_unlock(&dlm->spinlock);
+-
+       /* notify new node and send all lock state */
+       /* call send_one_lockres with migration flag.
+        * this serves as notice to the target node that a
+@@ -3246,6 +3241,15 @@ top:
+                           mle->new_master != dead_node)
+                               continue;
+ 
++                      if (mle->new_master == dead_node && mle->inuse) {
++                              mlog(ML_NOTICE, "%s: target %u died during "
++                                              "migration from %u, the MLE is "
++                                              "still keep used, ignore it!\n",
++                                              dlm->name, dead_node,
++                                              mle->master);
++                              continue;
++                      }
++
+                       /* If we have reached this point, this mle needs to be
+                        * removed from the list and freed. */
+                       dlm_clean_migration_mle(dlm, mle);
+diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
+index 9bd981cd3142..01c69f24e416 100644
+--- a/fs/ocfs2/dlm/dlmrecovery.c
++++ b/fs/ocfs2/dlm/dlmrecovery.c
+@@ -2326,6 +2326,8 @@ static void dlm_do_local_recovery_cleanup(struct 
dlm_ctxt *dlm, u8 dead_node)
+                                               break;
+                                       }
+                               }
++                              dlm_lockres_clear_refmap_bit(dlm, res,
++                                              dead_node);
+                               spin_unlock(&res->spinlock);
+                               continue;
+                       }
+diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
+index c327d4ee1235..7b3792e5844a 100644
+--- a/fs/sysv/inode.c
++++ b/fs/sysv/inode.c
+@@ -161,14 +161,8 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
+               inode->i_fop = &sysv_dir_operations;
+               inode->i_mapping->a_ops = &sysv_aops;
+       } else if (S_ISLNK(inode->i_mode)) {
+-              if (inode->i_blocks) {
+-                      inode->i_op = &sysv_symlink_inode_operations;
+-                      inode->i_mapping->a_ops = &sysv_aops;
+-              } else {
+-                      inode->i_op = &sysv_fast_symlink_inode_operations;
+-                      nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
+-                              sizeof(SYSV_I(inode)->i_data) - 1);
+-              }
++              inode->i_op = &sysv_symlink_inode_operations;
++              inode->i_mapping->a_ops = &sysv_aops;
+       } else
+               init_special_inode(inode, inode->i_mode, rdev);
+ }
+diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
+index d61c11170213..2f38daaab3d7 100644
+--- a/include/crypto/if_alg.h
++++ b/include/crypto/if_alg.h
+@@ -30,6 +30,8 @@ struct alg_sock {
+ 
+       struct sock *parent;
+ 
++      unsigned int refcnt;
++
+       const struct af_alg_type *type;
+       void *private;
+ };
+@@ -64,6 +66,7 @@ int af_alg_register_type(const struct af_alg_type *type);
+ int af_alg_unregister_type(const struct af_alg_type *type);
+ 
+ int af_alg_release(struct socket *sock);
++void af_alg_release_parent(struct sock *sk);
+ int af_alg_accept(struct sock *sk, struct socket *newsock);
+ 
+ int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len,
+@@ -80,11 +83,6 @@ static inline struct alg_sock *alg_sk(struct sock *sk)
+       return (struct alg_sock *)sk;
+ }
+ 
+-static inline void af_alg_release_parent(struct sock *sk)
+-{
+-      sock_put(alg_sk(sk)->parent);
+-}
+-
+ static inline void af_alg_init_completion(struct af_alg_completion 
*completion)
+ {
+       init_completion(&completion->completion);
+diff --git a/include/linux/signal.h b/include/linux/signal.h
+index 2ac423bdb676..53944e50e421 100644
+--- a/include/linux/signal.h
++++ b/include/linux/signal.h
+@@ -247,7 +247,6 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);
+ extern void set_current_blocked(sigset_t *);
+ extern void __set_current_blocked(const sigset_t *);
+ extern int show_unhandled_signals;
+-extern int sigsuspend(sigset_t *);
+ 
+ struct sigaction {
+ #ifndef __ARCH_HAS_IRIX_SIGACTION
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 2e51bcbea1e3..4d1f7fa3138d 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -3551,7 +3551,7 @@ SYSCALL_DEFINE0(pause)
+ 
+ #endif
+ 
+-int sigsuspend(sigset_t *set)
++static int sigsuspend(sigset_t *set)
+ {
+       current->saved_sigmask = current->blocked;
+       set_current_blocked(set);
+diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
+index 49b582a225b0..b9897e2be404 100644
+--- a/scripts/recordmcount.h
++++ b/scripts/recordmcount.h
+@@ -377,7 +377,7 @@ static void nop_mcount(Elf_Shdr const *const relhdr,
+ 
+               if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
+                       if (make_nop)
+-                              ret = make_nop((void *)ehdr, shdr->sh_offset + 
relp->r_offset);
++                              ret = make_nop((void *)ehdr, 
_w(shdr->sh_offset) + _w(relp->r_offset));
+                       if (warn_on_notrace_sect && !once) {
+                               printf("Section %s has mcount callers being 
ignored\n",
+                                      txtname);
+diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
+index 3fdf998ad057..572f95175e97 100644
+--- a/sound/core/compress_offload.c
++++ b/sound/core/compress_offload.c
+@@ -44,6 +44,13 @@
+ #include <sound/compress_offload.h>
+ #include <sound/compress_driver.h>
+ 
++/* struct snd_compr_codec_caps overflows the ioctl bit size for some
++ * architectures, so we need to disable the relevant ioctls.
++ */
++#if _IOC_SIZEBITS < 14
++#define COMPR_CODEC_CAPS_OVERFLOW
++#endif
++
+ /* TODO:
+  * - add substream support for multiple devices in case of
+  *    SND_DYNAMIC_MINORS is not used
+@@ -427,6 +434,7 @@ out:
+       return retval;
+ }
+ 
++#ifndef COMPR_CODEC_CAPS_OVERFLOW
+ static int
+ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
+ {
+@@ -450,6 +458,7 @@ out:
+       kfree(caps);
+       return retval;
+ }
++#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
+ 
+ /* revisit this with snd_pcm_preallocate_xxx */
+ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
+@@ -791,9 +800,11 @@ static long snd_compr_ioctl(struct file *f, unsigned int 
cmd, unsigned long arg)
+       case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
+               retval = snd_compr_get_caps(stream, arg);
+               break;
++#ifndef COMPR_CODEC_CAPS_OVERFLOW
+       case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
+               retval = snd_compr_get_codec_caps(stream, arg);
+               break;
++#endif
+       case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
+               retval = snd_compr_set_params(stream, arg);
+               break;
+diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
+index 4c1cc51772e6..7417f96cea6e 100644
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -834,7 +834,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
+       return snd_pcm_hw_param_near(substream, params, 
SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
+ }
+ 
+-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
++static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
++                                   bool trylock)
+ {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_hw_params *params, *sparams;
+@@ -848,7 +849,10 @@ static int snd_pcm_oss_change_params(struct 
snd_pcm_substream *substream)
+       struct snd_mask sformat_mask;
+       struct snd_mask mask;
+ 
+-      if (mutex_lock_interruptible(&runtime->oss.params_lock))
++      if (trylock) {
++              if (!(mutex_trylock(&runtime->oss.params_lock)))
++                      return -EAGAIN;
++      } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+               return -EINTR;
+       sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
+       params = kmalloc(sizeof(*params), GFP_KERNEL);
+@@ -1091,7 +1095,7 @@ static int snd_pcm_oss_get_active_substream(struct 
snd_pcm_oss_file *pcm_oss_fil
+               if (asubstream == NULL)
+                       asubstream = substream;
+               if (substream->runtime->oss.params) {
+-                      err = snd_pcm_oss_change_params(substream);
++                      err = snd_pcm_oss_change_params(substream, false);
+                       if (err < 0)
+                               return err;
+               }
+@@ -1130,7 +1134,7 @@ static int snd_pcm_oss_make_ready(struct 
snd_pcm_substream *substream)
+               return 0;
+       runtime = substream->runtime;
+       if (runtime->oss.params) {
+-              err = snd_pcm_oss_change_params(substream);
++              err = snd_pcm_oss_change_params(substream, false);
+               if (err < 0)
+                       return err;
+       }
+@@ -2168,7 +2172,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file 
*pcm_oss_file, int stre
+       runtime = substream->runtime;
+ 
+       if (runtime->oss.params &&
+-          (err = snd_pcm_oss_change_params(substream)) < 0)
++          (err = snd_pcm_oss_change_params(substream, false)) < 0)
+               return err;
+ 
+       info.fragsize = runtime->oss.period_bytes;
+@@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct 
vm_area_struct *area)
+               return -EIO;
+       
+       if (runtime->oss.params) {
+-              if ((err = snd_pcm_oss_change_params(substream)) < 0)
++              /* use mutex_trylock() for params_lock for avoiding a deadlock
++               * between mmap_sem and params_lock taken by
++               * copy_from/to_user() in snd_pcm_oss_write/read()
++               */
++              err = snd_pcm_oss_change_params(substream, true);
++              if (err < 0)
+                       return err;
+       }
+ #ifdef CONFIG_SND_PCM_OSS_PLUGINS
+diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
+index 7b596b5751db..500765f20843 100644
+--- a/sound/core/rawmidi.c
++++ b/sound/core/rawmidi.c
+@@ -934,31 +934,36 @@ static long snd_rawmidi_kernel_read1(struct 
snd_rawmidi_substream *substream,
+       unsigned long flags;
+       long result = 0, count1;
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
++      unsigned long appl_ptr;
+ 
++      spin_lock_irqsave(&runtime->lock, flags);
+       while (count > 0 && runtime->avail) {
+               count1 = runtime->buffer_size - runtime->appl_ptr;
+               if (count1 > count)
+                       count1 = count;
+-              spin_lock_irqsave(&runtime->lock, flags);
+               if (count1 > (int)runtime->avail)
+                       count1 = runtime->avail;
++
++              /* update runtime->appl_ptr before unlocking for userbuf */
++              appl_ptr = runtime->appl_ptr;
++              runtime->appl_ptr += count1;
++              runtime->appl_ptr %= runtime->buffer_size;
++              runtime->avail -= count1;
++
+               if (kernelbuf)
+-                      memcpy(kernelbuf + result, runtime->buffer + 
runtime->appl_ptr, count1);
++                      memcpy(kernelbuf + result, runtime->buffer + appl_ptr, 
count1);
+               if (userbuf) {
+                       spin_unlock_irqrestore(&runtime->lock, flags);
+                       if (copy_to_user(userbuf + result,
+-                                       runtime->buffer + runtime->appl_ptr, 
count1)) {
++                                       runtime->buffer + appl_ptr, count1)) {
+                               return result > 0 ? result : -EFAULT;
+                       }
+                       spin_lock_irqsave(&runtime->lock, flags);
+               }
+-              runtime->appl_ptr += count1;
+-              runtime->appl_ptr %= runtime->buffer_size;
+-              runtime->avail -= count1;
+-              spin_unlock_irqrestore(&runtime->lock, flags);
+               result += count1;
+               count -= count1;
+       }
++      spin_unlock_irqrestore(&runtime->lock, flags);
+       return result;
+ }
+ 
+@@ -1161,8 +1166,9 @@ static long snd_rawmidi_kernel_write1(struct 
snd_rawmidi_substream *substream,
+       unsigned long flags;
+       long count1, result;
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
++      unsigned long appl_ptr;
+ 
+-      if (snd_BUG_ON(!kernelbuf && !userbuf))
++      if (!kernelbuf && !userbuf)
+               return -EINVAL;
+       if (snd_BUG_ON(!runtime->buffer))
+               return -EINVAL;
+@@ -1181,12 +1187,19 @@ static long snd_rawmidi_kernel_write1(struct 
snd_rawmidi_substream *substream,
+                       count1 = count;
+               if (count1 > (long)runtime->avail)
+                       count1 = runtime->avail;
++
++              /* update runtime->appl_ptr before unlocking for userbuf */
++              appl_ptr = runtime->appl_ptr;
++              runtime->appl_ptr += count1;
++              runtime->appl_ptr %= runtime->buffer_size;
++              runtime->avail -= count1;
++
+               if (kernelbuf)
+-                      memcpy(runtime->buffer + runtime->appl_ptr,
++                      memcpy(runtime->buffer + appl_ptr,
+                              kernelbuf + result, count1);
+               else if (userbuf) {
+                       spin_unlock_irqrestore(&runtime->lock, flags);
+-                      if (copy_from_user(runtime->buffer + runtime->appl_ptr,
++                      if (copy_from_user(runtime->buffer + appl_ptr,
+                                          userbuf + result, count1)) {
+                               spin_lock_irqsave(&runtime->lock, flags);
+                               result = result > 0 ? result : -EFAULT;
+@@ -1194,9 +1207,6 @@ static long snd_rawmidi_kernel_write1(struct 
snd_rawmidi_substream *substream,
+                       }
+                       spin_lock_irqsave(&runtime->lock, flags);
+               }
+-              runtime->appl_ptr += count1;
+-              runtime->appl_ptr %= runtime->buffer_size;
+-              runtime->avail -= count1;
+               result += count1;
+               count -= count1;
+       }
+diff --git a/sound/core/seq/oss/seq_oss_synth.c 
b/sound/core/seq/oss/seq_oss_synth.c
+index c5b773a1eea9..4a09c3085ca4 100644
+--- a/sound/core/seq/oss/seq_oss_synth.c
++++ b/sound/core/seq/oss/seq_oss_synth.c
+@@ -310,7 +310,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
+       struct seq_oss_synth *rec;
+       struct seq_oss_synthinfo *info;
+ 
+-      if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
++      if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
+               return;
+       for (i = 0; i < dp->max_synthdev; i++) {
+               info = &dp->synths[i];
+diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
+index ecfbf5f39d38..08865dcbf5f1 100644
+--- a/sound/core/seq/seq_clientmgr.c
++++ b/sound/core/seq/seq_clientmgr.c
+@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client 
*client,
+       else
+               down_read(&grp->list_mutex);
+       list_for_each_entry(subs, &grp->list_head, src_list) {
++              /* both ports ready? */
++              if (atomic_read(&subs->ref_count) != 2)
++                      continue;
+               event->dest = subs->info.dest;
+               if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
+                       /* convert time according to flag with subscription */
+diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
+index 9516e5ce3aad..67c91d226552 100644
+--- a/sound/core/seq/seq_ports.c
++++ b/sound/core/seq/seq_ports.c
+@@ -175,10 +175,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct 
snd_seq_client *client,
+ }
+ 
+ /* */
+-enum group_type {
+-      SRC_LIST, DEST_LIST
+-};
+-
+ static int subscribe_port(struct snd_seq_client *client,
+                         struct snd_seq_client_port *port,
+                         struct snd_seq_port_subs_info *grp,
+@@ -205,6 +201,20 @@ static struct snd_seq_client_port *get_client_port(struct 
snd_seq_addr *addr,
+       return NULL;
+ }
+ 
++static void delete_and_unsubscribe_port(struct snd_seq_client *client,
++                                      struct snd_seq_client_port *port,
++                                      struct snd_seq_subscribers *subs,
++                                      bool is_src, bool ack);
++
++static inline struct snd_seq_subscribers *
++get_subscriber(struct list_head *p, bool is_src)
++{
++      if (is_src)
++              return list_entry(p, struct snd_seq_subscribers, src_list);
++      else
++              return list_entry(p, struct snd_seq_subscribers, dest_list);
++}
++
+ /*
+  * remove all subscribers on the list
+  * this is called from port_delete, for each src and dest list.
+@@ -212,7 +222,7 @@ static struct snd_seq_client_port *get_client_port(struct 
snd_seq_addr *addr,
+ static void clear_subscriber_list(struct snd_seq_client *client,
+                                 struct snd_seq_client_port *port,
+                                 struct snd_seq_port_subs_info *grp,
+-                                int grptype)
++                                int is_src)
+ {
+       struct list_head *p, *n;
+ 
+@@ -221,15 +231,13 @@ static void clear_subscriber_list(struct snd_seq_client 
*client,
+               struct snd_seq_client *c;
+               struct snd_seq_client_port *aport;
+ 
+-              if (grptype == SRC_LIST) {
+-                      subs = list_entry(p, struct snd_seq_subscribers, 
src_list);
++              subs = get_subscriber(p, is_src);
++              if (is_src)
+                       aport = get_client_port(&subs->info.dest, &c);
+-              } else {
+-                      subs = list_entry(p, struct snd_seq_subscribers, 
dest_list);
++              else
+                       aport = get_client_port(&subs->info.sender, &c);
+-              }
+-              list_del(p);
+-              unsubscribe_port(client, port, grp, &subs->info, 0);
++              delete_and_unsubscribe_port(client, port, subs, is_src, false);
++
+               if (!aport) {
+                       /* looks like the connected port is being deleted.
+                        * we decrease the counter, and when both ports are 
deleted
+@@ -237,21 +245,14 @@ static void clear_subscriber_list(struct snd_seq_client 
*client,
+                        */
+                       if (atomic_dec_and_test(&subs->ref_count))
+                               kfree(subs);
+-              } else {
+-                      /* ok we got the connected port */
+-                      struct snd_seq_port_subs_info *agrp;
+-                      agrp = (grptype == SRC_LIST) ? &aport->c_dest : 
&aport->c_src;
+-                      down_write(&agrp->list_mutex);
+-                      if (grptype == SRC_LIST)
+-                              list_del(&subs->dest_list);
+-                      else
+-                              list_del(&subs->src_list);
+-                      up_write(&agrp->list_mutex);
+-                      unsubscribe_port(c, aport, agrp, &subs->info, 1);
+-                      kfree(subs);
+-                      snd_seq_port_unlock(aport);
+-                      snd_seq_client_unlock(c);
++                      continue;
+               }
++
++              /* ok we got the connected port */
++              delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
++              kfree(subs);
++              snd_seq_port_unlock(aport);
++              snd_seq_client_unlock(c);
+       }
+ }
+ 
+@@ -264,8 +265,8 @@ static int port_delete(struct snd_seq_client *client,
+       snd_use_lock_sync(&port->use_lock); 
+ 
+       /* clear subscribers info */
+-      clear_subscriber_list(client, port, &port->c_src, SRC_LIST);
+-      clear_subscriber_list(client, port, &port->c_dest, DEST_LIST);
++      clear_subscriber_list(client, port, &port->c_src, true);
++      clear_subscriber_list(client, port, &port->c_dest, false);
+ 
+       if (port->private_free)
+               port->private_free(port->private_data);
+@@ -484,85 +485,120 @@ static int match_subs_info(struct 
snd_seq_port_subscribe *r,
+       return 0;
+ }
+ 
+-
+-/* connect two ports */
+-int snd_seq_port_connect(struct snd_seq_client *connector,
+-                       struct snd_seq_client *src_client,
+-                       struct snd_seq_client_port *src_port,
+-                       struct snd_seq_client *dest_client,
+-                       struct snd_seq_client_port *dest_port,
+-                       struct snd_seq_port_subscribe *info)
++static int check_and_subscribe_port(struct snd_seq_client *client,
++                                  struct snd_seq_client_port *port,
++                                  struct snd_seq_subscribers *subs,
++                                  bool is_src, bool exclusive, bool ack)
+ {
+-      struct snd_seq_port_subs_info *src = &src_port->c_src;
+-      struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
+-      struct snd_seq_subscribers *subs, *s;
+-      int err, src_called = 0;
+-      unsigned long flags;
+-      int exclusive;
++      struct snd_seq_port_subs_info *grp;
++      struct list_head *p;
++      struct snd_seq_subscribers *s;
++      int err;
+ 
+-      subs = kzalloc(sizeof(*subs), GFP_KERNEL);
+-      if (! subs)
+-              return -ENOMEM;
+-
+-      subs->info = *info;
+-      atomic_set(&subs->ref_count, 2);
+-
+-      down_write(&src->list_mutex);
+-      down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
+-
+-      exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0;
++      grp = is_src ? &port->c_src : &port->c_dest;
+       err = -EBUSY;
++      down_write(&grp->list_mutex);
+       if (exclusive) {
+-              if (! list_empty(&src->list_head) || ! 
list_empty(&dest->list_head))
++              if (!list_empty(&grp->list_head))
+                       goto __error;
+       } else {
+-              if (src->exclusive || dest->exclusive)
++              if (grp->exclusive)
+                       goto __error;
+               /* check whether already exists */
+-              list_for_each_entry(s, &src->list_head, src_list) {
+-                      if (match_subs_info(info, &s->info))
+-                              goto __error;
+-              }
+-              list_for_each_entry(s, &dest->list_head, dest_list) {
+-                      if (match_subs_info(info, &s->info))
++              list_for_each(p, &grp->list_head) {
++                      s = get_subscriber(p, is_src);
++                      if (match_subs_info(&subs->info, &s->info))
+                               goto __error;
+               }
+       }
+ 
+-      if ((err = subscribe_port(src_client, src_port, src, info,
+-                                connector->number != src_client->number)) < 0)
+-              goto __error;
+-      src_called = 1;
+-
+-      if ((err = subscribe_port(dest_client, dest_port, dest, info,
+-                                connector->number != dest_client->number)) < 
0)
++      err = subscribe_port(client, port, grp, &subs->info, ack);
++      if (err < 0) {
++              grp->exclusive = 0;
+               goto __error;
++      }
+ 
+       /* add to list */
+-      write_lock_irqsave(&src->list_lock, flags);
+-      // write_lock(&dest->list_lock); // no other lock yet
+-      list_add_tail(&subs->src_list, &src->list_head);
+-      list_add_tail(&subs->dest_list, &dest->list_head);
+-      // write_unlock(&dest->list_lock); // no other lock yet
+-      write_unlock_irqrestore(&src->list_lock, flags);
++      write_lock_irq(&grp->list_lock);
++      if (is_src)
++              list_add_tail(&subs->src_list, &grp->list_head);
++      else
++              list_add_tail(&subs->dest_list, &grp->list_head);
++      grp->exclusive = exclusive;
++      atomic_inc(&subs->ref_count);
++      write_unlock_irq(&grp->list_lock);
++      err = 0;
++
++ __error:
++      up_write(&grp->list_mutex);
++      return err;
++}
+ 
+-      src->exclusive = dest->exclusive = exclusive;
++static void delete_and_unsubscribe_port(struct snd_seq_client *client,
++                                      struct snd_seq_client_port *port,
++                                      struct snd_seq_subscribers *subs,
++                                      bool is_src, bool ack)
++{
++      struct snd_seq_port_subs_info *grp;
++
++      grp = is_src ? &port->c_src : &port->c_dest;
++      down_write(&grp->list_mutex);
++      write_lock_irq(&grp->list_lock);
++      if (is_src)
++              list_del(&subs->src_list);
++      else
++              list_del(&subs->dest_list);
++      grp->exclusive = 0;
++      write_unlock_irq(&grp->list_lock);
++      up_write(&grp->list_mutex);
++
++      unsubscribe_port(client, port, grp, &subs->info, ack);
++}
++
++/* connect two ports */
++int snd_seq_port_connect(struct snd_seq_client *connector,
++                       struct snd_seq_client *src_client,
++                       struct snd_seq_client_port *src_port,
++                       struct snd_seq_client *dest_client,
++                       struct snd_seq_client_port *dest_port,
++                       struct snd_seq_port_subscribe *info)
++{
++      struct snd_seq_subscribers *subs;
++      bool exclusive;
++      int err;
++
++      subs = kzalloc(sizeof(*subs), GFP_KERNEL);
++      if (!subs)
++              return -ENOMEM;
++
++      subs->info = *info;
++      atomic_set(&subs->ref_count, 0);
++      INIT_LIST_HEAD(&subs->src_list);
++      INIT_LIST_HEAD(&subs->dest_list);
++
++      exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE);
++
++      err = check_and_subscribe_port(src_client, src_port, subs, true,
++                                     exclusive,
++                                     connector->number != src_client->number);
++      if (err < 0)
++              goto error;
++      err = check_and_subscribe_port(dest_client, dest_port, subs, false,
++                                     exclusive,
++                                     connector->number != 
dest_client->number);
++      if (err < 0)
++              goto error_dest;
+ 
+-      up_write(&dest->list_mutex);
+-      up_write(&src->list_mutex);
+       return 0;
+ 
+- __error:
+-      if (src_called)
+-              unsubscribe_port(src_client, src_port, src, info,
+-                               connector->number != src_client->number);
++ error_dest:
++      delete_and_unsubscribe_port(src_client, src_port, subs, true,
++                                  connector->number != src_client->number);
++ error:
+       kfree(subs);
+-      up_write(&dest->list_mutex);
+-      up_write(&src->list_mutex);
+       return err;
+ }
+ 
+-
+ /* remove the connection */
+ int snd_seq_port_disconnect(struct snd_seq_client *connector,
+                           struct snd_seq_client *src_client,
+@@ -572,37 +608,28 @@ int snd_seq_port_disconnect(struct snd_seq_client 
*connector,
+                           struct snd_seq_port_subscribe *info)
+ {
+       struct snd_seq_port_subs_info *src = &src_port->c_src;
+-      struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
+       struct snd_seq_subscribers *subs;
+       int err = -ENOENT;
+-      unsigned long flags;
+ 
+       down_write(&src->list_mutex);
+-      down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
+-
+       /* look for the connection */
+       list_for_each_entry(subs, &src->list_head, src_list) {
+               if (match_subs_info(info, &subs->info)) {
+-                      write_lock_irqsave(&src->list_lock, flags);
+-                      // write_lock(&dest->list_lock);  // no lock yet
+-                      list_del(&subs->src_list);
+-                      list_del(&subs->dest_list);
+-                      // write_unlock(&dest->list_lock);
+-                      write_unlock_irqrestore(&src->list_lock, flags);
+-                      src->exclusive = dest->exclusive = 0;
+-                      unsubscribe_port(src_client, src_port, src, info,
+-                                       connector->number != 
src_client->number);
+-                      unsubscribe_port(dest_client, dest_port, dest, info,
+-                                       connector->number != 
dest_client->number);
+-                      kfree(subs);
++                      atomic_dec(&subs->ref_count); /* mark as not ready */
+                       err = 0;
+                       break;
+               }
+       }
+-
+-      up_write(&dest->list_mutex);
+       up_write(&src->list_mutex);
+-      return err;
++      if (err < 0)
++              return err;
++
++      delete_and_unsubscribe_port(src_client, src_port, subs, true,
++                                  connector->number != src_client->number);
++      delete_and_unsubscribe_port(dest_client, dest_port, subs, false,
++                                  connector->number != dest_client->number);
++      kfree(subs);
++      return 0;
+ }
+ 
+ 
+diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
+index 24d44b2f61ac..6ec30a98a92a 100644
+--- a/sound/core/seq/seq_timer.c
++++ b/sound/core/seq/seq_timer.c
+@@ -92,6 +92,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
+ 
+ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
+ {
++      unsigned long flags;
++
++      spin_lock_irqsave(&tmr->lock, flags);
+       /* setup defaults */
+       tmr->ppq = 96;          /* 96 PPQ */
+       tmr->tempo = 500000;    /* 120 BPM */
+@@ -107,21 +110,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
+       tmr->preferred_resolution = seq_default_timer_resolution;
+ 
+       tmr->skew = tmr->skew_base = SKEW_BASE;
++      spin_unlock_irqrestore(&tmr->lock, flags);
+ }
+ 
+-void snd_seq_timer_reset(struct snd_seq_timer * tmr)
++static void seq_timer_reset(struct snd_seq_timer *tmr)
+ {
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&tmr->lock, flags);
+-
+       /* reset time & songposition */
+       tmr->cur_time.tv_sec = 0;
+       tmr->cur_time.tv_nsec = 0;
+ 
+       tmr->tick.cur_tick = 0;
+       tmr->tick.fraction = 0;
++}
++
++void snd_seq_timer_reset(struct snd_seq_timer *tmr)
++{
++      unsigned long flags;
+ 
++      spin_lock_irqsave(&tmr->lock, flags);
++      seq_timer_reset(tmr);
+       spin_unlock_irqrestore(&tmr->lock, flags);
+ }
+ 
+@@ -140,8 +147,11 @@ static void snd_seq_timer_interrupt(struct 
snd_timer_instance *timeri,
+       tmr = q->timer;
+       if (tmr == NULL)
+               return;
+-      if (!tmr->running)
++      spin_lock_irqsave(&tmr->lock, flags);
++      if (!tmr->running) {
++              spin_unlock_irqrestore(&tmr->lock, flags);
+               return;
++      }
+ 
+       resolution *= ticks;
+       if (tmr->skew != tmr->skew_base) {
+@@ -150,8 +160,6 @@ static void snd_seq_timer_interrupt(struct 
snd_timer_instance *timeri,
+                       (((resolution & 0xffff) * tmr->skew) >> 16);
+       }
+ 
+-      spin_lock_irqsave(&tmr->lock, flags);
+-
+       /* update timer */
+       snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
+ 
+@@ -298,26 +306,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
+       t->callback = snd_seq_timer_interrupt;
+       t->callback_data = q;
+       t->flags |= SNDRV_TIMER_IFLG_AUTO;
++      spin_lock_irq(&tmr->lock);
+       tmr->timeri = t;
++      spin_unlock_irq(&tmr->lock);
+       return 0;
+ }
+ 
+ int snd_seq_timer_close(struct snd_seq_queue *q)
+ {
+       struct snd_seq_timer *tmr;
++      struct snd_timer_instance *t;
+       
+       tmr = q->timer;
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
+-      if (tmr->timeri) {
+-              snd_timer_stop(tmr->timeri);
+-              snd_timer_close(tmr->timeri);
+-              tmr->timeri = NULL;
+-      }
++      spin_lock_irq(&tmr->lock);
++      t = tmr->timeri;
++      tmr->timeri = NULL;
++      spin_unlock_irq(&tmr->lock);
++      if (t)
++              snd_timer_close(t);
+       return 0;
+ }
+ 
+-int snd_seq_timer_stop(struct snd_seq_timer * tmr)
++static int seq_timer_stop(struct snd_seq_timer *tmr)
+ {
+       if (! tmr->timeri)
+               return -EINVAL;
+@@ -328,6 +340,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr)
+       return 0;
+ }
+ 
++int snd_seq_timer_stop(struct snd_seq_timer *tmr)
++{
++      unsigned long flags;
++      int err;
++
++      spin_lock_irqsave(&tmr->lock, flags);
++      err = seq_timer_stop(tmr);
++      spin_unlock_irqrestore(&tmr->lock, flags);
++      return err;
++}
++
+ static int initialize_timer(struct snd_seq_timer *tmr)
+ {
+       struct snd_timer *t;
+@@ -360,13 +383,13 @@ static int initialize_timer(struct snd_seq_timer *tmr)
+       return 0;
+ }
+ 
+-int snd_seq_timer_start(struct snd_seq_timer * tmr)
++static int seq_timer_start(struct snd_seq_timer *tmr)
+ {
+       if (! tmr->timeri)
+               return -EINVAL;
+       if (tmr->running)
+-              snd_seq_timer_stop(tmr);
+-      snd_seq_timer_reset(tmr);
++              seq_timer_stop(tmr);
++      seq_timer_reset(tmr);
+       if (initialize_timer(tmr) < 0)
+               return -EINVAL;
+       snd_timer_start(tmr->timeri, tmr->ticks);
+@@ -375,14 +398,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr)
+       return 0;
+ }
+ 
+-int snd_seq_timer_continue(struct snd_seq_timer * tmr)
++int snd_seq_timer_start(struct snd_seq_timer *tmr)
++{
++      unsigned long flags;
++      int err;
++
++      spin_lock_irqsave(&tmr->lock, flags);
++      err = seq_timer_start(tmr);
++      spin_unlock_irqrestore(&tmr->lock, flags);
++      return err;
++}
++
++static int seq_timer_continue(struct snd_seq_timer *tmr)
+ {
+       if (! tmr->timeri)
+               return -EINVAL;
+       if (tmr->running)
+               return -EBUSY;
+       if (! tmr->initialized) {
+-              snd_seq_timer_reset(tmr);
++              seq_timer_reset(tmr);
+               if (initialize_timer(tmr) < 0)
+                       return -EINVAL;
+       }
+@@ -392,11 +426,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr)
+       return 0;
+ }
+ 
++int snd_seq_timer_continue(struct snd_seq_timer *tmr)
++{
++      unsigned long flags;
++      int err;
++
++      spin_lock_irqsave(&tmr->lock, flags);
++      err = seq_timer_continue(tmr);
++      spin_unlock_irqrestore(&tmr->lock, flags);
++      return err;
++}
++
+ /* return current 'real' time. use timeofday() to get better granularity. */
+ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
+ {
+       snd_seq_real_time_t cur_time;
++      unsigned long flags;
+ 
++      spin_lock_irqsave(&tmr->lock, flags);
+       cur_time = tmr->cur_time;
+       if (tmr->running) { 
+               struct timeval tm;
+@@ -412,7 +459,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct 
snd_seq_timer *tmr)
+               }
+               snd_seq_sanity_real_time(&cur_time);
+       }
+-                
++      spin_unlock_irqrestore(&tmr->lock, flags);
+       return cur_time;        
+ }
+ 
+diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
+index 4b50e604276d..0fa691e01384 100644
+--- a/sound/core/seq/seq_virmidi.c
++++ b/sound/core/seq/seq_virmidi.c
+@@ -254,9 +254,13 @@ static int snd_virmidi_output_open(struct 
snd_rawmidi_substream *substream)
+  */
+ 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;
+-      snd_midi_event_free(vmidi->parser);
++
++      write_lock_irq(&rdev->filelist_lock);
+       list_del(&vmidi->list);
++      write_unlock_irq(&rdev->filelist_lock);
++      snd_midi_event_free(vmidi->parser);
+       substream->runtime->private_data = NULL;
+       kfree(vmidi);
+       return 0;
+diff --git a/sound/core/timer.c b/sound/core/timer.c
+index 4e436fe53afa..d90d8f4b85fe 100644
+--- a/sound/core/timer.c
++++ b/sound/core/timer.c
+@@ -300,8 +300,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
+       return 0;
+ }
+ 
+-static int _snd_timer_stop(struct snd_timer_instance *timeri,
+-                         int keep_flag, int event);
++static int _snd_timer_stop(struct snd_timer_instance *timeri, int event);
+ 
+ /*
+  * close a timer instance
+@@ -343,7 +342,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
+               spin_unlock_irq(&timer->lock);
+               mutex_lock(&register_mutex);
+               list_del(&timeri->open_list);
+-              if (timer && list_empty(&timer->open_list_head) &&
++              if (list_empty(&timer->open_list_head) &&
+                   timer->hw.close)
+                       timer->hw.close(timer);
+               /* remove slave links */
+@@ -415,7 +414,7 @@ static void snd_timer_notify1(struct snd_timer_instance 
*ti, int event)
+       spin_lock_irqsave(&timer->lock, flags);
+       list_for_each_entry(ts, &ti->slave_active_head, active_list)
+               if (ts->ccallback)
+-                      ts->ccallback(ti, event + 100, &tstamp, resolution);
++                      ts->ccallback(ts, event + 100, &tstamp, resolution);
+       spin_unlock_irqrestore(&timer->lock, flags);
+ }
+ 
+@@ -444,6 +443,10 @@ static int snd_timer_start_slave(struct 
snd_timer_instance *timeri)
+       unsigned long flags;
+ 
+       spin_lock_irqsave(&slave_active_lock, flags);
++      if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
++              spin_unlock_irqrestore(&slave_active_lock, flags);
++              return -EBUSY;
++      }
+       timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
+       if (timeri->master && timeri->timer) {
+               spin_lock(&timeri->timer->lock);
+@@ -468,23 +471,30 @@ int snd_timer_start(struct snd_timer_instance *timeri, 
unsigned int ticks)
+               return -EINVAL;
+       if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
+               result = snd_timer_start_slave(timeri);
+-              snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
++              if (result >= 0)
++                      snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+               return result;
+       }
+       timer = timeri->timer;
+       if (timer == NULL)
+               return -EINVAL;
+       spin_lock_irqsave(&timer->lock, flags);
++      if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
++                           SNDRV_TIMER_IFLG_START)) {
++              result = -EBUSY;
++              goto unlock;
++      }
+       timeri->ticks = timeri->cticks = ticks;
+       timeri->pticks = 0;
+       result = snd_timer_start1(timer, timeri, ticks);
++ unlock:
+       spin_unlock_irqrestore(&timer->lock, flags);
+-      snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
++      if (result >= 0)
++              snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+       return result;
+ }
+ 
+-static int _snd_timer_stop(struct snd_timer_instance * timeri,
+-                         int keep_flag, int event)
++static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
+ {
+       struct snd_timer *timer;
+       unsigned long flags;
+@@ -493,19 +503,30 @@ static int _snd_timer_stop(struct snd_timer_instance * 
timeri,
+               return -ENXIO;
+ 
+       if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
+-              if (!keep_flag) {
+-                      spin_lock_irqsave(&slave_active_lock, flags);
+-                      timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
+-                      list_del_init(&timeri->ack_list);
+-                      list_del_init(&timeri->active_list);
++              spin_lock_irqsave(&slave_active_lock, flags);
++              if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) {
+                       spin_unlock_irqrestore(&slave_active_lock, flags);
++                      return -EBUSY;
+               }
++              if (timeri->timer)
++                      spin_lock(&timeri->timer->lock);
++              timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
++              list_del_init(&timeri->ack_list);
++              list_del_init(&timeri->active_list);
++              if (timeri->timer)
++                      spin_unlock(&timeri->timer->lock);
++              spin_unlock_irqrestore(&slave_active_lock, flags);
+               goto __end;
+       }
+       timer = timeri->timer;
+       if (!timer)
+               return -EINVAL;
+       spin_lock_irqsave(&timer->lock, flags);
++      if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
++                             SNDRV_TIMER_IFLG_START))) {
++              spin_unlock_irqrestore(&timer->lock, flags);
++              return -EBUSY;
++      }
+       list_del_init(&timeri->ack_list);
+       list_del_init(&timeri->active_list);
+       if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) &&
+@@ -520,9 +541,7 @@ static int _snd_timer_stop(struct snd_timer_instance * 
timeri,
+                       }
+               }
+       }
+-      if (!keep_flag)
+-              timeri->flags &=
+-                      ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
++      timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
+       spin_unlock_irqrestore(&timer->lock, flags);
+       __end:
+       if (event != SNDRV_TIMER_EVENT_RESOLUTION)
+@@ -541,7 +560,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri)
+       unsigned long flags;
+       int err;
+ 
+-      err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP);
++      err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP);
+       if (err < 0)
+               return err;
+       timer = timeri->timer;
+@@ -571,10 +590,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri)
+       if (! timer)
+               return -EINVAL;
+       spin_lock_irqsave(&timer->lock, flags);
++      if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
++              result = -EBUSY;
++              goto unlock;
++      }
+       if (!timeri->cticks)
+               timeri->cticks = 1;
+       timeri->pticks = 0;
+       result = snd_timer_start1(timer, timeri, timer->sticks);
++ unlock:
+       spin_unlock_irqrestore(&timer->lock, flags);
+       snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE);
+       return result;
+@@ -585,7 +609,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri)
+  */
+ int snd_timer_pause(struct snd_timer_instance * timeri)
+ {
+-      return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);
++      return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE);
+ }
+ 
+ /*
+@@ -702,8 +726,8 @@ void snd_timer_interrupt(struct snd_timer * timer, 
unsigned long ticks_left)
+                       ti->cticks = ti->ticks;
+               } else {
+                       ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
+-                      if (--timer->running)
+-                              list_del_init(&ti->active_list);
++                      --timer->running;
++                      list_del_init(&ti->active_list);
+               }
+               if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
+                   (ti->flags & SNDRV_TIMER_IFLG_FAST))
+diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
+index fd798f753609..982a2c2faf24 100644
+--- a/sound/drivers/dummy.c
++++ b/sound/drivers/dummy.c
+@@ -109,6 +109,9 @@ struct dummy_timer_ops {
+       snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
+ };
+ 
++#define get_dummy_ops(substream) \
++      (*(const struct dummy_timer_ops **)(substream)->runtime->private_data)
++
+ struct dummy_model {
+       const char *name;
+       int (*playback_constraints)(struct snd_pcm_runtime *runtime);
+@@ -137,7 +140,6 @@ struct snd_dummy {
+       int iobox;
+       struct snd_kcontrol *cd_volume_ctl;
+       struct snd_kcontrol *cd_switch_ctl;
+-      const struct dummy_timer_ops *timer_ops;
+ };
+ 
+ /*
+@@ -231,6 +233,8 @@ struct dummy_model *dummy_models[] = {
+  */
+ 
+ struct dummy_systimer_pcm {
++      /* ops must be the first item */
++      const struct dummy_timer_ops *timer_ops;
+       spinlock_t lock;
+       struct timer_list timer;
+       unsigned long base_time;
+@@ -368,6 +372,8 @@ static struct dummy_timer_ops dummy_systimer_ops = {
+  */
+ 
+ struct dummy_hrtimer_pcm {
++      /* ops must be the first item */
++      const struct dummy_timer_ops *timer_ops;
+       ktime_t base_time;
+       ktime_t period_time;
+       atomic_t running;
+@@ -494,31 +500,25 @@ static struct dummy_timer_ops dummy_hrtimer_ops = {
+ 
+ static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+ {
+-      struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+-              return dummy->timer_ops->start(substream);
++              return get_dummy_ops(substream)->start(substream);
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+-              return dummy->timer_ops->stop(substream);
++              return get_dummy_ops(substream)->stop(substream);
+       }
+       return -EINVAL;
+ }
+ 
+ static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
+ {
+-      struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-
+-      return dummy->timer_ops->prepare(substream);
++      return get_dummy_ops(substream)->prepare(substream);
+ }
+ 
+ static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream 
*substream)
+ {
+-      struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-
+-      return dummy->timer_ops->pointer(substream);
++      return get_dummy_ops(substream)->pointer(substream);
+ }
+ 
+ static struct snd_pcm_hardware dummy_pcm_hardware = {
+@@ -564,17 +564,19 @@ static int dummy_pcm_open(struct snd_pcm_substream 
*substream)
+       struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+       struct dummy_model *model = dummy->model;
+       struct snd_pcm_runtime *runtime = substream->runtime;
++      const struct dummy_timer_ops *ops;
+       int err;
+ 
+-      dummy->timer_ops = &dummy_systimer_ops;
++      ops = &dummy_systimer_ops;
+ #ifdef CONFIG_HIGH_RES_TIMERS
+       if (hrtimer)
+-              dummy->timer_ops = &dummy_hrtimer_ops;
++              ops = &dummy_hrtimer_ops;
+ #endif
+ 
+-      err = dummy->timer_ops->create(substream);
++      err = ops->create(substream);
+       if (err < 0)
+               return err;
++      get_dummy_ops(substream) = ops;
+ 
+       runtime->hw = dummy->pcm_hw;
+       if (substream->pcm->device & 1) {
+@@ -596,7 +598,7 @@ static int dummy_pcm_open(struct snd_pcm_substream 
*substream)
+                       err = model->capture_constraints(substream->runtime);
+       }
+       if (err < 0) {
+-              dummy->timer_ops->free(substream);
++              get_dummy_ops(substream)->free(substream);
+               return err;
+       }
+       return 0;
+@@ -604,8 +606,7 @@ static int dummy_pcm_open(struct snd_pcm_substream 
*substream)
+ 
+ static int dummy_pcm_close(struct snd_pcm_substream *substream)
+ {
+-      struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-      dummy->timer_ops->free(substream);
++      get_dummy_ops(substream)->free(substream);
+       return 0;
+ }
+ 
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 69a2aafb0b0f..babbf238a648 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -2188,6 +2188,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
+       SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", 
ALC882_FIXUP_NO_PRIMARY_HP),
+       SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", 
ALC882_FIXUP_NO_PRIMARY_HP),
++      SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", 
ALC882_FIXUP_NO_PRIMARY_HP),
+ 
+       /* All Apple entries are in codec SSIDs */
+       SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
+diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
+index 02d26915b61d..c6d408c819b1 100644
+--- a/sound/soc/soc-pcm.c
++++ b/sound/soc/soc-pcm.c
+@@ -1248,7 +1248,8 @@ static int dpcm_be_dai_hw_free(struct 
snd_soc_pcm_runtime *fe, int stream)
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
+-                  (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
++                  (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
++                  (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
+                       continue;
+ 
+               dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
+diff --git a/sound/usb/midi.c b/sound/usb/midi.c
+index dabbe05d17f5..37ecba340876 100644
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -2291,7 +2291,6 @@ int snd_usbmidi_create(struct snd_card *card,
+       else
+               err = snd_usbmidi_create_endpoints(umidi, endpoints);
+       if (err < 0) {
+-              snd_usbmidi_free(umidi);
+               return err;
+       }
+ 
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 94cd28c2bd8d..44550a4cf893 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -900,8 +900,12 @@ void snd_usb_set_interface_quirk(struct usb_device *dev)
+        * "Playback Design" products need a 50ms delay after setting the
+        * USB interface.
+        */
+-      if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba)
++      switch (le16_to_cpu(dev->descriptor.idVendor)) {
++      case 0x23ba: /* Playback Design */
++      case 0x0644: /* TEAC Corp. */
+               mdelay(50);
++              break;
++      }
+ }
+ 
+ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+@@ -916,6 +920,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, 
unsigned int pipe,
+           (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+               mdelay(20);
+ 
++      /*
++       * "TEAC Corp." products need a 20ms delay after each
++       * class compliant request
++       */
++      if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0644) &&
++          (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
++              mdelay(20);
++
+       /* Marantz/Denon devices with USB DAC functionality need a delay
+        * after each class compliant request
+        */

Reply via email to