aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-15 15:05:57 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-15 15:05:57 -0500
commit11e7651432405eeee833fe9d1307488df7a81cd3 (patch)
tree95e6b990ff145cac9c58f40e12f2e116acb260b3
parent5c0857a9afc74ec83e222ea1b9808988d08139d9 (diff)
parentf4d9605434c0fd4cc8639bf25cfc043418c52362 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Pull sparc fixes from David Miller: "A couple small fixes for sparc including some THP brown-paper-bag material: 1) During the merging of all the THP support for various architectures, sparc missed adding a HAVE_ARCH_TRANSPARENT_HUGEPAGE to it's Kconfig, oops. 2) Sparc needs to be mindful of hugepages in get_user_pages_fast(). 3) Fix memory leak in SBUS probe, from Cong Ding. 4) The sunvdc virtual disk client driver has a test of the bitmask of vdisk server supported operations which was off by one bit" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sunvdc: Fix off-by-one in generic_request(). sparc64: Fix get_user_pages_fast() wrt. THP. sparc64: Add missing HAVE_ARCH_TRANSPARENT_HUGEPAGE. sparc: kernel/sbus.c: fix memory leakage
-rw-r--r--arch/sparc/Kconfig1
-rw-r--r--arch/sparc/include/asm/pgtable_64.h14
-rw-r--r--arch/sparc/kernel/sbus.c6
-rw-r--r--arch/sparc/mm/gup.c59
-rw-r--r--drivers/block/sunvdc.c2
5 files changed, 68 insertions, 14 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 9f2edb5c5551..cb9c333d74e8 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -61,6 +61,7 @@ config SPARC64
61 select HAVE_MEMBLOCK 61 select HAVE_MEMBLOCK
62 select HAVE_MEMBLOCK_NODE_MAP 62 select HAVE_MEMBLOCK_NODE_MAP
63 select HAVE_SYSCALL_WRAPPERS 63 select HAVE_SYSCALL_WRAPPERS
64 select HAVE_ARCH_TRANSPARENT_HUGEPAGE
64 select HAVE_DYNAMIC_FTRACE 65 select HAVE_DYNAMIC_FTRACE
65 select HAVE_FTRACE_MCOUNT_RECORD 66 select HAVE_FTRACE_MCOUNT_RECORD
66 select HAVE_SYSCALL_TRACEPOINTS 67 select HAVE_SYSCALL_TRACEPOINTS
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 7870be0f5adc..08fcce90316b 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -71,7 +71,6 @@
71#define PMD_PADDR _AC(0xfffffffe,UL) 71#define PMD_PADDR _AC(0xfffffffe,UL)
72#define PMD_PADDR_SHIFT _AC(11,UL) 72#define PMD_PADDR_SHIFT _AC(11,UL)
73 73
74#ifdef CONFIG_TRANSPARENT_HUGEPAGE
75#define PMD_ISHUGE _AC(0x00000001,UL) 74#define PMD_ISHUGE _AC(0x00000001,UL)
76 75
77/* This is the PMD layout when PMD_ISHUGE is set. With 4MB huge 76/* This is the PMD layout when PMD_ISHUGE is set. With 4MB huge
@@ -86,7 +85,6 @@
86#define PMD_HUGE_ACCESSED _AC(0x00000080,UL) 85#define PMD_HUGE_ACCESSED _AC(0x00000080,UL)
87#define PMD_HUGE_EXEC _AC(0x00000040,UL) 86#define PMD_HUGE_EXEC _AC(0x00000040,UL)
88#define PMD_HUGE_SPLITTING _AC(0x00000020,UL) 87#define PMD_HUGE_SPLITTING _AC(0x00000020,UL)
89#endif
90 88
91/* PGDs point to PMD tables which are 8K aligned. */ 89/* PGDs point to PMD tables which are 8K aligned. */
92#define PGD_PADDR _AC(0xfffffffc,UL) 90#define PGD_PADDR _AC(0xfffffffc,UL)
@@ -628,6 +626,12 @@ static inline unsigned long pte_special(pte_t pte)
628 return pte_val(pte) & _PAGE_SPECIAL; 626 return pte_val(pte) & _PAGE_SPECIAL;
629} 627}
630 628
629static inline int pmd_large(pmd_t pmd)
630{
631 return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
632 (PMD_ISHUGE | PMD_HUGE_PRESENT);
633}
634
631#ifdef CONFIG_TRANSPARENT_HUGEPAGE 635#ifdef CONFIG_TRANSPARENT_HUGEPAGE
632static inline int pmd_young(pmd_t pmd) 636static inline int pmd_young(pmd_t pmd)
633{ 637{
@@ -646,12 +650,6 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
646 return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT); 650 return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT);
647} 651}
648 652
649static inline int pmd_large(pmd_t pmd)
650{
651 return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
652 (PMD_ISHUGE | PMD_HUGE_PRESENT);
653}
654
655static inline int pmd_trans_splitting(pmd_t pmd) 653static inline int pmd_trans_splitting(pmd_t pmd)
656{ 654{
657 return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) == 655 return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) ==
diff --git a/arch/sparc/kernel/sbus.c b/arch/sparc/kernel/sbus.c
index 1271b3a27d4e..be5bdf93c767 100644
--- a/arch/sparc/kernel/sbus.c
+++ b/arch/sparc/kernel/sbus.c
@@ -554,10 +554,8 @@ static void __init sbus_iommu_init(struct platform_device *op)
554 regs = pr->phys_addr; 554 regs = pr->phys_addr;
555 555
556 iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); 556 iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
557 if (!iommu)
558 goto fatal_memory_error;
559 strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC); 557 strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC);
560 if (!strbuf) 558 if (!iommu || !strbuf)
561 goto fatal_memory_error; 559 goto fatal_memory_error;
562 560
563 op->dev.archdata.iommu = iommu; 561 op->dev.archdata.iommu = iommu;
@@ -656,6 +654,8 @@ static void __init sbus_iommu_init(struct platform_device *op)
656 return; 654 return;
657 655
658fatal_memory_error: 656fatal_memory_error:
657 kfree(iommu);
658 kfree(strbuf);
659 prom_printf("sbus_iommu_init: Fatal memory allocation error.\n"); 659 prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
660} 660}
661 661
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c
index 42c55df3aec3..01ee23dd724d 100644
--- a/arch/sparc/mm/gup.c
+++ b/arch/sparc/mm/gup.c
@@ -66,6 +66,56 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
66 return 1; 66 return 1;
67} 67}
68 68
69static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
70 unsigned long end, int write, struct page **pages,
71 int *nr)
72{
73 struct page *head, *page, *tail;
74 u32 mask;
75 int refs;
76
77 mask = PMD_HUGE_PRESENT;
78 if (write)
79 mask |= PMD_HUGE_WRITE;
80 if ((pmd_val(pmd) & mask) != mask)
81 return 0;
82
83 refs = 0;
84 head = pmd_page(pmd);
85 page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
86 tail = page;
87 do {
88 VM_BUG_ON(compound_head(page) != head);
89 pages[*nr] = page;
90 (*nr)++;
91 page++;
92 refs++;
93 } while (addr += PAGE_SIZE, addr != end);
94
95 if (!page_cache_add_speculative(head, refs)) {
96 *nr -= refs;
97 return 0;
98 }
99
100 if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
101 *nr -= refs;
102 while (refs--)
103 put_page(head);
104 return 0;
105 }
106
107 /* Any tail page need their mapcount reference taken before we
108 * return.
109 */
110 while (refs--) {
111 if (PageTail(tail))
112 get_huge_page_tail(tail);
113 tail++;
114 }
115
116 return 1;
117}
118
69static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, 119static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
70 int write, struct page **pages, int *nr) 120 int write, struct page **pages, int *nr)
71{ 121{
@@ -77,9 +127,14 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
77 pmd_t pmd = *pmdp; 127 pmd_t pmd = *pmdp;
78 128
79 next = pmd_addr_end(addr, end); 129 next = pmd_addr_end(addr, end);
80 if (pmd_none(pmd)) 130 if (pmd_none(pmd) || pmd_trans_splitting(pmd))
81 return 0; 131 return 0;
82 if (!gup_pte_range(pmd, addr, next, write, pages, nr)) 132 if (unlikely(pmd_large(pmd))) {
133 if (!gup_huge_pmd(pmdp, pmd, addr, next,
134 write, pages, nr))
135 return 0;
136 } else if (!gup_pte_range(pmd, addr, next, write,
137 pages, nr))
83 return 0; 138 return 0;
84 } while (pmdp++, addr = next, addr != end); 139 } while (pmdp++, addr = next, addr != end);
85 140
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 564156a8e572..5814deb6963d 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -461,7 +461,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
461 int op_len, err; 461 int op_len, err;
462 void *req_buf; 462 void *req_buf;
463 463
464 if (!(((u64)1 << ((u64)op - 1)) & port->operations)) 464 if (!(((u64)1 << (u64)op) & port->operations))
465 return -EOPNOTSUPP; 465 return -EOPNOTSUPP;
466 466
467 switch (op) { 467 switch (op) {