Merge branch 'akpm' (fixes from Andrew Morton)
Merge patch-bomb from Andrew Morton: - part of OCFS2 (review is laggy again) - procfs - slab - all of MM - zram, zbud - various other random things: arch, filesystems. * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (164 commits) nosave: consolidate __nosave_{begin,end} in <asm/sections.h> include/linux/screen_info.h: remove unused ORIG_* macros kernel/sys.c: compat sysinfo syscall: fix undefined behavior kernel/sys.c: whitespace fixes acct: eliminate compile warning kernel/async.c: switch to pr_foo() include/linux/blkdev.h: use NULL instead of zero include/linux/kernel.h: deduplicate code implementing clamp* macros include/linux/kernel.h: rewrite min3, max3 and clamp using min and max alpha: use Kbuild logic to include <asm-generic/sections.h> frv: remove deprecated IRQF_DISABLED frv: remove unused cpuinfo_frv and friends to fix future build error zbud: avoid accessing last unused freelist zsmalloc: simplify init_zspage free obj linking mm/zsmalloc.c: correct comment for fullness group computation zram: use notify_free to account all free notifications zram: report maximum used memory zram: zram memory size limitation zsmalloc: change return value unit of zs_get_total_size_bytes zsmalloc: move pages_allocated to zs_pool ...
This commit is contained in:
+9
-5
@@ -472,7 +472,6 @@ static void do_acct_process(struct bsd_acct_struct *acct)
|
||||
acct_t ac;
|
||||
unsigned long flim;
|
||||
const struct cred *orig_cred;
|
||||
struct pid_namespace *ns = acct->ns;
|
||||
struct file *file = acct->file;
|
||||
|
||||
/*
|
||||
@@ -500,10 +499,15 @@ static void do_acct_process(struct bsd_acct_struct *acct)
|
||||
ac.ac_gid16 = ac.ac_gid;
|
||||
#endif
|
||||
#if ACCT_VERSION == 3
|
||||
ac.ac_pid = task_tgid_nr_ns(current, ns);
|
||||
rcu_read_lock();
|
||||
ac.ac_ppid = task_tgid_nr_ns(rcu_dereference(current->real_parent), ns);
|
||||
rcu_read_unlock();
|
||||
{
|
||||
struct pid_namespace *ns = acct->ns;
|
||||
|
||||
ac.ac_pid = task_tgid_nr_ns(current, ns);
|
||||
rcu_read_lock();
|
||||
ac.ac_ppid = task_tgid_nr_ns(rcu_dereference(current->real_parent),
|
||||
ns);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Get freeze protection. If the fs is frozen, just skip the write
|
||||
|
||||
+4
-4
@@ -115,7 +115,7 @@ static void async_run_entry_fn(struct work_struct *work)
|
||||
|
||||
/* 1) run (and print duration) */
|
||||
if (initcall_debug && system_state == SYSTEM_BOOTING) {
|
||||
printk(KERN_DEBUG "calling %lli_%pF @ %i\n",
|
||||
pr_debug("calling %lli_%pF @ %i\n",
|
||||
(long long)entry->cookie,
|
||||
entry->func, task_pid_nr(current));
|
||||
calltime = ktime_get();
|
||||
@@ -124,7 +124,7 @@ static void async_run_entry_fn(struct work_struct *work)
|
||||
if (initcall_debug && system_state == SYSTEM_BOOTING) {
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
printk(KERN_DEBUG "initcall %lli_%pF returned 0 after %lld usecs\n",
|
||||
pr_debug("initcall %lli_%pF returned 0 after %lld usecs\n",
|
||||
(long long)entry->cookie,
|
||||
entry->func,
|
||||
(long long)ktime_to_ns(delta) >> 10);
|
||||
@@ -285,7 +285,7 @@ void async_synchronize_cookie_domain(async_cookie_t cookie, struct async_domain
|
||||
ktime_t uninitialized_var(starttime), delta, endtime;
|
||||
|
||||
if (initcall_debug && system_state == SYSTEM_BOOTING) {
|
||||
printk(KERN_DEBUG "async_waiting @ %i\n", task_pid_nr(current));
|
||||
pr_debug("async_waiting @ %i\n", task_pid_nr(current));
|
||||
starttime = ktime_get();
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ void async_synchronize_cookie_domain(async_cookie_t cookie, struct async_domain
|
||||
endtime = ktime_get();
|
||||
delta = ktime_sub(endtime, starttime);
|
||||
|
||||
printk(KERN_DEBUG "async_continuing @ %i after %lli usec\n",
|
||||
pr_debug("async_continuing @ %i after %lli usec\n",
|
||||
task_pid_nr(current),
|
||||
(long long)ktime_to_ns(delta) >> 10);
|
||||
}
|
||||
|
||||
+1
-2
@@ -601,9 +601,8 @@ static void check_mm(struct mm_struct *mm)
|
||||
printk(KERN_ALERT "BUG: Bad rss-counter state "
|
||||
"mm:%p idx:%d val:%ld\n", mm, i, x);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
|
||||
VM_BUG_ON(mm->pmd_huge_pte);
|
||||
VM_BUG_ON_MM(mm->pmd_huge_pte, mm);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -369,7 +369,7 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
|
||||
{
|
||||
struct task_struct *p;
|
||||
|
||||
p = kthread_create_on_node(threadfn, data, cpu_to_mem(cpu), namefmt,
|
||||
p = kthread_create_on_node(threadfn, data, cpu_to_node(cpu), namefmt,
|
||||
cpu);
|
||||
if (IS_ERR(p))
|
||||
return p;
|
||||
|
||||
+1
-1
@@ -1946,7 +1946,7 @@ void task_numa_work(struct callback_head *work)
|
||||
vma = mm->mmap;
|
||||
}
|
||||
for (; vma; vma = vma->vm_next) {
|
||||
if (!vma_migratable(vma) || !vma_policy_mof(p, vma))
|
||||
if (!vma_migratable(vma) || !vma_policy_mof(vma))
|
||||
continue;
|
||||
|
||||
/*
|
||||
|
||||
+341
-146
@@ -62,28 +62,28 @@
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#ifndef SET_UNALIGN_CTL
|
||||
# define SET_UNALIGN_CTL(a,b) (-EINVAL)
|
||||
# define SET_UNALIGN_CTL(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef GET_UNALIGN_CTL
|
||||
# define GET_UNALIGN_CTL(a,b) (-EINVAL)
|
||||
# define GET_UNALIGN_CTL(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef SET_FPEMU_CTL
|
||||
# define SET_FPEMU_CTL(a,b) (-EINVAL)
|
||||
# define SET_FPEMU_CTL(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef GET_FPEMU_CTL
|
||||
# define GET_FPEMU_CTL(a,b) (-EINVAL)
|
||||
# define GET_FPEMU_CTL(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef SET_FPEXC_CTL
|
||||
# define SET_FPEXC_CTL(a,b) (-EINVAL)
|
||||
# define SET_FPEXC_CTL(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef GET_FPEXC_CTL
|
||||
# define GET_FPEXC_CTL(a,b) (-EINVAL)
|
||||
# define GET_FPEXC_CTL(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef GET_ENDIAN
|
||||
# define GET_ENDIAN(a,b) (-EINVAL)
|
||||
# define GET_ENDIAN(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef SET_ENDIAN
|
||||
# define SET_ENDIAN(a,b) (-EINVAL)
|
||||
# define SET_ENDIAN(a, b) (-EINVAL)
|
||||
#endif
|
||||
#ifndef GET_TSC_CTL
|
||||
# define GET_TSC_CTL(a) (-EINVAL)
|
||||
@@ -182,39 +182,40 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
|
||||
rcu_read_lock();
|
||||
read_lock(&tasklist_lock);
|
||||
switch (which) {
|
||||
case PRIO_PROCESS:
|
||||
if (who)
|
||||
p = find_task_by_vpid(who);
|
||||
else
|
||||
p = current;
|
||||
if (p)
|
||||
error = set_one_prio(p, niceval, error);
|
||||
break;
|
||||
case PRIO_PGRP:
|
||||
if (who)
|
||||
pgrp = find_vpid(who);
|
||||
else
|
||||
pgrp = task_pgrp(current);
|
||||
do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
|
||||
error = set_one_prio(p, niceval, error);
|
||||
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
||||
break;
|
||||
case PRIO_USER:
|
||||
uid = make_kuid(cred->user_ns, who);
|
||||
user = cred->user;
|
||||
if (!who)
|
||||
uid = cred->uid;
|
||||
else if (!uid_eq(uid, cred->uid) &&
|
||||
!(user = find_user(uid)))
|
||||
case PRIO_PROCESS:
|
||||
if (who)
|
||||
p = find_task_by_vpid(who);
|
||||
else
|
||||
p = current;
|
||||
if (p)
|
||||
error = set_one_prio(p, niceval, error);
|
||||
break;
|
||||
case PRIO_PGRP:
|
||||
if (who)
|
||||
pgrp = find_vpid(who);
|
||||
else
|
||||
pgrp = task_pgrp(current);
|
||||
do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
|
||||
error = set_one_prio(p, niceval, error);
|
||||
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
||||
break;
|
||||
case PRIO_USER:
|
||||
uid = make_kuid(cred->user_ns, who);
|
||||
user = cred->user;
|
||||
if (!who)
|
||||
uid = cred->uid;
|
||||
else if (!uid_eq(uid, cred->uid)) {
|
||||
user = find_user(uid);
|
||||
if (!user)
|
||||
goto out_unlock; /* No processes for this user */
|
||||
|
||||
do_each_thread(g, p) {
|
||||
if (uid_eq(task_uid(p), uid))
|
||||
error = set_one_prio(p, niceval, error);
|
||||
} while_each_thread(g, p);
|
||||
if (!uid_eq(uid, cred->uid))
|
||||
free_uid(user); /* For find_user() */
|
||||
break;
|
||||
}
|
||||
do_each_thread(g, p) {
|
||||
if (uid_eq(task_uid(p), uid))
|
||||
error = set_one_prio(p, niceval, error);
|
||||
} while_each_thread(g, p);
|
||||
if (!uid_eq(uid, cred->uid))
|
||||
free_uid(user); /* For find_user() */
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
read_unlock(&tasklist_lock);
|
||||
@@ -244,47 +245,48 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
|
||||
rcu_read_lock();
|
||||
read_lock(&tasklist_lock);
|
||||
switch (which) {
|
||||
case PRIO_PROCESS:
|
||||
if (who)
|
||||
p = find_task_by_vpid(who);
|
||||
else
|
||||
p = current;
|
||||
if (p) {
|
||||
case PRIO_PROCESS:
|
||||
if (who)
|
||||
p = find_task_by_vpid(who);
|
||||
else
|
||||
p = current;
|
||||
if (p) {
|
||||
niceval = nice_to_rlimit(task_nice(p));
|
||||
if (niceval > retval)
|
||||
retval = niceval;
|
||||
}
|
||||
break;
|
||||
case PRIO_PGRP:
|
||||
if (who)
|
||||
pgrp = find_vpid(who);
|
||||
else
|
||||
pgrp = task_pgrp(current);
|
||||
do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
|
||||
niceval = nice_to_rlimit(task_nice(p));
|
||||
if (niceval > retval)
|
||||
retval = niceval;
|
||||
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
||||
break;
|
||||
case PRIO_USER:
|
||||
uid = make_kuid(cred->user_ns, who);
|
||||
user = cred->user;
|
||||
if (!who)
|
||||
uid = cred->uid;
|
||||
else if (!uid_eq(uid, cred->uid)) {
|
||||
user = find_user(uid);
|
||||
if (!user)
|
||||
goto out_unlock; /* No processes for this user */
|
||||
}
|
||||
do_each_thread(g, p) {
|
||||
if (uid_eq(task_uid(p), uid)) {
|
||||
niceval = nice_to_rlimit(task_nice(p));
|
||||
if (niceval > retval)
|
||||
retval = niceval;
|
||||
}
|
||||
break;
|
||||
case PRIO_PGRP:
|
||||
if (who)
|
||||
pgrp = find_vpid(who);
|
||||
else
|
||||
pgrp = task_pgrp(current);
|
||||
do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
|
||||
niceval = nice_to_rlimit(task_nice(p));
|
||||
if (niceval > retval)
|
||||
retval = niceval;
|
||||
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
||||
break;
|
||||
case PRIO_USER:
|
||||
uid = make_kuid(cred->user_ns, who);
|
||||
user = cred->user;
|
||||
if (!who)
|
||||
uid = cred->uid;
|
||||
else if (!uid_eq(uid, cred->uid) &&
|
||||
!(user = find_user(uid)))
|
||||
goto out_unlock; /* No processes for this user */
|
||||
|
||||
do_each_thread(g, p) {
|
||||
if (uid_eq(task_uid(p), uid)) {
|
||||
niceval = nice_to_rlimit(task_nice(p));
|
||||
if (niceval > retval)
|
||||
retval = niceval;
|
||||
}
|
||||
} while_each_thread(g, p);
|
||||
if (!uid_eq(uid, cred->uid))
|
||||
free_uid(user); /* for find_user() */
|
||||
break;
|
||||
} while_each_thread(g, p);
|
||||
if (!uid_eq(uid, cred->uid))
|
||||
free_uid(user); /* for find_user() */
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
read_unlock(&tasklist_lock);
|
||||
@@ -306,7 +308,7 @@ out_unlock:
|
||||
*
|
||||
* The general idea is that a program which uses just setregid() will be
|
||||
* 100% compatible with BSD. A program which uses just setgid() will be
|
||||
* 100% compatible with POSIX with saved IDs.
|
||||
* 100% compatible with POSIX with saved IDs.
|
||||
*
|
||||
* SMP: There are not races, the GIDs are checked only by filesystem
|
||||
* operations (as far as semantic preservation is concerned).
|
||||
@@ -364,7 +366,7 @@ error:
|
||||
}
|
||||
|
||||
/*
|
||||
* setgid() is implemented like SysV w/ SAVED_IDS
|
||||
* setgid() is implemented like SysV w/ SAVED_IDS
|
||||
*
|
||||
* SMP: Same implicit races as above.
|
||||
*/
|
||||
@@ -442,7 +444,7 @@ static int set_user(struct cred *new)
|
||||
*
|
||||
* The general idea is that a program which uses just setreuid() will be
|
||||
* 100% compatible with BSD. A program which uses just setuid() will be
|
||||
* 100% compatible with POSIX with saved IDs.
|
||||
* 100% compatible with POSIX with saved IDs.
|
||||
*/
|
||||
SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
||||
{
|
||||
@@ -503,17 +505,17 @@ error:
|
||||
abort_creds(new);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setuid() is implemented like SysV with SAVED_IDS
|
||||
*
|
||||
* setuid() is implemented like SysV with SAVED_IDS
|
||||
*
|
||||
* Note that SAVED_ID's is deficient in that a setuid root program
|
||||
* like sendmail, for example, cannot set its uid to be a normal
|
||||
* like sendmail, for example, cannot set its uid to be a normal
|
||||
* user and then switch back, because if you're root, setuid() sets
|
||||
* the saved uid too. If you don't like this, blame the bright people
|
||||
* in the POSIX committee and/or USG. Note that the BSD-style setreuid()
|
||||
* will allow a root program to temporarily drop privileges and be able to
|
||||
* regain them by swapping the real and effective uid.
|
||||
* regain them by swapping the real and effective uid.
|
||||
*/
|
||||
SYSCALL_DEFINE1(setuid, uid_t, uid)
|
||||
{
|
||||
@@ -637,10 +639,12 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t _
|
||||
euid = from_kuid_munged(cred->user_ns, cred->euid);
|
||||
suid = from_kuid_munged(cred->user_ns, cred->suid);
|
||||
|
||||
if (!(retval = put_user(ruid, ruidp)) &&
|
||||
!(retval = put_user(euid, euidp)))
|
||||
retval = put_user(suid, suidp);
|
||||
|
||||
retval = put_user(ruid, ruidp);
|
||||
if (!retval) {
|
||||
retval = put_user(euid, euidp);
|
||||
if (!retval)
|
||||
return put_user(suid, suidp);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -709,9 +713,12 @@ SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t _
|
||||
egid = from_kgid_munged(cred->user_ns, cred->egid);
|
||||
sgid = from_kgid_munged(cred->user_ns, cred->sgid);
|
||||
|
||||
if (!(retval = put_user(rgid, rgidp)) &&
|
||||
!(retval = put_user(egid, egidp)))
|
||||
retval = put_user(sgid, sgidp);
|
||||
retval = put_user(rgid, rgidp);
|
||||
if (!retval) {
|
||||
retval = put_user(egid, egidp);
|
||||
if (!retval)
|
||||
retval = put_user(sgid, sgidp);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -1284,7 +1291,6 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
|
||||
/*
|
||||
* Back compatibility for getrlimit. Needed for some apps.
|
||||
*/
|
||||
|
||||
SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
|
||||
struct rlimit __user *, rlim)
|
||||
{
|
||||
@@ -1299,7 +1305,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
|
||||
x.rlim_cur = 0x7FFFFFFF;
|
||||
if (x.rlim_max > 0x7FFFFFFF)
|
||||
x.rlim_max = 0x7FFFFFFF;
|
||||
return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
|
||||
return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1527,7 +1533,7 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
|
||||
cputime_t tgutime, tgstime, utime, stime;
|
||||
unsigned long maxrss = 0;
|
||||
|
||||
memset((char *) r, 0, sizeof *r);
|
||||
memset((char *)r, 0, sizeof (*r));
|
||||
utime = stime = 0;
|
||||
|
||||
if (who == RUSAGE_THREAD) {
|
||||
@@ -1541,41 +1547,41 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
|
||||
return;
|
||||
|
||||
switch (who) {
|
||||
case RUSAGE_BOTH:
|
||||
case RUSAGE_CHILDREN:
|
||||
utime = p->signal->cutime;
|
||||
stime = p->signal->cstime;
|
||||
r->ru_nvcsw = p->signal->cnvcsw;
|
||||
r->ru_nivcsw = p->signal->cnivcsw;
|
||||
r->ru_minflt = p->signal->cmin_flt;
|
||||
r->ru_majflt = p->signal->cmaj_flt;
|
||||
r->ru_inblock = p->signal->cinblock;
|
||||
r->ru_oublock = p->signal->coublock;
|
||||
maxrss = p->signal->cmaxrss;
|
||||
case RUSAGE_BOTH:
|
||||
case RUSAGE_CHILDREN:
|
||||
utime = p->signal->cutime;
|
||||
stime = p->signal->cstime;
|
||||
r->ru_nvcsw = p->signal->cnvcsw;
|
||||
r->ru_nivcsw = p->signal->cnivcsw;
|
||||
r->ru_minflt = p->signal->cmin_flt;
|
||||
r->ru_majflt = p->signal->cmaj_flt;
|
||||
r->ru_inblock = p->signal->cinblock;
|
||||
r->ru_oublock = p->signal->coublock;
|
||||
maxrss = p->signal->cmaxrss;
|
||||
|
||||
if (who == RUSAGE_CHILDREN)
|
||||
break;
|
||||
|
||||
case RUSAGE_SELF:
|
||||
thread_group_cputime_adjusted(p, &tgutime, &tgstime);
|
||||
utime += tgutime;
|
||||
stime += tgstime;
|
||||
r->ru_nvcsw += p->signal->nvcsw;
|
||||
r->ru_nivcsw += p->signal->nivcsw;
|
||||
r->ru_minflt += p->signal->min_flt;
|
||||
r->ru_majflt += p->signal->maj_flt;
|
||||
r->ru_inblock += p->signal->inblock;
|
||||
r->ru_oublock += p->signal->oublock;
|
||||
if (maxrss < p->signal->maxrss)
|
||||
maxrss = p->signal->maxrss;
|
||||
t = p;
|
||||
do {
|
||||
accumulate_thread_rusage(t, r);
|
||||
} while_each_thread(p, t);
|
||||
if (who == RUSAGE_CHILDREN)
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
case RUSAGE_SELF:
|
||||
thread_group_cputime_adjusted(p, &tgutime, &tgstime);
|
||||
utime += tgutime;
|
||||
stime += tgstime;
|
||||
r->ru_nvcsw += p->signal->nvcsw;
|
||||
r->ru_nivcsw += p->signal->nivcsw;
|
||||
r->ru_minflt += p->signal->min_flt;
|
||||
r->ru_majflt += p->signal->maj_flt;
|
||||
r->ru_inblock += p->signal->inblock;
|
||||
r->ru_oublock += p->signal->oublock;
|
||||
if (maxrss < p->signal->maxrss)
|
||||
maxrss = p->signal->maxrss;
|
||||
t = p;
|
||||
do {
|
||||
accumulate_thread_rusage(t, r);
|
||||
} while_each_thread(p, t);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
unlock_task_sighand(p, &flags);
|
||||
|
||||
@@ -1585,6 +1591,7 @@ out:
|
||||
|
||||
if (who != RUSAGE_CHILDREN) {
|
||||
struct mm_struct *mm = get_task_mm(p);
|
||||
|
||||
if (mm) {
|
||||
setmax_mm_hiwater_rss(&maxrss, mm);
|
||||
mmput(mm);
|
||||
@@ -1596,6 +1603,7 @@ out:
|
||||
int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
|
||||
{
|
||||
struct rusage r;
|
||||
|
||||
k_getrusage(p, who, &r);
|
||||
return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
|
||||
}
|
||||
@@ -1628,12 +1636,14 @@ SYSCALL_DEFINE1(umask, int, mask)
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
|
||||
static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd)
|
||||
{
|
||||
struct fd exe;
|
||||
struct inode *inode;
|
||||
int err;
|
||||
|
||||
VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm);
|
||||
|
||||
exe = fdget(fd);
|
||||
if (!exe.file)
|
||||
return -EBADF;
|
||||
@@ -1654,8 +1664,6 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
|
||||
/*
|
||||
* Forbid mm->exe_file change if old file still mapped.
|
||||
*/
|
||||
@@ -1667,7 +1675,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
|
||||
if (vma->vm_file &&
|
||||
path_equal(&vma->vm_file->f_path,
|
||||
&mm->exe_file->f_path))
|
||||
goto exit_unlock;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1678,34 +1686,222 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
|
||||
*/
|
||||
err = -EPERM;
|
||||
if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags))
|
||||
goto exit_unlock;
|
||||
goto exit;
|
||||
|
||||
err = 0;
|
||||
set_mm_exe_file(mm, exe.file); /* this grabs a reference to exe.file */
|
||||
exit_unlock:
|
||||
up_write(&mm->mmap_sem);
|
||||
|
||||
exit:
|
||||
fdput(exe);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHECKPOINT_RESTORE
|
||||
/*
|
||||
* WARNING: we don't require any capability here so be very careful
|
||||
* in what is allowed for modification from userspace.
|
||||
*/
|
||||
static int validate_prctl_map(struct prctl_mm_map *prctl_map)
|
||||
{
|
||||
unsigned long mmap_max_addr = TASK_SIZE;
|
||||
struct mm_struct *mm = current->mm;
|
||||
int error = -EINVAL, i;
|
||||
|
||||
static const unsigned char offsets[] = {
|
||||
offsetof(struct prctl_mm_map, start_code),
|
||||
offsetof(struct prctl_mm_map, end_code),
|
||||
offsetof(struct prctl_mm_map, start_data),
|
||||
offsetof(struct prctl_mm_map, end_data),
|
||||
offsetof(struct prctl_mm_map, start_brk),
|
||||
offsetof(struct prctl_mm_map, brk),
|
||||
offsetof(struct prctl_mm_map, start_stack),
|
||||
offsetof(struct prctl_mm_map, arg_start),
|
||||
offsetof(struct prctl_mm_map, arg_end),
|
||||
offsetof(struct prctl_mm_map, env_start),
|
||||
offsetof(struct prctl_mm_map, env_end),
|
||||
};
|
||||
|
||||
/*
|
||||
* Make sure the members are not somewhere outside
|
||||
* of allowed address space.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(offsets); i++) {
|
||||
u64 val = *(u64 *)((char *)prctl_map + offsets[i]);
|
||||
|
||||
if ((unsigned long)val >= mmap_max_addr ||
|
||||
(unsigned long)val < mmap_min_addr)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the pairs are ordered.
|
||||
*/
|
||||
#define __prctl_check_order(__m1, __op, __m2) \
|
||||
((unsigned long)prctl_map->__m1 __op \
|
||||
(unsigned long)prctl_map->__m2) ? 0 : -EINVAL
|
||||
error = __prctl_check_order(start_code, <, end_code);
|
||||
error |= __prctl_check_order(start_data, <, end_data);
|
||||
error |= __prctl_check_order(start_brk, <=, brk);
|
||||
error |= __prctl_check_order(arg_start, <=, arg_end);
|
||||
error |= __prctl_check_order(env_start, <=, env_end);
|
||||
if (error)
|
||||
goto out;
|
||||
#undef __prctl_check_order
|
||||
|
||||
error = -EINVAL;
|
||||
|
||||
/*
|
||||
* @brk should be after @end_data in traditional maps.
|
||||
*/
|
||||
if (prctl_map->start_brk <= prctl_map->end_data ||
|
||||
prctl_map->brk <= prctl_map->end_data)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Neither we should allow to override limits if they set.
|
||||
*/
|
||||
if (check_data_rlimit(rlimit(RLIMIT_DATA), prctl_map->brk,
|
||||
prctl_map->start_brk, prctl_map->end_data,
|
||||
prctl_map->start_data))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Someone is trying to cheat the auxv vector.
|
||||
*/
|
||||
if (prctl_map->auxv_size) {
|
||||
if (!prctl_map->auxv || prctl_map->auxv_size > sizeof(mm->saved_auxv))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, make sure the caller has the rights to
|
||||
* change /proc/pid/exe link: only local root should
|
||||
* be allowed to.
|
||||
*/
|
||||
if (prctl_map->exe_fd != (u32)-1) {
|
||||
struct user_namespace *ns = current_user_ns();
|
||||
const struct cred *cred = current_cred();
|
||||
|
||||
if (!uid_eq(cred->uid, make_kuid(ns, 0)) ||
|
||||
!gid_eq(cred->gid, make_kgid(ns, 0)))
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data_size)
|
||||
{
|
||||
struct prctl_mm_map prctl_map = { .exe_fd = (u32)-1, };
|
||||
unsigned long user_auxv[AT_VECTOR_SIZE];
|
||||
struct mm_struct *mm = current->mm;
|
||||
int error;
|
||||
|
||||
BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv));
|
||||
BUILD_BUG_ON(sizeof(struct prctl_mm_map) > 256);
|
||||
|
||||
if (opt == PR_SET_MM_MAP_SIZE)
|
||||
return put_user((unsigned int)sizeof(prctl_map),
|
||||
(unsigned int __user *)addr);
|
||||
|
||||
if (data_size != sizeof(prctl_map))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&prctl_map, addr, sizeof(prctl_map)))
|
||||
return -EFAULT;
|
||||
|
||||
error = validate_prctl_map(&prctl_map);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (prctl_map.auxv_size) {
|
||||
memset(user_auxv, 0, sizeof(user_auxv));
|
||||
if (copy_from_user(user_auxv,
|
||||
(const void __user *)prctl_map.auxv,
|
||||
prctl_map.auxv_size))
|
||||
return -EFAULT;
|
||||
|
||||
/* Last entry must be AT_NULL as specification requires */
|
||||
user_auxv[AT_VECTOR_SIZE - 2] = AT_NULL;
|
||||
user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL;
|
||||
}
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
if (prctl_map.exe_fd != (u32)-1)
|
||||
error = prctl_set_mm_exe_file_locked(mm, prctl_map.exe_fd);
|
||||
downgrade_write(&mm->mmap_sem);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We don't validate if these members are pointing to
|
||||
* real present VMAs because application may have correspond
|
||||
* VMAs already unmapped and kernel uses these members for statistics
|
||||
* output in procfs mostly, except
|
||||
*
|
||||
* - @start_brk/@brk which are used in do_brk but kernel lookups
|
||||
* for VMAs when updating these memvers so anything wrong written
|
||||
* here cause kernel to swear at userspace program but won't lead
|
||||
* to any problem in kernel itself
|
||||
*/
|
||||
|
||||
mm->start_code = prctl_map.start_code;
|
||||
mm->end_code = prctl_map.end_code;
|
||||
mm->start_data = prctl_map.start_data;
|
||||
mm->end_data = prctl_map.end_data;
|
||||
mm->start_brk = prctl_map.start_brk;
|
||||
mm->brk = prctl_map.brk;
|
||||
mm->start_stack = prctl_map.start_stack;
|
||||
mm->arg_start = prctl_map.arg_start;
|
||||
mm->arg_end = prctl_map.arg_end;
|
||||
mm->env_start = prctl_map.env_start;
|
||||
mm->env_end = prctl_map.env_end;
|
||||
|
||||
/*
|
||||
* Note this update of @saved_auxv is lockless thus
|
||||
* if someone reads this member in procfs while we're
|
||||
* updating -- it may get partly updated results. It's
|
||||
* known and acceptable trade off: we leave it as is to
|
||||
* not introduce additional locks here making the kernel
|
||||
* more complex.
|
||||
*/
|
||||
if (prctl_map.auxv_size)
|
||||
memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv));
|
||||
|
||||
error = 0;
|
||||
out:
|
||||
up_read(&mm->mmap_sem);
|
||||
return error;
|
||||
}
|
||||
#endif /* CONFIG_CHECKPOINT_RESTORE */
|
||||
|
||||
static int prctl_set_mm(int opt, unsigned long addr,
|
||||
unsigned long arg4, unsigned long arg5)
|
||||
{
|
||||
unsigned long rlim = rlimit(RLIMIT_DATA);
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
int error;
|
||||
|
||||
if (arg5 || (arg4 && opt != PR_SET_MM_AUXV))
|
||||
if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV &&
|
||||
opt != PR_SET_MM_MAP &&
|
||||
opt != PR_SET_MM_MAP_SIZE)))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_CHECKPOINT_RESTORE
|
||||
if (opt == PR_SET_MM_MAP || opt == PR_SET_MM_MAP_SIZE)
|
||||
return prctl_set_mm_map(opt, (const void __user *)addr, arg4);
|
||||
#endif
|
||||
|
||||
if (!capable(CAP_SYS_RESOURCE))
|
||||
return -EPERM;
|
||||
|
||||
if (opt == PR_SET_MM_EXE_FILE)
|
||||
return prctl_set_mm_exe_file(mm, (unsigned int)addr);
|
||||
if (opt == PR_SET_MM_EXE_FILE) {
|
||||
down_write(&mm->mmap_sem);
|
||||
error = prctl_set_mm_exe_file_locked(mm, (unsigned int)addr);
|
||||
up_write(&mm->mmap_sem);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (addr >= TASK_SIZE || addr < mmap_min_addr)
|
||||
return -EINVAL;
|
||||
@@ -1733,9 +1929,8 @@ static int prctl_set_mm(int opt, unsigned long addr,
|
||||
if (addr <= mm->end_data)
|
||||
goto out;
|
||||
|
||||
if (rlim < RLIM_INFINITY &&
|
||||
(mm->brk - addr) +
|
||||
(mm->end_data - mm->start_data) > rlim)
|
||||
if (check_data_rlimit(rlimit(RLIMIT_DATA), mm->brk, addr,
|
||||
mm->end_data, mm->start_data))
|
||||
goto out;
|
||||
|
||||
mm->start_brk = addr;
|
||||
@@ -1745,9 +1940,8 @@ static int prctl_set_mm(int opt, unsigned long addr,
|
||||
if (addr <= mm->end_data)
|
||||
goto out;
|
||||
|
||||
if (rlim < RLIM_INFINITY &&
|
||||
(addr - mm->start_brk) +
|
||||
(mm->end_data - mm->start_data) > rlim)
|
||||
if (check_data_rlimit(rlimit(RLIMIT_DATA), addr, mm->start_brk,
|
||||
mm->end_data, mm->start_data))
|
||||
goto out;
|
||||
|
||||
mm->brk = addr;
|
||||
@@ -2023,6 +2217,7 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
|
||||
{
|
||||
int err = 0;
|
||||
int cpu = raw_smp_processor_id();
|
||||
|
||||
if (cpup)
|
||||
err |= put_user(cpu, cpup);
|
||||
if (nodep)
|
||||
@@ -2135,7 +2330,7 @@ COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info)
|
||||
/* Check to see if any memory value is too large for 32-bit and scale
|
||||
* down if needed
|
||||
*/
|
||||
if ((s.totalram >> 32) || (s.totalswap >> 32)) {
|
||||
if (upper_32_bits(s.totalram) || upper_32_bits(s.totalswap)) {
|
||||
int bitcount = 0;
|
||||
|
||||
while (s.mem_unit < PAGE_SIZE) {
|
||||
|
||||
@@ -1460,13 +1460,6 @@ static struct ctl_table vm_table[] = {
|
||||
.extra2 = &one,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.procname = "scan_unevictable_pages",
|
||||
.data = &scan_unevictable_pages,
|
||||
.maxlen = sizeof(scan_unevictable_pages),
|
||||
.mode = 0644,
|
||||
.proc_handler = scan_unevictable_handler,
|
||||
},
|
||||
#ifdef CONFIG_MEMORY_FAILURE
|
||||
{
|
||||
.procname = "memory_failure_early_kill",
|
||||
|
||||
+17
-1
@@ -47,6 +47,7 @@ static DEFINE_PER_CPU(bool, softlockup_touch_sync);
|
||||
static DEFINE_PER_CPU(bool, soft_watchdog_warn);
|
||||
static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
|
||||
static DEFINE_PER_CPU(unsigned long, soft_lockup_hrtimer_cnt);
|
||||
static DEFINE_PER_CPU(struct task_struct *, softlockup_task_ptr_saved);
|
||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
|
||||
static DEFINE_PER_CPU(bool, hard_watchdog_warn);
|
||||
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
|
||||
@@ -333,8 +334,22 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
|
||||
return HRTIMER_RESTART;
|
||||
|
||||
/* only warn once */
|
||||
if (__this_cpu_read(soft_watchdog_warn) == true)
|
||||
if (__this_cpu_read(soft_watchdog_warn) == true) {
|
||||
/*
|
||||
* When multiple processes are causing softlockups the
|
||||
* softlockup detector only warns on the first one
|
||||
* because the code relies on a full quiet cycle to
|
||||
* re-arm. The second process prevents the quiet cycle
|
||||
* and never gets reported. Use task pointers to detect
|
||||
* this.
|
||||
*/
|
||||
if (__this_cpu_read(softlockup_task_ptr_saved) !=
|
||||
current) {
|
||||
__this_cpu_write(soft_watchdog_warn, false);
|
||||
__touch_watchdog();
|
||||
}
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
if (softlockup_all_cpu_backtrace) {
|
||||
/* Prevent multiple soft-lockup reports if one cpu is already
|
||||
@@ -350,6 +365,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
|
||||
pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
|
||||
smp_processor_id(), duration,
|
||||
current->comm, task_pid_nr(current));
|
||||
__this_cpu_write(softlockup_task_ptr_saved, current);
|
||||
print_modules();
|
||||
print_irqtrace_events(current);
|
||||
if (regs)
|
||||
|
||||
Reference in New Issue
Block a user