Merge branch 'linus' into timers/core
Reason: Get upstream fixes before adding conflicting code. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
commit
6402c7dc2a
1262 changed files with 13884 additions and 7820 deletions
|
|
@ -392,6 +392,30 @@ bool ns_capable(struct user_namespace *ns, int cap)
|
|||
}
|
||||
EXPORT_SYMBOL(ns_capable);
|
||||
|
||||
/**
|
||||
* file_ns_capable - Determine if the file's opener had a capability in effect
|
||||
* @file: The file we want to check
|
||||
* @ns: The usernamespace we want the capability in
|
||||
* @cap: The capability to be tested for
|
||||
*
|
||||
* Return true if task that opened the file had a capability in effect
|
||||
* when the file was opened.
|
||||
*
|
||||
* This does not set PF_SUPERPRIV because the caller may not
|
||||
* actually be privileged.
|
||||
*/
|
||||
bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap)
|
||||
{
|
||||
if (WARN_ON_ONCE(!cap_valid(cap)))
|
||||
return false;
|
||||
|
||||
if (security_capable(file->f_cred, ns, cap) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(file_ns_capable);
|
||||
|
||||
/**
|
||||
* capable - Determine if the current task has a superior capability in effect
|
||||
* @cap: The capability to be tested for
|
||||
|
|
|
|||
|
|
@ -4434,12 +4434,15 @@ static void perf_event_task_event(struct perf_task_event *task_event)
|
|||
if (ctxn < 0)
|
||||
goto next;
|
||||
ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
|
||||
if (ctx)
|
||||
perf_event_task_ctx(ctx, task_event);
|
||||
}
|
||||
if (ctx)
|
||||
perf_event_task_ctx(ctx, task_event);
|
||||
next:
|
||||
put_cpu_ptr(pmu->pmu_cpu_context);
|
||||
}
|
||||
if (task_event->task_ctx)
|
||||
perf_event_task_ctx(task_event->task_ctx, task_event);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
@ -4734,7 +4737,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
|
|||
} else {
|
||||
if (arch_vma_name(mmap_event->vma)) {
|
||||
name = strncpy(tmp, arch_vma_name(mmap_event->vma),
|
||||
sizeof(tmp));
|
||||
sizeof(tmp) - 1);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
goto got_name;
|
||||
}
|
||||
|
||||
|
|
@ -5327,7 +5331,7 @@ static void sw_perf_event_destroy(struct perf_event *event)
|
|||
|
||||
static int perf_swevent_init(struct perf_event *event)
|
||||
{
|
||||
int event_id = event->attr.config;
|
||||
u64 event_id = event->attr.config;
|
||||
|
||||
if (event->attr.type != PERF_TYPE_SOFTWARE)
|
||||
return -ENOENT;
|
||||
|
|
@ -5647,6 +5651,7 @@ static void perf_swevent_init_hrtimer(struct perf_event *event)
|
|||
event->attr.sample_period = NSEC_PER_SEC / freq;
|
||||
hwc->sample_period = event->attr.sample_period;
|
||||
local64_set(&hwc->period_left, hwc->sample_period);
|
||||
hwc->last_period = hwc->sample_period;
|
||||
event->attr.freq = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -5982,6 +5987,7 @@ skip_type:
|
|||
if (pmu->pmu_cpu_context)
|
||||
goto got_cpu_context;
|
||||
|
||||
ret = -ENOMEM;
|
||||
pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
|
||||
if (!pmu->pmu_cpu_context)
|
||||
goto free_dev;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct ring_buffer {
|
|||
int page_order; /* allocation order */
|
||||
#endif
|
||||
int nr_pages; /* nr of data pages */
|
||||
int writable; /* are we writable */
|
||||
int overwrite; /* can overwrite itself */
|
||||
|
||||
atomic_t poll; /* POLL_ for wakeups */
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,24 @@
|
|||
static bool perf_output_space(struct ring_buffer *rb, unsigned long tail,
|
||||
unsigned long offset, unsigned long head)
|
||||
{
|
||||
unsigned long mask;
|
||||
unsigned long sz = perf_data_size(rb);
|
||||
unsigned long mask = sz - 1;
|
||||
|
||||
if (!rb->writable)
|
||||
/*
|
||||
* check if user-writable
|
||||
* overwrite : over-write its own tail
|
||||
* !overwrite: buffer possibly drops events.
|
||||
*/
|
||||
if (rb->overwrite)
|
||||
return true;
|
||||
|
||||
mask = perf_data_size(rb) - 1;
|
||||
/*
|
||||
* verify that payload is not bigger than buffer
|
||||
* otherwise masking logic may fail to detect
|
||||
* the "not enough space" condition
|
||||
*/
|
||||
if ((head - offset) > sz)
|
||||
return false;
|
||||
|
||||
offset = (offset - tail) & mask;
|
||||
head = (head - tail) & mask;
|
||||
|
|
@ -212,7 +224,9 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
|
|||
rb->watermark = max_size / 2;
|
||||
|
||||
if (flags & RING_BUFFER_WRITABLE)
|
||||
rb->writable = 1;
|
||||
rb->overwrite = 0;
|
||||
else
|
||||
rb->overwrite = 1;
|
||||
|
||||
atomic_set(&rb->refcount, 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -835,7 +835,7 @@ void do_exit(long code)
|
|||
/*
|
||||
* Make sure we are holding no locks:
|
||||
*/
|
||||
debug_check_no_locks_held();
|
||||
debug_check_no_locks_held(tsk);
|
||||
/*
|
||||
* We can do this unlocked here. The futex code uses this flag
|
||||
* just to verify whether the pi state cleanup has been done
|
||||
|
|
|
|||
|
|
@ -1141,6 +1141,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|||
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/*
|
||||
* Thread groups must share signals as well, and detached threads
|
||||
* can only be started up within the thread group.
|
||||
|
|
@ -1807,7 +1810,7 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
|
|||
* If unsharing a user namespace must also unshare the thread.
|
||||
*/
|
||||
if (unshare_flags & CLONE_NEWUSER)
|
||||
unshare_flags |= CLONE_THREAD;
|
||||
unshare_flags |= CLONE_THREAD | CLONE_FS;
|
||||
/*
|
||||
* If unsharing a pid namespace must also unshare the thread.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -223,7 +223,8 @@ static void drop_futex_key_refs(union futex_key *key)
|
|||
* @rw: mapping needs to be read/write (values: VERIFY_READ,
|
||||
* VERIFY_WRITE)
|
||||
*
|
||||
* Returns a negative error code or 0
|
||||
* Return: a negative error code or 0
|
||||
*
|
||||
* The key words are stored in *key on success.
|
||||
*
|
||||
* For shared mappings, it's (page->index, file_inode(vma->vm_file),
|
||||
|
|
@ -705,9 +706,9 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
|
|||
* be "current" except in the case of requeue pi.
|
||||
* @set_waiters: force setting the FUTEX_WAITERS bit (1) or not (0)
|
||||
*
|
||||
* Returns:
|
||||
* 0 - ready to wait
|
||||
* 1 - acquired the lock
|
||||
* Return:
|
||||
* 0 - ready to wait;
|
||||
* 1 - acquired the lock;
|
||||
* <0 - error
|
||||
*
|
||||
* The hb->lock and futex_key refs shall be held by the caller.
|
||||
|
|
@ -1191,9 +1192,9 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
|
|||
* then direct futex_lock_pi_atomic() to force setting the FUTEX_WAITERS bit.
|
||||
* hb1 and hb2 must be held by the caller.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - failed to acquire the lock atomicly
|
||||
* 1 - acquired the lock
|
||||
* Return:
|
||||
* 0 - failed to acquire the lock atomically;
|
||||
* 1 - acquired the lock;
|
||||
* <0 - error
|
||||
*/
|
||||
static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
||||
|
|
@ -1254,8 +1255,8 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
|||
* Requeue waiters on uaddr1 to uaddr2. In the requeue_pi case, try to acquire
|
||||
* uaddr2 atomically on behalf of the top waiter.
|
||||
*
|
||||
* Returns:
|
||||
* >=0 - on success, the number of tasks requeued or woken
|
||||
* Return:
|
||||
* >=0 - on success, the number of tasks requeued or woken;
|
||||
* <0 - on error
|
||||
*/
|
||||
static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
||||
|
|
@ -1536,8 +1537,8 @@ static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
|
|||
* The q->lock_ptr must not be held by the caller. A call to unqueue_me() must
|
||||
* be paired with exactly one earlier call to queue_me().
|
||||
*
|
||||
* Returns:
|
||||
* 1 - if the futex_q was still queued (and we removed unqueued it)
|
||||
* Return:
|
||||
* 1 - if the futex_q was still queued (and we removed unqueued it);
|
||||
* 0 - if the futex_q was already removed by the waking thread
|
||||
*/
|
||||
static int unqueue_me(struct futex_q *q)
|
||||
|
|
@ -1707,9 +1708,9 @@ static long futex_wait_restart(struct restart_block *restart);
|
|||
* the pi_state owner as well as handle race conditions that may allow us to
|
||||
* acquire the lock. Must be called with the hb lock held.
|
||||
*
|
||||
* Returns:
|
||||
* 1 - success, lock taken
|
||||
* 0 - success, lock not taken
|
||||
* Return:
|
||||
* 1 - success, lock taken;
|
||||
* 0 - success, lock not taken;
|
||||
* <0 - on error (-EFAULT)
|
||||
*/
|
||||
static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||
|
|
@ -1824,8 +1825,8 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
|
|||
* Return with the hb lock held and a q.key reference on success, and unlocked
|
||||
* with no q.key reference on failure.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - uaddr contains val and hb has been locked
|
||||
* Return:
|
||||
* 0 - uaddr contains val and hb has been locked;
|
||||
* <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlocked
|
||||
*/
|
||||
static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
|
||||
|
|
@ -2203,9 +2204,9 @@ pi_faulted:
|
|||
* the wakeup and return the appropriate error code to the caller. Must be
|
||||
* called with the hb lock held.
|
||||
*
|
||||
* Returns
|
||||
* 0 - no early wakeup detected
|
||||
* <0 - -ETIMEDOUT or -ERESTARTNOINTR
|
||||
* Return:
|
||||
* 0 = no early wakeup detected;
|
||||
* <0 = -ETIMEDOUT or -ERESTARTNOINTR
|
||||
*/
|
||||
static inline
|
||||
int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
||||
|
|
@ -2247,7 +2248,6 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
|||
* @val: the expected value of uaddr
|
||||
* @abs_time: absolute timeout
|
||||
* @bitset: 32 bit wakeup bitset set by userspace, defaults to all
|
||||
* @clockrt: whether to use CLOCK_REALTIME (1) or CLOCK_MONOTONIC (0)
|
||||
* @uaddr2: the pi futex we will take prior to returning to user-space
|
||||
*
|
||||
* The caller will wait on uaddr and will be requeued by futex_requeue() to
|
||||
|
|
@ -2258,7 +2258,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
|||
* there was a need to.
|
||||
*
|
||||
* We call schedule in futex_wait_queue_me() when we enqueue and return there
|
||||
* via the following:
|
||||
* via the following--
|
||||
* 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
|
||||
* 2) wakeup on uaddr2 after a requeue
|
||||
* 3) signal
|
||||
|
|
@ -2276,8 +2276,8 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
|||
*
|
||||
* If 4 or 7, we cleanup and return with -ETIMEDOUT.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - On success
|
||||
* Return:
|
||||
* 0 - On success;
|
||||
* <0 - On error
|
||||
*/
|
||||
static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
|
||||
{
|
||||
|
||||
.lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
|
||||
.clock_base =
|
||||
{
|
||||
{
|
||||
|
|
@ -1662,8 +1663,6 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
|
|||
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
|
||||
int i;
|
||||
|
||||
raw_spin_lock_init(&cpu_base->lock);
|
||||
|
||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
||||
cpu_base->clock_base[i].cpu_base = cpu_base;
|
||||
timerqueue_init_head(&cpu_base->clock_base[i].active);
|
||||
|
|
|
|||
118
kernel/kexec.c
118
kernel/kexec.c
|
|
@ -55,7 +55,7 @@ struct resource crashk_res = {
|
|||
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
|
||||
};
|
||||
struct resource crashk_low_res = {
|
||||
.name = "Crash kernel low",
|
||||
.name = "Crash kernel",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
|
||||
|
|
@ -1368,35 +1368,114 @@ static int __init parse_crashkernel_simple(char *cmdline,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define SUFFIX_HIGH 0
|
||||
#define SUFFIX_LOW 1
|
||||
#define SUFFIX_NULL 2
|
||||
static __initdata char *suffix_tbl[] = {
|
||||
[SUFFIX_HIGH] = ",high",
|
||||
[SUFFIX_LOW] = ",low",
|
||||
[SUFFIX_NULL] = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* That function is the entry point for command line parsing and should be
|
||||
* called from the arch-specific code.
|
||||
* That function parses "suffix" crashkernel command lines like
|
||||
*
|
||||
* crashkernel=size,[high|low]
|
||||
*
|
||||
* It returns 0 on success and -EINVAL on failure.
|
||||
*/
|
||||
static int __init parse_crashkernel_suffix(char *cmdline,
|
||||
unsigned long long *crash_size,
|
||||
unsigned long long *crash_base,
|
||||
const char *suffix)
|
||||
{
|
||||
char *cur = cmdline;
|
||||
|
||||
*crash_size = memparse(cmdline, &cur);
|
||||
if (cmdline == cur) {
|
||||
pr_warn("crashkernel: memory value expected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check with suffix */
|
||||
if (strncmp(cur, suffix, strlen(suffix))) {
|
||||
pr_warn("crashkernel: unrecognized char\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
cur += strlen(suffix);
|
||||
if (*cur != ' ' && *cur != '\0') {
|
||||
pr_warn("crashkernel: unrecognized char\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init char *get_last_crashkernel(char *cmdline,
|
||||
const char *name,
|
||||
const char *suffix)
|
||||
{
|
||||
char *p = cmdline, *ck_cmdline = NULL;
|
||||
|
||||
/* find crashkernel and use the last one if there are more */
|
||||
p = strstr(p, name);
|
||||
while (p) {
|
||||
char *end_p = strchr(p, ' ');
|
||||
char *q;
|
||||
|
||||
if (!end_p)
|
||||
end_p = p + strlen(p);
|
||||
|
||||
if (!suffix) {
|
||||
int i;
|
||||
|
||||
/* skip the one with any known suffix */
|
||||
for (i = 0; suffix_tbl[i]; i++) {
|
||||
q = end_p - strlen(suffix_tbl[i]);
|
||||
if (!strncmp(q, suffix_tbl[i],
|
||||
strlen(suffix_tbl[i])))
|
||||
goto next;
|
||||
}
|
||||
ck_cmdline = p;
|
||||
} else {
|
||||
q = end_p - strlen(suffix);
|
||||
if (!strncmp(q, suffix, strlen(suffix)))
|
||||
ck_cmdline = p;
|
||||
}
|
||||
next:
|
||||
p = strstr(p+1, name);
|
||||
}
|
||||
|
||||
if (!ck_cmdline)
|
||||
return NULL;
|
||||
|
||||
return ck_cmdline;
|
||||
}
|
||||
|
||||
static int __init __parse_crashkernel(char *cmdline,
|
||||
unsigned long long system_ram,
|
||||
unsigned long long *crash_size,
|
||||
unsigned long long *crash_base,
|
||||
const char *name)
|
||||
const char *name,
|
||||
const char *suffix)
|
||||
{
|
||||
char *p = cmdline, *ck_cmdline = NULL;
|
||||
char *first_colon, *first_space;
|
||||
char *ck_cmdline;
|
||||
|
||||
BUG_ON(!crash_size || !crash_base);
|
||||
*crash_size = 0;
|
||||
*crash_base = 0;
|
||||
|
||||
/* find crashkernel and use the last one if there are more */
|
||||
p = strstr(p, name);
|
||||
while (p) {
|
||||
ck_cmdline = p;
|
||||
p = strstr(p+1, name);
|
||||
}
|
||||
ck_cmdline = get_last_crashkernel(cmdline, name, suffix);
|
||||
|
||||
if (!ck_cmdline)
|
||||
return -EINVAL;
|
||||
|
||||
ck_cmdline += strlen(name);
|
||||
|
||||
if (suffix)
|
||||
return parse_crashkernel_suffix(ck_cmdline, crash_size,
|
||||
crash_base, suffix);
|
||||
/*
|
||||
* if the commandline contains a ':', then that's the extended
|
||||
* syntax -- if not, it must be the classic syntax
|
||||
|
|
@ -1413,13 +1492,26 @@ static int __init __parse_crashkernel(char *cmdline,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* That function is the entry point for command line parsing and should be
|
||||
* called from the arch-specific code.
|
||||
*/
|
||||
int __init parse_crashkernel(char *cmdline,
|
||||
unsigned long long system_ram,
|
||||
unsigned long long *crash_size,
|
||||
unsigned long long *crash_base)
|
||||
{
|
||||
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
|
||||
"crashkernel=");
|
||||
"crashkernel=", NULL);
|
||||
}
|
||||
|
||||
int __init parse_crashkernel_high(char *cmdline,
|
||||
unsigned long long system_ram,
|
||||
unsigned long long *crash_size,
|
||||
unsigned long long *crash_base)
|
||||
{
|
||||
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
|
||||
"crashkernel=", suffix_tbl[SUFFIX_HIGH]);
|
||||
}
|
||||
|
||||
int __init parse_crashkernel_low(char *cmdline,
|
||||
|
|
@ -1428,7 +1520,7 @@ int __init parse_crashkernel_low(char *cmdline,
|
|||
unsigned long long *crash_base)
|
||||
{
|
||||
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
|
||||
"crashkernel_low=");
|
||||
"crashkernel=", suffix_tbl[SUFFIX_LOW]);
|
||||
}
|
||||
|
||||
static void update_vmcoreinfo_note(void)
|
||||
|
|
|
|||
|
|
@ -794,16 +794,16 @@ out:
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
/* This should be called with kprobe_mutex locked */
|
||||
static void __kprobes optimize_all_kprobes(void)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
struct kprobe *p;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&kprobe_mutex);
|
||||
/* If optimization is already allowed, just return */
|
||||
if (kprobes_allow_optimization)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
kprobes_allow_optimization = true;
|
||||
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
|
||||
|
|
@ -813,18 +813,22 @@ static void __kprobes optimize_all_kprobes(void)
|
|||
optimize_kprobe(p);
|
||||
}
|
||||
printk(KERN_INFO "Kprobes globally optimized\n");
|
||||
out:
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
}
|
||||
|
||||
/* This should be called with kprobe_mutex locked */
|
||||
static void __kprobes unoptimize_all_kprobes(void)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
struct kprobe *p;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&kprobe_mutex);
|
||||
/* If optimization is already prohibited, just return */
|
||||
if (!kprobes_allow_optimization)
|
||||
if (!kprobes_allow_optimization) {
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
kprobes_allow_optimization = false;
|
||||
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
|
||||
|
|
@ -834,11 +838,14 @@ static void __kprobes unoptimize_all_kprobes(void)
|
|||
unoptimize_kprobe(p, false);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
|
||||
/* Wait for unoptimizing completion */
|
||||
wait_for_kprobe_optimizer();
|
||||
printk(KERN_INFO "Kprobes globally unoptimized\n");
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(kprobe_sysctl_mutex);
|
||||
int sysctl_kprobes_optimization;
|
||||
int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *length,
|
||||
|
|
@ -846,7 +853,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
|
|||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&kprobe_mutex);
|
||||
mutex_lock(&kprobe_sysctl_mutex);
|
||||
sysctl_kprobes_optimization = kprobes_allow_optimization ? 1 : 0;
|
||||
ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
|
||||
|
||||
|
|
@ -854,7 +861,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
|
|||
optimize_all_kprobes();
|
||||
else
|
||||
unoptimize_all_kprobes();
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
mutex_unlock(&kprobe_sysctl_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,12 +124,12 @@ void *kthread_data(struct task_struct *task)
|
|||
|
||||
static void __kthread_parkme(struct kthread *self)
|
||||
{
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
__set_current_state(TASK_PARKED);
|
||||
while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
|
||||
if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
|
||||
complete(&self->parked);
|
||||
schedule();
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
__set_current_state(TASK_PARKED);
|
||||
}
|
||||
clear_bit(KTHREAD_IS_PARKED, &self->flags);
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
|
@ -256,8 +256,13 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
|
|||
}
|
||||
EXPORT_SYMBOL(kthread_create_on_node);
|
||||
|
||||
static void __kthread_bind(struct task_struct *p, unsigned int cpu)
|
||||
static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state)
|
||||
{
|
||||
/* Must have done schedule() in kthread() before we set_task_cpu */
|
||||
if (!wait_task_inactive(p, state)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
/* It's safe because the task is inactive. */
|
||||
do_set_cpus_allowed(p, cpumask_of(cpu));
|
||||
p->flags |= PF_THREAD_BOUND;
|
||||
|
|
@ -274,12 +279,7 @@ static void __kthread_bind(struct task_struct *p, unsigned int cpu)
|
|||
*/
|
||||
void kthread_bind(struct task_struct *p, unsigned int cpu)
|
||||
{
|
||||
/* Must have done schedule() in kthread() before we set_task_cpu */
|
||||
if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
__kthread_bind(p, cpu);
|
||||
__kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
EXPORT_SYMBOL(kthread_bind);
|
||||
|
||||
|
|
@ -324,6 +324,22 @@ static struct kthread *task_get_live_kthread(struct task_struct *k)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)
|
||||
{
|
||||
clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
|
||||
/*
|
||||
* We clear the IS_PARKED bit here as we don't wait
|
||||
* until the task has left the park code. So if we'd
|
||||
* park before that happens we'd see the IS_PARKED bit
|
||||
* which might be about to be cleared.
|
||||
*/
|
||||
if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
|
||||
if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
|
||||
__kthread_bind(k, kthread->cpu, TASK_PARKED);
|
||||
wake_up_state(k, TASK_PARKED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kthread_unpark - unpark a thread created by kthread_create().
|
||||
* @k: thread created by kthread_create().
|
||||
|
|
@ -336,20 +352,8 @@ void kthread_unpark(struct task_struct *k)
|
|||
{
|
||||
struct kthread *kthread = task_get_live_kthread(k);
|
||||
|
||||
if (kthread) {
|
||||
clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
|
||||
/*
|
||||
* We clear the IS_PARKED bit here as we don't wait
|
||||
* until the task has left the park code. So if we'd
|
||||
* park before that happens we'd see the IS_PARKED bit
|
||||
* which might be about to be cleared.
|
||||
*/
|
||||
if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
|
||||
if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
|
||||
__kthread_bind(k, kthread->cpu);
|
||||
wake_up_process(k);
|
||||
}
|
||||
}
|
||||
if (kthread)
|
||||
__kthread_unpark(k, kthread);
|
||||
put_task_struct(k);
|
||||
}
|
||||
|
||||
|
|
@ -407,7 +411,7 @@ int kthread_stop(struct task_struct *k)
|
|||
trace_sched_kthread_stop(k);
|
||||
if (kthread) {
|
||||
set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
|
||||
clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
|
||||
__kthread_unpark(k, kthread);
|
||||
wake_up_process(k);
|
||||
wait_for_completion(&kthread->exited);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4088,7 +4088,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
|
||||
|
||||
static void print_held_locks_bug(void)
|
||||
static void print_held_locks_bug(struct task_struct *curr)
|
||||
{
|
||||
if (!debug_locks_off())
|
||||
return;
|
||||
|
|
@ -4097,21 +4097,22 @@ static void print_held_locks_bug(void)
|
|||
|
||||
printk("\n");
|
||||
printk("=====================================\n");
|
||||
printk("[ BUG: %s/%d still has locks held! ]\n",
|
||||
current->comm, task_pid_nr(current));
|
||||
printk("[ BUG: lock held at task exit time! ]\n");
|
||||
print_kernel_ident();
|
||||
printk("-------------------------------------\n");
|
||||
lockdep_print_held_locks(current);
|
||||
printk("%s/%d is exiting with locks still held!\n",
|
||||
curr->comm, task_pid_nr(curr));
|
||||
lockdep_print_held_locks(curr);
|
||||
|
||||
printk("\nstack backtrace:\n");
|
||||
dump_stack();
|
||||
}
|
||||
|
||||
void debug_check_no_locks_held(void)
|
||||
void debug_check_no_locks_held(struct task_struct *task)
|
||||
{
|
||||
if (unlikely(current->lockdep_depth > 0))
|
||||
print_held_locks_bug();
|
||||
if (unlikely(task->lockdep_depth > 0))
|
||||
print_held_locks_bug(task);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debug_check_no_locks_held);
|
||||
|
||||
void debug_show_all_locks(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
|
|||
int nr;
|
||||
int rc;
|
||||
struct task_struct *task, *me = current;
|
||||
int init_pids = thread_group_leader(me) ? 1 : 2;
|
||||
|
||||
/* Don't allow any more processes into the pid namespace */
|
||||
disable_pid_allocation(pid_ns);
|
||||
|
|
@ -230,7 +231,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
|
|||
*/
|
||||
for (;;) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
if (pid_ns->nr_hashed == 1)
|
||||
if (pid_ns->nr_hashed == init_pids)
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
|
|||
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
|
||||
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
|
||||
|
||||
DECLARE_WAIT_QUEUE_HEAD(log_wait);
|
||||
|
||||
int console_printk[4] = {
|
||||
DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
|
||||
DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
|
||||
|
|
@ -224,6 +222,7 @@ struct log {
|
|||
static DEFINE_RAW_SPINLOCK(logbuf_lock);
|
||||
|
||||
#ifdef CONFIG_PRINTK
|
||||
DECLARE_WAIT_QUEUE_HEAD(log_wait);
|
||||
/* the next printk record to read by syslog(READ) or /proc/kmsg */
|
||||
static u64 syslog_seq;
|
||||
static u32 syslog_idx;
|
||||
|
|
@ -1957,45 +1956,6 @@ int is_console_locked(void)
|
|||
return console_locked;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delayed printk version, for scheduler-internal messages:
|
||||
*/
|
||||
#define PRINTK_BUF_SIZE 512
|
||||
|
||||
#define PRINTK_PENDING_WAKEUP 0x01
|
||||
#define PRINTK_PENDING_SCHED 0x02
|
||||
|
||||
static DEFINE_PER_CPU(int, printk_pending);
|
||||
static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
|
||||
|
||||
static void wake_up_klogd_work_func(struct irq_work *irq_work)
|
||||
{
|
||||
int pending = __this_cpu_xchg(printk_pending, 0);
|
||||
|
||||
if (pending & PRINTK_PENDING_SCHED) {
|
||||
char *buf = __get_cpu_var(printk_sched_buf);
|
||||
printk(KERN_WARNING "[sched_delayed] %s", buf);
|
||||
}
|
||||
|
||||
if (pending & PRINTK_PENDING_WAKEUP)
|
||||
wake_up_interruptible(&log_wait);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
|
||||
.func = wake_up_klogd_work_func,
|
||||
.flags = IRQ_WORK_LAZY,
|
||||
};
|
||||
|
||||
void wake_up_klogd(void)
|
||||
{
|
||||
preempt_disable();
|
||||
if (waitqueue_active(&log_wait)) {
|
||||
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
|
||||
irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
|
||||
}
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static void console_cont_flush(char *text, size_t size)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
@ -2458,6 +2418,44 @@ static int __init printk_late_init(void)
|
|||
late_initcall(printk_late_init);
|
||||
|
||||
#if defined CONFIG_PRINTK
|
||||
/*
|
||||
* Delayed printk version, for scheduler-internal messages:
|
||||
*/
|
||||
#define PRINTK_BUF_SIZE 512
|
||||
|
||||
#define PRINTK_PENDING_WAKEUP 0x01
|
||||
#define PRINTK_PENDING_SCHED 0x02
|
||||
|
||||
static DEFINE_PER_CPU(int, printk_pending);
|
||||
static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
|
||||
|
||||
static void wake_up_klogd_work_func(struct irq_work *irq_work)
|
||||
{
|
||||
int pending = __this_cpu_xchg(printk_pending, 0);
|
||||
|
||||
if (pending & PRINTK_PENDING_SCHED) {
|
||||
char *buf = __get_cpu_var(printk_sched_buf);
|
||||
printk(KERN_WARNING "[sched_delayed] %s", buf);
|
||||
}
|
||||
|
||||
if (pending & PRINTK_PENDING_WAKEUP)
|
||||
wake_up_interruptible(&log_wait);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
|
||||
.func = wake_up_klogd_work_func,
|
||||
.flags = IRQ_WORK_LAZY,
|
||||
};
|
||||
|
||||
void wake_up_klogd(void)
|
||||
{
|
||||
preempt_disable();
|
||||
if (waitqueue_active(&log_wait)) {
|
||||
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
|
||||
irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
|
||||
}
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
int printk_sched(const char *fmt, ...)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -176,10 +176,36 @@ static u64 sched_clock_remote(struct sched_clock_data *scd)
|
|||
u64 this_clock, remote_clock;
|
||||
u64 *ptr, old_val, val;
|
||||
|
||||
#if BITS_PER_LONG != 64
|
||||
again:
|
||||
/*
|
||||
* Careful here: The local and the remote clock values need to
|
||||
* be read out atomic as we need to compare the values and
|
||||
* then update either the local or the remote side. So the
|
||||
* cmpxchg64 below only protects one readout.
|
||||
*
|
||||
* We must reread via sched_clock_local() in the retry case on
|
||||
* 32bit as an NMI could use sched_clock_local() via the
|
||||
* tracer and hit between the readout of
|
||||
* the low32bit and the high 32bit portion.
|
||||
*/
|
||||
this_clock = sched_clock_local(my_scd);
|
||||
/*
|
||||
* We must enforce atomic readout on 32bit, otherwise the
|
||||
* update on the remote cpu can hit inbetween the readout of
|
||||
* the low32bit and the high 32bit portion.
|
||||
*/
|
||||
remote_clock = cmpxchg64(&scd->clock, 0, 0);
|
||||
#else
|
||||
/*
|
||||
* On 64bit the read of [my]scd->clock is atomic versus the
|
||||
* update, so we can avoid the above 32bit dance.
|
||||
*/
|
||||
sched_clock_local(my_scd);
|
||||
again:
|
||||
this_clock = my_scd->clock;
|
||||
remote_clock = scd->clock;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use the opportunity that we have both locks
|
||||
|
|
|
|||
|
|
@ -1498,8 +1498,10 @@ static void try_to_wake_up_local(struct task_struct *p)
|
|||
{
|
||||
struct rq *rq = task_rq(p);
|
||||
|
||||
BUG_ON(rq != this_rq());
|
||||
BUG_ON(p == current);
|
||||
if (WARN_ON_ONCE(rq != this_rq()) ||
|
||||
WARN_ON_ONCE(p == current))
|
||||
return;
|
||||
|
||||
lockdep_assert_held(&rq->lock);
|
||||
|
||||
if (!raw_spin_trylock(&p->pi_lock)) {
|
||||
|
|
@ -4999,7 +5001,7 @@ static void sd_free_ctl_entry(struct ctl_table **tablep)
|
|||
}
|
||||
|
||||
static int min_load_idx = 0;
|
||||
static int max_load_idx = CPU_LOAD_IDX_MAX;
|
||||
static int max_load_idx = CPU_LOAD_IDX_MAX-1;
|
||||
|
||||
static void
|
||||
set_table_entry(struct ctl_table *entry,
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
|
|||
|
||||
t = tsk;
|
||||
do {
|
||||
task_cputime(tsk, &utime, &stime);
|
||||
task_cputime(t, &utime, &stime);
|
||||
times->utime += utime;
|
||||
times->stime += stime;
|
||||
times->sum_exec_runtime += task_sched_runtime(t);
|
||||
|
|
|
|||
|
|
@ -485,6 +485,9 @@ flush_signal_handlers(struct task_struct *t, int force_default)
|
|||
if (force_default || ka->sa.sa_handler != SIG_IGN)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
ka->sa.sa_flags = 0;
|
||||
#ifdef __ARCH_HAS_SA_RESTORER
|
||||
ka->sa.sa_restorer = NULL;
|
||||
#endif
|
||||
sigemptyset(&ka->sa.sa_mask);
|
||||
ka++;
|
||||
}
|
||||
|
|
@ -2682,7 +2685,7 @@ static int do_sigpending(void *set, unsigned long sigsetsize)
|
|||
/**
|
||||
* sys_rt_sigpending - examine a pending signal that has been raised
|
||||
* while blocked
|
||||
* @set: stores pending signals
|
||||
* @uset: stores pending signals
|
||||
* @sigsetsize: size of sigset_t type or larger
|
||||
*/
|
||||
SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize)
|
||||
|
|
@ -2945,7 +2948,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
|
|||
|
||||
static int do_tkill(pid_t tgid, pid_t pid, int sig)
|
||||
{
|
||||
struct siginfo info;
|
||||
struct siginfo info = {};
|
||||
|
||||
info.si_signo = sig;
|
||||
info.si_errno = 0;
|
||||
|
|
|
|||
|
|
@ -185,8 +185,18 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
|
|||
}
|
||||
get_task_struct(tsk);
|
||||
*per_cpu_ptr(ht->store, cpu) = tsk;
|
||||
if (ht->create)
|
||||
ht->create(cpu);
|
||||
if (ht->create) {
|
||||
/*
|
||||
* Make sure that the task has actually scheduled out
|
||||
* into park position, before calling the create
|
||||
* callback. At least the migration thread callback
|
||||
* requires that the task is off the runqueue.
|
||||
*/
|
||||
if (!wait_task_inactive(tsk, TASK_PARKED))
|
||||
WARN_ON(1);
|
||||
else
|
||||
ht->create(cpu);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
62
kernel/sys.c
62
kernel/sys.c
|
|
@ -324,7 +324,6 @@ void kernel_restart_prepare(char *cmd)
|
|||
system_state = SYSTEM_RESTART;
|
||||
usermodehelper_disable();
|
||||
device_shutdown();
|
||||
syscore_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -370,6 +369,7 @@ void kernel_restart(char *cmd)
|
|||
{
|
||||
kernel_restart_prepare(cmd);
|
||||
disable_nonboot_cpus();
|
||||
syscore_shutdown();
|
||||
if (!cmd)
|
||||
printk(KERN_EMERG "Restarting system.\n");
|
||||
else
|
||||
|
|
@ -395,6 +395,7 @@ static void kernel_shutdown_prepare(enum system_states state)
|
|||
void kernel_halt(void)
|
||||
{
|
||||
kernel_shutdown_prepare(SYSTEM_HALT);
|
||||
disable_nonboot_cpus();
|
||||
syscore_shutdown();
|
||||
printk(KERN_EMERG "System halted.\n");
|
||||
kmsg_dump(KMSG_DUMP_HALT);
|
||||
|
|
@ -2185,9 +2186,8 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
|
|||
|
||||
char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
|
||||
|
||||
static int __orderly_poweroff(void)
|
||||
static int __orderly_poweroff(bool force)
|
||||
{
|
||||
int argc;
|
||||
char **argv;
|
||||
static char *envp[] = {
|
||||
"HOME=/",
|
||||
|
|
@ -2196,35 +2196,19 @@ static int __orderly_poweroff(void)
|
|||
};
|
||||
int ret;
|
||||
|
||||
argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
|
||||
if (argv == NULL) {
|
||||
argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL);
|
||||
if (argv) {
|
||||
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
||||
argv_free(argv);
|
||||
} else {
|
||||
printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
|
||||
__func__, poweroff_cmd);
|
||||
return -ENOMEM;
|
||||
__func__, poweroff_cmd);
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_WAIT_EXEC,
|
||||
NULL, NULL, NULL);
|
||||
argv_free(argv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* orderly_poweroff - Trigger an orderly system poweroff
|
||||
* @force: force poweroff if command execution fails
|
||||
*
|
||||
* This may be called from any context to trigger a system shutdown.
|
||||
* If the orderly shutdown fails, it will force an immediate shutdown.
|
||||
*/
|
||||
int orderly_poweroff(bool force)
|
||||
{
|
||||
int ret = __orderly_poweroff();
|
||||
|
||||
if (ret && force) {
|
||||
printk(KERN_WARNING "Failed to start orderly shutdown: "
|
||||
"forcing the issue\n");
|
||||
|
||||
"forcing the issue\n");
|
||||
/*
|
||||
* I guess this should try to kick off some daemon to sync and
|
||||
* poweroff asap. Or not even bother syncing if we're doing an
|
||||
|
|
@ -2236,4 +2220,28 @@ int orderly_poweroff(bool force)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool poweroff_force;
|
||||
|
||||
static void poweroff_work_func(struct work_struct *work)
|
||||
{
|
||||
__orderly_poweroff(poweroff_force);
|
||||
}
|
||||
|
||||
static DECLARE_WORK(poweroff_work, poweroff_work_func);
|
||||
|
||||
/**
|
||||
* orderly_poweroff - Trigger an orderly system poweroff
|
||||
* @force: force poweroff if command execution fails
|
||||
*
|
||||
* This may be called from any context to trigger a system shutdown.
|
||||
* If the orderly shutdown fails, it will force an immediate shutdown.
|
||||
*/
|
||||
int orderly_poweroff(bool force)
|
||||
{
|
||||
if (force) /* do not override the pending "true" */
|
||||
poweroff_force = true;
|
||||
schedule_work(&poweroff_work);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(orderly_poweroff);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)
|
|||
*/
|
||||
int tick_check_broadcast_device(struct clock_event_device *dev)
|
||||
{
|
||||
if ((tick_broadcast_device.evtdev &&
|
||||
if ((dev->features & CLOCK_EVT_FEAT_DUMMY) ||
|
||||
(tick_broadcast_device.evtdev &&
|
||||
tick_broadcast_device.evtdev->rating >= dev->rating) ||
|
||||
(dev->features & CLOCK_EVT_FEAT_C3STOP))
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -739,12 +739,6 @@ static void blk_add_trace_rq_complete(void *ignore,
|
|||
struct request_queue *q,
|
||||
struct request *rq)
|
||||
{
|
||||
struct blk_trace *bt = q->blk_trace;
|
||||
|
||||
/* if control ever passes through here, it's a request based driver */
|
||||
if (unlikely(bt && !bt->rq_based))
|
||||
bt->rq_based = true;
|
||||
|
||||
blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
|
||||
}
|
||||
|
||||
|
|
@ -780,24 +774,10 @@ static void blk_add_trace_bio_bounce(void *ignore,
|
|||
blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0);
|
||||
}
|
||||
|
||||
static void blk_add_trace_bio_complete(void *ignore, struct bio *bio, int error)
|
||||
static void blk_add_trace_bio_complete(void *ignore,
|
||||
struct request_queue *q, struct bio *bio,
|
||||
int error)
|
||||
{
|
||||
struct request_queue *q;
|
||||
struct blk_trace *bt;
|
||||
|
||||
if (!bio->bi_bdev)
|
||||
return;
|
||||
|
||||
q = bdev_get_queue(bio->bi_bdev);
|
||||
bt = q->blk_trace;
|
||||
|
||||
/*
|
||||
* Request based drivers will generate both rq and bio completions.
|
||||
* Ignore bio ones.
|
||||
*/
|
||||
if (likely(!bt) || bt->rq_based)
|
||||
return;
|
||||
|
||||
blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
static struct ftrace_ops ftrace_list_end __read_mostly = {
|
||||
.func = ftrace_stub,
|
||||
.flags = FTRACE_OPS_FL_RECURSION_SAFE,
|
||||
.flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB,
|
||||
};
|
||||
|
||||
/* ftrace_enabled is a method to turn ftrace on or off */
|
||||
|
|
@ -694,7 +694,6 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat)
|
|||
free_page(tmp);
|
||||
}
|
||||
|
||||
free_page((unsigned long)stat->pages);
|
||||
stat->pages = NULL;
|
||||
stat->start = NULL;
|
||||
|
||||
|
|
@ -1053,6 +1052,19 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
|
|||
|
||||
static struct pid * const ftrace_swapper_pid = &init_struct_pid;
|
||||
|
||||
loff_t
|
||||
ftrace_filter_lseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
loff_t ret;
|
||||
|
||||
if (file->f_mode & FMODE_READ)
|
||||
ret = seq_lseek(file, offset, whence);
|
||||
else
|
||||
file->f_pos = ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
#ifndef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
|
|
@ -2613,7 +2625,7 @@ static void ftrace_filter_reset(struct ftrace_hash *hash)
|
|||
* routine, you can use ftrace_filter_write() for the write
|
||||
* routine if @flag has FTRACE_ITER_FILTER set, or
|
||||
* ftrace_notrace_write() if @flag has FTRACE_ITER_NOTRACE set.
|
||||
* ftrace_regex_lseek() should be used as the lseek routine, and
|
||||
* ftrace_filter_lseek() should be used as the lseek routine, and
|
||||
* release must call ftrace_regex_release().
|
||||
*/
|
||||
int
|
||||
|
|
@ -2697,19 +2709,6 @@ ftrace_notrace_open(struct inode *inode, struct file *file)
|
|||
inode, file);
|
||||
}
|
||||
|
||||
loff_t
|
||||
ftrace_regex_lseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
loff_t ret;
|
||||
|
||||
if (file->f_mode & FMODE_READ)
|
||||
ret = seq_lseek(file, offset, whence);
|
||||
else
|
||||
file->f_pos = ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ftrace_match(char *str, char *regex, int len, int type)
|
||||
{
|
||||
int matched = 0;
|
||||
|
|
@ -3104,8 +3103,8 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
|||
continue;
|
||||
}
|
||||
|
||||
hlist_del(&entry->node);
|
||||
call_rcu(&entry->rcu, ftrace_free_entry_rcu);
|
||||
hlist_del_rcu(&entry->node);
|
||||
call_rcu_sched(&entry->rcu, ftrace_free_entry_rcu);
|
||||
}
|
||||
}
|
||||
__disable_ftrace_function_probe();
|
||||
|
|
@ -3441,14 +3440,14 @@ static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata;
|
|||
|
||||
static int __init set_ftrace_notrace(char *str)
|
||||
{
|
||||
strncpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE);
|
||||
strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE);
|
||||
return 1;
|
||||
}
|
||||
__setup("ftrace_notrace=", set_ftrace_notrace);
|
||||
|
||||
static int __init set_ftrace_filter(char *str)
|
||||
{
|
||||
strncpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE);
|
||||
strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE);
|
||||
return 1;
|
||||
}
|
||||
__setup("ftrace_filter=", set_ftrace_filter);
|
||||
|
|
@ -3571,7 +3570,7 @@ static const struct file_operations ftrace_filter_fops = {
|
|||
.open = ftrace_filter_open,
|
||||
.read = seq_read,
|
||||
.write = ftrace_filter_write,
|
||||
.llseek = ftrace_regex_lseek,
|
||||
.llseek = ftrace_filter_lseek,
|
||||
.release = ftrace_regex_release,
|
||||
};
|
||||
|
||||
|
|
@ -3579,7 +3578,7 @@ static const struct file_operations ftrace_notrace_fops = {
|
|||
.open = ftrace_notrace_open,
|
||||
.read = seq_read,
|
||||
.write = ftrace_notrace_write,
|
||||
.llseek = ftrace_regex_lseek,
|
||||
.llseek = ftrace_filter_lseek,
|
||||
.release = ftrace_regex_release,
|
||||
};
|
||||
|
||||
|
|
@ -3784,8 +3783,8 @@ static const struct file_operations ftrace_graph_fops = {
|
|||
.open = ftrace_graph_open,
|
||||
.read = seq_read,
|
||||
.write = ftrace_graph_write,
|
||||
.llseek = ftrace_filter_lseek,
|
||||
.release = ftrace_graph_release,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
||||
|
|
@ -4131,7 +4130,8 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
|
|||
preempt_disable_notrace();
|
||||
trace_recursion_set(TRACE_CONTROL_BIT);
|
||||
do_for_each_ftrace_op(op, ftrace_control_list) {
|
||||
if (!ftrace_function_local_disabled(op) &&
|
||||
if (!(op->flags & FTRACE_OPS_FL_STUB) &&
|
||||
!ftrace_function_local_disabled(op) &&
|
||||
ftrace_ops_test(op, ip))
|
||||
op->func(ip, parent_ip, op, regs);
|
||||
} while_for_each_ftrace_op(op);
|
||||
|
|
@ -4439,7 +4439,7 @@ static const struct file_operations ftrace_pid_fops = {
|
|||
.open = ftrace_pid_open,
|
||||
.write = ftrace_pid_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.llseek = ftrace_filter_lseek,
|
||||
.release = ftrace_pid_release,
|
||||
};
|
||||
|
||||
|
|
@ -4555,12 +4555,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
|
|||
ftrace_startup_sysctl();
|
||||
|
||||
/* we are starting ftrace again */
|
||||
if (ftrace_ops_list != &ftrace_list_end) {
|
||||
if (ftrace_ops_list->next == &ftrace_list_end)
|
||||
ftrace_trace_function = ftrace_ops_list->func;
|
||||
else
|
||||
ftrace_trace_function = ftrace_ops_list_func;
|
||||
}
|
||||
if (ftrace_ops_list != &ftrace_list_end)
|
||||
update_ftrace_function();
|
||||
|
||||
} else {
|
||||
/* stopping ftrace calls (just send to ftrace_stub) */
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ static char *default_bootup_tracer;
|
|||
|
||||
static int __init set_cmdline_ftrace(char *str)
|
||||
{
|
||||
strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
|
||||
strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
|
||||
default_bootup_tracer = bootup_tracer_buf;
|
||||
/* We are using ftrace early, expand it */
|
||||
ring_buffer_expanded = 1;
|
||||
|
|
@ -162,7 +162,7 @@ static char *trace_boot_options __initdata;
|
|||
|
||||
static int __init set_trace_boot_options(char *str)
|
||||
{
|
||||
strncpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);
|
||||
strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);
|
||||
trace_boot_options = trace_boot_options_buf;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -704,7 +704,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
|
|||
void
|
||||
update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
|
||||
{
|
||||
struct ring_buffer *buf = tr->buffer;
|
||||
struct ring_buffer *buf;
|
||||
|
||||
if (trace_stop_count)
|
||||
return;
|
||||
|
|
@ -719,6 +719,7 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
|
|||
|
||||
arch_spin_lock(&ftrace_max_lock);
|
||||
|
||||
buf = tr->buffer;
|
||||
tr->buffer = max_tr.buffer;
|
||||
max_tr.buffer = buf;
|
||||
|
||||
|
|
@ -743,8 +744,11 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
|
|||
return;
|
||||
|
||||
WARN_ON_ONCE(!irqs_disabled());
|
||||
if (WARN_ON_ONCE(!current_trace->allocated_snapshot))
|
||||
if (!current_trace->allocated_snapshot) {
|
||||
/* Only the nop tracer should hit this when disabling */
|
||||
WARN_ON_ONCE(current_trace != &nop_trace);
|
||||
return;
|
||||
}
|
||||
|
||||
arch_spin_lock(&ftrace_max_lock);
|
||||
|
||||
|
|
@ -2880,11 +2884,25 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void set_tracer_flags(unsigned int mask, int enabled)
|
||||
/* Some tracers require overwrite to stay enabled */
|
||||
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
|
||||
{
|
||||
if (tracer->enabled && (mask & TRACE_ITER_OVERWRITE) && !set)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_tracer_flag(unsigned int mask, int enabled)
|
||||
{
|
||||
/* do nothing if flag is already set */
|
||||
if (!!(trace_flags & mask) == !!enabled)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/* Give the tracer a chance to approve the change */
|
||||
if (current_trace->flag_changed)
|
||||
if (current_trace->flag_changed(current_trace, mask, !!enabled))
|
||||
return -EINVAL;
|
||||
|
||||
if (enabled)
|
||||
trace_flags |= mask;
|
||||
|
|
@ -2894,18 +2912,24 @@ static void set_tracer_flags(unsigned int mask, int enabled)
|
|||
if (mask == TRACE_ITER_RECORD_CMD)
|
||||
trace_event_enable_cmd_record(enabled);
|
||||
|
||||
if (mask == TRACE_ITER_OVERWRITE)
|
||||
if (mask == TRACE_ITER_OVERWRITE) {
|
||||
ring_buffer_change_overwrite(global_trace.buffer, enabled);
|
||||
#ifdef CONFIG_TRACER_MAX_TRACE
|
||||
ring_buffer_change_overwrite(max_tr.buffer, enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mask == TRACE_ITER_PRINTK)
|
||||
trace_printk_start_stop_comm(enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trace_set_options(char *option)
|
||||
{
|
||||
char *cmp;
|
||||
int neg = 0;
|
||||
int ret = 0;
|
||||
int ret = -ENODEV;
|
||||
int i;
|
||||
|
||||
cmp = strstrip(option);
|
||||
|
|
@ -2915,19 +2939,20 @@ static int trace_set_options(char *option)
|
|||
cmp += 2;
|
||||
}
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
|
||||
for (i = 0; trace_options[i]; i++) {
|
||||
if (strcmp(cmp, trace_options[i]) == 0) {
|
||||
set_tracer_flags(1 << i, !neg);
|
||||
ret = set_tracer_flag(1 << i, !neg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no option could be set, test the specific tracer options */
|
||||
if (!trace_options[i]) {
|
||||
mutex_lock(&trace_types_lock);
|
||||
if (!trace_options[i])
|
||||
ret = set_tracer_option(current_trace, cmp, neg);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
}
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2937,6 +2962,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
|||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
char buf[64];
|
||||
int ret;
|
||||
|
||||
if (cnt >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
|
@ -2946,7 +2972,9 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
|||
|
||||
buf[cnt] = 0;
|
||||
|
||||
trace_set_options(buf);
|
||||
ret = trace_set_options(buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*ppos += cnt;
|
||||
|
||||
|
|
@ -3250,6 +3278,9 @@ static int tracing_set_tracer(const char *buf)
|
|||
goto out;
|
||||
|
||||
trace_branch_disable();
|
||||
|
||||
current_trace->enabled = false;
|
||||
|
||||
if (current_trace->reset)
|
||||
current_trace->reset(tr);
|
||||
|
||||
|
|
@ -3294,6 +3325,7 @@ static int tracing_set_tracer(const char *buf)
|
|||
}
|
||||
|
||||
current_trace = t;
|
||||
current_trace->enabled = true;
|
||||
trace_branch_enable(tr);
|
||||
out:
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
|
@ -4780,7 +4812,13 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
|||
|
||||
if (val != 0 && val != 1)
|
||||
return -EINVAL;
|
||||
set_tracer_flags(1 << index, val);
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
ret = set_tracer_flag(1 << index, val);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*ppos += cnt;
|
||||
|
||||
|
|
|
|||
|
|
@ -283,11 +283,15 @@ struct tracer {
|
|||
enum print_line_t (*print_line)(struct trace_iterator *iter);
|
||||
/* If you handled the flag setting, return 0 */
|
||||
int (*set_flag)(u32 old_flags, u32 bit, int set);
|
||||
/* Return 0 if OK with change, else return non-zero */
|
||||
int (*flag_changed)(struct tracer *tracer,
|
||||
u32 mask, int set);
|
||||
struct tracer *next;
|
||||
struct tracer_flags *flags;
|
||||
bool print_max;
|
||||
bool use_max_tr;
|
||||
bool allocated_snapshot;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -943,6 +947,8 @@ extern const char *__stop___trace_bprintk_fmt[];
|
|||
|
||||
void trace_printk_init_buffers(void);
|
||||
void trace_printk_start_comm(void);
|
||||
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
|
||||
int set_tracer_flag(unsigned int mask, int enabled);
|
||||
|
||||
#undef FTRACE_ENTRY
|
||||
#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ enum {
|
|||
|
||||
static int trace_type __read_mostly;
|
||||
|
||||
static int save_lat_flag;
|
||||
static int save_flags;
|
||||
|
||||
static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
|
||||
static int start_irqsoff_tracer(struct trace_array *tr, int graph);
|
||||
|
|
@ -558,8 +558,11 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
|
|||
|
||||
static void __irqsoff_tracer_init(struct trace_array *tr)
|
||||
{
|
||||
save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
|
||||
trace_flags |= TRACE_ITER_LATENCY_FMT;
|
||||
save_flags = trace_flags;
|
||||
|
||||
/* non overwrite screws up the latency tracers */
|
||||
set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
|
||||
set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
|
||||
|
||||
tracing_max_latency = 0;
|
||||
irqsoff_trace = tr;
|
||||
|
|
@ -573,10 +576,13 @@ static void __irqsoff_tracer_init(struct trace_array *tr)
|
|||
|
||||
static void irqsoff_tracer_reset(struct trace_array *tr)
|
||||
{
|
||||
int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
|
||||
int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
|
||||
|
||||
stop_irqsoff_tracer(tr, is_graph());
|
||||
|
||||
if (!save_lat_flag)
|
||||
trace_flags &= ~TRACE_ITER_LATENCY_FMT;
|
||||
set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
|
||||
set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
|
||||
}
|
||||
|
||||
static void irqsoff_tracer_start(struct trace_array *tr)
|
||||
|
|
@ -609,6 +615,7 @@ static struct tracer irqsoff_tracer __read_mostly =
|
|||
.print_line = irqsoff_print_line,
|
||||
.flags = &tracer_flags,
|
||||
.set_flag = irqsoff_set_flag,
|
||||
.flag_changed = trace_keep_overwrite,
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_irqsoff,
|
||||
#endif
|
||||
|
|
@ -642,6 +649,7 @@ static struct tracer preemptoff_tracer __read_mostly =
|
|||
.print_line = irqsoff_print_line,
|
||||
.flags = &tracer_flags,
|
||||
.set_flag = irqsoff_set_flag,
|
||||
.flag_changed = trace_keep_overwrite,
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_preemptoff,
|
||||
#endif
|
||||
|
|
@ -677,6 +685,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
|
|||
.print_line = irqsoff_print_line,
|
||||
.flags = &tracer_flags,
|
||||
.set_flag = irqsoff_set_flag,
|
||||
.flag_changed = trace_keep_overwrite,
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_preemptirqsoff,
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ static void __wakeup_reset(struct trace_array *tr);
|
|||
static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
|
||||
static void wakeup_graph_return(struct ftrace_graph_ret *trace);
|
||||
|
||||
static int save_lat_flag;
|
||||
static int save_flags;
|
||||
|
||||
#define TRACE_DISPLAY_GRAPH 1
|
||||
|
||||
|
|
@ -540,8 +540,11 @@ static void stop_wakeup_tracer(struct trace_array *tr)
|
|||
|
||||
static int __wakeup_tracer_init(struct trace_array *tr)
|
||||
{
|
||||
save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
|
||||
trace_flags |= TRACE_ITER_LATENCY_FMT;
|
||||
save_flags = trace_flags;
|
||||
|
||||
/* non overwrite screws up the latency tracers */
|
||||
set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
|
||||
set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
|
||||
|
||||
tracing_max_latency = 0;
|
||||
wakeup_trace = tr;
|
||||
|
|
@ -563,12 +566,15 @@ static int wakeup_rt_tracer_init(struct trace_array *tr)
|
|||
|
||||
static void wakeup_tracer_reset(struct trace_array *tr)
|
||||
{
|
||||
int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
|
||||
int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
|
||||
|
||||
stop_wakeup_tracer(tr);
|
||||
/* make sure we put back any tasks we are tracing */
|
||||
wakeup_reset(tr);
|
||||
|
||||
if (!save_lat_flag)
|
||||
trace_flags &= ~TRACE_ITER_LATENCY_FMT;
|
||||
set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
|
||||
set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
|
||||
}
|
||||
|
||||
static void wakeup_tracer_start(struct trace_array *tr)
|
||||
|
|
@ -594,6 +600,7 @@ static struct tracer wakeup_tracer __read_mostly =
|
|||
.print_line = wakeup_print_line,
|
||||
.flags = &tracer_flags,
|
||||
.set_flag = wakeup_set_flag,
|
||||
.flag_changed = trace_keep_overwrite,
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_wakeup,
|
||||
#endif
|
||||
|
|
@ -615,6 +622,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
|
|||
.print_line = wakeup_print_line,
|
||||
.flags = &tracer_flags,
|
||||
.set_flag = wakeup_set_flag,
|
||||
.flag_changed = trace_keep_overwrite,
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_wakeup,
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ static const struct file_operations stack_trace_filter_fops = {
|
|||
.open = stack_trace_filter_open,
|
||||
.read = seq_read,
|
||||
.write = ftrace_filter_write,
|
||||
.llseek = ftrace_regex_lseek,
|
||||
.llseek = ftrace_filter_lseek,
|
||||
.release = ftrace_regex_release,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ struct user_namespace init_user_ns = {
|
|||
.owner = GLOBAL_ROOT_UID,
|
||||
.group = GLOBAL_ROOT_GID,
|
||||
.proc_inum = PROC_USER_INIT_INO,
|
||||
.may_mount_sysfs = true,
|
||||
.may_mount_proc = true,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(init_user_ns);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/projid.h>
|
||||
#include <linux/fs_struct.h>
|
||||
|
||||
static struct kmem_cache *user_ns_cachep __read_mostly;
|
||||
|
||||
static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
||||
static bool new_idmap_permitted(const struct file *file,
|
||||
struct user_namespace *ns, int cap_setid,
|
||||
struct uid_gid_map *map);
|
||||
|
||||
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
||||
|
|
@ -60,6 +62,15 @@ int create_user_ns(struct cred *new)
|
|||
kgid_t group = new->egid;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Verify that we can not violate the policy of which files
|
||||
* may be accessed that is specified by the root directory,
|
||||
* by verifing that the root directory is at the root of the
|
||||
* mount namespace which allows all files to be accessed.
|
||||
*/
|
||||
if (current_chrooted())
|
||||
return -EPERM;
|
||||
|
||||
/* The creator needs a mapping in the parent user namespace
|
||||
* or else we won't be able to reasonably tell userspace who
|
||||
* created a user_namespace.
|
||||
|
|
@ -86,6 +97,8 @@ int create_user_ns(struct cred *new)
|
|||
|
||||
set_cred_user_ns(new, ns);
|
||||
|
||||
update_mnt_policy(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -600,10 +613,10 @@ static ssize_t map_write(struct file *file, const char __user *buf,
|
|||
if (map->nr_extents != 0)
|
||||
goto out;
|
||||
|
||||
/* Require the appropriate privilege CAP_SETUID or CAP_SETGID
|
||||
* over the user namespace in order to set the id mapping.
|
||||
/*
|
||||
* Adjusting namespace settings requires capabilities on the target.
|
||||
*/
|
||||
if (cap_valid(cap_setid) && !ns_capable(ns, cap_setid))
|
||||
if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
|
||||
goto out;
|
||||
|
||||
/* Get a buffer */
|
||||
|
|
@ -688,7 +701,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
|
|||
|
||||
ret = -EPERM;
|
||||
/* Validate the user is allowed to use user id's mapped to. */
|
||||
if (!new_idmap_permitted(ns, cap_setid, &new_map))
|
||||
if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
|
||||
goto out;
|
||||
|
||||
/* Map the lower ids from the parent user namespace to the
|
||||
|
|
@ -775,7 +788,8 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t
|
|||
&ns->projid_map, &ns->parent->projid_map);
|
||||
}
|
||||
|
||||
static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
||||
static bool new_idmap_permitted(const struct file *file,
|
||||
struct user_namespace *ns, int cap_setid,
|
||||
struct uid_gid_map *new_map)
|
||||
{
|
||||
/* Allow mapping to your own filesystem ids */
|
||||
|
|
@ -783,12 +797,12 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
|||
u32 id = new_map->extent[0].lower_first;
|
||||
if (cap_setid == CAP_SETUID) {
|
||||
kuid_t uid = make_kuid(ns->parent, id);
|
||||
if (uid_eq(uid, current_fsuid()))
|
||||
if (uid_eq(uid, file->f_cred->fsuid))
|
||||
return true;
|
||||
}
|
||||
else if (cap_setid == CAP_SETGID) {
|
||||
kgid_t gid = make_kgid(ns->parent, id);
|
||||
if (gid_eq(gid, current_fsgid()))
|
||||
if (gid_eq(gid, file->f_cred->fsgid))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -799,8 +813,10 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
|||
|
||||
/* Allow the specified ids if we have the appropriate capability
|
||||
* (CAP_SETUID or CAP_SETGID) over the parent user namespace.
|
||||
* And the opener of the id file also had the approprpiate capability.
|
||||
*/
|
||||
if (ns_capable(ns->parent, cap_setid))
|
||||
if (ns_capable(ns->parent, cap_setid) &&
|
||||
file_ns_capable(file, ns->parent, cap_setid))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -837,6 +853,9 @@ static int userns_install(struct nsproxy *nsproxy, void *ns)
|
|||
if (atomic_read(¤t->mm->mm_users) > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (current->fs->users != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
|
|
|
|||
|
|
@ -457,11 +457,12 @@ static int worker_pool_assign_id(struct worker_pool *pool)
|
|||
int ret;
|
||||
|
||||
mutex_lock(&worker_pool_idr_mutex);
|
||||
idr_pre_get(&worker_pool_idr, GFP_KERNEL);
|
||||
ret = idr_get_new(&worker_pool_idr, pool, &pool->id);
|
||||
ret = idr_alloc(&worker_pool_idr, pool, 0, 0, GFP_KERNEL);
|
||||
if (ret >= 0)
|
||||
pool->id = ret;
|
||||
mutex_unlock(&worker_pool_idr_mutex);
|
||||
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3446,28 +3447,34 @@ static void wq_unbind_fn(struct work_struct *work)
|
|||
|
||||
spin_unlock_irq(&pool->lock);
|
||||
mutex_unlock(&pool->assoc_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call schedule() so that we cross rq->lock and thus can guarantee
|
||||
* sched callbacks see the %WORKER_UNBOUND flag. This is necessary
|
||||
* as scheduler callbacks may be invoked from other cpus.
|
||||
*/
|
||||
schedule();
|
||||
/*
|
||||
* Call schedule() so that we cross rq->lock and thus can
|
||||
* guarantee sched callbacks see the %WORKER_UNBOUND flag.
|
||||
* This is necessary as scheduler callbacks may be invoked
|
||||
* from other cpus.
|
||||
*/
|
||||
schedule();
|
||||
|
||||
/*
|
||||
* Sched callbacks are disabled now. Zap nr_running. After this,
|
||||
* nr_running stays zero and need_more_worker() and keep_working()
|
||||
* are always true as long as the worklist is not empty. Pools on
|
||||
* @cpu now behave as unbound (in terms of concurrency management)
|
||||
* pools which are served by workers tied to the CPU.
|
||||
*
|
||||
* On return from this function, the current worker would trigger
|
||||
* unbound chain execution of pending work items if other workers
|
||||
* didn't already.
|
||||
*/
|
||||
for_each_std_worker_pool(pool, cpu)
|
||||
/*
|
||||
* Sched callbacks are disabled now. Zap nr_running.
|
||||
* After this, nr_running stays zero and need_more_worker()
|
||||
* and keep_working() are always true as long as the
|
||||
* worklist is not empty. This pool now behaves as an
|
||||
* unbound (in terms of concurrency management) pool which
|
||||
* are served by workers tied to the pool.
|
||||
*/
|
||||
atomic_set(&pool->nr_running, 0);
|
||||
|
||||
/*
|
||||
* With concurrency management just turned off, a busy
|
||||
* worker blocking could lead to lengthy stalls. Kick off
|
||||
* unbound chain execution of currently pending work items.
|
||||
*/
|
||||
spin_lock_irq(&pool->lock);
|
||||
wake_up_worker(pool);
|
||||
spin_unlock_irq(&pool->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue