Author: mpagano Date: 2014-04-04 00:13:19 +0000 (Fri, 04 Apr 2014) New Revision: 2735
Added: genpatches-2.6/trunk/3.13/1008_linux-3.13.9.patch Modified: genpatches-2.6/trunk/3.13/0000_README Log: Linux patch 3.13.9 Modified: genpatches-2.6/trunk/3.13/0000_README =================================================================== --- genpatches-2.6/trunk/3.13/0000_README 2014-04-02 14:23:41 UTC (rev 2734) +++ genpatches-2.6/trunk/3.13/0000_README 2014-04-04 00:13:19 UTC (rev 2735) @@ -74,6 +74,10 @@ From: http://www.kernel.org Desc: Linux 3.13.8 +Patch: 1008_linux-3.13.9.patch +From: http://www.kernel.org +Desc: Linux 3.13.9 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. Added: genpatches-2.6/trunk/3.13/1008_linux-3.13.9.patch =================================================================== --- genpatches-2.6/trunk/3.13/1008_linux-3.13.9.patch (rev 0) +++ genpatches-2.6/trunk/3.13/1008_linux-3.13.9.patch 2014-04-04 00:13:19 UTC (rev 2735) @@ -0,0 +1,1425 @@ +diff --git a/Makefile b/Makefile +index 4cab13b605c1..652f97296a40 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 13 +-SUBLEVEL = 8 ++SUBLEVEL = 9 + EXTRAVERSION = + NAME = One Giant Leap for Frogkind + +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index 5ad38ad07890..bbc8b12fa443 100644 +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -445,20 +445,10 @@ static inline int pte_same(pte_t a, pte_t b) + return a.pte == b.pte; + } + +-static inline int pteval_present(pteval_t pteval) +-{ +- /* +- * Yes Linus, _PAGE_PROTNONE == _PAGE_NUMA. Expressing it this +- * way clearly states that the intent is that protnone and numa +- * hinting ptes are considered present for the purposes of +- * pagetable operations like zapping, protection changes, gup etc. +- */ +- return pteval & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_NUMA); +-} +- + static inline int pte_present(pte_t a) + { +- return pteval_present(pte_flags(a)); ++ return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE | ++ _PAGE_NUMA); + } + + #define pte_accessible pte_accessible +diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h +index d35f24e231cd..1306d117967d 100644 +--- a/arch/x86/include/asm/topology.h ++++ b/arch/x86/include/asm/topology.h +@@ -119,9 +119,10 @@ static inline void setup_node_to_cpumask_map(void) { } + + extern const struct cpumask *cpu_coregroup_mask(int cpu); + +-#ifdef ENABLE_TOPO_DEFINES + #define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id) + #define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id) ++ ++#ifdef ENABLE_TOPO_DEFINES + #define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu)) + #define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu)) + #endif +diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c +index 3c76c3d50471..ce563be09cc1 100644 +--- a/arch/x86/xen/mmu.c ++++ b/arch/x86/xen/mmu.c +@@ -365,7 +365,7 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, + /* Assume pteval_t is equivalent to all the other *val_t types. */ + static pteval_t pte_mfn_to_pfn(pteval_t val) + { +- if (pteval_present(val)) { ++ if (val & _PAGE_PRESENT) { + unsigned long mfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; + unsigned long pfn = mfn_to_pfn(mfn); + +@@ -381,7 +381,7 @@ static pteval_t pte_mfn_to_pfn(pteval_t val) + + static pteval_t pte_pfn_to_mfn(pteval_t val) + { +- if (pteval_present(val)) { ++ if (val & _PAGE_PRESENT) { + unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; + pteval_t flags = val & PTE_FLAGS_MASK; + unsigned long mfn; +diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c +index d2515435e23f..8fb295350efb 100644 +--- a/drivers/block/aoe/aoecmd.c ++++ b/drivers/block/aoe/aoecmd.c +@@ -905,7 +905,7 @@ bio_pageinc(struct bio *bio) + /* Non-zero page count for non-head members of + * compound pages is no longer allowed by the kernel. + */ +- page = compound_trans_head(bv->bv_page); ++ page = compound_head(bv->bv_page); + atomic_inc(&page->_count); + } + } +@@ -918,7 +918,7 @@ bio_pagedec(struct bio *bio) + int i; + + bio_for_each_segment(bv, bio, i) { +- page = compound_trans_head(bv->bv_page); ++ page = compound_head(bv->bv_page); + atomic_dec(&page->_count); + } + } +diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c +index d3c3b5b15824..e79720d5ceff 100644 +--- a/drivers/gpu/drm/i915/i915_gem_gtt.c ++++ b/drivers/gpu/drm/i915/i915_gem_gtt.c +@@ -828,7 +828,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev) + dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, + dev_priv->gtt.base.start / PAGE_SIZE, + dev_priv->gtt.base.total / PAGE_SIZE, +- false); ++ true); + } + + void i915_gem_restore_gtt_mappings(struct drm_device *dev) +diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c +index 3e5ea2c87a6e..886778a60d35 100644 +--- a/drivers/i2c/busses/i2c-cpm.c ++++ b/drivers/i2c/busses/i2c-cpm.c +@@ -40,7 +40,9 @@ + #include <linux/i2c.h> + #include <linux/io.h> + #include <linux/dma-mapping.h> ++#include <linux/of_address.h> + #include <linux/of_device.h> ++#include <linux/of_irq.h> + #include <linux/of_platform.h> + #include <sysdev/fsl_soc.h> + #include <asm/cpm.h> +diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c +index a5869a856ea5..bba656a3336e 100644 +--- a/drivers/input/mouse/cypress_ps2.c ++++ b/drivers/input/mouse/cypress_ps2.c +@@ -410,7 +410,6 @@ static int cypress_set_input_params(struct input_dev *input, + __clear_bit(REL_X, input->relbit); + __clear_bit(REL_Y, input->relbit); + +- __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_LEFT, input->keybit); + __set_bit(BTN_RIGHT, input->keybit); +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 26386f9d2569..d8d49d10f9bb 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -265,11 +265,22 @@ static int synaptics_identify(struct psmouse *psmouse) + * Read touchpad resolution and maximum reported coordinates + * Resolution is left zero if touchpad does not support the query + */ ++ ++static const int *quirk_min_max; ++ + static int synaptics_resolution(struct psmouse *psmouse) + { + struct synaptics_data *priv = psmouse->private; + unsigned char resp[3]; + ++ if (quirk_min_max) { ++ priv->x_min = quirk_min_max[0]; ++ priv->x_max = quirk_min_max[1]; ++ priv->y_min = quirk_min_max[2]; ++ priv->y_max = quirk_min_max[3]; ++ return 0; ++ } ++ + if (SYN_ID_MAJOR(priv->identity) < 4) + return 0; + +@@ -1485,10 +1496,54 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = { + { } + }; + ++static const struct dmi_system_id min_max_dmi_table[] __initconst = { ++#if defined(CONFIG_DMI) ++ { ++ /* Lenovo ThinkPad Helix */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"), ++ }, ++ .driver_data = (int []){1024, 5052, 2258, 4832}, ++ }, ++ { ++ /* Lenovo ThinkPad X240 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"), ++ }, ++ .driver_data = (int []){1232, 5710, 1156, 4696}, ++ }, ++ { ++ /* Lenovo ThinkPad T440s */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"), ++ }, ++ .driver_data = (int []){1024, 5112, 2024, 4832}, ++ }, ++ { ++ /* Lenovo ThinkPad T540p */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"), ++ }, ++ .driver_data = (int []){1024, 5056, 2058, 4832}, ++ }, ++#endif ++ { } ++}; ++ + void __init synaptics_module_init(void) + { ++ const struct dmi_system_id *min_max_dmi; ++ + impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); + broken_olpc_ec = dmi_check_system(olpc_dmi_table); ++ ++ min_max_dmi = dmi_first_match(min_max_dmi_table); ++ if (min_max_dmi) ++ quirk_min_max = min_max_dmi->driver_data; + } + + static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c +index 4c842c320c2e..b604564dec5c 100644 +--- a/drivers/input/mousedev.c ++++ b/drivers/input/mousedev.c +@@ -67,7 +67,6 @@ struct mousedev { + struct device dev; + struct cdev cdev; + bool exist; +- bool is_mixdev; + + struct list_head mixdev_node; + bool opened_by_mixdev; +@@ -77,6 +76,9 @@ struct mousedev { + int old_x[4], old_y[4]; + int frac_dx, frac_dy; + unsigned long touch; ++ ++ int (*open_device)(struct mousedev *mousedev); ++ void (*close_device)(struct mousedev *mousedev); + }; + + enum mousedev_emul { +@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; + static struct mousedev *mousedev_mix; + static LIST_HEAD(mousedev_mix_list); + +-static void mixdev_open_devices(void); +-static void mixdev_close_devices(void); +- + #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) + #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) + +@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev) + if (retval) + return retval; + +- if (mousedev->is_mixdev) +- mixdev_open_devices(); +- else if (!mousedev->exist) ++ if (!mousedev->exist) + retval = -ENODEV; + else if (!mousedev->open++) { + retval = input_open_device(&mousedev->handle); +@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev) + { + mutex_lock(&mousedev->mutex); + +- if (mousedev->is_mixdev) +- mixdev_close_devices(); +- else if (mousedev->exist && !--mousedev->open) ++ if (mousedev->exist && !--mousedev->open) + input_close_device(&mousedev->handle); + + mutex_unlock(&mousedev->mutex); +@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev) + * stream. Note that this function is called with mousedev_mix->mutex + * held. + */ +-static void mixdev_open_devices(void) ++static int mixdev_open_devices(struct mousedev *mixdev) + { +- struct mousedev *mousedev; ++ int error; ++ ++ error = mutex_lock_interruptible(&mixdev->mutex); ++ if (error) ++ return error; + +- if (mousedev_mix->open++) +- return; ++ if (!mixdev->open++) { ++ struct mousedev *mousedev; + +- list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { +- if (!mousedev->opened_by_mixdev) { +- if (mousedev_open_device(mousedev)) +- continue; ++ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { ++ if (!mousedev->opened_by_mixdev) { ++ if (mousedev_open_device(mousedev)) ++ continue; + +- mousedev->opened_by_mixdev = true; ++ mousedev->opened_by_mixdev = true; ++ } + } + } ++ ++ mutex_unlock(&mixdev->mutex); ++ return 0; + } + + /* +@@ -481,19 +484,22 @@ static void mixdev_open_devices(void) + * device. Note that this function is called with mousedev_mix->mutex + * held. + */ +-static void mixdev_close_devices(void) ++static void mixdev_close_devices(struct mousedev *mixdev) + { +- struct mousedev *mousedev; ++ mutex_lock(&mixdev->mutex); + +- if (--mousedev_mix->open) +- return; ++ if (!--mixdev->open) { ++ struct mousedev *mousedev; + +- list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { +- if (mousedev->opened_by_mixdev) { +- mousedev->opened_by_mixdev = false; +- mousedev_close_device(mousedev); ++ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { ++ if (mousedev->opened_by_mixdev) { ++ mousedev->opened_by_mixdev = false; ++ mousedev_close_device(mousedev); ++ } + } + } ++ ++ mutex_unlock(&mixdev->mutex); + } + + +@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file) + mousedev_detach_client(mousedev, client); + kfree(client); + +- mousedev_close_device(mousedev); ++ mousedev->close_device(mousedev); + + return 0; + } +@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file) + client->mousedev = mousedev; + mousedev_attach_client(mousedev, client); + +- error = mousedev_open_device(mousedev); ++ error = mousedev->open_device(mousedev); + if (error) + goto err_free_client; + +@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev, + + if (mixdev) { + dev_set_name(&mousedev->dev, "mice"); ++ ++ mousedev->open_device = mixdev_open_devices; ++ mousedev->close_device = mixdev_close_devices; + } else { + int dev_no = minor; + /* Normalize device number if it falls into legacy range */ + if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) + dev_no -= MOUSEDEV_MINOR_BASE; + dev_set_name(&mousedev->dev, "mouse%d", dev_no); ++ ++ mousedev->open_device = mousedev_open_device; ++ mousedev->close_device = mousedev_close_device; + } + + mousedev->exist = true; +- mousedev->is_mixdev = mixdev; + mousedev->handle.dev = input_get_device(dev); + mousedev->handle.name = dev_name(&mousedev->dev); + mousedev->handle.handler = handler; +@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev) + device_del(&mousedev->dev); + mousedev_cleanup(mousedev); + input_free_minor(MINOR(mousedev->dev.devt)); +- if (!mousedev->is_mixdev) ++ if (mousedev != mousedev_mix) + input_unregister_handle(&mousedev->handle); + put_device(&mousedev->dev); + } +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index df75a2302740..bb2021e48344 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -88,8 +88,9 @@ + #define MVNETA_TX_IN_PRGRS BIT(1) + #define MVNETA_TX_FIFO_EMPTY BIT(8) + #define MVNETA_RX_MIN_FRAME_SIZE 0x247c +-#define MVNETA_SGMII_SERDES_CFG 0x24A0 ++#define MVNETA_SERDES_CFG 0x24A0 + #define MVNETA_SGMII_SERDES_PROTO 0x0cc7 ++#define MVNETA_RGMII_SERDES_PROTO 0x0667 + #define MVNETA_TYPE_PRIO 0x24bc + #define MVNETA_FORCE_UNI BIT(21) + #define MVNETA_TXQ_CMD_1 0x24e4 +@@ -161,7 +162,7 @@ + #define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc + #define MVNETA_GMAC0_PORT_ENABLE BIT(0) + #define MVNETA_GMAC_CTRL_2 0x2c08 +-#define MVNETA_GMAC2_PSC_ENABLE BIT(3) ++#define MVNETA_GMAC2_PCS_ENABLE BIT(3) + #define MVNETA_GMAC2_PORT_RGMII BIT(4) + #define MVNETA_GMAC2_PORT_RESET BIT(6) + #define MVNETA_GMAC_STATUS 0x2c10 +@@ -706,35 +707,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp, + mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val); + } + +- +- +-/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */ +-static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable) +-{ +- u32 val; +- +- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); +- +- if (enable) +- val |= MVNETA_GMAC2_PORT_RGMII; +- else +- val &= ~MVNETA_GMAC2_PORT_RGMII; +- +- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); +-} +- +-/* Config SGMII port */ +-static void mvneta_port_sgmii_config(struct mvneta_port *pp) +-{ +- u32 val; +- +- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); +- val |= MVNETA_GMAC2_PSC_ENABLE; +- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); +- +- mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); +-} +- + /* Start the Ethernet port RX and TX activity */ + static void mvneta_port_up(struct mvneta_port *pp) + { +@@ -2729,12 +2701,15 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode) + mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0); + + if (phy_mode == PHY_INTERFACE_MODE_SGMII) +- mvneta_port_sgmii_config(pp); ++ mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); ++ else ++ mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO); + +- mvneta_gmac_rgmii_set(pp, 1); ++ val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); ++ ++ val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII; + + /* Cancel Port Reset */ +- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); + val &= ~MVNETA_GMAC2_PORT_RESET; + mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); + +diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c +index 4fb7a8f83c8a..54af4e933695 100644 +--- a/drivers/vfio/vfio_iommu_type1.c ++++ b/drivers/vfio/vfio_iommu_type1.c +@@ -186,12 +186,12 @@ static bool is_invalid_reserved_pfn(unsigned long pfn) + if (pfn_valid(pfn)) { + bool reserved; + struct page *tail = pfn_to_page(pfn); +- struct page *head = compound_trans_head(tail); ++ struct page *head = compound_head(tail); + reserved = !!(PageReserved(head)); + if (head != tail) { + /* + * "head" is not a dangling pointer +- * (compound_trans_head takes care of that) ++ * (compound_head takes care of that) + * but the hugepage may have been split + * from under us (and we may not hold a + * reference count on the head page so it can +diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c +index 4c02e2b94103..2c85267668fc 100644 +--- a/drivers/xen/balloon.c ++++ b/drivers/xen/balloon.c +@@ -406,11 +406,25 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) + state = BP_EAGAIN; + break; + } ++ scrub_page(page); + +- pfn = page_to_pfn(page); +- frame_list[i] = pfn_to_mfn(pfn); ++ frame_list[i] = page_to_pfn(page); ++ } + +- scrub_page(page); ++ /* ++ * Ensure that ballooned highmem pages don't have kmaps. ++ * ++ * Do this before changing the p2m as kmap_flush_unused() ++ * reads PTEs to obtain pages (and hence needs the original ++ * p2m entry). ++ */ ++ kmap_flush_unused(); ++ ++ /* Update direct mapping, invalidate P2M, and add to balloon. */ ++ for (i = 0; i < nr_pages; i++) { ++ pfn = frame_list[i]; ++ frame_list[i] = pfn_to_mfn(pfn); ++ page = pfn_to_page(pfn); + + #ifdef CONFIG_XEN_HAVE_PVMMU + /* +@@ -436,11 +450,9 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) + } + #endif + +- balloon_append(pfn_to_page(pfn)); ++ balloon_append(page); + } + +- /* Ensure that ballooned highmem pages don't have kmaps. */ +- kmap_flush_unused(); + flush_tlb_all(); + + set_xen_guest_handle(reservation.extent_start, frame_list); +diff --git a/fs/dcache.c b/fs/dcache.c +index fdbe23027810..f7ad6d71b1c1 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) + u32 dlen = ACCESS_ONCE(name->len); + char *p; + +- if (*buflen < dlen + 1) +- return -ENAMETOOLONG; + *buflen -= dlen + 1; ++ if (*buflen < 0) ++ return -ENAMETOOLONG; + p = *buffer -= dlen + 1; + *p++ = '/'; + while (dlen--) { +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 31fa964742bc..3617e33257a3 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -38,6 +38,7 @@ + #include <linux/slab.h> + #include <linux/ratelimit.h> + #include <linux/aio.h> ++#include <linux/bitops.h> + + #include "ext4_jbd2.h" + #include "xattr.h" +@@ -3926,18 +3927,20 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) + void ext4_set_inode_flags(struct inode *inode) + { + unsigned int flags = EXT4_I(inode)->i_flags; ++ unsigned int new_fl = 0; + +- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + if (flags & EXT4_SYNC_FL) +- inode->i_flags |= S_SYNC; ++ new_fl |= S_SYNC; + if (flags & EXT4_APPEND_FL) +- inode->i_flags |= S_APPEND; ++ new_fl |= S_APPEND; + if (flags & EXT4_IMMUTABLE_FL) +- inode->i_flags |= S_IMMUTABLE; ++ new_fl |= S_IMMUTABLE; + if (flags & EXT4_NOATIME_FL) +- inode->i_flags |= S_NOATIME; ++ new_fl |= S_NOATIME; + if (flags & EXT4_DIRSYNC_FL) +- inode->i_flags |= S_DIRSYNC; ++ new_fl |= S_DIRSYNC; ++ set_mask_bits(&inode->i_flags, ++ S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl); + } + + /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ +diff --git a/fs/mount.h b/fs/mount.h +index a17458ca6f29..b29e42f05f34 100644 +--- a/fs/mount.h ++++ b/fs/mount.h +@@ -19,13 +19,13 @@ struct mnt_pcp { + }; + + struct mountpoint { +- struct list_head m_hash; ++ struct hlist_node m_hash; + struct dentry *m_dentry; + int m_count; + }; + + struct mount { +- struct list_head mnt_hash; ++ struct hlist_node mnt_hash; + struct mount *mnt_parent; + struct dentry *mnt_mountpoint; + struct vfsmount mnt; +diff --git a/fs/namei.c b/fs/namei.c +index cfe660870251..399f6378de54 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -1098,7 +1098,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, + return false; + + if (!d_mountpoint(path->dentry)) +- break; ++ return true; + + mounted = __lookup_mnt(path->mnt, path->dentry); + if (!mounted) +@@ -1114,20 +1114,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, + */ + *inode = path->dentry->d_inode; + } +- return true; +-} +- +-static void follow_mount_rcu(struct nameidata *nd) +-{ +- while (d_mountpoint(nd->path.dentry)) { +- struct mount *mounted; +- mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry); +- if (!mounted) +- break; +- nd->path.mnt = &mounted->mnt; +- nd->path.dentry = mounted->mnt.mnt_root; +- nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); +- } ++ return read_seqretry(&mount_lock, nd->m_seq); + } + + static int follow_dotdot_rcu(struct nameidata *nd) +@@ -1155,7 +1142,17 @@ static int follow_dotdot_rcu(struct nameidata *nd) + break; + nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); + } +- follow_mount_rcu(nd); ++ while (d_mountpoint(nd->path.dentry)) { ++ struct mount *mounted; ++ mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry); ++ if (!mounted) ++ break; ++ nd->path.mnt = &mounted->mnt; ++ nd->path.dentry = mounted->mnt.mnt_root; ++ nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); ++ if (!read_seqretry(&mount_lock, nd->m_seq)) ++ goto failed; ++ } + nd->inode = nd->path.dentry->d_inode; + return 0; + +diff --git a/fs/namespace.c b/fs/namespace.c +index be32ebccdeb1..6d0e54e27d33 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -23,11 +23,34 @@ + #include <linux/uaccess.h> + #include <linux/proc_ns.h> + #include <linux/magic.h> ++#include <linux/bootmem.h> + #include "pnode.h" + #include "internal.h" + +-#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) +-#define HASH_SIZE (1UL << HASH_SHIFT) ++static unsigned int m_hash_mask __read_mostly; ++static unsigned int m_hash_shift __read_mostly; ++static unsigned int mp_hash_mask __read_mostly; ++static unsigned int mp_hash_shift __read_mostly; ++ ++static __initdata unsigned long mhash_entries; ++static int __init set_mhash_entries(char *str) ++{ ++ if (!str) ++ return 0; ++ mhash_entries = simple_strtoul(str, &str, 0); ++ return 1; ++} ++__setup("mhash_entries=", set_mhash_entries); ++ ++static __initdata unsigned long mphash_entries; ++static int __init set_mphash_entries(char *str) ++{ ++ if (!str) ++ return 0; ++ mphash_entries = simple_strtoul(str, &str, 0); ++ return 1; ++} ++__setup("mphash_entries=", set_mphash_entries); + + static int event; + static DEFINE_IDA(mnt_id_ida); +@@ -36,8 +59,8 @@ static DEFINE_SPINLOCK(mnt_id_lock); + static int mnt_id_start = 0; + static int mnt_group_start = 1; + +-static struct list_head *mount_hashtable __read_mostly; +-static struct list_head *mountpoint_hashtable __read_mostly; ++static struct hlist_head *mount_hashtable __read_mostly; ++static struct hlist_head *mountpoint_hashtable __read_mostly; + static struct kmem_cache *mnt_cache __read_mostly; + static DECLARE_RWSEM(namespace_sem); + +@@ -55,12 +78,19 @@ EXPORT_SYMBOL_GPL(fs_kobj); + */ + __cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock); + +-static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) ++static inline struct hlist_head *m_hash(struct vfsmount *mnt, struct dentry *dentry) + { + unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); + tmp += ((unsigned long)dentry / L1_CACHE_BYTES); +- tmp = tmp + (tmp >> HASH_SHIFT); +- return tmp & (HASH_SIZE - 1); ++ tmp = tmp + (tmp >> m_hash_shift); ++ return &mount_hashtable[tmp & m_hash_mask]; ++} ++ ++static inline struct hlist_head *mp_hash(struct dentry *dentry) ++{ ++ unsigned long tmp = ((unsigned long)dentry / L1_CACHE_BYTES); ++ tmp = tmp + (tmp >> mp_hash_shift); ++ return &mountpoint_hashtable[tmp & mp_hash_mask]; + } + + /* +@@ -187,7 +217,7 @@ static struct mount *alloc_vfsmnt(const char *name) + mnt->mnt_writers = 0; + #endif + +- INIT_LIST_HEAD(&mnt->mnt_hash); ++ INIT_HLIST_NODE(&mnt->mnt_hash); + INIT_LIST_HEAD(&mnt->mnt_child); + INIT_LIST_HEAD(&mnt->mnt_mounts); + INIT_LIST_HEAD(&mnt->mnt_list); +@@ -575,10 +605,10 @@ bool legitimize_mnt(struct vfsmount *bastard, unsigned seq) + */ + struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) + { +- struct list_head *head = mount_hashtable + hash(mnt, dentry); ++ struct hlist_head *head = m_hash(mnt, dentry); + struct mount *p; + +- list_for_each_entry_rcu(p, head, mnt_hash) ++ hlist_for_each_entry_rcu(p, head, mnt_hash) + if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) + return p; + return NULL; +@@ -590,13 +620,17 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) + */ + struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) + { +- struct list_head *head = mount_hashtable + hash(mnt, dentry); +- struct mount *p; +- +- list_for_each_entry_reverse(p, head, mnt_hash) +- if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) +- return p; +- return NULL; ++ struct mount *p, *res; ++ res = p = __lookup_mnt(mnt, dentry); ++ if (!p) ++ goto out; ++ hlist_for_each_entry_continue(p, mnt_hash) { ++ if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) ++ break; ++ res = p; ++ } ++out: ++ return res; + } + + /* +@@ -633,11 +667,11 @@ struct vfsmount *lookup_mnt(struct path *path) + + static struct mountpoint *new_mountpoint(struct dentry *dentry) + { +- struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); ++ struct hlist_head *chain = mp_hash(dentry); + struct mountpoint *mp; + int ret; + +- list_for_each_entry(mp, chain, m_hash) { ++ hlist_for_each_entry(mp, chain, m_hash) { + if (mp->m_dentry == dentry) { + /* might be worth a WARN_ON() */ + if (d_unlinked(dentry)) +@@ -659,7 +693,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) + + mp->m_dentry = dentry; + mp->m_count = 1; +- list_add(&mp->m_hash, chain); ++ hlist_add_head(&mp->m_hash, chain); + return mp; + } + +@@ -670,7 +704,7 @@ static void put_mountpoint(struct mountpoint *mp) + spin_lock(&dentry->d_lock); + dentry->d_flags &= ~DCACHE_MOUNTED; + spin_unlock(&dentry->d_lock); +- list_del(&mp->m_hash); ++ hlist_del(&mp->m_hash); + kfree(mp); + } + } +@@ -712,7 +746,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path) + mnt->mnt_parent = mnt; + mnt->mnt_mountpoint = mnt->mnt.mnt_root; + list_del_init(&mnt->mnt_child); +- list_del_init(&mnt->mnt_hash); ++ hlist_del_init_rcu(&mnt->mnt_hash); + put_mountpoint(mnt->mnt_mp); + mnt->mnt_mp = NULL; + } +@@ -739,15 +773,14 @@ static void attach_mnt(struct mount *mnt, + struct mountpoint *mp) + { + mnt_set_mountpoint(parent, mp, mnt); +- list_add_tail(&mnt->mnt_hash, mount_hashtable + +- hash(&parent->mnt, mp->m_dentry)); ++ hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry)); + list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); + } + + /* + * vfsmount lock must be held for write + */ +-static void commit_tree(struct mount *mnt) ++static void commit_tree(struct mount *mnt, struct mount *shadows) + { + struct mount *parent = mnt->mnt_parent; + struct mount *m; +@@ -762,8 +795,11 @@ static void commit_tree(struct mount *mnt) + + list_splice(&head, n->list.prev); + +- list_add_tail(&mnt->mnt_hash, mount_hashtable + +- hash(&parent->mnt, mnt->mnt_mountpoint)); ++ if (shadows) ++ hlist_add_after_rcu(&shadows->mnt_hash, &mnt->mnt_hash); ++ else ++ hlist_add_head_rcu(&mnt->mnt_hash, ++ m_hash(&parent->mnt, mnt->mnt_mountpoint)); + list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); + touch_mnt_namespace(n); + } +@@ -1153,26 +1189,28 @@ int may_umount(struct vfsmount *mnt) + + EXPORT_SYMBOL(may_umount); + +-static LIST_HEAD(unmounted); /* protected by namespace_sem */ ++static HLIST_HEAD(unmounted); /* protected by namespace_sem */ + + static void namespace_unlock(void) + { + struct mount *mnt; +- LIST_HEAD(head); ++ struct hlist_head head = unmounted; + +- if (likely(list_empty(&unmounted))) { ++ if (likely(hlist_empty(&head))) { + up_write(&namespace_sem); + return; + } + +- list_splice_init(&unmounted, &head); ++ head.first->pprev = &head.first; ++ INIT_HLIST_HEAD(&unmounted); ++ + up_write(&namespace_sem); + + synchronize_rcu(); + +- while (!list_empty(&head)) { +- mnt = list_first_entry(&head, struct mount, mnt_hash); +- list_del_init(&mnt->mnt_hash); ++ while (!hlist_empty(&head)) { ++ mnt = hlist_entry(head.first, struct mount, mnt_hash); ++ hlist_del_init(&mnt->mnt_hash); + if (mnt->mnt_ex_mountpoint.mnt) + path_put(&mnt->mnt_ex_mountpoint); + mntput(&mnt->mnt); +@@ -1193,16 +1231,19 @@ static inline void namespace_lock(void) + */ + void umount_tree(struct mount *mnt, int how) + { +- LIST_HEAD(tmp_list); ++ HLIST_HEAD(tmp_list); + struct mount *p; ++ struct mount *last = NULL; + +- for (p = mnt; p; p = next_mnt(p, mnt)) +- list_move(&p->mnt_hash, &tmp_list); ++ for (p = mnt; p; p = next_mnt(p, mnt)) { ++ hlist_del_init_rcu(&p->mnt_hash); ++ hlist_add_head(&p->mnt_hash, &tmp_list); ++ } + + if (how) + propagate_umount(&tmp_list); + +- list_for_each_entry(p, &tmp_list, mnt_hash) { ++ hlist_for_each_entry(p, &tmp_list, mnt_hash) { + list_del_init(&p->mnt_expire); + list_del_init(&p->mnt_list); + __touch_mnt_namespace(p->mnt_ns); +@@ -1220,8 +1261,13 @@ void umount_tree(struct mount *mnt, int how) + p->mnt_mp = NULL; + } + change_mnt_propagation(p, MS_PRIVATE); ++ last = p; ++ } ++ if (last) { ++ last->mnt_hash.next = unmounted.first; ++ unmounted.first = tmp_list.first; ++ unmounted.first->pprev = &unmounted.first; + } +- list_splice(&tmp_list, &unmounted); + } + + static void shrink_submounts(struct mount *mnt); +@@ -1605,24 +1651,23 @@ static int attach_recursive_mnt(struct mount *source_mnt, + struct mountpoint *dest_mp, + struct path *parent_path) + { +- LIST_HEAD(tree_list); ++ HLIST_HEAD(tree_list); + struct mount *child, *p; ++ struct hlist_node *n; + int err; + + if (IS_MNT_SHARED(dest_mnt)) { + err = invent_group_ids(source_mnt, true); + if (err) + goto out; +- } +- err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list); +- if (err) +- goto out_cleanup_ids; +- +- lock_mount_hash(); +- +- if (IS_MNT_SHARED(dest_mnt)) { ++ err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list); ++ if (err) ++ goto out_cleanup_ids; ++ lock_mount_hash(); + for (p = source_mnt; p; p = next_mnt(p, source_mnt)) + set_mnt_shared(p); ++ } else { ++ lock_mount_hash(); + } + if (parent_path) { + detach_mnt(source_mnt, parent_path); +@@ -1630,20 +1675,22 @@ static int attach_recursive_mnt(struct mount *source_mnt, + touch_mnt_namespace(source_mnt->mnt_ns); + } else { + mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); +- commit_tree(source_mnt); ++ commit_tree(source_mnt, NULL); + } + +- list_for_each_entry_safe(child, p, &tree_list, mnt_hash) { +- list_del_init(&child->mnt_hash); +- commit_tree(child); ++ hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) { ++ struct mount *q; ++ hlist_del_init(&child->mnt_hash); ++ q = __lookup_mnt_last(&child->mnt_parent->mnt, ++ child->mnt_mountpoint); ++ commit_tree(child, q); + } + unlock_mount_hash(); + + return 0; + + out_cleanup_ids: +- if (IS_MNT_SHARED(dest_mnt)) +- cleanup_group_ids(source_mnt, NULL); ++ cleanup_group_ids(source_mnt, NULL); + out: + return err; + } +@@ -2777,18 +2824,24 @@ void __init mnt_init(void) + mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), + 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); + +- mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); +- mountpoint_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); ++ mount_hashtable = alloc_large_system_hash("Mount-cache", ++ sizeof(struct hlist_head), ++ mhash_entries, 19, ++ 0, ++ &m_hash_shift, &m_hash_mask, 0, 0); ++ mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache", ++ sizeof(struct hlist_head), ++ mphash_entries, 19, ++ 0, ++ &mp_hash_shift, &mp_hash_mask, 0, 0); + + if (!mount_hashtable || !mountpoint_hashtable) + panic("Failed to allocate mount hash table\n"); + +- printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE); +- +- for (u = 0; u < HASH_SIZE; u++) +- INIT_LIST_HEAD(&mount_hashtable[u]); +- for (u = 0; u < HASH_SIZE; u++) +- INIT_LIST_HEAD(&mountpoint_hashtable[u]); ++ for (u = 0; u <= m_hash_mask; u++) ++ INIT_HLIST_HEAD(&mount_hashtable[u]); ++ for (u = 0; u <= mp_hash_mask; u++) ++ INIT_HLIST_HEAD(&mountpoint_hashtable[u]); + + err = sysfs_init(); + if (err) +diff --git a/fs/pnode.c b/fs/pnode.c +index c7221bb19801..88396df725b4 100644 +--- a/fs/pnode.c ++++ b/fs/pnode.c +@@ -220,14 +220,14 @@ static struct mount *get_source(struct mount *dest, + * @tree_list : list of heads of trees to be attached. + */ + int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, +- struct mount *source_mnt, struct list_head *tree_list) ++ struct mount *source_mnt, struct hlist_head *tree_list) + { + struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; + struct mount *m, *child; + int ret = 0; + struct mount *prev_dest_mnt = dest_mnt; + struct mount *prev_src_mnt = source_mnt; +- LIST_HEAD(tmp_list); ++ HLIST_HEAD(tmp_list); + + for (m = propagation_next(dest_mnt, dest_mnt); m; + m = propagation_next(m, dest_mnt)) { +@@ -246,27 +246,29 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, + child = copy_tree(source, source->mnt.mnt_root, type); + if (IS_ERR(child)) { + ret = PTR_ERR(child); +- list_splice(tree_list, tmp_list.prev); ++ tmp_list = *tree_list; ++ tmp_list.first->pprev = &tmp_list.first; ++ INIT_HLIST_HEAD(tree_list); + goto out; + } + + if (is_subdir(dest_mp->m_dentry, m->mnt.mnt_root)) { + mnt_set_mountpoint(m, dest_mp, child); +- list_add_tail(&child->mnt_hash, tree_list); ++ hlist_add_head(&child->mnt_hash, tree_list); + } else { + /* + * This can happen if the parent mount was bind mounted + * on some subdirectory of a shared/slave mount. + */ +- list_add_tail(&child->mnt_hash, &tmp_list); ++ hlist_add_head(&child->mnt_hash, &tmp_list); + } + prev_dest_mnt = m; + prev_src_mnt = child; + } + out: + lock_mount_hash(); +- while (!list_empty(&tmp_list)) { +- child = list_first_entry(&tmp_list, struct mount, mnt_hash); ++ while (!hlist_empty(&tmp_list)) { ++ child = hlist_entry(tmp_list.first, struct mount, mnt_hash); + umount_tree(child, 0); + } + unlock_mount_hash(); +@@ -338,8 +340,10 @@ static void __propagate_umount(struct mount *mnt) + * umount the child only if the child has no + * other children + */ +- if (child && list_empty(&child->mnt_mounts)) +- list_move_tail(&child->mnt_hash, &mnt->mnt_hash); ++ if (child && list_empty(&child->mnt_mounts)) { ++ hlist_del_init_rcu(&child->mnt_hash); ++ hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash); ++ } + } + } + +@@ -350,11 +354,11 @@ static void __propagate_umount(struct mount *mnt) + * + * vfsmount lock must be held for write + */ +-int propagate_umount(struct list_head *list) ++int propagate_umount(struct hlist_head *list) + { + struct mount *mnt; + +- list_for_each_entry(mnt, list, mnt_hash) ++ hlist_for_each_entry(mnt, list, mnt_hash) + __propagate_umount(mnt); + return 0; + } +diff --git a/fs/pnode.h b/fs/pnode.h +index 59e7eda1851e..fc28a27fa892 100644 +--- a/fs/pnode.h ++++ b/fs/pnode.h +@@ -36,8 +36,8 @@ static inline void set_mnt_shared(struct mount *mnt) + + void change_mnt_propagation(struct mount *, int); + int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, +- struct list_head *); +-int propagate_umount(struct list_head *); ++ struct hlist_head *); ++int propagate_umount(struct hlist_head *); + int propagate_mount_busy(struct mount *, int); + void mnt_release_group_id(struct mount *); + int get_dominating_id(struct mount *mnt, const struct path *root); +diff --git a/fs/proc/page.c b/fs/proc/page.c +index b8730d9ebaee..2a8cc94bb641 100644 +--- a/fs/proc/page.c ++++ b/fs/proc/page.c +@@ -121,7 +121,7 @@ u64 stable_page_flags(struct page *page) + * just checks PG_head/PG_tail, so we need to check PageLRU to make + * sure a given page is a thp, not a non-huge compound page. + */ +- else if (PageTransCompound(page) && PageLRU(compound_trans_head(page))) ++ else if (PageTransCompound(page) && PageLRU(compound_head(page))) + u |= 1 << KPF_THP; + + /* +diff --git a/include/linux/bitops.h b/include/linux/bitops.h +index abc9ca778456..be5fd38bd5a0 100644 +--- a/include/linux/bitops.h ++++ b/include/linux/bitops.h +@@ -196,6 +196,21 @@ static inline unsigned long __ffs64(u64 word) + + #ifdef __KERNEL__ + ++#ifndef set_mask_bits ++#define set_mask_bits(ptr, _mask, _bits) \ ++({ \ ++ const typeof(*ptr) mask = (_mask), bits = (_bits); \ ++ typeof(*ptr) old, new; \ ++ \ ++ do { \ ++ old = ACCESS_ONCE(*ptr); \ ++ new = (old & ~mask) | bits; \ ++ } while (cmpxchg(ptr, old, new) != old); \ ++ \ ++ new; \ ++}) ++#endif ++ + #ifndef find_last_bit + /** + * find_last_bit - find the last set bit in a memory region +diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h +index 39c1d9469677..10d59f3a5ebd 100644 +--- a/include/linux/cgroup.h ++++ b/include/linux/cgroup.h +@@ -169,6 +169,8 @@ struct cgroup { + * + * The ID of the root cgroup is always 0, and a new cgroup + * will be assigned with a smallest available ID. ++ * ++ * Allocating/Removing ID must be protected by cgroup_mutex. + */ + int id; + +diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h +index 91672e2deec3..b826239bdce0 100644 +--- a/include/linux/huge_mm.h ++++ b/include/linux/huge_mm.h +@@ -157,23 +157,6 @@ static inline int hpage_nr_pages(struct page *page) + return HPAGE_PMD_NR; + return 1; + } +-static inline struct page *compound_trans_head(struct page *page) +-{ +- if (PageTail(page)) { +- struct page *head; +- head = page->first_page; +- smp_rmb(); +- /* +- * head may be a dangling pointer. +- * __split_huge_page_refcount clears PageTail before +- * overwriting first_page, so if PageTail is still +- * there it means the head pointer isn't dangling. +- */ +- if (PageTail(page)) +- return head; +- } +- return page; +-} + + extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long addr, pmd_t pmd, pmd_t *pmdp); +@@ -203,7 +186,6 @@ static inline int split_huge_page(struct page *page) + do { } while (0) + #define split_huge_page_pmd_mm(__mm, __address, __pmd) \ + do { } while (0) +-#define compound_trans_head(page) compound_head(page) + static inline int hugepage_madvise(struct vm_area_struct *vma, + unsigned long *vm_flags, int advice) + { +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 0ab54390a63b..5360b8245109 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -389,8 +389,18 @@ static inline void compound_unlock_irqrestore(struct page *page, + + static inline struct page *compound_head(struct page *page) + { +- if (unlikely(PageTail(page))) +- return page->first_page; ++ if (unlikely(PageTail(page))) { ++ struct page *head = page->first_page; ++ ++ /* ++ * page->first_page may be a dangling pointer to an old ++ * compound page, so recheck that it is still a tail ++ * page before returning. ++ */ ++ smp_rmb(); ++ if (likely(PageTail(page))) ++ return head; ++ } + return page; + } + +diff --git a/kernel/cgroup.c b/kernel/cgroup.c +index 271acd834913..b44dd4989bc1 100644 +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -4363,16 +4363,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, + rcu_assign_pointer(cgrp->name, name); + + /* +- * Temporarily set the pointer to NULL, so idr_find() won't return +- * a half-baked cgroup. +- */ +- cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); +- if (cgrp->id < 0) { +- err = -ENOMEM; +- goto err_free_name; +- } +- +- /* + * Only live parents can have children. Note that the liveliness + * check isn't strictly necessary because cgroup_mkdir() and + * cgroup_rmdir() are fully synchronized by i_mutex; however, do it +@@ -4381,7 +4371,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, + */ + if (!cgroup_lock_live_group(parent)) { + err = -ENODEV; +- goto err_free_id; ++ goto err_free_name; + } + + /* Grab a reference on the superblock so the hierarchy doesn't +@@ -4391,6 +4381,16 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, + * fs */ + atomic_inc(&sb->s_active); + ++ /* ++ * Temporarily set the pointer to NULL, so idr_find() won't return ++ * a half-baked cgroup. ++ */ ++ cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); ++ if (cgrp->id < 0) { ++ err = -ENOMEM; ++ goto err_unlock; ++ } ++ + init_cgroup_housekeeping(cgrp); + + dentry->d_fsdata = cgrp; +@@ -4491,11 +4491,11 @@ err_free_all: + ss->css_free(css); + } + } ++ idr_remove(&root->cgroup_idr, cgrp->id); ++err_unlock: + mutex_unlock(&cgroup_mutex); + /* Release the reference count that we took on the superblock */ + deactivate_super(sb); +-err_free_id: +- idr_remove(&root->cgroup_idr, cgrp->id); + err_free_name: + kfree(rcu_dereference_raw(cgrp->name)); + err_free_cgrp: +diff --git a/lib/random32.c b/lib/random32.c +index 1e5b2df44291..614896778700 100644 +--- a/lib/random32.c ++++ b/lib/random32.c +@@ -244,8 +244,19 @@ static void __prandom_reseed(bool late) + static bool latch = false; + static DEFINE_SPINLOCK(lock); + ++ /* Asking for random bytes might result in bytes getting ++ * moved into the nonblocking pool and thus marking it ++ * as initialized. In this case we would double back into ++ * this function and attempt to do a late reseed. ++ * Ignore the pointless attempt to reseed again if we're ++ * already waiting for bytes when the nonblocking pool ++ * got initialized. ++ */ ++ + /* only allow initial seeding (late == false) once */ +- spin_lock_irqsave(&lock, flags); ++ if (!spin_trylock_irqsave(&lock, flags)) ++ return; ++ + if (latch && !late) + goto out; + latch = true; +diff --git a/mm/ksm.c b/mm/ksm.c +index 175fff79dc95..418b8cad8b01 100644 +--- a/mm/ksm.c ++++ b/mm/ksm.c +@@ -444,7 +444,7 @@ static void break_cow(struct rmap_item *rmap_item) + static struct page *page_trans_compound_anon(struct page *page) + { + if (PageTransCompound(page)) { +- struct page *head = compound_trans_head(page); ++ struct page *head = compound_head(page); + /* + * head may actually be splitted and freed from under + * us but it's ok here. +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index 90977ac8bed8..4566e8fa7b71 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1645,7 +1645,7 @@ int soft_offline_page(struct page *page, int flags) + { + int ret; + unsigned long pfn = page_to_pfn(page); +- struct page *hpage = compound_trans_head(page); ++ struct page *hpage = compound_head(page); + + if (PageHWPoison(page)) { + pr_info("soft offline: %#lx page already poisoned\n", pfn); +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 56f268de3d41..589521d432d8 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -369,9 +369,11 @@ void prep_compound_page(struct page *page, unsigned long order) + __SetPageHead(page); + for (i = 1; i < nr_pages; i++) { + struct page *p = page + i; +- __SetPageTail(p); + set_page_count(p, 0); + p->first_page = page; ++ /* Make sure p->first_page is always valid for PageTail() */ ++ smp_wmb(); ++ __SetPageTail(p); + } + } + +diff --git a/mm/swap.c b/mm/swap.c +index 84b26aaabd03..7010cf417fdf 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -84,7 +84,7 @@ static void put_compound_page(struct page *page) + { + if (unlikely(PageTail(page))) { + /* __split_huge_page_refcount can run under us */ +- struct page *page_head = compound_trans_head(page); ++ struct page *page_head = compound_head(page); + + if (likely(page != page_head && + get_page_unless_zero(page_head))) { +@@ -222,7 +222,7 @@ bool __get_page_tail(struct page *page) + */ + unsigned long flags; + bool got = false; +- struct page *page_head = compound_trans_head(page); ++ struct page *page_head = compound_head(page); + + if (likely(page != page_head && get_page_unless_zero(page_head))) { + /* Ref to put_compound_page() comment. */ +diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c +index a99b6c3427b0..59359bec328a 100644 +--- a/net/netfilter/nf_conntrack_proto_dccp.c ++++ b/net/netfilter/nf_conntrack_proto_dccp.c +@@ -428,7 +428,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, + const char *msg; + u_int8_t state; + +- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); ++ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); + BUG_ON(dh == NULL); + + state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; +@@ -486,7 +486,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, + u_int8_t type, old_state, new_state; + enum ct_dccp_roles role; + +- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); ++ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); + BUG_ON(dh == NULL); + type = dh->dccph_type; + +@@ -577,7 +577,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl, + unsigned int cscov; + const char *msg; + +- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); ++ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); + if (dh == NULL) { + msg = "nf_ct_dccp: short packet "; + goto out_invalid;