Skip to content

Commit f1ebdd6

Browse files
committed
Merge branch 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6
* 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6: (22 commits) Add _addr_lsb field to ia64 siginfo Fix migration.c compilation on s390 HWPOISON: Remove retry loop for try_to_unmap HWPOISON: Turn addr_valid from bitfield into char HWPOISON: Disable DEBUG by default HWPOISON: Convert pr_debugs to pr_info HWPOISON: Improve comments in memory-failure.c x86: HWPOISON: Report correct address granuality for huge hwpoison faults Encode huge page size for VM_FAULT_HWPOISON errors Fix build error with !CONFIG_MIGRATION hugepage: move is_hugepage_on_freelist inside ifdef to avoid warning Clean up __page_set_anon_rmap HWPOISON, hugetlb: fix unpoison for hugepage HWPOISON, hugetlb: soft offlining for hugepage HWPOSION, hugetlb: recover from free hugepage error when !MF_COUNT_INCREASED hugetlb: move refcounting in hugepage allocation inside hugetlb_lock HWPOISON, hugetlb: add free check to dequeue_hwpoison_huge_page() hugetlb: hugepage migration core hugetlb: redefine hugepage copy functions hugetlb: add allocate function for hugepage migration ...
2 parents f99d055 + 46e387b commit f1ebdd6

File tree

13 files changed

+596
-167
lines changed

13 files changed

+596
-167
lines changed

arch/ia64/include/asm/siginfo.h

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ typedef struct siginfo {
6262
int _imm; /* immediate value for "break" */
6363
unsigned int _flags; /* see below */
6464
unsigned long _isr; /* isr */
65+
short _addr_lsb; /* lsb of faulting address */
6566
} _sigfault;
6667

6768
/* SIGPOLL */

arch/x86/mm/fault.c

+13-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/kprobes.h> /* __kprobes, ... */
1212
#include <linux/mmiotrace.h> /* kmmio_handler, ... */
1313
#include <linux/perf_event.h> /* perf_sw_event */
14+
#include <linux/hugetlb.h> /* hstate_index_to_shift */
1415

1516
#include <asm/traps.h> /* dotraplinkage, ... */
1617
#include <asm/pgalloc.h> /* pgd_*(), ... */
@@ -160,15 +161,20 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
160161

161162
static void
162163
force_sig_info_fault(int si_signo, int si_code, unsigned long address,
163-
struct task_struct *tsk)
164+
struct task_struct *tsk, int fault)
164165
{
166+
unsigned lsb = 0;
165167
siginfo_t info;
166168

167169
info.si_signo = si_signo;
168170
info.si_errno = 0;
169171
info.si_code = si_code;
170172
info.si_addr = (void __user *)address;
171-
info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0;
173+
if (fault & VM_FAULT_HWPOISON_LARGE)
174+
lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
175+
if (fault & VM_FAULT_HWPOISON)
176+
lsb = PAGE_SHIFT;
177+
info.si_addr_lsb = lsb;
172178

173179
force_sig_info(si_signo, &info, tsk);
174180
}
@@ -722,7 +728,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
722728
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
723729
tsk->thread.trap_no = 14;
724730

725-
force_sig_info_fault(SIGSEGV, si_code, address, tsk);
731+
force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
726732

727733
return;
728734
}
@@ -807,14 +813,14 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
807813
tsk->thread.trap_no = 14;
808814

809815
#ifdef CONFIG_MEMORY_FAILURE
810-
if (fault & VM_FAULT_HWPOISON) {
816+
if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
811817
printk(KERN_ERR
812818
"MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
813819
tsk->comm, tsk->pid, address);
814820
code = BUS_MCEERR_AR;
815821
}
816822
#endif
817-
force_sig_info_fault(SIGBUS, code, address, tsk);
823+
force_sig_info_fault(SIGBUS, code, address, tsk, fault);
818824
}
819825

820826
static noinline void
@@ -824,7 +830,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
824830
if (fault & VM_FAULT_OOM) {
825831
out_of_memory(regs, error_code, address);
826832
} else {
827-
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON))
833+
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
834+
VM_FAULT_HWPOISON_LARGE))
828835
do_sigbus(regs, error_code, address, fault);
829836
else
830837
BUG();

fs/hugetlbfs/inode.c

+15
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/statfs.h>
3232
#include <linux/security.h>
3333
#include <linux/magic.h>
34+
#include <linux/migrate.h>
3435

3536
#include <asm/uaccess.h>
3637

@@ -573,6 +574,19 @@ static int hugetlbfs_set_page_dirty(struct page *page)
573574
return 0;
574575
}
575576

577+
static int hugetlbfs_migrate_page(struct address_space *mapping,
578+
struct page *newpage, struct page *page)
579+
{
580+
int rc;
581+
582+
rc = migrate_huge_page_move_mapping(mapping, newpage, page);
583+
if (rc)
584+
return rc;
585+
migrate_page_copy(newpage, page);
586+
587+
return 0;
588+
}
589+
576590
static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
577591
{
578592
struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
@@ -659,6 +673,7 @@ static const struct address_space_operations hugetlbfs_aops = {
659673
.write_begin = hugetlbfs_write_begin,
660674
.write_end = hugetlbfs_write_end,
661675
.set_page_dirty = hugetlbfs_set_page_dirty,
676+
.migratepage = hugetlbfs_migrate_page,
662677
};
663678

664679

fs/signalfd.c

+10
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
9898
err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr);
9999
#ifdef __ARCH_SI_TRAPNO
100100
err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
101+
#endif
102+
#ifdef BUS_MCEERR_AO
103+
/*
104+
* Other callers might not initialize the si_lsb field,
105+
* so check explicitly for the right codes here.
106+
*/
107+
if (kinfo->si_code == BUS_MCEERR_AR ||
108+
kinfo->si_code == BUS_MCEERR_AO)
109+
err |= __put_user((short) kinfo->si_addr_lsb,
110+
&uinfo->ssi_addr_lsb);
101111
#endif
102112
break;
103113
case __SI_CHLD:

include/linux/hugetlb.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to,
4343
struct vm_area_struct *vma,
4444
int acctflags);
4545
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
46-
void __isolate_hwpoisoned_huge_page(struct page *page);
46+
int dequeue_hwpoisoned_huge_page(struct page *page);
47+
void copy_huge_page(struct page *dst, struct page *src);
4748

4849
extern unsigned long hugepages_treat_as_movable;
4950
extern const unsigned long hugetlb_zero, hugetlb_infinity;
@@ -101,7 +102,10 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
101102
#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
102103
#define hugetlb_fault(mm, vma, addr, flags) ({ BUG(); 0; })
103104
#define huge_pte_offset(mm, address) 0
104-
#define __isolate_hwpoisoned_huge_page(page) 0
105+
#define dequeue_hwpoisoned_huge_page(page) 0
106+
static inline void copy_huge_page(struct page *dst, struct page *src)
107+
{
108+
}
105109

106110
#define hugetlb_change_protection(vma, address, end, newprot)
107111

@@ -228,6 +232,8 @@ struct huge_bootmem_page {
228232
struct hstate *hstate;
229233
};
230234

235+
struct page *alloc_huge_page_node(struct hstate *h, int nid);
236+
231237
/* arch callback */
232238
int __init alloc_bootmem_huge_page(struct hstate *h);
233239

@@ -301,8 +307,14 @@ static inline struct hstate *page_hstate(struct page *page)
301307
return size_to_hstate(PAGE_SIZE << compound_order(page));
302308
}
303309

310+
static inline unsigned hstate_index_to_shift(unsigned index)
311+
{
312+
return hstates[index].order + PAGE_SHIFT;
313+
}
314+
304315
#else
305316
struct hstate {};
317+
#define alloc_huge_page_node(h, nid) NULL
306318
#define alloc_bootmem_huge_page(h) NULL
307319
#define hstate_file(f) NULL
308320
#define hstate_vma(v) NULL
@@ -317,6 +329,7 @@ static inline unsigned int pages_per_huge_page(struct hstate *h)
317329
{
318330
return 1;
319331
}
332+
#define hstate_index_to_shift(index) 0
320333
#endif
321334

322335
#endif /* _LINUX_HUGETLB_H */

include/linux/migrate.h

+16
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ extern int migrate_page(struct address_space *,
1414
struct page *, struct page *);
1515
extern int migrate_pages(struct list_head *l, new_page_t x,
1616
unsigned long private, int offlining);
17+
extern int migrate_huge_pages(struct list_head *l, new_page_t x,
18+
unsigned long private, int offlining);
1719

1820
extern int fail_migrate_page(struct address_space *,
1921
struct page *, struct page *);
@@ -23,12 +25,17 @@ extern int migrate_prep_local(void);
2325
extern int migrate_vmas(struct mm_struct *mm,
2426
const nodemask_t *from, const nodemask_t *to,
2527
unsigned long flags);
28+
extern void migrate_page_copy(struct page *newpage, struct page *page);
29+
extern int migrate_huge_page_move_mapping(struct address_space *mapping,
30+
struct page *newpage, struct page *page);
2631
#else
2732
#define PAGE_MIGRATION 0
2833

2934
static inline void putback_lru_pages(struct list_head *l) {}
3035
static inline int migrate_pages(struct list_head *l, new_page_t x,
3136
unsigned long private, int offlining) { return -ENOSYS; }
37+
static inline int migrate_huge_pages(struct list_head *l, new_page_t x,
38+
unsigned long private, int offlining) { return -ENOSYS; }
3239

3340
static inline int migrate_prep(void) { return -ENOSYS; }
3441
static inline int migrate_prep_local(void) { return -ENOSYS; }
@@ -40,6 +47,15 @@ static inline int migrate_vmas(struct mm_struct *mm,
4047
return -ENOSYS;
4148
}
4249

50+
static inline void migrate_page_copy(struct page *newpage,
51+
struct page *page) {}
52+
53+
static inline int migrate_huge_page_move_mapping(struct address_space *mapping,
54+
struct page *newpage, struct page *page)
55+
{
56+
return -ENOSYS;
57+
}
58+
4359
/* Possible settings for the migrate_page() method in address_operations */
4460
#define migrate_page NULL
4561
#define fail_migrate_page NULL

include/linux/mm.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -718,12 +718,20 @@ static inline int page_mapped(struct page *page)
718718
#define VM_FAULT_SIGBUS 0x0002
719719
#define VM_FAULT_MAJOR 0x0004
720720
#define VM_FAULT_WRITE 0x0008 /* Special case for get_user_pages */
721-
#define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned page */
721+
#define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned small page */
722+
#define VM_FAULT_HWPOISON_LARGE 0x0020 /* Hit poisoned large page. Index encoded in upper bits */
722723

723724
#define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */
724725
#define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */
725726

726-
#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON)
727+
#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
728+
729+
#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
730+
VM_FAULT_HWPOISON_LARGE)
731+
732+
/* Encode hstate index for a hwpoisoned large page */
733+
#define VM_FAULT_SET_HINDEX(x) ((x) << 12)
734+
#define VM_FAULT_GET_HINDEX(x) (((x) >> 12) & 0xf)
727735

728736
/*
729737
* Can be called by the pagefault handler when it gets a VM_FAULT_OOM.

include/linux/signalfd.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct signalfd_siginfo {
3333
__u64 ssi_utime;
3434
__u64 ssi_stime;
3535
__u64 ssi_addr;
36+
__u16 ssi_addr_lsb;
3637

3738
/*
3839
* Pad strcture to 128 bytes. Remember to update the
@@ -43,7 +44,7 @@ struct signalfd_siginfo {
4344
* comes out of a read(2) and we really don't want to have
4445
* a compat on read(2).
4546
*/
46-
__u8 __pad[48];
47+
__u8 __pad[46];
4748
};
4849

4950

0 commit comments

Comments
 (0)