From: "Alice Ferrazzi" <alicef@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/linux-patches:4.1 commit in: /
Date: Tue, 10 Jan 2017 04:02:25 +0000 (UTC) [thread overview]
Message-ID: <1484021276.3f861dc13e810781883d0f1cfe33a821ee3504f8.alicef@gentoo> (raw)
commit: 3f861dc13e810781883d0f1cfe33a821ee3504f8
Author: Alice Ferrazzi <alicef <AT> gentoo <DOT> org>
AuthorDate: Tue Jan 10 04:07:56 2017 +0000
Commit: Alice Ferrazzi <alicef <AT> gentoo <DOT> org>
CommitDate: Tue Jan 10 04:07:56 2017 +0000
URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=3f861dc1
Linux patch 4.1.37
0000_README | 8 +-
1036_linux-4.1.37.patch | 2732 ++++++++++++++++++++++
1520_fix-race-condition-in-packet-set-ring.patch | 62 -
3 files changed, 2736 insertions(+), 66 deletions(-)
diff --git a/0000_README b/0000_README
index 7e1cb6f..e28d8f1 100644
--- a/0000_README
+++ b/0000_README
@@ -187,6 +187,10 @@ Patch: 1035_linux-4.1.36.patch
From: http://www.kernel.org
Desc: Linux 4.1.36
+Patch: 1036_linux-4.1.37.patch
+From: http://www.kernel.org
+Desc: Linux 4.1.37
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
@@ -195,10 +199,6 @@ Patch: 1510_fs-enable-link-security-restrictions-by-default.patch
From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/
Desc: Enable link security restrictions by default.
-Patch: 1520_fix-race-condition-in-packet-set-ring.patch
-From: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c
-Desc: packet: fix race condition in packet_set_ring. CVE-2016-8655. Bug #601926.
-
Patch: 1800_fix-lru-cache-add-oom-regression.patch
From: http://thread.gmane.org/gmane.linux.kernel.stable/184384
Desc: Revert commit 8f182270dfec mm/swap.c: flush lru pvecs on compound page arrival to fix OOM error.
diff --git a/1036_linux-4.1.37.patch b/1036_linux-4.1.37.patch
new file mode 100644
index 0000000..c9fbe6d
--- /dev/null
+++ b/1036_linux-4.1.37.patch
@@ -0,0 +1,2732 @@
+diff --git a/Documentation/arm/CCN.txt b/Documentation/arm/CCN.txt
+index 0632b3aad83e..715776f06df6 100644
+--- a/Documentation/arm/CCN.txt
++++ b/Documentation/arm/CCN.txt
+@@ -38,7 +38,7 @@ Example of perf tool use:
+ / # perf list | grep ccn
+ ccn/cycles/ [Kernel PMU event]
+ <...>
+- ccn/xp_valid_flit/ [Kernel PMU event]
++ ccn/xp_valid_flit,xp=?,port=?,vc=?,dir=?/ [Kernel PMU event]
+ <...>
+
+ / # perf stat -C 0 -e ccn/cycles/,ccn/xp_valid_flit,xp=1,port=0,vc=1,dir=1/ \
+diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
+index e69274de8d0c..0500895b768f 100644
+--- a/Documentation/filesystems/porting
++++ b/Documentation/filesystems/porting
+@@ -287,8 +287,8 @@ implementing on-disk size changes. Start with a copy of the old inode_setattr
+ and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
+ be in order of zeroing blocks using block_truncate_page or similar helpers,
+ size update and on finally on-disk truncation which should not fail.
+-inode_change_ok now includes the size checks for ATTR_SIZE and must be called
+-in the beginning of ->setattr unconditionally.
++setattr_prepare (which used to be inode_change_ok) now includes the size checks
++for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally.
+
+ [mandatory]
+
+diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
+index 302b5ed616a6..35e17f748ca7 100644
+--- a/Documentation/sysctl/fs.txt
++++ b/Documentation/sysctl/fs.txt
+@@ -265,6 +265,13 @@ aio-nr can grow to.
+
+ ==============================================================
+
++mount-max:
++
++This denotes the maximum number of mounts that may exist
++in a mount namespace.
++
++==============================================================
++
+
+ 2. /proc/sys/fs/binfmt_misc
+ ----------------------------------------------------------
+diff --git a/Makefile b/Makefile
+index aa9fbee620ff..df72b644f78c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 1
+-SUBLEVEL = 36
++SUBLEVEL = 37
+ EXTRAVERSION =
+ NAME = Series 4800
+
+diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
+index b52101d37ec7..ee21eecbe0d2 100644
+--- a/arch/arm/include/asm/dma-mapping.h
++++ b/arch/arm/include/asm/dma-mapping.h
+@@ -117,7 +117,7 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
+ /* The ARM override for dma_max_pfn() */
+ static inline unsigned long dma_max_pfn(struct device *dev)
+ {
+- return PHYS_PFN_OFFSET + dma_to_pfn(dev, *dev->dma_mask);
++ return dma_to_pfn(dev, *dev->dma_mask);
+ }
+ #define dma_max_pfn(dev) dma_max_pfn(dev)
+
+diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
+index cd791948b286..7e459b7ee708 100644
+--- a/arch/x86/include/asm/tlbflush.h
++++ b/arch/x86/include/asm/tlbflush.h
+@@ -32,7 +32,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
+ /* Initialize cr4 shadow for this CPU. */
+ static inline void cr4_init_shadow(void)
+ {
+- this_cpu_write(cpu_tlbstate.cr4, __read_cr4());
++ this_cpu_write(cpu_tlbstate.cr4, __read_cr4_safe());
+ }
+
+ /* Set in this cpu's CR4. */
+diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile
+index 2c835e356349..d445c5f1aeb1 100644
+--- a/arch/x86/purgatory/Makefile
++++ b/arch/x86/purgatory/Makefile
+@@ -12,6 +12,7 @@ targets += purgatory.ro
+
+ KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes -fno-zero-initialized-in-bss -fno-builtin -ffreestanding -c -MD -Os -mcmodel=large
+ KBUILD_CFLAGS += -m$(BITS)
++KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
+
+ $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
+ $(call if_changed,ld)
+diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c
+index 27fd0dacad5f..4d523cfe51ce 100644
+--- a/drivers/bus/arm-ccn.c
++++ b/drivers/bus/arm-ccn.c
+@@ -183,6 +183,7 @@ struct arm_ccn {
+ struct arm_ccn_component *xp;
+
+ struct arm_ccn_dt dt;
++ int mn_id;
+ };
+
+
+@@ -322,6 +323,7 @@ struct arm_ccn_pmu_event {
+ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
++ struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev));
+ struct arm_ccn_pmu_event *event = container_of(attr,
+ struct arm_ccn_pmu_event, attr);
+ ssize_t res;
+@@ -336,6 +338,26 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
+ if (event->mask)
+ res += snprintf(buf + res, PAGE_SIZE - res, ",mask=0x%x",
+ event->mask);
++
++ /* Arguments required by an event */
++ switch (event->type) {
++ case CCN_TYPE_CYCLES:
++ break;
++ case CCN_TYPE_XP:
++ res += snprintf(buf + res, PAGE_SIZE - res,
++ ",xp=?,port=?,vc=?,dir=?");
++ if (event->event == CCN_EVENT_WATCHPOINT)
++ res += snprintf(buf + res, PAGE_SIZE - res,
++ ",cmp_l=?,cmp_h=?,mask=?");
++ break;
++ case CCN_TYPE_MN:
++ res += snprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id);
++ break;
++ default:
++ res += snprintf(buf + res, PAGE_SIZE - res, ",node=?");
++ break;
++ }
++
+ res += snprintf(buf + res, PAGE_SIZE - res, "\n");
+
+ return res;
+@@ -360,9 +382,9 @@ static umode_t arm_ccn_pmu_events_is_visible(struct kobject *kobj,
+ }
+
+ static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = {
+- CCN_EVENT_MN(eobarrier, "dir=0,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
+- CCN_EVENT_MN(ecbarrier, "dir=0,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
+- CCN_EVENT_MN(dvmop, "dir=0,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
++ CCN_EVENT_MN(eobarrier, "dir=1,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
++ CCN_EVENT_MN(ecbarrier, "dir=1,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
++ CCN_EVENT_MN(dvmop, "dir=1,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
+ CCN_EVENT_HNI(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY),
+ CCN_EVENT_HNI(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY),
+ CCN_EVENT_HNI(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY),
+@@ -649,6 +671,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
+
+ /* Validate node/xp vs topology */
+ switch (type) {
++ case CCN_TYPE_MN:
++ if (node_xp != ccn->mn_id) {
++ dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp);
++ return -EINVAL;
++ }
++ break;
+ case CCN_TYPE_XP:
+ if (node_xp >= ccn->num_xps) {
+ dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp);
+@@ -1214,6 +1242,8 @@ static int arm_ccn_init_nodes(struct arm_ccn *ccn, int region,
+
+ switch (type) {
+ case CCN_TYPE_MN:
++ ccn->mn_id = id;
++ return 0;
+ case CCN_TYPE_DT:
+ return 0;
+ case CCN_TYPE_XP:
+diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
+index cd0554f68316..4ff8c334e7c8 100644
+--- a/drivers/gpu/drm/msm/msm_gem_submit.c
++++ b/drivers/gpu/drm/msm/msm_gem_submit.c
+@@ -55,6 +55,14 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
+ return submit;
+ }
+
++static inline unsigned long __must_check
++copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
++{
++ if (access_ok(VERIFY_READ, from, n))
++ return __copy_from_user_inatomic(to, from, n);
++ return -EFAULT;
++}
++
+ static int submit_lookup_objects(struct msm_gem_submit *submit,
+ struct drm_msm_gem_submit *args, struct drm_file *file)
+ {
+@@ -62,6 +70,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
+ int ret = 0;
+
+ spin_lock(&file->table_lock);
++ pagefault_disable();
+
+ for (i = 0; i < args->nr_bos; i++) {
+ struct drm_msm_gem_submit_bo submit_bo;
+@@ -70,10 +79,15 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
+ void __user *userptr =
+ to_user_ptr(args->bos + (i * sizeof(submit_bo)));
+
+- ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
+- if (ret) {
+- ret = -EFAULT;
+- goto out_unlock;
++ ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo));
++ if (unlikely(ret)) {
++ pagefault_enable();
++ spin_unlock(&file->table_lock);
++ ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
++ if (ret)
++ goto out;
++ spin_lock(&file->table_lock);
++ pagefault_disable();
+ }
+
+ if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
+@@ -113,9 +127,12 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
+ }
+
+ out_unlock:
+- submit->nr_bos = i;
++ pagefault_enable();
+ spin_unlock(&file->table_lock);
+
++out:
++ submit->nr_bos = i;
++
+ return ret;
+ }
+
+diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
+index feb6d18de78d..16970fccc5cd 100644
+--- a/drivers/mtd/nand/davinci_nand.c
++++ b/drivers/mtd/nand/davinci_nand.c
+@@ -241,6 +241,9 @@ static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
+ unsigned long flags;
+ u32 val;
+
++ /* Reset ECC hardware */
++ davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
++
+ spin_lock_irqsave(&davinci_nand_lock, flags);
+
+ /* Start 4-bit ECC calculation for read/write */
+diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
+index ad535a854e5c..eab132778e67 100644
+--- a/drivers/net/can/dev.c
++++ b/drivers/net/can/dev.c
+@@ -21,6 +21,7 @@
+ #include <linux/slab.h>
+ #include <linux/netdevice.h>
+ #include <linux/if_arp.h>
++#include <linux/workqueue.h>
+ #include <linux/can.h>
+ #include <linux/can/dev.h>
+ #include <linux/can/skb.h>
+@@ -471,9 +472,8 @@ EXPORT_SYMBOL_GPL(can_free_echo_skb);
+ /*
+ * CAN device restart for bus-off recovery
+ */
+-static void can_restart(unsigned long data)
++static void can_restart(struct net_device *dev)
+ {
+- struct net_device *dev = (struct net_device *)data;
+ struct can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct sk_buff *skb;
+@@ -513,6 +513,14 @@ restart:
+ netdev_err(dev, "Error %d during restart", err);
+ }
+
++static void can_restart_work(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct can_priv *priv = container_of(dwork, struct can_priv, restart_work);
++
++ can_restart(priv->dev);
++}
++
+ int can_restart_now(struct net_device *dev)
+ {
+ struct can_priv *priv = netdev_priv(dev);
+@@ -526,8 +534,8 @@ int can_restart_now(struct net_device *dev)
+ if (priv->state != CAN_STATE_BUS_OFF)
+ return -EBUSY;
+
+- /* Runs as soon as possible in the timer context */
+- mod_timer(&priv->restart_timer, jiffies);
++ cancel_delayed_work_sync(&priv->restart_work);
++ can_restart(dev);
+
+ return 0;
+ }
+@@ -548,8 +556,8 @@ void can_bus_off(struct net_device *dev)
+ netif_carrier_off(dev);
+
+ if (priv->restart_ms)
+- mod_timer(&priv->restart_timer,
+- jiffies + (priv->restart_ms * HZ) / 1000);
++ schedule_delayed_work(&priv->restart_work,
++ msecs_to_jiffies(priv->restart_ms));
+ }
+ EXPORT_SYMBOL_GPL(can_bus_off);
+
+@@ -658,6 +666,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
+ return NULL;
+
+ priv = netdev_priv(dev);
++ priv->dev = dev;
+
+ if (echo_skb_max) {
+ priv->echo_skb_max = echo_skb_max;
+@@ -667,7 +676,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
+
+ priv->state = CAN_STATE_STOPPED;
+
+- init_timer(&priv->restart_timer);
++ INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
+
+ return dev;
+ }
+@@ -748,8 +757,6 @@ int open_candev(struct net_device *dev)
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+
+- setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);
+-
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(open_candev);
+@@ -764,7 +771,7 @@ void close_candev(struct net_device *dev)
+ {
+ struct can_priv *priv = netdev_priv(dev);
+
+- del_timer_sync(&priv->restart_timer);
++ cancel_delayed_work_sync(&priv->restart_work);
+ can_flush_echo_skb(dev);
+ }
+ EXPORT_SYMBOL_GPL(close_candev);
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
+index 940f78e41993..d9e873c3a273 100644
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -635,7 +635,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
+ }
+ }
+
+- pp = eth_gro_receive(head, skb);
++ pp = call_gro_receive(eth_gro_receive, head, skb);
+
+ out:
+ skb_gro_remcsum_cleanup(skb, &grc);
+diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
+index 2926295a936d..c9f87cdc85c1 100644
+--- a/drivers/scsi/arcmsr/arcmsr_hba.c
++++ b/drivers/scsi/arcmsr/arcmsr_hba.c
+@@ -2300,7 +2300,8 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+ }
+ case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
+ unsigned char *ver_addr;
+- int32_t user_len, cnt2end;
++ uint32_t user_len;
++ int32_t cnt2end;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+ ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC);
+ if (!ver_addr) {
+@@ -2309,6 +2310,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+ }
+ ptmpuserbuffer = ver_addr;
+ user_len = pcmdmessagefld->cmdmessage.Length;
++ if (user_len > ARCMSR_API_DATA_BUFLEN) {
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ kfree(ver_addr);
++ goto message_out;
++ }
+ memcpy(ptmpuserbuffer,
+ pcmdmessagefld->messagedatabuffer, user_len);
+ spin_lock_irqsave(&acb->wqbuffer_lock, flags);
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 14e5c7cea929..1fcd31c6b37b 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1862,7 +1862,7 @@ struct megasas_instance_template {
+ };
+
+ #define MEGASAS_IS_LOGICAL(scp) \
+- (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
++ ((scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
+
+ #define MEGASAS_DEV_INDEX(inst, scp) \
+ ((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + \
+diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
+index a27af7882170..d60425996948 100644
+--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
++++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
+@@ -1323,7 +1323,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
+ attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
+ }
+
+- /* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
++ /* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
+ if (attr->ia_valid & TIMES_SET_FLAGS) {
+ if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
+ !capable(CFS_CAP_FOWNER))
+diff --git a/fs/9p/acl.c b/fs/9p/acl.c
+index 31c010372660..de59b4892bfb 100644
+--- a/fs/9p/acl.c
++++ b/fs/9p/acl.c
+@@ -320,32 +320,26 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+- umode_t mode = inode->i_mode;
+- retval = posix_acl_equiv_mode(acl, &mode);
+- if (retval < 0)
++ struct iattr iattr;
++
++ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
++ if (retval)
+ goto err_out;
+- else {
+- struct iattr iattr;
+- if (retval == 0) {
+- /*
+- * ACL can be represented
+- * by the mode bits. So don't
+- * update ACL.
+- */
+- acl = NULL;
+- value = NULL;
+- size = 0;
+- }
+- /* Updte the mode bits */
+- iattr.ia_mode = ((mode & S_IALLUGO) |
+- (inode->i_mode & ~S_IALLUGO));
+- iattr.ia_valid = ATTR_MODE;
+- /* FIXME should we update ctime ?
+- * What is the following setxattr update the
+- * mode ?
++ if (!acl) {
++ /*
++ * ACL can be represented
++ * by the mode bits. So don't
++ * update ACL.
+ */
+- v9fs_vfs_setattr_dotl(dentry, &iattr);
++ value = NULL;
++ size = 0;
+ }
++ iattr.ia_valid = ATTR_MODE;
++ /* FIXME should we update ctime ?
++ * What is the following setxattr update the
++ * mode ?
++ */
++ v9fs_vfs_setattr_dotl(dentry, &iattr);
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
+index 53f1e8a21707..99c3c4ffe1d9 100644
+--- a/fs/9p/vfs_inode.c
++++ b/fs/9p/vfs_inode.c
+@@ -1094,7 +1094,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
+ struct p9_wstat wstat;
+
+ p9_debug(P9_DEBUG_VFS, "\n");
+- retval = inode_change_ok(d_inode(dentry), iattr);
++ retval = setattr_prepare(dentry, iattr);
+ if (retval)
+ return retval;
+
+diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
+index 4d3ecfb55fcf..ce7ab92f7e84 100644
+--- a/fs/9p/vfs_inode_dotl.c
++++ b/fs/9p/vfs_inode_dotl.c
+@@ -560,7 +560,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
+
+ p9_debug(P9_DEBUG_VFS, "\n");
+
+- retval = inode_change_ok(inode, iattr);
++ retval = setattr_prepare(dentry, iattr);
+ if (retval)
+ return retval;
+
+diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
+index 335055d828e4..f57baaa511aa 100644
+--- a/fs/adfs/inode.c
++++ b/fs/adfs/inode.c
+@@ -303,7 +303,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
+ unsigned int ia_valid = attr->ia_valid;
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+
+ /*
+ * we can't change the UID or GID of any file -
+diff --git a/fs/affs/inode.c b/fs/affs/inode.c
+index a022f4accd76..87953b94a5ae 100644
+--- a/fs/affs/inode.c
++++ b/fs/affs/inode.c
+@@ -218,7 +218,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
+
+ pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);
+
+- error = inode_change_ok(inode,attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ goto out;
+
+diff --git a/fs/attr.c b/fs/attr.c
+index 6530ced19697..ee697ddc6c2e 100644
+--- a/fs/attr.c
++++ b/fs/attr.c
+@@ -17,19 +17,22 @@
+ #include <linux/ima.h>
+
+ /**
+- * inode_change_ok - check if attribute changes to an inode are allowed
+- * @inode: inode to check
++ * setattr_prepare - check if attribute changes to a dentry are allowed
++ * @dentry: dentry to check
+ * @attr: attributes to change
+ *
+ * Check if we are allowed to change the attributes contained in @attr
+- * in the given inode. This includes the normal unix access permission
+- * checks, as well as checks for rlimits and others.
++ * in the given dentry. This includes the normal unix access permission
++ * checks, as well as checks for rlimits and others. The function also clears
++ * SGID bit from mode if user is not allowed to set it. Also file capabilities
++ * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
+ *
+ * Should be called as the first thing in ->setattr implementations,
+ * possibly after taking additional locks.
+ */
+-int inode_change_ok(const struct inode *inode, struct iattr *attr)
++int setattr_prepare(struct dentry *dentry, struct iattr *attr)
+ {
++ struct inode *inode = d_inode(dentry);
+ unsigned int ia_valid = attr->ia_valid;
+
+ /*
+@@ -44,7 +47,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
+
+ /* If force is set do it anyway. */
+ if (ia_valid & ATTR_FORCE)
+- return 0;
++ goto kill_priv;
+
+ /* Make sure a caller can chown. */
+ if ((ia_valid & ATTR_UID) &&
+@@ -77,9 +80,19 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
+ return -EPERM;
+ }
+
++kill_priv:
++ /* User has permission for the change */
++ if (ia_valid & ATTR_KILL_PRIV) {
++ int error;
++
++ error = security_inode_killpriv(dentry);
++ if (error)
++ return error;
++ }
++
+ return 0;
+ }
+-EXPORT_SYMBOL(inode_change_ok);
++EXPORT_SYMBOL(setattr_prepare);
+
+ /**
+ * inode_newsize_ok - may this inode be truncated to a given size
+@@ -217,13 +230,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
+ if (!(ia_valid & ATTR_MTIME_SET))
+ attr->ia_mtime = now;
+ if (ia_valid & ATTR_KILL_PRIV) {
+- attr->ia_valid &= ~ATTR_KILL_PRIV;
+- ia_valid &= ~ATTR_KILL_PRIV;
+ error = security_inode_need_killpriv(dentry);
+- if (error > 0)
+- error = security_inode_killpriv(dentry);
+- if (error)
++ if (error < 0)
+ return error;
++ if (error == 0)
++ ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
+ }
+
+ /*
+diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
+index 9a0124a95851..fb3e64d37cb4 100644
+--- a/fs/btrfs/acl.c
++++ b/fs/btrfs/acl.c
+@@ -83,11 +83,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (ret < 0)
++ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (ret)
+ return ret;
+- if (ret == 0)
+- acl = NULL;
+ }
+ ret = 0;
+ break;
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index c4771af7fd6f..757a34bdd2b9 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4975,7 +4975,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
+index 64fa248343f6..d7496e3dbfc4 100644
+--- a/fs/ceph/acl.c
++++ b/fs/ceph/acl.c
+@@ -94,11 +94,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+- ret = posix_acl_equiv_mode(acl, &new_mode);
+- if (ret < 0)
++ ret = posix_acl_update_mode(inode, &new_mode, &acl);
++ if (ret)
+ goto out;
+- if (ret == 0)
+- acl = NULL;
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
+index e876e1944519..4484aaf5c478 100644
+--- a/fs/ceph/inode.c
++++ b/fs/ceph/inode.c
+@@ -1728,7 +1728,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err != 0)
+ return err;
+
+diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
+index 9fb3bc26a2ab..f82dfe7ae3e8 100644
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -2134,7 +2134,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ attrs->ia_valid |= ATTR_FORCE;
+
+- rc = inode_change_ok(inode, attrs);
++ rc = setattr_prepare(direntry, attrs);
+ if (rc < 0)
+ goto out;
+
+@@ -2274,7 +2274,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ attrs->ia_valid |= ATTR_FORCE;
+
+- rc = inode_change_ok(inode, attrs);
++ rc = setattr_prepare(direntry, attrs);
+ if (rc < 0) {
+ free_xid(xid);
+ return rc;
+diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
+index fc850b55db67..661dd53f0040 100644
+--- a/fs/ecryptfs/inode.c
++++ b/fs/ecryptfs/inode.c
+@@ -942,7 +942,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
+ }
+ mutex_unlock(&crypt_stat->cs_mutex);
+
+- rc = inode_change_ok(inode, ia);
++ rc = setattr_prepare(dentry, ia);
+ if (rc)
+ goto out;
+ if (ia->ia_valid & ATTR_SIZE) {
+diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
+index 786e4cc8c889..159c30c18395 100644
+--- a/fs/exofs/inode.c
++++ b/fs/exofs/inode.c
+@@ -1038,7 +1038,7 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
+ if (unlikely(error))
+ return error;
+
+- error = inode_change_ok(inode, iattr);
++ error = setattr_prepare(dentry, iattr);
+ if (unlikely(error))
+ return error;
+
+diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
+index 27695e6f4e46..d6aeb84e90b6 100644
+--- a/fs/ext2/acl.c
++++ b/fs/ext2/acl.c
+@@ -193,15 +193,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ case ACL_TYPE_ACCESS:
+ name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
+ if (acl) {
+- error = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (error < 0)
++ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (error)
+ return error;
+- else {
+- inode->i_ctime = CURRENT_TIME_SEC;
+- mark_inode_dirty(inode);
+- if (error == 0)
+- acl = NULL;
+- }
++ inode->i_ctime = CURRENT_TIME_SEC;
++ mark_inode_dirty(inode);
+ }
+ break;
+
+diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
+index f460ae36d5b7..f08604366cb5 100644
+--- a/fs/ext2/inode.c
++++ b/fs/ext2/inode.c
+@@ -1547,7 +1547,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, iattr);
++ error = setattr_prepare(dentry, iattr);
+ if (error)
+ return error;
+
+diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
+index 2ee2dc4351d1..3613e87c688f 100644
+--- a/fs/ext3/inode.c
++++ b/fs/ext3/inode.c
+@@ -3244,7 +3244,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
+ int error, rc = 0;
+ const unsigned int ia_valid = attr->ia_valid;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
+index 69b1e73026a5..c3fe1e323951 100644
+--- a/fs/ext4/acl.c
++++ b/fs/ext4/acl.c
+@@ -196,15 +196,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
+ case ACL_TYPE_ACCESS:
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
+ if (acl) {
+- error = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (error < 0)
++ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (error)
+ return error;
+- else {
+- inode->i_ctime = ext4_current_time(inode);
+- ext4_mark_inode_dirty(handle, inode);
+- if (error == 0)
+- acl = NULL;
+- }
++ inode->i_ctime = ext4_current_time(inode);
++ ext4_mark_inode_dirty(handle, inode);
+ }
+ break;
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 15213a567301..145d6ba4117d 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1008,6 +1008,7 @@ struct ext4_inode_info {
+ /*
+ * Mount flags set via mount options or defaults
+ */
++#define EXT4_MOUNT_NO_MBCACHE 0x00001 /* Disable mbcache */
+ #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
+ #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
+ #define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 9b55c6f71bf2..5beca5c5413e 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4751,7 +4751,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
+ int orphan = 0;
+ const unsigned int ia_valid = attr->ia_valid;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index afb3eb3e8b0f..4723d8b02747 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1144,6 +1144,7 @@ enum {
+ Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
+ Opt_inode_readahead_blks, Opt_journal_ioprio,
+ Opt_dioread_nolock, Opt_dioread_lock,
++ Opt_no_mbcache,
+ Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
+ Opt_max_dir_size_kb, Opt_nojournal_checksum,
+ };
+@@ -1222,6 +1223,7 @@ static const match_table_t tokens = {
+ {Opt_discard, "discard"},
+ {Opt_nodiscard, "nodiscard"},
+ {Opt_init_itable, "init_itable=%u"},
++ {Opt_no_mbcache, "no_mbcache"},
+ {Opt_init_itable, "init_itable"},
+ {Opt_noinit_itable, "noinit_itable"},
+ {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
+@@ -1385,6 +1387,7 @@ static const struct mount_opts {
+ {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
+ {Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
+ {Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR},
++ {Opt_no_mbcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
+ {Opt_commit, 0, MOPT_GTE0},
+ {Opt_max_batch_time, 0, MOPT_GTE0},
+ {Opt_min_batch_time, 0, MOPT_GTE0},
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index 16e28c08d1e8..cdc26e54400f 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -80,7 +80,7 @@
+ # define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+ #endif
+
+-static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
++static void ext4_xattr_cache_insert(struct inode *, struct buffer_head *);
+ static struct buffer_head *ext4_xattr_cache_find(struct inode *,
+ struct ext4_xattr_header *,
+ struct mb_cache_entry **);
+@@ -278,7 +278,6 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
+ struct ext4_xattr_entry *entry;
+ size_t size;
+ int error;
+- struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+
+ ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
+ name_index, name, buffer, (long)buffer_size);
+@@ -300,7 +299,7 @@ bad_block:
+ error = -EIO;
+ goto cleanup;
+ }
+- ext4_xattr_cache_insert(ext4_mb_cache, bh);
++ ext4_xattr_cache_insert(inode, bh);
+ entry = BFIRST(bh);
+ error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
+ if (error == -EIO)
+@@ -426,7 +425,6 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
+ struct inode *inode = d_inode(dentry);
+ struct buffer_head *bh = NULL;
+ int error;
+- struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+
+ ea_idebug(inode, "buffer=%p, buffer_size=%ld",
+ buffer, (long)buffer_size);
+@@ -448,7 +446,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
+ error = -EIO;
+ goto cleanup;
+ }
+- ext4_xattr_cache_insert(ext4_mb_cache, bh);
++ ext4_xattr_cache_insert(inode, bh);
+ error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
+
+ cleanup:
+@@ -547,7 +545,8 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
+ int error = 0;
+ struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+
+- ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
++ if (!test_opt(inode->i_sb, NO_MBCACHE))
++ ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
+ BUFFER_TRACE(bh, "get_write_access");
+ error = ext4_journal_get_write_access(handle, bh);
+ if (error)
+@@ -788,8 +787,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+ if (i->value && i->value_len > sb->s_blocksize)
+ return -ENOSPC;
+ if (s->base) {
+- ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
+- bs->bh->b_blocknr);
++ if (!test_opt(inode->i_sb, NO_MBCACHE))
++ ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
++ bs->bh->b_blocknr);
+ BUFFER_TRACE(bs->bh, "get_write_access");
+ error = ext4_journal_get_write_access(handle, bs->bh);
+ if (error)
+@@ -807,7 +807,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+ if (!IS_LAST_ENTRY(s->first))
+ ext4_xattr_rehash(header(s->base),
+ s->here);
+- ext4_xattr_cache_insert(ext4_mb_cache,
++ ext4_xattr_cache_insert(inode,
+ bs->bh);
+ }
+ unlock_buffer(bs->bh);
+@@ -892,7 +892,8 @@ inserted:
+ if (error)
+ goto cleanup_dquot;
+ }
+- mb_cache_entry_release(ce);
++ if (ce)
++ mb_cache_entry_release(ce);
+ ce = NULL;
+ } else if (bs->bh && s->base == bs->bh->b_data) {
+ /* We were modifying this block in-place. */
+@@ -939,7 +940,7 @@ getblk_failed:
+ memcpy(new_bh->b_data, s->base, new_bh->b_size);
+ set_buffer_uptodate(new_bh);
+ unlock_buffer(new_bh);
+- ext4_xattr_cache_insert(ext4_mb_cache, new_bh);
++ ext4_xattr_cache_insert(inode, new_bh);
+ error = ext4_handle_dirty_xattr_block(handle,
+ inode, new_bh);
+ if (error)
+@@ -1529,12 +1530,17 @@ ext4_xattr_put_super(struct super_block *sb)
+ * Returns 0, or a negative error number on failure.
+ */
+ static void
+-ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh)
++ext4_xattr_cache_insert(struct inode *inode, struct buffer_head *bh)
+ {
++ struct super_block *sb = inode->i_sb;
++ struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+ __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
+ struct mb_cache_entry *ce;
+ int error;
+
++ if (test_opt(sb, NO_MBCACHE))
++ return;
++
+ ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
+ if (!ce) {
+ ea_bdebug(bh, "out of memory");
+@@ -1609,6 +1615,8 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
+ struct mb_cache_entry *ce;
+ struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+
++ if (test_opt(inode->i_sb, NO_MBCACHE))
++ return NULL;
+ if (!header->h_hash)
+ return NULL; /* never share */
+ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
+diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
+index 4320ffab3495..c5e4a1856a0f 100644
+--- a/fs/f2fs/acl.c
++++ b/fs/f2fs/acl.c
+@@ -214,12 +214,10 @@ static int __f2fs_set_acl(struct inode *inode, int type,
+ case ACL_TYPE_ACCESS:
+ name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
+ if (acl) {
+- error = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (error < 0)
++ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (error)
+ return error;
+ set_acl_inode(fi, inode->i_mode);
+- if (error == 0)
+- acl = NULL;
+ }
+ break;
+
+diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
+index 2b52e48d7482..85e40c0fdcc4 100644
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -617,7 +617,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ int err;
+
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+diff --git a/fs/fat/file.c b/fs/fat/file.c
+index 442d50a0e33e..5d37650483c6 100644
+--- a/fs/fat/file.c
++++ b/fs/fat/file.c
+@@ -388,7 +388,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
+ attr->ia_valid &= ~TIMES_SET_FLAGS;
+ }
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ attr->ia_valid = ia_valid;
+ if (error) {
+ if (sbi->options.quiet)
+diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
+index 0572bca49f15..88b09a33d117 100644
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -1602,9 +1602,10 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
+ * vmtruncate() doesn't allow for this case, so do the rlimit checking
+ * and the actual truncation by hand.
+ */
+-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
++int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
+ struct file *file)
+ {
++ struct inode *inode = d_inode(dentry);
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ FUSE_ARGS(args);
+@@ -1619,7 +1620,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
+ if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
+ attr->ia_valid |= ATTR_FORCE;
+
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+@@ -1718,9 +1719,9 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
+ return -EACCES;
+
+ if (attr->ia_valid & ATTR_FILE)
+- return fuse_do_setattr(inode, attr, attr->ia_file);
++ return fuse_do_setattr(entry, attr, attr->ia_file);
+ else
+- return fuse_do_setattr(inode, attr, NULL);
++ return fuse_do_setattr(entry, attr, NULL);
+ }
+
+ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
+diff --git a/fs/fuse/file.c b/fs/fuse/file.c
+index d8f29ef2d819..1f03f0a36e35 100644
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -2797,7 +2797,7 @@ static void fuse_do_truncate(struct file *file)
+ attr.ia_file = file;
+ attr.ia_valid |= ATTR_FILE;
+
+- fuse_do_setattr(inode, &attr, file);
++ fuse_do_setattr(file->f_path.dentry, &attr, file);
+ }
+
+ static inline loff_t fuse_round_up(loff_t off)
+diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
+index 85f9d8273455..30d2bde45f68 100644
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -913,7 +913,7 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos);
+ int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
+ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
+
+-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
++int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
+ struct file *file);
+
+ void fuse_set_initialized(struct fuse_conn *fc);
+diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
+index 1be3b061c05c..ff0ac96a8e7b 100644
+--- a/fs/gfs2/acl.c
++++ b/fs/gfs2/acl.c
+@@ -79,17 +79,11 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ if (type == ACL_TYPE_ACCESS) {
+ umode_t mode = inode->i_mode;
+
+- error = posix_acl_equiv_mode(acl, &mode);
+- if (error < 0)
++ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (error)
+ return error;
+-
+- if (error == 0)
+- acl = NULL;
+-
+- if (mode != inode->i_mode) {
+- inode->i_mode = mode;
++ if (mode != inode->i_mode)
+ mark_inode_dirty(inode);
+- }
+ }
+
+ if (acl) {
+diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
+index 1b3ca7a2e3fc..6f7f848a3c4e 100644
+--- a/fs/gfs2/inode.c
++++ b/fs/gfs2/inode.c
+@@ -1759,7 +1759,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ goto out;
+
+diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
+index b99ebddb10cb..6409b8b4afd4 100644
+--- a/fs/hfs/inode.c
++++ b/fs/hfs/inode.c
+@@ -604,7 +604,7 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
+ struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
+ int error;
+
+- error = inode_change_ok(inode, attr); /* basic permission checks */
++ error = setattr_prepare(dentry, attr); /* basic permission checks */
+ if (error)
+ return error;
+
+diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
+index 6dd107d7421e..d87c8a27e063 100644
+--- a/fs/hfsplus/inode.c
++++ b/fs/hfsplus/inode.c
+@@ -246,7 +246,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
+index df0c9af68d05..71b3087b7e32 100644
+--- a/fs/hfsplus/posix_acl.c
++++ b/fs/hfsplus/posix_acl.c
+@@ -68,8 +68,8 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
+ case ACL_TYPE_ACCESS:
+ xattr_name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+- err = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (err < 0)
++ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (err)
+ return err;
+ }
+ err = 0;
+diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
+index f895a85d9304..81ce4e4ad0f9 100644
+--- a/fs/hostfs/hostfs_kern.c
++++ b/fs/hostfs/hostfs_kern.c
+@@ -812,7 +812,7 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
+
+ int fd = HOSTFS_I(inode)->fd;
+
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
+index 933c73780813..efbed9520fdc 100644
+--- a/fs/hpfs/inode.c
++++ b/fs/hpfs/inode.c
+@@ -272,7 +272,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
+ if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
+ goto out_unlock;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ goto out_unlock;
+
+diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
+index 87724c1d7be6..a533d8c66489 100644
+--- a/fs/hugetlbfs/inode.c
++++ b/fs/hugetlbfs/inode.c
+@@ -400,7 +400,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
+
+ BUG_ON(!inode);
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
+index 2f7a3c090489..f9f86f87d32b 100644
+--- a/fs/jffs2/acl.c
++++ b/fs/jffs2/acl.c
+@@ -235,9 +235,10 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ case ACL_TYPE_ACCESS:
+ xprefix = JFFS2_XPREFIX_ACL_ACCESS;
+ if (acl) {
+- umode_t mode = inode->i_mode;
+- rc = posix_acl_equiv_mode(acl, &mode);
+- if (rc < 0)
++ umode_t mode;
++
++ rc = posix_acl_update_mode(inode, &mode, &acl);
++ if (rc)
+ return rc;
+ if (inode->i_mode != mode) {
+ struct iattr attr;
+@@ -249,8 +250,6 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ if (rc < 0)
+ return rc;
+ }
+- if (rc == 0)
+- acl = NULL;
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
+index fe5ea080b4ec..6273abad377f 100644
+--- a/fs/jffs2/fs.c
++++ b/fs/jffs2/fs.c
+@@ -193,7 +193,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
+ struct inode *inode = d_inode(dentry);
+ int rc;
+
+- rc = inode_change_ok(inode, iattr);
++ rc = setattr_prepare(dentry, iattr);
+ if (rc)
+ return rc;
+
+diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
+index 0c8ca830b113..9fad9f4fe883 100644
+--- a/fs/jfs/acl.c
++++ b/fs/jfs/acl.c
+@@ -84,13 +84,11 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
+ case ACL_TYPE_ACCESS:
+ ea_name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (rc < 0)
++ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (rc)
+ return rc;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+- if (rc == 0)
+- acl = NULL;
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+diff --git a/fs/jfs/file.c b/fs/jfs/file.c
+index e98d39d75cf4..66d6362a9007 100644
+--- a/fs/jfs/file.c
++++ b/fs/jfs/file.c
+@@ -103,7 +103,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
+ struct inode *inode = d_inode(dentry);
+ int rc;
+
+- rc = inode_change_ok(inode, iattr);
++ rc = setattr_prepare(dentry, iattr);
+ if (rc)
+ return rc;
+
+diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
+index 756dd56aaf60..a17c850a4958 100644
+--- a/fs/kernfs/inode.c
++++ b/fs/kernfs/inode.c
+@@ -119,7 +119,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
+ return -EINVAL;
+
+ mutex_lock(&kernfs_mutex);
+- error = inode_change_ok(inode, iattr);
++ error = setattr_prepare(dentry, iattr);
+ if (error)
+ goto out;
+
+diff --git a/fs/libfs.c b/fs/libfs.c
+index f4641fd27bda..50edbdc23cef 100644
+--- a/fs/libfs.c
++++ b/fs/libfs.c
+@@ -371,7 +371,7 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, iattr);
++ error = setattr_prepare(dentry, iattr);
+ if (error)
+ return error;
+
+diff --git a/fs/logfs/file.c b/fs/logfs/file.c
+index 1a6f0167b16a..3abe1414c3f4 100644
+--- a/fs/logfs/file.c
++++ b/fs/logfs/file.c
+@@ -244,7 +244,7 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+ int err = 0;
+
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+diff --git a/fs/minix/file.c b/fs/minix/file.c
+index 94f0eb9a6e2c..a6a4797aa0d4 100644
+--- a/fs/minix/file.c
++++ b/fs/minix/file.c
+@@ -26,7 +26,7 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/mount.h b/fs/mount.h
+index 6a61c2b3e385..2152c16ddf74 100644
+--- a/fs/mount.h
++++ b/fs/mount.h
+@@ -13,6 +13,8 @@ struct mnt_namespace {
+ u64 seq; /* Sequence number to prevent loops */
+ wait_queue_head_t poll;
+ u64 event;
++ unsigned int mounts; /* # of mounts in the namespace */
++ unsigned int pending_mounts;
+ };
+
+ struct mnt_pcp {
+diff --git a/fs/namespace.c b/fs/namespace.c
+index 556721fb0cf6..f853aaf92ec9 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -27,6 +27,9 @@
+ #include "pnode.h"
+ #include "internal.h"
+
++/* Maximum number of mounts in a mount namespace */
++unsigned int sysctl_mount_max __read_mostly = 100000;
++
+ static unsigned int m_hash_mask __read_mostly;
+ static unsigned int m_hash_shift __read_mostly;
+ static unsigned int mp_hash_mask __read_mostly;
+@@ -888,6 +891,9 @@ static void commit_tree(struct mount *mnt, struct mount *shadows)
+
+ list_splice(&head, n->list.prev);
+
++ n->mounts += n->pending_mounts;
++ n->pending_mounts = 0;
++
+ attach_shadowed(mnt, parent, shadows);
+ touch_mnt_namespace(n);
+ }
+@@ -1408,11 +1414,16 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
+ propagate_umount(&tmp_list);
+
+ while (!list_empty(&tmp_list)) {
++ struct mnt_namespace *ns;
+ bool disconnect;
+ p = list_first_entry(&tmp_list, struct mount, mnt_list);
+ list_del_init(&p->mnt_expire);
+ list_del_init(&p->mnt_list);
+- __touch_mnt_namespace(p->mnt_ns);
++ ns = p->mnt_ns;
++ if (ns) {
++ ns->mounts--;
++ __touch_mnt_namespace(ns);
++ }
+ p->mnt_ns = NULL;
+ if (how & UMOUNT_SYNC)
+ p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
+@@ -1821,6 +1832,28 @@ static int invent_group_ids(struct mount *mnt, bool recurse)
+ return 0;
+ }
+
++int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
++{
++ unsigned int max = READ_ONCE(sysctl_mount_max);
++ unsigned int mounts = 0, old, pending, sum;
++ struct mount *p;
++
++ for (p = mnt; p; p = next_mnt(p, mnt))
++ mounts++;
++
++ old = ns->mounts;
++ pending = ns->pending_mounts;
++ sum = old + pending;
++ if ((old > sum) ||
++ (pending > sum) ||
++ (max < sum) ||
++ (mounts > (max - sum)))
++ return -ENOSPC;
++
++ ns->pending_mounts = pending + mounts;
++ return 0;
++}
++
+ /*
+ * @source_mnt : mount tree to be attached
+ * @nd : place the mount tree @source_mnt is attached
+@@ -1890,10 +1923,18 @@ static int attach_recursive_mnt(struct mount *source_mnt,
+ struct path *parent_path)
+ {
+ HLIST_HEAD(tree_list);
++ struct mnt_namespace *ns = dest_mnt->mnt_ns;
+ struct mount *child, *p;
+ struct hlist_node *n;
+ int err;
+
++ /* Is there space to add these mounts to the mount namespace? */
++ if (!parent_path) {
++ err = count_mounts(ns, source_mnt);
++ if (err)
++ goto out;
++ }
++
+ if (IS_MNT_SHARED(dest_mnt)) {
+ err = invent_group_ids(source_mnt, true);
+ if (err)
+@@ -1930,11 +1971,13 @@ static int attach_recursive_mnt(struct mount *source_mnt,
+ out_cleanup_ids:
+ while (!hlist_empty(&tree_list)) {
+ child = hlist_entry(tree_list.first, struct mount, mnt_hash);
++ child->mnt_parent->mnt_ns->pending_mounts = 0;
+ umount_tree(child, UMOUNT_SYNC);
+ }
+ unlock_mount_hash();
+ cleanup_group_ids(source_mnt, NULL);
+ out:
++ ns->pending_mounts = 0;
+ return err;
+ }
+
+@@ -2758,6 +2801,8 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
+ init_waitqueue_head(&new_ns->poll);
+ new_ns->event = 0;
+ new_ns->user_ns = get_user_ns(user_ns);
++ new_ns->mounts = 0;
++ new_ns->pending_mounts = 0;
+ return new_ns;
+ }
+
+@@ -2807,6 +2852,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
+ q = new;
+ while (p) {
+ q->mnt_ns = new_ns;
++ new_ns->mounts++;
+ if (new_fs) {
+ if (&p->mnt == new_fs->root.mnt) {
+ new_fs->root.mnt = mntget(&q->mnt);
+@@ -2845,6 +2891,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
+ struct mount *mnt = real_mount(m);
+ mnt->mnt_ns = new_ns;
+ new_ns->root = mnt;
++ new_ns->mounts++;
+ list_add(&mnt->mnt_list, &new_ns->list);
+ } else {
+ mntput(m);
+diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
+index 9605a2f63549..7b1261bc2dee 100644
+--- a/fs/ncpfs/inode.c
++++ b/fs/ncpfs/inode.c
+@@ -884,7 +884,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
+ /* ageing the dentry to force validation */
+ ncp_age_dentry(server, dentry);
+
+- result = inode_change_ok(inode, attr);
++ result = setattr_prepare(dentry, attr);
+ if (result < 0)
+ goto out;
+
+diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
+index aecbcd34d336..44f6f4f5eee0 100644
+--- a/fs/nfsd/nfsproc.c
++++ b/fs/nfsd/nfsproc.c
+@@ -59,13 +59,59 @@ static __be32
+ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
+ struct nfsd_attrstat *resp)
+ {
++ struct iattr *iap = &argp->attrs;
++ struct svc_fh *fhp;
+ __be32 nfserr;
++
+ dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
+ SVCFH_fmt(&argp->fh),
+ argp->attrs.ia_valid, (long) argp->attrs.ia_size);
+
+- fh_copy(&resp->fh, &argp->fh);
+- nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0);
++ fhp = fh_copy(&resp->fh, &argp->fh);
++
++ /*
++ * NFSv2 does not differentiate between "set-[ac]time-to-now"
++ * which only requires access, and "set-[ac]time-to-X" which
++ * requires ownership.
++ * So if it looks like it might be "set both to the same time which
++ * is close to now", and if setattr_prepare fails, then we
++ * convert to "set to now" instead of "set to explicit time"
++ *
++ * We only call setattr_prepare as the last test as technically
++ * it is not an interface that we should be using.
++ */
++#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
++#define MAX_TOUCH_TIME_ERROR (30*60)
++ if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
++ iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
++ /*
++ * Looks probable.
++ *
++ * Now just make sure time is in the right ballpark.
++ * Solaris, at least, doesn't seem to care what the time
++ * request is. We require it be within 30 minutes of now.
++ */
++ time_t delta = iap->ia_atime.tv_sec - get_seconds();
++
++ nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
++ if (nfserr)
++ goto done;
++
++ if (delta < 0)
++ delta = -delta;
++ if (delta < MAX_TOUCH_TIME_ERROR &&
++ setattr_prepare(fhp->fh_dentry, iap) != 0) {
++ /*
++ * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
++ * This will cause notify_change to set these times
++ * to "now"
++ */
++ iap->ia_valid &= ~BOTH_TIME_SET;
++ }
++ }
++
++ nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time_t)0);
++done:
+ return nfsd_return_attrs(nfserr, resp);
+ }
+
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index 84d770be056e..92de3747ea8b 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -302,42 +302,6 @@ commit_metadata(struct svc_fh *fhp)
+ static void
+ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
+ {
+- /*
+- * NFSv2 does not differentiate between "set-[ac]time-to-now"
+- * which only requires access, and "set-[ac]time-to-X" which
+- * requires ownership.
+- * So if it looks like it might be "set both to the same time which
+- * is close to now", and if inode_change_ok fails, then we
+- * convert to "set to now" instead of "set to explicit time"
+- *
+- * We only call inode_change_ok as the last test as technically
+- * it is not an interface that we should be using.
+- */
+-#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
+-#define MAX_TOUCH_TIME_ERROR (30*60)
+- if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
+- iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
+- /*
+- * Looks probable.
+- *
+- * Now just make sure time is in the right ballpark.
+- * Solaris, at least, doesn't seem to care what the time
+- * request is. We require it be within 30 minutes of now.
+- */
+- time_t delta = iap->ia_atime.tv_sec - get_seconds();
+- if (delta < 0)
+- delta = -delta;
+- if (delta < MAX_TOUCH_TIME_ERROR &&
+- inode_change_ok(inode, iap) != 0) {
+- /*
+- * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
+- * This will cause notify_change to set these times
+- * to "now"
+- */
+- iap->ia_valid &= ~BOTH_TIME_SET;
+- }
+- }
+-
+ /* sanitize the mode change */
+ if (iap->ia_valid & ATTR_MODE) {
+ iap->ia_mode &= S_IALLUGO;
+diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
+index 258d9fe2521a..b40df2bb5ee4 100644
+--- a/fs/nilfs2/inode.c
++++ b/fs/nilfs2/inode.c
+@@ -839,7 +839,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
+ struct super_block *sb = inode->i_sb;
+ int err;
+
+- err = inode_change_ok(inode, iattr);
++ err = setattr_prepare(dentry, iattr);
+ if (err)
+ return err;
+
+diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
+index d284f07eda77..c178763893f3 100644
+--- a/fs/ntfs/inode.c
++++ b/fs/ntfs/inode.c
+@@ -2893,7 +2893,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
+ int err;
+ unsigned int ia_valid = attr->ia_valid;
+
+- err = inode_change_ok(vi, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ goto out;
+ /* We do not support NTFS ACLs yet. */
+diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
+index 762e5a3aecd3..c7641f656494 100644
+--- a/fs/ocfs2/acl.c
++++ b/fs/ocfs2/acl.c
+@@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,
+ case ACL_TYPE_ACCESS:
+ name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
+ if (acl) {
+- umode_t mode = inode->i_mode;
+- ret = posix_acl_equiv_mode(acl, &mode);
+- if (ret < 0)
+- return ret;
++ umode_t mode;
+
+- if (ret == 0)
+- acl = NULL;
++ ret = posix_acl_update_mode(inode, &mode, &acl);
++ if (ret)
++ return ret;
+
+ ret = ocfs2_acl_set_mode(inode, di_bh,
+ handle, mode);
+diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
+index b5cf27dcb18a..43ac2289c613 100644
+--- a/fs/ocfs2/dlmfs/dlmfs.c
++++ b/fs/ocfs2/dlmfs/dlmfs.c
+@@ -211,7 +211,7 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+
+ attr->ia_valid &= ~ATTR_SIZE;
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
+index e00be7f509db..bc06b982e9ea 100644
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -1150,7 +1150,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
+ return 0;
+
+- status = inode_change_ok(inode, attr);
++ status = setattr_prepare(dentry, attr);
+ if (status)
+ return status;
+
+diff --git a/fs/omfs/file.c b/fs/omfs/file.c
+index d9e26cfbb793..bf83e6644333 100644
+--- a/fs/omfs/file.c
++++ b/fs/omfs/file.c
+@@ -349,7 +349,7 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
+index 0bb8347c0d8b..d293034ae2cb 100644
+--- a/fs/overlayfs/inode.c
++++ b/fs/overlayfs/inode.c
+@@ -54,7 +54,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
+ * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
+ * check for a swapfile (which this won't be anyway).
+ */
+- err = inode_change_ok(dentry->d_inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+diff --git a/fs/pnode.c b/fs/pnode.c
+index 99899705b105..234a9ac49958 100644
+--- a/fs/pnode.c
++++ b/fs/pnode.c
+@@ -259,7 +259,7 @@ static int propagate_one(struct mount *m)
+ read_sequnlock_excl(&mount_lock);
+ }
+ hlist_add_head(&child->mnt_hash, list);
+- return 0;
++ return count_mounts(m->mnt_ns, child);
+ }
+
+ /*
+diff --git a/fs/pnode.h b/fs/pnode.h
+index 0fcdbe7ca648..550f5a8b4fcf 100644
+--- a/fs/pnode.h
++++ b/fs/pnode.h
+@@ -52,4 +52,5 @@ void mnt_set_mountpoint(struct mount *, struct mountpoint *,
+ struct mount *copy_tree(struct mount *, struct dentry *, int);
+ bool is_path_reachable(struct mount *, struct dentry *,
+ const struct path *root);
++int count_mounts(struct mnt_namespace *ns, struct mount *mnt);
+ #endif /* _LINUX_PNODE_H */
+diff --git a/fs/posix_acl.c b/fs/posix_acl.c
+index a9dafa83678c..0ef1c3722504 100644
+--- a/fs/posix_acl.c
++++ b/fs/posix_acl.c
+@@ -598,6 +598,37 @@ no_mem:
+ }
+ EXPORT_SYMBOL_GPL(posix_acl_create);
+
++/**
++ * posix_acl_update_mode - update mode in set_acl
++ *
++ * Update the file mode when setting an ACL: compute the new file permission
++ * bits based on the ACL. In addition, if the ACL is equivalent to the new
++ * file mode, set *acl to NULL to indicate that no ACL should be set.
++ *
++ * As with chmod, clear the setgit bit if the caller is not in the owning group
++ * or capable of CAP_FSETID (see inode_change_ok).
++ *
++ * Called from set_acl inode operations.
++ */
++int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
++ struct posix_acl **acl)
++{
++ umode_t mode = inode->i_mode;
++ int error;
++
++ error = posix_acl_equiv_mode(*acl, &mode);
++ if (error < 0)
++ return error;
++ if (error == 0)
++ *acl = NULL;
++ if (!in_group_p(inode->i_gid) &&
++ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
++ mode &= ~S_ISGID;
++ *mode_p = mode;
++ return 0;
++}
++EXPORT_SYMBOL(posix_acl_update_mode);
++
+ /*
+ * Fix up the uids and gids in posix acl extended attributes in place.
+ */
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 239dca3fb676..fab32ad5d96d 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -517,7 +517,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
+ if (attr->ia_valid & ATTR_MODE)
+ return -EPERM;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/proc/generic.c b/fs/proc/generic.c
+index e5dee5c3188e..d99099fe62d4 100644
+--- a/fs/proc/generic.c
++++ b/fs/proc/generic.c
+@@ -105,7 +105,7 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
+ struct proc_dir_entry *de = PDE(inode);
+ int error;
+
+- error = inode_change_ok(inode, iattr);
++ error = setattr_prepare(dentry, iattr);
+ if (error)
+ return error;
+
+diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
+index fdda62e6115e..0dea606074c7 100644
+--- a/fs/proc/proc_sysctl.c
++++ b/fs/proc/proc_sysctl.c
+@@ -753,7 +753,7 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
+ if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
+ return -EPERM;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
+index ba1323a94924..aab2593f3179 100644
+--- a/fs/ramfs/file-nommu.c
++++ b/fs/ramfs/file-nommu.c
+@@ -168,7 +168,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
+ int ret = 0;
+
+ /* POSIX UID/GID verification for setting inode attributes */
+- ret = inode_change_ok(inode, ia);
++ ret = setattr_prepare(dentry, ia);
+ if (ret)
+ return ret;
+
+diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
+index f6f2fbad9777..7da1232a78e3 100644
+--- a/fs/reiserfs/inode.c
++++ b/fs/reiserfs/inode.c
+@@ -3312,7 +3312,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
+ unsigned int ia_valid;
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
+index 4b34b9dc03dd..9b1824f35501 100644
+--- a/fs/reiserfs/xattr_acl.c
++++ b/fs/reiserfs/xattr_acl.c
+@@ -246,13 +246,9 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+- error = posix_acl_equiv_mode(acl, &inode->i_mode);
+- if (error < 0)
++ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ if (error)
+ return error;
+- else {
+- if (error == 0)
+- acl = NULL;
+- }
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+diff --git a/fs/sysv/file.c b/fs/sysv/file.c
+index 82ddc09061e2..7ba997e31aeb 100644
+--- a/fs/sysv/file.c
++++ b/fs/sysv/file.c
+@@ -33,7 +33,7 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
+index 75e9b2db14ab..2dc8ce485c51 100644
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
+
+ dbg_gen("ino %lu, mode %#x, ia_valid %#x",
+ inode->i_ino, inode->i_mode, attr->ia_valid);
+- err = inode_change_ok(inode, attr);
++ err = setattr_prepare(dentry, attr);
+ if (err)
+ return err;
+
+diff --git a/fs/udf/file.c b/fs/udf/file.c
+index 7a95b8fed302..889f1e5da507 100644
+--- a/fs/udf/file.c
++++ b/fs/udf/file.c
+@@ -252,7 +252,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
+ struct inode *inode = d_inode(dentry);
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
+index 21154704c168..a958b36f40bb 100644
+--- a/fs/ufs/truncate.c
++++ b/fs/ufs/truncate.c
+@@ -496,7 +496,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)
+ unsigned int ia_valid = attr->ia_valid;
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/fs/utimes.c b/fs/utimes.c
+index aa138d64560a..61abc3051377 100644
+--- a/fs/utimes.c
++++ b/fs/utimes.c
+@@ -81,7 +81,7 @@ static int utimes_common(struct path *path, struct timespec *times)
+ newattrs.ia_valid |= ATTR_MTIME_SET;
+ }
+ /*
+- * Tell inode_change_ok(), that this is an explicit time
++ * Tell setattr_prepare(), that this is an explicit time
+ * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
+ * were used.
+ */
+@@ -90,7 +90,7 @@ static int utimes_common(struct path *path, struct timespec *times)
+ /*
+ * If times is NULL (or both times are UTIME_NOW),
+ * then we need to check permissions, because
+- * inode_change_ok() won't do it.
++ * setattr_prepare() won't do it.
+ */
+ error = -EACCES;
+ if (IS_IMMUTABLE(inode))
+diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
+index 4b641676f258..e80dbfa2a7b9 100644
+--- a/fs/xfs/xfs_acl.c
++++ b/fs/xfs/xfs_acl.c
+@@ -284,16 +284,11 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ return error;
+
+ if (type == ACL_TYPE_ACCESS) {
+- umode_t mode = inode->i_mode;
+- error = posix_acl_equiv_mode(acl, &mode);
+-
+- if (error <= 0) {
+- acl = NULL;
+-
+- if (error < 0)
+- return error;
+- }
++ umode_t mode;
+
++ error = posix_acl_update_mode(inode, &mode, &acl);
++ if (error)
++ return error;
+ error = xfs_set_mode(inode, mode);
+ if (error)
+ return error;
+diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
+index 3b7591224f4a..550f8c4733ee 100644
+--- a/fs/xfs/xfs_file.c
++++ b/fs/xfs/xfs_file.c
+@@ -973,7 +973,7 @@ xfs_file_fallocate(
+
+ iattr.ia_valid = ATTR_SIZE;
+ iattr.ia_size = new_size;
+- error = xfs_setattr_size(ip, &iattr);
++ error = xfs_vn_setattr_size(file->f_path.dentry, &iattr);
+ if (error)
+ goto out_unlock;
+ }
+diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
+index c29f34253e2b..6b67d617c092 100644
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -1766,7 +1766,7 @@ xfs_inactive_truncate(
+ /*
+ * Log the inode size first to prevent stale data exposure in the event
+ * of a system crash before the truncate completes. See the related
+- * comment in xfs_setattr_size() for details.
++ * comment in xfs_vn_setattr_size() for details.
+ */
+ ip->i_d.di_size = 0;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
+index 87f67c6b654c..82e49109d0b6 100644
+--- a/fs/xfs/xfs_ioctl.c
++++ b/fs/xfs/xfs_ioctl.c
+@@ -720,7 +720,7 @@ xfs_ioc_space(
+ iattr.ia_valid = ATTR_SIZE;
+ iattr.ia_size = bf->l_start;
+
+- error = xfs_setattr_size(ip, &iattr);
++ error = xfs_vn_setattr_size(filp->f_path.dentry, &iattr);
+ break;
+ default:
+ ASSERT(0);
+diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
+index f4cd7204e236..4e4d6511185b 100644
+--- a/fs/xfs/xfs_iops.c
++++ b/fs/xfs/xfs_iops.c
+@@ -537,6 +537,30 @@ xfs_setattr_time(
+ }
+ }
+
++static int
++xfs_vn_change_ok(
++ struct dentry *dentry,
++ struct iattr *iattr)
++{
++ struct inode *inode = d_inode(dentry);
++ struct xfs_inode *ip = XFS_I(inode);
++ struct xfs_mount *mp = ip->i_mount;
++
++ if (mp->m_flags & XFS_MOUNT_RDONLY)
++ return -EROFS;
++
++ if (XFS_FORCED_SHUTDOWN(mp))
++ return -EIO;
++
++ return setattr_prepare(dentry, iattr);
++}
++
++/*
++ * Set non-size attributes of an inode.
++ *
++ * Caution: The caller of this function is responsible for calling
++ * setattr_prepare() or otherwise verifying the change is fine.
++ */
+ int
+ xfs_setattr_nonsize(
+ struct xfs_inode *ip,
+@@ -553,21 +577,6 @@ xfs_setattr_nonsize(
+ struct xfs_dquot *udqp = NULL, *gdqp = NULL;
+ struct xfs_dquot *olddquot1 = NULL, *olddquot2 = NULL;
+
+- trace_xfs_setattr(ip);
+-
+- /* If acls are being inherited, we already have this checked */
+- if (!(flags & XFS_ATTR_NOACL)) {
+- if (mp->m_flags & XFS_MOUNT_RDONLY)
+- return -EROFS;
+-
+- if (XFS_FORCED_SHUTDOWN(mp))
+- return -EIO;
+-
+- error = inode_change_ok(inode, iattr);
+- if (error)
+- return error;
+- }
+-
+ ASSERT((mask & ATTR_SIZE) == 0);
+
+ /*
+@@ -741,8 +750,27 @@ out_dqrele:
+ return error;
+ }
+
++int
++xfs_vn_setattr_nonsize(
++ struct dentry *dentry,
++ struct iattr *iattr)
++{
++ struct xfs_inode *ip = XFS_I(d_inode(dentry));
++ int error;
++
++ trace_xfs_setattr(ip);
++
++ error = xfs_vn_change_ok(dentry, iattr);
++ if (error)
++ return error;
++ return xfs_setattr_nonsize(ip, iattr, 0);
++}
++
+ /*
+ * Truncate file. Must have write permission and not be a directory.
++ *
++ * Caution: The caller of this function is responsible for calling
++ * setattr_prepare() or otherwise verifying the change is fine.
+ */
+ int
+ xfs_setattr_size(
+@@ -758,18 +786,6 @@ xfs_setattr_size(
+ uint commit_flags = 0;
+ bool did_zeroing = false;
+
+- trace_xfs_setattr(ip);
+-
+- if (mp->m_flags & XFS_MOUNT_RDONLY)
+- return -EROFS;
+-
+- if (XFS_FORCED_SHUTDOWN(mp))
+- return -EIO;
+-
+- error = inode_change_ok(inode, iattr);
+- if (error)
+- return error;
+-
+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
+ ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
+ ASSERT(S_ISREG(ip->i_d.di_mode));
+@@ -941,16 +957,32 @@ out_trans_cancel:
+ goto out_unlock;
+ }
+
++int
++xfs_vn_setattr_size(
++ struct dentry *dentry,
++ struct iattr *iattr)
++{
++ struct xfs_inode *ip = XFS_I(d_inode(dentry));
++ int error;
++
++ trace_xfs_setattr(ip);
++
++ error = xfs_vn_change_ok(dentry, iattr);
++ if (error)
++ return error;
++ return xfs_setattr_size(ip, iattr);
++}
++
+ STATIC int
+ xfs_vn_setattr(
+ struct dentry *dentry,
+ struct iattr *iattr)
+ {
+- struct xfs_inode *ip = XFS_I(d_inode(dentry));
+ int error;
+
+ if (iattr->ia_valid & ATTR_SIZE) {
+- uint iolock = XFS_IOLOCK_EXCL;
++ struct xfs_inode *ip = XFS_I(d_inode(dentry));
++ uint iolock = XFS_IOLOCK_EXCL;
+
+ xfs_ilock(ip, iolock);
+ error = xfs_break_layouts(d_inode(dentry), &iolock, true);
+@@ -958,11 +990,11 @@ xfs_vn_setattr(
+ xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+ iolock |= XFS_MMAPLOCK_EXCL;
+
+- error = xfs_setattr_size(ip, iattr);
++ error = xfs_vn_setattr_size(dentry, iattr);
+ }
+ xfs_iunlock(ip, iolock);
+ } else {
+- error = xfs_setattr_nonsize(ip, iattr, 0);
++ error = xfs_vn_setattr_nonsize(dentry, iattr);
+ }
+
+ return error;
+diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h
+index a0f84abb0d09..0259a383721a 100644
+--- a/fs/xfs/xfs_iops.h
++++ b/fs/xfs/xfs_iops.h
+@@ -33,6 +33,7 @@ extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
+ extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr);
+ extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
+ int flags);
+-extern int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap);
++extern int xfs_vn_setattr_nonsize(struct dentry *dentry, struct iattr *vap);
++extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap);
+
+ #endif /* __XFS_IOPS_H__ */
+diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
+index 5e13b987d9e2..678e97fa3869 100644
+--- a/include/linux/can/dev.h
++++ b/include/linux/can/dev.h
+@@ -31,6 +31,7 @@ enum can_mode {
+ * CAN common private data
+ */
+ struct can_priv {
++ struct net_device *dev;
+ struct can_device_stats can_stats;
+
+ struct can_bittiming bittiming, data_bittiming;
+@@ -46,7 +47,7 @@ struct can_priv {
+ u32 ctrlmode_static; /* static enabled options for driver/hardware */
+
+ int restart_ms;
+- struct timer_list restart_timer;
++ struct delayed_work restart_work;
+
+ int (*do_set_bittiming)(struct net_device *dev);
+ int (*do_set_data_bittiming)(struct net_device *dev);
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index ae327f6a53f6..31c3d818c981 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2816,7 +2816,7 @@ extern int buffer_migrate_page(struct address_space *,
+ #define buffer_migrate_page NULL
+ #endif
+
+-extern int inode_change_ok(const struct inode *, struct iattr *);
++extern int setattr_prepare(struct dentry *, struct iattr *);
+ extern int inode_newsize_ok(const struct inode *, loff_t offset);
+ extern void setattr_copy(struct inode *inode, const struct iattr *attr);
+
+diff --git a/include/linux/mount.h b/include/linux/mount.h
+index f822c3c11377..dc6cd800cd5d 100644
+--- a/include/linux/mount.h
++++ b/include/linux/mount.h
+@@ -95,4 +95,6 @@ extern void mark_mounts_for_expiry(struct list_head *mounts);
+
+ extern dev_t name_to_dev_t(const char *name);
+
++extern unsigned int sysctl_mount_max;
++
+ #endif /* _LINUX_MOUNT_H */
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 6c86c7edafa7..ddd47c3a757d 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1957,7 +1957,10 @@ struct napi_gro_cb {
+ /* Used in foo-over-udp, set in udp[46]_gro_receive */
+ u8 is_ipv6:1;
+
+- /* 7 bit hole */
++ /* Number of gro_receive callbacks this packet already went through */
++ u8 recursion_counter:4;
++
++ /* 3 bit hole */
+
+ /* used to support CHECKSUM_COMPLETE for tunneling protocols */
+ __wsum csum;
+@@ -1968,6 +1971,25 @@ struct napi_gro_cb {
+
+ #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
+
++#define GRO_RECURSION_LIMIT 15
++static inline int gro_recursion_inc_test(struct sk_buff *skb)
++{
++ return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
++}
++
++typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *);
++static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
++ struct sk_buff **head,
++ struct sk_buff *skb)
++{
++ if (gro_recursion_inc_test(skb)) {
++ NAPI_GRO_CB(skb)->flush |= 1;
++ return NULL;
++ }
++
++ return cb(head, skb);
++}
++
+ struct packet_type {
+ __be16 type; /* This is really htons(ether_type). */
+ struct net_device *dev; /* NULL is wildcarded here */
+diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
+index 3e96a6a76103..d1a8ad7e5ae4 100644
+--- a/include/linux/posix_acl.h
++++ b/include/linux/posix_acl.h
+@@ -95,6 +95,7 @@ extern int set_posix_acl(struct inode *, int, struct posix_acl *);
+ extern int posix_acl_chmod(struct inode *, umode_t);
+ extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
+ struct posix_acl **);
++extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
+
+ extern int simple_set_acl(struct inode *, struct posix_acl *, int);
+ extern int simple_acl_create(struct inode *, struct inode *);
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 6d204f3f9df8..3d3a365233f0 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -1434,6 +1434,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli
+ {
+ if (sk->sk_send_head == skb_unlinked)
+ sk->sk_send_head = NULL;
++ if (tcp_sk(sk)->highest_sack == skb_unlinked)
++ tcp_sk(sk)->highest_sack = NULL;
+ }
+
+ static inline void tcp_init_send_head(struct sock *sk)
+diff --git a/kernel/cpuset.c b/kernel/cpuset.c
+index 388fc6f78c6f..71403502411b 100644
+--- a/kernel/cpuset.c
++++ b/kernel/cpuset.c
+@@ -323,8 +323,7 @@ static struct file_system_type cpuset_fs_type = {
+ /*
+ * Return in pmask the portion of a cpusets's cpus_allowed that
+ * are online. If none are online, walk up the cpuset hierarchy
+- * until we find one that does have some online cpus. The top
+- * cpuset always has some cpus online.
++ * until we find one that does have some online cpus.
+ *
+ * One way or another, we guarantee to return some non-empty subset
+ * of cpu_online_mask.
+@@ -333,8 +332,20 @@ static struct file_system_type cpuset_fs_type = {
+ */
+ static void guarantee_online_cpus(struct cpuset *cs, struct cpumask *pmask)
+ {
+- while (!cpumask_intersects(cs->effective_cpus, cpu_online_mask))
++ while (!cpumask_intersects(cs->effective_cpus, cpu_online_mask)) {
+ cs = parent_cs(cs);
++ if (unlikely(!cs)) {
++ /*
++ * The top cpuset doesn't have any online cpu as a
++ * consequence of a race between cpuset_hotplug_work
++ * and cpu hotplug notifier. But we know the top
++ * cpuset's effective_cpus is on its way to to be
++ * identical to cpu_online_mask.
++ */
++ cpumask_copy(pmask, cpu_online_mask);
++ return;
++ }
++ }
+ cpumask_and(pmask, cs->effective_cpus, cpu_online_mask);
+ }
+
+diff --git a/kernel/ptrace.c b/kernel/ptrace.c
+index 261ee21e62db..9650e7aee267 100644
+--- a/kernel/ptrace.c
++++ b/kernel/ptrace.c
+@@ -20,6 +20,7 @@
+ #include <linux/uio.h>
+ #include <linux/audit.h>
+ #include <linux/pid_namespace.h>
++#include <linux/user_namespace.h>
+ #include <linux/syscalls.h>
+ #include <linux/uaccess.h>
+ #include <linux/regset.h>
+@@ -207,12 +208,34 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
+ return ret;
+ }
+
+-static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
++static bool ptrace_has_cap(const struct cred *tcred, unsigned int mode)
+ {
++ struct user_namespace *tns = tcred->user_ns;
++
++ /* When a root-owned process enters a user namespace created by a
++ * malicious user, the user shouldn't be able to execute code under
++ * uid 0 by attaching to the root-owned process via ptrace.
++ * Therefore, similar to the capable_wrt_inode_uidgid() check,
++ * verify that all the uids and gids of the target process are
++ * mapped into a namespace below the current one in which the caller
++ * is capable.
++ * No fsuid/fsgid check because __ptrace_may_access doesn't do it
++ * either.
++ */
++ while (
++ !kuid_has_mapping(tns, tcred->euid) ||
++ !kuid_has_mapping(tns, tcred->suid) ||
++ !kuid_has_mapping(tns, tcred->uid) ||
++ !kgid_has_mapping(tns, tcred->egid) ||
++ !kgid_has_mapping(tns, tcred->sgid) ||
++ !kgid_has_mapping(tns, tcred->gid)) {
++ tns = tns->parent;
++ }
++
+ if (mode & PTRACE_MODE_NOAUDIT)
+- return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE);
++ return has_ns_capability_noaudit(current, tns, CAP_SYS_PTRACE);
+ else
+- return has_ns_capability(current, ns, CAP_SYS_PTRACE);
++ return has_ns_capability(current, tns, CAP_SYS_PTRACE);
+ }
+
+ /* Returns 0 on success, -errno on denial. */
+@@ -264,7 +287,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
+ gid_eq(caller_gid, tcred->sgid) &&
+ gid_eq(caller_gid, tcred->gid))
+ goto ok;
+- if (ptrace_has_cap(tcred->user_ns, mode))
++ if (ptrace_has_cap(tcred, mode))
+ goto ok;
+ rcu_read_unlock();
+ return -EPERM;
+@@ -275,7 +298,7 @@ ok:
+ dumpable = get_dumpable(task->mm);
+ rcu_read_lock();
+ if (dumpable != SUID_DUMP_USER &&
+- !ptrace_has_cap(__task_cred(task)->user_ns, mode)) {
++ !ptrace_has_cap(__task_cred(task), mode)) {
+ rcu_read_unlock();
+ return -EPERM;
+ }
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 7d4900404c94..cebbff5f34fe 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -64,6 +64,7 @@
+ #include <linux/binfmts.h>
+ #include <linux/sched/sysctl.h>
+ #include <linux/kexec.h>
++#include <linux/mount.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/processor.h>
+@@ -1709,6 +1710,14 @@ static struct ctl_table fs_table[] = {
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ },
++ {
++ .procname = "mount-max",
++ .data = &sysctl_mount_max,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = &one,
++ },
+ { }
+ };
+
+diff --git a/mm/ksm.c b/mm/ksm.c
+index 7ee101eaacdf..22a2883eb822 100644
+--- a/mm/ksm.c
++++ b/mm/ksm.c
+@@ -283,7 +283,8 @@ static inline struct rmap_item *alloc_rmap_item(void)
+ {
+ struct rmap_item *rmap_item;
+
+- rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL);
++ rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
+ if (rmap_item)
+ ksm_rmap_items++;
+ return rmap_item;
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 46511ad90bc5..feaaf6ea1b86 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -548,7 +548,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ int error;
+
+- error = inode_change_ok(inode, attr);
++ error = setattr_prepare(dentry, attr);
+ if (error)
+ return error;
+
+diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
+index 825e8fb5114b..f9e9a8148a43 100644
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -334,16 +334,19 @@ static int rfcomm_sock_create(struct net *net, struct socket *sock,
+
+ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+ {
+- struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++ struct sockaddr_rc sa;
+ struct sock *sk = sock->sk;
+- int chan = sa->rc_channel;
+- int err = 0;
+-
+- BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
++ int len, err = 0;
+
+ if (!addr || addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
++ memset(&sa, 0, sizeof(sa));
++ len = min_t(unsigned int, sizeof(sa), addr_len);
++ memcpy(&sa, addr, len);
++
++ BT_DBG("sk %p %pMR", sk, &sa.rc_bdaddr);
++
+ lock_sock(sk);
+
+ if (sk->sk_state != BT_OPEN) {
+@@ -358,12 +361,13 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
+
+ write_lock(&rfcomm_sk_list.lock);
+
+- if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) {
++ if (sa.rc_channel &&
++ __rfcomm_get_listen_sock_by_addr(sa.rc_channel, &sa.rc_bdaddr)) {
+ err = -EADDRINUSE;
+ } else {
+ /* Save source address */
+- bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr);
+- rfcomm_pi(sk)->channel = chan;
++ bacpy(&rfcomm_pi(sk)->src, &sa.rc_bdaddr);
++ rfcomm_pi(sk)->channel = sa.rc_channel;
+ sk->sk_state = BT_BOUND;
+ }
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 185a3398c651..56d820fc2707 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -4060,6 +4060,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
+ NAPI_GRO_CB(skb)->flush = 0;
+ NAPI_GRO_CB(skb)->free = 0;
+ NAPI_GRO_CB(skb)->udp_mark = 0;
++ NAPI_GRO_CB(skb)->recursion_counter = 0;
+ NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
+
+ /* Setup for GRO checksum validation */
+diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
+index f3bad41d725f..76f8389eacd2 100644
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -434,7 +434,7 @@ struct sk_buff **eth_gro_receive(struct sk_buff **head,
+
+ skb_gro_pull(skb, sizeof(*eh));
+ skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
+- pp = ptype->callbacks.gro_receive(head, skb);
++ pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+
+ out_unlock:
+ rcu_read_unlock();
+diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
+index 0cc98b135b8f..2095cd6c31fd 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -1377,7 +1377,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
+ skb_gro_pull(skb, sizeof(*iph));
+ skb_set_transport_header(skb, skb_gro_offset(skb));
+
+- pp = ops->callbacks.gro_receive(head, skb);
++ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+
+ out_unlock:
+ rcu_read_unlock();
+diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
+index 4b67937692c9..b22a75c0a3d9 100644
+--- a/net/ipv4/fou.c
++++ b/net/ipv4/fou.c
+@@ -188,7 +188,7 @@ static struct sk_buff **fou_gro_receive(struct sk_buff **head,
+ if (!ops || !ops->callbacks.gro_receive)
+ goto out_unlock;
+
+- pp = ops->callbacks.gro_receive(head, skb);
++ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+
+ out_unlock:
+ rcu_read_unlock();
+@@ -355,7 +355,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
+ if (WARN_ON(!ops || !ops->callbacks.gro_receive))
+ goto out_unlock;
+
+- pp = ops->callbacks.gro_receive(head, skb);
++ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+
+ out_unlock:
+ rcu_read_unlock();
+diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
+index 5a8ee3282550..53300b88d569 100644
+--- a/net/ipv4/gre_offload.c
++++ b/net/ipv4/gre_offload.c
+@@ -214,7 +214,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
+ /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
+ skb_gro_postpull_rcsum(skb, greh, grehlen);
+
+- pp = ptype->callbacks.gro_receive(head, skb);
++ pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+
+ out_unlock:
+ rcu_read_unlock();
+diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
+index f6ee0d561aab..3dac3d4aa26f 100644
+--- a/net/ipv4/ping.c
++++ b/net/ipv4/ping.c
+@@ -659,6 +659,10 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
+ if (len > 0xFFFF)
+ return -EMSGSIZE;
+
++ /* Must have at least a full ICMP header. */
++ if (len < icmph_len)
++ return -EINVAL;
++
+ /*
+ * Check the flags.
+ */
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index f9386160cbee..2af7b7e1a0f6 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -339,8 +339,13 @@ unflush:
+ skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
+ skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
+ NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
+- pp = uo_priv->offload->callbacks.gro_receive(head, skb,
+- uo_priv->offload);
++
++ if (gro_recursion_inc_test(skb)) {
++ pp = NULL;
++ } else {
++ pp = uo_priv->offload->callbacks.gro_receive(head, skb,
++ uo_priv->offload);
++ }
+
+ out_unlock:
+ rcu_read_unlock();
+diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
+index 08b62047c67f..db0b8428d248 100644
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -247,7 +247,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
+
+ skb_gro_postpull_rcsum(skb, iph, nlen);
+
+- pp = ops->callbacks.gro_receive(head, skb);
++ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+
+ out_unlock:
+ rcu_read_unlock();
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index a3654d929814..b9d1baaa8bdc 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -3344,19 +3344,25 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
+
+ if (optlen != sizeof(val))
+ return -EINVAL;
+- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
+- return -EBUSY;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+ switch (val) {
+ case TPACKET_V1:
+ case TPACKET_V2:
+ case TPACKET_V3:
+- po->tp_version = val;
+- return 0;
++ break;
+ default:
+ return -EINVAL;
+ }
++ lock_sock(sk);
++ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
++ ret = -EBUSY;
++ } else {
++ po->tp_version = val;
++ ret = 0;
++ }
++ release_sock(sk);
++ return ret;
+ }
+ case PACKET_RESERVE:
+ {
+@@ -3819,6 +3825,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ /* Added to avoid minimal code churn */
+ struct tpacket_req *req = &req_u->req;
+
++ lock_sock(sk);
+ /* Opening a Tx-ring is NOT supported in TPACKET_V3 */
+ if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
+ WARN(1, "Tx-ring is not supported.\n");
+@@ -3900,7 +3907,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ goto out;
+ }
+
+- lock_sock(sk);
+
+ /* Detach socket from network */
+ spin_lock(&po->bind_lock);
+@@ -3949,11 +3955,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ if (!tx_ring)
+ prb_shutdown_retire_blk_timer(po, tx_ring, rb_queue);
+ }
+- release_sock(sk);
+
+ if (pg_vec)
+ free_pg_vec(pg_vec, order, req->tp_block_nr);
+ out:
++ release_sock(sk);
+ return err;
+ }
+
+diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
+index 70e3dacbf84a..bf7d6a44c6f2 100644
+--- a/net/tipc/bearer.c
++++ b/net/tipc/bearer.c
+@@ -386,6 +386,10 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
+ dev = dev_get_by_name(net, driver_name);
+ if (!dev)
+ return -ENODEV;
++ if (tipc_mtu_bad(dev, 0)) {
++ dev_put(dev);
++ return -EINVAL;
++ }
+
+ /* Associate TIPC bearer with L2 bearer */
+ rcu_assign_pointer(b->media_ptr, dev);
+@@ -524,14 +528,17 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
+ if (!b_ptr)
+ return NOTIFY_DONE;
+
+- b_ptr->mtu = dev->mtu;
+-
+ switch (evt) {
+ case NETDEV_CHANGE:
+ if (netif_carrier_ok(dev))
+ break;
+ case NETDEV_DOWN:
+ case NETDEV_CHANGEMTU:
++ if (tipc_mtu_bad(dev, 0)) {
++ bearer_disable(net, b_ptr, false);
++ break;
++ }
++ b_ptr->mtu = dev->mtu;
+ tipc_reset_bearer(net, b_ptr);
+ break;
+ case NETDEV_CHANGEADDR:
+diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
+index 5cad243ee8fc..b7302b012624 100644
+--- a/net/tipc/bearer.h
++++ b/net/tipc/bearer.h
+@@ -38,6 +38,7 @@
+ #define _TIPC_BEARER_H
+
+ #include "netlink.h"
++#include "msg.h"
+ #include <net/genetlink.h>
+
+ #define MAX_BEARERS 2
+@@ -61,6 +62,9 @@
+ #define TIPC_MEDIA_TYPE_IB 2
+ #define TIPC_MEDIA_TYPE_UDP 3
+
++/* minimum bearer MTU */
++#define TIPC_MIN_BEARER_MTU (MAX_H_SIZE + INT_H_SIZE)
++
+ /**
+ * struct tipc_node_map - set of node identifiers
+ * @count: # of nodes in set
+@@ -218,4 +222,13 @@ void tipc_bearer_stop(struct net *net);
+ void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf,
+ struct tipc_media_addr *dest);
+
++/* check if device MTU is too low for tipc headers */
++static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve)
++{
++ if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve)
++ return false;
++ netdev_warn(dev, "MTU too low for tipc bearer\n");
++ return true;
++}
++
+ #endif /* _TIPC_BEARER_H */
+diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
+index f8dfee5072c0..e14f23542a1a 100644
+--- a/net/tipc/udp_media.c
++++ b/net/tipc/udp_media.c
+@@ -374,6 +374,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
+ udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
+ udp_conf.use_udp_checksums = false;
+ ub->ifindex = dev->ifindex;
++ if (tipc_mtu_bad(dev, sizeof(struct iphdr) +
++ sizeof(struct udphdr))) {
++ err = -EINVAL;
++ goto err;
++ }
+ b->mtu = dev->mtu - sizeof(struct iphdr)
+ - sizeof(struct udphdr);
+ #if IS_ENABLED(CONFIG_IPV6)
+diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh
+index 973e8c141567..17867e723a51 100755
+--- a/scripts/gcc-x86_64-has-stack-protector.sh
++++ b/scripts/gcc-x86_64-has-stack-protector.sh
+@@ -1,6 +1,6 @@
+ #!/bin/sh
+
+-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
++echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
+ if [ "$?" -eq "0" ] ; then
+ echo y
+ else
diff --git a/1520_fix-race-condition-in-packet-set-ring.patch b/1520_fix-race-condition-in-packet-set-ring.patch
deleted file mode 100644
index d85527f..0000000
--- a/1520_fix-race-condition-in-packet-set-ring.patch
+++ /dev/null
@@ -1,62 +0,0 @@
---- a/net/packet/af_packet.c 2016-12-07 18:10:25.785812861 -0500
-+++ b/net/packet/af_packet.c 2016-12-07 18:18:45.597933525 -0500
-@@ -3648,19 +3648,25 @@ packet_setsockopt(struct socket *sock, i
-
- if (optlen != sizeof(val))
- return -EINVAL;
-- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-- return -EBUSY;
- if (copy_from_user(&val, optval, sizeof(val)))
- return -EFAULT;
- switch (val) {
- case TPACKET_V1:
- case TPACKET_V2:
- case TPACKET_V3:
-- po->tp_version = val;
-- return 0;
-+ break;
- default:
- return -EINVAL;
- }
-+ lock_sock(sk);
-+ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
-+ ret = -EBUSY;
-+ } else {
-+ po->tp_version = val;
-+ ret = 0;
-+ }
-+ release_sock(sk);
-+ return ret;
- }
- case PACKET_RESERVE:
- {
-@@ -4164,6 +4170,7 @@ static int packet_set_ring(struct sock *
- /* Added to avoid minimal code churn */
- struct tpacket_req *req = &req_u->req;
-
-+ lock_sock(sk);
- /* Opening a Tx-ring is NOT supported in TPACKET_V3 */
- if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
- net_warn_ratelimited("Tx-ring is not supported.\n");
-@@ -4245,8 +4252,6 @@ static int packet_set_ring(struct sock *
- goto out;
- }
-
-- lock_sock(sk);
--
- /* Detach socket from network */
- spin_lock(&po->bind_lock);
- was_running = po->running;
-@@ -4294,11 +4299,11 @@ static int packet_set_ring(struct sock *
- if (!tx_ring)
- prb_shutdown_retire_blk_timer(po, rb_queue);
- }
-- release_sock(sk);
-
- if (pg_vec)
- free_pg_vec(pg_vec, order, req->tp_block_nr);
- out:
-+ release_sock(sk);
- return err;
- }
-
next reply other threads:[~2017-01-10 4:02 UTC|newest]
Thread overview: 71+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-10 4:02 Alice Ferrazzi [this message]
-- strict thread matches above, loose matches on Subject: below --
2018-05-29 10:34 [gentoo-commits] proj/linux-patches:4.1 commit in: / Mike Pagano
2018-01-23 9:37 Alice Ferrazzi
2017-12-15 20:22 Alice Ferrazzi
2017-12-08 14:48 Mike Pagano
2017-12-07 18:53 Mike Pagano
2017-10-18 11:51 Mike Pagano
2017-09-13 19:38 Mike Pagano
2017-08-06 18:01 Mike Pagano
2017-04-14 19:17 Mike Pagano
2017-03-14 11:39 Mike Pagano
2017-03-02 16:31 Mike Pagano
2017-03-02 16:31 Mike Pagano
2017-02-24 16:11 Mike Pagano
2017-01-18 23:50 Alice Ferrazzi
2016-12-08 0:43 Mike Pagano
2016-11-30 11:45 Mike Pagano
2016-11-23 11:25 Mike Pagano
2016-10-28 10:19 Mike Pagano
2016-10-12 19:52 Mike Pagano
2016-09-18 12:47 Mike Pagano
2016-08-22 23:29 Mike Pagano
2016-08-10 12:55 Mike Pagano
2016-07-31 16:01 Mike Pagano
2016-07-15 14:18 Mike Pagano
2016-07-13 23:38 Mike Pagano
2016-07-02 15:31 Mike Pagano
2016-07-01 19:56 Mike Pagano
2016-06-23 11:45 Mike Pagano
2016-06-08 11:17 Mike Pagano
2016-05-24 12:39 Mike Pagano
2016-05-12 0:12 Mike Pagano
2016-04-28 18:56 Mike Pagano
2016-04-22 18:06 Mike Pagano
2016-04-20 11:23 Mike Pagano
2016-04-06 11:23 Mike Pagano
2016-03-22 22:47 Mike Pagano
2016-03-17 22:52 Mike Pagano
2016-03-05 23:38 Mike Pagano
2016-02-16 15:28 Mike Pagano
2016-01-31 23:29 Mike Pagano
2016-01-23 18:30 Mike Pagano
2016-01-20 13:54 Mike Pagano
2015-12-15 11:17 Mike Pagano
2015-12-10 13:54 Mike Pagano
2015-11-10 0:30 Mike Pagano
2015-11-05 23:29 Mike Pagano
2015-11-05 23:29 Mike Pagano
2015-10-27 13:19 Mike Pagano
2015-10-26 20:51 Mike Pagano
2015-10-26 20:49 Mike Pagano
2015-10-03 16:07 Mike Pagano
2015-10-02 12:08 Mike Pagano
2015-09-29 17:50 Mike Pagano
2015-09-28 23:57 Mike Pagano
2015-09-21 22:16 Mike Pagano
2015-09-14 15:20 Mike Pagano
2015-08-17 15:38 Mike Pagano
2015-08-12 14:17 Mike Pagano
2015-08-10 23:42 Mike Pagano
2015-08-03 19:01 Mike Pagano
2015-07-22 10:31 Mike Pagano
2015-07-22 10:09 Mike Pagano
2015-07-19 18:55 Mike Pagano
2015-07-17 15:24 Mike Pagano
2015-07-10 23:47 Mike Pagano
2015-07-01 15:33 Mike Pagano
2015-06-27 19:50 Mike Pagano
2015-06-26 22:36 Mike Pagano
2015-06-20 17:37 Mike Pagano
2015-06-08 17:59 Mike Pagano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1484021276.3f861dc13e810781883d0f1cfe33a821ee3504f8.alicef@gentoo \
--to=alicef@gentoo.org \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox