From c353c3fb0700a3c17ea2b0237710a184232ccd7f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Fri, 2 Feb 2007 16:39:12 +0100 Subject: Driver core: let request_module() send a /sys/modules/kmod/-uevent On recent systems, calls to /sbin/modprobe are handled by udev depending on the kind of device the kernel has discovered. This patch creates an uevent for the kernels internal request_module(), to let udev take control over the request, instead of forking the binary directly by the kernel. The direct execution of /sbin/modprobe can be disabled by setting: /sys/module/kmod/mod_request_helper (/proc/sys/kernel/modprobe) to an empty string, the same way /proc/sys/kernel/hotplug is disabled on an udev system. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- kernel/kmod.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/module.c | 26 +++++++----- kernel/params.c | 1 + 3 files changed, 137 insertions(+), 10 deletions(-) (limited to 'kernel') diff --git a/kernel/kmod.c b/kernel/kmod.c index 796276141e51..9f923f8ce6a0 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -36,6 +36,8 @@ #include #include +extern int delete_module(const char *name, unsigned int flags); + extern int max_threads; static struct workqueue_struct *khelper_wq; @@ -46,6 +48,7 @@ static struct workqueue_struct *khelper_wq; modprobe_path is set via /proc/sys. */ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; +struct module_kobject kmod_mk; /** * request_module - try to load a kernel module @@ -75,6 +78,11 @@ int request_module(const char *fmt, ...) static atomic_t kmod_concurrent = ATOMIC_INIT(0); #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; + char modalias[16 + MODULE_NAME_LEN] = "MODALIAS="; + char *uevent_envp[2] = { + modalias, + NULL + }; va_start(args, fmt); ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); @@ -82,6 +90,12 @@ int request_module(const char *fmt, ...) if (ret >= MODULE_NAME_LEN) return -ENAMETOOLONG; + strcpy(&modalias[strlen("MODALIAS=")], module_name); + kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp); + + if (modprobe_path[0] == '\0') + goto out; + /* If modprobe needs a service that is in a module, we get a recursive * loop. Limit the number of running kmod threads to max_threads/2 or * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method @@ -108,9 +122,115 @@ int request_module(const char *fmt, ...) ret = call_usermodehelper(modprobe_path, argv, envp, 1); atomic_dec(&kmod_concurrent); +out: return ret; } EXPORT_SYMBOL(request_module); + +static ssize_t store_mod_request(struct module_attribute *mattr, + struct module *mod, + const char *buffer, size_t count) +{ + char name[MODULE_NAME_LEN]; + int ret; + + if (count < 1 || count+1 > MODULE_NAME_LEN) + return -EINVAL; + memcpy(name, buffer, count); + name[count] = '\0'; + if (name[count-1] == '\n') + name[count-1] = '\0'; + + ret = request_module(name); + if (ret < 0) + return ret; + return count; +} + +static struct module_attribute mod_request = { + .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE }, + .store = store_mod_request, +}; + +#ifdef CONFIG_MODULE_UNLOAD +static ssize_t store_mod_unload(struct module_attribute *mattr, + struct module *mod, + const char *buffer, size_t count) +{ + char name[MODULE_NAME_LEN]; + int ret; + + if (count < 1 || count+1 > MODULE_NAME_LEN) + return -EINVAL; + memcpy(name, buffer, count); + name[count] = '\0'; + if (name[count-1] == '\n') + name[count-1] = '\0'; + + ret = delete_module(name, O_NONBLOCK); + if (ret < 0) + return ret; + return count; +} + +static struct module_attribute mod_unload = { + .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE }, + .store = store_mod_unload, +}; +#endif + +static ssize_t show_mod_request_helper(struct module_attribute *mattr, + struct module *mod, + char *buffer) +{ + return sprintf(buffer, "%s\n", modprobe_path); +} + +static ssize_t store_mod_request_helper(struct module_attribute *mattr, + struct module *mod, + const char *buffer, size_t count) +{ + if (count < 1 || count+1 > KMOD_PATH_LEN) + return -EINVAL; + memcpy(modprobe_path, buffer, count); + modprobe_path[count] = '\0'; + if (modprobe_path[count-1] == '\n') + modprobe_path[count-1] = '\0'; + return count; +} + +static struct module_attribute mod_request_helper = { + .attr = { + .name = "mod_request_helper", + .mode = S_IWUSR | S_IRUGO, + .owner = THIS_MODULE + }, + .show = show_mod_request_helper, + .store = store_mod_request_helper, +}; + +void __init kmod_sysfs_init(void) +{ + int ret; + + kmod_mk.mod = THIS_MODULE; + kobj_set_kset_s(&kmod_mk, module_subsys); + kobject_set_name(&kmod_mk.kobj, "kmod"); + kobject_init(&kmod_mk.kobj); + ret = kobject_add(&kmod_mk.kobj); + if (ret < 0) + goto out; + + ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr); + ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr); +#ifdef CONFIG_MODULE_UNLOAD + ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr); +#endif + + kobject_uevent(&kmod_mk.kobj, KOBJ_ADD); +out: + return; +} #endif /* CONFIG_KMOD */ struct subprocess_info { diff --git a/kernel/module.c b/kernel/module.c index 8a94e054230c..225501f620ff 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -653,20 +653,11 @@ static void wait_for_zero_refcount(struct module *mod) mutex_lock(&module_mutex); } -asmlinkage long -sys_delete_module(const char __user *name_user, unsigned int flags) +int delete_module(const char *name, unsigned int flags) { struct module *mod; - char name[MODULE_NAME_LEN]; int ret, forced = 0; - if (!capable(CAP_SYS_MODULE)) - return -EPERM; - - if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) - return -EFAULT; - name[MODULE_NAME_LEN-1] = '\0'; - if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; @@ -727,6 +718,21 @@ sys_delete_module(const char __user *name_user, unsigned int flags) return ret; } +asmlinkage long +sys_delete_module(const char __user *name_user, unsigned int flags) +{ + char name[MODULE_NAME_LEN]; + + if (!capable(CAP_SYS_MODULE)) + return -EPERM; + + if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) + return -EFAULT; + name[MODULE_NAME_LEN-1] = '\0'; + + return delete_module(name, flags); +} + static void print_unload_info(struct seq_file *m, struct module *mod) { struct module_use *use; diff --git a/kernel/params.c b/kernel/params.c index 553cf7d6a4be..7d231c6c1334 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -714,6 +714,7 @@ static int __init param_sysfs_init(void) } param_sysfs_builtin(); + kmod_sysfs_init(); return 0; } -- cgit v1.2.3 From b92be9f1ecd3c8b16e9bb22d55bb97b3d89f091a Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 14 Feb 2007 21:03:39 +0100 Subject: Driver: remove redundant kobject_unregister checks Here is a patch that removes all redundant kobject_unregister argument checks. Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/module.c b/kernel/module.c index 225501f620ff..e06b77af23fd 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1180,11 +1180,8 @@ 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); } -- cgit v1.2.3 From ef665c1a06be719ed9a6b0ad7967137258d9457a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 13 Feb 2007 15:19:06 -0800 Subject: sysfs: fix build errors: uevent with CONFIG_SYSFS=n Fix source files to build with CONFIG_SYSFS=n. module_subsys is not available. SYSFS=n, MODULES=y: T:y SYSFS=n, MODULES=n: T:y SYSFS=y, MODULES=y: T:y SYSFS=y, MODULES=n: T:y Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 14 ++++++++++---- kernel/params.c | 28 +++++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'kernel') diff --git a/kernel/module.c b/kernel/module.c index e06b77af23fd..8c25b1a04fa6 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1074,7 +1074,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; @@ -1100,7 +1101,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; @@ -1115,8 +1116,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; @@ -1139,7 +1142,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) { @@ -1175,6 +1178,7 @@ out_unreg: out: return err; } +#endif static void mod_kobject_remove(struct module *mod) { @@ -2348,6 +2352,7 @@ void print_modules(void) printk("\n"); } +#ifdef CONFIG_SYSFS static char *make_driver_name(struct device_driver *drv) { char *driver_name; @@ -2422,6 +2427,7 @@ void module_remove_driver(struct device_driver *drv) } } 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 7d231c6c1334..7a751570b56d 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 == '-') @@ -391,6 +389,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 +425,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, return len; return err; } +#endif #ifdef CONFIG_MODULES #define __modinit @@ -433,6 +433,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 +501,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 +624,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 +671,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 +686,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 */ @@ -720,6 +713,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); -- cgit v1.2.3 From c3de4b38153a201cfc8561abb093a1b482fd3abb Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 9 Feb 2007 08:11:47 -0700 Subject: Revert "[PATCH] make kernel/signal.c:kill_proc_info() static" This reverts commit d3228a887cae75ef2b8b1211c31c539bef5a5698. DeBunk this code. We need it for compat_sys_rt_sigqueueinfo. Signed-off-by: Kyle McMartin --- kernel/signal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/signal.c b/kernel/signal.c index 5630255d2e2a..8a04869402fb 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1137,7 +1137,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(); -- cgit v1.2.3 From 0bbfb7c2e4b682542a822d3af05cea0e5cb5ba81 Mon Sep 17 00:00:00 2001 From: Patrick Pletscher Date: Sat, 17 Feb 2007 20:10:16 +0100 Subject: kernel/printk.c: comment fix Signed-off-by: Patrick Pletscher Signed-off-by: Adrian Bunk --- kernel/printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/printk.c b/kernel/printk.c index 0c151877ff71..4b47e59248df 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; -- cgit v1.2.3 From a17b4ad778e1857944f5a1df95fb7758cd5cc58d Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Thu, 14 Dec 2006 11:48:47 -0500 Subject: [PATCH] minor update to rule add/delete messages (ver 2) I was looking at parsing some of these messages and found that I wanted what it was doing next to an op= for the parser to key on. Also missing was the list number and results. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- kernel/auditfilter.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 87865f8b4ce3..3749193aed8c 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 -- cgit v1.2.3 From 6a01b07fae482f9b34491b317056c89d3b96ca2e Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Fri, 19 Jan 2007 14:39:55 -0500 Subject: [PATCH] audit config lockdown The following patch adds a new mode to the audit system. It uses the audit_enabled config option to introduce the idea of audit enabled, but configuration is immutable. Any attempt to change the configuration while in this mode is audited. To change the audit rules, you'd need to reboot the machine. To use this option, you'd need a modified version of auditctl and use "-e 2". This is intended to go at the end of the audit.rules file for people that want an immutable configuration. This patch also adds "res=" to a number of configuration commands that did not have it before. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- kernel/audit.c | 216 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 157 insertions(+), 59 deletions(-) (limited to 'kernel') diff --git a/kernel/audit.c b/kernel/audit.c index d9b690ac684b..76c9a11b72d6 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. */ @@ -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, -- cgit v1.2.3 From db3495099d3d52854b13874905af6e40a91f4721 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 7 Feb 2007 01:48:00 -0500 Subject: [PATCH] AUDIT_FD_PAIR Provide an audit record of the descriptor pair returned by pipe() and socketpair(). Rewritten from the original posted to linux-audit by John D. Ramsdell Signed-off-by: Al Viro --- kernel/auditsc.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'kernel') diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 298897559ca4..359955800dd2 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; @@ -961,6 +966,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); } @@ -1814,6 +1824,36 @@ int audit_socketcall(int nargs, unsigned long *args) return 0; } +/** + * __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 -- cgit v1.2.3 From 6ba9b346e1e0eca65ec589d32de3a9fe32dc5de6 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Feb 2007 18:11:56 +0000 Subject: [PATCH] NOHZ: Fix RCU handling When a CPU is needed for RCU the tick has to continue even when it was stopped before. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- kernel/time/tick-sched.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 95e41f7f850b..9234e44fc94a 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -191,19 +191,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 -- cgit v1.2.3 From bc5393a6c9c0e70b4b43fb2fb63e3315e9a15c8f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 19 Feb 2007 18:12:05 +0000 Subject: [PATCH] NOHZ: Produce debug output instead of a BUG() The BUG_ON() in tick_nohz_stop_sched_tick() triggers on some boxen. Remove the BUG_ON and print information about the pending softirq to allow better debugging of the problem. Signed-off-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- kernel/time/tick-sched.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 9234e44fc94a..512a4a906467 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -165,7 +165,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(); /* -- cgit v1.2.3 From 346fd59bab28093276be102632f72691a2c243fe Mon Sep 17 00:00:00 2001 From: Srinivasa Ds Date: Tue, 20 Feb 2007 13:57:54 -0800 Subject: [PATCH] kprobes: list all active probes in the system This patch lists all active probes in the system by scanning through kprobe_table[]. It takes care of aggregate handlers and prints the type of the probe. Letter "k" for kprobes, "j" for jprobes, "r" for kretprobes. It also lists address of the instruction,its symbolic name(function name + offset) and the module name. One can access this file through /sys/kernel/debug/kprobes/list. Output looks like this ===================== llm40:~/a # cat /sys/kernel/debug/kprobes/list c0169ae3 r sys_read+0x0 c0169ae3 k sys_read+0x0 c01694c8 k vfs_write+0x0 c0167d20 r sys_open+0x0 f8e658a6 k reiserfs_delete_inode+0x0 reiserfs c0120f4a k do_fork+0x0 c0120f4a j do_fork+0x0 c0169b4a r sys_write+0x0 c0169b4a k sys_write+0x0 c0169622 r vfs_read+0x0 ================================= [akpm@linux-foundation.org: cleanup] [ananth@in.ibm.com: sparc build fix] Signed-off-by: Srinivasa DS Cc: Prasanna S Panchamukhi Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Signed-off-by: Ananth N Mavinakayanahalli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kprobes.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 6fcf8dd148d0..d25a9ada3f8e 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -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); - -- cgit v1.2.3 From 60e114d1134555d1813e20a8cd86304331da05c7 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Tue, 20 Feb 2007 13:58:00 -0800 Subject: [PATCH] lockdep: debug_locks check after check_chain_key In __lock_acquire check_chain_key can turn off debug_locks, so check is needed to assure proper return code. Signed-off-by: Jarek Poplawski Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/lockdep.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'kernel') diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 592c576d77a7..a08a17218dfa 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"); -- cgit v1.2.3 From 63ce18cfe685115ff8d341bae4c9204a79043cf0 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 21 Feb 2007 12:45:35 -0800 Subject: driver core: refcounting fix Fix a reference counting bug exposed by commit 725522b5453dd680412f2b6463a988e4fd148757. If driver.mod_name exists, we take a reference in module_add_driver(), and never release it. Undo that reference in module_remove_driver(). Signed-off-by: Mike Galbraith Cc: Kay Sievers Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'kernel') diff --git a/kernel/module.c b/kernel/module.c index 8c25b1a04fa6..1ecf08106381 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2425,6 +2425,12 @@ void module_remove_driver(struct device_driver *drv) kfree(driver_name); } } + /* + * Undo the additional reference we added in module_add_driver() + * via kset_find_obj() + */ + if (drv->mod_name) + kobject_put(&drv->kobj); } EXPORT_SYMBOL(module_remove_driver); #endif -- cgit v1.2.3 From 9c372d06ce9ddf65e1393f9ea22a6d6bd5f96b42 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2007 01:38:29 -0800 Subject: power management: no valid states w/o pm_ops Change /sys/power/state to not advertise any valid states (except for disk if SOFTWARE_SUSPEND is enabled) when no pm_ops have been set so userspace can easily discover what states should be available. Signed-off-by: Johannes Berg Cc: "Randy.Dunlap" Cc: Rafael J. Wysocki Cc: Pavel Macheck Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- kernel/power/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/power/main.c b/kernel/power/main.c index e1c413120469..a064dfd8877a 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -167,7 +167,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 all are valid. */ + if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state))) return 0; return 1; } -- cgit v1.2.3 From 4541ac94d0ea0b00776edd5904ac91dd6d6330f7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 20 Feb 2007 01:07:49 +0100 Subject: make kernel/kmod.c:kmod_mk static This patch makes the needlessly global struct kmod_mk static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- kernel/kmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/kmod.c b/kernel/kmod.c index 9f923f8ce6a0..f936108f2963 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -48,7 +48,7 @@ static struct workqueue_struct *khelper_wq; modprobe_path is set via /proc/sys. */ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; -struct module_kobject kmod_mk; +static struct module_kobject kmod_mk; /** * request_module - try to load a kernel module -- cgit v1.2.3 From dfff0a0671baf4e69fc676bf8150635407548288 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 23 Feb 2007 14:54:57 -0800 Subject: Revert "Driver core: let request_module() send a /sys/modules/kmod/-uevent" This reverts commit c353c3fb0700a3c17ea2b0237710a184232ccd7f. It turns out that we end up with a loop trying to load the unix module and calling netfilter to do that. Will redo the patch later to not have this loop. Acked-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- kernel/kmod.c | 120 -------------------------------------------------------- kernel/module.c | 26 +++++------- kernel/params.c | 1 - 3 files changed, 10 insertions(+), 137 deletions(-) (limited to 'kernel') diff --git a/kernel/kmod.c b/kernel/kmod.c index f936108f2963..796276141e51 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -36,8 +36,6 @@ #include #include -extern int delete_module(const char *name, unsigned int flags); - extern int max_threads; static struct workqueue_struct *khelper_wq; @@ -48,7 +46,6 @@ static struct workqueue_struct *khelper_wq; modprobe_path is set via /proc/sys. */ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; -static struct module_kobject kmod_mk; /** * request_module - try to load a kernel module @@ -78,11 +75,6 @@ int request_module(const char *fmt, ...) static atomic_t kmod_concurrent = ATOMIC_INIT(0); #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; - char modalias[16 + MODULE_NAME_LEN] = "MODALIAS="; - char *uevent_envp[2] = { - modalias, - NULL - }; va_start(args, fmt); ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); @@ -90,12 +82,6 @@ int request_module(const char *fmt, ...) if (ret >= MODULE_NAME_LEN) return -ENAMETOOLONG; - strcpy(&modalias[strlen("MODALIAS=")], module_name); - kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp); - - if (modprobe_path[0] == '\0') - goto out; - /* If modprobe needs a service that is in a module, we get a recursive * loop. Limit the number of running kmod threads to max_threads/2 or * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method @@ -122,115 +108,9 @@ int request_module(const char *fmt, ...) ret = call_usermodehelper(modprobe_path, argv, envp, 1); atomic_dec(&kmod_concurrent); -out: return ret; } EXPORT_SYMBOL(request_module); - -static ssize_t store_mod_request(struct module_attribute *mattr, - struct module *mod, - const char *buffer, size_t count) -{ - char name[MODULE_NAME_LEN]; - int ret; - - if (count < 1 || count+1 > MODULE_NAME_LEN) - return -EINVAL; - memcpy(name, buffer, count); - name[count] = '\0'; - if (name[count-1] == '\n') - name[count-1] = '\0'; - - ret = request_module(name); - if (ret < 0) - return ret; - return count; -} - -static struct module_attribute mod_request = { - .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE }, - .store = store_mod_request, -}; - -#ifdef CONFIG_MODULE_UNLOAD -static ssize_t store_mod_unload(struct module_attribute *mattr, - struct module *mod, - const char *buffer, size_t count) -{ - char name[MODULE_NAME_LEN]; - int ret; - - if (count < 1 || count+1 > MODULE_NAME_LEN) - return -EINVAL; - memcpy(name, buffer, count); - name[count] = '\0'; - if (name[count-1] == '\n') - name[count-1] = '\0'; - - ret = delete_module(name, O_NONBLOCK); - if (ret < 0) - return ret; - return count; -} - -static struct module_attribute mod_unload = { - .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE }, - .store = store_mod_unload, -}; -#endif - -static ssize_t show_mod_request_helper(struct module_attribute *mattr, - struct module *mod, - char *buffer) -{ - return sprintf(buffer, "%s\n", modprobe_path); -} - -static ssize_t store_mod_request_helper(struct module_attribute *mattr, - struct module *mod, - const char *buffer, size_t count) -{ - if (count < 1 || count+1 > KMOD_PATH_LEN) - return -EINVAL; - memcpy(modprobe_path, buffer, count); - modprobe_path[count] = '\0'; - if (modprobe_path[count-1] == '\n') - modprobe_path[count-1] = '\0'; - return count; -} - -static struct module_attribute mod_request_helper = { - .attr = { - .name = "mod_request_helper", - .mode = S_IWUSR | S_IRUGO, - .owner = THIS_MODULE - }, - .show = show_mod_request_helper, - .store = store_mod_request_helper, -}; - -void __init kmod_sysfs_init(void) -{ - int ret; - - kmod_mk.mod = THIS_MODULE; - kobj_set_kset_s(&kmod_mk, module_subsys); - kobject_set_name(&kmod_mk.kobj, "kmod"); - kobject_init(&kmod_mk.kobj); - ret = kobject_add(&kmod_mk.kobj); - if (ret < 0) - goto out; - - ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr); - ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr); -#ifdef CONFIG_MODULE_UNLOAD - ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr); -#endif - - kobject_uevent(&kmod_mk.kobj, KOBJ_ADD); -out: - return; -} #endif /* CONFIG_KMOD */ struct subprocess_info { diff --git a/kernel/module.c b/kernel/module.c index 1ecf08106381..f77e893e4620 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -653,11 +653,20 @@ static void wait_for_zero_refcount(struct module *mod) mutex_lock(&module_mutex); } -int delete_module(const char *name, unsigned int flags) +asmlinkage long +sys_delete_module(const char __user *name_user, unsigned int flags) { struct module *mod; + char name[MODULE_NAME_LEN]; int ret, forced = 0; + if (!capable(CAP_SYS_MODULE)) + return -EPERM; + + if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) + return -EFAULT; + name[MODULE_NAME_LEN-1] = '\0'; + if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; @@ -718,21 +727,6 @@ int delete_module(const char *name, unsigned int flags) return ret; } -asmlinkage long -sys_delete_module(const char __user *name_user, unsigned int flags) -{ - char name[MODULE_NAME_LEN]; - - if (!capable(CAP_SYS_MODULE)) - return -EPERM; - - if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) - return -EFAULT; - name[MODULE_NAME_LEN-1] = '\0'; - - return delete_module(name, flags); -} - static void print_unload_info(struct seq_file *m, struct module *mod) { struct module_use *use; diff --git a/kernel/params.c b/kernel/params.c index 7a751570b56d..e265b13195b1 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -707,7 +707,6 @@ static int __init param_sysfs_init(void) } param_sysfs_builtin(); - kmod_sysfs_init(); return 0; } -- cgit v1.2.3 From 2a786b452eba900324c29a8fcf5c96d5b1c01000 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 23 Feb 2007 04:46:20 -0700 Subject: [PATCH] genirq: Mask irqs when migrating them. move_native_irqs tries to do the right thing when migrating irqs by disabling them. However disabling them is a software logical thing, not a hardware thing. This has always been a little flaky and after Ingo's latest round of changes it is guaranteed to not mask the apic. So this patch fixes move_native_irq to directly call the mask and unmask chip methods to guarantee that we mask the irq when we are migrating it. We must do this as it is required by all code that call into the path. Since we don't know the masked status when IRQ_DISABLED is set so we will not be able to restore it. The patch makes the code just give up and trying again the next time this routing is called. Signed-off-by: Eric W. Biederman Acked-by: Suresh Siddha Signed-off-by: Linus Torvalds --- kernel/irq/migration.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index 4baa3bbcd25a..77b7acc875c5 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); } -- cgit v1.2.3 From 9e203bcc1051cac2a8b15c3ee9db4c0d05794abe Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 24 Feb 2007 22:10:13 -0800 Subject: [TIME] tick-sched: Add missing asm/irq_regs.h include. Acked-by: Thomas Gleixner Signed-off-by: David S. Miller --- kernel/time/tick-sched.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'kernel') diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 512a4a906467..51556b95f60f 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -21,6 +21,8 @@ #include #include +#include + #include "tick-internal.h" /* -- cgit v1.2.3 From 3494c16676a21e7e53e21b08a0a469a38df6dcfb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 24 Feb 2007 22:11:42 -0800 Subject: [TICK] tick-common: Fix one-shot handling in tick_handle_periodic(). When clockevents_program_event() is given an expire time in the past, it does not update dev->next_event, so this looping code would loop forever once the first in-the-past expiration time was used. Keep advancing "next" locally to fix this bug. Acked-by: Thomas Gleixner Signed-off-by: David S. Miller --- kernel/time/tick-common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 4500e347f1bb..0986a2bfab49 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); } } -- cgit v1.2.3 From 9d6346311418d12e90cca9384e5fbbe2ffa18efb Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 28 Feb 2007 20:12:07 -0800 Subject: [PATCH] update timekeeping_is_continuous comment Signed-off-by: Daniel Walker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/timer.c b/kernel/timer.c index cb1b86a9c52f..d033313bf53c 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -908,7 +908,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) { -- cgit v1.2.3 From 05fb6bf0b29552b64dc86f405a484de2514e0ac2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 28 Feb 2007 20:12:13 -0800 Subject: [PATCH] kernel-doc fixes for 2.6.20-git15 (non-drivers) Fix kernel-doc warnings in 2.6.20-git15 (lib/, mm/, kernel/, include/). Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/relay.c | 3 +-- kernel/timer.c | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/relay.c b/kernel/relay.c index ef8a935710a2..577f251c7e28 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/timer.c b/kernel/timer.c index d033313bf53c..6663a87f7304 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -711,6 +711,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) { -- cgit v1.2.3 From c1e16aa2792a129d8920e22210ef21eb62a0f80a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 28 Feb 2007 20:12:19 -0800 Subject: [PATCH] Fix posix-cpu-timer breakage caused by stale p->last_ran value Problem description at: http://bugzilla.kernel.org/show_bug.cgi?id=8048 Commit b18ec80396834497933d77b81ec0918519f4e2a7 [PATCH] sched: improve migration accuracy optimized the scheduler time calculations, but broke posix-cpu-timers. The problem is that the p->last_ran value is not updated after a context switch. So a subsequent call to current_sched_time() calculates with a stale p->last_ran value, i.e. accounts the full time, which the task was scheduled away. Signed-off-by: Thomas Gleixner Acked-by: Ingo Molnar Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/sched.c b/kernel/sched.c index 0dc757246d89..0c5ebf59b8bc 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3566,7 +3566,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; -- cgit v1.2.3 From 93a6fefe2f6fc380870c0985b246bec7f37a06f7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 28 Feb 2007 20:12:23 -0800 Subject: [PATCH] fix the SYSCTL=n compilation /home/bunk/linux/kernel-2.6/linux-2.6.20-mm2/kernel/sysctl.c:1411: error: conflicting types for 'register_sysctl_table' /home/bunk/linux/kernel-2.6/linux-2.6.20-mm2/include/linux/sysctl.h:1042: error: previous declaration of 'register_sysctl_table' was here make[2]: *** [kernel/sysctl.o] Error 1 Caused by commit 0b4d414714f0d2f922d39424b0c5c82ad900a381. Signed-off-by: Adrian Bunk Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sysctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3ca1d5ff0319..34b2301276ce 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1359,8 +1359,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; } -- cgit v1.2.3 From 1499993cc7bfd568f471bd697499cff394e46822 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Wed, 28 Feb 2007 20:12:31 -0800 Subject: [PATCH] fix section mismatch warning in lockdep lockdep_init() is marked __init but used in several places outside __init code. This causes following warnings: $ scripts/mod/modpost kernel/lockdep.o WARNING: kernel/built-in.o - Section mismatch: reference to .init.text:lockdep_init from .text.lockdep_init_map after 'lockdep_init_map' (at offset 0x105) WARNING: kernel/built-in.o - Section mismatch: reference to .init.text:lockdep_init from .text.lockdep_reset_lock after 'lockdep_reset_lock' (at offset 0x35) WARNING: kernel/built-in.o - Section mismatch: reference to .init.text:lockdep_init from .text.__lock_acquire after '__lock_acquire' (at offset 0xb2) The warnings are less obviously due to heavy inlining by gcc - this is not altered. Fix the section mismatch warnings by removing the __init marking, which seems obviously wrong. Signed-off-by: Sam Ravnborg Acked-by: Ingo Molnar Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/lockdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/lockdep.c b/kernel/lockdep.c index a08a17218dfa..8dc24c92dc6d 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -2602,7 +2602,7 @@ out_restore: raw_local_irq_restore(flags); } -void __init lockdep_init(void) +void lockdep_init(void) { int i; -- cgit v1.2.3 From 7355690ead6d61f6344072ae61060f985060da29 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 28 Feb 2007 20:13:42 -0800 Subject: [PATCH] sched: fix SMT scheduler bug The SMT scheduler incorrectly skips kernel threads even if they are runnable (but they are preempted by a higher-prio user-space task which got SMT-delayed by an even higher-priority task running on a sibling CPU). Fix this for now by only doing the SMT-nice optimization if the to-be-delayed task is the only runnable task. (This should cover most of the real-life cases anyway.) This bug has been in the SMT scheduler since 2.6.17 or so, but has only been noticed now by the active check in the dynticks code. Signed-off-by: Ingo Molnar Cc: Michal Piotrowski Cc: Nick Piggin Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/sched.c b/kernel/sched.c index 0c5ebf59b8bc..5f102e6c7a4c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3547,7 +3547,7 @@ need_resched_nonpreemptible: } } next->sleep_type = SLEEP_NORMAL; - if (dependent_sleeper(cpu, rq, next)) + if (rq->nr_running == 1 && dependent_sleeper(cpu, rq, next)) next = rq->idle; switch_tasks: if (next == rq->idle) -- cgit v1.2.3 From 5c36e6578d81f79ede871d3e66a0d6beeffeb3dc Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 1 Mar 2007 10:07:42 +0900 Subject: sysctl: Support vdso_enabled sysctl on SH. All of the logic for this was already in place, we just hadn't wired it up in the sysctl table. Signed-off-by: Paul Mundt --- kernel/sysctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 34b2301276ce..1b255df4fcd0 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", -- cgit v1.2.3 From 69f7c0a1be84b10a81b6edcce2dbee0cdec26eba Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Mar 2007 00:30:29 -0800 Subject: [PATCH] sched: remove SMT nice Remove the SMT-nice feature which idles sibling cpus on SMT cpus to facilitiate nice working properly where cpu power is shared. The idling of cpus in the presence of runnable tasks is considered too fragile, easy to break with outside code, and the complexity of managing this system if an architecture comes along with many logical cores sharing cpu power will be unworkable. Remove the associated per_cpu_gain variable in sched_domains used only by this code. Also: The reason is that with dynticks enabled, this code breaks without yet further tweaks so dynticks brought on the rapid demise of this code. So either we tweak this code or kill it off entirely. It was Ingo's preference to kill it off. Either way this needs to happen for 2.6.21 since dynticks has gone in. Signed-off-by: Con Kolivas Acked-by: Ingo Molnar Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 155 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 154 deletions(-) (limited to 'kernel') diff --git a/kernel/sched.c b/kernel/sched.c index 5f102e6c7a4c..a4ca632c477c 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 (rq->nr_running == 1 && dependent_sleeper(cpu, rq, next)) - next = rq->idle; switch_tasks: if (next == rq->idle) schedstat_inc(rq, sched_goidle); -- cgit v1.2.3 From 6bb74df481223731af6c7e0ff3adb31f6442cfcd Mon Sep 17 00:00:00 2001 From: john stultz Date: Mon, 5 Mar 2007 00:30:50 -0800 Subject: [PATCH] clocksource init adjustments (fix bug #7426) This patch resolves the issue found here: http://bugme.osdl.org/show_bug.cgi?id=7426 The basic summary is: Currently we register most of i386/x86_64 clocksources at module_init time. Then we enable clocksource selection at late_initcall time. This causes some problems for drivers that use gettimeofday for init calibration routines (specifically the es1968 driver in this case), where durring module_init, the only clocksource available is the low-res jiffies clocksource. This may cause slight calibration errors, due to the small sampling time used. It should be noted that drivers that require fine grained time may not function on architectures that do not have better then jiffies resolution timekeeping (there are a few). However, this does not discount the reasonable need for such fine-grained timekeeping at init time. Thus the solution here is to register clocksources earlier (ideally when the hardware is being initialized), and then we enable clocksource selection at fs_initcall (before device_initcall). This patch should probably get some testing time in -mm, since clocksource selection is one of the most important issues for correct timekeeping, and I've only been able to test this on a few of my own boxes. Signed-off-by: John Stultz Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/time/clocksource.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 193a0793af95..5b0e46b56fd0 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); -- cgit v1.2.3 From e81ce1f7ecdaed2844c75313b09af791d44e6373 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Mar 2007 00:30:51 -0800 Subject: [PATCH] timer/hrtimer: take per cpu locks in sane order Doing something like this on a two cpu system # echo 0 > /sys/devices/system/cpu/cpu0/online # echo 1 > /sys/devices/system/cpu/cpu0/online # echo 0 > /sys/devices/system/cpu/cpu1/online will give me this: ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.21-rc2-g562aa1d4-dirty #7 ------------------------------------------------------- bash/1282 is trying to acquire lock: (&cpu_base->lock_key){.+..}, at: [<000000000005f17e>] hrtimer_cpu_notify+0xc6/0x240 but task is already holding lock: (&cpu_base->lock_key#2){.+..}, at: [<000000000005f174>] hrtimer_cpu_notify+0xbc/0x240 which lock already depends on the new lock. This happens because we have the following code in kernel/hrtimer.c: migrate_hrtimers(int cpu) [...] old_base = &per_cpu(hrtimer_bases, cpu); new_base = &get_cpu_var(hrtimer_bases); [...] spin_lock(&new_base->lock); spin_lock(&old_base->lock); Which means the spinlocks are taken in an order which depends on which cpu gets shut down from which other cpu. Therefore lockdep complains that there might be an ABBA deadlock. Since migrate_hrtimers() gets only called on cpu hotplug it's safe to assume that it isn't executed concurrently on a The same problem exists in kernel/timer.c: migrate_timers(). As pointed out by Christian Borntraeger one possible solution to avoid the locking order complaints would be to make sure that the locks are always taken in the same order. E.g. by taking the lock of the cpu with the lower number first. To achieve this we introduce two new spinlock functions double_spin_lock and double_spin_unlock which lock or unlock two locks in a given order. Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Roman Zippel Cc: John Stultz Cc: Christian Borntraeger Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/hrtimer.c | 9 ++++----- kernel/timer.c | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'kernel') diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 476cb0c0b4a4..de93a8176ca6 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1355,17 +1355,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/timer.c b/kernel/timer.c index 6663a87f7304..8ad384253ef2 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1651,8 +1651,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); @@ -1665,8 +1665,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); } -- cgit v1.2.3 From 6321dd60c76b2e12383bc06046288b15397ed3a0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 6 Mar 2007 08:25:42 +0100 Subject: [PATCH] Save/restore periodic tick information over suspend/resume The programming of periodic tick devices needs to be saved/restored across suspend/resume - otherwise we might end up with a system coming up that relies on getting a PIT (or HPET) interrupt, while those devices default to 'no interrupts' after powerup. (To confuse things it worked to a certain degree on some systems because the lapic gets initialized as a side-effect of SMP bootup.) This suspend / resume thing was dropped unintentionally during the last-minute -mm code reshuffling. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Linus Torvalds --- kernel/time/tick-broadcast.c | 36 ++++++++++++++++++++++++++++++++++++ kernel/time/tick-common.c | 32 ++++++++++++++++++++++++++++++++ kernel/time/tick-internal.h | 4 ++++ kernel/timer.c | 6 ++++++ 4 files changed, 78 insertions(+) (limited to 'kernel') diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 12b3efeb9f6f..5567745470f7 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -284,6 +284,42 @@ 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) { + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC && + !cpus_empty(tick_broadcast_mask)) + tick_broadcast_start_periodic(bc); + + broadcast = cpu_isset(smp_processor_id(), tick_broadcast_mask); + } + spin_unlock_irqrestore(&tick_broadcast_lock, flags); + + return broadcast; +} + + #ifdef CONFIG_TICK_ONESHOT static cpumask_t tick_broadcast_oneshot_mask; diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 0986a2bfab49..43ba1bdec14c 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -298,6 +298,28 @@ static void tick_shutdown(unsigned int *cpup) spin_unlock_irqrestore(&tick_device_lock, flags); } +static void tick_suspend_periodic(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) + clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_SHUTDOWN); + spin_unlock_irqrestore(&tick_device_lock, flags); +} + +static void tick_resume_periodic(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); + spin_unlock_irqrestore(&tick_device_lock, flags); +} + /* * Notification about clock event devices */ @@ -325,6 +347,16 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason, tick_shutdown(dev); break; + case CLOCK_EVT_NOTIFY_SUSPEND: + tick_suspend_periodic(); + tick_suspend_broadcast(); + break; + + case CLOCK_EVT_NOTIFY_RESUME: + if (!tick_resume_broadcast()) + tick_resume_periodic(); + break; + default: break; } diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 54861a0f29ff..75890efd24ff 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -67,6 +67,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 +92,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/timer.c b/kernel/timer.c index 8ad384253ef2..ee0a2da4aab3 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -997,6 +997,9 @@ 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(); @@ -1011,6 +1014,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; } -- cgit v1.2.3 From f8953856eb8dd62232aee6cacb46993dc2ac4869 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 6 Mar 2007 01:42:08 -0800 Subject: [PATCH] highres: do not run the TIMER_SOFTIRQ after switching to highres mode The TIMER_SOFTIRQ runs the hrtimers during bootup until a usable clocksource and clock event sources are registered. The switch to high resolution mode happens inside of the TIMER_SOFTIRQ, but runs the softirq afterwards. That way the tick emulation timer, which was set up in the switch to highres might be executed in the softirq context, which is a BUG. The rbtree has not to be touched by the softirq after the highres switch. This BUG was observed by Andres Salomon, who provided the information to debug it. Return early from the softirq, when the switch was sucessful. [dilinger@debian.org: add debug warning] [akpm@linux-foundation.org: make debug warning compile] Signed-off-by: Thomas Gleixner Cc: Andres Salomon Acked-by: Ingo Molnar Signed-off-by: Andres Salomon Acked-by: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/hrtimer.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index de93a8176ca6..ec4cb9f3e3b7 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -540,19 +540,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 +565,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) @@ -1130,6 +1131,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 +1177,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); -- cgit v1.2.3 From 90675a27fa3eb0e97f1d040b183cceb44316e669 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 6 Mar 2007 01:42:11 -0800 Subject: [PATCH] fix vsyscall settimeofday I've only seen this on x86_64. The vsyscall state only gets updated when a timer interrupts comes in. So if the time is set long before the next timer, there will be a period when a gettimeofday() won't reflect the correct time. I added an explicit update_vsyscall() during the settimeofday(), that way the vsyscall state doesn't get stale. Signed-off-by: Daniel Walker Cc: Thomas Gleixner Acked-by: Ingo Molnar Acked-by: John Stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/timer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'kernel') diff --git a/kernel/timer.c b/kernel/timer.c index ee0a2da4aab3..797cccb86431 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -862,6 +862,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 */ -- cgit v1.2.3 From d6ad67112a78623025632865d716b2f7645874c5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 6 Mar 2007 01:42:13 -0800 Subject: [PATCH] Publish rcutorture module parameters via sysfs, read-only rcutorture's module parameters currently use permissions of 0, so they don't show up in /sys/module/rcutorture/parameters. Change the permissions on all module parameters to world-readable (0444). rcutorture does all of its initialization and thread startup when loaded and relies on the parameters not changing during execution, so they should not permit writing. However, reading seems fine. Signed-off-by: Josh Triplett Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'kernel') diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 482b11ff65cb..bcd14e83ef39 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:" -- cgit v1.2.3 From c7276fde27bca89798f33c0be9543dc108468788 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 6 Mar 2007 01:42:24 -0800 Subject: [PATCH] kconfig: Update swsusp description Update the outdated and inaccurate description of the software suspend in Kconfig. Signed-off-by: Rafael J. Wysocki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/power/Kconfig | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'kernel') diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 95f6657fff73..51a4dd0f1b74 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