summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c232
-rw-r--r--kernel/auditfilter.c9
-rw-r--r--kernel/auditsc.c64
-rw-r--r--kernel/cpu.c32
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/futex.c2
-rw-r--r--kernel/hrtimer.c57
-rw-r--r--kernel/irq/devres.c2
-rw-r--r--kernel/irq/migration.c9
-rw-r--r--kernel/kallsyms.c23
-rw-r--r--kernel/kprobes.c113
-rw-r--r--kernel/lockdep.c14
-rw-r--r--kernel/module.c43
-rw-r--r--kernel/params.c32
-rw-r--r--kernel/power/Kconfig37
-rw-r--r--kernel/power/console.c10
-rw-r--r--kernel/power/disk.c94
-rw-r--r--kernel/power/main.c42
-rw-r--r--kernel/power/swsusp.c2
-rw-r--r--kernel/power/user.c9
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/rcutorture.c14
-rw-r--r--kernel/relay.c3
-rw-r--r--kernel/resource.c21
-rw-r--r--kernel/sched.c195
-rw-r--r--kernel/signal.c3
-rw-r--r--kernel/sysctl.c8
-rw-r--r--kernel/taskstats.c4
-rw-r--r--kernel/time.c4
-rw-r--r--kernel/time/clockevents.c69
-rw-r--r--kernel/time/clocksource.c11
-rw-r--r--kernel/time/jiffies.c2
-rw-r--r--kernel/time/ntp.c30
-rw-r--r--kernel/time/tick-broadcast.c53
-rw-r--r--kernel/time/tick-common.c38
-rw-r--r--kernel/time/tick-internal.h15
-rw-r--r--kernel/time/tick-oneshot.c12
-rw-r--r--kernel/time/tick-sched.c14
-rw-r--r--kernel/time/timer_list.c6
-rw-r--r--kernel/timer.c42
41 files changed, 810 insertions, 566 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index d9b690ac684..4e9d2082968 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -2,7 +2,7 @@
* Gateway between the kernel (e.g., selinux) and the user-space audit daemon.
* System-call specific features have moved to auditsc.c
*
- * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright 2003-2007 Red Hat Inc., Durham, North Carolina.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -65,7 +65,9 @@
* (Initialization happens after skb_init is called.) */
static int audit_initialized;
-/* No syscall auditing will take place unless audit_enabled != 0. */
+/* 0 - no auditing
+ * 1 - auditing enabled
+ * 2 - auditing enabled and configuration is locked/unchangeable. */
int audit_enabled;
/* Default state when kernel boots without any parameters. */
@@ -149,7 +151,7 @@ struct audit_buffer {
static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
{
- struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
+ struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
nlh->nlmsg_pid = pid;
}
@@ -239,102 +241,150 @@ void audit_log_lost(const char *message)
static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
{
- int old = audit_rate_limit;
+ int res, rc = 0, old = audit_rate_limit;
+
+ /* check if we are locked */
+ if (audit_enabled == 2)
+ res = 0;
+ else
+ res = 1;
if (sid) {
char *ctx = NULL;
u32 len;
- int rc;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
- return rc;
- else
+ if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_rate_limit=%d old=%d by auid=%u subj=%s",
- limit, old, loginuid, ctx);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_rate_limit=%d old=%d by auid=%u",
- limit, old, loginuid);
- audit_rate_limit = limit;
- return 0;
+ "audit_rate_limit=%d old=%d by auid=%u"
+ " subj=%s res=%d",
+ limit, old, loginuid, ctx, res);
+ kfree(ctx);
+ } else
+ res = 0; /* Something weird, deny request */
+ }
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+ "audit_rate_limit=%d old=%d by auid=%u res=%d",
+ limit, old, loginuid, res);
+
+ /* If we are allowed, make the change */
+ if (res == 1)
+ audit_rate_limit = limit;
+ /* Not allowed, update reason */
+ else if (rc == 0)
+ rc = -EPERM;
+ return rc;
}
static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
{
- int old = audit_backlog_limit;
+ int res, rc = 0, old = audit_backlog_limit;
+
+ /* check if we are locked */
+ if (audit_enabled == 2)
+ res = 0;
+ else
+ res = 1;
if (sid) {
char *ctx = NULL;
u32 len;
- int rc;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
- return rc;
- else
+ if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_backlog_limit=%d old=%d by auid=%u subj=%s",
- limit, old, loginuid, ctx);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_backlog_limit=%d old=%d by auid=%u",
- limit, old, loginuid);
- audit_backlog_limit = limit;
- return 0;
+ "audit_backlog_limit=%d old=%d by auid=%u"
+ " subj=%s res=%d",
+ limit, old, loginuid, ctx, res);
+ kfree(ctx);
+ } else
+ res = 0; /* Something weird, deny request */
+ }
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+ "audit_backlog_limit=%d old=%d by auid=%u res=%d",
+ limit, old, loginuid, res);
+
+ /* If we are allowed, make the change */
+ if (res == 1)
+ audit_backlog_limit = limit;
+ /* Not allowed, update reason */
+ else if (rc == 0)
+ rc = -EPERM;
+ return rc;
}
static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
{
- int old = audit_enabled;
+ int res, rc = 0, old = audit_enabled;
- if (state != 0 && state != 1)
+ if (state < 0 || state > 2)
return -EINVAL;
+ /* check if we are locked */
+ if (audit_enabled == 2)
+ res = 0;
+ else
+ res = 1;
+
if (sid) {
char *ctx = NULL;
u32 len;
- int rc;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
- return rc;
- else
+ if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_enabled=%d old=%d by auid=%u subj=%s",
- state, old, loginuid, ctx);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_enabled=%d old=%d by auid=%u",
- state, old, loginuid);
- audit_enabled = state;
- return 0;
+ "audit_enabled=%d old=%d by auid=%u"
+ " subj=%s res=%d",
+ state, old, loginuid, ctx, res);
+ kfree(ctx);
+ } else
+ res = 0; /* Something weird, deny request */
+ }
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+ "audit_enabled=%d old=%d by auid=%u res=%d",
+ state, old, loginuid, res);
+
+ /* If we are allowed, make the change */
+ if (res == 1)
+ audit_enabled = state;
+ /* Not allowed, update reason */
+ else if (rc == 0)
+ rc = -EPERM;
+ return rc;
}
static int audit_set_failure(int state, uid_t loginuid, u32 sid)
{
- int old = audit_failure;
+ int res, rc = 0, old = audit_failure;
if (state != AUDIT_FAIL_SILENT
&& state != AUDIT_FAIL_PRINTK
&& state != AUDIT_FAIL_PANIC)
return -EINVAL;
+ /* check if we are locked */
+ if (audit_enabled == 2)
+ res = 0;
+ else
+ res = 1;
+
if (sid) {
char *ctx = NULL;
u32 len;
- int rc;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
- return rc;
- else
+ if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_failure=%d old=%d by auid=%u subj=%s",
- state, old, loginuid, ctx);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_failure=%d old=%d by auid=%u",
- state, old, loginuid);
- audit_failure = state;
- return 0;
+ "audit_failure=%d old=%d by auid=%u"
+ " subj=%s res=%d",
+ state, old, loginuid, ctx, res);
+ kfree(ctx);
+ } else
+ res = 0; /* Something weird, deny request */
+ }
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+ "audit_failure=%d old=%d by auid=%u res=%d",
+ state, old, loginuid, res);
+
+ /* If we are allowed, make the change */
+ if (res == 1)
+ audit_failure = state;
+ /* Not allowed, update reason */
+ else if (rc == 0)
+ rc = -EPERM;
+ return rc;
}
static int kauditd_thread(void *dummy)
@@ -599,6 +649,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_DEL:
if (nlmsg_len(nlh) < sizeof(struct audit_rule))
return -EINVAL;
+ if (audit_enabled == 2) {
+ ab = audit_log_start(NULL, GFP_KERNEL,
+ AUDIT_CONFIG_CHANGE);
+ if (ab) {
+ audit_log_format(ab,
+ "pid=%d uid=%u auid=%u",
+ pid, uid, loginuid);
+ if (sid) {
+ if (selinux_sid_to_string(
+ sid, &ctx, &len)) {
+ audit_log_format(ab,
+ " ssid=%u", sid);
+ /* Maybe call audit_panic? */
+ } else
+ audit_log_format(ab,
+ " subj=%s", ctx);
+ kfree(ctx);
+ }
+ audit_log_format(ab, " audit_enabled=%d res=0",
+ audit_enabled);
+ audit_log_end(ab);
+ }
+ return -EPERM;
+ }
/* fallthrough */
case AUDIT_LIST:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
@@ -609,6 +683,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_DEL_RULE:
if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
return -EINVAL;
+ if (audit_enabled == 2) {
+ ab = audit_log_start(NULL, GFP_KERNEL,
+ AUDIT_CONFIG_CHANGE);
+ if (ab) {
+ audit_log_format(ab,
+ "pid=%d uid=%u auid=%u",
+ pid, uid, loginuid);
+ if (sid) {
+ if (selinux_sid_to_string(
+ sid, &ctx, &len)) {
+ audit_log_format(ab,
+ " ssid=%u", sid);
+ /* Maybe call audit_panic? */
+ } else
+ audit_log_format(ab,
+ " subj=%s", ctx);
+ kfree(ctx);
+ }
+ audit_log_format(ab, " audit_enabled=%d res=0",
+ audit_enabled);
+ audit_log_end(ab);
+ }
+ return -EPERM;
+ }
/* fallthrough */
case AUDIT_LIST_RULES:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
@@ -652,7 +750,7 @@ static void audit_receive_skb(struct sk_buff *skb)
u32 rlen;
while (skb->len >= NLMSG_SPACE(0)) {
- nlh = (struct nlmsghdr *)skb->data;
+ nlh = nlmsg_hdr(skb);
if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
return;
rlen = NLMSG_ALIGN(nlh->nlmsg_len);
@@ -697,7 +795,7 @@ static int __init audit_init(void)
printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
audit_default ? "enabled" : "disabled");
audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
- THIS_MODULE);
+ NULL, THIS_MODULE);
if (!audit_sock)
audit_panic("cannot initialize netlink socket");
else
@@ -975,7 +1073,7 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
goto out;
}
va_copy(args2, args);
- len = vsnprintf(skb->tail, avail, fmt, args);
+ len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args);
if (len >= avail) {
/* The printk buffer is 1024 bytes long, so if we get
* here and AUDIT_BUFSIZ is at least 1024, then we can
@@ -984,7 +1082,7 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
if (!avail)
goto out;
- len = vsnprintf(skb->tail, avail, fmt, args2);
+ len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
}
if (len > 0)
skb_put(skb, len);
@@ -1045,7 +1143,7 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
return;
}
- ptr = skb->tail;
+ ptr = skb_tail_pointer(skb);
for (i=0; i<len; i++) {
*ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
*ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */
@@ -1077,7 +1175,7 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
if (!avail)
return;
}
- ptr = skb->tail;
+ ptr = skb_tail_pointer(skb);
*ptr++ = '"';
memcpy(ptr, string, slen);
ptr += slen;
@@ -1170,7 +1268,7 @@ void audit_log_end(struct audit_buffer *ab)
audit_log_lost("rate limit exceeded");
} else {
if (audit_pid) {
- struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
+ struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);
skb_queue_tail(&audit_skb_queue, ab->skb);
ab->skb = NULL;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 87865f8b4ce..3749193aed8 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -937,9 +937,10 @@ static void audit_update_watch(struct audit_parent *parent,
}
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- audit_log_format(ab, "audit updated rules specifying path=");
+ audit_log_format(ab, "op=updated rules specifying path=");
audit_log_untrustedstring(ab, owatch->path);
audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino);
+ audit_log_format(ab, " list=%d res=1", r->listnr);
audit_log_end(ab);
audit_remove_watch(owatch);
@@ -969,14 +970,14 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
e = container_of(r, struct audit_entry, rule);
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- audit_log_format(ab, "audit implicitly removed rule path=");
+ audit_log_format(ab, "op=remove rule path=");
audit_log_untrustedstring(ab, w->path);
if (r->filterkey) {
audit_log_format(ab, " key=");
audit_log_untrustedstring(ab, r->filterkey);
} else
audit_log_format(ab, " key=(null)");
- audit_log_format(ab, " list=%d", r->listnr);
+ audit_log_format(ab, " list=%d res=1", r->listnr);
audit_log_end(ab);
list_del(&r->rlist);
@@ -1410,7 +1411,7 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
audit_log_format(ab, " subj=%s", ctx);
kfree(ctx);
}
- audit_log_format(ab, " %s rule key=", action);
+ audit_log_format(ab, " op=%s rule key=", action);
if (rule->filterkey)
audit_log_untrustedstring(ab, rule->filterkey);
else
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 298897559ca..628c7ac590a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -170,6 +170,11 @@ struct audit_aux_data_sockaddr {
char a[0];
};
+struct audit_aux_data_fd_pair {
+ struct audit_aux_data d;
+ int fd[2];
+};
+
struct audit_aux_data_path {
struct audit_aux_data d;
struct dentry *dentry;
@@ -734,28 +739,26 @@ static inline void audit_free_context(struct audit_context *context)
void audit_log_task_context(struct audit_buffer *ab)
{
char *ctx = NULL;
- ssize_t len = 0;
+ unsigned len;
+ int error;
+ u32 sid;
+
+ selinux_get_task_sid(current, &sid);
+ if (!sid)
+ return;
- len = security_getprocattr(current, "current", NULL, 0);
- if (len < 0) {
- if (len != -EINVAL)
+ error = selinux_sid_to_string(sid, &ctx, &len);
+ if (error) {
+ if (error != -EINVAL)
goto error_path;
return;
}
- ctx = kmalloc(len, GFP_KERNEL);
- if (!ctx)
- goto error_path;
-
- len = security_getprocattr(current, "current", ctx, len);
- if (len < 0 )
- goto error_path;
-
audit_log_format(ab, " subj=%s", ctx);
+ kfree(ctx);
return;
error_path:
- kfree(ctx);
audit_panic("error in audit_log_task_context");
return;
}
@@ -961,6 +964,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
break; }
+ case AUDIT_FD_PAIR: {
+ struct audit_aux_data_fd_pair *axs = (void *)aux;
+ audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
+ break; }
+
}
audit_log_end(ab);
}
@@ -1815,6 +1823,36 @@ int audit_socketcall(int nargs, unsigned long *args)
}
/**
+ * __audit_fd_pair - record audit data for pipe and socketpair
+ * @fd1: the first file descriptor
+ * @fd2: the second file descriptor
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int __audit_fd_pair(int fd1, int fd2)
+{
+ struct audit_context *context = current->audit_context;
+ struct audit_aux_data_fd_pair *ax;
+
+ if (likely(!context)) {
+ return 0;
+ }
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax) {
+ return -ENOMEM;
+ }
+
+ ax->fd[0] = fd1;
+ ax->fd[1] = fd2;
+
+ ax->d.type = AUDIT_FD_PAIR;
+ ax->d.next = context->aux;
+ context->aux = (void *)ax;
+ return 0;
+}
+
+/**
* audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto
* @len: data length in user space
* @a: data address in kernel space
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 3d4206ada5c..36e70845cfc 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -254,6 +254,12 @@ int __cpuinit cpu_up(unsigned int cpu)
}
#ifdef CONFIG_SUSPEND_SMP
+/* Needed to prevent the microcode driver from requesting firmware in its CPU
+ * hotplug notifier during the suspend/resume.
+ */
+int suspend_cpu_hotplug;
+EXPORT_SYMBOL(suspend_cpu_hotplug);
+
static cpumask_t frozen_cpus;
int disable_nonboot_cpus(void)
@@ -261,16 +267,8 @@ int disable_nonboot_cpus(void)
int cpu, first_cpu, error = 0;
mutex_lock(&cpu_add_remove_lock);
- first_cpu = first_cpu(cpu_present_map);
- if (!cpu_online(first_cpu)) {
- error = _cpu_up(first_cpu);
- if (error) {
- printk(KERN_ERR "Could not bring CPU%d up.\n",
- first_cpu);
- goto out;
- }
- }
-
+ suspend_cpu_hotplug = 1;
+ first_cpu = first_cpu(cpu_online_map);
/* We take down all of the non-boot CPUs in one shot to avoid races
* with the userspace trying to use the CPU hotplug at the same time
*/
@@ -296,7 +294,7 @@ int disable_nonboot_cpus(void)
} else {
printk(KERN_ERR "Non-boot CPUs are not disabled\n");
}
-out:
+ suspend_cpu_hotplug = 0;
mutex_unlock(&cpu_add_remove_lock);
return error;
}
@@ -308,20 +306,22 @@ void enable_nonboot_cpus(void)
/* Allow everyone to use the CPU hotplug again */
mutex_lock(&cpu_add_remove_lock);
cpu_hotplug_disabled = 0;
- mutex_unlock(&cpu_add_remove_lock);
if (cpus_empty(frozen_cpus))
- return;
+ goto out;
+ suspend_cpu_hotplug = 1;
printk("Enabling non-boot CPUs ...\n");
for_each_cpu_mask(cpu, frozen_cpus) {
- error = cpu_up(cpu);
+ error = _cpu_up(cpu);
if (!error) {
printk("CPU%d is up\n", cpu);
continue;
}
- printk(KERN_WARNING "Error taking CPU%d up: %d\n",
- cpu, error);
+ printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
}
cpus_clear(frozen_cpus);
+ suspend_cpu_hotplug = 0;
+out:
+ mutex_unlock(&cpu_add_remove_lock);
}
#endif
diff --git a/kernel/exit.c b/kernel/exit.c
index f132349c032..b55ed4cc910 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -790,7 +790,7 @@ static void exit_notify(struct task_struct *tsk)
pgrp = task_pgrp(tsk);
if ((task_pgrp(t) != pgrp) &&
- (task_session(t) != task_session(tsk)) &&
+ (task_session(t) == task_session(tsk)) &&
will_become_orphaned_pgrp(pgrp, tsk) &&
has_stopped_jobs(pgrp)) {
__kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp);
diff --git a/kernel/fork.c b/kernel/fork.c
index d154cc78648..6af959c034d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -933,8 +933,8 @@ asmlinkage long sys_set_tid_address(int __user *tidptr)
static inline void rt_mutex_init_task(struct task_struct *p)
{
-#ifdef CONFIG_RT_MUTEXES
spin_lock_init(&p->pi_lock);
+#ifdef CONFIG_RT_MUTEXES
plist_head_init(&p->pi_waiters, &p->pi_lock);
p->pi_blocked_on = NULL;
#endif
diff --git a/kernel/futex.c b/kernel/futex.c
index e749e7df14b..5a270b5e3f9 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -565,6 +565,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
if (!pi_state)
return -EINVAL;
+ spin_lock(&pi_state->pi_mutex.wait_lock);
new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
/*
@@ -604,6 +605,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
pi_state->owner = new_owner;
spin_unlock_irq(&new_owner->pi_lock);
+ spin_unlock(&pi_state->pi_mutex.wait_lock);
rt_mutex_unlock(&pi_state->pi_mutex);
return 0;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 476cb0c0b4a..1b3033105b4 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -59,6 +59,7 @@ ktime_t ktime_get(void)
return timespec_to_ktime(now);
}
+EXPORT_SYMBOL_GPL(ktime_get);
/**
* ktime_get_real - get the real (wall-) time in ktime_t format
@@ -135,7 +136,7 @@ EXPORT_SYMBOL_GPL(ktime_get_ts);
static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
{
ktime_t xtim, tomono;
- struct timespec xts;
+ struct timespec xts, tom;
unsigned long seq;
do {
@@ -145,10 +146,11 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
#else
xts = xtime;
#endif
+ tom = wall_to_monotonic;
} while (read_seqretry(&xtime_lock, seq));
xtim = timespec_to_ktime(xts);
- tomono = timespec_to_ktime(wall_to_monotonic);
+ tomono = timespec_to_ktime(tom);
base->clock_base[CLOCK_REALTIME].softirq_time = xtim;
base->clock_base[CLOCK_MONOTONIC].softirq_time =
ktime_add(xtim, tomono);
@@ -277,6 +279,8 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec)
return ktime_add(kt, tmp);
}
+
+EXPORT_SYMBOL_GPL(ktime_add_ns);
# endif /* !CONFIG_KTIME_SCALAR */
/*
@@ -458,6 +462,18 @@ void clock_was_set(void)
}
/*
+ * During resume we might have to reprogram the high resolution timer
+ * interrupt (on the local CPU):
+ */
+void hres_timers_resume(void)
+{
+ WARN_ON_ONCE(num_online_cpus() > 1);
+
+ /* Retrigger the CPU local events: */
+ retrigger_next_event(NULL);
+}
+
+/*
* Check, whether the timer is on the callback pending list
*/
static inline int hrtimer_cb_pending(const struct hrtimer *timer)
@@ -540,19 +556,19 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
/*
* Switch to high resolution mode
*/
-static void hrtimer_switch_to_hres(void)
+static int hrtimer_switch_to_hres(void)
{
struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
unsigned long flags;
if (base->hres_active)
- return;
+ return 1;
local_irq_save(flags);
if (tick_init_highres()) {
local_irq_restore(flags);
- return;
+ return 0;
}
base->hres_active = 1;
base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES;
@@ -565,13 +581,14 @@ static void hrtimer_switch_to_hres(void)
local_irq_restore(flags);
printk(KERN_INFO "Switched to high resolution mode on CPU %d\n",
smp_processor_id());
+ return 1;
}
#else
static inline int hrtimer_hres_active(void) { return 0; }
static inline int hrtimer_is_hres_enabled(void) { return 0; }
-static inline void hrtimer_switch_to_hres(void) { }
+static inline int hrtimer_switch_to_hres(void) { return 0; }
static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { }
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
struct hrtimer_clock_base *base)
@@ -643,6 +660,12 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
orun++;
}
timer->expires = ktime_add(timer->expires, interval);
+ /*
+ * Make sure, that the result did not wrap with a very large
+ * interval.
+ */
+ if (timer->expires.tv64 < 0)
+ timer->expires = ktime_set(KTIME_SEC_MAX, 0);
return orun;
}
@@ -806,7 +829,12 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
timer_stats_hrtimer_set_start_info(timer);
- enqueue_hrtimer(timer, new_base, base == new_base);
+ /*
+ * Only allow reprogramming if the new base is on this CPU.
+ * (it might still be on another CPU if the timer was pending)
+ */
+ enqueue_hrtimer(timer, new_base,
+ new_base->cpu_base == &__get_cpu_var(hrtimer_bases));
unlock_hrtimer_base(timer, &flags);
@@ -1130,6 +1158,9 @@ static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base,
if (base->softirq_time.tv64 <= timer->expires.tv64)
break;
+#ifdef CONFIG_HIGH_RES_TIMERS
+ WARN_ON_ONCE(timer->cb_mode == HRTIMER_CB_IRQSAFE_NO_SOFTIRQ);
+#endif
timer_stats_account_hrtimer(timer);
fn = timer->function;
@@ -1173,7 +1204,8 @@ void hrtimer_run_queues(void)
* deadlock vs. xtime_lock.
*/
if (tick_check_oneshot_change(!hrtimer_is_hres_enabled()))
- hrtimer_switch_to_hres();
+ if (hrtimer_switch_to_hres())
+ return;
hrtimer_get_softirq_time(cpu_base);
@@ -1355,17 +1387,16 @@ static void migrate_hrtimers(int cpu)
tick_cancel_sched_timer(cpu);
local_irq_disable();
-
- spin_lock(&new_base->lock);
- spin_lock(&old_base->lock);
+ double_spin_lock(&new_base->lock, &old_base->lock,
+ smp_processor_id() < cpu);
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
migrate_hrtimer_list(&old_base->clock_base[i],
&new_base->clock_base[i]);
}
- spin_unlock(&old_base->lock);
- spin_unlock(&new_base->lock);
+ double_spin_unlock(&new_base->lock, &old_base->lock,
+ smp_processor_id() < cpu);
local_irq_enable();
put_cpu_var(hrtimer_bases);
}
diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c
index 85a430da0fb..d8ee241115f 100644
--- a/kernel/irq/devres.c
+++ b/kernel/irq/devres.c
@@ -54,7 +54,7 @@ int devm_request_irq(struct device *dev, unsigned int irq,
rc = request_irq(irq, handler, irqflags, devname, dev_id);
if (rc) {
- kfree(dr);
+ devres_free(dr);
return rc;
}
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
index 4baa3bbcd25..77b7acc875c 100644
--- a/kernel/irq/migration.c
+++ b/kernel/irq/migration.c
@@ -65,12 +65,11 @@ void move_native_irq(int irq)
if (likely(!(desc->status & IRQ_MOVE_PENDING)))
return;
- if (likely(!(desc->status & IRQ_DISABLED)))
- desc->chip->disable(irq);
+ if (unlikely(desc->status & IRQ_DISABLED))
+ return;
+ desc->chip->mask(irq);
move_masked_irq(irq);
-
- if (likely(!(desc->status & IRQ_DISABLED)))
- desc->chip->enable(irq);
+ desc->chip->unmask(irq);
}
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 6f294ff4f9e..5a0de840973 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -267,27 +267,33 @@ const char *kallsyms_lookup(unsigned long addr,
return NULL;
}
-/* Replace "%s" in format with address, or returns -errno. */
-void __print_symbol(const char *fmt, unsigned long address)
+/* Look up a kernel symbol and return it in a text buffer. */
+int sprint_symbol(char *buffer, unsigned long address)
{
char *modname;
const char *name;
unsigned long offset, size;
char namebuf[KSYM_NAME_LEN+1];
- char buffer[sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN +
- 2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1];
name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
-
if (!name)
- sprintf(buffer, "0x%lx", address);
+ return sprintf(buffer, "0x%lx", address);
else {
if (modname)
- sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
+ return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
size, modname);
else
- sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+ return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
}
+}
+
+/* Look up a kernel symbol and print it to the kernel messages. */
+void __print_symbol(const char *fmt, unsigned long address)
+{
+ char buffer[KSYM_SYMBOL_LEN];
+
+ sprint_symbol(buffer, address);
+
printk(fmt, buffer);
}
@@ -452,3 +458,4 @@ static int __init kallsyms_init(void)
__initcall(kallsyms_init);
EXPORT_SYMBOL(__print_symbol);
+EXPORT_SYMBOL_GPL(sprint_symbol);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 6fcf8dd148d..d25a9ada3f8 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -39,6 +39,8 @@
#include <linux/moduleloader.h>
#include <linux/kallsyms.h>
#include <linux/freezer.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
#include <asm-generic/sections.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
@@ -778,6 +780,12 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
return -ENOSYS;
}
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+ struct pt_regs *regs)
+{
+ return 0;
+}
+
#endif /* ARCH_SUPPORTS_KRETPROBES */
void __kprobes unregister_kretprobe(struct kretprobe *rp)
@@ -815,7 +823,109 @@ static int __init init_kprobes(void)
return err;
}
-__initcall(init_kprobes);
+#ifdef CONFIG_DEBUG_FS
+static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p,
+ const char *sym, int offset,char *modname)
+{
+ char *kprobe_type;
+
+ if (p->pre_handler == pre_handler_kretprobe)
+ kprobe_type = "r";
+ else if (p->pre_handler == setjmp_pre_handler)
+ kprobe_type = "j";
+ else
+ kprobe_type = "k";
+ if (sym)
+ seq_printf(pi, "%p %s %s+0x%x %s\n", p->addr, kprobe_type,
+ sym, offset, (modname ? modname : " "));
+ else
+ seq_printf(pi, "%p %s %p\n", p->addr, kprobe_type, p->addr);
+}
+
+static void __kprobes *kprobe_seq_start(struct seq_file *f, loff_t *pos)
+{
+ return (*pos < KPROBE_TABLE_SIZE) ? pos : NULL;
+}
+
+static void __kprobes *kprobe_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= KPROBE_TABLE_SIZE)
+ return NULL;
+ return pos;
+}
+
+static void __kprobes kprobe_seq_stop(struct seq_file *f, void *v)
+{
+ /* Nothing to do */
+}
+
+static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct kprobe *p, *kp;
+ const char *sym = NULL;
+ unsigned int i = *(loff_t *) v;
+ unsigned long size, offset = 0;
+ char *modname, namebuf[128];
+
+ head = &kprobe_table[i];
+ preempt_disable();
+ hlist_for_each_entry_rcu(p, node, head, hlist) {
+ sym = kallsyms_lookup((unsigned long)p->addr, &size,
+ &offset, &modname, namebuf);
+ if (p->pre_handler == aggr_pre_handler) {
+ list_for_each_entry_rcu(kp, &p->list, list)
+ report_probe(pi, kp, sym, offset, modname);
+ } else
+ report_probe(pi, p, sym, offset, modname);
+ }
+ preempt_enable();
+ return 0;
+}
+
+static struct seq_operations kprobes_seq_ops = {
+ .start = kprobe_seq_start,
+ .next = kprobe_seq_next,
+ .stop = kprobe_seq_stop,
+ .show = show_kprobe_addr
+};
+
+static int __kprobes kprobes_open(struct inode *inode, struct file *filp)
+{
+ return seq_open(filp, &kprobes_seq_ops);
+}
+
+static struct file_operations debugfs_kprobes_operations = {
+ .open = kprobes_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __kprobes debugfs_kprobe_init(void)
+{
+ struct dentry *dir, *file;
+
+ dir = debugfs_create_dir("kprobes", NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ file = debugfs_create_file("list", 0444, dir , 0 ,
+ &debugfs_kprobes_operations);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+late_initcall(debugfs_kprobe_init);
+#endif /* CONFIG_DEBUG_FS */
+
+module_init(init_kprobes);
EXPORT_SYMBOL_GPL(register_kprobe);
EXPORT_SYMBOL_GPL(unregister_kprobe);
@@ -824,4 +934,3 @@ EXPORT_SYMBOL_GPL(unregister_jprobe);
EXPORT_SYMBOL_GPL(jprobe_return);
EXPORT_SYMBOL_GPL(register_kretprobe);
EXPORT_SYMBOL_GPL(unregister_kretprobe);
-
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 592c576d77a..7065a687ac5 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -2228,6 +2228,10 @@ out_calc_hash:
curr->lockdep_depth++;
check_chain_key(curr);
+#ifdef CONFIG_DEBUG_LOCKDEP
+ if (unlikely(!debug_locks))
+ return 0;
+#endif
if (unlikely(curr->lockdep_depth >= MAX_LOCK_DEPTH)) {
debug_locks_off();
printk("BUG: MAX_LOCK_DEPTH too low!\n");
@@ -2598,7 +2602,7 @@ out_restore:
raw_local_irq_restore(flags);
}
-void __init lockdep_init(void)
+void lockdep_init(void)
{
int i;
@@ -2738,6 +2742,10 @@ void debug_show_all_locks(void)
int count = 10;
int unlock = 1;
+ if (unlikely(!debug_locks)) {
+ printk("INFO: lockdep is turned off.\n");
+ return;
+ }
printk("\nShowing all locks held in the system:\n");
/*
@@ -2781,6 +2789,10 @@ EXPORT_SYMBOL_GPL(debug_show_all_locks);
void debug_show_held_locks(struct task_struct *task)
{
+ if (unlikely(!debug_locks)) {
+ printk("INFO: lockdep is turned off.\n");
+ return;
+ }
lockdep_print_held_locks(task);
}
diff --git a/kernel/module.c b/kernel/module.c
index 8a94e054230..9da5af668a2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1068,7 +1068,8 @@ static inline void remove_sect_attrs(struct module *mod)
}
#endif /* CONFIG_KALLSYMS */
-static int module_add_modinfo_attrs(struct module *mod)
+#ifdef CONFIG_SYSFS
+int module_add_modinfo_attrs(struct module *mod)
{
struct module_attribute *attr;
struct module_attribute *temp_attr;
@@ -1094,7 +1095,7 @@ static int module_add_modinfo_attrs(struct module *mod)
return error;
}
-static void module_remove_modinfo_attrs(struct module *mod)
+void module_remove_modinfo_attrs(struct module *mod)
{
struct module_attribute *attr;
int i;
@@ -1109,8 +1110,10 @@ static void module_remove_modinfo_attrs(struct module *mod)
}
kfree(mod->modinfo_attrs);
}
+#endif
-static int mod_sysfs_init(struct module *mod)
+#ifdef CONFIG_SYSFS
+int mod_sysfs_init(struct module *mod)
{
int err;
@@ -1133,7 +1136,7 @@ out:
return err;
}
-static int mod_sysfs_setup(struct module *mod,
+int mod_sysfs_setup(struct module *mod,
struct kernel_param *kparam,
unsigned int num_params)
{
@@ -1145,8 +1148,10 @@ static int mod_sysfs_setup(struct module *mod,
goto out;
mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
- if (!mod->holders_dir)
+ if (!mod->holders_dir) {
+ err = -ENOMEM;
goto out_unreg;
+ }
err = module_param_sysfs_setup(mod, kparam, num_params);
if (err)
@@ -1169,16 +1174,14 @@ out_unreg:
out:
return err;
}
+#endif
static void mod_kobject_remove(struct module *mod)
{
module_remove_modinfo_attrs(mod);
module_param_sysfs_remove(mod);
- if (mod->mkobj.drivers_dir)
- kobject_unregister(mod->mkobj.drivers_dir);
- if (mod->holders_dir)
- kobject_unregister(mod->holders_dir);
-
+ kobject_unregister(mod->mkobj.drivers_dir);
+ kobject_unregister(mod->holders_dir);
kobject_unregister(&mod->mkobj.kobj);
}
@@ -2345,6 +2348,7 @@ void print_modules(void)
printk("\n");
}
+#ifdef CONFIG_SYSFS
static char *make_driver_name(struct device_driver *drv)
{
char *driver_name;
@@ -2382,8 +2386,13 @@ void module_add_driver(struct module *mod, struct device_driver *drv)
/* Lookup built-in module entry in /sys/modules */
mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name);
- if (mkobj)
+ if (mkobj) {
mk = container_of(mkobj, struct module_kobject, kobj);
+ /* remember our module structure */
+ drv->mkobj = mk;
+ /* kset_find_obj took a reference */
+ kobject_put(mkobj);
+ }
}
if (!mk)
@@ -2403,22 +2412,28 @@ EXPORT_SYMBOL(module_add_driver);
void module_remove_driver(struct device_driver *drv)
{
+ struct module_kobject *mk = NULL;
char *driver_name;
if (!drv)
return;
sysfs_remove_link(&drv->kobj, "module");
- if (drv->owner && drv->owner->mkobj.drivers_dir) {
+
+ if (drv->owner)
+ mk = &drv->owner->mkobj;
+ else if (drv->mkobj)
+ mk = drv->mkobj;
+ if (mk && mk->drivers_dir) {
driver_name = make_driver_name(drv);
if (driver_name) {
- sysfs_remove_link(drv->owner->mkobj.drivers_dir,
- driver_name);
+ sysfs_remove_link(mk->drivers_dir, driver_name);
kfree(driver_name);
}
}
}
EXPORT_SYMBOL(module_remove_driver);
+#endif
#ifdef CONFIG_MODVERSIONS
/* Generate the signature for struct module here, too, for modversions. */
diff --git a/kernel/params.c b/kernel/params.c
index 553cf7d6a4b..1fc4ac746cd 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -30,8 +30,6 @@
#define DEBUGP(fmt, a...)
#endif
-static struct kobj_type module_ktype;
-
static inline char dash2underscore(char c)
{
if (c == '-')
@@ -358,6 +356,10 @@ int param_set_copystring(const char *val, struct kernel_param *kp)
{
struct kparam_string *kps = kp->arg;
+ if (!val) {
+ printk(KERN_ERR "%s: missing param set value\n", kp->name);
+ return -EINVAL;
+ }
if (strlen(val)+1 > kps->maxlen) {
printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
kp->name, kps->maxlen-1);
@@ -391,6 +393,7 @@ struct module_param_attrs
struct param_attribute attrs[0];
};
+#ifdef CONFIG_SYSFS
#define to_param_attr(n) container_of(n, struct param_attribute, mattr);
static ssize_t param_attr_show(struct module_attribute *mattr,
@@ -426,6 +429,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
return len;
return err;
}
+#endif
#ifdef CONFIG_MODULES
#define __modinit
@@ -433,6 +437,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
#define __modinit __init
#endif
+#ifdef CONFIG_SYSFS
/*
* param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME
* @mk: struct module_kobject (contains parent kobject)
@@ -500,9 +505,7 @@ param_sysfs_setup(struct module_kobject *mk,
return mp;
}
-
#ifdef CONFIG_MODULES
-
/*
* module_param_sysfs_setup - setup sysfs support for one module
* @mod: module
@@ -625,7 +628,6 @@ static void __init param_sysfs_builtin(void)
/* module-related sysfs stuff */
-#ifdef CONFIG_SYSFS
#define to_module_attr(n) container_of(n, struct module_attribute, attr);
#define to_module_kobject(n) container_of(n, struct module_kobject, kobj);
@@ -673,6 +675,8 @@ static struct sysfs_ops module_sysfs_ops = {
.store = module_attr_store,
};
+static struct kobj_type module_ktype;
+
static int uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
@@ -686,19 +690,12 @@ static struct kset_uevent_ops module_uevent_ops = {
.filter = uevent_filter,
};
-#else
-static struct sysfs_ops module_sysfs_ops = {
- .show = NULL,
- .store = NULL,
-};
-#endif
+decl_subsys(module, &module_ktype, &module_uevent_ops);
static struct kobj_type module_ktype = {
.sysfs_ops = &module_sysfs_ops,
};
-decl_subsys(module, &module_ktype, &module_uevent_ops);
-
/*
* param_sysfs_init - wrapper for built-in params support
*/
@@ -719,6 +716,15 @@ static int __init param_sysfs_init(void)
}
subsys_initcall(param_sysfs_init);
+#else
+#if 0
+static struct sysfs_ops module_sysfs_ops = {
+ .show = NULL,
+ .store = NULL,
+};
+#endif
+#endif
+
EXPORT_SYMBOL(param_set_byte);
EXPORT_SYMBOL(param_get_byte);
EXPORT_SYMBOL(param_set_short);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 95f6657fff7..51a4dd0f1b7 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -81,29 +81,34 @@ config SOFTWARE_SUSPEND
bool "Software Suspend"
depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
---help---
- Enable the possibility of suspending the machine.
- It doesn't need ACPI or APM.
- You may suspend your machine by 'swsusp' or 'shutdown -z <time>'
- (patch for sysvinit needed).
+ Enable the suspend to disk (STD) functionality.
- It creates an image which is saved in your active swap. Upon next
+ You can suspend your machine with 'echo disk > /sys/power/state'.
+ Alternatively, you can use the additional userland tools available
+ from <http://suspend.sf.net>.
+
+ In principle it does not require ACPI or APM, although for example
+ ACPI will be used if available.
+
+ It creates an image which is saved in your active swap. Upon the next
boot, pass the 'resume=/dev/swappartition' argument to the kernel to
have it detect the saved image, restore memory state from it, and
continue to run as before. If you do not want the previous state to
- be reloaded, then use the 'noresume' kernel argument. However, note
- that your partitions will be fsck'd and you must re-mkswap your swap
- partitions. It does not work with swap files.
+ be reloaded, then use the 'noresume' kernel command line argument.
+ Note, however, that fsck will be run on your filesystems and you will
+ need to run mkswap against the swap partition used for the suspend.
- Right now you may boot without resuming and then later resume but
- in meantime you cannot use those swap partitions/files which were
- involved in suspending. Also in this case there is a risk that buffers
- on disk won't match with saved ones.
+ It also works with swap files to a limited extent (for details see
+ <file:Documentation/power/swsusp-and-swap-files.txt>).
- For more information take a look at <file:Documentation/power/swsusp.txt>.
+ Right now you may boot without resuming and resume later but in the
+ meantime you cannot use the swap partition(s)/file(s) involved in
+ suspending. Also in this case you must not use the filesystems
+ that were mounted before the suspend. In particular, you MUST NOT
+ MOUNT any journaled filesystems mounted before the suspend or they
+ will get corrupted in a nasty way.
- (For now, swsusp is incompatible with PAE aka HIGHMEM_64G on i386.
- we need identity mapping for resume to work, and that is trivial
- to get with 4MB pages, but less than trivial on PAE).
+ For more information take a look at <file:Documentation/power/swsusp.txt>.
config PM_STD_PARTITION
string "Default resume partition"
diff --git a/kernel/power/console.c b/kernel/power/console.c
index 623786d4415..89bcf4973ee 100644
--- a/kernel/power/console.c
+++ b/kernel/power/console.c
@@ -27,7 +27,15 @@ int pm_prepare_console(void)
return 1;
}
- set_console(SUSPEND_CONSOLE);
+ if (set_console(SUSPEND_CONSOLE)) {
+ /*
+ * We're unable to switch to the SUSPEND_CONSOLE.
+ * Let the calling function know so it can decide
+ * what to do.
+ */
+ release_console_sem();
+ return 1;
+ }
release_console_sem();
if (vt_waitactive(SUSPEND_CONSOLE)) {
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 406b20adb27..02e4fb69111 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -39,7 +39,13 @@ static inline int platform_prepare(void)
{
int error = 0;
- if (pm_disk_mode == PM_DISK_PLATFORM) {
+ switch (pm_disk_mode) {
+ case PM_DISK_TEST:
+ case PM_DISK_TESTPROC:
+ case PM_DISK_SHUTDOWN:
+ case PM_DISK_REBOOT:
+ break;
+ default:
if (pm_ops && pm_ops->prepare)
error = pm_ops->prepare(PM_SUSPEND_DISK);
}
@@ -48,40 +54,48 @@ static inline int platform_prepare(void)
/**
* power_down - Shut machine down for hibernate.
- * @mode: Suspend-to-disk mode
*
- * Use the platform driver, if configured so, and return gracefully if it
- * fails.
- * Otherwise, try to power off and reboot. If they fail, halt the machine,
- * there ain't no turning back.
+ * Use the platform driver, if configured so; otherwise try
+ * to power off or reboot.
*/
-static void power_down(suspend_disk_method_t mode)
+static void power_down(void)
{
- switch(mode) {
- case PM_DISK_PLATFORM:
- if (pm_ops && pm_ops->enter) {
- kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
- pm_ops->enter(PM_SUSPEND_DISK);
- break;
- }
+ switch (pm_disk_mode) {
+ case PM_DISK_TEST:
+ case PM_DISK_TESTPROC:
+ break;
case PM_DISK_SHUTDOWN:
kernel_power_off();
break;
case PM_DISK_REBOOT:
kernel_restart(NULL);
break;
+ default:
+ if (pm_ops && pm_ops->enter) {
+ kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+ pm_ops->enter(PM_SUSPEND_DISK);
+ break;
+ }
}
kernel_halt();
- /* Valid image is on the disk, if we continue we risk serious data corruption
- after resume. */
+ /*
+ * Valid image is on the disk, if we continue we risk serious data
+ * corruption after resume.
+ */
printk(KERN_CRIT "Please power me down manually\n");
while(1);
}
static inline void platform_finish(void)
{
- if (pm_disk_mode == PM_DISK_PLATFORM) {
+ switch (pm_disk_mode) {
+ case PM_DISK_TEST:
+ case PM_DISK_TESTPROC:
+ case PM_DISK_SHUTDOWN:
+ case PM_DISK_REBOOT:
+ break;
+ default:
if (pm_ops && pm_ops->finish)
pm_ops->finish(PM_SUSPEND_DISK);
}
@@ -108,8 +122,6 @@ static int prepare_processes(void)
/**
* pm_suspend_disk - The granpappy of hibernation power management.
*
- * If we're going through the firmware, then get it over with quickly.
- *
* If not, then call swsusp to do its thing, then figure out how
* to power down the system.
*/
@@ -166,7 +178,7 @@ int pm_suspend_disk(void)
pr_debug("PM: writing image.\n");
error = swsusp_write();
if (!error)
- power_down(pm_disk_mode);
+ power_down();
else {
swsusp_free();
goto Thaw;
@@ -240,12 +252,6 @@ static int software_resume(void)
goto Done;
}
- error = platform_prepare();
- if (error) {
- swsusp_free();
- goto Thaw;
- }
-
pr_debug("PM: Reading swsusp image.\n");
error = swsusp_read();
@@ -268,7 +274,6 @@ static int software_resume(void)
enable_nonboot_cpus();
Free:
swsusp_free();
- platform_finish();
device_resume();
resume_console();
Thaw:
@@ -285,7 +290,6 @@ late_initcall(software_resume);
static const char * const pm_disk_modes[] = {
- [PM_DISK_FIRMWARE] = "firmware",
[PM_DISK_PLATFORM] = "platform",
[PM_DISK_SHUTDOWN] = "shutdown",
[PM_DISK_REBOOT] = "reboot",
@@ -296,27 +300,25 @@ static const char * const pm_disk_modes[] = {
/**
* disk - Control suspend-to-disk mode
*
- * Suspend-to-disk can be handled in several ways. The greatest
- * distinction is who writes memory to disk - the firmware or the OS.
- * If the firmware does it, we assume that it also handles suspending
- * the system.
- * If the OS does it, then we have three options for putting the system
- * to sleep - using the platform driver (e.g. ACPI or other PM registers),
- * powering off the system or rebooting the system (for testing).
+ * Suspend-to-disk can be handled in several ways. We have a few options
+ * for putting the system to sleep - using the platform driver (e.g. ACPI
+ * or other pm_ops), powering off the system or rebooting the system
+ * (for testing) as well as the two test modes.
*
- * The system will support either 'firmware' or 'platform', and that is
- * known a priori (and encoded in pm_ops). But, the user may choose
- * 'shutdown' or 'reboot' as alternatives.
+ * The system can support 'platform', and that is known a priori (and
+ * encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot'
+ * as alternatives, as well as the test modes 'test' and 'testproc'.
*
* show() will display what the mode is currently set to.
* store() will accept one of
*
- * 'firmware'
* 'platform'
* 'shutdown'
* 'reboot'
+ * 'test'
+ * 'testproc'
*
- * It will only change to 'firmware' or 'platform' if the system
+ * It will only change to 'platform' if the system
* supports it (as determined from pm_ops->pm_disk_mode).
*/
@@ -338,17 +340,21 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
len = p ? p - buf : n;
mutex_lock(&pm_mutex);
- for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) {
+ for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
if (!strncmp(buf, pm_disk_modes[i], len)) {
mode = i;
break;
}
}
if (mode) {
- if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
- mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
+ switch (mode) {
+ case PM_DISK_SHUTDOWN:
+ case PM_DISK_REBOOT:
+ case PM_DISK_TEST:
+ case PM_DISK_TESTPROC:
pm_disk_mode = mode;
- } else {
+ break;
+ default:
if (pm_ops && pm_ops->enter &&
(mode == pm_ops->pm_disk_mode))
pm_disk_mode = mode;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index e1c41312046..72419a3b1be 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -30,7 +30,7 @@
DEFINE_MUTEX(pm_mutex);
struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
+suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
/**
* pm_set_ops - Set the global power method table.
@@ -41,9 +41,26 @@ void pm_set_ops(struct pm_ops * ops)
{
mutex_lock(&pm_mutex);
pm_ops = ops;
+ if (ops && ops->pm_disk_mode != PM_DISK_INVALID) {
+ pm_disk_mode = ops->pm_disk_mode;
+ } else
+ pm_disk_mode = PM_DISK_SHUTDOWN;
mutex_unlock(&pm_mutex);
}
+/**
+ * pm_valid_only_mem - generic memory-only valid callback
+ *
+ * pm_ops drivers that implement mem suspend only and only need
+ * to check for that in their .valid callback can use this instead
+ * of rolling their own .valid callback.
+ */
+int pm_valid_only_mem(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM;
+}
+
+
static inline void pm_finish(suspend_state_t state)
{
if (pm_ops->finish)
@@ -111,13 +128,24 @@ static int suspend_prepare(suspend_state_t state)
return error;
}
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+{
+ local_irq_disable();
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+{
+ local_irq_enable();
+}
int suspend_enter(suspend_state_t state)
{
int error = 0;
- unsigned long flags;
- local_irq_save(flags);
+ arch_suspend_disable_irqs();
+ BUG_ON(!irqs_disabled());
if ((error = device_power_down(PMSG_SUSPEND))) {
printk(KERN_ERR "Some devices failed to power down\n");
@@ -126,7 +154,8 @@ int suspend_enter(suspend_state_t state)
error = pm_ops->enter(state);
device_power_up();
Done:
- local_irq_restore(flags);
+ arch_suspend_enable_irqs();
+ BUG_ON(irqs_disabled());
return error;
}
@@ -167,7 +196,10 @@ static inline int valid_state(suspend_state_t state)
if (state == PM_SUSPEND_DISK)
return 1;
- if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
+ /* all other states need lowlevel support and need to be
+ * valid to the lowlevel implementation, no valid callback
+ * implies that none are valid. */
+ if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
return 0;
return 1;
}
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 7fb834397a0..175370824f3 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -229,13 +229,13 @@ int swsusp_shrink_memory(void)
size += highmem_size;
for_each_zone (zone)
if (populated_zone(zone)) {
+ tmp += snapshot_additional_pages(zone);
if (is_highmem(zone)) {
highmem_size -=
zone_page_state(zone, NR_FREE_PAGES);
} else {
tmp -= zone_page_state(zone, NR_FREE_PAGES);
tmp += zone->lowmem_reserve[ZONE_NORMAL];
- tmp += snapshot_additional_pages(zone);
}
}
diff --git a/kernel/power/user.c b/kernel/power/user.c
index dd09efe7df5..7cf6713b232 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -368,9 +368,12 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
if (error) {
printk(KERN_ERR "Failed to suspend some devices.\n");
} else {
- /* Enter S3, system is already frozen */
- suspend_enter(PM_SUSPEND_MEM);
-
+ error = disable_nonboot_cpus();
+ if (!error) {
+ /* Enter S3, system is already frozen */
+ suspend_enter(PM_SUSPEND_MEM);
+ enable_nonboot_cpus();
+ }
/* Wake up devices */
device_resume();
}
diff --git a/kernel/printk.c b/kernel/printk.c
index 0c151877ff7..4b47e59248d 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -54,7 +54,7 @@ int console_printk[4] = {
};
/*
- * Low lever drivers may need that to know if they can schedule in
+ * Low level drivers may need that to know if they can schedule in
* their unblank() callback or not. So let's export it.
*/
int oops_in_progress;
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 482b11ff65c..bcd14e83ef3 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -60,19 +60,19 @@ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
static char *torture_type = "rcu"; /* What RCU implementation to torture. */
-module_param(nreaders, int, 0);
+module_param(nreaders, int, 0444);
MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-module_param(nfakewriters, int, 0);
+module_param(nfakewriters, int, 0444);
MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-module_param(stat_interval, int, 0);
+module_param(stat_interval, int, 0444);
MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-module_param(verbose, bool, 0);
+module_param(verbose, bool, 0444);
MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-module_param(test_no_idle_hz, bool, 0);
+module_param(test_no_idle_hz, bool, 0444);
MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-module_param(shuffle_interval, int, 0);
+module_param(shuffle_interval, int, 0444);
MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-module_param(torture_type, charp, 0);
+module_param(torture_type, charp, 0444);
MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
#define TORTURE_FLAG "-torture:"
diff --git a/kernel/relay.c b/kernel/relay.c
index ef8a935710a..577f251c7e2 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -474,13 +474,12 @@ static void setup_callbacks(struct rchan *chan,
}
/**
- *
* relay_hotcpu_callback - CPU hotplug callback
* @nb: notifier block
* @action: hotplug action to take
* @hcpu: CPU number
*
- * Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD)
+ * Returns the success/failure of the operation. (%NOTIFY_OK, %NOTIFY_BAD)
*/
static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
unsigned long action,
diff --git a/kernel/resource.c b/kernel/resource.c
index bdb55a33f96..9bd14fd3e6d 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -213,27 +213,6 @@ int request_resource(struct resource *root, struct resource *new)
EXPORT_SYMBOL(request_resource);
/**
- * ____request_resource - reserve a resource, with resource conflict returned
- * @root: root resource descriptor
- * @new: resource descriptor desired by caller
- *
- * Returns:
- * On success, NULL is returned.
- * On error, a pointer to the conflicting resource is returned.
- */
-struct resource *____request_resource(struct resource *root, struct resource *new)
-{
- struct resource *conflict;
-
- write_lock(&resource_lock);
- conflict = __request_resource(root, new);
- write_unlock(&resource_lock);
- return conflict;
-}
-
-EXPORT_SYMBOL(____request_resource);
-
-/**
* release_resource - release a previously reserved resource
* @old: resource pointer
*/
diff --git a/kernel/sched.c b/kernel/sched.c
index 0dc757246d8..960d7c5fca3 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3006,23 +3006,6 @@ static inline void idle_balance(int cpu, struct rq *rq)
}
#endif
-static inline void wake_priority_sleeper(struct rq *rq)
-{
-#ifdef CONFIG_SCHED_SMT
- if (!rq->nr_running)
- return;
-
- spin_lock(&rq->lock);
- /*
- * If an SMT sibling task has been put to sleep for priority
- * reasons reschedule the idle task to see if it can now run.
- */
- if (rq->nr_running)
- resched_task(rq->idle);
- spin_unlock(&rq->lock);
-#endif
-}
-
DEFINE_PER_CPU(struct kernel_stat, kstat);
EXPORT_PER_CPU_SYMBOL(kstat);
@@ -3239,10 +3222,7 @@ void scheduler_tick(void)
update_cpu_clock(p, rq, now);
- if (p == rq->idle)
- /* Task on the idle queue */
- wake_priority_sleeper(rq);
- else
+ if (p != rq->idle)
task_running_tick(rq, p);
#ifdef CONFIG_SMP
update_load(rq);
@@ -3251,136 +3231,6 @@ void scheduler_tick(void)
#endif
}
-#ifdef CONFIG_SCHED_SMT
-static inline void wakeup_busy_runqueue(struct rq *rq)
-{
- /* If an SMT runqueue is sleeping due to priority reasons wake it up */
- if (rq->curr == rq->idle && rq->nr_running)
- resched_task(rq->idle);
-}
-
-/*
- * Called with interrupt disabled and this_rq's runqueue locked.
- */
-static void wake_sleeping_dependent(int this_cpu)
-{
- struct sched_domain *tmp, *sd = NULL;
- int i;
-
- for_each_domain(this_cpu, tmp) {
- if (tmp->flags & SD_SHARE_CPUPOWER) {
- sd = tmp;
- break;
- }
- }
-
- if (!sd)
- return;
-
- for_each_cpu_mask(i, sd->span) {
- struct rq *smt_rq = cpu_rq(i);
-
- if (i == this_cpu)
- continue;
- if (unlikely(!spin_trylock(&smt_rq->lock)))
- continue;
-
- wakeup_busy_runqueue(smt_rq);
- spin_unlock(&smt_rq->lock);
- }
-}
-
-/*
- * number of 'lost' timeslices this task wont be able to fully
- * utilize, if another task runs on a sibling. This models the
- * slowdown effect of other tasks running on siblings:
- */
-static inline unsigned long
-smt_slice(struct task_struct *p, struct sched_domain *sd)
-{
- return p->time_slice * (100 - sd->per_cpu_gain) / 100;
-}
-
-/*
- * To minimise lock contention and not have to drop this_rq's runlock we only
- * trylock the sibling runqueues and bypass those runqueues if we fail to
- * acquire their lock. As we only trylock the normal locking order does not
- * need to be obeyed.
- */
-static int
-dependent_sleeper(int this_cpu, struct rq *this_rq, struct task_struct *p)
-{
- struct sched_domain *tmp, *sd = NULL;
- int ret = 0, i;
-
- /* kernel/rt threads do not participate in dependent sleeping */
- if (!p->mm || rt_task(p))
- return 0;
-
- for_each_domain(this_cpu, tmp) {
- if (tmp->flags & SD_SHARE_CPUPOWER) {
- sd = tmp;
- break;
- }
- }
-
- if (!sd)
- return 0;
-
- for_each_cpu_mask(i, sd->span) {
- struct task_struct *smt_curr;
- struct rq *smt_rq;
-
- if (i == this_cpu)
- continue;
-
- smt_rq = cpu_rq(i);
- if (unlikely(!spin_trylock(&smt_rq->lock)))
- continue;
-
- smt_curr = smt_rq->curr;
-
- if (!smt_curr->mm)
- goto unlock;
-
- /*
- * If a user task with lower static priority than the
- * running task on the SMT sibling is trying to schedule,
- * delay it till there is proportionately less timeslice
- * left of the sibling task to prevent a lower priority
- * task from using an unfair proportion of the
- * physical cpu's resources. -ck
- */
- if (rt_task(smt_curr)) {
- /*
- * With real time tasks we run non-rt tasks only
- * per_cpu_gain% of the time.
- */
- if ((jiffies % DEF_TIMESLICE) >
- (sd->per_cpu_gain * DEF_TIMESLICE / 100))
- ret = 1;
- } else {
- if (smt_curr->static_prio < p->static_prio &&
- !TASK_PREEMPTS_CURR(p, smt_rq) &&
- smt_slice(smt_curr, sd) > task_timeslice(p))
- ret = 1;
- }
-unlock:
- spin_unlock(&smt_rq->lock);
- }
- return ret;
-}
-#else
-static inline void wake_sleeping_dependent(int this_cpu)
-{
-}
-static inline int
-dependent_sleeper(int this_cpu, struct rq *this_rq, struct task_struct *p)
-{
- return 0;
-}
-#endif
-
#if defined(CONFIG_PREEMPT) && defined(CONFIG_DEBUG_PREEMPT)
void fastcall add_preempt_count(int val)
@@ -3507,7 +3357,6 @@ need_resched_nonpreemptible:
if (!rq->nr_running) {
next = rq->idle;
rq->expired_timestamp = 0;
- wake_sleeping_dependent(cpu);
goto switch_tasks;
}
}
@@ -3547,8 +3396,6 @@ need_resched_nonpreemptible:
}
}
next->sleep_type = SLEEP_NORMAL;
- if (dependent_sleeper(cpu, rq, next))
- next = rq->idle;
switch_tasks:
if (next == rq->idle)
schedstat_inc(rq, sched_goidle);
@@ -3566,7 +3413,7 @@ switch_tasks:
sched_info_switch(prev, next);
if (likely(prev != next)) {
- next->timestamp = now;
+ next->timestamp = next->last_ran = now;
rq->nr_switches++;
rq->curr = next;
++*switch_count;
@@ -4840,32 +4687,10 @@ out_unlock:
return retval;
}
-static inline struct task_struct *eldest_child(struct task_struct *p)
-{
- if (list_empty(&p->children))
- return NULL;
- return list_entry(p->children.next,struct task_struct,sibling);
-}
-
-static inline struct task_struct *older_sibling(struct task_struct *p)
-{
- if (p->sibling.prev==&p->parent->children)
- return NULL;
- return list_entry(p->sibling.prev,struct task_struct,sibling);
-}
-
-static inline struct task_struct *younger_sibling(struct task_struct *p)
-{
- if (p->sibling.next==&p->parent->children)
- return NULL;
- return list_entry(p->sibling.next,struct task_struct,sibling);
-}
-
static const char stat_nam[] = "RSDTtZX";
static void show_task(struct task_struct *p)
{
- struct task_struct *relative;
unsigned long free = 0;
unsigned state;
@@ -4891,19 +4716,7 @@ static void show_task(struct task_struct *p)
free = (unsigned long)n - (unsigned long)end_of_stack(p);
}
#endif
- printk("%5lu %5d %6d ", free, p->pid, p->parent->pid);
- if ((relative = eldest_child(p)))
- printk("%5d ", relative->pid);
- else
- printk(" ");
- if ((relative = younger_sibling(p)))
- printk("%7d", relative->pid);
- else
- printk(" ");
- if ((relative = older_sibling(p)))
- printk(" %5d", relative->pid);
- else
- printk(" ");
+ printk("%5lu %5d %6d", free, p->pid, p->parent->pid);
if (!p->mm)
printk(" (L-TLB)\n");
else
@@ -4933,7 +4746,7 @@ void show_state_filter(unsigned long state_filter)
* console might take alot of time:
*/
touch_nmi_watchdog();
- if (p->state & state_filter)
+ if (!state_filter || (p->state & state_filter))
show_task(p);
} while_each_thread(g, p);
diff --git a/kernel/signal.c b/kernel/signal.c
index e2a7d4bf7d5..3670225ecbc 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1140,7 +1140,8 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
return error;
}
-static int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
+int
+kill_proc_info(int sig, struct siginfo *info, pid_t pid)
{
int error;
rcu_read_lock();
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 3ca1d5ff031..c904748f229 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -846,7 +846,8 @@ static ctl_table vm_table[] = {
.extra2 = &one_hundred,
},
#endif
-#ifdef CONFIG_X86_32
+#if defined(CONFIG_X86_32) || \
+ (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
{
.ctl_name = VM_VDSO_ENABLED,
.procname = "vdso_enabled",
@@ -1359,8 +1360,7 @@ void unregister_sysctl_table(struct ctl_table_header * header)
}
#else /* !CONFIG_SYSCTL */
-struct ctl_table_header * register_sysctl_table(ctl_table * table,
- int insert_at_head)
+struct ctl_table_header *register_sysctl_table(ctl_table * table)
{
return NULL;
}
@@ -1676,7 +1676,7 @@ static int proc_dointvec_taint(ctl_table *table, int write, struct file *filp,
{
int op;
- if (!capable(CAP_SYS_ADMIN))
+ if (write && !capable(CAP_SYS_ADMIN))
return -EPERM;
op = OP_OR;
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 4c3476fa058..ad7d2392cb0 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -102,7 +102,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
*/
static int send_reply(struct sk_buff *skb, pid_t pid)
{
- struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+ struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
void *reply = genlmsg_data(genlhdr);
int rc;
@@ -121,7 +121,7 @@ static int send_reply(struct sk_buff *skb, pid_t pid)
static void send_cpu_listeners(struct sk_buff *skb,
struct listener_list *listeners)
{
- struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+ struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
struct listener *s, *tmp;
struct sk_buff *skb_next, *skb_cur = skb;
void *reply = genlmsg_data(genlhdr);
diff --git a/kernel/time.c b/kernel/time.c
index c6c80ea5d0e..ba18ec4899b 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -452,6 +452,7 @@ struct timespec ns_to_timespec(const s64 nsec)
return ts;
}
+EXPORT_SYMBOL(ns_to_timespec);
/**
* ns_to_timeval - Convert nanoseconds to timeval
@@ -469,6 +470,7 @@ struct timeval ns_to_timeval(const s64 nsec)
return tv;
}
+EXPORT_SYMBOL(ns_to_timeval);
/*
* Convert jiffies to milliseconds and back.
@@ -635,6 +637,7 @@ timeval_to_jiffies(const struct timeval *value)
(((u64)usec * USEC_CONVERSION + USEC_ROUND) >>
(USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
}
+EXPORT_SYMBOL(timeval_to_jiffies);
void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
{
@@ -649,6 +652,7 @@ void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
tv_usec /= NSEC_PER_USEC;
value->tv_usec = tv_usec;
}
+EXPORT_SYMBOL(jiffies_to_timeval);
/*
* Convert jiffies/jiffies_64 to clock_t and back.
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 67932ea78c1..76212b2a99d 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -274,72 +274,3 @@ void clockevents_notify(unsigned long reason, void *arg)
}
EXPORT_SYMBOL_GPL(clockevents_notify);
-#ifdef CONFIG_SYSFS
-
-/**
- * clockevents_show_registered - sysfs interface for listing clockevents
- * @dev: unused
- * @buf: char buffer to be filled with clock events list
- *
- * Provides sysfs interface for listing registered clock event devices
- */
-static ssize_t clockevents_show_registered(struct sys_device *dev, char *buf)
-{
- struct list_head *tmp;
- char *p = buf;
- int cpu;
-
- spin_lock(&clockevents_lock);
-
- list_for_each(tmp, &clockevent_devices) {
- struct clock_event_device *ce;
-
- ce = list_entry(tmp, struct clock_event_device, list);
- p += sprintf(p, "%-20s F:%04x M:%d", ce->name,
- ce->features, ce->mode);
- p += sprintf(p, " C:");
- if (!cpus_equal(ce->cpumask, cpu_possible_map)) {
- for_each_cpu_mask(cpu, ce->cpumask)
- p += sprintf(p, " %d", cpu);
- } else {
- /*
- * FIXME: Add the cpu which is handling this sucker
- */
- }
- p += sprintf(p, "\n");
- }
-
- spin_unlock(&clockevents_lock);
-
- return p - buf;
-}
-
-/*
- * Sysfs setup bits:
- */
-static SYSDEV_ATTR(registered, 0600,
- clockevents_show_registered, NULL);
-
-static struct sysdev_class clockevents_sysclass = {
- set_kset_name("clockevents"),
-};
-
-static struct sys_device clockevents_sys_device = {
- .id = 0,
- .cls = &clockevents_sysclass,
-};
-
-static int __init clockevents_sysfs_init(void)
-{
- int error = sysdev_class_register(&clockevents_sysclass);
-
- if (!error)
- error = sysdev_register(&clockevents_sys_device);
- if (!error)
- error = sysdev_create_file(
- &clockevents_sys_device,
- &attr_registered);
- return error;
-}
-device_initcall(clockevents_sysfs_init);
-#endif
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 193a0793af9..fe5c7db2424 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -55,16 +55,18 @@ static DEFINE_SPINLOCK(clocksource_lock);
static char override_name[32];
static int finished_booting;
-/* clocksource_done_booting - Called near the end of bootup
+/* clocksource_done_booting - Called near the end of core bootup
*
- * Hack to avoid lots of clocksource churn at boot time
+ * Hack to avoid lots of clocksource churn at boot time.
+ * We use fs_initcall because we want this to start before
+ * device_initcall but after subsys_initcall.
*/
static int __init clocksource_done_booting(void)
{
finished_booting = 1;
return 0;
}
-late_initcall(clocksource_done_booting);
+fs_initcall(clocksource_done_booting);
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
static LIST_HEAD(watchdog_list);
@@ -149,7 +151,8 @@ static void clocksource_check_watchdog(struct clocksource *cs)
watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
add_timer(&watchdog_timer);
}
- } else if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) {
+ } else {
+ if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
if (!watchdog || cs->rating > watchdog->rating) {
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index 3be8da8fed7..4c256fdb887 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -69,4 +69,4 @@ static int __init init_jiffies_clocksource(void)
return clocksource_register(&clocksource_jiffies);
}
-module_init(init_jiffies_clocksource);
+core_initcall(init_jiffies_clocksource);
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index eb12509e00b..cb25649c6f5 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -32,7 +32,7 @@ static u64 tick_length, tick_length_base;
/* TIME_ERROR prevents overwriting the CMOS clock */
static int time_state = TIME_OK; /* clock synchronization status */
int time_status = STA_UNSYNC; /* clock status bits */
-static long time_offset; /* time adjustment (ns) */
+static s64 time_offset; /* time adjustment (ns) */
static long time_constant = 2; /* pll time constant */
long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
@@ -196,7 +196,7 @@ void __attribute__ ((weak)) notify_arch_cmos_timer(void)
*/
int do_adjtimex(struct timex *txc)
{
- long ltemp, mtemp, save_adjust;
+ long mtemp, save_adjust, rem;
s64 freq_adj, temp64;
int result;
@@ -277,14 +277,14 @@ int do_adjtimex(struct timex *txc)
time_adjust = txc->offset;
}
else if (time_status & STA_PLL) {
- ltemp = txc->offset * NSEC_PER_USEC;
+ time_offset = txc->offset * NSEC_PER_USEC;
/*
* Scale the phase adjustment and
* clamp to the operating range.
*/
- time_offset = min(ltemp, MAXPHASE * NSEC_PER_USEC);
- time_offset = max(time_offset, -MAXPHASE * NSEC_PER_USEC);
+ time_offset = min(time_offset, (s64)MAXPHASE * NSEC_PER_USEC);
+ time_offset = max(time_offset, (s64)-MAXPHASE * NSEC_PER_USEC);
/*
* Select whether the frequency is to be controlled
@@ -297,11 +297,11 @@ int do_adjtimex(struct timex *txc)
mtemp = xtime.tv_sec - time_reftime;
time_reftime = xtime.tv_sec;
- freq_adj = (s64)time_offset * mtemp;
+ freq_adj = time_offset * mtemp;
freq_adj = shift_right(freq_adj, time_constant * 2 +
(SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
- temp64 = (s64)time_offset << (SHIFT_NSEC - SHIFT_FLL);
+ temp64 = time_offset << (SHIFT_NSEC - SHIFT_FLL);
if (time_offset < 0) {
temp64 = -temp64;
do_div(temp64, mtemp);
@@ -314,8 +314,10 @@ int do_adjtimex(struct timex *txc)
freq_adj += time_freq;
freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
- time_offset = (time_offset / NTP_INTERVAL_FREQ)
- << SHIFT_UPDATE;
+ time_offset = div_long_long_rem_signed(time_offset,
+ NTP_INTERVAL_FREQ,
+ &rem);
+ time_offset <<= SHIFT_UPDATE;
} /* STA_PLL */
} /* txc->modes & ADJ_OFFSET */
if (txc->modes & ADJ_TICK)
@@ -328,12 +330,12 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
result = TIME_ERROR;
if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
- txc->offset = save_adjust;
+ txc->offset = save_adjust;
else
- txc->offset = shift_right(time_offset, SHIFT_UPDATE)
- * NTP_INTERVAL_FREQ / 1000;
- txc->freq = (time_freq / NSEC_PER_USEC)
- << (SHIFT_USEC - SHIFT_NSEC);
+ txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) *
+ NTP_INTERVAL_FREQ / 1000;
+ txc->freq = (time_freq / NSEC_PER_USEC) <<
+ (SHIFT_USEC - SHIFT_NSEC);
txc->maxerror = time_maxerror;
txc->esterror = time_esterror;
txc->status = time_status;
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 12b3efeb9f6..eadfce2fff7 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -284,6 +284,49 @@ void tick_shutdown_broadcast(unsigned int *cpup)
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
+void tick_suspend_broadcast(void)
+{
+ struct clock_event_device *bc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tick_broadcast_lock, flags);
+
+ bc = tick_broadcast_device.evtdev;
+ if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+ clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+
+ spin_unlock_irqrestore(&tick_broadcast_lock, flags);
+}
+
+int tick_resume_broadcast(void)
+{
+ struct clock_event_device *bc;
+ unsigned long flags;
+ int broadcast = 0;
+
+ spin_lock_irqsave(&tick_broadcast_lock, flags);
+
+ bc = tick_broadcast_device.evtdev;
+
+ if (bc) {
+ switch (tick_broadcast_device.mode) {
+ case TICKDEV_MODE_PERIODIC:
+ if(!cpus_empty(tick_broadcast_mask))
+ tick_broadcast_start_periodic(bc);
+ broadcast = cpu_isset(smp_processor_id(),
+ tick_broadcast_mask);
+ break;
+ case TICKDEV_MODE_ONESHOT:
+ broadcast = tick_resume_broadcast_oneshot(bc);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&tick_broadcast_lock, flags);
+
+ return broadcast;
+}
+
+
#ifdef CONFIG_TICK_ONESHOT
static cpumask_t tick_broadcast_oneshot_mask;
@@ -311,6 +354,16 @@ static int tick_broadcast_set_event(ktime_t expires, int force)
}
}
+int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
+{
+ clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+
+ if(!cpus_empty(tick_broadcast_oneshot_mask))
+ tick_broadcast_set_event(ktime_get(), 1);
+
+ return cpu_isset(smp_processor_id(), tick_broadcast_oneshot_mask);
+}
+
/*
* Reprogram the broadcast device:
*
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 4500e347f1b..bfda3f7f071 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -77,6 +77,7 @@ static void tick_periodic(int cpu)
void tick_handle_periodic(struct clock_event_device *dev)
{
int cpu = smp_processor_id();
+ ktime_t next;
tick_periodic(cpu);
@@ -86,12 +87,12 @@ void tick_handle_periodic(struct clock_event_device *dev)
* Setup the next period for devices, which do not have
* periodic mode:
*/
+ next = ktime_add(dev->next_event, tick_period);
for (;;) {
- ktime_t next = ktime_add(dev->next_event, tick_period);
-
if (!clockevents_program_event(dev, next, ktime_get()))
return;
tick_periodic(cpu);
+ next = ktime_add(next, tick_period);
}
}
@@ -297,6 +298,29 @@ static void tick_shutdown(unsigned int *cpup)
spin_unlock_irqrestore(&tick_device_lock, flags);
}
+static void tick_suspend(void)
+{
+ struct tick_device *td = &__get_cpu_var(tick_cpu_device);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tick_device_lock, flags);
+ clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_SHUTDOWN);
+ spin_unlock_irqrestore(&tick_device_lock, flags);
+}
+
+static void tick_resume(void)
+{
+ struct tick_device *td = &__get_cpu_var(tick_cpu_device);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tick_device_lock, flags);
+ if (td->mode == TICKDEV_MODE_PERIODIC)
+ tick_setup_periodic(td->evtdev, 0);
+ else
+ tick_resume_oneshot();
+ spin_unlock_irqrestore(&tick_device_lock, flags);
+}
+
/*
* Notification about clock event devices
*/
@@ -324,6 +348,16 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
tick_shutdown(dev);
break;
+ case CLOCK_EVT_NOTIFY_SUSPEND:
+ tick_suspend();
+ tick_suspend_broadcast();
+ break;
+
+ case CLOCK_EVT_NOTIFY_RESUME:
+ if (!tick_resume_broadcast())
+ tick_resume();
+ break;
+
default:
break;
}
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index 54861a0f29f..c9d203bde51 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -19,12 +19,13 @@ extern void tick_setup_oneshot(struct clock_event_device *newdev,
extern int tick_program_event(ktime_t expires, int force);
extern void tick_oneshot_notify(void);
extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
-
+extern void tick_resume_oneshot(void);
# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
extern void tick_broadcast_oneshot_control(unsigned long reason);
extern void tick_broadcast_switch_to_oneshot(void);
extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
+extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
# else /* BROADCAST */
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{
@@ -43,6 +44,10 @@ void tick_setup_oneshot(struct clock_event_device *newdev,
{
BUG();
}
+static inline void tick_resume_oneshot(void)
+{
+ BUG();
+}
static inline int tick_program_event(ktime_t expires, int force)
{
return 0;
@@ -54,6 +59,10 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
}
static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
+static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
+{
+ return 0;
+}
#endif /* !TICK_ONESHOT */
/*
@@ -67,6 +76,8 @@ extern int tick_check_broadcast_device(struct clock_event_device *dev);
extern int tick_is_broadcast_device(struct clock_event_device *dev);
extern void tick_broadcast_on_off(unsigned long reason, int *oncpu);
extern void tick_shutdown_broadcast(unsigned int *cpup);
+extern void tick_suspend_broadcast(void);
+extern int tick_resume_broadcast(void);
extern void
tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
@@ -90,6 +101,8 @@ static inline int tick_device_uses_broadcast(struct clock_event_device *dev,
static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { }
static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
+static inline void tick_suspend_broadcast(void) { }
+static inline int tick_resume_broadcast(void) { return 0; }
/*
* Set the periodic handler in non broadcast mode
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index 2e8b7ff863c..f6997ab0c3c 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -41,6 +41,18 @@ int tick_program_event(ktime_t expires, int force)
}
/**
+ * tick_resume_onshot - resume oneshot mode
+ */
+void tick_resume_oneshot(void)
+{
+ struct tick_device *td = &__get_cpu_var(tick_cpu_device);
+ struct clock_event_device *dev = td->evtdev;
+
+ clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
+ tick_program_event(ktime_get(), 1);
+}
+
+/**
* tick_setup_oneshot - setup the event device for oneshot mode (hres or nohz)
*/
void tick_setup_oneshot(struct clock_event_device *newdev,
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 95e41f7f850..51556b95f60 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -21,6 +21,8 @@
#include <linux/sched.h>
#include <linux/tick.h>
+#include <asm/irq_regs.h>
+
#include "tick-internal.h"
/*
@@ -165,7 +167,9 @@ void tick_nohz_stop_sched_tick(void)
goto end;
cpu = smp_processor_id();
- BUG_ON(local_softirq_pending());
+ if (unlikely(local_softirq_pending()))
+ printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
+ local_softirq_pending());
now = ktime_get();
/*
@@ -191,19 +195,19 @@ void tick_nohz_stop_sched_tick(void)
next_jiffies = get_next_timer_interrupt(last_jiffies);
delta_jiffies = next_jiffies - last_jiffies;
+ if (rcu_needs_cpu(cpu))
+ delta_jiffies = 1;
/*
* Do not stop the tick, if we are only one off
* or if the cpu is required for rcu
*/
- if (!ts->tick_stopped && (delta_jiffies == 1 || rcu_needs_cpu(cpu)))
+ if (!ts->tick_stopped && delta_jiffies == 1)
goto out;
/* Schedule the tick, if we are at least one jiffie off */
if ((long)delta_jiffies >= 1) {
- if (rcu_needs_cpu(cpu))
- delta_jiffies = 1;
- else
+ if (delta_jiffies > 1)
cpu_set(cpu, nohz_cpu_mask);
/*
* nohz_stop_sched_tick can be called several times before
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index f82c635c3d5..59df5e8555a 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -194,9 +194,9 @@ print_tickdevice(struct seq_file *m, struct tick_device *td)
return;
}
SEQ_printf(m, "%s\n", dev->name);
- SEQ_printf(m, " max_delta_ns: %ld\n", dev->max_delta_ns);
- SEQ_printf(m, " min_delta_ns: %ld\n", dev->min_delta_ns);
- SEQ_printf(m, " mult: %ld\n", dev->mult);
+ SEQ_printf(m, " max_delta_ns: %lu\n", dev->max_delta_ns);
+ SEQ_printf(m, " min_delta_ns: %lu\n", dev->min_delta_ns);
+ SEQ_printf(m, " mult: %lu\n", dev->mult);
SEQ_printf(m, " shift: %d\n", dev->shift);
SEQ_printf(m, " mode: %d\n", dev->mode);
SEQ_printf(m, " next_event: %Ld nsecs\n",
diff --git a/kernel/timer.c b/kernel/timer.c
index cb1b86a9c52..b22bd39740d 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -505,6 +505,8 @@ out:
return ret;
}
+EXPORT_SYMBOL(try_to_del_timer_sync);
+
/**
* del_timer_sync - deactivate a timer and wait for the handler to finish.
* @timer: the timer to be deactivated
@@ -695,15 +697,28 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
{
ktime_t hr_delta = hrtimer_get_next_event();
struct timespec tsdelta;
+ unsigned long delta;
if (hr_delta.tv64 == KTIME_MAX)
return expires;
- if (hr_delta.tv64 <= TICK_NSEC)
- return now;
+ /*
+ * Expired timer available, let it expire in the next tick
+ */
+ if (hr_delta.tv64 <= 0)
+ return now + 1;
tsdelta = ktime_to_timespec(hr_delta);
- now += timespec_to_jiffies(&tsdelta);
+ delta = timespec_to_jiffies(&tsdelta);
+ /*
+ * Take rounding errors in to account and make sure, that it
+ * expires in the next tick. Otherwise we go into an endless
+ * ping pong due to tick_nohz_stop_sched_tick() retriggering
+ * the timer softirq
+ */
+ if (delta < 1)
+ delta = 1;
+ now += delta;
if (time_before(now, expires))
return now;
return expires;
@@ -711,6 +726,7 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
/**
* next_timer_interrupt - return the jiffy of the next pending timer
+ * @now: current time (in jiffies)
*/
unsigned long get_next_timer_interrupt(unsigned long now)
{
@@ -861,6 +877,8 @@ int do_settimeofday(struct timespec *tv)
clock->error = 0;
ntp_clear();
+ update_vsyscall(&xtime, clock);
+
write_sequnlock_irqrestore(&xtime_lock, flags);
/* signal hrtimers about time change */
@@ -908,7 +926,7 @@ static inline void change_clocksource(void) { }
#endif
/**
- * timeofday_is_continuous - check to see if timekeeping is free running
+ * timekeeping_is_continuous - check to see if timekeeping is free running
*/
int timekeeping_is_continuous(void)
{
@@ -996,8 +1014,11 @@ static int timekeeping_resume(struct sys_device *dev)
write_sequnlock_irqrestore(&xtime_lock, flags);
touch_softlockup_watchdog();
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+
/* Resume hrtimers */
- clock_was_set();
+ hres_timers_resume();
return 0;
}
@@ -1010,6 +1031,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
timekeeping_suspended = 1;
timekeeping_suspend_time = read_persistent_clock();
write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+
return 0;
}
@@ -1650,8 +1674,8 @@ static void __devinit migrate_timers(int cpu)
new_base = get_cpu_var(tvec_bases);
local_irq_disable();
- spin_lock(&new_base->lock);
- spin_lock(&old_base->lock);
+ double_spin_lock(&new_base->lock, &old_base->lock,
+ smp_processor_id() < cpu);
BUG_ON(old_base->running_timer);
@@ -1664,8 +1688,8 @@ static void __devinit migrate_timers(int cpu)
migrate_timer_list(new_base, old_base->tv5.vec + i);
}
- spin_unlock(&old_base->lock);
- spin_unlock(&new_base->lock);
+ double_spin_unlock(&new_base->lock, &old_base->lock,
+ smp_processor_id() < cpu);
local_irq_enable();
put_cpu_var(tvec_bases);
}