aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
Commit message (Expand)AuthorAge
* Merge branch 'locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...Linus Torvalds2009-06-10
|\
| * mutex: add atomic_dec_and_mutex_lock(), fixAndrew Morton2009-04-30
| * locking, rtmutex.c: Documentation cleanupLuis Henriques2009-04-29
* | Merge branch 'futexes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...Linus Torvalds2009-06-10
|\ \
| * | futex: fix restart in wait_requeue_piThomas Gleixner2009-05-20
| * | futex: fix restart for early wakeup in futex_wait_requeue_pi()Thomas Gleixner2009-05-20
| * | futex: cleanup error exitThomas Gleixner2009-05-20
| * | Merge branch 'core/urgent' into core/futexesThomas Gleixner2009-05-20
| |\ \
| * | | futex: remove the wait queueThomas Gleixner2009-05-15
| * | | futex: remove FUTEX_REQUEUE_PI (non CMP)Darren Hart2009-04-30
| * | | futex: fix futex_wait_setup key handlingDarren Hart2009-04-10
| * | | futex: fixup unlocked requeue pi caseDarren Hart2009-04-08
| * | | futex: add requeue_pi functionalityDarren Hart2009-04-06
| * | | futex: split out futex value validation codeDarren Hart2009-04-06
| * | | futex: distangle futex_requeue()Darren Hart2009-04-06
| * | | futex: add FUTEX_HAS_TIMEOUT flag to restart.futex.flagsDarren Hart2009-04-06
| * | | rt_mutex: add proxy lock routinesDarren Hart2009-04-06
| * | | futex: split out fixup owner logic from futex_lock_pi()Darren Hart2009-04-06
| * | | futex: split out atomic logic from futex_lock_pi()Darren Hart2009-04-06
| * | | futex: add helper to find the top prio waiter of a futexDarren Hart2009-04-06
| * | | futex: separate futex_wait_queue_me() logic from futex_wait()Darren Hart2009-04-06
* | | | Merge branch 'x86-xen-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...Linus Torvalds2009-06-10
|\ \ \ \
| * \ \ \ Merge branch 'x86/urgent' into x86/xenIngo Molnar2009-05-08
| |\ \ \ \
| * \ \ \ \ Merge commit 'origin/master' into for-linus/xen/masterJeremy Fitzhardinge2009-04-07
| |\ \ \ \ \
| * | | | | | x86/paravirt: finish change from lazy cpu to context switch start/endJeremy Fitzhardinge2009-03-30
| * | | | | | x86/pvops: replace arch_enter_lazy_cpu_mode with arch_start_context_switchJeremy Fitzhardinge2009-03-30
* | | | | | | Merge branch 'sched-docs-for-linus' of git://git.kernel.org/pub/scm/linux/ker...Linus Torvalds2009-06-10
|\ \ \ \ \ \ \
| * | | | | | | sched: Document memory barriers implied by sleep/wake-up primitivesDavid Howells2009-04-29
| | |_|_|_|_|/ | |/| | | | |
* | | | | | | Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/ker...Linus Torvalds2009-06-10
|\ \ \ \ \ \ \
| * | | | | | | sched: properly define the sched_group::cpumask and sched_domain::span fieldsIngo Molnar2009-05-19
| * | | | | | | sched, timers: cleanup avenrun usersThomas Gleixner2009-05-15
| * | | | | | | sched, timers: move calc_load() to schedulerThomas Gleixner2009-05-15
| * | | | | | | Merge commit 'v2.6.30-rc5' into sched/coreIngo Molnar2009-05-11
| |\ \ \ \ \ \ \
| * | | | | | | | sched: emit thread info flags with stack traceDavid Rientjes2009-05-07
| * | | | | | | | sched: rt: document the risk of small values in the bandwidth settingsPeter Zijlstra2009-05-05
| * | | | | | | | sched: Replace first_cpu() with cpumask_first() in ILB nomination codeGautham R Shenoy2009-04-21
| * | | | | | | | sched: remove extra call overhead for schedule()Peter Zijlstra2009-04-20
| * | | | | | | | sched: use group_first_cpu() instead of cpumask_first(sched_group_cpus())Miao Xie2009-04-15
| * | | | | | | | wait: don't use __wake_up_common()Johannes Weiner2009-04-14
| * | | | | | | | sched: Nominate a power-efficient ilb in select_nohz_balancer()Gautham R Shenoy2009-04-14
| * | | | | | | | sched: Nominate idle load balancer from a semi-idle package.Gautham R Shenoy2009-04-14
| * | | | | | | | sched: remove redundant hierarchy walk in check_preempt_wakeupPaul Turner2009-04-09
* | | | | | | | | Merge branch 'x86-kbuild-for-linus' of git://git.kernel.org/pub/scm/linux/ker...Linus Torvalds2009-06-10
|\ \ \ \ \ \ \ \ \
| * | | | | | | | | x86: add extension fields for bootloader type and versionH. Peter Anvin2009-05-11
* | | | | | | | | | Merge branch 'irq-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...Linus Torvalds2009-06-10
|\ \ \ \ \ \ \ \ \ \
| * \ \ \ \ \ \ \ \ \ Merge branch 'linus' into irq/numaIngo Molnar2009-06-01
| |\ \ \ \ \ \ \ \ \ \
| * | | | | | | | | | | sparseirq: Allow early irq_desc allocationPaul Mundt2009-05-23
| * | | | | | | | | | | Merge branch 'x86/apic' into irq/numaIngo Molnar2009-05-12
| |\ \ \ \ \ \ \ \ \ \ \ | | | |_|_|/ / / / / / / | | |/| | | | | | | | |
| * | | | | | | | | | | x86/irq: use move_irq_desc() in create_irq_nr()Yinghai Lu2009-05-01
| * | | | | | | | | | | x86/irq: change irq_desc_alloc() to take node instead of cpuYinghai Lu2009-04-28
dynamic_netconsole_init(void) { config_group_init(&netconsole_subsys.su_group); mutex_init(&netconsole_subsys.su_mutex); return configfs_register_subsystem(&netconsole_subsys); } static void __exit dynamic_netconsole_exit(void) { configfs_unregister_subsystem(&netconsole_subsys); } /* * Targets that were created by parsing the boot/module option string * do not exist in the configfs hierarchy (and have NULL names) and will * never go away, so make these a no-op for them. */ static void netconsole_target_get(struct netconsole_target *nt) { if (config_item_name(&nt->item)) config_item_get(&nt->item); } static void netconsole_target_put(struct netconsole_target *nt) { if (config_item_name(&nt->item)) config_item_put(&nt->item); } #else /* !CONFIG_NETCONSOLE_DYNAMIC */ static int __init dynamic_netconsole_init(void) { return 0; } static void __exit dynamic_netconsole_exit(void) { } /* * No danger of targets going away from under us when dynamic * reconfigurability is off. */ static void netconsole_target_get(struct netconsole_target *nt) { } static void netconsole_target_put(struct netconsole_target *nt) { } #endif /* CONFIG_NETCONSOLE_DYNAMIC */ /* Allocate new target (from boot/module param) and setup netpoll for it */ static struct netconsole_target *alloc_param_target(char *target_config) { int err = -ENOMEM; struct netconsole_target *nt; /* * Allocate and initialize with defaults. * Note that these targets get their config_item fields zeroed-out. */ nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) { printk(KERN_ERR "netconsole: failed to allocate memory\n"); goto fail; } nt->np.name = "netconsole"; strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Parse parameters and setup netpoll */ err = netpoll_parse_options(&nt->np, target_config); if (err) goto fail; err = netpoll_setup(&nt->np); if (err) goto fail; nt->enabled = 1; return nt; fail: kfree(nt); return ERR_PTR(err); } /* Cleanup netpoll for given target (from boot/module param) and free it */ static void free_param_target(struct netconsole_target *nt) { netpoll_cleanup(&nt->np); kfree(nt); } #ifdef CONFIG_NETCONSOLE_DYNAMIC /* * Our subsystem hierarchy is: * * /sys/kernel/config/netconsole/ * | * <target>/ * | enabled * | dev_name * | local_port * | remote_port * | local_ip * | remote_ip * | local_mac * | remote_mac * | * <target>/... */ struct netconsole_target_attr { struct configfs_attribute attr; ssize_t (*show)(struct netconsole_target *nt, char *buf); ssize_t (*store)(struct netconsole_target *nt, const char *buf, size_t count); }; static struct netconsole_target *to_target(struct config_item *item) { return item ? container_of(item, struct netconsole_target, item) : NULL; } /* * Attribute operations for netconsole_target. */ static ssize_t show_enabled(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); } static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); } static ssize_t show_local_port(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port); } static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port); } static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip); } static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip); } static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) { struct net_device *dev = nt->np.dev; static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) { return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac); } /* * This one is special -- targets created through the configfs interface * are not enabled (and the corresponding netpoll activated) by default. * The user is expected to set the desired parameters first (which * would enable him to dynamically add new netpoll targets for new * network interfaces as and when they come up). */ static ssize_t store_enabled(struct netconsole_target *nt, const char *buf, size_t count) { int enabled; int err; err = kstrtoint(buf, 10, &enabled); if (err < 0) return err; if (enabled < 0 || enabled > 1) return -EINVAL; if (enabled) { /* 1 */ /* * Skip netpoll_parse_options() -- all the attributes are * already configured via configfs. Just print them out. */ netpoll_print_options(&nt->np); err = netpoll_setup(&nt->np); if (err) return err; printk(KERN_INFO "netconsole: network logging started\n"); } else { /* 0 */ netpoll_cleanup(&nt->np); } nt->enabled = enabled; return strnlen(buf, count); } static ssize_t store_dev_name(struct netconsole_target *nt, const char *buf, size_t count) { size_t len; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } strlcpy(nt->np.dev_name, buf, IFNAMSIZ); /* Get rid of possible trailing newline from echo(1) */ len = strnlen(nt->np.dev_name, IFNAMSIZ); if (nt->np.dev_name[len - 1] == '\n') nt->np.dev_name[len - 1] = '\0'; return strnlen(buf, count); } static ssize_t store_local_port(struct netconsole_target *nt, const char *buf, size_t count) { int rv; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } rv = kstrtou16(buf, 10, &nt->np.local_port); if (rv < 0) return rv; return strnlen(buf, count); } static ssize_t store_remote_port(struct netconsole_target *nt, const char *buf, size_t count) { int rv; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } rv = kstrtou16(buf, 10, &nt->np.remote_port); if (rv < 0) return rv; return strnlen(buf, count); } static ssize_t store_local_ip(struct netconsole_target *nt, const char *buf, size_t count) { if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } nt->np.local_ip = in_aton(buf); return strnlen(buf, count); } static ssize_t store_remote_ip(struct netconsole_target *nt, const char *buf, size_t count) { if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } nt->np.remote_ip = in_aton(buf); return strnlen(buf, count); } static ssize_t store_remote_mac(struct netconsole_target *nt, const char *buf, size_t count) { u8 remote_mac[ETH_ALEN]; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } if (!mac_pton(buf, remote_mac)) return -EINVAL; if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') return -EINVAL; memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); return strnlen(buf, count); } /* * Attribute definitions for netconsole_target. */ #define NETCONSOLE_TARGET_ATTR_RO(_name) \ static struct netconsole_target_attr netconsole_target_##_name = \ __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL) #define NETCONSOLE_TARGET_ATTR_RW(_name) \ static struct netconsole_target_attr netconsole_target_##_name = \ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) NETCONSOLE_TARGET_ATTR_RW(enabled); NETCONSOLE_TARGET_ATTR_RW(dev_name); NETCONSOLE_TARGET_ATTR_RW(local_port); NETCONSOLE_TARGET_ATTR_RW(remote_port); NETCONSOLE_TARGET_ATTR_RW(local_ip); NETCONSOLE_TARGET_ATTR_RW(remote_ip); NETCONSOLE_TARGET_ATTR_RO(local_mac); NETCONSOLE_TARGET_ATTR_RW(remote_mac); static struct configfs_attribute *netconsole_target_attrs[] = { &netconsole_target_enabled.attr, &netconsole_target_dev_name.attr, &netconsole_target_local_port.attr, &netconsole_target_remote_port.attr, &netconsole_target_local_ip.attr, &netconsole_target_remote_ip.attr, &netconsole_target_local_mac.attr, &netconsole_target_remote_mac.attr, NULL, }; /* * Item operations and type for netconsole_target. */ static void netconsole_target_release(struct config_item *item) { kfree(to_target(item)); } static ssize_t netconsole_target_attr_show(struct config_item *item, struct configfs_attribute *attr, char *buf) { ssize_t ret = -EINVAL; struct netconsole_target *nt = to_target(item); struct netconsole_target_attr *na = container_of(attr, struct netconsole_target_attr, attr); if (na->show) ret = na->show(nt, buf); return ret; } static ssize_t netconsole_target_attr_store(struct config_item *item, struct configfs_attribute *attr, const char *buf, size_t count) { ssize_t ret = -EINVAL; struct netconsole_target *nt = to_target(item); struct netconsole_target_attr *na = container_of(attr, struct netconsole_target_attr, attr); if (na->store) ret = na->store(nt, buf, count); return ret; } static struct configfs_item_operations netconsole_target_item_ops = { .release = netconsole_target_release, .show_attribute = netconsole_target_attr_show, .store_attribute = netconsole_target_attr_store, }; static struct config_item_type netconsole_target_type = { .ct_attrs = netconsole_target_attrs, .ct_item_ops = &netconsole_target_item_ops, .ct_owner = THIS_MODULE, }; /* * Group operations and type for netconsole_subsys. */ static struct config_item *make_netconsole_target(struct config_group *group, const char *name) { unsigned long flags; struct netconsole_target *nt; /* * Allocate and initialize with defaults. * Target is disabled at creation (enabled == 0). */ nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) { printk(KERN_ERR "netconsole: failed to allocate memory\n"); return ERR_PTR(-ENOMEM); } nt->np.name = "netconsole"; strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Initialize the config_item member */ config_item_init_type_name(&nt->item, name, &netconsole_target_type); /* Adding, but it is disabled */ spin_lock_irqsave(&target_list_lock, flags); list_add(&nt->list, &target_list); spin_unlock_irqrestore(&target_list_lock, flags); return &nt->item; } static void drop_netconsole_target(struct config_group *group, struct config_item *item) { unsigned long flags; struct netconsole_target *nt = to_target(item); spin_lock_irqsave(&target_list_lock, flags); list_del(&nt->list); spin_unlock_irqrestore(&target_list_lock, flags); /* * The target may have never been enabled, or was manually disabled * before being removed so netpoll may have already been cleaned up. */ if (nt->enabled) netpoll_cleanup(&nt->np); config_item_put(&nt->item); } static struct configfs_group_operations netconsole_subsys_group_ops = { .make_item = make_netconsole_target, .drop_item = drop_netconsole_target, }; static struct config_item_type netconsole_subsys_type = { .ct_group_ops = &netconsole_subsys_group_ops, .ct_owner = THIS_MODULE, }; /* The netconsole configfs subsystem */ static struct configfs_subsystem netconsole_subsys = { .su_group = { .cg_item = { .ci_namebuf = "netconsole", .ci_type = &netconsole_subsys_type, }, }, }; #endif /* CONFIG_NETCONSOLE_DYNAMIC */ /* Handle network interface device notifications */ static int netconsole_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { unsigned long flags; struct netconsole_target *nt; struct net_device *dev = ptr; bool stopped = false; if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || event == NETDEV_RELEASE || event == NETDEV_JOIN)) goto done; spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->np.dev == dev) { switch (event) { case NETDEV_CHANGENAME: strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); break; case NETDEV_RELEASE: case NETDEV_JOIN: case NETDEV_UNREGISTER: /* * rtnl_lock already held */ if (nt->np.dev) { spin_unlock_irqrestore( &target_list_lock, flags); __netpoll_cleanup(&nt->np); spin_lock_irqsave(&target_list_lock, flags); dev_put(nt->np.dev); nt->np.dev = NULL; netconsole_target_put(nt); } nt->enabled = 0; stopped = true; break; } } netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags); if (stopped) { printk(KERN_INFO "netconsole: network logging stopped on " "interface %s as it ", dev->name); switch (event) { case NETDEV_UNREGISTER: printk(KERN_CONT "unregistered\n"); break; case NETDEV_RELEASE: printk(KERN_CONT "released slaves\n"); break; case NETDEV_JOIN: printk(KERN_CONT "is joining a master device\n"); break; } } done: return NOTIFY_DONE; } static struct notifier_block netconsole_netdev_notifier = { .notifier_call = netconsole_netdev_event, }; static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; unsigned long flags; struct netconsole_target *nt; const char *tmp; /* Avoid taking lock and disabling interrupts unnecessarily */ if (list_empty(&target_list)) return; spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->enabled && netif_running(nt->np.dev)) { /* * We nest this inside the for-each-target loop above * so that we're able to get as much logging out to * at least one target if we die inside here, instead * of unnecessarily keeping all targets in lock-step. */ tmp = msg; for (left = len; left;) { frag = min(left, MAX_PRINT_CHUNK); netpoll_send_udp(&nt->np, tmp, frag); tmp += frag; left -= frag; } } netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags); } static struct console netconsole = { .name = "netcon", .flags = CON_ENABLED, .write = write_msg, }; static int __init init_netconsole(void) { int err; struct netconsole_target *nt, *tmp; unsigned long flags; char *target_config; char *input = config; if (strnlen(input, MAX_PARAM_LENGTH)) { while ((target_config = strsep(&input, ";"))) { nt = alloc_param_target(target_config); if (IS_ERR(nt)) { err = PTR_ERR(nt); goto fail; } /* Dump existing printks when we register */ netconsole.flags |= CON_PRINTBUFFER; spin_lock_irqsave(&target_list_lock, flags); list_add(&nt->list, &target_list); spin_unlock_irqrestore(&target_list_lock, flags); } } err = register_netdevice_notifier(&netconsole_netdev_notifier); if (err) goto fail; err = dynamic_netconsole_init(); if (err) goto undonotifier; register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); return err; undonotifier: unregister_netdevice_notifier(&netconsole_netdev_notifier); fail: printk(KERN_ERR "netconsole: cleaning up\n"); /* * Remove all targets and destroy them (only targets created * from the boot/module option exist here). Skipping the list * lock is safe here, and netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); free_param_target(nt); } return err; } static void __exit cleanup_netconsole(void) { struct netconsole_target *nt, *tmp; unregister_console(&netconsole); dynamic_netconsole_exit(); unregister_netdevice_notifier(&netconsole_netdev_notifier); /* * Targets created via configfs pin references on our module * and would first be rmdir(2)'ed from userspace. We reach * here only when they are already destroyed, and only those * created from the boot/module option are left, so remove and * destroy them. Skipping the list lock is safe here, and * netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); free_param_target(nt); } } module_init(init_netconsole); module_exit(cleanup_netconsole);