From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1FA5423EA97 for ; Wed, 14 Oct 2026 09:32:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791970343; cv=none; b=eE56JitRr6vXAQq/fpqrOl1nvLH3pQPxHZriP2JyRzqD3oFYemolPpZuKSDClZRp0NHEPumJcyfD+GXP3L+4EYmOvHQw76MTjZpUCRDLy4ZoNnxaXBHsnio00LIC4j9WTSVY3R5ml7is/oREmCF59oCMZ+Nrb8qvhAbbftTdH7Y= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791970343; c=relaxed/simple; bh=XpZYgAKF6Bfy79RxlkKPvcOO0II0yYMHazQzvE59K6M=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=skPa+okPawWN3K75xBwQAGmZ/BDk4XKmf1KKsZsDlF9PwUpnF9Cqm5HFTyBXajn4hTmectWWNnaaLlntHJQ/Ou8KOL71fiGCVSaLSn5UW0VlOM6h+zYOBf6YK9GULRSeml7N6p9NpOndcy7x9jKtt+QTdRtBD3q4W1EkMuei7Fk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com; spf=pass smtp.mailfrom=suse.com; dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com header.b=I4q+bTV0; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com header.b="I4q+bTV0" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-48b02b1b4cfso3742290f8f.0 for ; Wed, 14 Oct 2026 02:32:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=google; t=1791970333; x=1792575133; darn=vger.kernel.org; h=in-reply-to:content-disposition:content-type:mime-version :references:message-id:subject:cc:to:from:date:from:to:cc:subject :date:message-id:reply-to:content-type; bh=qbp1OaXo+QOhXfEK2yTqfOOSMPB/aU27i+I9ooebTqo=; b=I4q+bTV0w61+lNEBRyb2T7sPDBJg4/3FLkQbbbx+7LYtPkxNQRd7IDsWq1LWP41wFF 34ygerVeTcPw9zctqCauUbprahmMPWKzcYJNb64pW8FDLjc0ILmvshkWS0h1yk/SJ97w 3illbiN/ZoxUGorSJTRpljTQy25x9zVJ1X+X4R0BikZfH9MVk+YUCysYg8LR+O0CVVQX Ic+zKeq70uh2WLDyzc3G339E/i9rqUTK6JX6tHCWhJ/zO5Vmui2QIXLOZyXoAOV29D25 hHXim7bwdWZnT9m4nESBiswtvsPW3aE4FH+b+tCD1u8ArMQlQskIY0Wh0zqLWBWzAYF5 oSXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791970333; x=1792575133; h=in-reply-to:content-disposition:content-type:mime-version :references:message-id:subject:cc:to:from:date:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=qbp1OaXo+QOhXfEK2yTqfOOSMPB/aU27i+I9ooebTqo=; b=i4dbKqBsgTwtXr9c7NlQls7a51BmZX4Vi4cD6kOB2YYq2yUeewE1RulcKeeUJOOVnZ 3esVUvogNxonznR9kZzyGiG9ElXClXTH70+W4JALVnolephc87ZpHT85k5oeCcUppKCi Zh+7SVB2Vf6PcSMCnrxmcoOkMLW/iQtk5e07uOvN827E6XH2e5kbNK1+9M+ONVbPLG8c Jch8RktmiFKzQBJFQQx/uBwY2rZozJqEJjHfLhgPJN8y1J4RrJdppTInC3C2+hZMmEbx fhTf1TX8cYqPz2LLRYwKGoHkWUiEq2QZ2rx3ja9yAMuUGXNSS5sQYPnH0CcfjD4k/VwP 8RHg== X-Forwarded-Encrypted: i=1; AKwUvByz/wdxd+n5t+vc3eaCqUwVykO6pw0lxnU5CxKxwfaj+rmuUVtbm3iVh11O7S+d3Pn2XbEVnMTjOweuCPY=@vger.kernel.org X-Gm-Message-State: AFq9FYKgJoRHtcp/rUjZhiAsXbstG6aEA+ucBA0UG+H5ywhltX/OQC9r LTj5Aoki3oTq47ZHrw/5qAQhIEo87dqG/rWi88wto32dhtjEVPRmpejn31TIHQmXUKw= X-Gm-Gg: AYBFou35u/ARpofUygIfEOW+OIu5j3mGPVmMZyFaxMXr2586wUJHKwUdiinAeaxIs7T GSf0h18asApeUcLox5g/ZQwXDLLau1XTj1dHui0he6FTy3Pb1xjYGjrVbwCu/S6TKY9bofODbi6 6m/Cij0bbTEjx/M75NNcVKffYCjQFvVh9nik8tKi4YgYHSBkXR+po1d2aLHmXVaUxZIakLKIo/o 94oSHPceQRbk/E8O/cqDNov2YfjpPZV8x/f/Q8JAlrP1EGodhQ30wawZYS39y7a/s+dz9KPTASi 8tIQPWE2rP3B3yx5ltxy21vrddKB5kPAR+1nYSpZwy79HpbwaS8tbJiOE2vAgr8O61uzkmNlMpQ koBuJJV5A3OrpXIT07CXutnbXn2z0Bt6RzTD39KfAIElPikjyduQ62CMFulAWmauh9cK6G5OGz7 8pUrt4BiyXlNI+eloKaXekHULZqFBNMrNoU0FbDU6g8Z5IoolRMlq6E26Qw34Ze2ju5E3Rdr7CR wgwY96LPAoY X-Received: by 2002:a05:600c:8a09:20b0:4a1:9c98:b9b8 with SMTP id 5b1f17b1804b1-4a19c98c153mr160639475e9.11.1791970333205; Wed, 14 Oct 2026 02:32:13 -0700 (PDT) Received: from localhost (109-81-25-183.rct.o2.cz. [109.81.25.183]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48de0aaaaebsm10999272f8f.14.2026.10.14.02.32.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Oct 2026 02:32:12 -0700 (PDT) Date: Wed, 14 Oct 2026 11:32:11 +0200 From: Michal Hocko To: Ye Liu Cc: David Rientjes , Shakeel Butt , Andrew Morton , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, Ye Liu Subject: Re: [PATCH] proc: Move OOM-related procfs code to fs/proc/oom.c Message-ID: References: <20261014-oom_procfs-v1-1-f2d75e73571e@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20261014-oom_procfs-v1-1-f2d75e73571e@linux.dev> On Wed 14-10-26 16:54:12, Ye Liu wrote: > From: Ye Liu > > fs/proc/base.c is a large file (~3700 lines) handling all per-process > procfs entries. The OOM score, oom_adj, and oom_score_adj interface > code is self-contained and has no dependencies on other parts of > base.c, so move it into a dedicated fs/proc/oom.c following the same > pattern as fs/proc/fd.c and fs/proc/task_mmu.c. > > This makes both files easier to read and keeps OOM-related procfs > entries together in one place. Are there plans to separate other functionality or is this one off thing? In general I am not against of moving stuff to more specialized files. An obvious downside is a review as it is quite easy to overlook a subtle change when moving so much code. Something worth undertaking if there is a bigger goal. Not so sure if this is just a one of and fs/proc/base.c still keeps other random stuff in. > Signed-off-by: Ye Liu > --- > MAINTAINERS | 1 + > fs/proc/Makefile | 1 + > fs/proc/base.c | 232 ------------------------------------------------- > fs/proc/internal.h | 8 ++ > fs/proc/oom.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 259 insertions(+), 232 deletions(-) > > diff --git a/MAINTAINERS b/MAINTAINERS > index 1da3623e77ce..4b1c13a65136 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -17676,6 +17676,7 @@ R: David Rientjes > R: Shakeel Butt > L: linux-mm@kvack.org > S: Maintained > +F: fs/proc/oom.c > F: include/linux/oom.h > F: include/trace/events/oom.h > F: include/uapi/linux/oom.h > diff --git a/fs/proc/Makefile b/fs/proc/Makefile > index 27e2b26b2d42..68e65866b5df 100644 > --- a/fs/proc/Makefile > +++ b/fs/proc/Makefile > @@ -21,6 +21,7 @@ proc-y += interrupts.o > endif > proc-y += loadavg.o > proc-y += meminfo.o > +proc-y += oom.o > proc-y += stat.o > proc-y += uptime.o > proc-y += util.o > diff --git a/fs/proc/base.c b/fs/proc/base.c > index 8c04fcd436d2..26ccc05a50ff 100644 > --- a/fs/proc/base.c > +++ b/fs/proc/base.c > @@ -80,7 +80,6 @@ > #include > #include > #include > -#include > #include > #include > #include > @@ -99,7 +98,6 @@ > #include > #include > #include > -#include > #include "internal.h" > #include "fd.h" > > @@ -580,28 +578,6 @@ static const struct file_operations proc_lstats_operations = { > > #endif > > -static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, > - struct pid *pid, struct task_struct *task) > -{ > - unsigned long totalpages = totalram_pages() + total_swap_pages; > - unsigned long points = 0; > - long badness; > - > - badness = oom_badness(task, totalpages); > - /* > - * Special case OOM_SCORE_ADJ_MIN for all others scale the > - * badness value into [0, 2000] range which we have been > - * exporting for a long time so userspace might depend on it. > - */ > - if (badness != LONG_MIN) > - points = (OOM_SCORE_ADJ_MAX + > - badness * OOM_SCORE_ADJ_MAX / (long)totalpages) * 2 / 3; > - > - seq_printf(m, "%lu\n", points); > - > - return 0; > -} > - > struct limit_names { > const char *name; > const char *unit; > @@ -1115,214 +1091,6 @@ static const struct file_operations proc_auxv_operations = { > .release = mem_release, > }; > > -static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, > - loff_t *ppos) > -{ > - struct task_struct *task = get_proc_task(file_inode(file)); > - char buffer[PROC_NUMBUF]; > - int oom_adj = OOM_ADJUST_MIN; > - size_t len; > - > - if (!task) > - return -ESRCH; > - if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) > - oom_adj = OOM_ADJUST_MAX; > - else > - oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) / > - OOM_SCORE_ADJ_MAX; > - put_task_struct(task); > - if (oom_adj > OOM_ADJUST_MAX) > - oom_adj = OOM_ADJUST_MAX; > - len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj); > - return simple_read_from_buffer(buf, count, ppos, buffer, len); > -} > - > -static int __set_oom_adj(struct file *file, int oom_adj, bool legacy) > -{ > - struct mm_struct *mm = NULL; > - struct task_struct *task; > - int err = 0; > - > - task = get_proc_task(file_inode(file)); > - if (!task) > - return -ESRCH; > - > - mutex_lock(&oom_adj_mutex); > - if (legacy) { > - if (oom_adj < task->signal->oom_score_adj && > - !capable(CAP_SYS_RESOURCE)) { > - err = -EACCES; > - goto err_unlock; > - } > - /* > - * /proc/pid/oom_adj is provided for legacy purposes, ask users to use > - * /proc/pid/oom_score_adj instead. > - */ > - pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", > - current->comm, task_pid_nr(current), task_pid_nr(task), > - task_pid_nr(task)); > - } else { > - if ((short)oom_adj < task->signal->oom_score_adj_min && > - !capable(CAP_SYS_RESOURCE)) { > - err = -EACCES; > - goto err_unlock; > - } > - } > - > - /* > - * Make sure we will check other processes sharing the mm if this is > - * not vfrok which wants its own oom_score_adj. > - * pin the mm so it doesn't go away and get reused after task_unlock > - */ > - if (!task->vfork_done) { > - struct task_struct *p = find_lock_task_mm(task); > - > - if (p) { > - if (mm_flags_test(MMF_MULTIPROCESS, p->mm)) { > - mm = p->mm; > - mmgrab(mm); > - } > - task_unlock(p); > - } > - } > - > - task->signal->oom_score_adj = oom_adj; > - if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) > - task->signal->oom_score_adj_min = (short)oom_adj; > - trace_oom_score_adj_update(task); > - > - if (mm) { > - struct task_struct *p; > - > - rcu_read_lock(); > - for_each_process(p) { > - if (same_thread_group(task, p)) > - continue; > - > - /* do not touch kernel threads or the global init */ > - if (p->flags & PF_KTHREAD || is_global_init(p)) > - continue; > - > - task_lock(p); > - if (!p->vfork_done && process_shares_mm(p, mm)) { > - p->signal->oom_score_adj = oom_adj; > - if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) > - p->signal->oom_score_adj_min = (short)oom_adj; > - } > - task_unlock(p); > - } > - rcu_read_unlock(); > - mmdrop(mm); > - } > -err_unlock: > - mutex_unlock(&oom_adj_mutex); > - put_task_struct(task); > - return err; > -} > - > -/* > - * /proc/pid/oom_adj exists solely for backwards compatibility with previous > - * kernels. The effective policy is defined by oom_score_adj, which has a > - * different scale: oom_adj grew exponentially and oom_score_adj grows linearly. > - * Values written to oom_adj are simply mapped linearly to oom_score_adj. > - * Processes that become oom disabled via oom_adj will still be oom disabled > - * with this implementation. > - * > - * oom_adj cannot be removed since existing userspace binaries use it. > - */ > -static ssize_t oom_adj_write(struct file *file, const char __user *buf, > - size_t count, loff_t *ppos) > -{ > - char buffer[PROC_NUMBUF] = {}; > - int oom_adj; > - int err; > - > - if (count > sizeof(buffer) - 1) > - count = sizeof(buffer) - 1; > - if (copy_from_user(buffer, buf, count)) { > - err = -EFAULT; > - goto out; > - } > - > - err = kstrtoint(strstrip(buffer), 0, &oom_adj); > - if (err) > - goto out; > - if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) && > - oom_adj != OOM_DISABLE) { > - err = -EINVAL; > - goto out; > - } > - > - /* > - * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum > - * value is always attainable. > - */ > - if (oom_adj == OOM_ADJUST_MAX) > - oom_adj = OOM_SCORE_ADJ_MAX; > - else > - oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; > - > - err = __set_oom_adj(file, oom_adj, true); > -out: > - return err < 0 ? err : count; > -} > - > -static const struct file_operations proc_oom_adj_operations = { > - .read = oom_adj_read, > - .write = oom_adj_write, > - .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_inode(file)); > - char buffer[PROC_NUMBUF]; > - short oom_score_adj = OOM_SCORE_ADJ_MIN; > - size_t len; > - > - if (!task) > - return -ESRCH; > - oom_score_adj = task->signal->oom_score_adj; > - put_task_struct(task); > - len = snprintf(buffer, sizeof(buffer), "%hd\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) > -{ > - char buffer[PROC_NUMBUF] = {}; > - int oom_score_adj; > - int err; > - > - if (count > sizeof(buffer) - 1) > - count = sizeof(buffer) - 1; > - if (copy_from_user(buffer, buf, count)) { > - err = -EFAULT; > - goto out; > - } > - > - err = kstrtoint(strstrip(buffer), 0, &oom_score_adj); > - if (err) > - goto out; > - if (oom_score_adj < OOM_SCORE_ADJ_MIN || > - oom_score_adj > OOM_SCORE_ADJ_MAX) { > - err = -EINVAL; > - goto out; > - } > - > - err = __set_oom_adj(file, oom_score_adj, false); > -out: > - return err < 0 ? err : count; > -} > - > -static const struct file_operations proc_oom_score_adj_operations = { > - .read = oom_score_adj_read, > - .write = oom_score_adj_write, > - .llseek = default_llseek, > -}; > - > #ifdef CONFIG_AUDIT > #define TMPBUFLEN 11 > static ssize_t proc_loginuid_read(struct file * file, char __user * buf, > diff --git a/fs/proc/internal.h b/fs/proc/internal.h > index df873df9afc5..b72a2bd604ed 100644 > --- a/fs/proc/internal.h > +++ b/fs/proc/internal.h > @@ -238,6 +238,14 @@ static inline int folio_average_page_mapcount(struct folio *folio) > /* ... but return at least 1. */ > return max_t(int, avg + entire_mapcount, 1); > } > +/* > + * oom.c > + */ > +int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, > + struct pid *pid, struct task_struct *task); > +extern const struct file_operations proc_oom_adj_operations; > +extern const struct file_operations proc_oom_score_adj_operations; > + > /* > * array.c > */ > diff --git a/fs/proc/oom.c b/fs/proc/oom.c > new file mode 100644 > index 000000000000..5f22ec4a4a6e > --- /dev/null > +++ b/fs/proc/oom.c > @@ -0,0 +1,249 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * OOM-related procfs entries > + * > + * This file handles the OOM score, oom_adj, and oom_score_adj interfaces > + * in /proc//. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "internal.h" > + > +int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, > + struct pid *pid, struct task_struct *task) > +{ > + unsigned long totalpages = totalram_pages() + total_swap_pages; > + unsigned long points = 0; > + long badness; > + > + badness = oom_badness(task, totalpages); > + /* > + * Special case OOM_SCORE_ADJ_MIN for all others scale the > + * badness value into [0, 2000] range which we have been > + * exporting for a long time so userspace might depend on it. > + */ > + if (badness != LONG_MIN) > + points = (OOM_SCORE_ADJ_MAX + > + badness * OOM_SCORE_ADJ_MAX / (long)totalpages) * 2 / 3; > + > + seq_printf(m, "%lu\n", points); > + > + return 0; > +} > + > +static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, > + loff_t *ppos) > +{ > + struct task_struct *task = get_proc_task(file_inode(file)); > + char buffer[PROC_NUMBUF]; > + int oom_adj = OOM_ADJUST_MIN; > + size_t len; > + > + if (!task) > + return -ESRCH; > + if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) > + oom_adj = OOM_ADJUST_MAX; > + else > + oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) / > + OOM_SCORE_ADJ_MAX; > + put_task_struct(task); > + if (oom_adj > OOM_ADJUST_MAX) > + oom_adj = OOM_ADJUST_MAX; > + len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj); > + return simple_read_from_buffer(buf, count, ppos, buffer, len); > +} > + > +static int __set_oom_adj(struct file *file, int oom_adj, bool legacy) > +{ > + struct mm_struct *mm = NULL; > + struct task_struct *task; > + int err = 0; > + > + task = get_proc_task(file_inode(file)); > + if (!task) > + return -ESRCH; > + > + mutex_lock(&oom_adj_mutex); > + if (legacy) { > + if (oom_adj < task->signal->oom_score_adj && > + !capable(CAP_SYS_RESOURCE)) { > + err = -EACCES; > + goto err_unlock; > + } > + /* > + * /proc/pid/oom_adj is provided for legacy purposes, ask users to use > + * /proc/pid/oom_score_adj instead. > + */ > + pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", > + current->comm, task_pid_nr(current), task_pid_nr(task), > + task_pid_nr(task)); > + } else { > + if ((short)oom_adj < task->signal->oom_score_adj_min && > + !capable(CAP_SYS_RESOURCE)) { > + err = -EACCES; > + goto err_unlock; > + } > + } > + > + /* > + * Make sure we will check other processes sharing the mm if this is > + * not vfrok which wants its own oom_score_adj. > + * pin the mm so it doesn't go away and get reused after task_unlock > + */ > + if (!task->vfork_done) { > + struct task_struct *p = find_lock_task_mm(task); > + > + if (p) { > + if (mm_flags_test(MMF_MULTIPROCESS, p->mm)) { > + mm = p->mm; > + mmgrab(mm); > + } > + task_unlock(p); > + } > + } > + > + task->signal->oom_score_adj = oom_adj; > + if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) > + task->signal->oom_score_adj_min = (short)oom_adj; > + trace_oom_score_adj_update(task); > + > + if (mm) { > + struct task_struct *p; > + > + rcu_read_lock(); > + for_each_process(p) { > + if (same_thread_group(task, p)) > + continue; > + > + /* do not touch kernel threads or the global init */ > + if (p->flags & PF_KTHREAD || is_global_init(p)) > + continue; > + > + task_lock(p); > + if (!p->vfork_done && process_shares_mm(p, mm)) { > + p->signal->oom_score_adj = oom_adj; > + if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) > + p->signal->oom_score_adj_min = (short)oom_adj; > + } > + task_unlock(p); > + } > + rcu_read_unlock(); > + mmdrop(mm); > + } > +err_unlock: > + mutex_unlock(&oom_adj_mutex); > + put_task_struct(task); > + return err; > +} > + > +/* > + * /proc/pid/oom_adj exists solely for backwards compatibility with previous > + * kernels. The effective policy is defined by oom_score_adj, which has a > + * different scale: oom_adj grew exponentially and oom_score_adj grows linearly. > + * Values written to oom_adj are simply mapped linearly to oom_score_adj. > + * Processes that become oom disabled via oom_adj will still be oom disabled > + * with this implementation. > + * > + * oom_adj cannot be removed since existing userspace binaries use it. > + */ > +static ssize_t oom_adj_write(struct file *file, const char __user *buf, > + size_t count, loff_t *ppos) > +{ > + char buffer[PROC_NUMBUF] = {}; > + int oom_adj; > + int err; > + > + if (count > sizeof(buffer) - 1) > + count = sizeof(buffer) - 1; > + if (copy_from_user(buffer, buf, count)) { > + err = -EFAULT; > + goto out; > + } > + > + err = kstrtoint(strstrip(buffer), 0, &oom_adj); > + if (err) > + goto out; > + if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) && > + oom_adj != OOM_DISABLE) { > + err = -EINVAL; > + goto out; > + } > + > + /* > + * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum > + * value is always attainable. > + */ > + if (oom_adj == OOM_ADJUST_MAX) > + oom_adj = OOM_SCORE_ADJ_MAX; > + else > + oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; > + > + err = __set_oom_adj(file, oom_adj, true); > +out: > + return err < 0 ? err : count; > +} > + > +const struct file_operations proc_oom_adj_operations = { > + .read = oom_adj_read, > + .write = oom_adj_write, > + .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_inode(file)); > + char buffer[PROC_NUMBUF]; > + short oom_score_adj = OOM_SCORE_ADJ_MIN; > + size_t len; > + > + if (!task) > + return -ESRCH; > + oom_score_adj = task->signal->oom_score_adj; > + put_task_struct(task); > + len = snprintf(buffer, sizeof(buffer), "%hd\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) > +{ > + char buffer[PROC_NUMBUF] = {}; > + int oom_score_adj; > + int err; > + > + if (count > sizeof(buffer) - 1) > + count = sizeof(buffer) - 1; > + if (copy_from_user(buffer, buf, count)) { > + err = -EFAULT; > + goto out; > + } > + > + err = kstrtoint(strstrip(buffer), 0, &oom_score_adj); > + if (err) > + goto out; > + if (oom_score_adj < OOM_SCORE_ADJ_MIN || > + oom_score_adj > OOM_SCORE_ADJ_MAX) { > + err = -EINVAL; > + goto out; > + } > + > + err = __set_oom_adj(file, oom_score_adj, false); > +out: > + return err < 0 ? err : count; > +} > + > +const struct file_operations proc_oom_score_adj_operations = { > + .read = oom_score_adj_read, > + .write = oom_score_adj_write, > + .llseek = default_llseek, > +}; > > --- > base-commit: 1fffefb00cc0b0da1f2ae24e3d33364530ea6515 > base-tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master > change-id: 20261014-oom_procfs-f74a922f73f1 > > Best regards, > -- > Ye Liu -- Michal Hocko SUSE Labs