commit:     0cf9a96e20f1df4bba833a1d18501d54a897acdf
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Mon Sep 28 14:09:52 2015 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Mon Sep 28 14:09:52 2015 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=0cf9a96e

Linux patch 3.12.48

 1047_linux-3.12.48.patch | 1502 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1502 insertions(+)

diff --git a/1047_linux-3.12.48.patch b/1047_linux-3.12.48.patch
new file mode 100644
index 0000000..c0f1bf4
--- /dev/null
+++ b/1047_linux-3.12.48.patch
@@ -0,0 +1,1502 @@
+diff --git a/Makefile b/Makefile
+index c45298b8b2d5..a01f2573731d 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 3
+ PATCHLEVEL = 12
+-SUBLEVEL = 47
++SUBLEVEL = 48
+ EXTRAVERSION =
+ NAME = One Giant Leap for Frogkind
+ 
+diff --git a/drivers/block/mtip32xx/mtip32xx.c 
b/drivers/block/mtip32xx/mtip32xx.c
+index 560227b817fe..01c7270b5e84 100644
+--- a/drivers/block/mtip32xx/mtip32xx.c
++++ b/drivers/block/mtip32xx/mtip32xx.c
+@@ -2810,34 +2810,51 @@ static ssize_t show_device_status(struct device_driver 
*drv, char *buf)
+ static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf,
+                                               size_t len, loff_t *offset)
+ {
++      struct driver_data *dd =  (struct driver_data *)f->private_data;
+       int size = *offset;
+-      char buf[MTIP_DFS_MAX_BUF_SIZE];
++      char *buf;
++      int rv = 0;
+ 
+       if (!len || *offset)
+               return 0;
+ 
++      buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
++      if (!buf) {
++              dev_err(&dd->pdev->dev,
++                      "Memory allocation: status buffer\n");
++              return -ENOMEM;
++      }
++
+       size += show_device_status(NULL, buf);
+ 
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+-              return -EFAULT;
++              rv = -EFAULT;
+ 
+-      return *offset;
++      kfree(buf);
++      return rv ? rv : *offset;
+ }
+ 
+ static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
+                                 size_t len, loff_t *offset)
+ {
+       struct driver_data *dd =  (struct driver_data *)f->private_data;
+-      char buf[MTIP_DFS_MAX_BUF_SIZE];
++      char *buf;
+       u32 group_allocated;
+       int size = *offset;
+-      int n;
++      int n, rv = 0;
+ 
+       if (!len || size)
+               return 0;
+ 
++      buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
++      if (!buf) {
++              dev_err(&dd->pdev->dev,
++                      "Memory allocation: register buffer\n");
++              return -ENOMEM;
++      }
++
+       size += sprintf(&buf[size], "H/ S ACTive      : [ 0x");
+ 
+       for (n = dd->slot_groups-1; n >= 0; n--)
+@@ -2892,21 +2909,30 @@ static ssize_t mtip_hw_read_registers(struct file *f, 
char __user *ubuf,
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+-              return -EFAULT;
++              rv = -EFAULT;
+ 
+-      return *offset;
++      kfree(buf);
++      return rv ? rv : *offset;
+ }
+ 
+ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
+                                 size_t len, loff_t *offset)
+ {
+       struct driver_data *dd =  (struct driver_data *)f->private_data;
+-      char buf[MTIP_DFS_MAX_BUF_SIZE];
++      char *buf;
+       int size = *offset;
++      int rv = 0;
+ 
+       if (!len || size)
+               return 0;
+ 
++      buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
++      if (!buf) {
++              dev_err(&dd->pdev->dev,
++                      "Memory allocation: flag buffer\n");
++              return -ENOMEM;
++      }
++
+       size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
+                                                       dd->port->flags);
+       size += sprintf(&buf[size], "Flag-dd   : [ %08lX ]\n",
+@@ -2915,9 +2941,10 @@ static ssize_t mtip_hw_read_flags(struct file *f, char 
__user *ubuf,
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+-              return -EFAULT;
++              rv = -EFAULT;
+ 
+-      return *offset;
++      kfree(buf);
++      return rv ? rv : *offset;
+ }
+ 
+ static const struct file_operations mtip_device_status_fops = {
+diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c 
b/drivers/gpu/drm/radeon/radeon_irq_kms.c
+index 4a2d91536a8d..c843cf0aa623 100644
+--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
++++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
+@@ -73,6 +73,11 @@ static void radeon_hotplug_work_func(struct work_struct 
*work)
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+ 
++      /* we can race here at startup, some boards seem to trigger
++       * hotplug irqs when they shouldn't. */
++      if (!rdev->mode_info.mode_config_initialized)
++              return;
++
+       mutex_lock(&mode_config->mutex);
+       if (mode_config->num_connector) {
+               list_for_each_entry(connector, &mode_config->connector_list, 
head)
+diff --git a/drivers/isdn/gigaset/ser-gigaset.c 
b/drivers/isdn/gigaset/ser-gigaset.c
+index 8c91fd5eb6fd..3ac9c4194814 100644
+--- a/drivers/isdn/gigaset/ser-gigaset.c
++++ b/drivers/isdn/gigaset/ser-gigaset.c
+@@ -524,9 +524,18 @@ gigaset_tty_open(struct tty_struct *tty)
+       cs->hw.ser->tty = tty;
+       atomic_set(&cs->hw.ser->refcnt, 1);
+       init_completion(&cs->hw.ser->dead_cmp);
+-
+       tty->disc_data = cs;
+ 
++      /* Set the amount of data we're willing to receive per call
++       * from the hardware driver to half of the input buffer size
++       * to leave some reserve.
++       * Note: We don't do flow control towards the hardware driver.
++       * If more data is received than will fit into the input buffer,
++       * it will be dropped and an error will be logged. This should
++       * never happen as the device is slow and the buffer size ample.
++       */
++      tty->receive_room = RBUFSIZE/2;
++
+       /* OK.. Initialization of the datastructures and the HW is done.. Now
+        * startup system and notify the LL that we are ready to run
+        */
+diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
+index 4296155090b2..afcd18428945 100644
+--- a/drivers/md/dm-cache-policy-mq.c
++++ b/drivers/md/dm-cache-policy-mq.c
+@@ -855,7 +855,7 @@ static void mq_destroy(struct dm_cache_policy *p)
+       struct mq_policy *mq = to_mq_policy(p);
+ 
+       free_bitset(mq->allocation_bitset);
+-      kfree(mq->table);
++      vfree(mq->table);
+       free_entries(mq);
+       kfree(mq);
+ }
+@@ -1106,7 +1106,7 @@ static struct dm_cache_policy *mq_create(dm_cblock_t 
cache_size,
+ 
+       mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
+       mq->hash_bits = ffs(mq->nr_buckets) - 1;
+-      mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL);
++      mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
+       if (!mq->table)
+               goto bad_alloc_table;
+ 
+diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
+index e775bfbc5e6e..5f187294c85a 100644
+--- a/drivers/mfd/lpc_ich.c
++++ b/drivers/mfd/lpc_ich.c
+@@ -872,8 +872,8 @@ gpe0_done:
+       lpc_ich_enable_gpio_space(dev);
+ 
+       lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]);
+-      ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
+-                            1, NULL, 0, NULL);
++      ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO,
++                            &lpc_ich_cells[LPC_GPIO], 1, NULL, 0, NULL);
+ 
+ gpio_done:
+       if (acpi_conflict)
+@@ -932,8 +932,8 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
+       }
+ 
+       lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
+-      ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
+-                            1, NULL, 0, NULL);
++      ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO,
++                            &lpc_ich_cells[LPC_WDT], 1, NULL, 0, NULL);
+ 
+ wdt_done:
+       return ret;
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 5f95537d4896..b3892b0d2e61 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -671,6 +671,22 @@ static void bond_set_dev_addr(struct net_device *bond_dev,
+       call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
+ }
+ 
++static struct slave *bond_get_old_active(struct bonding *bond,
++                                       struct slave *new_active)
++{
++      struct slave *slave;
++
++      bond_for_each_slave(bond, slave) {
++              if (slave == new_active)
++                      continue;
++
++              if (ether_addr_equal(bond->dev->dev_addr, slave->dev->dev_addr))
++                      return slave;
++      }
++
++      return NULL;
++}
++
+ /*
+  * bond_do_fail_over_mac
+  *
+@@ -712,6 +728,9 @@ static void bond_do_fail_over_mac(struct bonding *bond,
+               write_unlock_bh(&bond->curr_slave_lock);
+               read_unlock(&bond->lock);
+ 
++              if (!old_active)
++                      old_active = bond_get_old_active(bond, new_active);
++
+               if (old_active) {
+                       memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN);
+                       memcpy(saddr.sa_data, old_active->dev->dev_addr,
+@@ -1917,6 +1936,7 @@ static int  bond_release_and_destroy(struct net_device 
*bond_dev,
+               bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
+               pr_info("%s: destroying bond %s.\n",
+                       bond_dev->name, bond_dev->name);
++              bond_remove_proc_entry(bond);
+               unregister_netdevice(bond_dev);
+       }
+       return ret;
+diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c 
b/drivers/net/ethernet/mellanox/mlx4/eq.c
+index 0416c5b3b35c..3990b435a081 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
++++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
+@@ -558,7 +558,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct 
mlx4_eq *eq)
+                                               mlx4_dbg(dev, "%s: Sending 
MLX4_PORT_CHANGE_SUBTYPE_DOWN"
+                                                        " to slave: %d, 
port:%d\n",
+                                                        __func__, i, port);
+-                                              s_info = 
&priv->mfunc.master.vf_oper[slave].vport[port].state;
++                                              s_info = 
&priv->mfunc.master.vf_oper[i].vport[port].state;
+                                               if (IFLA_VF_LINK_STATE_AUTO == 
s_info->link_state)
+                                                       mlx4_slave_event(dev, 
i, eqe);
+                                       } else {  /* IB port */
+@@ -584,7 +584,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct 
mlx4_eq *eq)
+                                       for (i = 0; i < dev->num_slaves; i++) {
+                                               if (i == 
mlx4_master_func_num(dev))
+                                                       continue;
+-                                              s_info = 
&priv->mfunc.master.vf_oper[slave].vport[port].state;
++                                              s_info = 
&priv->mfunc.master.vf_oper[i].vport[port].state;
+                                               if (IFLA_VF_LINK_STATE_AUTO == 
s_info->link_state)
+                                                       mlx4_slave_event(dev, 
i, eqe);
+                                       }
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
+index c913e8cc3b26..ed7759980c47 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.c
++++ b/drivers/scsi/lpfc/lpfc_scsi.c
+@@ -3423,7 +3423,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct 
lpfc_scsi_buf *lpfc_cmd)
+                */
+ 
+               nseg = scsi_dma_map(scsi_cmnd);
+-              if (unlikely(!nseg))
++              if (unlikely(nseg <= 0))
+                       return 1;
+               sgl += 1;
+               /* clear the last flag in the fcp_rsp map entry */
+diff --git a/fs/aio.c b/fs/aio.c
+index 329e6c1f3a43..31a5cb74ae1f 100644
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -146,6 +146,7 @@ struct kioctx {
+ 
+       struct {
+               unsigned        tail;
++              unsigned        completed_events;
+               spinlock_t      completion_lock;
+       } ____cacheline_aligned_in_smp;
+ 
+@@ -899,6 +900,68 @@ out:
+       return ret;
+ }
+ 
++/* refill_reqs_available
++ *    Updates the reqs_available reference counts used for tracking the
++ *    number of free slots in the completion ring.  This can be called
++ *    from aio_complete() (to optimistically update reqs_available) or
++ *    from aio_get_req() (the we're out of events case).  It must be
++ *    called holding ctx->completion_lock.
++ */
++static void refill_reqs_available(struct kioctx *ctx, unsigned head,
++                                  unsigned tail)
++{
++      unsigned events_in_ring, completed;
++
++      /* Clamp head since userland can write to it. */
++      head %= ctx->nr_events;
++      if (head <= tail)
++              events_in_ring = tail - head;
++      else
++              events_in_ring = ctx->nr_events - (head - tail);
++
++      completed = ctx->completed_events;
++      if (events_in_ring < completed)
++              completed -= events_in_ring;
++      else
++              completed = 0;
++
++      if (!completed)
++              return;
++
++      ctx->completed_events -= completed;
++      put_reqs_available(ctx, completed);
++}
++
++/* user_refill_reqs_available
++ *    Called to refill reqs_available when aio_get_req() encounters an
++ *    out of space in the completion ring.
++ */
++static void user_refill_reqs_available(struct kioctx *ctx)
++{
++      spin_lock_irq(&ctx->completion_lock);
++      if (ctx->completed_events) {
++              struct aio_ring *ring;
++              unsigned head;
++
++              /* Access of ring->head may race with aio_read_events_ring()
++               * here, but that's okay since whether we read the old version
++               * or the new version, and either will be valid.  The important
++               * part is that head cannot pass tail since we prevent
++               * aio_complete() from updating tail by holding
++               * ctx->completion_lock.  Even if head is invalid, the check
++               * against ctx->completed_events below will make sure we do the
++               * safe/right thing.
++               */
++              ring = kmap_atomic(ctx->ring_pages[0]);
++              head = ring->head;
++              kunmap_atomic(ring);
++
++              refill_reqs_available(ctx, head, ctx->tail);
++      }
++
++      spin_unlock_irq(&ctx->completion_lock);
++}
++
+ /* aio_get_req
+  *    Allocate a slot for an aio request.
+  * Returns NULL if no requests are free.
+@@ -907,8 +970,11 @@ static inline struct kiocb *aio_get_req(struct kioctx 
*ctx)
+ {
+       struct kiocb *req;
+ 
+-      if (!get_reqs_available(ctx))
+-              return NULL;
++      if (!get_reqs_available(ctx)) {
++              user_refill_reqs_available(ctx);
++              if (!get_reqs_available(ctx))
++                      return NULL;
++      }
+ 
+       req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL|__GFP_ZERO);
+       if (unlikely(!req))
+@@ -967,8 +1033,8 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
+       struct kioctx   *ctx = iocb->ki_ctx;
+       struct aio_ring *ring;
+       struct io_event *ev_page, *event;
++      unsigned tail, pos, head;
+       unsigned long   flags;
+-      unsigned tail, pos;
+ 
+       /*
+        * Special case handling for sync iocbs:
+@@ -1029,10 +1095,14 @@ void aio_complete(struct kiocb *iocb, long res, long 
res2)
+       ctx->tail = tail;
+ 
+       ring = kmap_atomic(ctx->ring_pages[0]);
++      head = ring->head;
+       ring->tail = tail;
+       kunmap_atomic(ring);
+       flush_dcache_page(ctx->ring_pages[0]);
+ 
++      ctx->completed_events++;
++      if (ctx->completed_events > 1)
++              refill_reqs_available(ctx, head, tail);
+       spin_unlock_irqrestore(&ctx->completion_lock, flags);
+ 
+       pr_debug("added to ring %p at [%u]\n", iocb, tail);
+@@ -1047,7 +1117,6 @@ void aio_complete(struct kiocb *iocb, long res, long 
res2)
+ 
+       /* everything turned out well, dispose of the aiocb. */
+       kiocb_free(iocb);
+-      put_reqs_available(ctx, 1);
+ 
+       /*
+        * We have to order our ring_info tail store above and test
+diff --git a/fs/bio.c b/fs/bio.c
+index ea5035da4d9a..e7fb3f82f5f5 100644
+--- a/fs/bio.c
++++ b/fs/bio.c
+@@ -601,7 +601,7 @@ EXPORT_SYMBOL(bio_get_nr_vecs);
+ 
+ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct 
page
+                         *page, unsigned int len, unsigned int offset,
+-                        unsigned short max_sectors)
++                        unsigned int max_sectors)
+ {
+       int retried_segments = 0;
+       struct bio_vec *bvec;
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index 89b5519085c2..ebad721656f3 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2245,6 +2245,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct 
smb_vol *vol)
+ 
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
++              if (ses->status == CifsExiting)
++                      continue;
+               if (!match_session(ses, vol))
+                       continue;
+               ++ses->ses_count;
+@@ -2258,24 +2260,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, 
struct smb_vol *vol)
+ static void
+ cifs_put_smb_ses(struct cifs_ses *ses)
+ {
+-      unsigned int xid;
++      unsigned int rc, xid;
+       struct TCP_Server_Info *server = ses->server;
+ 
+       cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
++
+       spin_lock(&cifs_tcp_ses_lock);
++      if (ses->status == CifsExiting) {
++              spin_unlock(&cifs_tcp_ses_lock);
++              return;
++      }
+       if (--ses->ses_count > 0) {
+               spin_unlock(&cifs_tcp_ses_lock);
+               return;
+       }
+-
+-      list_del_init(&ses->smb_ses_list);
++      if (ses->status == CifsGood)
++              ses->status = CifsExiting;
+       spin_unlock(&cifs_tcp_ses_lock);
+ 
+-      if (ses->status == CifsGood && server->ops->logoff) {
++      if (ses->status == CifsExiting && server->ops->logoff) {
+               xid = get_xid();
+-              server->ops->logoff(xid, ses);
++              rc = server->ops->logoff(xid, ses);
++              if (rc)
++                      cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
++                              __func__, rc);
+               _free_xid(xid);
+       }
++
++      spin_lock(&cifs_tcp_ses_lock);
++      list_del_init(&ses->smb_ses_list);
++      spin_unlock(&cifs_tcp_ses_lock);
++
+       sesInfoFree(ses);
+       cifs_put_tcp_session(server);
+ }
+diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
+index 340abca3aa52..ee1963b2e5a7 100644
+--- a/fs/cifs/smb2transport.c
++++ b/fs/cifs/smb2transport.c
+@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr 
*buf,
+               return -EAGAIN;
+       }
+ 
+-      if (ses->status != CifsGood) {
+-              /* check if SMB2 session is bad because we are setting it up */
++      if (ses->status == CifsNew) {
+               if ((buf->Command != SMB2_SESSION_SETUP) &&
+                   (buf->Command != SMB2_NEGOTIATE))
+                       return -EAGAIN;
+               /* else ok - we are setting up session */
+       }
++
++      if (ses->status == CifsExiting) {
++              if (buf->Command != SMB2_LOGOFF)
++                      return -EAGAIN;
++              /* else ok - we are shutting down the session */
++      }
++
+       *mid = smb2_mid_entry_alloc(buf, ses->server);
+       if (*mid == NULL)
+               return -ENOMEM;
+diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
+index 800b938e4061..ebb46e311e0b 100644
+--- a/fs/cifs/transport.c
++++ b/fs/cifs/transport.c
+@@ -431,13 +431,20 @@ static int allocate_mid(struct cifs_ses *ses, struct 
smb_hdr *in_buf,
+               return -EAGAIN;
+       }
+ 
+-      if (ses->status != CifsGood) {
+-              /* check if SMB session is bad because we are setting it up */
++      if (ses->status == CifsNew) {
+               if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
+                       (in_buf->Command != SMB_COM_NEGOTIATE))
+                       return -EAGAIN;
+               /* else ok - we are setting up session */
+       }
++
++      if (ses->status == CifsExiting) {
++              /* check if SMB session is bad because we are setting it up */
++              if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
++                      return -EAGAIN;
++              /* else ok - we are shutting down session */
++      }
++
+       *ppmidQ = AllocMidQEntry(in_buf, ses->server);
+       if (*ppmidQ == NULL)
+               return -ENOMEM;
+diff --git a/include/net/ip.h b/include/net/ip.h
+index 1b1269e13596..553c07514a05 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -141,6 +141,7 @@ static inline struct sk_buff *ip_finish_skb(struct sock 
*sk, struct flowi4 *fl4)
+ }
+ 
+ /* datagram.c */
++int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int 
addr_len);
+ extern int            ip4_datagram_connect(struct sock *sk, 
+                                            struct sockaddr *uaddr, int 
addr_len);
+ 
+diff --git a/include/net/netfilter/nf_conntrack.h 
b/include/net/netfilter/nf_conntrack.h
+index 0c1288a50e8b..a68a061882f4 100644
+--- a/include/net/netfilter/nf_conntrack.h
++++ b/include/net/netfilter/nf_conntrack.h
+@@ -293,6 +293,8 @@ extern unsigned int nf_conntrack_max;
+ extern unsigned int nf_conntrack_hash_rnd;
+ void init_nf_conntrack_hash_rnd(void);
+ 
++void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl);
++
+ #define NF_CT_STAT_INC(net, count)      __this_cpu_inc((net)->ct.stat->count)
+ #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
+ 
+diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
+index b7b1914dfa25..27cf128ebc15 100644
+--- a/net/bridge/br_mdb.c
++++ b/net/bridge/br_mdb.c
+@@ -347,7 +347,6 @@ static int br_mdb_add_group(struct net_bridge *br, struct 
net_bridge_port *port,
+               return -ENOMEM;
+       rcu_assign_pointer(*pp, p);
+ 
+-      br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
+       return 0;
+ }
+ 
+@@ -370,6 +369,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge 
*br,
+       if (!p || p->br != br || p->state == BR_STATE_DISABLED)
+               return -EINVAL;
+ 
++      memset(&ip, 0, sizeof(ip));
+       ip.proto = entry->addr.proto;
+       if (ip.proto == htons(ETH_P_IP))
+               ip.u.ip4 = entry->addr.u.ip4;
+@@ -416,6 +416,7 @@ static int __br_mdb_del(struct net_bridge *br, struct 
br_mdb_entry *entry)
+       if (!netif_running(br->dev) || br->multicast_disabled)
+               return -EINVAL;
+ 
++      memset(&ip, 0, sizeof(ip));
+       ip.proto = entry->addr.proto;
+       if (ip.proto == htons(ETH_P_IP)) {
+               if (timer_pending(&br->ip4_querier.timer))
+diff --git a/net/core/datagram.c b/net/core/datagram.c
+index af814e764206..98e3d61e7476 100644
+--- a/net/core/datagram.c
++++ b/net/core/datagram.c
+@@ -130,6 +130,35 @@ out_noerr:
+       goto out;
+ }
+ 
++static struct sk_buff *skb_set_peeked(struct sk_buff *skb)
++{
++      struct sk_buff *nskb;
++
++      if (skb->peeked)
++              return skb;
++
++      /* We have to unshare an skb before modifying it. */
++      if (!skb_shared(skb))
++              goto done;
++
++      nskb = skb_clone(skb, GFP_ATOMIC);
++      if (!nskb)
++              return ERR_PTR(-ENOMEM);
++
++      skb->prev->next = nskb;
++      skb->next->prev = nskb;
++      nskb->prev = skb->prev;
++      nskb->next = skb->next;
++
++      consume_skb(skb);
++      skb = nskb;
++
++done:
++      skb->peeked = 1;
++
++      return skb;
++}
++
+ /**
+  *    __skb_recv_datagram - Receive a datagram skbuff
+  *    @sk: socket
+@@ -164,7 +193,9 @@ out_noerr:
+ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
+                                   int *peeked, int *off, int *err)
+ {
++      struct sk_buff_head *queue = &sk->sk_receive_queue;
+       struct sk_buff *skb, *last;
++      unsigned long cpu_flags;
+       long timeo;
+       /*
+        * Caller is allowed not to check sk->sk_err before skb_recv_datagram()
+@@ -183,8 +214,6 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, 
unsigned int flags,
+                * Look at current nfs client by the way...
+                * However, this function was correct in any case. 8)
+                */
+-              unsigned long cpu_flags;
+-              struct sk_buff_head *queue = &sk->sk_receive_queue;
+               int _off = *off;
+ 
+               last = (struct sk_buff *)queue;
+@@ -198,7 +227,12 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, 
unsigned int flags,
+                                       _off -= skb->len;
+                                       continue;
+                               }
+-                              skb->peeked = 1;
++
++                              skb = skb_set_peeked(skb);
++                              error = PTR_ERR(skb);
++                              if (IS_ERR(skb))
++                                      goto unlock_err;
++
+                               atomic_inc(&skb->users);
+                       } else
+                               __skb_unlink(skb, queue);
+@@ -222,6 +256,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, 
unsigned int flags,
+ 
+       return NULL;
+ 
++unlock_err:
++      spin_unlock_irqrestore(&queue->lock, cpu_flags);
+ no_packet:
+       *err = error;
+       return NULL;
+@@ -742,7 +778,8 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, 
int len)
+       if (likely(!sum)) {
+               if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
+                       netdev_rx_csum_fault(skb->dev);
+-              skb->ip_summed = CHECKSUM_UNNECESSARY;
++              if (!skb_shared(skb))
++                      skb->ip_summed = CHECKSUM_UNNECESSARY;
+       }
+       return sum;
+ }
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 3ca487e14080..f991f5d3371d 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3193,6 +3193,8 @@ static int enqueue_to_backlog(struct sk_buff *skb, int 
cpu,
+       local_irq_save(flags);
+ 
+       rps_lock(sd);
++      if (!netif_running(skb->dev))
++              goto drop;
+       qlen = skb_queue_len(&sd->input_pkt_queue);
+       if (qlen <= netdev_max_backlog && !skb_flow_limit(skb, qlen)) {
+               if (skb_queue_len(&sd->input_pkt_queue)) {
+@@ -3214,6 +3216,7 @@ enqueue:
+               goto enqueue;
+       }
+ 
++drop:
+       sd->dropped++;
+       rps_unlock(sd);
+ 
+@@ -3518,8 +3521,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, 
bool pfmemalloc)
+ 
+       pt_prev = NULL;
+ 
+-      rcu_read_lock();
+-
+ another_round:
+       skb->skb_iif = skb->dev->ifindex;
+ 
+@@ -3529,7 +3530,7 @@ another_round:
+           skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
+               skb = skb_vlan_untag(skb);
+               if (unlikely(!skb))
+-                      goto unlock;
++                      goto out;
+       }
+ 
+ #ifdef CONFIG_NET_CLS_ACT
+@@ -3554,7 +3555,7 @@ skip_taps:
+ #ifdef CONFIG_NET_CLS_ACT
+       skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
+       if (!skb)
+-              goto unlock;
++              goto out;
+ ncls:
+ #endif
+ 
+@@ -3569,7 +3570,7 @@ ncls:
+               if (vlan_do_receive(&skb))
+                       goto another_round;
+               else if (unlikely(!skb))
+-                      goto unlock;
++                      goto out;
+       }
+ 
+       rx_handler = rcu_dereference(skb->dev->rx_handler);
+@@ -3581,7 +3582,7 @@ ncls:
+               switch (rx_handler(&skb)) {
+               case RX_HANDLER_CONSUMED:
+                       ret = NET_RX_SUCCESS;
+-                      goto unlock;
++                      goto out;
+               case RX_HANDLER_ANOTHER:
+                       goto another_round;
+               case RX_HANDLER_EXACT:
+@@ -3633,8 +3634,6 @@ drop:
+               ret = NET_RX_DROP;
+       }
+ 
+-unlock:
+-      rcu_read_unlock();
+ out:
+       return ret;
+ }
+@@ -3681,29 +3680,30 @@ static int __netif_receive_skb(struct sk_buff *skb)
+  */
+ int netif_receive_skb(struct sk_buff *skb)
+ {
++      int ret;
++
+       net_timestamp_check(netdev_tstamp_prequeue, skb);
+ 
+       if (skb_defer_rx_timestamp(skb))
+               return NET_RX_SUCCESS;
+ 
++      rcu_read_lock();
++
+ #ifdef CONFIG_RPS
+       if (static_key_false(&rps_needed)) {
+               struct rps_dev_flow voidflow, *rflow = &voidflow;
+-              int cpu, ret;
+-
+-              rcu_read_lock();
+-
+-              cpu = get_rps_cpu(skb->dev, skb, &rflow);
++              int cpu = get_rps_cpu(skb->dev, skb, &rflow);
+ 
+               if (cpu >= 0) {
+                       ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
+                       rcu_read_unlock();
+                       return ret;
+               }
+-              rcu_read_unlock();
+       }
+ #endif
+-      return __netif_receive_skb(skb);
++      ret = __netif_receive_skb(skb);
++      rcu_read_unlock();
++      return ret;
+ }
+ EXPORT_SYMBOL(netif_receive_skb);
+ 
+@@ -4113,8 +4113,10 @@ static int process_backlog(struct napi_struct *napi, 
int quota)
+               unsigned int qlen;
+ 
+               while ((skb = __skb_dequeue(&sd->process_queue))) {
++                      rcu_read_lock();
+                       local_irq_enable();
+                       __netif_receive_skb(skb);
++                      rcu_read_unlock();
+                       local_irq_disable();
+                       input_queue_head_incr(sd);
+                       if (++work >= quota) {
+@@ -5302,6 +5304,7 @@ static void rollback_registered_many(struct list_head 
*head)
+               unlist_netdevice(dev);
+ 
+               dev->reg_state = NETREG_UNREGISTERING;
++              on_each_cpu(flush_backlog, dev, 1);
+       }
+ 
+       synchronize_net();
+@@ -5559,7 +5562,8 @@ static int netif_alloc_netdev_queues(struct net_device 
*dev)
+       struct netdev_queue *tx;
+       size_t sz = count * sizeof(*tx);
+ 
+-      BUG_ON(count < 1 || count > 0xffff);
++      if (count < 1 || count > 0xffff)
++              return -EINVAL;
+ 
+       tx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+       if (!tx) {
+@@ -5917,8 +5921,6 @@ void netdev_run_todo(void)
+ 
+               dev->reg_state = NETREG_UNREGISTERED;
+ 
+-              on_each_cpu(flush_backlog, dev, 1);
+-
+               netdev_wait_allrefs(dev);
+ 
+               /* paranoia */
+diff --git a/net/core/pktgen.c b/net/core/pktgen.c
+index a104ba3c5768..cea47344d535 100644
+--- a/net/core/pktgen.c
++++ b/net/core/pktgen.c
+@@ -3423,8 +3423,10 @@ static int pktgen_thread_worker(void *arg)
+       pktgen_rem_thread(t);
+ 
+       /* Wait for kthread_stop */
+-      while (!kthread_should_stop()) {
++      for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
++              if (kthread_should_stop())
++                      break;
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 76cc27f3f991..fd3a16e45dd9 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -1197,10 +1197,6 @@ static const struct nla_policy 
ifla_info_policy[IFLA_INFO_MAX+1] = {
+       [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
+ };
+ 
+-static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = {
+-      [IFLA_VF_INFO]          = { .type = NLA_NESTED },
+-};
+-
+ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
+       [IFLA_VF_MAC]           = { .len = sizeof(struct ifla_vf_mac) },
+       [IFLA_VF_VLAN]          = { .len = sizeof(struct ifla_vf_vlan) },
+@@ -1274,67 +1270,66 @@ static int validate_linkmsg(struct net_device *dev, 
struct nlattr *tb[])
+       return 0;
+ }
+ 
+-static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
++static int do_setvfinfo(struct net_device *dev, struct nlattr **tb)
+ {
+-      int rem, err = -EINVAL;
+-      struct nlattr *vf;
+       const struct net_device_ops *ops = dev->netdev_ops;
++      int err = -EINVAL;
+ 
+-      nla_for_each_nested(vf, attr, rem) {
+-              switch (nla_type(vf)) {
+-              case IFLA_VF_MAC: {
+-                      struct ifla_vf_mac *ivm;
+-                      ivm = nla_data(vf);
+-                      err = -EOPNOTSUPP;
+-                      if (ops->ndo_set_vf_mac)
+-                              err = ops->ndo_set_vf_mac(dev, ivm->vf,
+-                                                        ivm->mac);
+-                      break;
+-              }
+-              case IFLA_VF_VLAN: {
+-                      struct ifla_vf_vlan *ivv;
+-                      ivv = nla_data(vf);
+-                      err = -EOPNOTSUPP;
+-                      if (ops->ndo_set_vf_vlan)
+-                              err = ops->ndo_set_vf_vlan(dev, ivv->vf,
+-                                                         ivv->vlan,
+-                                                         ivv->qos);
+-                      break;
+-              }
+-              case IFLA_VF_TX_RATE: {
+-                      struct ifla_vf_tx_rate *ivt;
+-                      ivt = nla_data(vf);
+-                      err = -EOPNOTSUPP;
+-                      if (ops->ndo_set_vf_tx_rate)
+-                              err = ops->ndo_set_vf_tx_rate(dev, ivt->vf,
+-                                                            ivt->rate);
+-                      break;
+-              }
+-              case IFLA_VF_SPOOFCHK: {
+-                      struct ifla_vf_spoofchk *ivs;
+-                      ivs = nla_data(vf);
+-                      err = -EOPNOTSUPP;
+-                      if (ops->ndo_set_vf_spoofchk)
+-                              err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
+-                                                             ivs->setting);
+-                      break;
+-              }
+-              case IFLA_VF_LINK_STATE: {
+-                      struct ifla_vf_link_state *ivl;
+-                      ivl = nla_data(vf);
+-                      err = -EOPNOTSUPP;
+-                      if (ops->ndo_set_vf_link_state)
+-                              err = ops->ndo_set_vf_link_state(dev, ivl->vf,
+-                                                               
ivl->link_state);
+-                      break;
+-              }
+-              default:
+-                      err = -EINVAL;
+-                      break;
+-              }
+-              if (err)
+-                      break;
++      if (tb[IFLA_VF_MAC]) {
++              struct ifla_vf_mac *ivm = nla_data(tb[IFLA_VF_MAC]);
++
++              err = -EOPNOTSUPP;
++              if (ops->ndo_set_vf_mac)
++                      err = ops->ndo_set_vf_mac(dev, ivm->vf,
++                                                ivm->mac);
++              if (err < 0)
++                      return err;
++      }
++
++      if (tb[IFLA_VF_VLAN]) {
++              struct ifla_vf_vlan *ivv = nla_data(tb[IFLA_VF_VLAN]);
++
++              err = -EOPNOTSUPP;
++              if (ops->ndo_set_vf_vlan)
++                      err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan,
++                                                 ivv->qos);
++              if (err < 0)
++                      return err;
++      }
++
++      if (tb[IFLA_VF_TX_RATE]) {
++              struct ifla_vf_tx_rate *ivt = nla_data(tb[IFLA_VF_TX_RATE]);
++
++              err = -EOPNOTSUPP;
++              if (ops->ndo_set_vf_tx_rate)
++                      err = ops->ndo_set_vf_tx_rate(dev, ivt->vf,
++                                                    ivt->rate);
++              if (err < 0)
++                      return err;
+       }
++
++      if (tb[IFLA_VF_SPOOFCHK]) {
++              struct ifla_vf_spoofchk *ivs = nla_data(tb[IFLA_VF_SPOOFCHK]);
++
++              err = -EOPNOTSUPP;
++              if (ops->ndo_set_vf_spoofchk)
++                      err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
++                                                     ivs->setting);
++              if (err < 0)
++                      return err;
++      }
++
++      if (tb[IFLA_VF_LINK_STATE]) {
++              struct ifla_vf_link_state *ivl = 
nla_data(tb[IFLA_VF_LINK_STATE]);
++
++              err = -EOPNOTSUPP;
++              if (ops->ndo_set_vf_link_state)
++                      err = ops->ndo_set_vf_link_state(dev, ivl->vf,
++                                                       ivl->link_state);
++              if (err < 0)
++                      return err;
++      }
++
+       return err;
+ }
+ 
+@@ -1517,14 +1512,21 @@ static int do_setlink(const struct sk_buff *skb,
+       }
+ 
+       if (tb[IFLA_VFINFO_LIST]) {
++              struct nlattr *vfinfo[IFLA_VF_MAX + 1];
+               struct nlattr *attr;
+               int rem;
++
+               nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) {
+-                      if (nla_type(attr) != IFLA_VF_INFO) {
++                      if (nla_type(attr) != IFLA_VF_INFO ||
++                          nla_len(attr) < NLA_HDRLEN) {
+                               err = -EINVAL;
+                               goto errout;
+                       }
+-                      err = do_setvfinfo(dev, attr);
++                      err = nla_parse_nested(vfinfo, IFLA_VF_MAX, attr,
++                                             ifla_vf_policy);
++                      if (err < 0)
++                              goto errout;
++                      err = do_setvfinfo(dev, vfinfo);
+                       if (err < 0)
+                               goto errout;
+                       modified = 1;
+diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
+index 5f3dc1df04bf..291b0821d1ac 100644
+--- a/net/ipv4/datagram.c
++++ b/net/ipv4/datagram.c
+@@ -20,7 +20,7 @@
+ #include <net/route.h>
+ #include <net/tcp_states.h>
+ 
+-int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int 
addr_len)
++int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int 
addr_len)
+ {
+       struct inet_sock *inet = inet_sk(sk);
+       struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+@@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr 
*uaddr, int addr_len)
+ 
+       sk_dst_reset(sk);
+ 
+-      lock_sock(sk);
+-
+       oif = sk->sk_bound_dev_if;
+       saddr = inet->inet_saddr;
+       if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
+@@ -81,9 +79,19 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr 
*uaddr, int addr_len)
+       sk_dst_set(sk, &rt->dst);
+       err = 0;
+ out:
+-      release_sock(sk);
+       return err;
+ }
++EXPORT_SYMBOL(__ip4_datagram_connect);
++
++int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int 
addr_len)
++{
++      int res;
++
++      lock_sock(sk);
++      res = __ip4_datagram_connect(sk, uaddr, addr_len);
++      release_sock(sk);
++      return res;
++}
+ EXPORT_SYMBOL(ip4_datagram_connect);
+ 
+ /* Because UDP xmit path can manipulate sk_dst_cache without holding
+diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
+index 4c1884fed548..4d98a6b80b04 100644
+--- a/net/ipv4/ip_fragment.c
++++ b/net/ipv4/ip_fragment.c
+@@ -356,7 +356,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff 
*skb)
+       ihl = ip_hdrlen(skb);
+ 
+       /* Determine the position of this fragment. */
+-      end = offset + skb->len - ihl;
++      end = offset + skb->len - skb_network_offset(skb) - ihl;
+       err = -EINVAL;
+ 
+       /* Is this the final fragment? */
+@@ -386,7 +386,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff 
*skb)
+               goto err;
+ 
+       err = -ENOMEM;
+-      if (pskb_pull(skb, ihl) == NULL)
++      if (!pskb_pull(skb, skb_network_offset(skb) + ihl))
+               goto err;
+ 
+       err = pskb_trim_rcsum(skb, end - offset);
+@@ -627,6 +627,9 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff 
*prev,
+       iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0;
+       iph->tot_len = htons(len);
+       iph->tos |= ecn;
++
++      ip_send_check(iph);
++
+       IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
+       qp->q.fragments = NULL;
+       qp->q.fragments_tail = NULL;
+diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
+index edd5a8171357..6913e2fdc12c 100644
+--- a/net/ipv4/ip_tunnel.c
++++ b/net/ipv4/ip_tunnel.c
+@@ -476,7 +476,8 @@ drop:
+ EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
+ 
+ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
+-                          struct rtable *rt, __be16 df)
++                          struct rtable *rt, __be16 df,
++                          const struct iphdr *inner_iph)
+ {
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+       int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len;
+@@ -493,7 +494,8 @@ static int tnl_update_pmtu(struct net_device *dev, struct 
sk_buff *skb,
+ 
+       if (skb->protocol == htons(ETH_P_IP)) {
+               if (!skb_is_gso(skb) &&
+-                  (df & htons(IP_DF)) && mtu < pkt_size) {
++                  (inner_iph->frag_off & htons(IP_DF)) &&
++                  mtu < pkt_size) {
+                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 
htonl(mtu));
+                       return -E2BIG;
+@@ -611,7 +613,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device 
*dev,
+               goto tx_error;
+       }
+ 
+-      if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off)) {
++      if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph)) {
+               ip_rt_put(rt);
+               goto tx_error;
+       }
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 9f9ad99fcfdd..da44cb4f51d1 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
+       return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0);
+ }
+ 
+-int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int 
addr_len)
++static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, 
int addr_len)
+ {
+       struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
+       struct inet_sock        *inet = inet_sk(sk);
+@@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr 
*uaddr, int addr_len)
+       if (usin->sin6_family == AF_INET) {
+               if (__ipv6_only_sock(sk))
+                       return -EAFNOSUPPORT;
+-              err = ip4_datagram_connect(sk, uaddr, addr_len);
++              err = __ip4_datagram_connect(sk, uaddr, addr_len);
+               goto ipv4_connected;
+       }
+ 
+@@ -99,9 +99,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr 
*uaddr, int addr_len)
+               sin.sin_addr.s_addr = daddr->s6_addr32[3];
+               sin.sin_port = usin->sin6_port;
+ 
+-              err = ip4_datagram_connect(sk,
+-                                         (struct sockaddr *) &sin,
+-                                         sizeof(sin));
++              err = __ip4_datagram_connect(sk,
++                                           (struct sockaddr *) &sin,
++                                           sizeof(sin));
+ 
+ ipv4_connected:
+               if (err)
+@@ -204,6 +204,16 @@ out:
+       fl6_sock_release(flowlabel);
+       return err;
+ }
++
++int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int 
addr_len)
++{
++      int res;
++
++      lock_sock(sk);
++      res = __ip6_datagram_connect(sk, uaddr, addr_len);
++      release_sock(sk);
++      return res;
++}
+ EXPORT_SYMBOL_GPL(ip6_datagram_connect);
+ 
+ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
+index 51d54dc376f3..05c94d9c3776 100644
+--- a/net/ipv6/ip6_input.c
++++ b/net/ipv6/ip6_input.c
+@@ -329,10 +329,10 @@ int ip6_mc_input(struct sk_buff *skb)
+                               if (offset < 0)
+                                       goto out;
+ 
+-                              if (!ipv6_is_mld(skb, nexthdr, offset))
+-                                      goto out;
++                              if (ipv6_is_mld(skb, nexthdr, offset))
++                                      deliver = true;
+ 
+-                              deliver = true;
++                              goto out;
+                       }
+                       /* unknown RA - process it normally */
+               }
+diff --git a/net/netfilter/nf_conntrack_core.c 
b/net/netfilter/nf_conntrack_core.c
+index 5d892febd64c..cf9bfc5ddb34 100644
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -318,6 +318,21 @@ static void death_by_timeout(unsigned long ul_conntrack)
+       nf_ct_delete((struct nf_conn *)ul_conntrack, 0, 0);
+ }
+ 
++static inline bool
++nf_ct_key_equal(struct nf_conntrack_tuple_hash *h,
++                      const struct nf_conntrack_tuple *tuple,
++                      u16 zone)
++{
++      struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
++
++      /* A conntrack can be recreated with the equal tuple,
++       * so we need to check that the conntrack is confirmed
++       */
++      return nf_ct_tuple_equal(tuple, &h->tuple) &&
++              nf_ct_zone(ct) == zone &&
++              nf_ct_is_confirmed(ct);
++}
++
+ /*
+  * Warning :
+  * - Caller must take a reference on returned object
+@@ -339,8 +354,7 @@ ____nf_conntrack_find(struct net *net, u16 zone,
+       local_bh_disable();
+ begin:
+       hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) {
+-              if (nf_ct_tuple_equal(tuple, &h->tuple) &&
+-                  nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
++              if (nf_ct_key_equal(h, tuple, zone)) {
+                       NF_CT_STAT_INC(net, found);
+                       local_bh_enable();
+                       return h;
+@@ -387,8 +401,7 @@ begin:
+                            !atomic_inc_not_zero(&ct->ct_general.use)))
+                       h = NULL;
+               else {
+-                      if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
+-                                   nf_ct_zone(ct) != zone)) {
++                      if (unlikely(!nf_ct_key_equal(h, tuple, zone))) {
+                               nf_ct_put(ct);
+                               goto begin;
+                       }
+@@ -450,7 +463,9 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
+                       goto out;
+ 
+       add_timer(&ct->timeout);
+-      nf_conntrack_get(&ct->ct_general);
++      smp_wmb();
++      /* The caller holds a reference to this object */
++      atomic_set(&ct->ct_general.use, 2);
+       __nf_conntrack_hash_insert(ct, hash, repl_hash);
+       NF_CT_STAT_INC(net, insert);
+       spin_unlock_bh(&nf_conntrack_lock);
+@@ -464,6 +479,21 @@ out:
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
+ 
++/* deletion from this larval template list happens via nf_ct_put() */
++void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
++{
++      __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
++      __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
++      nf_conntrack_get(&tmpl->ct_general);
++
++      spin_lock_bh(&nf_conntrack_lock);
++      /* Overload tuple linked list to put us in template list. */
++      hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
++                               &net->ct.tmpl);
++      spin_unlock_bh(&nf_conntrack_lock);
++}
++EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
++
+ /* Confirm a connection given skb; places it in hash table */
+ int
+ __nf_conntrack_confirm(struct sk_buff *skb)
+@@ -735,11 +765,10 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
+               nf_ct_zone->id = zone;
+       }
+ #endif
+-      /*
+-       * changes to lookup keys must be done before setting refcnt to 1
++      /* Because we use RCU lookups, we set ct_general.use to zero before
++       * this is inserted in any list.
+        */
+-      smp_wmb();
+-      atomic_set(&ct->ct_general.use, 1);
++      atomic_set(&ct->ct_general.use, 0);
+       return ct;
+ 
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+@@ -763,6 +792,11 @@ void nf_conntrack_free(struct nf_conn *ct)
+ {
+       struct net *net = nf_ct_net(ct);
+ 
++      /* A freed object has refcnt == 0, that's
++       * the golden rule for SLAB_DESTROY_BY_RCU
++       */
++      NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 0);
++
+       nf_ct_ext_destroy(ct);
+       atomic_dec(&net->ct.count);
+       nf_ct_ext_free(ct);
+@@ -857,6 +891,9 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
+               NF_CT_STAT_INC(net, new);
+       }
+ 
++      /* Now it is inserted into the unconfirmed list, bump refcount */
++      nf_conntrack_get(&ct->ct_general);
++
+       /* Overload tuple linked list to put us in unconfirmed list. */
+       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                      &net->ct.unconfirmed);
+diff --git a/net/netfilter/nf_synproxy_core.c 
b/net/netfilter/nf_synproxy_core.c
+index cdf4567ba9b3..bf6e9a144dac 100644
+--- a/net/netfilter/nf_synproxy_core.c
++++ b/net/netfilter/nf_synproxy_core.c
+@@ -362,9 +362,8 @@ static int __net_init synproxy_net_init(struct net *net)
+               goto err2;
+       if (!nfct_synproxy_ext_add(ct))
+               goto err2;
+-      __set_bit(IPS_TEMPLATE_BIT, &ct->status);
+-      __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+ 
++      nf_conntrack_tmpl_insert(net, ct);
+       snet->tmpl = ct;
+ 
+       snet->stats = alloc_percpu(struct synproxy_stats);
+@@ -389,7 +388,7 @@ static void __net_exit synproxy_net_exit(struct net *net)
+ {
+       struct synproxy_net *snet = synproxy_pernet(net);
+ 
+-      nf_conntrack_free(snet->tmpl);
++      nf_ct_put(snet->tmpl);
+       synproxy_proc_exit(net);
+       free_percpu(snet->stats);
+ }
+diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
+index da35ac06a975..889960193544 100644
+--- a/net/netfilter/xt_CT.c
++++ b/net/netfilter/xt_CT.c
+@@ -226,12 +226,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param 
*par,
+                       goto err3;
+       }
+ 
+-      __set_bit(IPS_TEMPLATE_BIT, &ct->status);
+-      __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+-
+-      /* Overload tuple linked list to put us in template list. */
+-      hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+-                               &par->net->ct.tmpl);
++      nf_conntrack_tmpl_insert(par->net, ct);
+ out:
+       info->ct = ct;
+       return 0;
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 5a75a1eb3ae7..22e0f478a2a3 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -342,25 +342,52 @@ err1:
+       return NULL;
+ }
+ 
++
++static void
++__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, 
void **pg_vec,
++                 unsigned int order)
++{
++      struct netlink_sock *nlk = nlk_sk(sk);
++      struct sk_buff_head *queue;
++      struct netlink_ring *ring;
++
++      queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
++      ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
++
++      spin_lock_bh(&queue->lock);
++
++      ring->frame_max         = req->nm_frame_nr - 1;
++      ring->head              = 0;
++      ring->frame_size        = req->nm_frame_size;
++      ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
++
++      swap(ring->pg_vec_len, req->nm_block_nr);
++      swap(ring->pg_vec_order, order);
++      swap(ring->pg_vec, pg_vec);
++
++      __skb_queue_purge(queue);
++      spin_unlock_bh(&queue->lock);
++
++      WARN_ON(atomic_read(&nlk->mapped));
++
++      if (pg_vec)
++              free_pg_vec(pg_vec, order, req->nm_block_nr);
++}
++
+ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
+-                          bool closing, bool tx_ring)
++                          bool tx_ring)
+ {
+       struct netlink_sock *nlk = nlk_sk(sk);
+       struct netlink_ring *ring;
+-      struct sk_buff_head *queue;
+       void **pg_vec = NULL;
+       unsigned int order = 0;
+-      int err;
+ 
+       ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
+-      queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
+ 
+-      if (!closing) {
+-              if (atomic_read(&nlk->mapped))
+-                      return -EBUSY;
+-              if (atomic_read(&ring->pending))
+-                      return -EBUSY;
+-      }
++      if (atomic_read(&nlk->mapped))
++              return -EBUSY;
++      if (atomic_read(&ring->pending))
++              return -EBUSY;
+ 
+       if (req->nm_block_nr) {
+               if (ring->pg_vec != NULL)
+@@ -392,31 +419,19 @@ static int netlink_set_ring(struct sock *sk, struct 
nl_mmap_req *req,
+                       return -EINVAL;
+       }
+ 
+-      err = -EBUSY;
+       mutex_lock(&nlk->pg_vec_lock);
+-      if (closing || atomic_read(&nlk->mapped) == 0) {
+-              err = 0;
+-              spin_lock_bh(&queue->lock);
+-
+-              ring->frame_max         = req->nm_frame_nr - 1;
+-              ring->head              = 0;
+-              ring->frame_size        = req->nm_frame_size;
+-              ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
+-
+-              swap(ring->pg_vec_len, req->nm_block_nr);
+-              swap(ring->pg_vec_order, order);
+-              swap(ring->pg_vec, pg_vec);
+-
+-              __skb_queue_purge(queue);
+-              spin_unlock_bh(&queue->lock);
+-
+-              WARN_ON(atomic_read(&nlk->mapped));
++      if (atomic_read(&nlk->mapped) == 0) {
++              __netlink_set_ring(sk, req, tx_ring, pg_vec, order);
++              mutex_unlock(&nlk->pg_vec_lock);
++              return 0;
+       }
++
+       mutex_unlock(&nlk->pg_vec_lock);
+ 
+       if (pg_vec)
+               free_pg_vec(pg_vec, order, req->nm_block_nr);
+-      return err;
++
++      return -EBUSY;
+ }
+ 
+ static void netlink_mm_open(struct vm_area_struct *vma)
+@@ -885,10 +900,10 @@ static void netlink_sock_destruct(struct sock *sk)
+ 
+               memset(&req, 0, sizeof(req));
+               if (nlk->rx_ring.pg_vec)
+-                      netlink_set_ring(sk, &req, true, false);
++                      __netlink_set_ring(sk, &req, false, NULL, 0);
+               memset(&req, 0, sizeof(req));
+               if (nlk->tx_ring.pg_vec)
+-                      netlink_set_ring(sk, &req, true, true);
++                      __netlink_set_ring(sk, &req, true, NULL, 0);
+       }
+ #endif /* CONFIG_NETLINK_MMAP */
+ 
+@@ -2182,7 +2197,7 @@ static int netlink_setsockopt(struct socket *sock, int 
level, int optname,
+                       return -EINVAL;
+               if (copy_from_user(&req, optval, sizeof(req)))
+                       return -EFAULT;
+-              err = netlink_set_ring(sk, &req, false,
++              err = netlink_set_ring(sk, &req,
+                                      optname == NETLINK_TX_RING);
+               break;
+       }
+diff --git a/net/rds/info.c b/net/rds/info.c
+index 9a6b4f66187c..140a44a5f7b7 100644
+--- a/net/rds/info.c
++++ b/net/rds/info.c
+@@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, 
char __user *optval,
+ 
+       /* check for all kinds of wrapping and the like */
+       start = (unsigned long)optval;
+-      if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) {
++      if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
+               ret = -EINVAL;
+               goto out;
+       }
+diff --git a/net/tipc/socket.c b/net/tipc/socket.c
+index dffdbeac18ca..d1233088f953 100644
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -1607,6 +1607,7 @@ static int accept(struct socket *sock, struct socket 
*new_sock, int flags)
+       res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1);
+       if (res)
+               goto exit;
++      security_sk_clone(sock->sk, new_sock->sk);
+ 
+       new_sk = new_sock->sk;
+       new_tsock = tipc_sk(new_sk);

Reply via email to