From 0bf3d5a0fb569b13fc5a05f7d5a240d2db70ac61 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 10 Nov 2010 11:45:20 +0200 Subject: OMAP: DSS: Fix documentation regarding 'vram' kernel parameter The DSS documentation didn't mention the option to give the VRAM start address. Signed-off-by: Tomi Valkeinen Signed-off-by: Paul Mundt --- Documentation/arm/OMAP/DSS | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS index 0af0e9eed5d6..888ae7b83ae4 100644 --- a/Documentation/arm/OMAP/DSS +++ b/Documentation/arm/OMAP/DSS @@ -255,9 +255,10 @@ framebuffer parameters. Kernel boot arguments --------------------- -vram= - - Amount of total VRAM to preallocate. For example, "10M". omapfb - allocates memory for framebuffers from VRAM. +vram=[,] + - Amount of total VRAM to preallocate and optionally a physical start + memory address. For example, "10M". omapfb allocates memory for + framebuffers from VRAM. omapfb.mode=:[,...] - Default video mode for specified displays. For example, -- cgit v1.2.3-59-g8ed1b From 5d0af85cd0964bb845b63d5059bb20e8f7731e65 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 28 Oct 2010 21:37:10 +0000 Subject: xfs: remove experimental tag from the delaylog option We promised to do this for 2.6.37, and the code looks stable enough to keep that promise. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder --- Documentation/filesystems/xfs-delayed-logging-design.txt | 11 ----------- fs/xfs/linux-2.6/xfs_super.c | 3 --- 2 files changed, 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/xfs-delayed-logging-design.txt b/Documentation/filesystems/xfs-delayed-logging-design.txt index 96d0df28bed3..7445bf335dae 100644 --- a/Documentation/filesystems/xfs-delayed-logging-design.txt +++ b/Documentation/filesystems/xfs-delayed-logging-design.txt @@ -794,17 +794,6 @@ designed. Roadmap: -2.6.37 Remove experimental tag from mount option - => should be roughly 6 months after initial merge - => enough time to: - => gain confidence and fix problems reported by early - adopters (a.k.a. guinea pigs) - => address worst performance regressions and undesired - behaviours - => start tuning/optimising code for parallelism - => start tuning/optimising algorithms consuming - excessive CPU time - 2.6.39 Switch default mount option to use delayed logging => should be roughly 12 months after initial merge => enough time to shake out remaining problems before next round of diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 9f3a78fe6ae4..064f964d4f3c 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -353,9 +353,6 @@ xfs_parseargs( mp->m_qflags &= ~XFS_OQUOTA_ENFD; } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) { mp->m_flags |= XFS_MOUNT_DELAYLOG; - cmn_err(CE_WARN, - "Enabling EXPERIMENTAL delayed logging feature " - "- use at your own risk.\n"); } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) { mp->m_flags &= ~XFS_MOUNT_DELAYLOG; } else if (!strcmp(this_char, "ihashsize")) { -- cgit v1.2.3-59-g8ed1b From 43e60861fe9d39740cf5b355f58fecedf0d8e9ba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Nov 2010 01:51:26 +0100 Subject: PM / OPP: Hide OPP configuration when SoCs do not provide an implementation Since the OPP API is only useful with an appropraite SoC-specific implementation there is no point in offering the ability to enable the API on general systems. Provide an ARCH_HAS OPP Kconfig symbol which masks out the option unless selected by an implementation. Signed-off-by: Mark Brown Acked-by: Nishanth Menon Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- Documentation/power/opp.txt | 3 +++ kernel/power/Kconfig | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/power/opp.txt b/Documentation/power/opp.txt index 44d87ad3cea9..cd445582d1f8 100644 --- a/Documentation/power/opp.txt +++ b/Documentation/power/opp.txt @@ -37,6 +37,9 @@ Typical usage of the OPP library is as follows: SoC framework -> modifies on required cases certain OPPs -> OPP layer -> queries to search/retrieve information -> +Architectures that provide a SoC framework for OPP should select ARCH_HAS_OPP +to make the OPP layer available. + OPP layer expects each domain to be represented by a unique device pointer. SoC framework registers a set of initial OPPs per device with the OPP layer. This list is expected to be an optimally small number typically around 5 per device. diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 29bff6117abc..a5aff3ebad38 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -246,9 +246,13 @@ config PM_OPS depends on PM_SLEEP || PM_RUNTIME default y +config ARCH_HAS_OPP + bool + config PM_OPP bool "Operating Performance Point (OPP) Layer library" depends on PM + depends on ARCH_HAS_OPP ---help--- SOCs have a standard set of tuples consisting of frequency and voltage pairs that the device will support per voltage domain. This -- cgit v1.2.3-59-g8ed1b From b17cd8d69a75f921d9d444cc3ac9b5b1d0b66ca0 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Sun, 7 Nov 2010 01:28:24 -0500 Subject: driver core: prune docs about device_interface drivers/base/intf.c was removed before the beginning of (git) time but its Documentation stuck around. Remove it. Signed-off-by: Brandon Philips Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/interface.txt | 129 ------------------------------- include/linux/cpu.h | 5 -- include/linux/node.h | 5 -- 3 files changed, 139 deletions(-) delete mode 100644 Documentation/driver-model/interface.txt (limited to 'Documentation') diff --git a/Documentation/driver-model/interface.txt b/Documentation/driver-model/interface.txt deleted file mode 100644 index c66912bfe866..000000000000 --- a/Documentation/driver-model/interface.txt +++ /dev/null @@ -1,129 +0,0 @@ - -Device Interfaces - -Introduction -~~~~~~~~~~~~ - -Device interfaces are the logical interfaces of device classes that correlate -directly to userspace interfaces, like device nodes. - -Each device class may have multiple interfaces through which you can -access the same device. An input device may support the mouse interface, -the 'evdev' interface, and the touchscreen interface. A SCSI disk would -support the disk interface, the SCSI generic interface, and possibly a raw -device interface. - -Device interfaces are registered with the class they belong to. As devices -are added to the class, they are added to each interface registered with -the class. The interface is responsible for determining whether the device -supports the interface or not. - - -Programming Interface -~~~~~~~~~~~~~~~~~~~~~ - -struct device_interface { - char * name; - rwlock_t lock; - u32 devnum; - struct device_class * devclass; - - struct list_head node; - struct driver_dir_entry dir; - - int (*add_device)(struct device *); - int (*add_device)(struct intf_data *); -}; - -int interface_register(struct device_interface *); -void interface_unregister(struct device_interface *); - - -An interface must specify the device class it belongs to. It is added -to that class's list of interfaces on registration. - - -Interfaces can be added to a device class at any time. Whenever it is -added, each device in the class is passed to the interface's -add_device callback. When an interface is removed, each device is -removed from the interface. - - -Devices -~~~~~~~ -Once a device is added to a device class, it is added to each -interface that is registered with the device class. The class -is expected to place a class-specific data structure in -struct device::class_data. The interface can use that (along with -other fields of struct device) to determine whether or not the driver -and/or device support that particular interface. - - -Data -~~~~ - -struct intf_data { - struct list_head node; - struct device_interface * intf; - struct device * dev; - u32 intf_num; -}; - -int interface_add_data(struct interface_data *); - -The interface is responsible for allocating and initializing a struct -intf_data and calling interface_add_data() to add it to the device's list -of interfaces it belongs to. This list will be iterated over when the device -is removed from the class (instead of all possible interfaces for a class). -This structure should probably be embedded in whatever per-device data -structure the interface is allocating anyway. - -Devices are enumerated within the interface. This happens in interface_add_data() -and the enumerated value is stored in the struct intf_data for that device. - -sysfs -~~~~~ -Each interface is given a directory in the directory of the device -class it belongs to: - -Interfaces get a directory in the class's directory as well: - - class/ - `-- input - |-- devices - |-- drivers - |-- mouse - `-- evdev - -When a device is added to the interface, a symlink is created that points -to the device's directory in the physical hierarchy: - - class/ - `-- input - |-- devices - | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - |-- drivers - | `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ - |-- mouse - | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - `-- evdev - `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - - -Future Plans -~~~~~~~~~~~~ -A device interface is correlated directly with a userspace interface -for a device, specifically a device node. For instance, a SCSI disk -exposes at least two interfaces to userspace: the standard SCSI disk -interface and the SCSI generic interface. It might also export a raw -device interface. - -Many interfaces have a major number associated with them and each -device gets a minor number. Or, multiple interfaces might share one -major number, and each will receive a range of minor numbers (like in -the case of input devices). - -These major and minor numbers could be stored in the interface -structure. Major and minor allocations could happen when the interface -is registered with the class, or via a helper function. - diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 4823af64e9db..5f09323ee880 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -10,11 +10,6 @@ * * CPUs are exported via sysfs in the class/cpu/devices/ * directory. - * - * Per-cpu interfaces can be implemented using a struct device_interface. - * See the following for how to do this: - * - drivers/base/intf.c - * - Documentation/driver-model/interface.txt */ #ifndef _LINUX_CPU_H_ #define _LINUX_CPU_H_ diff --git a/include/linux/node.h b/include/linux/node.h index 06292dac3eab..1466945cc9ef 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -10,11 +10,6 @@ * * Nodes are exported via driverfs in the class/node/devices/ * directory. - * - * Per-node interfaces can be implemented using a struct device_interface. - * See the following for how to do this: - * - drivers/base/intf.c - * - Documentation/driver-model/interface.txt */ #ifndef _LINUX_NODE_H_ #define _LINUX_NODE_H_ -- cgit v1.2.3-59-g8ed1b From 17a9e7bbae178d1326e4631ab6350a272349c99d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 11 Nov 2010 12:09:59 +0100 Subject: Documentation: remove anticipatory scheduler info Remove anticipatory block I/O scheduler info from Documentation/ since the code has been deleted. Signed-off-by: Randy Dunlap Reported-by: "Robert P. J. Day" Cc: Jens Axboe Signed-off-by: Jens Axboe --- Documentation/block/switching-sched.txt | 8 ++++---- Documentation/kernel-parameters.txt | 2 +- Documentation/rbtree.txt | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/switching-sched.txt b/Documentation/block/switching-sched.txt index d5af3f630814..71cfbdc0f74d 100644 --- a/Documentation/block/switching-sched.txt +++ b/Documentation/block/switching-sched.txt @@ -16,7 +16,7 @@ you can do so by typing: As of the Linux 2.6.10 kernel, it is now possible to change the IO scheduler for a given block device on the fly (thus making it possible, for instance, to set the CFQ scheduler for the system default, but -set a specific device to use the anticipatory or noop schedulers - which +set a specific device to use the deadline or noop schedulers - which can improve that device's throughput). To set a specific scheduler, simply do this: @@ -31,7 +31,7 @@ a "cat /sys/block/DEV/queue/scheduler" - the list of valid names will be displayed, with the currently selected scheduler in brackets: # cat /sys/block/hda/queue/scheduler -noop anticipatory deadline [cfq] -# echo anticipatory > /sys/block/hda/queue/scheduler +noop deadline [cfq] +# echo deadline > /sys/block/hda/queue/scheduler # cat /sys/block/hda/queue/scheduler -noop [anticipatory] deadline cfq +noop [deadline] cfq diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ed45e9802aa8..92e83e53148f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -706,7 +706,7 @@ and is between 256 and 4096 characters. It is defined in the file arch/x86/kernel/cpu/cpufreq/elanfreq.c. elevator= [IOSCHED] - Format: {"anticipatory" | "cfq" | "deadline" | "noop"} + Format: {"cfq" | "deadline" | "noop"} See Documentation/block/as-iosched.txt and Documentation/block/deadline-iosched.txt for details. diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt index 221f38be98f4..19f8278c3854 100644 --- a/Documentation/rbtree.txt +++ b/Documentation/rbtree.txt @@ -21,8 +21,8 @@ three rotations, respectively, to balance the tree), with slightly slower To quote Linux Weekly News: There are a number of red-black trees in use in the kernel. - The anticipatory, deadline, and CFQ I/O schedulers all employ - rbtrees to track requests; the packet CD/DVD driver does the same. + The deadline and CFQ I/O schedulers employ rbtrees to + track requests; the packet CD/DVD driver does the same. The high-resolution timer code uses an rbtree to organize outstanding timer requests. The ext3 filesystem tracks directory entries in a red-black tree. Virtual memory areas (VMAs) are tracked with red-black -- cgit v1.2.3-59-g8ed1b From 203f40a5a030ed4048cd40e3bd9ab5df6c5df589 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 11 Nov 2010 14:05:18 -0800 Subject: oom: document obsolete oom_adj tunable /proc/pid/oom_adj was deprecated in August 2010 with the introduction of the new oom killer heuristic. This patch copies the Documentation/feature-removal-schedule.txt entry for this tunable to the Documentation/ABI/obsolete directory so nobody misses it. Signed-off-by: David Rientjes Reported-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/obsolete/proc-pid-oom_adj | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/ABI/obsolete/proc-pid-oom_adj (limited to 'Documentation') diff --git a/Documentation/ABI/obsolete/proc-pid-oom_adj b/Documentation/ABI/obsolete/proc-pid-oom_adj new file mode 100644 index 000000000000..cf63f264ce0f --- /dev/null +++ b/Documentation/ABI/obsolete/proc-pid-oom_adj @@ -0,0 +1,22 @@ +What: /proc//oom_adj +When: August 2012 +Why: /proc//oom_adj allows userspace to influence the oom killer's + badness heuristic used to determine which task to kill when the kernel + is out of memory. + + The badness heuristic has since been rewritten since the introduction of + this tunable such that its meaning is deprecated. The value was + implemented as a bitshift on a score generated by the badness() + function that did not have any precise units of measure. With the + rewrite, the score is given as a proportion of available memory to the + task allocating pages, so using a bitshift which grows the score + exponentially is, thus, impossible to tune with fine granularity. + + A much more powerful interface, /proc//oom_score_adj, was + introduced with the oom killer rewrite that allows users to increase or + decrease the badness() score linearly. This interface will replace + /proc//oom_adj. + + A warning will be emitted to the kernel log if an application uses this + deprecated interface. After it is printed once, future warnings will be + suppressed until the kernel is rebooted. -- cgit v1.2.3-59-g8ed1b From eaf06b241b091357e72b76863ba16e89610d31bd Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Thu, 11 Nov 2010 14:05:18 -0800 Subject: Restrict unprivileged access to kernel syslog The kernel syslog contains debugging information that is often useful during exploitation of other vulnerabilities, such as kernel heap addresses. Rather than futilely attempt to sanitize hundreds (or thousands) of printk statements and simultaneously cripple useful debugging functionality, it is far simpler to create an option that prevents unprivileged users from reading the syslog. This patch, loosely based on grsecurity's GRKERNSEC_DMESG, creates the dmesg_restrict sysctl. When set to "0", the default, no restrictions are enforced. When set to "1", only users with CAP_SYS_ADMIN can read the kernel syslog via dmesg(8) or other mechanisms. [akpm@linux-foundation.org: explain the config option in kernel.txt] Signed-off-by: Dan Rosenberg Acked-by: Ingo Molnar Acked-by: Eugene Teo Acked-by: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/kernel.txt | 14 ++++++++++++++ include/linux/kernel.h | 1 + kernel/printk.c | 6 ++++++ kernel/sysctl.c | 9 +++++++++ security/Kconfig | 12 ++++++++++++ security/commoncap.c | 2 ++ 6 files changed, 44 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 3894eaa23486..209e1584c3dc 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -28,6 +28,7 @@ show up in /proc/sys/kernel: - core_uses_pid - ctrl-alt-del - dentry-state +- dmesg_restrict - domainname - hostname - hotplug @@ -213,6 +214,19 @@ to decide what to do with it. ============================================================== +dmesg_restrict: + +This toggle indicates whether unprivileged users are prevented from using +dmesg(8) to view messages from the kernel's log buffer. When +dmesg_restrict is set to (0) there are no restrictions. When +dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use +dmesg(8). + +The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default +value of dmesg_restrict. + +============================================================== + domainname & hostname: These files can be used to set the NIS/YP domainname and the diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b526947bdf48..fc3da9e4da19 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -293,6 +293,7 @@ extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, unsigned int interval_msec); extern int printk_delay_msec; +extern int dmesg_restrict; /* * Print a one-time message (analogous to WARN_ONCE() et al): diff --git a/kernel/printk.c b/kernel/printk.c index b2ebaee8c377..38e7d5868d60 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -261,6 +261,12 @@ static inline void boot_delay_msec(void) } #endif +#ifdef CONFIG_SECURITY_DMESG_RESTRICT +int dmesg_restrict = 1; +#else +int dmesg_restrict; +#endif + int do_syslog(int type, char __user *buf, int len, bool from_file) { unsigned i, j, limit, count; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c33a1edb799f..b65bf634035e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -703,6 +703,15 @@ static struct ctl_table kern_table[] = { .extra2 = &ten_thousand, }, #endif + { + .procname = "dmesg_restrict", + .data = &dmesg_restrict, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { .procname = "ngroups_max", .data = &ngroups_max, diff --git a/security/Kconfig b/security/Kconfig index bd72ae623494..e80da955e687 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -39,6 +39,18 @@ config KEYS_DEBUG_PROC_KEYS If you are unsure as to whether this is required, answer N. +config SECURITY_DMESG_RESTRICT + bool "Restrict unprivileged access to the kernel syslog" + default n + help + This enforces restrictions on unprivileged users reading the kernel + syslog via dmesg(8). + + If this option is not selected, no restrictions will be enforced + unless the dmesg_restrict sysctl is explicitly set to (1). + + If you are unsure how to answer this question, answer N. + config SECURITY bool "Enable different security models" depends on SYSFS diff --git a/security/commoncap.c b/security/commoncap.c index 5e632b4857e4..04b80f9912bf 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -895,6 +895,8 @@ int cap_syslog(int type, bool from_file) { if (type != SYSLOG_ACTION_OPEN && from_file) return 0; + if (dmesg_restrict && !capable(CAP_SYS_ADMIN)) + return -EPERM; if ((type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) return -EPERM; -- cgit v1.2.3-59-g8ed1b From 5ada28bf76752e33dce3d807bf0dfbe6d1b943ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Nov 2010 14:05:21 -0800 Subject: led-class: always implement blinking Currently, blinking LEDs can be awkward because it is not guaranteed that all LEDs implement blinking. The trigger that wants it to blink then needs to implement its own timer solution. Rather than require that, add led_blink_set() API that triggers can use. This function will attempt to use hw blinking, but if that fails implements a timer for it. To stop blinking again, brightness_set() also needs to be wrapped into API that will stop the software blink. As a result of this, the timer trigger becomes a very trivial one, and hopefully we can finally see triggers using blinking as well because it's always easy to use. Signed-off-by: Johannes Berg Acked-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/leds-class.txt | 21 +++--- drivers/leds/Kconfig | 2 +- drivers/leds/led-class.c | 105 +++++++++++++++++++++++++++++- drivers/leds/led-triggers.c | 2 +- drivers/leds/ledtrig-timer.c | 124 +++--------------------------------- drivers/net/wireless/rt2x00/Kconfig | 3 - include/linux/leds.h | 47 ++++++++++++-- 7 files changed, 171 insertions(+), 133 deletions(-) (limited to 'Documentation') diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt index 8fd5ca2ae32d..58b266bd1846 100644 --- a/Documentation/leds-class.txt +++ b/Documentation/leds-class.txt @@ -60,15 +60,18 @@ Hardware accelerated blink of LEDs Some LEDs can be programmed to blink without any CPU interaction. To support this feature, a LED driver can optionally implement the -blink_set() function (see ). If implemented, triggers can -attempt to use it before falling back to software timers. The blink_set() -function should return 0 if the blink setting is supported, or -EINVAL -otherwise, which means that LED blinking will be handled by software. - -The blink_set() function should choose a user friendly blinking -value if it is called with *delay_on==0 && *delay_off==0 parameters. In -this case the driver should give back the chosen value through delay_on -and delay_off parameters to the leds subsystem. +blink_set() function (see ). To set an LED to blinking, +however, it is better to use use the API function led_blink_set(), +as it will check and implement software fallback if necessary. + +To turn off blinking again, use the API function led_brightness_set() +as that will not just set the LED brightness but also stop any software +timers that may have been required for blinking. + +The blink_set() function should choose a user friendly blinking value +if it is called with *delay_on==0 && *delay_off==0 parameters. In this +case the driver should give back the chosen value through delay_on and +delay_off parameters to the leds subsystem. Setting the brightness to zero with brightness_set() callback function should completely turn off the LED and cancel the previously programmed diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index cc2a88d5192f..56b4b7a5ff31 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -10,7 +10,7 @@ menuconfig NEW_LEDS if NEW_LEDS config LEDS_CLASS - tristate "LED Class Support" + bool "LED Class Support" help This option enables the led sysfs class in /sys/class/leds. You'll need this to do anything useful with LEDs. If unsure, say N. diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 260660076507..211e21f34bd5 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -81,6 +81,79 @@ static struct device_attribute led_class_attrs[] = { __ATTR_NULL, }; +static void led_timer_function(unsigned long data) +{ + struct led_classdev *led_cdev = (void *)data; + unsigned long brightness; + unsigned long delay; + + if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) { + led_set_brightness(led_cdev, LED_OFF); + return; + } + + brightness = led_get_brightness(led_cdev); + if (!brightness) { + /* Time to switch the LED on. */ + brightness = led_cdev->blink_brightness; + delay = led_cdev->blink_delay_on; + } else { + /* Store the current brightness value to be able + * to restore it when the delay_off period is over. + */ + led_cdev->blink_brightness = brightness; + brightness = LED_OFF; + delay = led_cdev->blink_delay_off; + } + + led_set_brightness(led_cdev, brightness); + + mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); +} + +static void led_stop_software_blink(struct led_classdev *led_cdev) +{ + /* deactivate previous settings */ + del_timer_sync(&led_cdev->blink_timer); + led_cdev->blink_delay_on = 0; + led_cdev->blink_delay_off = 0; +} + +static void led_set_software_blink(struct led_classdev *led_cdev, + unsigned long delay_on, + unsigned long delay_off) +{ + int current_brightness; + + current_brightness = led_get_brightness(led_cdev); + if (current_brightness) + led_cdev->blink_brightness = current_brightness; + if (!led_cdev->blink_brightness) + led_cdev->blink_brightness = led_cdev->max_brightness; + + if (delay_on == led_cdev->blink_delay_on && + delay_off == led_cdev->blink_delay_off) + return; + + led_stop_software_blink(led_cdev); + + led_cdev->blink_delay_on = delay_on; + led_cdev->blink_delay_off = delay_off; + + /* never on - don't blink */ + if (!delay_on) + return; + + /* never off - just set to brightness */ + if (!delay_off) { + led_set_brightness(led_cdev, led_cdev->blink_brightness); + return; + } + + mod_timer(&led_cdev->blink_timer, jiffies + 1); +} + + /** * led_classdev_suspend - suspend an led_classdev. * @led_cdev: the led_classdev to suspend. @@ -148,6 +221,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) led_update_brightness(led_cdev); + init_timer(&led_cdev->blink_timer); + led_cdev->blink_timer.function = led_timer_function; + led_cdev->blink_timer.data = (unsigned long)led_cdev; + #ifdef CONFIG_LEDS_TRIGGERS led_trigger_set_default(led_cdev); #endif @@ -157,7 +234,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) return 0; } - EXPORT_SYMBOL_GPL(led_classdev_register); /** @@ -175,6 +251,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev) up_write(&led_cdev->trigger_lock); #endif + /* Stop blinking */ + led_brightness_set(led_cdev, LED_OFF); + device_unregister(led_cdev->dev); down_write(&leds_list_lock); @@ -183,6 +262,30 @@ void led_classdev_unregister(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_classdev_unregister); +void led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + if (led_cdev->blink_set && + led_cdev->blink_set(led_cdev, delay_on, delay_off)) + return; + + /* blink with 1 Hz as default if nothing specified */ + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + led_set_software_blink(led_cdev, *delay_on, *delay_off); +} +EXPORT_SYMBOL(led_blink_set); + +void led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + led_stop_software_blink(led_cdev); + led_cdev->brightness_set(led_cdev, brightness); +} +EXPORT_SYMBOL(led_brightness_set); + static int __init leds_init(void) { leds_class = class_create(THIS_MODULE, "leds"); diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index f1c00db88b5e..c41eb6180c9c 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -113,7 +113,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) if (led_cdev->trigger->deactivate) led_cdev->trigger->deactivate(led_cdev); led_cdev->trigger = NULL; - led_set_brightness(led_cdev, LED_OFF); + led_brightness_set(led_cdev, LED_OFF); } if (trigger) { write_lock_irqsave(&trigger->leddev_list_lock, flags); diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index 82b77bd482ff..b09bcbeade9c 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -12,73 +12,25 @@ */ #include -#include #include #include -#include -#include #include -#include -#include #include #include -#include #include "leds.h" -struct timer_trig_data { - int brightness_on; /* LED brightness during "on" period. - * (LED_OFF < brightness_on <= LED_FULL) - */ - unsigned long delay_on; /* milliseconds on */ - unsigned long delay_off; /* milliseconds off */ - struct timer_list timer; -}; - -static void led_timer_function(unsigned long data) -{ - struct led_classdev *led_cdev = (struct led_classdev *) data; - struct timer_trig_data *timer_data = led_cdev->trigger_data; - unsigned long brightness; - unsigned long delay; - - if (!timer_data->delay_on || !timer_data->delay_off) { - led_set_brightness(led_cdev, LED_OFF); - return; - } - - brightness = led_get_brightness(led_cdev); - if (!brightness) { - /* Time to switch the LED on. */ - brightness = timer_data->brightness_on; - delay = timer_data->delay_on; - } else { - /* Store the current brightness value to be able - * to restore it when the delay_off period is over. - */ - timer_data->brightness_on = brightness; - brightness = LED_OFF; - delay = timer_data->delay_off; - } - - led_set_brightness(led_cdev, brightness); - - mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); -} - static ssize_t led_delay_on_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct timer_trig_data *timer_data = led_cdev->trigger_data; - return sprintf(buf, "%lu\n", timer_data->delay_on); + return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); } static ssize_t led_delay_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct timer_trig_data *timer_data = led_cdev->trigger_data; int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); @@ -88,21 +40,7 @@ static ssize_t led_delay_on_store(struct device *dev, count++; if (count == size) { - if (timer_data->delay_on != state) { - /* the new value differs from the previous */ - timer_data->delay_on = state; - - /* deactivate previous settings */ - del_timer_sync(&timer_data->timer); - - /* try to activate hardware acceleration, if any */ - if (!led_cdev->blink_set || - led_cdev->blink_set(led_cdev, - &timer_data->delay_on, &timer_data->delay_off)) { - /* no hardware acceleration, blink via timer */ - mod_timer(&timer_data->timer, jiffies + 1); - } - } + led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off); ret = count; } @@ -113,16 +51,14 @@ static ssize_t led_delay_off_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct timer_trig_data *timer_data = led_cdev->trigger_data; - return sprintf(buf, "%lu\n", timer_data->delay_off); + return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); } static ssize_t led_delay_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct timer_trig_data *timer_data = led_cdev->trigger_data; int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); @@ -132,21 +68,7 @@ static ssize_t led_delay_off_store(struct device *dev, count++; if (count == size) { - if (timer_data->delay_off != state) { - /* the new value differs from the previous */ - timer_data->delay_off = state; - - /* deactivate previous settings */ - del_timer_sync(&timer_data->timer); - - /* try to activate hardware acceleration, if any */ - if (!led_cdev->blink_set || - led_cdev->blink_set(led_cdev, - &timer_data->delay_on, &timer_data->delay_off)) { - /* no hardware acceleration, blink via timer */ - mod_timer(&timer_data->timer, jiffies + 1); - } - } + led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state); ret = count; } @@ -158,60 +80,34 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); static void timer_trig_activate(struct led_classdev *led_cdev) { - struct timer_trig_data *timer_data; int rc; - timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); - if (!timer_data) - return; - - timer_data->brightness_on = led_get_brightness(led_cdev); - if (timer_data->brightness_on == LED_OFF) - timer_data->brightness_on = led_cdev->max_brightness; - led_cdev->trigger_data = timer_data; - - init_timer(&timer_data->timer); - timer_data->timer.function = led_timer_function; - timer_data->timer.data = (unsigned long) led_cdev; + led_cdev->trigger_data = NULL; rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); if (rc) - goto err_out; + return; rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); if (rc) goto err_out_delayon; - /* If there is hardware support for blinking, start one - * user friendly blink rate chosen by the driver. - */ - if (led_cdev->blink_set) - led_cdev->blink_set(led_cdev, - &timer_data->delay_on, &timer_data->delay_off); + led_cdev->trigger_data = (void *)1; return; err_out_delayon: device_remove_file(led_cdev->dev, &dev_attr_delay_on); -err_out: - led_cdev->trigger_data = NULL; - kfree(timer_data); } static void timer_trig_deactivate(struct led_classdev *led_cdev) { - struct timer_trig_data *timer_data = led_cdev->trigger_data; - unsigned long on = 0, off = 0; - - if (timer_data) { + if (led_cdev->trigger_data) { device_remove_file(led_cdev->dev, &dev_attr_delay_on); device_remove_file(led_cdev->dev, &dev_attr_delay_off); - del_timer_sync(&timer_data->timer); - kfree(timer_data); } - /* If there is hardware support for blinking, stop it */ - if (led_cdev->blink_set) - led_cdev->blink_set(led_cdev, &on, &off); + /* Stop blinking */ + led_brightness_set(led_cdev, LED_OFF); } static struct led_trigger timer_led_trigger = { diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index eea1ef2f502b..4396d4b9bfb9 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -221,9 +221,6 @@ config RT2X00_LIB_LEDS boolean default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) -comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00" - depends on RT2X00_LIB=y && LEDS_CLASS=m - config RT2X00_LIB_DEBUGFS bool "Ralink debugfs support" depends on RT2X00_LIB && MAC80211_DEBUGFS diff --git a/include/linux/leds.h b/include/linux/leds.h index ba6986a11663..0f19df9e37b0 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -15,6 +15,7 @@ #include #include #include +#include struct device; /* @@ -45,10 +46,14 @@ struct led_classdev { /* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); - /* Activate hardware accelerated blink, delays are in - * miliseconds and if none is provided then a sensible default - * should be chosen. The call can adjust the timings if it can't - * match the values specified exactly. */ + /* + * Activate hardware accelerated blink, delays are in milliseconds + * and if both are zero then a sensible default should be chosen. + * The call should adjust the timings in that case and if it can't + * match the values specified exactly. + * Deactivate blinking again when the brightness is set to a fixed + * value via the brightness_set() callback. + */ int (*blink_set)(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off); @@ -57,6 +62,10 @@ struct led_classdev { struct list_head node; /* LED Device list */ const char *default_trigger; /* Trigger to use */ + unsigned long blink_delay_on, blink_delay_off; + struct timer_list blink_timer; + int blink_brightness; + #ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ struct rw_semaphore trigger_lock; @@ -73,6 +82,36 @@ extern void led_classdev_unregister(struct led_classdev *led_cdev); extern void led_classdev_suspend(struct led_classdev *led_cdev); extern void led_classdev_resume(struct led_classdev *led_cdev); +/** + * led_blink_set - set blinking with software fallback + * @led_cdev: the LED to start blinking + * @delay_on: the time it should be on (in ms) + * @delay_off: the time it should ble off (in ms) + * + * This function makes the LED blink, attempting to use the + * hardware acceleration if possible, but falling back to + * software blinking if there is no hardware blinking or if + * the LED refuses the passed values. + * + * Note that if software blinking is active, simply calling + * led_cdev->brightness_set() will not stop the blinking, + * use led_classdev_brightness_set() instead. + */ +extern void led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off); +/** + * led_brightness_set - set LED brightness + * @led_cdev: the LED to set + * @brightness: the brightness to set it to + * + * Set an LED's brightness, and, if necessary, cancel the + * software blink timer that implements blinking when the + * hardware doesn't. + */ +extern void led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness); + /* * LED Triggers */ -- cgit v1.2.3-59-g8ed1b From 5991e154b2d09ad28af9dc7d3226b35dbbc052c3 Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Thu, 11 Nov 2010 14:05:23 -0800 Subject: Documentation: led drivers lp5521 and lp5523 Create sub directory Documentation/leds and add short documentation for LP5521 and LP5523 drivers. Signed-off-by: Samu Onkalo Cc: Richard Purdie Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/leds/leds-lp5521.txt | 88 ++++++++++++++++++++++++++++++++++++++ Documentation/leds/leds-lp5523.txt | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 Documentation/leds/leds-lp5521.txt create mode 100644 Documentation/leds/leds-lp5523.txt (limited to 'Documentation') diff --git a/Documentation/leds/leds-lp5521.txt b/Documentation/leds/leds-lp5521.txt new file mode 100644 index 000000000000..c4d8d151e0fe --- /dev/null +++ b/Documentation/leds/leds-lp5521.txt @@ -0,0 +1,88 @@ +Kernel driver for lp5521 +======================== + +* National Semiconductor LP5521 led driver chip +* Datasheet: http://www.national.com/pf/LP/LP5521.html + +Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo +Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) + +Description +----------- + +LP5521 can drive up to 3 channels. Leds can be controlled directly via +the led class control interface. Channels have generic names: +lp5521:channelx, where x is 0 .. 2 + +All three channels can be also controlled using the engine micro programs. +More details of the instructions can be found from the public data sheet. + +Control interface for the engines: +x is 1 .. 3 +enginex_mode : disabled, load, run +enginex_load : store program (visible only in engine load mode) + +Example (start to blink the channel 2 led): +cd /sys/class/leds/lp5521:channel2/device +echo "load" > engine3_mode +echo "037f4d0003ff6000" > engine3_load +echo "run" > engine3_mode + +stop the engine: +echo "disabled" > engine3_mode + +sysfs contains a selftest entry. +The test communicates with the chip and checks that +the clock mode is automatically set to the requested one. + +Each channel has its own led current settings. +/sys/class/leds/lp5521:channel0/led_current - RW +/sys/class/leds/lp5521:channel0/max_current - RO +Format: 10x mA i.e 10 means 1.0 mA + +example platform data: + +Note: chan_nr can have values between 0 and 2. + +static struct lp5521_led_config lp5521_led_config[] = { + { + .chan_nr = 0, + .led_current = 50, + .max_current = 130, + }, { + .chan_nr = 1, + .led_current = 0, + .max_current = 130, + }, { + .chan_nr = 2, + .led_current = 0, + .max_current = 130, + } +}; + +static int lp5521_setup(void) +{ + /* setup HW resources */ +} + +static void lp5521_release(void) +{ + /* Release HW resources */ +} + +static void lp5521_enable(bool state) +{ + /* Control of chip enable signal */ +} + +static struct lp5521_platform_data lp5521_platform_data = { + .led_config = lp5521_led_config, + .num_channels = ARRAY_SIZE(lp5521_led_config), + .clock_mode = LP5521_CLOCK_EXT, + .setup_resources = lp5521_setup, + .release_resources = lp5521_release, + .enable = lp5521_enable, +}; + +If the current is set to 0 in the platform data, that channel is +disabled and it is not visible in the sysfs. diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt new file mode 100644 index 000000000000..fad2feb8b7ce --- /dev/null +++ b/Documentation/leds/leds-lp5523.txt @@ -0,0 +1,83 @@ +Kernel driver for lp5523 +======================== + +* National Semiconductor LP5523 led driver chip +* Datasheet: http://www.national.com/pf/LP/LP5523.html + +Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo +Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) + +Description +----------- +LP5523 can drive up to 9 channels. Leds can be controlled directly via +the led class control interface. Channels have generic names: +lp5523:channelx where x is 0...8 + +The chip provides 3 engines. Each engine can control channels without +interaction from the main CPU. Details of the micro engine code can be found +from the public data sheet. Leds can be muxed to different channels. + +Control interface for the engines: +x is 1 .. 3 +enginex_mode : disabled, load, run +enginex_load : microcode load (visible only in load mode) +enginex_leds : led mux control (visible only in load mode) + +cd /sys/class/leds/lp5523:channel2/device +echo "load" > engine3_mode +echo "9d80400004ff05ff437f0000" > engine3_load +echo "111111111" > engine3_leds +echo "run" > engine3_mode + +sysfs contains a selftest entry. It measures each channel +voltage level and checks if it looks reasonable. If the level is too high, +the led is missing; if the level is too low, there is a short circuit. + +Selftest uses always the current from the platform data. + +Each channel contains led current settings. +/sys/class/leds/lp5523:channel2/led_current - RW +/sys/class/leds/lp5523:channel2/max_current - RO +Format: 10x mA i.e 10 means 1.0 mA + +Example platform data: + +Note - chan_nr can have values between 0 and 8. + +static struct lp5523_led_config lp5523_led_config[] = { + { + .chan_nr = 0, + .led_current = 50, + .max_current = 130, + }, +... + }, { + .chan_nr = 8, + .led_current = 50, + .max_current = 130, + } +}; + +static int lp5523_setup(void) +{ + /* Setup HW resources */ +} + +static void lp5523_release(void) +{ + /* Release HW resources */ +} + +static void lp5523_enable(bool state) +{ + /* Control chip enable signal */ +} + +static struct lp5523_platform_data lp5523_platform_data = { + .led_config = lp5523_led_config, + .num_channels = ARRAY_SIZE(lp5523_led_config), + .clock_mode = LP5523_CLOCK_EXT, + .setup_resources = lp5523_setup, + .release_resources = lp5523_release, + .enable = lp5523_enable, +}; -- cgit v1.2.3-59-g8ed1b From cbaf087a9f5e4721e83e8681ef328158f2298c6f Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 8 Nov 2010 09:13:48 +0000 Subject: docs: Add neigh/gc_thresh3 and route/max_size documentation. Signed-off-by: Ben Greear Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index c7165f4cb792..fe95105992c5 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -20,6 +20,15 @@ ip_no_pmtu_disc - BOOLEAN min_pmtu - INTEGER default 562 - minimum discovered Path MTU +route/max_size - INTEGER + Maximum number of routes allowed in the kernel. Increase + this when using large numbers of interfaces and/or routes. + +neigh/default/gc_thresh3 - INTEGER + Maximum number of neighbor entries allowed. Increase this + when using large numbers of interfaces and when communicating + with large numbers of directly-connected peers. + mtu_expires - INTEGER Time, in seconds, that cached PMTU information is kept. -- cgit v1.2.3-59-g8ed1b From 9a1683d1dd14d6ed35d2884c6b79ff12fc6bef39 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 15 Nov 2010 18:14:43 +0900 Subject: sh: clkfwk: Kill off unused clk_set_rate_ex(). With the refactoring of the SH7722 clock framework some time ago this abstraction has become unecessary. Kill it off before anyone else gets the bright idea to start using it. Signed-off-by: Paul Mundt --- Documentation/DocBook/sh.tmpl | 4 ---- Documentation/sh/clk.txt | 32 -------------------------------- drivers/sh/clk/core.c | 12 +++--------- include/linux/sh_clk.h | 30 ------------------------------ 4 files changed, 3 insertions(+), 75 deletions(-) delete mode 100644 Documentation/sh/clk.txt (limited to 'Documentation') diff --git a/Documentation/DocBook/sh.tmpl b/Documentation/DocBook/sh.tmpl index d858d92cf6d9..4a38f604fa66 100644 --- a/Documentation/DocBook/sh.tmpl +++ b/Documentation/DocBook/sh.tmpl @@ -79,10 +79,6 @@ - - Clock Framework Extensions -!Iinclude/linux/sh_clk.h - Machine Specific Interfaces diff --git a/Documentation/sh/clk.txt b/Documentation/sh/clk.txt deleted file mode 100644 index 114b595cfa97..000000000000 --- a/Documentation/sh/clk.txt +++ /dev/null @@ -1,32 +0,0 @@ -Clock framework on SuperH architecture - -The framework on SH extends existing API by the function clk_set_rate_ex, -which prototype is as follows: - - clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id) - -The algo_id parameter is used to specify algorithm used to recalculate clocks, -adjanced to clock, specified as first argument. It is assumed that algo_id==0 -means no changes to adjanced clock - -Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method, -if it is present in ops structure. The method should set the clock rate and adjust -all needed clocks according to the passed algo_id. -Exact values for algo_id are machine-dependent. For the sh7722, the following -values are defined: - - NO_CHANGE = 0, - IUS_N1_N1, /* I:U = N:1, U:Sh = N:1 */ - IUS_322, /* I:U:Sh = 3:2:2 */ - IUS_522, /* I:U:Sh = 5:2:2 */ - IUS_N11, /* I:U:Sh = N:1:1 */ - SB_N1, /* Sh:B = N:1 */ - SB3_N1, /* Sh:B3 = N:1 */ - SB3_32, /* Sh:B3 = 3:2 */ - SB3_43, /* Sh:B3 = 4:3 */ - SB3_54, /* Sh:B3 = 5:4 */ - BP_N1, /* B:P = N:1 */ - IP_N1 /* I:P = N:1 */ - -Each of these constants means relation between clocks that can be set via the FRQCR -register diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index cb12a8e1466b..69be6bb92323 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -454,12 +454,6 @@ unsigned long clk_get_rate(struct clk *clk) EXPORT_SYMBOL_GPL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) -{ - return clk_set_rate_ex(clk, rate, 0); -} -EXPORT_SYMBOL_GPL(clk_set_rate); - -int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) { int ret = -EOPNOTSUPP; unsigned long flags; @@ -467,7 +461,7 @@ int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) spin_lock_irqsave(&clock_lock, flags); if (likely(clk->ops && clk->ops->set_rate)) { - ret = clk->ops->set_rate(clk, rate, algo_id); + ret = clk->ops->set_rate(clk, rate, 0); if (ret != 0) goto out_unlock; } else { @@ -485,7 +479,7 @@ out_unlock: return ret; } -EXPORT_SYMBOL_GPL(clk_set_rate_ex); +EXPORT_SYMBOL_GPL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { @@ -654,7 +648,7 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) clkp->parent); if (likely(clkp->ops->set_rate)) clkp->ops->set_rate(clkp, - rate, NO_CHANGE); + rate, 0); else if (likely(clkp->ops->recalc)) clkp->rate = clkp->ops->recalc(clkp); } diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index cea0c38e7a63..30885d928801 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -67,36 +67,6 @@ int clk_register(struct clk *); void clk_unregister(struct clk *); void clk_enable_init_clocks(void); -/** - * clk_set_rate_ex - set the clock rate for a clock source, with additional parameter - * @clk: clock source - * @rate: desired clock rate in Hz - * @algo_id: algorithm id to be passed down to ops->set_rate - * - * Returns success (0) or negative errno. - */ -int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id); - -enum clk_sh_algo_id { - NO_CHANGE = 0, - - IUS_N1_N1, - IUS_322, - IUS_522, - IUS_N11, - - SB_N1, - - SB3_N1, - SB3_32, - SB3_43, - SB3_54, - - BP_N1, - - IP_N1, -}; - struct clk_div_mult_table { unsigned int *divisors; unsigned int nr_divisors; -- cgit v1.2.3-59-g8ed1b From e1e18ee1cb58228a577668284c1dd03d859d7157 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Nov 2010 22:40:38 +0100 Subject: i2c: Mark i2c_adapter.id as deprecated It's about time to make it clear that i2c_adapter.id is deprecated. Hopefully this will remind the last user to move over to a different strategy. Signed-off-by: Jean Delvare Acked-by: Jarod Wilson Acked-by: Mauro Carvalho Chehab Acked-by: Hans Verkuil --- Documentation/feature-removal-schedule.txt | 10 ++++++++++ drivers/i2c/i2c-mux.c | 1 - include/linux/i2c.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d8f36f984faa..6c2f55e05f13 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -554,3 +554,13 @@ Why: This is a legacy interface which have been replaced by a more Who: NeilBrown ---------------------------- + +What: i2c_adapter.id +When: June 2011 +Why: This field is deprecated. I2C device drivers shouldn't change their + behavior based on the underlying I2C adapter. Instead, the I2C + adapter driver should instantiate the I2C devices and provide the + needed platform-specific information. +Who: Jean Delvare + +---------------------------- diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index d32a4843fc3a..d7a4833be416 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -120,7 +120,6 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, snprintf(priv->adap.name, sizeof(priv->adap.name), "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id); priv->adap.owner = THIS_MODULE; - priv->adap.id = parent->id; priv->adap.algo = &priv->algo; priv->adap.algo_data = priv; priv->adap.dev.parent = &parent->dev; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 889b35abaeda..56cfe23ffb39 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -353,7 +353,7 @@ struct i2c_algorithm { */ struct i2c_adapter { struct module *owner; - unsigned int id; + unsigned int id __deprecated; unsigned int class; /* classes to allow probing for */ const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data; -- cgit v1.2.3-59-g8ed1b From 89c8fb7a0156f19237880c4ea576eb5add8c0d60 Mon Sep 17 00:00:00 2001 From: Vicente Jimenez Aguilar Date: Thu, 18 Nov 2010 15:01:54 +0900 Subject: fbdev: Update documentation index file. This is a simple update of the file Documentation/fb/00-INDEX based on the directory content. Signed-off-by: Vicente Jimenez Aguilar Signed-off-by: Paul Mundt --- Documentation/fb/00-INDEX | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX index a618fd99c9f0..30a70542e823 100644 --- a/Documentation/fb/00-INDEX +++ b/Documentation/fb/00-INDEX @@ -4,33 +4,41 @@ please mail me. Geert Uytterhoeven 00-INDEX - - this file + - this file. arkfb.txt - info on the fbdev driver for ARK Logic chips. aty128fb.txt - info on the ATI Rage128 frame buffer driver. cirrusfb.txt - info on the driver for Cirrus Logic chipsets. +cmap_xfbdev.txt + - an introduction to fbdev's cmap structures. deferred_io.txt - an introduction to deferred IO. +efifb.txt + - info on the EFI platform driver for Intel based Apple computers. +ep93xx-fb.txt + - info on the driver for EP93xx LCD controller. fbcon.txt - intro to and usage guide for the framebuffer console (fbcon). framebuffer.txt - introduction to frame buffer devices. -imacfb.txt - - info on the generic EFI platform driver for Intel based Macs. +gxfb.txt + - info on the framebuffer driver for AMD Geode GX2 based processors. intel810.txt - documentation for the Intel 810/815 framebuffer driver. intelfb.txt - docs for Intel 830M/845G/852GM/855GM/865G/915G/945G fb driver. internals.txt - quick overview of frame buffer device internals. +lxfb.txt + - info on the framebuffer driver for AMD Geode LX based processors. matroxfb.txt - info on the Matrox framebuffer driver for Alpha, Intel and PPC. +metronomefb.txt + - info on the driver for the Metronome display controller. modedb.txt - info on the video mode database. -matroxfb.txt - - info on the Matrox frame buffer driver. pvr2fb.txt - info on the PowerVR 2 frame buffer driver. pxafb.txt @@ -39,13 +47,23 @@ s3fb.txt - info on the fbdev driver for S3 Trio/Virge chips. sa1100fb.txt - information about the driver for the SA-1100 LCD controller. +sh7760fb.txt + - info on the SH7760/SH7763 integrated LCDC Framebuffer driver. sisfb.txt - info on the framebuffer device driver for various SiS chips. sstfb.txt - info on the frame buffer driver for 3dfx' Voodoo Graphics boards. tgafb.txt - - info on the TGA (DECChip 21030) frame buffer driver + - info on the TGA (DECChip 21030) frame buffer driver. +tridentfb.txt + info on the framebuffer driver for some Trident chip based cards. +uvesafb.txt + - info on the userspace VESA (VBE2+ compliant) frame buffer device. vesafb.txt - - info on the VESA frame buffer device + - info on the VESA frame buffer device. +viafb.modes + - list of modes for VIA Integration Graphic Chip. +viafb.txt + - info on the VIA Integration Graphic Chip console framebuffer driver. vt8623fb.txt - info on the fb driver for the graphics core in VIA VT8623 chipsets. -- cgit v1.2.3-59-g8ed1b From 09c9feb94672bdb3ca6d424a292ffc26eff8ca0b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Nov 2010 12:27:32 -0800 Subject: Documentation: make configfs example code simpler, clearer If "p" is NULL then it will cause an oops when we pass it to simple_strtoul(). In this case "p" can not be NULL so I removed the check. I also changed the check a little to make it more explicit that we are testing whether p points to the NUL char. Signed-off-by: Dan Carpenter Acked-by: Joel Becker Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/filesystems/configfs/configfs_example_explicit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/configfs/configfs_example_explicit.c b/Documentation/filesystems/configfs/configfs_example_explicit.c index d428cc9f07f3..fd53869f5633 100644 --- a/Documentation/filesystems/configfs/configfs_example_explicit.c +++ b/Documentation/filesystems/configfs/configfs_example_explicit.c @@ -89,7 +89,7 @@ static ssize_t childless_storeme_write(struct childless *childless, char *p = (char *) page; tmp = simple_strtoul(p, &p, 10); - if (!p || (*p && (*p != '\n'))) + if ((*p != '\0') && (*p != '\n')) return -EINVAL; if (tmp > INT_MAX) -- cgit v1.2.3-59-g8ed1b From ebde7b062cd9e2ea968c93f23f73dd28c0a192d1 Mon Sep 17 00:00:00 2001 From: Bernhard Walle Date: Thu, 18 Nov 2010 12:27:33 -0800 Subject: Documentation/gpio.txt: explain poll/select usage Add a bit more information how to use poll(2) on GPIO value files correctly. For me it was not clear that I need to poll(2) for POLLPRI|POLLERR or select(2) for exceptfds. Signed-off-by: Bernhard Walle Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/gpio.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 9633da01ff46..792faa3c06cf 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -617,6 +617,16 @@ and have the following read/write attributes: is configured as an output, this value may be written; any nonzero value is treated as high. + If the pin can be configured as interrupt-generating interrupt + and if it has been configured to generate interrupts (see the + description of "edge"), you can poll(2) on that file and + poll(2) will return whenever the interrupt was triggered. If + you use poll(2), set the events POLLPRI and POLLERR. If you + use select(2), set the file descriptor in exceptfds. After + poll(2) returns, either lseek(2) to the beginning of the sysfs + file and read the new value or close the file and re-open it + to read the value. + "edge" ... reads as either "none", "rising", "falling", or "both". Write these strings to select the signal edge(s) that will make poll(2) on the "value" file return. -- cgit v1.2.3-59-g8ed1b From f99e0e98f95bbe8833bd96c314b71ef859851bc5 Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Thu, 18 Nov 2010 12:27:34 -0800 Subject: Documentation: change email address for Hans Koch My old mail address doesn't exist anymore. This changes all occurrences to my new address. Signed-off-by: Hans J. Koch Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/DocBook/uio-howto.tmpl | 6 +++--- Documentation/hwmon/lm93 | 2 +- Documentation/hwmon/max6650 | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 4d4ce0e61e42..b4665b9c40b0 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -16,7 +16,7 @@
- hjk@linutronix.de + hjk@hansjkoch.de
@@ -114,7 +114,7 @@ GPL version 2. If you know of any translations for this document, or you are interested in translating it, please email me -hjk@linutronix.de. +hjk@hansjkoch.de.
@@ -171,7 +171,7 @@ interested in translating it, please email me Feedback Find something wrong with this document? (Or perhaps something right?) I would love to hear from you. Please email me at - hjk@linutronix.de. + hjk@hansjkoch.de.
diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93 index ac711f357faf..7a10616d0b44 100644 --- a/Documentation/hwmon/lm93 +++ b/Documentation/hwmon/lm93 @@ -11,7 +11,7 @@ Authors: Mark M. Hoffman Ported to 2.6 by Eric J. Bowersox Adapted to 2.6.20 by Carsten Emde - Modified for mainline integration by Hans J. Koch + Modified for mainline integration by Hans J. Koch Module Parameters ----------------- diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650 index 8be7beb9e3e8..c565650fcfc6 100644 --- a/Documentation/hwmon/max6650 +++ b/Documentation/hwmon/max6650 @@ -8,7 +8,7 @@ Supported chips: Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf Authors: - Hans J. Koch + Hans J. Koch John Morris Claus Gindhart -- cgit v1.2.3-59-g8ed1b From e4fabad30eaba5bb78cd8d47885f1b705a0918a0 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 18 Nov 2010 12:27:35 -0800 Subject: Documentation/development-process: use -next trees instead of staging This is confusing, as we have "staging" trees for drivers/staging. Call them -next trees. Signed-off-by: Andres Salomon Acked-by: Greg Kroah-Hartman Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/development-process/2.Process | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/development-process/2.Process b/Documentation/development-process/2.Process index 97726eba6102..ae8127c1a780 100644 --- a/Documentation/development-process/2.Process +++ b/Documentation/development-process/2.Process @@ -154,7 +154,7 @@ The stages that a patch goes through are, generally: inclusion, it should be accepted by a relevant subsystem maintainer - though this acceptance is not a guarantee that the patch will make it all the way to the mainline. The patch will show up in the maintainer's - subsystem tree and into the staging trees (described below). When the + subsystem tree and into the -next trees (described below). When the process works, this step leads to more extensive review of the patch and the discovery of any problems resulting from the integration of this patch with work being done by others. @@ -236,7 +236,7 @@ finding the right maintainer. Sending patches directly to Linus is not normally the right way to go. -2.4: STAGING TREES +2.4: NEXT TREES The chain of subsystem trees guides the flow of patches into the kernel, but it also raises an interesting question: what if somebody wants to look @@ -250,7 +250,7 @@ changes land in the mainline kernel. One could pull changes from all of the interesting subsystem trees, but that would be a big and error-prone job. -The answer comes in the form of staging trees, where subsystem trees are +The answer comes in the form of -next trees, where subsystem trees are collected for testing and review. The older of these trees, maintained by Andrew Morton, is called "-mm" (for memory management, which is how it got started). The -mm tree integrates patches from a long list of subsystem @@ -275,7 +275,7 @@ directory at: Use of the MMOTM tree is likely to be a frustrating experience, though; there is a definite chance that it will not even compile. -The other staging tree, started more recently, is linux-next, maintained by +The other -next tree, started more recently, is linux-next, maintained by Stephen Rothwell. The linux-next tree is, by design, a snapshot of what the mainline is expected to look like after the next merge window closes. Linux-next trees are announced on the linux-kernel and linux-next mailing -- cgit v1.2.3-59-g8ed1b From f830673f6aa28741ff6993deade587c8550c1dd3 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 18 Nov 2010 12:27:36 -0800 Subject: Documentation/development-process: more staging info Document things that I would've liked to have known when submitting a driver to gregkh for staging. Signed-off-by: Andres Salomon Acked-by: Greg Kroah-Hartman Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/development-process/2.Process | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/development-process/2.Process b/Documentation/development-process/2.Process index ae8127c1a780..911a45186340 100644 --- a/Documentation/development-process/2.Process +++ b/Documentation/development-process/2.Process @@ -303,12 +303,25 @@ volatility of linux-next tends to make it a difficult development target. See http://lwn.net/Articles/289013/ for more information on this topic, and stay tuned; much is still in flux where linux-next is involved. -Besides the mmotm and linux-next trees, the kernel source tree now contains -the drivers/staging/ directory and many sub-directories for drivers or -filesystems that are on their way to being added to the kernel tree -proper, but they remain in drivers/staging/ while they still need more -work. - +2.4.1: STAGING TREES + +The kernel source tree now contains the drivers/staging/ directory, where +many sub-directories for drivers or filesystems that are on their way to +being added to the kernel tree live. They remain in drivers/staging while +they still need more work; once complete, they can be moved into the +kernel proper. This is a way to keep track of drivers that aren't +up to Linux kernel coding or quality standards, but people may want to use +them and track development. + +Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree. +Drivers that still need work are sent to him, with each driver having +its own subdirectory in drivers/staging/. Along with the driver source +files, a TODO file should be present in the directory as well. The TODO +file lists the pending work that the driver needs for acceptance into +the kernel proper, as well as a list of people that should be Cc'd for any +patches to the driver. Staging drivers that don't currently build should +have their config entries depend upon CONFIG_BROKEN. Once they can +be successfully built without outside patches, CONFIG_BROKEN can be removed. 2.5: TOOLS -- cgit v1.2.3-59-g8ed1b From a42c390cfa0c2612459d7226ba11612847ca3a64 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Wed, 24 Nov 2010 12:57:08 -0800 Subject: cgroups: make swap accounting default behavior configurable Swap accounting can be configured by CONFIG_CGROUP_MEM_RES_CTLR_SWAP configuration option and then it is turned on by default. There is a boot option (noswapaccount) which can disable this feature. This makes it hard for distributors to enable the configuration option as this feature leads to a bigger memory consumption and this is a no-go for general purpose distribution kernel. On the other hand swap accounting may be very usuful for some workloads. This patch adds a new configuration option which controls the default behavior (CGROUP_MEM_RES_CTLR_SWAP_ENABLED). If the option is selected then the feature is turned on by default. It also adds a new boot parameter swapaccount[=1|0] which enhances the original noswapaccount parameter semantic by means of enable/disable logic (defaults to 1 if no value is provided to be still consistent with noswapaccount). The default behavior is unchanged (if CONFIG_CGROUP_MEM_RES_CTLR_SWAP is enabled then CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is enabled as well) Signed-off-by: Michal Hocko Acked-by: Daisuke Nishimura Cc: Balbir Singh Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 5 +++++ init/Kconfig | 13 +++++++++++++ mm/memcontrol.c | 21 +++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 92e83e53148f..cdd2a6e8a3b7 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2385,6 +2385,11 @@ and is between 256 and 4096 characters. It is defined in the file improve throughput, but will also increase the amount of memory reserved for use by the client. + swapaccount[=0|1] + [KNL] Enable accounting of swap in memory resource + controller if no parameter or 1 is given or disable + it if 0 is given (See Documentation/cgroups/memory.txt) + swiotlb= [IA-64] Number of I/O TLB slabs switches= [HW,M68k] diff --git a/init/Kconfig b/init/Kconfig index 88c10468db46..c9728992a776 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -613,6 +613,19 @@ config CGROUP_MEM_RES_CTLR_SWAP if boot option "noswapaccount" is set, swap will not be accounted. Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page size is 4096bytes, 512k per 1Gbytes of swap. +config CGROUP_MEM_RES_CTLR_SWAP_ENABLED + bool "Memory Resource Controller Swap Extension enabled by default" + depends on CGROUP_MEM_RES_CTLR_SWAP + default y + help + Memory Resource Controller Swap Extension comes with its price in + a bigger memory consumption. General purpose distribution kernels + which want to enable the feautre but keep it disabled by default + and let the user enable it by swapaccount boot command line + parameter should have this option unselected. + For those who want to have the feature enabled by default should + select this option (if, for some reason, they need to disable it + then noswapaccount does the trick). menuconfig CGROUP_SCHED bool "Group CPU scheduler" diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 26218df8d19d..7a22b4129211 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -61,7 +61,14 @@ struct mem_cgroup *root_mem_cgroup __read_mostly; #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP /* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */ int do_swap_account __read_mostly; -static int really_do_swap_account __initdata = 1; /* for remember boot option*/ + +/* for remember boot option*/ +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED +static int really_do_swap_account __initdata = 1; +#else +static int really_do_swap_account __initdata = 0; +#endif + #else #define do_swap_account (0) #endif @@ -4920,10 +4927,20 @@ struct cgroup_subsys mem_cgroup_subsys = { }; #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP +static int __init enable_swap_account(char *s) +{ + /* consider enabled if no parameter or 1 is given */ + if (!s || !strcmp(s, "1")) + really_do_swap_account = 1; + else if (!strcmp(s, "0")) + really_do_swap_account = 0; + return 1; +} +__setup("swapaccount", enable_swap_account); static int __init disable_swap_account(char *s) { - really_do_swap_account = 0; + enable_swap_account("0"); return 1; } __setup("noswapaccount", disable_swap_account); -- cgit v1.2.3-59-g8ed1b From 5989f11ba11c72f98d57580b991418d9ff6a207d Mon Sep 17 00:00:00 2001 From: Raoul Bhatia Date: Thu, 25 Nov 2010 17:32:47 +0100 Subject: EDAC: Fix typos in Documentation/edac.txt Fix trivial typos in edac.txt Signed-off-by: Raoul Bhatia Signed-off-by: Borislav Petkov --- Documentation/edac.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 0b875e8da969..9ee774de57cd 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -196,7 +196,7 @@ csrow3. The representation of the above is reflected in the directory tree in EDAC's sysfs interface. Starting in directory /sys/devices/system/edac/mc each memory controller will be represented -by its own 'mcX' directory, where 'X" is the index of the MC. +by its own 'mcX' directory, where 'X' is the index of the MC. ..../edac/mc/ @@ -207,7 +207,7 @@ by its own 'mcX' directory, where 'X" is the index of the MC. .... Under each 'mcX' directory each 'csrowX' is again represented by a -'csrowX', where 'X" is the csrow index: +'csrowX', where 'X' is the csrow index: .../mc/mc0/ @@ -232,7 +232,7 @@ EDAC control and attribute files. In 'mcX' directories are EDAC control and attribute files for -this 'X" instance of the memory controllers: +this 'X' instance of the memory controllers: Counter reset control file: @@ -343,7 +343,7 @@ Sdram memory scrubbing rate: 'csrowX' DIRECTORIES In the 'csrowX' directories are EDAC control and attribute files for -this 'X" instance of csrow: +this 'X' instance of csrow: Total Uncorrectable Errors count attribute file: -- cgit v1.2.3-59-g8ed1b From 0147fc058d11bd4009b126d09974d2c8f48fef15 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 22 Nov 2010 12:54:21 +0000 Subject: tcp: restrict net.ipv4.tcp_adv_win_scale (#20312) tcp_win_from_space() does the following: if (sysctl_tcp_adv_win_scale <= 0) return space >> (-sysctl_tcp_adv_win_scale); else return space - (space >> sysctl_tcp_adv_win_scale); "space" is int. As per C99 6.5.7 (3) shifting int for 32 or more bits is undefined behaviour. Indeed, if sysctl_tcp_adv_win_scale is exactly 32, space >> 32 equals space and function returns 0. Which means we busyloop in tcp_fixup_rcvbuf(). Restrict net.ipv4.tcp_adv_win_scale to [-31, 31]. Fix https://bugzilla.kernel.org/show_bug.cgi?id=20312 Steps to reproduce: echo 32 >/proc/sys/net/ipv4/tcp_adv_win_scale wget www.kernel.org [softlockup] Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 1 + net/ipv4/sysctl_net_ipv4.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index fe95105992c5..3c5e465296e1 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -144,6 +144,7 @@ tcp_adv_win_scale - INTEGER Count buffering overhead as bytes/2^tcp_adv_win_scale (if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale), if it is <= 0. + Possible values are [-31, 31], inclusive. Default: 2 tcp_allowed_congestion_control - STRING diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index e91911d7aae2..1b4ec21497a4 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -26,6 +26,8 @@ static int zero; static int tcp_retr1_max = 255; static int ip_local_port_range_min[] = { 1, 1 }; static int ip_local_port_range_max[] = { 65535, 65535 }; +static int tcp_adv_win_scale_min = -31; +static int tcp_adv_win_scale_max = 31; /* Update system visible IP port range */ static void set_local_port_range(int range[2]) @@ -426,7 +428,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_adv_win_scale, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &tcp_adv_win_scale_min, + .extra2 = &tcp_adv_win_scale_max, }, { .procname = "tcp_tw_reuse", -- cgit v1.2.3-59-g8ed1b From dfc5606dc51381186de765243bab340c8e021868 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 19 Nov 2010 14:51:04 -0800 Subject: rbd: replace the rbd sysfs interface The new interface creates directories per mapped image and under each it creates a subdir per available snapshot. This allows keeping a cleaner interface within the sysfs guidelines. The ABI documentation was updated too. Acked-by: Greg Kroah-Hartman Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil --- Documentation/ABI/testing/sysfs-bus-rbd | 83 ++++ drivers/block/rbd.c | 748 ++++++++++++++++++++------------ 2 files changed, 554 insertions(+), 277 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-rbd (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd new file mode 100644 index 000000000000..90a87e2a572b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-rbd @@ -0,0 +1,83 @@ +What: /sys/bus/rbd/ +Date: November 2010 +Contact: Yehuda Sadeh , + Sage Weil +Description: + +Being used for adding and removing rbd block devices. + +Usage: [snap name] + + $ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add + +The snapshot name can be "-" or omitted to map the image read/write. A +will be assigned for any registered block device. If snapshot is used, it will +be mapped read-only. + +Removal of a device: + + $ echo > /sys/bus/rbd/remove + +Entries under /sys/bus/rbd/devices// +-------------------------------------------- + +client_id + + The ceph unique client id that was assigned for this specific session. + +major + + The block device major number. + +name + + The name of the rbd image. + +pool + + The pool where this rbd image resides. The pool-name pair is unique + per rados system. + +size + + The size (in bytes) of the mapped block device. + +refresh + + Writing to this file will reread the image header data and set + all relevant datastructures accordingly. + +current_snap + + The current snapshot for which the device is mapped. + +create_snap + + Create a snapshot: + + $ echo > /sys/bus/rbd/devices//snap_create + +rollback_snap + + Rolls back data to the specified snapshot. This goes over the entire + list of rados blocks and sends a rollback command to each. + + $ echo > /sys/bus/rbd/devices//snap_rollback + +snap_* + + A directory per each snapshot + + +Entries under /sys/bus/rbd/devices//snap_ +------------------------------------------------------------- + +id + + The rados internal snapshot id assigned for this snapshot + +size + + The size of the image when this snapshot was taken. + + diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 6ec9d53806c5..008d4a00b50d 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -21,80 +21,9 @@ - Instructions for use - -------------------- + For usage instructions, please refer to: - 1) Map a Linux block device to an existing rbd image. - - Usage: [snap name] - - $ echo "192.168.0.1 name=admin rbd foo" > /sys/class/rbd/add - - The snapshot name can be "-" or omitted to map the image read/write. - - 2) List all active blkdev<->object mappings. - - In this example, we have performed step #1 twice, creating two blkdevs, - mapped to two separate rados objects in the rados rbd pool - - $ cat /sys/class/rbd/list - #id major client_name pool name snap KB - 0 254 client4143 rbd foo - 1024000 - - The columns, in order, are: - - blkdev unique id - - blkdev assigned major - - rados client id - - rados pool name - - rados block device name - - mapped snapshot ("-" if none) - - device size in KB - - - 3) Create a snapshot. - - Usage: - - $ echo "0 mysnap" > /sys/class/rbd/snap_create - - - 4) Listing a snapshot. - - $ cat /sys/class/rbd/snaps_list - #id snap KB - 0 - 1024000 (*) - 0 foo 1024000 - - The columns, in order, are: - - blkdev unique id - - snapshot name, '-' means none (active read/write version) - - size of device at time of snapshot - - the (*) indicates this is the active version - - 5) Rollback to snapshot. - - Usage: - - $ echo "0 mysnap" > /sys/class/rbd/snap_rollback - - - 6) Mapping an image using snapshot. - - A snapshot mapping is read-only. This is being done by passing - snap= to the options when adding a device. - - $ echo "192.168.0.1 name=admin,snap=mysnap rbd foo" > /sys/class/rbd/add - - - 7) Remove an active blkdev<->rbd image mapping. - - In this example, we remove the mapping with blkdev unique id 1. - - $ echo 1 > /sys/class/rbd/remove - - - NOTE: The actual creation and deletion of rados objects is outside the scope - of this driver. + Documentation/ABI/testing/sysfs-bus-rbd */ @@ -163,6 +92,14 @@ struct rbd_request { u64 len; }; +struct rbd_snap { + struct device dev; + const char *name; + size_t size; + struct list_head node; + u64 id; +}; + /* * a single device */ @@ -193,21 +130,60 @@ struct rbd_device { int read_only; struct list_head node; + + /* list of snapshots */ + struct list_head snaps; + + /* sysfs related */ + struct device dev; +}; + +static struct bus_type rbd_bus_type = { + .name = "rbd", }; static spinlock_t node_lock; /* protects client get/put */ -static struct class *class_rbd; /* /sys/class/rbd */ static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ static LIST_HEAD(rbd_dev_list); /* devices */ static LIST_HEAD(rbd_client_list); /* clients */ +static int __rbd_init_snaps_header(struct rbd_device *rbd_dev); +static void rbd_dev_release(struct device *dev); +static ssize_t rbd_snap_rollback(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size); +static ssize_t rbd_snap_add(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count); +static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev, + struct rbd_snap *snap);; + + +static struct rbd_device *dev_to_rbd(struct device *dev) +{ + return container_of(dev, struct rbd_device, dev); +} + +static struct device *rbd_get_dev(struct rbd_device *rbd_dev) +{ + return get_device(&rbd_dev->dev); +} + +static void rbd_put_dev(struct rbd_device *rbd_dev) +{ + put_device(&rbd_dev->dev); +} static int rbd_open(struct block_device *bdev, fmode_t mode) { struct gendisk *disk = bdev->bd_disk; struct rbd_device *rbd_dev = disk->private_data; + rbd_get_dev(rbd_dev); + set_device_ro(bdev, rbd_dev->read_only); if ((mode & FMODE_WRITE) && rbd_dev->read_only) @@ -216,9 +192,19 @@ static int rbd_open(struct block_device *bdev, fmode_t mode) return 0; } +static int rbd_release(struct gendisk *disk, fmode_t mode) +{ + struct rbd_device *rbd_dev = disk->private_data; + + rbd_put_dev(rbd_dev); + + return 0; +} + static const struct block_device_operations rbd_bd_ops = { .owner = THIS_MODULE, .open = rbd_open, + .release = rbd_release, }; /* @@ -361,7 +347,6 @@ static int rbd_header_from_disk(struct rbd_image_header *header, int ret = -ENOMEM; init_rwsem(&header->snap_rwsem); - header->snap_names_len = le64_to_cpu(ondisk->snap_names_len); header->snapc = kmalloc(sizeof(struct ceph_snap_context) + snap_count * @@ -1256,10 +1241,20 @@ bad: return -ERANGE; } +static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) +{ + struct rbd_snap *snap; + + while (!list_empty(&rbd_dev->snaps)) { + snap = list_first_entry(&rbd_dev->snaps, struct rbd_snap, node); + __rbd_remove_snap_dev(rbd_dev, snap); + } +} + /* * only read the first part of the ondisk header, without the snaps info */ -static int rbd_update_snaps(struct rbd_device *rbd_dev) +static int __rbd_update_snaps(struct rbd_device *rbd_dev) { int ret; struct rbd_image_header h; @@ -1280,12 +1275,15 @@ static int rbd_update_snaps(struct rbd_device *rbd_dev) rbd_dev->header.total_snaps = h.total_snaps; rbd_dev->header.snapc = h.snapc; rbd_dev->header.snap_names = h.snap_names; + rbd_dev->header.snap_names_len = h.snap_names_len; rbd_dev->header.snap_sizes = h.snap_sizes; rbd_dev->header.snapc->seq = snap_seq; + ret = __rbd_init_snaps_header(rbd_dev); + up_write(&rbd_dev->header.snap_rwsem); - return 0; + return ret; } static int rbd_init_disk(struct rbd_device *rbd_dev) @@ -1300,6 +1298,11 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) if (rc) return rc; + /* no need to lock here, as rbd_dev is not registered yet */ + rc = __rbd_init_snaps_header(rbd_dev); + if (rc) + return rc; + rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size); if (rc) return rc; @@ -1343,54 +1346,360 @@ out: return rc; } -/******************************************************************** - * /sys/class/rbd/ - * add map rados objects to blkdev - * remove unmap rados objects - * list show mappings - *******************************************************************/ +/* + sysfs +*/ + +static ssize_t rbd_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size); +} + +static ssize_t rbd_major_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); -static void class_rbd_release(struct class *cls) + return sprintf(buf, "%d\n", rbd_dev->major); +} + +static ssize_t rbd_client_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { - kfree(cls); + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client)); } -static ssize_t class_rbd_list(struct class *c, - struct class_attribute *attr, - char *data) +static ssize_t rbd_pool_show(struct device *dev, + struct device_attribute *attr, char *buf) { - int n = 0; - struct list_head *tmp; - int max = PAGE_SIZE; + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%s\n", rbd_dev->pool_name); +} + +static ssize_t rbd_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%s\n", rbd_dev->obj); +} + +static ssize_t rbd_snap_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%s\n", rbd_dev->snap_name); +} + +static ssize_t rbd_image_refresh(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + int rc; + int ret = size; mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - n += snprintf(data, max, - "#id\tmajor\tclient_name\tpool\tname\tsnap\tKB\n"); + rc = __rbd_update_snaps(rbd_dev); + if (rc < 0) + ret = rc; - list_for_each(tmp, &rbd_dev_list) { - struct rbd_device *rbd_dev; + mutex_unlock(&ctl_mutex); + return ret; +} - rbd_dev = list_entry(tmp, struct rbd_device, node); - n += snprintf(data+n, max-n, - "%d\t%d\tclient%lld\t%s\t%s\t%s\t%lld\n", - rbd_dev->id, - rbd_dev->major, - ceph_client_id(rbd_dev->client), - rbd_dev->pool_name, - rbd_dev->obj, rbd_dev->snap_name, - rbd_dev->header.image_size >> 10); - if (n == max) +static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL); +static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL); +static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL); +static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); +static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); +static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); +static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add); +static DEVICE_ATTR(rollback_snap, S_IWUSR, NULL, rbd_snap_rollback); + +static struct attribute *rbd_attrs[] = { + &dev_attr_size.attr, + &dev_attr_major.attr, + &dev_attr_client_id.attr, + &dev_attr_pool.attr, + &dev_attr_name.attr, + &dev_attr_current_snap.attr, + &dev_attr_refresh.attr, + &dev_attr_create_snap.attr, + &dev_attr_rollback_snap.attr, + NULL +}; + +static struct attribute_group rbd_attr_group = { + .attrs = rbd_attrs, +}; + +static const struct attribute_group *rbd_attr_groups[] = { + &rbd_attr_group, + NULL +}; + +static void rbd_sysfs_dev_release(struct device *dev) +{ +} + +static struct device_type rbd_device_type = { + .name = "rbd", + .groups = rbd_attr_groups, + .release = rbd_sysfs_dev_release, +}; + + +/* + sysfs - snapshots +*/ + +static ssize_t rbd_snap_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); + + return sprintf(buf, "%lld\n", (long long)snap->size); +} + +static ssize_t rbd_snap_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); + + return sprintf(buf, "%lld\n", (long long)snap->id); +} + +static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL); +static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL); + +static struct attribute *rbd_snap_attrs[] = { + &dev_attr_snap_size.attr, + &dev_attr_snap_id.attr, + NULL, +}; + +static struct attribute_group rbd_snap_attr_group = { + .attrs = rbd_snap_attrs, +}; + +static void rbd_snap_dev_release(struct device *dev) +{ + struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); + kfree(snap->name); + kfree(snap); +} + +static const struct attribute_group *rbd_snap_attr_groups[] = { + &rbd_snap_attr_group, + NULL +}; + +static struct device_type rbd_snap_device_type = { + .groups = rbd_snap_attr_groups, + .release = rbd_snap_dev_release, +}; + +static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev, + struct rbd_snap *snap) +{ + list_del(&snap->node); + device_unregister(&snap->dev); +} + +static int rbd_register_snap_dev(struct rbd_device *rbd_dev, + struct rbd_snap *snap, + struct device *parent) +{ + struct device *dev = &snap->dev; + int ret; + + dev->type = &rbd_snap_device_type; + dev->parent = parent; + dev->release = rbd_snap_dev_release; + dev_set_name(dev, "snap_%s", snap->name); + ret = device_register(dev); + + return ret; +} + +static int __rbd_add_snap_dev(struct rbd_device *rbd_dev, + int i, const char *name, + struct rbd_snap **snapp) +{ + int ret; + struct rbd_snap *snap = kzalloc(sizeof(*snap), GFP_KERNEL); + if (!snap) + return -ENOMEM; + snap->name = kstrdup(name, GFP_KERNEL); + snap->size = rbd_dev->header.snap_sizes[i]; + snap->id = rbd_dev->header.snapc->snaps[i]; + if (device_is_registered(&rbd_dev->dev)) { + ret = rbd_register_snap_dev(rbd_dev, snap, + &rbd_dev->dev); + if (ret < 0) + goto err; + } + *snapp = snap; + return 0; +err: + kfree(snap->name); + kfree(snap); + return ret; +} + +/* + * search for the previous snap in a null delimited string list + */ +const char *rbd_prev_snap_name(const char *name, const char *start) +{ + if (name < start + 2) + return NULL; + + name -= 2; + while (*name) { + if (name == start) + return start; + name--; + } + return name + 1; +} + +/* + * compare the old list of snapshots that we have to what's in the header + * and update it accordingly. Note that the header holds the snapshots + * in a reverse order (from newest to oldest) and we need to go from + * older to new so that we don't get a duplicate snap name when + * doing the process (e.g., removed snapshot and recreated a new + * one with the same name. + */ +static int __rbd_init_snaps_header(struct rbd_device *rbd_dev) +{ + const char *name, *first_name; + int i = rbd_dev->header.total_snaps; + struct rbd_snap *snap, *old_snap = NULL; + int ret; + struct list_head *p, *n; + + first_name = rbd_dev->header.snap_names; + name = first_name + rbd_dev->header.snap_names_len; + + list_for_each_prev_safe(p, n, &rbd_dev->snaps) { + u64 cur_id; + + old_snap = list_entry(p, struct rbd_snap, node); + + if (i) + cur_id = rbd_dev->header.snapc->snaps[i - 1]; + + if (!i || old_snap->id < cur_id) { + /* old_snap->id was skipped, thus was removed */ + __rbd_remove_snap_dev(rbd_dev, old_snap); + continue; + } + if (old_snap->id == cur_id) { + /* we have this snapshot already */ + i--; + name = rbd_prev_snap_name(name, first_name); + continue; + } + for (; i > 0; + i--, name = rbd_prev_snap_name(name, first_name)) { + if (!name) { + WARN_ON(1); + return -EINVAL; + } + cur_id = rbd_dev->header.snapc->snaps[i]; + /* snapshot removal? handle it above */ + if (cur_id >= old_snap->id) + break; + /* a new snapshot */ + ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap); + if (ret < 0) + return ret; + + /* note that we add it backward so using n and not p */ + list_add(&snap->node, n); + p = &snap->node; + } + } + /* we're done going over the old snap list, just add what's left */ + for (; i > 0; i--) { + name = rbd_prev_snap_name(name, first_name); + if (!name) { + WARN_ON(1); + return -EINVAL; + } + ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap); + if (ret < 0) + return ret; + list_add(&snap->node, &rbd_dev->snaps); + } + + return 0; +} + + +static void rbd_root_dev_release(struct device *dev) +{ +} + +static struct device rbd_root_dev = { + .init_name = "rbd", + .release = rbd_root_dev_release, +}; + +static int rbd_bus_add_dev(struct rbd_device *rbd_dev) +{ + int ret = -ENOMEM; + struct device *dev; + struct rbd_snap *snap; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + dev = &rbd_dev->dev; + + dev->bus = &rbd_bus_type; + dev->type = &rbd_device_type; + dev->parent = &rbd_root_dev; + dev->release = rbd_dev_release; + dev_set_name(dev, "%d", rbd_dev->id); + ret = device_register(dev); + if (ret < 0) + goto done_free; + + list_for_each_entry(snap, &rbd_dev->snaps, node) { + ret = rbd_register_snap_dev(rbd_dev, snap, + &rbd_dev->dev); + if (ret < 0) break; } mutex_unlock(&ctl_mutex); - return n; + return 0; +done_free: + mutex_unlock(&ctl_mutex); + return ret; } -static ssize_t class_rbd_add(struct class *c, - struct class_attribute *attr, - const char *buf, size_t count) +static void rbd_bus_del_dev(struct rbd_device *rbd_dev) +{ + device_unregister(&rbd_dev->dev); +} + +static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) { struct ceph_osd_client *osdc; struct rbd_device *rbd_dev; @@ -1419,6 +1728,7 @@ static ssize_t class_rbd_add(struct class *c, /* static rbd_device initialization */ spin_lock_init(&rbd_dev->lock); INIT_LIST_HEAD(&rbd_dev->node); + INIT_LIST_HEAD(&rbd_dev->snaps); /* generate unique id: find highest unique id, add one */ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); @@ -1478,6 +1788,9 @@ static ssize_t class_rbd_add(struct class *c, } rbd_dev->major = irc; + rc = rbd_bus_add_dev(rbd_dev); + if (rc) + goto err_out_disk; /* set up and announce blkdev mapping */ rc = rbd_init_disk(rbd_dev); if (rc) @@ -1487,6 +1800,8 @@ static ssize_t class_rbd_add(struct class *c, err_out_blkdev: unregister_blkdev(rbd_dev->major, rbd_dev->name); +err_out_disk: + rbd_free_disk(rbd_dev); err_out_client: rbd_put_client(rbd_dev); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); @@ -1518,35 +1833,10 @@ static struct rbd_device *__rbd_get_dev(unsigned long id) return NULL; } -static ssize_t class_rbd_remove(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static void rbd_dev_release(struct device *dev) { - struct rbd_device *rbd_dev = NULL; - int target_id, rc; - unsigned long ul; - - rc = strict_strtoul(buf, 10, &ul); - if (rc) - return rc; - - /* convert to int; abort if we lost anything in the conversion */ - target_id = (int) ul; - if (target_id != ul) - return -EINVAL; - - /* remove object from list immediately */ - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - - rbd_dev = __rbd_get_dev(target_id); - if (rbd_dev) - list_del_init(&rbd_dev->node); - - mutex_unlock(&ctl_mutex); - - if (!rbd_dev) - return -ENOENT; + struct rbd_device *rbd_dev = + container_of(dev, struct rbd_device, dev); rbd_put_client(rbd_dev); @@ -1557,67 +1847,11 @@ static ssize_t class_rbd_remove(struct class *c, /* release module ref */ module_put(THIS_MODULE); - - return count; } -static ssize_t class_rbd_snaps_list(struct class *c, - struct class_attribute *attr, - char *data) -{ - struct rbd_device *rbd_dev = NULL; - struct list_head *tmp; - struct rbd_image_header *header; - int i, n = 0, max = PAGE_SIZE; - int ret; - - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - - n += snprintf(data, max, "#id\tsnap\tKB\n"); - - list_for_each(tmp, &rbd_dev_list) { - char *names, *p; - struct ceph_snap_context *snapc; - - rbd_dev = list_entry(tmp, struct rbd_device, node); - header = &rbd_dev->header; - - down_read(&header->snap_rwsem); - - names = header->snap_names; - snapc = header->snapc; - - n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n", - rbd_dev->id, RBD_SNAP_HEAD_NAME, - header->image_size >> 10, - (!rbd_dev->cur_snap ? " (*)" : "")); - if (n == max) - break; - - p = names; - for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) { - n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n", - rbd_dev->id, p, header->snap_sizes[i] >> 10, - (rbd_dev->cur_snap && - (snap_index(header, i) == rbd_dev->cur_snap) ? - " (*)" : "")); - if (n == max) - break; - } - - up_read(&header->snap_rwsem); - } - - - ret = n; - mutex_unlock(&ctl_mutex); - return ret; -} - -static ssize_t class_rbd_snaps_refresh(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static ssize_t rbd_remove(struct bus_type *bus, + const char *buf, + size_t count) { struct rbd_device *rbd_dev = NULL; int target_id, rc; @@ -1641,95 +1875,70 @@ static ssize_t class_rbd_snaps_refresh(struct class *c, goto done; } - rc = rbd_update_snaps(rbd_dev); - if (rc < 0) - ret = rc; + list_del_init(&rbd_dev->node); + + __rbd_remove_all_snaps(rbd_dev); + rbd_bus_del_dev(rbd_dev); done: mutex_unlock(&ctl_mutex); return ret; } -static ssize_t class_rbd_snap_create(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static ssize_t rbd_snap_add(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { - struct rbd_device *rbd_dev = NULL; - int target_id, ret; - char *name; - - name = kmalloc(RBD_MAX_SNAP_NAME_LEN + 1, GFP_KERNEL); + struct rbd_device *rbd_dev = dev_to_rbd(dev); + int ret; + char *name = kmalloc(count + 1, GFP_KERNEL); if (!name) return -ENOMEM; - /* parse snaps add command */ - if (sscanf(buf, "%d " - "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", - &target_id, - name) != 2) { - ret = -EINVAL; - goto done; - } + snprintf(name, count, "%s", buf); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rbd_dev = __rbd_get_dev(target_id); - if (!rbd_dev) { - ret = -ENOENT; - goto done_unlock; - } - ret = rbd_header_add_snap(rbd_dev, name, GFP_KERNEL); if (ret < 0) goto done_unlock; - ret = rbd_update_snaps(rbd_dev); + ret = __rbd_update_snaps(rbd_dev); if (ret < 0) goto done_unlock; ret = count; done_unlock: mutex_unlock(&ctl_mutex); -done: kfree(name); return ret; } -static ssize_t class_rbd_rollback(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static ssize_t rbd_snap_rollback(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { - struct rbd_device *rbd_dev = NULL; - int target_id, ret; + struct rbd_device *rbd_dev = dev_to_rbd(dev); + int ret; u64 snapid; - char snap_name[RBD_MAX_SNAP_NAME_LEN]; u64 cur_ofs; - char *seg_name; + char *seg_name = NULL; + char *snap_name = kmalloc(count + 1, GFP_KERNEL); + ret = -ENOMEM; + if (!snap_name) + return ret; /* parse snaps add command */ - if (sscanf(buf, "%d " - "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", - &target_id, - snap_name) != 2) { - return -EINVAL; - } - - ret = -ENOMEM; + snprintf(snap_name, count, "%s", buf); seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); if (!seg_name) - return ret; + goto done; mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rbd_dev = __rbd_get_dev(target_id); - if (!rbd_dev) { - ret = -ENOENT; - goto done_unlock; - } - ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL); if (ret < 0) goto done_unlock; @@ -1750,7 +1959,7 @@ static ssize_t class_rbd_rollback(struct class *c, seg_name, ret); } - ret = rbd_update_snaps(rbd_dev); + ret = __rbd_update_snaps(rbd_dev); if (ret < 0) goto done_unlock; @@ -1758,57 +1967,42 @@ static ssize_t class_rbd_rollback(struct class *c, done_unlock: mutex_unlock(&ctl_mutex); +done: kfree(seg_name); + kfree(snap_name); return ret; } -static struct class_attribute class_rbd_attrs[] = { - __ATTR(add, 0200, NULL, class_rbd_add), - __ATTR(remove, 0200, NULL, class_rbd_remove), - __ATTR(list, 0444, class_rbd_list, NULL), - __ATTR(snaps_refresh, 0200, NULL, class_rbd_snaps_refresh), - __ATTR(snap_create, 0200, NULL, class_rbd_snap_create), - __ATTR(snaps_list, 0444, class_rbd_snaps_list, NULL), - __ATTR(snap_rollback, 0200, NULL, class_rbd_rollback), +static struct bus_attribute rbd_bus_attrs[] = { + __ATTR(add, S_IWUSR, NULL, rbd_add), + __ATTR(remove, S_IWUSR, NULL, rbd_remove), __ATTR_NULL }; /* * create control files in sysfs - * /sys/class/rbd/... + * /sys/bus/rbd/... */ static int rbd_sysfs_init(void) { - int ret = -ENOMEM; + int ret; - class_rbd = kzalloc(sizeof(*class_rbd), GFP_KERNEL); - if (!class_rbd) - goto out; + rbd_bus_type.bus_attrs = rbd_bus_attrs; - class_rbd->name = DRV_NAME; - class_rbd->owner = THIS_MODULE; - class_rbd->class_release = class_rbd_release; - class_rbd->class_attrs = class_rbd_attrs; + ret = bus_register(&rbd_bus_type); + if (ret < 0) + return ret; - ret = class_register(class_rbd); - if (ret) - goto out_class; - return 0; + ret = device_register(&rbd_root_dev); -out_class: - kfree(class_rbd); - class_rbd = NULL; - pr_err(DRV_NAME ": failed to create class rbd\n"); -out: return ret; } static void rbd_sysfs_cleanup(void) { - if (class_rbd) - class_destroy(class_rbd); - class_rbd = NULL; + device_unregister(&rbd_root_dev); + bus_unregister(&rbd_bus_type); } int __init rbd_init(void) -- cgit v1.2.3-59-g8ed1b From 4fe65cab844e6d3d7d310e66a501d5e7242ecb54 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 2 Dec 2010 14:31:19 -0800 Subject: Documentation/filesystems/vfs.txt: fix ->repeasepage() description ->releasepage() does not remove the page from the mapping. Acked-by: Neil Brown Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/vfs.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index ed7e5efc06d8..55c28b79d8dc 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -660,11 +660,10 @@ struct address_space_operations { releasepage: releasepage is called on PagePrivate pages to indicate that the page should be freed if possible. ->releasepage should remove any private data from the page and clear the - PagePrivate flag. It may also remove the page from the - address_space. If this fails for some reason, it may indicate - failure with a 0 return value. - This is used in two distinct though related cases. The first - is when the VM finds a clean page with no active users and + PagePrivate flag. If releasepage() fails for some reason, it must + indicate failure with a 0 return value. + releasepage() is used in two distinct though related cases. The + first is when the VM finds a clean page with no active users and wants to make it a free page. If ->releasepage succeeds, the page will be removed from the address_space and become free. -- cgit v1.2.3-59-g8ed1b