Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 207264
b: refs/heads/master
c: a63d83f
h: refs/heads/master
v: v3
  • Loading branch information
David Rientjes authored and Linus Torvalds committed Aug 10, 2010
1 parent c27daef commit c48ee1c
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 192 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 74bcbf40546bb7500f2a7ba4ff3cc056a6bd004a
refs/heads/master: a63d83f427fbce97a6cea0db2e64b0eb8435cd10
94 changes: 57 additions & 37 deletions trunk/Documentation/filesystems/proc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ Table of Contents
2 Modifying System Parameters

3 Per-Process Parameters
3.1 /proc/<pid>/oom_adj - Adjust the oom-killer score
3.1 /proc/<pid>/oom_adj & /proc/<pid>/oom_score_adj - Adjust the oom-killer
score
3.2 /proc/<pid>/oom_score - Display current oom-killer score
3.3 /proc/<pid>/io - Display the IO accounting fields
3.4 /proc/<pid>/coredump_filter - Core dump filtering settings
Expand Down Expand Up @@ -1234,42 +1235,61 @@ of the kernel.
CHAPTER 3: PER-PROCESS PARAMETERS
------------------------------------------------------------------------------

3.1 /proc/<pid>/oom_adj - Adjust the oom-killer score
------------------------------------------------------

This file can be used to adjust the score used to select which processes
should be killed in an out-of-memory situation. Giving it a high score will
increase the likelihood of this process being killed by the oom-killer. Valid
values are in the range -16 to +15, plus the special value -17, which disables
oom-killing altogether for this process.

The process to be killed in an out-of-memory situation is selected among all others
based on its badness score. This value equals the original memory size of the process
and is then updated according to its CPU time (utime + stime) and the
run time (uptime - start time). The longer it runs the smaller is the score.
Badness score is divided by the square root of the CPU time and then by
the double square root of the run time.

Swapped out tasks are killed first. Half of each child's memory size is added to
the parent's score if they do not share the same memory. Thus forking servers
are the prime candidates to be killed. Having only one 'hungry' child will make
parent less preferable than the child.

/proc/<pid>/oom_score shows process' current badness score.

The following heuristics are then applied:
* if the task was reniced, its score doubles
* superuser or direct hardware access tasks (CAP_SYS_ADMIN, CAP_SYS_RESOURCE
or CAP_SYS_RAWIO) have their score divided by 4
* if oom condition happened in one cpuset and checked process does not belong
to it, its score is divided by 8
* the resulting score is multiplied by two to the power of oom_adj, i.e.
points <<= oom_adj when it is positive and
points >>= -(oom_adj) otherwise

The task with the highest badness score is then selected and its children
are killed, process itself will be killed in an OOM situation when it does
not have children or some of them disabled oom like described above.
3.1 /proc/<pid>/oom_adj & /proc/<pid>/oom_score_adj- Adjust the oom-killer score
--------------------------------------------------------------------------------

These file can be used to adjust the badness heuristic used to select which
process gets killed in out of memory conditions.

The badness heuristic assigns a value to each candidate task ranging from 0
(never kill) to 1000 (always kill) to determine which process is targeted. The
units are roughly a proportion along that range of allowed memory the process
may allocate from based on an estimation of its current memory and swap use.
For example, if a task is using all allowed memory, its badness score will be
1000. If it is using half of its allowed memory, its score will be 500.

There is an additional factor included in the badness score: root
processes are given 3% extra memory over other tasks.

The amount of "allowed" memory depends on the context in which the oom killer
was called. If it is due to the memory assigned to the allocating task's cpuset
being exhausted, the allowed memory represents the set of mems assigned to that
cpuset. If it is due to a mempolicy's node(s) being exhausted, the allowed
memory represents the set of mempolicy nodes. If it is due to a memory
limit (or swap limit) being reached, the allowed memory is that configured
limit. Finally, if it is due to the entire system being out of memory, the
allowed memory represents all allocatable resources.

The value of /proc/<pid>/oom_score_adj is added to the badness score before it
is used to determine which task to kill. Acceptable values range from -1000
(OOM_SCORE_ADJ_MIN) to +1000 (OOM_SCORE_ADJ_MAX). This allows userspace to
polarize the preference for oom killing either by always preferring a certain
task or completely disabling it. The lowest possible value, -1000, is
equivalent to disabling oom killing entirely for that task since it will always
report a badness score of 0.

Consequently, it is very simple for userspace to define the amount of memory to
consider for each task. Setting a /proc/<pid>/oom_score_adj value of +500, for
example, is roughly equivalent to allowing the remainder of tasks sharing the
same system, cpuset, mempolicy, or memory controller resources to use at least
50% more memory. A value of -500, on the other hand, would be roughly
equivalent to discounting 50% of the task's allowed memory from being considered
as scoring against the task.

For backwards compatibility with previous kernels, /proc/<pid>/oom_adj may also
be used to tune the badness score. Its acceptable values range from -16
(OOM_ADJUST_MIN) to +15 (OOM_ADJUST_MAX) and a special value of -17
(OOM_DISABLE) to disable oom killing entirely for that task. Its value is
scaled linearly with /proc/<pid>/oom_score_adj.

Writing to /proc/<pid>/oom_score_adj or /proc/<pid>/oom_adj will change the
other with its scaled value.

Caveat: when a parent task is selected, the oom killer will sacrifice any first
generation children with seperate address spaces instead, if possible. This
avoids servers and important system daemons from being killed and loses the
minimal amount of work.


3.2 /proc/<pid>/oom_score - Display current oom-killer score
-------------------------------------------------------------
Expand Down
94 changes: 90 additions & 4 deletions trunk/fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include <linux/namei.h>
#include <linux/mnt_namespace.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/rcupdate.h>
#include <linux/kallsyms.h>
#include <linux/stacktrace.h>
Expand Down Expand Up @@ -430,12 +431,11 @@ static const struct file_operations proc_lstats_operations = {
static int proc_oom_score(struct task_struct *task, char *buffer)
{
unsigned long points = 0;
struct timespec uptime;

do_posix_clock_monotonic_gettime(&uptime);
read_lock(&tasklist_lock);
if (pid_alive(task))
points = badness(task, NULL, NULL, uptime.tv_sec);
points = oom_badness(task, NULL, NULL,
totalram_pages + total_swap_pages);
read_unlock(&tasklist_lock);
return sprintf(buffer, "%lu\n", points);
}
Expand Down Expand Up @@ -1038,7 +1038,15 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
}

task->signal->oom_adj = oom_adjust;

/*
* Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
* value is always attainable.
*/
if (task->signal->oom_adj == OOM_ADJUST_MAX)
task->signal->oom_score_adj = OOM_SCORE_ADJ_MAX;
else
task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
-OOM_DISABLE;
unlock_task_sighand(task, &flags);
put_task_struct(task);

Expand All @@ -1051,6 +1059,82 @@ static const struct file_operations proc_oom_adjust_operations = {
.llseek = generic_file_llseek,
};

static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char buffer[PROC_NUMBUF];
int oom_score_adj = OOM_SCORE_ADJ_MIN;
unsigned long flags;
size_t len;

if (!task)
return -ESRCH;
if (lock_task_sighand(task, &flags)) {
oom_score_adj = task->signal->oom_score_adj;
unlock_task_sighand(task, &flags);
}
put_task_struct(task);
len = snprintf(buffer, sizeof(buffer), "%d\n", oom_score_adj);
return simple_read_from_buffer(buf, count, ppos, buffer, len);
}

static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct task_struct *task;
char buffer[PROC_NUMBUF];
unsigned long flags;
long oom_score_adj;
int err;

memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
if (copy_from_user(buffer, buf, count))
return -EFAULT;

err = strict_strtol(strstrip(buffer), 0, &oom_score_adj);
if (err)
return -EINVAL;
if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
oom_score_adj > OOM_SCORE_ADJ_MAX)
return -EINVAL;

task = get_proc_task(file->f_path.dentry->d_inode);
if (!task)
return -ESRCH;
if (!lock_task_sighand(task, &flags)) {
put_task_struct(task);
return -ESRCH;
}
if (oom_score_adj < task->signal->oom_score_adj &&
!capable(CAP_SYS_RESOURCE)) {
unlock_task_sighand(task, &flags);
put_task_struct(task);
return -EACCES;
}

task->signal->oom_score_adj = oom_score_adj;
/*
* Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
* always attainable.
*/
if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
task->signal->oom_adj = OOM_DISABLE;
else
task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) /
OOM_SCORE_ADJ_MAX;
unlock_task_sighand(task, &flags);
put_task_struct(task);
return count;
}

static const struct file_operations proc_oom_score_adj_operations = {
.read = oom_score_adj_read,
.write = oom_score_adj_write,
};

#ifdef CONFIG_AUDITSYSCALL
#define TMPBUFLEN 21
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
Expand Down Expand Up @@ -2623,6 +2707,7 @@ static const struct pid_entry tgid_base_stuff[] = {
#endif
INF("oom_score", S_IRUGO, proc_oom_score),
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUGO, proc_sessionid_operations),
Expand Down Expand Up @@ -2957,6 +3042,7 @@ static const struct pid_entry tid_base_stuff[] = {
#endif
INF("oom_score", S_IRUGO, proc_oom_score),
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUSR, proc_sessionid_operations),
Expand Down
8 changes: 8 additions & 0 deletions trunk/include/linux/memcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ void mem_cgroup_update_file_mapped(struct page *page, int val);
unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
gfp_t gfp_mask, int nid,
int zid);
u64 mem_cgroup_get_limit(struct mem_cgroup *mem);

#else /* CONFIG_CGROUP_MEM_RES_CTLR */
struct mem_cgroup;

Expand Down Expand Up @@ -304,6 +306,12 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
return 0;
}

static inline
u64 mem_cgroup_get_limit(struct mem_cgroup *mem)
{
return 0;
}

#endif /* CONFIG_CGROUP_MEM_CONT */

#endif /* _LINUX_MEMCONTROL_H */
Expand Down
14 changes: 13 additions & 1 deletion trunk/include/linux/oom.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
#ifndef __INCLUDE_LINUX_OOM_H
#define __INCLUDE_LINUX_OOM_H

/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
/*
* /proc/<pid>/oom_adj set to -17 protects from the oom-killer
*/
#define OOM_DISABLE (-17)
/* inclusive */
#define OOM_ADJUST_MIN (-16)
#define OOM_ADJUST_MAX 15

/*
* /proc/<pid>/oom_score_adj set to OOM_SCORE_ADJ_MIN disables oom killing for
* pid.
*/
#define OOM_SCORE_ADJ_MIN (-1000)
#define OOM_SCORE_ADJ_MAX 1000

#ifdef __KERNEL__

#include <linux/sched.h>
#include <linux/types.h>
#include <linux/nodemask.h>

Expand All @@ -27,6 +37,8 @@ enum oom_constraint {
CONSTRAINT_MEMCG,
};

extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
const nodemask_t *nodemask, unsigned long totalpages);
extern int try_set_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);

Expand Down
3 changes: 2 additions & 1 deletion trunk/include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,8 @@ struct signal_struct {
struct tty_audit_buf *tty_audit_buf;
#endif

int oom_adj; /* OOM kill score adjustment (bit shift) */
int oom_adj; /* OOM kill score adjustment (bit shift) */
int oom_score_adj; /* OOM kill score adjustment */
};

/* Context switch must be unlocked if interrupts are to be enabled */
Expand Down
1 change: 1 addition & 0 deletions trunk/kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
tty_audit_fork(sig);

sig->oom_adj = current->signal->oom_adj;
sig->oom_score_adj = current->signal->oom_score_adj;

return 0;
}
Expand Down
18 changes: 18 additions & 0 deletions trunk/mm/memcontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,24 @@ static int mem_cgroup_count_children(struct mem_cgroup *mem)
return num;
}

/*
* Return the memory (and swap, if configured) limit for a memcg.
*/
u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
{
u64 limit;
u64 memsw;

limit = res_counter_read_u64(&memcg->res, RES_LIMIT) +
total_swap_pages;
memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
/*
* If memsw is finite and limits the amount of swap space available
* to this memcg, return that limit.
*/
return min(limit, memsw);
}

/*
* Visit the first child (need not be the first child as per the ordering
* of the cgroup list, since we track last_scanned_child) of @mem and use
Expand Down
Loading

0 comments on commit c48ee1c

Please sign in to comment.