diff options
38 files changed, 304 insertions, 74 deletions
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild index 33a2c94fed0d..63b4a1705182 100644 --- a/arch/c6x/include/asm/Kbuild +++ b/arch/c6x/include/asm/Kbuild | |||
| @@ -30,6 +30,7 @@ generic-y += pgalloc.h | |||
| 30 | generic-y += preempt.h | 30 | generic-y += preempt.h |
| 31 | generic-y += segment.h | 31 | generic-y += segment.h |
| 32 | generic-y += serial.h | 32 | generic-y += serial.h |
| 33 | generic-y += shmparam.h | ||
| 33 | generic-y += tlbflush.h | 34 | generic-y += tlbflush.h |
| 34 | generic-y += topology.h | 35 | generic-y += topology.h |
| 35 | generic-y += trace_clock.h | 36 | generic-y += trace_clock.h |
diff --git a/arch/c6x/include/uapi/asm/Kbuild b/arch/c6x/include/uapi/asm/Kbuild index 6c6f6301012e..0febf1a07c30 100644 --- a/arch/c6x/include/uapi/asm/Kbuild +++ b/arch/c6x/include/uapi/asm/Kbuild | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | include include/uapi/asm-generic/Kbuild.asm | 1 | include include/uapi/asm-generic/Kbuild.asm |
| 2 | 2 | ||
| 3 | generic-y += kvm_para.h | 3 | generic-y += kvm_para.h |
| 4 | generic-y += shmparam.h | ||
| 5 | generic-y += ucontext.h | 4 | generic-y += ucontext.h |
diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild index cd400d353d18..961c1dc064e1 100644 --- a/arch/h8300/include/asm/Kbuild +++ b/arch/h8300/include/asm/Kbuild | |||
| @@ -40,6 +40,7 @@ generic-y += preempt.h | |||
| 40 | generic-y += scatterlist.h | 40 | generic-y += scatterlist.h |
| 41 | generic-y += sections.h | 41 | generic-y += sections.h |
| 42 | generic-y += serial.h | 42 | generic-y += serial.h |
| 43 | generic-y += shmparam.h | ||
| 43 | generic-y += sizes.h | 44 | generic-y += sizes.h |
| 44 | generic-y += spinlock.h | 45 | generic-y += spinlock.h |
| 45 | generic-y += timex.h | 46 | generic-y += timex.h |
diff --git a/arch/h8300/include/uapi/asm/Kbuild b/arch/h8300/include/uapi/asm/Kbuild index 6c6f6301012e..0febf1a07c30 100644 --- a/arch/h8300/include/uapi/asm/Kbuild +++ b/arch/h8300/include/uapi/asm/Kbuild | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | include include/uapi/asm-generic/Kbuild.asm | 1 | include include/uapi/asm-generic/Kbuild.asm |
| 2 | 2 | ||
| 3 | generic-y += kvm_para.h | 3 | generic-y += kvm_para.h |
| 4 | generic-y += shmparam.h | ||
| 5 | generic-y += ucontext.h | 4 | generic-y += ucontext.h |
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild index 47c4da3d64a4..b25fd42aa0f4 100644 --- a/arch/hexagon/include/asm/Kbuild +++ b/arch/hexagon/include/asm/Kbuild | |||
| @@ -30,6 +30,7 @@ generic-y += rwsem.h | |||
| 30 | generic-y += sections.h | 30 | generic-y += sections.h |
| 31 | generic-y += segment.h | 31 | generic-y += segment.h |
| 32 | generic-y += serial.h | 32 | generic-y += serial.h |
| 33 | generic-y += shmparam.h | ||
| 33 | generic-y += sizes.h | 34 | generic-y += sizes.h |
| 34 | generic-y += topology.h | 35 | generic-y += topology.h |
| 35 | generic-y += trace_clock.h | 36 | generic-y += trace_clock.h |
diff --git a/arch/hexagon/include/uapi/asm/Kbuild b/arch/hexagon/include/uapi/asm/Kbuild index 61d955c1747a..c1b06dcf6cf8 100644 --- a/arch/hexagon/include/uapi/asm/Kbuild +++ b/arch/hexagon/include/uapi/asm/Kbuild | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | include include/uapi/asm-generic/Kbuild.asm | 1 | include include/uapi/asm-generic/Kbuild.asm |
| 2 | 2 | ||
| 3 | generic-y += shmparam.h | ||
| 4 | generic-y += ucontext.h | 3 | generic-y += ucontext.h |
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index 9f1dd26903e3..95f8f631c4df 100644 --- a/arch/m68k/include/asm/Kbuild +++ b/arch/m68k/include/asm/Kbuild | |||
| @@ -20,6 +20,7 @@ generic-y += mm-arch-hooks.h | |||
| 20 | generic-y += percpu.h | 20 | generic-y += percpu.h |
| 21 | generic-y += preempt.h | 21 | generic-y += preempt.h |
| 22 | generic-y += sections.h | 22 | generic-y += sections.h |
| 23 | generic-y += shmparam.h | ||
| 23 | generic-y += spinlock.h | 24 | generic-y += spinlock.h |
| 24 | generic-y += topology.h | 25 | generic-y += topology.h |
| 25 | generic-y += trace_clock.h | 26 | generic-y += trace_clock.h |
diff --git a/arch/m68k/include/uapi/asm/Kbuild b/arch/m68k/include/uapi/asm/Kbuild index b8b3525271fa..960bf1e4be53 100644 --- a/arch/m68k/include/uapi/asm/Kbuild +++ b/arch/m68k/include/uapi/asm/Kbuild | |||
| @@ -2,4 +2,3 @@ include include/uapi/asm-generic/Kbuild.asm | |||
| 2 | 2 | ||
| 3 | generated-y += unistd_32.h | 3 | generated-y += unistd_32.h |
| 4 | generic-y += kvm_para.h | 4 | generic-y += kvm_para.h |
| 5 | generic-y += shmparam.h | ||
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild index 9c7d1d25bf3d..791cc8d54d0a 100644 --- a/arch/microblaze/include/asm/Kbuild +++ b/arch/microblaze/include/asm/Kbuild | |||
| @@ -26,6 +26,7 @@ generic-y += parport.h | |||
| 26 | generic-y += percpu.h | 26 | generic-y += percpu.h |
| 27 | generic-y += preempt.h | 27 | generic-y += preempt.h |
| 28 | generic-y += serial.h | 28 | generic-y += serial.h |
| 29 | generic-y += shmparam.h | ||
| 29 | generic-y += syscalls.h | 30 | generic-y += syscalls.h |
| 30 | generic-y += topology.h | 31 | generic-y += topology.h |
| 31 | generic-y += trace_clock.h | 32 | generic-y += trace_clock.h |
diff --git a/arch/microblaze/include/uapi/asm/Kbuild b/arch/microblaze/include/uapi/asm/Kbuild index 28823e3db825..97823ec46e97 100644 --- a/arch/microblaze/include/uapi/asm/Kbuild +++ b/arch/microblaze/include/uapi/asm/Kbuild | |||
| @@ -2,5 +2,4 @@ include include/uapi/asm-generic/Kbuild.asm | |||
| 2 | 2 | ||
| 3 | generated-y += unistd_32.h | 3 | generated-y += unistd_32.h |
| 4 | generic-y += kvm_para.h | 4 | generic-y += kvm_para.h |
| 5 | generic-y += shmparam.h | ||
| 6 | generic-y += ucontext.h | 5 | generic-y += ucontext.h |
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild index eb87cd8327c8..1f04844b6b82 100644 --- a/arch/openrisc/include/asm/Kbuild +++ b/arch/openrisc/include/asm/Kbuild | |||
| @@ -34,6 +34,7 @@ generic-y += qrwlock_types.h | |||
| 34 | generic-y += qrwlock.h | 34 | generic-y += qrwlock.h |
| 35 | generic-y += sections.h | 35 | generic-y += sections.h |
| 36 | generic-y += segment.h | 36 | generic-y += segment.h |
| 37 | generic-y += shmparam.h | ||
| 37 | generic-y += string.h | 38 | generic-y += string.h |
| 38 | generic-y += switch_to.h | 39 | generic-y += switch_to.h |
| 39 | generic-y += topology.h | 40 | generic-y += topology.h |
diff --git a/arch/openrisc/include/uapi/asm/Kbuild b/arch/openrisc/include/uapi/asm/Kbuild index 6c6f6301012e..0febf1a07c30 100644 --- a/arch/openrisc/include/uapi/asm/Kbuild +++ b/arch/openrisc/include/uapi/asm/Kbuild | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | include include/uapi/asm-generic/Kbuild.asm | 1 | include include/uapi/asm-generic/Kbuild.asm |
| 2 | 2 | ||
| 3 | generic-y += kvm_para.h | 3 | generic-y += kvm_para.h |
| 4 | generic-y += shmparam.h | ||
| 5 | generic-y += ucontext.h | 4 | generic-y += ucontext.h |
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild index 1372553dc0a9..1d1544b6ca74 100644 --- a/arch/unicore32/include/asm/Kbuild +++ b/arch/unicore32/include/asm/Kbuild | |||
| @@ -28,6 +28,7 @@ generic-y += preempt.h | |||
| 28 | generic-y += sections.h | 28 | generic-y += sections.h |
| 29 | generic-y += segment.h | 29 | generic-y += segment.h |
| 30 | generic-y += serial.h | 30 | generic-y += serial.h |
| 31 | generic-y += shmparam.h | ||
| 31 | generic-y += sizes.h | 32 | generic-y += sizes.h |
| 32 | generic-y += syscalls.h | 33 | generic-y += syscalls.h |
| 33 | generic-y += topology.h | 34 | generic-y += topology.h |
diff --git a/arch/unicore32/include/uapi/asm/Kbuild b/arch/unicore32/include/uapi/asm/Kbuild index 6c6f6301012e..0febf1a07c30 100644 --- a/arch/unicore32/include/uapi/asm/Kbuild +++ b/arch/unicore32/include/uapi/asm/Kbuild | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | include include/uapi/asm-generic/Kbuild.asm | 1 | include include/uapi/asm-generic/Kbuild.asm |
| 2 | 2 | ||
| 3 | generic-y += kvm_para.h | 3 | generic-y += kvm_para.h |
| 4 | generic-y += shmparam.h | ||
| 5 | generic-y += ucontext.h | 4 | generic-y += ucontext.h |
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index 8f657286d599..0ce558a8150d 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h | |||
| @@ -7,7 +7,11 @@ | |||
| 7 | #endif | 7 | #endif |
| 8 | 8 | ||
| 9 | #ifdef CONFIG_KASAN | 9 | #ifdef CONFIG_KASAN |
| 10 | #ifdef CONFIG_KASAN_EXTRA | ||
| 11 | #define KASAN_STACK_ORDER 2 | ||
| 12 | #else | ||
| 10 | #define KASAN_STACK_ORDER 1 | 13 | #define KASAN_STACK_ORDER 1 |
| 14 | #endif | ||
| 11 | #else | 15 | #else |
| 12 | #define KASAN_STACK_ORDER 0 | 16 | #define KASAN_STACK_ORDER 0 |
| 13 | #endif | 17 | #endif |
diff --git a/fs/autofs/expire.c b/fs/autofs/expire.c index d441244b79df..28d9c2b1b3bb 100644 --- a/fs/autofs/expire.c +++ b/fs/autofs/expire.c | |||
| @@ -596,7 +596,6 @@ int autofs_expire_run(struct super_block *sb, | |||
| 596 | pkt.len = dentry->d_name.len; | 596 | pkt.len = dentry->d_name.len; |
| 597 | memcpy(pkt.name, dentry->d_name.name, pkt.len); | 597 | memcpy(pkt.name, dentry->d_name.name, pkt.len); |
| 598 | pkt.name[pkt.len] = '\0'; | 598 | pkt.name[pkt.len] = '\0'; |
| 599 | dput(dentry); | ||
| 600 | 599 | ||
| 601 | if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire))) | 600 | if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire))) |
| 602 | ret = -EFAULT; | 601 | ret = -EFAULT; |
| @@ -609,6 +608,8 @@ int autofs_expire_run(struct super_block *sb, | |||
| 609 | complete_all(&ino->expire_complete); | 608 | complete_all(&ino->expire_complete); |
| 610 | spin_unlock(&sbi->fs_lock); | 609 | spin_unlock(&sbi->fs_lock); |
| 611 | 610 | ||
| 611 | dput(dentry); | ||
| 612 | |||
| 612 | return ret; | 613 | return ret; |
| 613 | } | 614 | } |
| 614 | 615 | ||
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index 0e8ea2d9a2bb..078992eee299 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c | |||
| @@ -266,8 +266,10 @@ int autofs_fill_super(struct super_block *s, void *data, int silent) | |||
| 266 | } | 266 | } |
| 267 | root_inode = autofs_get_inode(s, S_IFDIR | 0755); | 267 | root_inode = autofs_get_inode(s, S_IFDIR | 0755); |
| 268 | root = d_make_root(root_inode); | 268 | root = d_make_root(root_inode); |
| 269 | if (!root) | 269 | if (!root) { |
| 270 | ret = -ENOMEM; | ||
| 270 | goto fail_ino; | 271 | goto fail_ino; |
| 272 | } | ||
| 271 | pipe = NULL; | 273 | pipe = NULL; |
| 272 | 274 | ||
| 273 | root->d_fsdata = ino; | 275 | root->d_fsdata = ino; |
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 82377017130f..d31b6c72b476 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c | |||
| @@ -21,8 +21,13 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
| 21 | spin_lock(&sb->s_inode_list_lock); | 21 | spin_lock(&sb->s_inode_list_lock); |
| 22 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 22 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
| 23 | spin_lock(&inode->i_lock); | 23 | spin_lock(&inode->i_lock); |
| 24 | /* | ||
| 25 | * We must skip inodes in unusual state. We may also skip | ||
| 26 | * inodes without pages but we deliberately won't in case | ||
| 27 | * we need to reschedule to avoid softlockups. | ||
| 28 | */ | ||
| 24 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || | 29 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || |
| 25 | (inode->i_mapping->nrpages == 0)) { | 30 | (inode->i_mapping->nrpages == 0 && !need_resched())) { |
| 26 | spin_unlock(&inode->i_lock); | 31 | spin_unlock(&inode->i_lock); |
| 27 | continue; | 32 | continue; |
| 28 | } | 33 | } |
| @@ -30,6 +35,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
| 30 | spin_unlock(&inode->i_lock); | 35 | spin_unlock(&inode->i_lock); |
| 31 | spin_unlock(&sb->s_inode_list_lock); | 36 | spin_unlock(&sb->s_inode_list_lock); |
| 32 | 37 | ||
| 38 | cond_resched(); | ||
| 33 | invalidate_mapping_pages(inode->i_mapping, 0, -1); | 39 | invalidate_mapping_pages(inode->i_mapping, 0, -1); |
| 34 | iput(toput_inode); | 40 | iput(toput_inode); |
| 35 | toput_inode = inode; | 41 | toput_inode = inode; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 8ae109429a88..e39bac94dead 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -256,7 +256,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, | |||
| 256 | inode = proc_get_inode(dir->i_sb, de); | 256 | inode = proc_get_inode(dir->i_sb, de); |
| 257 | if (!inode) | 257 | if (!inode) |
| 258 | return ERR_PTR(-ENOMEM); | 258 | return ERR_PTR(-ENOMEM); |
| 259 | d_set_d_op(dentry, &proc_misc_dentry_ops); | 259 | d_set_d_op(dentry, de->proc_dops); |
| 260 | return d_splice_alias(inode, dentry); | 260 | return d_splice_alias(inode, dentry); |
| 261 | } | 261 | } |
| 262 | read_unlock(&proc_subdir_lock); | 262 | read_unlock(&proc_subdir_lock); |
| @@ -429,6 +429,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
| 429 | INIT_LIST_HEAD(&ent->pde_openers); | 429 | INIT_LIST_HEAD(&ent->pde_openers); |
| 430 | proc_set_user(ent, (*parent)->uid, (*parent)->gid); | 430 | proc_set_user(ent, (*parent)->uid, (*parent)->gid); |
| 431 | 431 | ||
| 432 | ent->proc_dops = &proc_misc_dentry_ops; | ||
| 433 | |||
| 432 | out: | 434 | out: |
| 433 | return ent; | 435 | return ent; |
| 434 | } | 436 | } |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 5185d7f6a51e..95b14196f284 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -44,6 +44,7 @@ struct proc_dir_entry { | |||
| 44 | struct completion *pde_unload_completion; | 44 | struct completion *pde_unload_completion; |
| 45 | const struct inode_operations *proc_iops; | 45 | const struct inode_operations *proc_iops; |
| 46 | const struct file_operations *proc_fops; | 46 | const struct file_operations *proc_fops; |
| 47 | const struct dentry_operations *proc_dops; | ||
| 47 | union { | 48 | union { |
| 48 | const struct seq_operations *seq_ops; | 49 | const struct seq_operations *seq_ops; |
| 49 | int (*single_show)(struct seq_file *, void *); | 50 | int (*single_show)(struct seq_file *, void *); |
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index d5e0fcb3439e..a7b12435519e 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c | |||
| @@ -38,6 +38,22 @@ static struct net *get_proc_net(const struct inode *inode) | |||
| 38 | return maybe_get_net(PDE_NET(PDE(inode))); | 38 | return maybe_get_net(PDE_NET(PDE(inode))); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) | ||
| 42 | { | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static const struct dentry_operations proc_net_dentry_ops = { | ||
| 47 | .d_revalidate = proc_net_d_revalidate, | ||
| 48 | .d_delete = always_delete_dentry, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static void pde_force_lookup(struct proc_dir_entry *pde) | ||
| 52 | { | ||
| 53 | /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ | ||
| 54 | pde->proc_dops = &proc_net_dentry_ops; | ||
| 55 | } | ||
| 56 | |||
| 41 | static int seq_open_net(struct inode *inode, struct file *file) | 57 | static int seq_open_net(struct inode *inode, struct file *file) |
| 42 | { | 58 | { |
| 43 | unsigned int state_size = PDE(inode)->state_size; | 59 | unsigned int state_size = PDE(inode)->state_size; |
| @@ -90,6 +106,7 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode, | |||
| 90 | p = proc_create_reg(name, mode, &parent, data); | 106 | p = proc_create_reg(name, mode, &parent, data); |
| 91 | if (!p) | 107 | if (!p) |
| 92 | return NULL; | 108 | return NULL; |
| 109 | pde_force_lookup(p); | ||
| 93 | p->proc_fops = &proc_net_seq_fops; | 110 | p->proc_fops = &proc_net_seq_fops; |
| 94 | p->seq_ops = ops; | 111 | p->seq_ops = ops; |
| 95 | p->state_size = state_size; | 112 | p->state_size = state_size; |
| @@ -133,6 +150,7 @@ struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode | |||
| 133 | p = proc_create_reg(name, mode, &parent, data); | 150 | p = proc_create_reg(name, mode, &parent, data); |
| 134 | if (!p) | 151 | if (!p) |
| 135 | return NULL; | 152 | return NULL; |
| 153 | pde_force_lookup(p); | ||
| 136 | p->proc_fops = &proc_net_seq_fops; | 154 | p->proc_fops = &proc_net_seq_fops; |
| 137 | p->seq_ops = ops; | 155 | p->seq_ops = ops; |
| 138 | p->state_size = state_size; | 156 | p->state_size = state_size; |
| @@ -181,6 +199,7 @@ struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode, | |||
| 181 | p = proc_create_reg(name, mode, &parent, data); | 199 | p = proc_create_reg(name, mode, &parent, data); |
| 182 | if (!p) | 200 | if (!p) |
| 183 | return NULL; | 201 | return NULL; |
| 202 | pde_force_lookup(p); | ||
| 184 | p->proc_fops = &proc_net_single_fops; | 203 | p->proc_fops = &proc_net_single_fops; |
| 185 | p->single_show = show; | 204 | p->single_show = show; |
| 186 | return proc_register(parent, p); | 205 | return proc_register(parent, p); |
| @@ -223,6 +242,7 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo | |||
| 223 | p = proc_create_reg(name, mode, &parent, data); | 242 | p = proc_create_reg(name, mode, &parent, data); |
| 224 | if (!p) | 243 | if (!p) |
| 225 | return NULL; | 244 | return NULL; |
| 245 | pde_force_lookup(p); | ||
| 226 | p->proc_fops = &proc_net_single_fops; | 246 | p->proc_fops = &proc_net_single_fops; |
| 227 | p->single_show = show; | 247 | p->single_show = show; |
| 228 | p->write = write; | 248 | p->write = write; |
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 07da5c6c5ba0..368267c1b71b 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h | |||
| @@ -21,14 +21,16 @@ struct vmem_altmap; | |||
| 21 | * walkers which rely on the fully initialized page->flags and others | 21 | * walkers which rely on the fully initialized page->flags and others |
| 22 | * should use this rather than pfn_valid && pfn_to_page | 22 | * should use this rather than pfn_valid && pfn_to_page |
| 23 | */ | 23 | */ |
| 24 | #define pfn_to_online_page(pfn) \ | 24 | #define pfn_to_online_page(pfn) \ |
| 25 | ({ \ | 25 | ({ \ |
| 26 | struct page *___page = NULL; \ | 26 | struct page *___page = NULL; \ |
| 27 | unsigned long ___nr = pfn_to_section_nr(pfn); \ | 27 | unsigned long ___pfn = pfn; \ |
| 28 | \ | 28 | unsigned long ___nr = pfn_to_section_nr(___pfn); \ |
| 29 | if (___nr < NR_MEM_SECTIONS && online_section_nr(___nr))\ | 29 | \ |
| 30 | ___page = pfn_to_page(pfn); \ | 30 | if (___nr < NR_MEM_SECTIONS && online_section_nr(___nr) && \ |
| 31 | ___page; \ | 31 | pfn_valid_within(___pfn)) \ |
| 32 | ___page = pfn_to_page(___pfn); \ | ||
| 33 | ___page; \ | ||
| 32 | }) | 34 | }) |
| 33 | 35 | ||
| 34 | /* | 36 | /* |
diff --git a/include/linux/sched/coredump.h b/include/linux/sched/coredump.h index ec912d01126f..ecdc6542070f 100644 --- a/include/linux/sched/coredump.h +++ b/include/linux/sched/coredump.h | |||
| @@ -71,6 +71,7 @@ static inline int get_dumpable(struct mm_struct *mm) | |||
| 71 | #define MMF_HUGE_ZERO_PAGE 23 /* mm has ever used the global huge zero page */ | 71 | #define MMF_HUGE_ZERO_PAGE 23 /* mm has ever used the global huge zero page */ |
| 72 | #define MMF_DISABLE_THP 24 /* disable THP for all VMAs */ | 72 | #define MMF_DISABLE_THP 24 /* disable THP for all VMAs */ |
| 73 | #define MMF_OOM_VICTIM 25 /* mm is the oom victim */ | 73 | #define MMF_OOM_VICTIM 25 /* mm is the oom victim */ |
| 74 | #define MMF_OOM_REAP_QUEUED 26 /* mm was queued for oom_reaper */ | ||
| 74 | #define MMF_DISABLE_THP_MASK (1 << MMF_DISABLE_THP) | 75 | #define MMF_DISABLE_THP_MASK (1 << MMF_DISABLE_THP) |
| 75 | 76 | ||
| 76 | #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK |\ | 77 | #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK |\ |
diff --git a/init/Kconfig b/init/Kconfig index 513fa544a134..c9386a365eea 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -512,6 +512,17 @@ config PSI_DEFAULT_DISABLED | |||
| 512 | per default but can be enabled through passing psi=1 on the | 512 | per default but can be enabled through passing psi=1 on the |
| 513 | kernel commandline during boot. | 513 | kernel commandline during boot. |
| 514 | 514 | ||
| 515 | This feature adds some code to the task wakeup and sleep | ||
| 516 | paths of the scheduler. The overhead is too low to affect | ||
| 517 | common scheduling-intense workloads in practice (such as | ||
| 518 | webservers, memcache), but it does show up in artificial | ||
| 519 | scheduler stress tests, such as hackbench. | ||
| 520 | |||
| 521 | If you are paranoid and not sure what the kernel will be | ||
| 522 | used for, say Y. | ||
| 523 | |||
| 524 | Say N if unsure. | ||
| 525 | |||
| 515 | endmenu # "CPU/Task time and stats accounting" | 526 | endmenu # "CPU/Task time and stats accounting" |
| 516 | 527 | ||
| 517 | config CPU_ISOLATION | 528 | config CPU_ISOLATION |
| @@ -825,7 +836,7 @@ config CGROUP_PIDS | |||
| 825 | PIDs controller is designed to stop this from happening. | 836 | PIDs controller is designed to stop this from happening. |
| 826 | 837 | ||
| 827 | It should be noted that organisational operations (such as attaching | 838 | It should be noted that organisational operations (such as attaching |
| 828 | to a cgroup hierarchy will *not* be blocked by the PIDs controller), | 839 | to a cgroup hierarchy) will *not* be blocked by the PIDs controller, |
| 829 | since the PIDs limit only affects a process's ability to fork, not to | 840 | since the PIDs limit only affects a process's ability to fork, not to |
| 830 | attach to a cgroup. | 841 | attach to a cgroup. |
| 831 | 842 | ||
diff --git a/kernel/exit.c b/kernel/exit.c index 3fb7be001964..2639a30a8aa5 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -558,12 +558,14 @@ static struct task_struct *find_alive_thread(struct task_struct *p) | |||
| 558 | return NULL; | 558 | return NULL; |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | static struct task_struct *find_child_reaper(struct task_struct *father) | 561 | static struct task_struct *find_child_reaper(struct task_struct *father, |
| 562 | struct list_head *dead) | ||
| 562 | __releases(&tasklist_lock) | 563 | __releases(&tasklist_lock) |
| 563 | __acquires(&tasklist_lock) | 564 | __acquires(&tasklist_lock) |
| 564 | { | 565 | { |
| 565 | struct pid_namespace *pid_ns = task_active_pid_ns(father); | 566 | struct pid_namespace *pid_ns = task_active_pid_ns(father); |
| 566 | struct task_struct *reaper = pid_ns->child_reaper; | 567 | struct task_struct *reaper = pid_ns->child_reaper; |
| 568 | struct task_struct *p, *n; | ||
| 567 | 569 | ||
| 568 | if (likely(reaper != father)) | 570 | if (likely(reaper != father)) |
| 569 | return reaper; | 571 | return reaper; |
| @@ -579,6 +581,12 @@ static struct task_struct *find_child_reaper(struct task_struct *father) | |||
| 579 | panic("Attempted to kill init! exitcode=0x%08x\n", | 581 | panic("Attempted to kill init! exitcode=0x%08x\n", |
| 580 | father->signal->group_exit_code ?: father->exit_code); | 582 | father->signal->group_exit_code ?: father->exit_code); |
| 581 | } | 583 | } |
| 584 | |||
| 585 | list_for_each_entry_safe(p, n, dead, ptrace_entry) { | ||
| 586 | list_del_init(&p->ptrace_entry); | ||
| 587 | release_task(p); | ||
| 588 | } | ||
| 589 | |||
| 582 | zap_pid_ns_processes(pid_ns); | 590 | zap_pid_ns_processes(pid_ns); |
| 583 | write_lock_irq(&tasklist_lock); | 591 | write_lock_irq(&tasklist_lock); |
| 584 | 592 | ||
| @@ -668,7 +676,7 @@ static void forget_original_parent(struct task_struct *father, | |||
| 668 | exit_ptrace(father, dead); | 676 | exit_ptrace(father, dead); |
| 669 | 677 | ||
| 670 | /* Can drop and reacquire tasklist_lock */ | 678 | /* Can drop and reacquire tasklist_lock */ |
| 671 | reaper = find_child_reaper(father); | 679 | reaper = find_child_reaper(father, dead); |
| 672 | if (list_empty(&father->children)) | 680 | if (list_empty(&father->children)) |
| 673 | return; | 681 | return; |
| 674 | 682 | ||
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index fe24de3fbc93..c3484785b179 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c | |||
| @@ -124,6 +124,7 @@ | |||
| 124 | * sampling of the aggregate task states would be. | 124 | * sampling of the aggregate task states would be. |
| 125 | */ | 125 | */ |
| 126 | 126 | ||
| 127 | #include "../workqueue_internal.h" | ||
| 127 | #include <linux/sched/loadavg.h> | 128 | #include <linux/sched/loadavg.h> |
| 128 | #include <linux/seq_file.h> | 129 | #include <linux/seq_file.h> |
| 129 | #include <linux/proc_fs.h> | 130 | #include <linux/proc_fs.h> |
| @@ -480,9 +481,6 @@ static void psi_group_change(struct psi_group *group, int cpu, | |||
| 480 | groupc->tasks[t]++; | 481 | groupc->tasks[t]++; |
| 481 | 482 | ||
| 482 | write_seqcount_end(&groupc->seq); | 483 | write_seqcount_end(&groupc->seq); |
| 483 | |||
| 484 | if (!delayed_work_pending(&group->clock_work)) | ||
| 485 | schedule_delayed_work(&group->clock_work, PSI_FREQ); | ||
| 486 | } | 484 | } |
| 487 | 485 | ||
| 488 | static struct psi_group *iterate_groups(struct task_struct *task, void **iter) | 486 | static struct psi_group *iterate_groups(struct task_struct *task, void **iter) |
| @@ -513,6 +511,7 @@ void psi_task_change(struct task_struct *task, int clear, int set) | |||
| 513 | { | 511 | { |
| 514 | int cpu = task_cpu(task); | 512 | int cpu = task_cpu(task); |
| 515 | struct psi_group *group; | 513 | struct psi_group *group; |
| 514 | bool wake_clock = true; | ||
| 516 | void *iter = NULL; | 515 | void *iter = NULL; |
| 517 | 516 | ||
| 518 | if (!task->pid) | 517 | if (!task->pid) |
| @@ -530,8 +529,22 @@ void psi_task_change(struct task_struct *task, int clear, int set) | |||
| 530 | task->psi_flags &= ~clear; | 529 | task->psi_flags &= ~clear; |
| 531 | task->psi_flags |= set; | 530 | task->psi_flags |= set; |
| 532 | 531 | ||
| 533 | while ((group = iterate_groups(task, &iter))) | 532 | /* |
| 533 | * Periodic aggregation shuts off if there is a period of no | ||
| 534 | * task changes, so we wake it back up if necessary. However, | ||
| 535 | * don't do this if the task change is the aggregation worker | ||
| 536 | * itself going to sleep, or we'll ping-pong forever. | ||
| 537 | */ | ||
| 538 | if (unlikely((clear & TSK_RUNNING) && | ||
| 539 | (task->flags & PF_WQ_WORKER) && | ||
| 540 | wq_worker_last_func(task) == psi_update_work)) | ||
| 541 | wake_clock = false; | ||
| 542 | |||
| 543 | while ((group = iterate_groups(task, &iter))) { | ||
| 534 | psi_group_change(group, cpu, clear, set); | 544 | psi_group_change(group, cpu, clear, set); |
| 545 | if (wake_clock && !delayed_work_pending(&group->clock_work)) | ||
| 546 | schedule_delayed_work(&group->clock_work, PSI_FREQ); | ||
| 547 | } | ||
| 535 | } | 548 | } |
| 536 | 549 | ||
| 537 | void psi_memstall_tick(struct task_struct *task, int cpu) | 550 | void psi_memstall_tick(struct task_struct *task, int cpu) |
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 392be4b252f6..fc5d23d752a5 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -910,6 +910,26 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task) | |||
| 910 | } | 910 | } |
| 911 | 911 | ||
| 912 | /** | 912 | /** |
| 913 | * wq_worker_last_func - retrieve worker's last work function | ||
| 914 | * | ||
| 915 | * Determine the last function a worker executed. This is called from | ||
| 916 | * the scheduler to get a worker's last known identity. | ||
| 917 | * | ||
| 918 | * CONTEXT: | ||
| 919 | * spin_lock_irq(rq->lock) | ||
| 920 | * | ||
| 921 | * Return: | ||
| 922 | * The last work function %current executed as a worker, NULL if it | ||
| 923 | * hasn't executed any work yet. | ||
| 924 | */ | ||
| 925 | work_func_t wq_worker_last_func(struct task_struct *task) | ||
| 926 | { | ||
| 927 | struct worker *worker = kthread_data(task); | ||
| 928 | |||
| 929 | return worker->last_func; | ||
| 930 | } | ||
| 931 | |||
| 932 | /** | ||
| 913 | * worker_set_flags - set worker flags and adjust nr_running accordingly | 933 | * worker_set_flags - set worker flags and adjust nr_running accordingly |
| 914 | * @worker: self | 934 | * @worker: self |
| 915 | * @flags: flags to set | 935 | * @flags: flags to set |
| @@ -2184,6 +2204,9 @@ __acquires(&pool->lock) | |||
| 2184 | if (unlikely(cpu_intensive)) | 2204 | if (unlikely(cpu_intensive)) |
| 2185 | worker_clr_flags(worker, WORKER_CPU_INTENSIVE); | 2205 | worker_clr_flags(worker, WORKER_CPU_INTENSIVE); |
| 2186 | 2206 | ||
| 2207 | /* tag the worker for identification in schedule() */ | ||
| 2208 | worker->last_func = worker->current_func; | ||
| 2209 | |||
| 2187 | /* we're done with it, release */ | 2210 | /* we're done with it, release */ |
| 2188 | hash_del(&worker->hentry); | 2211 | hash_del(&worker->hentry); |
| 2189 | worker->current_work = NULL; | 2212 | worker->current_work = NULL; |
diff --git a/kernel/workqueue_internal.h b/kernel/workqueue_internal.h index 66fbb5a9e633..cb68b03ca89a 100644 --- a/kernel/workqueue_internal.h +++ b/kernel/workqueue_internal.h | |||
| @@ -53,6 +53,9 @@ struct worker { | |||
| 53 | 53 | ||
| 54 | /* used only by rescuers to point to the target workqueue */ | 54 | /* used only by rescuers to point to the target workqueue */ |
| 55 | struct workqueue_struct *rescue_wq; /* I: the workqueue to rescue */ | 55 | struct workqueue_struct *rescue_wq; /* I: the workqueue to rescue */ |
| 56 | |||
| 57 | /* used by the scheduler to determine a worker's last known identity */ | ||
| 58 | work_func_t last_func; | ||
| 56 | }; | 59 | }; |
| 57 | 60 | ||
| 58 | /** | 61 | /** |
| @@ -67,9 +70,10 @@ static inline struct worker *current_wq_worker(void) | |||
| 67 | 70 | ||
| 68 | /* | 71 | /* |
| 69 | * Scheduler hooks for concurrency managed workqueue. Only to be used from | 72 | * Scheduler hooks for concurrency managed workqueue. Only to be used from |
| 70 | * sched/core.c and workqueue.c. | 73 | * sched/ and workqueue.c. |
| 71 | */ | 74 | */ |
| 72 | void wq_worker_waking_up(struct task_struct *task, int cpu); | 75 | void wq_worker_waking_up(struct task_struct *task, int cpu); |
| 73 | struct task_struct *wq_worker_sleeping(struct task_struct *task); | 76 | struct task_struct *wq_worker_sleeping(struct task_struct *task); |
| 77 | work_func_t wq_worker_last_func(struct task_struct *task); | ||
| 74 | 78 | ||
| 75 | #endif /* _KERNEL_WORKQUEUE_INTERNAL_H */ | 79 | #endif /* _KERNEL_WORKQUEUE_INTERNAL_H */ |
diff --git a/lib/test_kmod.c b/lib/test_kmod.c index d82d022111e0..9cf77628fc91 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c | |||
| @@ -632,7 +632,7 @@ static void __kmod_config_free(struct test_config *config) | |||
| 632 | config->test_driver = NULL; | 632 | config->test_driver = NULL; |
| 633 | 633 | ||
| 634 | kfree_const(config->test_fs); | 634 | kfree_const(config->test_fs); |
| 635 | config->test_driver = NULL; | 635 | config->test_fs = NULL; |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | static void kmod_config_free(struct kmod_test_device *test_dev) | 638 | static void kmod_config_free(struct kmod_test_device *test_dev) |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index df2e7dd5ff17..afef61656c1e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
| @@ -4268,7 +4268,8 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 4268 | break; | 4268 | break; |
| 4269 | } | 4269 | } |
| 4270 | if (ret & VM_FAULT_RETRY) { | 4270 | if (ret & VM_FAULT_RETRY) { |
| 4271 | if (nonblocking) | 4271 | if (nonblocking && |
| 4272 | !(fault_flags & FAULT_FLAG_RETRY_NOWAIT)) | ||
| 4272 | *nonblocking = 0; | 4273 | *nonblocking = 0; |
| 4273 | *nr_pages = 0; | 4274 | *nr_pages = 0; |
| 4274 | /* | 4275 | /* |
diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile index 0a14fcff70ed..e2bb06c1b45e 100644 --- a/mm/kasan/Makefile +++ b/mm/kasan/Makefile | |||
| @@ -5,6 +5,7 @@ UBSAN_SANITIZE_generic.o := n | |||
| 5 | UBSAN_SANITIZE_tags.o := n | 5 | UBSAN_SANITIZE_tags.o := n |
| 6 | KCOV_INSTRUMENT := n | 6 | KCOV_INSTRUMENT := n |
| 7 | 7 | ||
| 8 | CFLAGS_REMOVE_common.o = -pg | ||
| 8 | CFLAGS_REMOVE_generic.o = -pg | 9 | CFLAGS_REMOVE_generic.o = -pg |
| 9 | # Function splitter causes unnecessary splits in __asan_load1/__asan_store1 | 10 | # Function splitter causes unnecessary splits in __asan_load1/__asan_store1 |
| 10 | # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533 | 11 | # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533 |
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 7c72f2a95785..831be5ff5f4d 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
| @@ -372,7 +372,8 @@ static void kill_procs(struct list_head *to_kill, int forcekill, bool fail, | |||
| 372 | if (fail || tk->addr_valid == 0) { | 372 | if (fail || tk->addr_valid == 0) { |
| 373 | pr_err("Memory failure: %#lx: forcibly killing %s:%d because of failure to unmap corrupted page\n", | 373 | pr_err("Memory failure: %#lx: forcibly killing %s:%d because of failure to unmap corrupted page\n", |
| 374 | pfn, tk->tsk->comm, tk->tsk->pid); | 374 | pfn, tk->tsk->comm, tk->tsk->pid); |
| 375 | force_sig(SIGKILL, tk->tsk); | 375 | do_send_sig_info(SIGKILL, SEND_SIG_PRIV, |
| 376 | tk->tsk, PIDTYPE_PID); | ||
| 376 | } | 377 | } |
| 377 | 378 | ||
| 378 | /* | 379 | /* |
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index b9a667d36c55..124e794867c5 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
| @@ -1233,7 +1233,8 @@ static bool is_pageblock_removable_nolock(struct page *page) | |||
| 1233 | bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) | 1233 | bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) |
| 1234 | { | 1234 | { |
| 1235 | struct page *page = pfn_to_page(start_pfn); | 1235 | struct page *page = pfn_to_page(start_pfn); |
| 1236 | struct page *end_page = page + nr_pages; | 1236 | unsigned long end_pfn = min(start_pfn + nr_pages, zone_end_pfn(page_zone(page))); |
| 1237 | struct page *end_page = pfn_to_page(end_pfn); | ||
| 1237 | 1238 | ||
| 1238 | /* Check the starting page of each pageblock within the range */ | 1239 | /* Check the starting page of each pageblock within the range */ |
| 1239 | for (; page < end_page; page = next_active_pageblock(page)) { | 1240 | for (; page < end_page; page = next_active_pageblock(page)) { |
| @@ -1273,6 +1274,9 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn, | |||
| 1273 | i++; | 1274 | i++; |
| 1274 | if (i == MAX_ORDER_NR_PAGES || pfn + i >= end_pfn) | 1275 | if (i == MAX_ORDER_NR_PAGES || pfn + i >= end_pfn) |
| 1275 | continue; | 1276 | continue; |
| 1277 | /* Check if we got outside of the zone */ | ||
| 1278 | if (zone && !zone_spans_pfn(zone, pfn + i)) | ||
| 1279 | return 0; | ||
| 1276 | page = pfn_to_page(pfn + i); | 1280 | page = pfn_to_page(pfn + i); |
| 1277 | if (zone && page_zone(page) != zone) | 1281 | if (zone && page_zone(page) != zone) |
| 1278 | return 0; | 1282 | return 0; |
| @@ -1301,23 +1305,27 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn, | |||
| 1301 | static unsigned long scan_movable_pages(unsigned long start, unsigned long end) | 1305 | static unsigned long scan_movable_pages(unsigned long start, unsigned long end) |
| 1302 | { | 1306 | { |
| 1303 | unsigned long pfn; | 1307 | unsigned long pfn; |
| 1304 | struct page *page; | 1308 | |
| 1305 | for (pfn = start; pfn < end; pfn++) { | 1309 | for (pfn = start; pfn < end; pfn++) { |
| 1306 | if (pfn_valid(pfn)) { | 1310 | struct page *page, *head; |
| 1307 | page = pfn_to_page(pfn); | 1311 | unsigned long skip; |
| 1308 | if (PageLRU(page)) | 1312 | |
| 1309 | return pfn; | 1313 | if (!pfn_valid(pfn)) |
| 1310 | if (__PageMovable(page)) | 1314 | continue; |
| 1311 | return pfn; | 1315 | page = pfn_to_page(pfn); |
| 1312 | if (PageHuge(page)) { | 1316 | if (PageLRU(page)) |
| 1313 | if (hugepage_migration_supported(page_hstate(page)) && | 1317 | return pfn; |
| 1314 | page_huge_active(page)) | 1318 | if (__PageMovable(page)) |
| 1315 | return pfn; | 1319 | return pfn; |
| 1316 | else | 1320 | |
| 1317 | pfn = round_up(pfn + 1, | 1321 | if (!PageHuge(page)) |
| 1318 | 1 << compound_order(page)) - 1; | 1322 | continue; |
| 1319 | } | 1323 | head = compound_head(page); |
| 1320 | } | 1324 | if (hugepage_migration_supported(page_hstate(head)) && |
| 1325 | page_huge_active(head)) | ||
| 1326 | return pfn; | ||
| 1327 | skip = (1 << compound_order(head)) - (page - head); | ||
| 1328 | pfn += skip - 1; | ||
| 1321 | } | 1329 | } |
| 1322 | return 0; | 1330 | return 0; |
| 1323 | } | 1331 | } |
| @@ -1344,7 +1352,6 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
| 1344 | { | 1352 | { |
| 1345 | unsigned long pfn; | 1353 | unsigned long pfn; |
| 1346 | struct page *page; | 1354 | struct page *page; |
| 1347 | int not_managed = 0; | ||
| 1348 | int ret = 0; | 1355 | int ret = 0; |
| 1349 | LIST_HEAD(source); | 1356 | LIST_HEAD(source); |
| 1350 | 1357 | ||
| @@ -1392,7 +1399,6 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
| 1392 | else | 1399 | else |
| 1393 | ret = isolate_movable_page(page, ISOLATE_UNEVICTABLE); | 1400 | ret = isolate_movable_page(page, ISOLATE_UNEVICTABLE); |
| 1394 | if (!ret) { /* Success */ | 1401 | if (!ret) { /* Success */ |
| 1395 | put_page(page); | ||
| 1396 | list_add_tail(&page->lru, &source); | 1402 | list_add_tail(&page->lru, &source); |
| 1397 | if (!__PageMovable(page)) | 1403 | if (!__PageMovable(page)) |
| 1398 | inc_node_page_state(page, NR_ISOLATED_ANON + | 1404 | inc_node_page_state(page, NR_ISOLATED_ANON + |
| @@ -1401,22 +1407,10 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
| 1401 | } else { | 1407 | } else { |
| 1402 | pr_warn("failed to isolate pfn %lx\n", pfn); | 1408 | pr_warn("failed to isolate pfn %lx\n", pfn); |
| 1403 | dump_page(page, "isolation failed"); | 1409 | dump_page(page, "isolation failed"); |
| 1404 | put_page(page); | ||
| 1405 | /* Because we don't have big zone->lock. we should | ||
| 1406 | check this again here. */ | ||
| 1407 | if (page_count(page)) { | ||
| 1408 | not_managed++; | ||
| 1409 | ret = -EBUSY; | ||
| 1410 | break; | ||
| 1411 | } | ||
| 1412 | } | 1410 | } |
| 1411 | put_page(page); | ||
| 1413 | } | 1412 | } |
| 1414 | if (!list_empty(&source)) { | 1413 | if (!list_empty(&source)) { |
| 1415 | if (not_managed) { | ||
| 1416 | putback_movable_pages(&source); | ||
| 1417 | goto out; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | /* Allocate a new page from the nearest neighbor node */ | 1414 | /* Allocate a new page from the nearest neighbor node */ |
| 1421 | ret = migrate_pages(&source, new_node_page, NULL, 0, | 1415 | ret = migrate_pages(&source, new_node_page, NULL, 0, |
| 1422 | MIGRATE_SYNC, MR_MEMORY_HOTPLUG); | 1416 | MIGRATE_SYNC, MR_MEMORY_HOTPLUG); |
| @@ -1429,7 +1423,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
| 1429 | putback_movable_pages(&source); | 1423 | putback_movable_pages(&source); |
| 1430 | } | 1424 | } |
| 1431 | } | 1425 | } |
| 1432 | out: | 1426 | |
| 1433 | return ret; | 1427 | return ret; |
| 1434 | } | 1428 | } |
| 1435 | 1429 | ||
| @@ -1576,7 +1570,6 @@ static int __ref __offline_pages(unsigned long start_pfn, | |||
| 1576 | we assume this for now. .*/ | 1570 | we assume this for now. .*/ |
| 1577 | if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, | 1571 | if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, |
| 1578 | &valid_end)) { | 1572 | &valid_end)) { |
| 1579 | mem_hotplug_done(); | ||
| 1580 | ret = -EINVAL; | 1573 | ret = -EINVAL; |
| 1581 | reason = "multizone range"; | 1574 | reason = "multizone range"; |
| 1582 | goto failed_removal; | 1575 | goto failed_removal; |
| @@ -1591,7 +1584,6 @@ static int __ref __offline_pages(unsigned long start_pfn, | |||
| 1591 | MIGRATE_MOVABLE, | 1584 | MIGRATE_MOVABLE, |
| 1592 | SKIP_HWPOISON | REPORT_FAILURE); | 1585 | SKIP_HWPOISON | REPORT_FAILURE); |
| 1593 | if (ret) { | 1586 | if (ret) { |
| 1594 | mem_hotplug_done(); | ||
| 1595 | reason = "failure to isolate range"; | 1587 | reason = "failure to isolate range"; |
| 1596 | goto failed_removal; | 1588 | goto failed_removal; |
| 1597 | } | 1589 | } |
diff --git a/mm/migrate.c b/mm/migrate.c index a16b15090df3..d4fd680be3b0 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
| @@ -709,7 +709,6 @@ static bool buffer_migrate_lock_buffers(struct buffer_head *head, | |||
| 709 | /* Simple case, sync compaction */ | 709 | /* Simple case, sync compaction */ |
| 710 | if (mode != MIGRATE_ASYNC) { | 710 | if (mode != MIGRATE_ASYNC) { |
| 711 | do { | 711 | do { |
| 712 | get_bh(bh); | ||
| 713 | lock_buffer(bh); | 712 | lock_buffer(bh); |
| 714 | bh = bh->b_this_page; | 713 | bh = bh->b_this_page; |
| 715 | 714 | ||
| @@ -720,18 +719,15 @@ static bool buffer_migrate_lock_buffers(struct buffer_head *head, | |||
| 720 | 719 | ||
| 721 | /* async case, we cannot block on lock_buffer so use trylock_buffer */ | 720 | /* async case, we cannot block on lock_buffer so use trylock_buffer */ |
| 722 | do { | 721 | do { |
| 723 | get_bh(bh); | ||
| 724 | if (!trylock_buffer(bh)) { | 722 | if (!trylock_buffer(bh)) { |
| 725 | /* | 723 | /* |
| 726 | * We failed to lock the buffer and cannot stall in | 724 | * We failed to lock the buffer and cannot stall in |
| 727 | * async migration. Release the taken locks | 725 | * async migration. Release the taken locks |
| 728 | */ | 726 | */ |
| 729 | struct buffer_head *failed_bh = bh; | 727 | struct buffer_head *failed_bh = bh; |
| 730 | put_bh(failed_bh); | ||
| 731 | bh = head; | 728 | bh = head; |
| 732 | while (bh != failed_bh) { | 729 | while (bh != failed_bh) { |
| 733 | unlock_buffer(bh); | 730 | unlock_buffer(bh); |
| 734 | put_bh(bh); | ||
| 735 | bh = bh->b_this_page; | 731 | bh = bh->b_this_page; |
| 736 | } | 732 | } |
| 737 | return false; | 733 | return false; |
| @@ -818,7 +814,6 @@ unlock_buffers: | |||
| 818 | bh = head; | 814 | bh = head; |
| 819 | do { | 815 | do { |
| 820 | unlock_buffer(bh); | 816 | unlock_buffer(bh); |
| 821 | put_bh(bh); | ||
| 822 | bh = bh->b_this_page; | 817 | bh = bh->b_this_page; |
| 823 | 818 | ||
| 824 | } while (bh != head); | 819 | } while (bh != head); |
| @@ -1135,10 +1130,13 @@ out: | |||
| 1135 | * If migration is successful, decrease refcount of the newpage | 1130 | * If migration is successful, decrease refcount of the newpage |
| 1136 | * which will not free the page because new page owner increased | 1131 | * which will not free the page because new page owner increased |
| 1137 | * refcounter. As well, if it is LRU page, add the page to LRU | 1132 | * refcounter. As well, if it is LRU page, add the page to LRU |
| 1138 | * list in here. | 1133 | * list in here. Use the old state of the isolated source page to |
| 1134 | * determine if we migrated a LRU page. newpage was already unlocked | ||
| 1135 | * and possibly modified by its owner - don't rely on the page | ||
| 1136 | * state. | ||
| 1139 | */ | 1137 | */ |
| 1140 | if (rc == MIGRATEPAGE_SUCCESS) { | 1138 | if (rc == MIGRATEPAGE_SUCCESS) { |
| 1141 | if (unlikely(__PageMovable(newpage))) | 1139 | if (unlikely(!is_lru)) |
| 1142 | put_page(newpage); | 1140 | put_page(newpage); |
| 1143 | else | 1141 | else |
| 1144 | putback_lru_page(newpage); | 1142 | putback_lru_page(newpage); |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index f0e8cd9edb1a..26ea8636758f 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
| @@ -647,8 +647,8 @@ static int oom_reaper(void *unused) | |||
| 647 | 647 | ||
| 648 | static void wake_oom_reaper(struct task_struct *tsk) | 648 | static void wake_oom_reaper(struct task_struct *tsk) |
| 649 | { | 649 | { |
| 650 | /* tsk is already queued? */ | 650 | /* mm is already queued? */ |
| 651 | if (tsk == oom_reaper_list || tsk->oom_reaper_list) | 651 | if (test_and_set_bit(MMF_OOM_REAP_QUEUED, &tsk->signal->oom_mm->flags)) |
| 652 | return; | 652 | return; |
| 653 | 653 | ||
| 654 | get_task_struct(tsk); | 654 | get_task_struct(tsk); |
| @@ -975,6 +975,13 @@ static void oom_kill_process(struct oom_control *oc, const char *message) | |||
| 975 | * still freeing memory. | 975 | * still freeing memory. |
| 976 | */ | 976 | */ |
| 977 | read_lock(&tasklist_lock); | 977 | read_lock(&tasklist_lock); |
| 978 | |||
| 979 | /* | ||
| 980 | * The task 'p' might have already exited before reaching here. The | ||
| 981 | * put_task_struct() will free task_struct 'p' while the loop still try | ||
| 982 | * to access the field of 'p', so, get an extra reference. | ||
| 983 | */ | ||
| 984 | get_task_struct(p); | ||
| 978 | for_each_thread(p, t) { | 985 | for_each_thread(p, t) { |
| 979 | list_for_each_entry(child, &t->children, sibling) { | 986 | list_for_each_entry(child, &t->children, sibling) { |
| 980 | unsigned int child_points; | 987 | unsigned int child_points; |
| @@ -994,6 +1001,7 @@ static void oom_kill_process(struct oom_control *oc, const char *message) | |||
| 994 | } | 1001 | } |
| 995 | } | 1002 | } |
| 996 | } | 1003 | } |
| 1004 | put_task_struct(p); | ||
| 997 | read_unlock(&tasklist_lock); | 1005 | read_unlock(&tasklist_lock); |
| 998 | 1006 | ||
| 999 | /* | 1007 | /* |
diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index 82121a81681f..29bac5ef9a93 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore | |||
| @@ -10,4 +10,5 @@ | |||
| 10 | /proc-uptime-002 | 10 | /proc-uptime-002 |
| 11 | /read | 11 | /read |
| 12 | /self | 12 | /self |
| 13 | /setns-dcache | ||
| 13 | /thread-self | 14 | /thread-self |
diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index 1c12c34cf85d..434d033ee067 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile | |||
| @@ -14,6 +14,7 @@ TEST_GEN_PROGS += proc-uptime-001 | |||
| 14 | TEST_GEN_PROGS += proc-uptime-002 | 14 | TEST_GEN_PROGS += proc-uptime-002 |
| 15 | TEST_GEN_PROGS += read | 15 | TEST_GEN_PROGS += read |
| 16 | TEST_GEN_PROGS += self | 16 | TEST_GEN_PROGS += self |
| 17 | TEST_GEN_PROGS += setns-dcache | ||
| 17 | TEST_GEN_PROGS += thread-self | 18 | TEST_GEN_PROGS += thread-self |
| 18 | 19 | ||
| 19 | include ../lib.mk | 20 | include ../lib.mk |
diff --git a/tools/testing/selftests/proc/setns-dcache.c b/tools/testing/selftests/proc/setns-dcache.c new file mode 100644 index 000000000000..60ab197a73fc --- /dev/null +++ b/tools/testing/selftests/proc/setns-dcache.c | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2019 Alexey Dobriyan <adobriyan@gmail.com> | ||
| 3 | * | ||
| 4 | * Permission to use, copy, modify, and distribute this software for any | ||
| 5 | * purpose with or without fee is hereby granted, provided that the above | ||
| 6 | * copyright notice and this permission notice appear in all copies. | ||
| 7 | * | ||
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 15 | */ | ||
| 16 | /* | ||
| 17 | * Test that setns(CLONE_NEWNET) points to new /proc/net content even | ||
| 18 | * if old one is in dcache. | ||
| 19 | * | ||
| 20 | * FIXME /proc/net/unix is under CONFIG_UNIX which can be disabled. | ||
| 21 | */ | ||
| 22 | #undef NDEBUG | ||
| 23 | #include <assert.h> | ||
| 24 | #include <errno.h> | ||
| 25 | #include <sched.h> | ||
| 26 | #include <signal.h> | ||
| 27 | #include <stdio.h> | ||
| 28 | #include <stdlib.h> | ||
| 29 | #include <string.h> | ||
| 30 | #include <unistd.h> | ||
| 31 | #include <sys/types.h> | ||
| 32 | #include <sys/stat.h> | ||
| 33 | #include <fcntl.h> | ||
| 34 | #include <sys/socket.h> | ||
| 35 | |||
| 36 | static pid_t pid = -1; | ||
| 37 | |||
| 38 | static void f(void) | ||
| 39 | { | ||
| 40 | if (pid > 0) { | ||
| 41 | kill(pid, SIGTERM); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | int main(void) | ||
| 46 | { | ||
| 47 | int fd[2]; | ||
| 48 | char _ = 0; | ||
| 49 | int nsfd; | ||
| 50 | |||
| 51 | atexit(f); | ||
| 52 | |||
| 53 | /* Check for priviledges and syscall availability straight away. */ | ||
| 54 | if (unshare(CLONE_NEWNET) == -1) { | ||
| 55 | if (errno == ENOSYS || errno == EPERM) { | ||
| 56 | return 4; | ||
| 57 | } | ||
| 58 | return 1; | ||
| 59 | } | ||
| 60 | /* Distinguisher between two otherwise empty net namespaces. */ | ||
| 61 | if (socket(AF_UNIX, SOCK_STREAM, 0) == -1) { | ||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | if (pipe(fd) == -1) { | ||
| 66 | return 1; | ||
| 67 | } | ||
| 68 | |||
| 69 | pid = fork(); | ||
| 70 | if (pid == -1) { | ||
| 71 | return 1; | ||
| 72 | } | ||
| 73 | |||
| 74 | if (pid == 0) { | ||
| 75 | if (unshare(CLONE_NEWNET) == -1) { | ||
| 76 | return 1; | ||
| 77 | } | ||
| 78 | |||
| 79 | if (write(fd[1], &_, 1) != 1) { | ||
| 80 | return 1; | ||
| 81 | } | ||
| 82 | |||
| 83 | pause(); | ||
| 84 | |||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | if (read(fd[0], &_, 1) != 1) { | ||
| 89 | return 1; | ||
| 90 | } | ||
| 91 | |||
| 92 | { | ||
| 93 | char buf[64]; | ||
| 94 | snprintf(buf, sizeof(buf), "/proc/%u/ns/net", pid); | ||
| 95 | nsfd = open(buf, O_RDONLY); | ||
| 96 | if (nsfd == -1) { | ||
| 97 | return 1; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | /* Reliably pin dentry into dcache. */ | ||
| 102 | (void)open("/proc/net/unix", O_RDONLY); | ||
| 103 | |||
| 104 | if (setns(nsfd, CLONE_NEWNET) == -1) { | ||
| 105 | return 1; | ||
| 106 | } | ||
| 107 | |||
| 108 | kill(pid, SIGTERM); | ||
| 109 | pid = 0; | ||
| 110 | |||
| 111 | { | ||
| 112 | char buf[4096]; | ||
| 113 | ssize_t rv; | ||
| 114 | int fd; | ||
| 115 | |||
| 116 | fd = open("/proc/net/unix", O_RDONLY); | ||
| 117 | if (fd == -1) { | ||
| 118 | return 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | #define S "Num RefCount Protocol Flags Type St Inode Path\n" | ||
| 122 | rv = read(fd, buf, sizeof(buf)); | ||
| 123 | |||
| 124 | assert(rv == strlen(S)); | ||
| 125 | assert(memcmp(buf, S, strlen(S)) == 0); | ||
| 126 | } | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
