diff options
158 files changed, 2190 insertions, 1551 deletions
@@ -24,6 +24,7 @@ *.order *.elf *.bin +*.tar *.gz *.bz2 *.lzma diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 449a8a1..4d4f06d 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -659,6 +659,19 @@ macros using parameters. #define CONSTANT 0x4000 #define CONSTEXP (CONSTANT | 3) +5) namespace collisions when defining local variables in macros resembling +functions: + +#define FOO(x) \ +({ \ + typeof(x) ret; \ + ret = calc_ret(x); \ + (ret); \ +)} + +ret is a common name for a local variable - __foo_ret is less likely +to collide with an existing variable. + The cpp manual deals with macros exhaustively. The gcc internals manual also covers RTL which is used frequently with assembly language in the kernel. diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 447671b..b03a832 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -614,8 +614,8 @@ The canonical patch message body contains the following: - An empty line. - - The body of the explanation, which will be copied to the - permanent changelog to describe this patch. + - The body of the explanation, line wrapped at 75 columns, which will + be copied to the permanent changelog to describe this patch. - The "Signed-off-by:" lines, described above, which will also go in the changelog. diff --git a/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt b/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt new file mode 100644 index 0000000..d4649860 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt @@ -0,0 +1,17 @@ +Conexant Digicolor Real Time Clock controller + +This binding currently supports the CX92755 SoC. + +Required properties: +- compatible: should be "cnxt,cx92755-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: rtc alarm interrupt + +Example: + + rtc@f0000c30 { + compatible = "cnxt,cx92755-rtc"; + reg = <0xf0000c30 0x18>; + interrupts = <25>; + }; diff --git a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt b/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt index b800070..fa6a942 100644 --- a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt @@ -7,6 +7,11 @@ Required properties: region. - interrupts: rtc alarm interrupt +Optional properties: +- stmp,crystal-freq: override crystal frequency as determined from fuse bits. + Only <32000> and <32768> are possible for the hardware. Use <0> for + "no crystal". + Example: rtc@80056000 { diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index a07ba61..8e36c7e 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -200,12 +200,12 @@ contains details information about the process itself. Its fields are explained in Table 1-4. (for SMP CONFIG users) -For making accounting scalable, RSS related information are handled in -asynchronous manner and the vaule may not be very precise. To see a precise +For making accounting scalable, RSS related information are handled in an +asynchronous manner and the value may not be very precise. To see a precise snapshot of a moment, you can see /proc/<pid>/smaps file and scan page table. It's slow but very precise. -Table 1-2: Contents of the status files (as of 2.6.30-rc7) +Table 1-2: Contents of the status files (as of 3.20.0) .............................................................................. Field Content Name filename of the executable @@ -213,6 +213,7 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7) in an uninterruptible wait, Z is zombie, T is traced or stopped) Tgid thread group ID + Ngid NUMA group ID (0 if none) Pid process id PPid process id of the parent process TracerPid PID of process tracing this process (0 if not) @@ -220,6 +221,10 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7) Gid Real, effective, saved set, and file system GIDs FDSize number of file descriptor slots currently allocated Groups supplementary group list + NStgid descendant namespace thread group ID hierarchy + NSpid descendant namespace process ID hierarchy + NSpgid descendant namespace process group ID hierarchy + NSsid descendant namespace session ID hierarchy VmPeak peak virtual memory size VmSize total program size VmLck locked memory size @@ -1704,6 +1709,10 @@ A typical output is flags: 0100002 mnt_id: 19 +All locks associated with a file descriptor are shown in its fdinfo too. + +lock: 1: FLOCK ADVISORY WRITE 359 00:13:11691 0 EOF + The files such as eventfd, fsnotify, signalfd, epoll among the regular pos/flags pair provide additional information particular to the objects they represent. diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 94f574b..135b3f5 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -80,7 +80,7 @@ static void hex_dump(const void *src, size_t length, size_t line_size, char *pre * Unescape - process hexadecimal escape character * converts shell input "\x23" -> 0x23 */ -int unespcape(char *_dst, char *_src, size_t len) +static int unescape(char *_dst, char *_src, size_t len) { int ret = 0; char *src = _src; @@ -304,7 +304,7 @@ int main(int argc, char *argv[]) size = strlen(input_tx+1); tx = malloc(size); rx = malloc(size); - size = unespcape((char *)tx, input_tx, size); + size = unescape((char *)tx, input_tx, size); transfer(fd, tx, rx, size); free(rx); free(tx); diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 99d7eb3..c831001 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -872,6 +872,27 @@ can be ORed together: ============================================================== +threads-max + +This value controls the maximum number of threads that can be created +using fork(). + +During initialization the kernel sets this value such that even if the +maximum number of threads is created, the thread structures occupy only +a part (1/8th) of the available RAM pages. + +The minimum value that can be written to threads-max is 20. +The maximum value that can be written to threads-max is given by the +constant FUTEX_TID_MASK (0x3fffffff). +If a value outside of this range is written to threads-max an error +EINVAL occurs. + +The value written is checked against the available RAM pages. If the +thread structures would occupy too much (more than 1/8th) of the +available RAM pages threads-max is reduced accordingly. + +============================================================== + unknown_nmi_panic: The value in this file affects behavior of handling NMI. When the diff --git a/MAINTAINERS b/MAINTAINERS index bf990f5..f7bbaec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1215,6 +1215,7 @@ F: arch/arm/mach-orion5x/ts78xx-* ARM/Mediatek SoC support M: Matthias Brugger <matthias.bgg@gmail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/mt6* F: arch/arm/boot/dts/mt8* @@ -8183,6 +8184,7 @@ X: kernel/torture.c REAL TIME CLOCK (RTC) SUBSYSTEM M: Alessandro Zummo <a.zummo@towertech.it> +M: Alexandre Belloni <alexandre.belloni@free-electrons.com> L: rtc-linux@googlegroups.com Q: http://patchwork.ozlabs.org/project/rtc-linux/list/ S: Maintained diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h index b4cf036..43a7559 100644 --- a/arch/alpha/include/asm/processor.h +++ b/arch/alpha/include/asm/processor.h @@ -44,6 +44,7 @@ struct task_struct; extern unsigned long thread_saved_pc(struct task_struct *); /* Do necessary setup to start up a newly executed thread. */ +struct pt_regs; extern void start_thread(struct pt_regs *, unsigned long, unsigned long); /* Free all resources held by a thread. */ diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index 1badf9b..e00a018 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -52,7 +52,7 @@ static void show_callee_regs(struct callee_regs *cregs) print_reg_file(&(cregs->r13), 13); } -void print_task_path_n_nm(struct task_struct *tsk, char *buf) +static void print_task_path_n_nm(struct task_struct *tsk, char *buf) { struct path path; char *path_nm = NULL; @@ -77,7 +77,6 @@ void print_task_path_n_nm(struct task_struct *tsk, char *buf) done: pr_info("Path: %s\n", path_nm); } -EXPORT_SYMBOL(print_task_path_n_nm); static void show_faulting_vma(unsigned long address, char *buf) { diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index eb0f43f..3c4596d 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -21,6 +21,7 @@ generic-y += preempt.h generic-y += resource.h generic-y += rwsem.h generic-y += scatterlist.h +generic-y += seccomp.h generic-y += sections.h generic-y += segment.h generic-y += sembuf.h diff --git a/arch/arm/include/asm/seccomp.h b/arch/arm/include/asm/seccomp.h deleted file mode 100644 index 52b156b..0000000 --- a/arch/arm/include/asm/seccomp.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASM_ARM_SECCOMP_H -#define _ASM_ARM_SECCOMP_H - -#include <linux/unistd.h> - -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - -#endif /* _ASM_ARM_SECCOMP_H */ diff --git a/arch/microblaze/include/asm/seccomp.h b/arch/microblaze/include/asm/seccomp.h index 0d91275..204618a 100644 --- a/arch/microblaze/include/asm/seccomp.h +++ b/arch/microblaze/include/asm/seccomp.h @@ -3,14 +3,8 @@ #include <linux/unistd.h> -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit #define __NR_seccomp_sigreturn __NR_sigreturn -#define __NR_seccomp_read_32 __NR_read -#define __NR_seccomp_write_32 __NR_write -#define __NR_seccomp_exit_32 __NR_exit -#define __NR_seccomp_sigreturn_32 __NR_sigreturn +#include <asm-generic/seccomp.h> #endif /* _ASM_MICROBLAZE_SECCOMP_H */ diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index 70ffe9b..fe48220 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -105,7 +105,8 @@ CONFIG_RTC_CLASS=y # CONFIG_RTC_HCTOSYS is not set # CONFIG_RTC_INTF_SYSFS is not set # CONFIG_RTC_INTF_PROC is not set -CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1685_FAMILY=y +CONFIG_RTC_DRV_DS1685=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y diff --git a/arch/mips/include/asm/mach-ip32/mc146818rtc.h b/arch/mips/include/asm/mach-ip32/mc146818rtc.h deleted file mode 100644 index 6b6bab4..0000000 --- a/arch/mips/include/asm/mach-ip32/mc146818rtc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1998, 2001, 03 by Ralf Baechle - * Copyright (C) 2000 Harald Koerfgen - * - * RTC routines for IP32 style attached Dallas chip. - */ -#ifndef __ASM_MACH_IP32_MC146818RTC_H -#define __ASM_MACH_IP32_MC146818RTC_H - -#include <asm/ip32/mace.h> - -#define RTC_PORT(x) (0x70 + (x)) - -static unsigned char CMOS_READ(unsigned long addr) -{ - return mace->isa.rtc[addr << 8]; -} - -static inline void CMOS_WRITE(unsigned char data, unsigned long addr) -{ - mace->isa.rtc[addr << 8] = data; -} - -/* - * FIXME: Do it right. For now just assume that no one lives in 20th century - * and no O2 user in 22th century ;-) - */ -#define mc146818_decode_year(year) ((year) + 2000) - -#define RTC_ALWAYS_BCD 0 - -#endif /* __ASM_MACH_IP32_MC146818RTC_H */ diff --git a/arch/mips/include/asm/seccomp.h b/arch/mips/include/asm/seccomp.h index f29c75c..1d8a2e2 100644 --- a/arch/mips/include/asm/seccomp.h +++ b/arch/mips/include/asm/seccomp.h @@ -2,11 +2,6 @@ #include <linux/unistd.h> -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - /* * Kludge alert: * @@ -29,4 +24,6 @@ #endif /* CONFIG_MIPS32_O32 */ +#include <asm-generic/seccomp.h> + #endif /* __ASM_SECCOMP_H */ diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c index 511e9ff..b522477 100644 --- a/arch/mips/sgi-ip32/ip32-platform.c +++ b/arch/mips/sgi-ip32/ip32-platform.c @@ -9,10 +9,13 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/serial_8250.h> +#include <linux/rtc/ds1685.h> #include <asm/ip32/mace.h> #include <asm/ip32/ip32_ints.h> +extern void ip32_prepare_poweroff(void); + #define MACEISA_SERIAL1_OFFS offsetof(struct sgi_mace, isa.serial1) #define MACEISA_SERIAL2_OFFS offsetof(struct sgi_mace, isa.serial2) @@ -90,18 +93,47 @@ static __init int sgio2btns_devinit(void) device_initcall(sgio2btns_devinit); -static struct resource sgio2_cmos_rsrc[] = { +#define MACE_RTC_RES_START (MACE_BASE + offsetof(struct sgi_mace, isa.rtc)) +#define MACE_RTC_RES_END (MACE_RTC_RES_START + 32767) + +static struct resource ip32_rtc_resources[] = { { - .start = 0x70, - .end = 0x71, - .flags = IORESOURCE_IO + .start = MACEISA_RTC_IRQ, + .end = MACEISA_RTC_IRQ, + .flags = IORESOURCE_IRQ + }, { + .start = MACE_RTC_RES_START, + .end = MACE_RTC_RES_END, + .flags = IORESOURCE_MEM, } }; -static __init int sgio2_cmos_devinit(void) +/* RTC registers on IP32 are each padded by 256 bytes (0x100). */ +static struct ds1685_rtc_platform_data +ip32_rtc_platform_data[] = { + { + .regstep = 0x100, + .bcd_mode = true, + .no_irq = false, + .uie_unsupported = false, + .alloc_io_resources = true, + .plat_prepare_poweroff = ip32_prepare_poweroff, + }, +}; + +struct platform_device ip32_rtc_device = { + .name = "rtc-ds1685", + .id = -1, + .dev = { + .platform_data = ip32_rtc_platform_data, + }, + .num_resources = ARRAY_SIZE(ip32_rtc_resources), + .resource = ip32_rtc_resources, +}; + ++static int __init sgio2_rtc_devinit(void) { - return IS_ERR(platform_device_register_simple("rtc_cmos", -1, - sgio2_cmos_rsrc, 1)); + return platform_device_register(&ip32_rtc_device); } device_initcall(sgio2_cmos_devinit); diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 44b3470..8bd415c 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -11,10 +11,11 @@ #include <linux/compiler.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/sched.h> #include <linux/notifier.h> #include <linux/delay.h> -#include <linux/ds17287rtc.h> +#include <linux/rtc/ds1685.h> #include <linux/interrupt.h> #include <linux/pm.h> @@ -33,53 +34,40 @@ #define POWERDOWN_FREQ (HZ / 4) #define PANIC_FREQ (HZ / 8) -static struct timer_list power_timer, blink_timer, debounce_timer; -static int has_panicked, shuting_down; +extern struct platform_device ip32_rtc_device; -static void ip32_machine_restart(char *command) __noreturn; -static void ip32_machine_halt(void) __noreturn; -static void ip32_machine_power_off(void) __noreturn; +static struct timer_list power_timer, blink_timer; +static int has_panicked, shutting_down; -static void ip32_machine_restart(char *cmd) +static __noreturn void ip32_poweroff(void *data) { - crime->control = CRIME_CONTROL_HARD_RESET; - while (1); -} + void (*poweroff_func)(struct platform_device *) = + symbol_get(ds1685_rtc_poweroff); + +#ifdef CONFIG_MODULES + /* If the first __symbol_get failed, our module wasn't loaded. */ + if (!poweroff_func) { + request_module("rtc-ds1685"); + poweroff_func = symbol_get(ds1685_rtc_poweroff); + } +#endif -static inline void ip32_machine_halt(void) -{ - ip32_machine_power_off(); -} + if (!poweroff_func) + pr_emerg("RTC not available for power-off. Spinning forever ...\n"); + else { + (*poweroff_func)((struct platform_device *)data); + symbol_put(ds1685_rtc_poweroff); + } -static void ip32_machine_power_off(void) -{ - unsigned char reg_a, xctrl_a, xctrl_b; - - disable_irq(MACEISA_RTC_IRQ); - reg_a = CMOS_READ(RTC_REG_A); - - /* setup for kickstart & wake-up (DS12287 Ref. Man. p. 19) */ - reg_a &= ~DS_REGA_DV2; - reg_a |= DS_REGA_DV1; - - CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A); - wbflush(); - xctrl_b = CMOS_READ(DS_B1_XCTRL4B) - | DS_XCTRL4B_ABE | DS_XCTRL4B_KFE; - CMOS_WRITE(xctrl_b, DS_B1_XCTRL4B); - xctrl_a = CMOS_READ(DS_B1_XCTRL4A) & ~DS_XCTRL4A_IFS; - CMOS_WRITE(xctrl_a, DS_B1_XCTRL4A); - wbflush(); - /* adios amigos... */ - CMOS_WRITE(xctrl_a | DS_XCTRL4A_PAB, DS_B1_XCTRL4A); - CMOS_WRITE(reg_a, RTC_REG_A); - wbflush(); - while (1); + unreachable(); } -static void power_timeout(unsigned long data) +static void ip32_machine_restart(char *cmd) __noreturn; +static void ip32_machine_restart(char *cmd) { - ip32_machine_power_off(); + msleep(20); + crime->control = CRIME_CONTROL_HARD_RESET; + unreachable(); } static void blink_timeout(unsigned long data) @@ -89,44 +77,27 @@ static void blink_timeout(unsigned long data) mod_timer(&blink_timer, jiffies + data); } -static void debounce(unsigned long data) +static void ip32_machine_halt(void) { - unsigned char reg_a, reg_c, xctrl_a; - - reg_c = CMOS_READ(RTC_INTR_FLAGS); - reg_a = CMOS_READ(RTC_REG_A); - CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A); - wbflush(); - xctrl_a = CMOS_READ(DS_B1_XCTRL4A); - if ((xctrl_a & DS_XCTRL4A_IFS) || (reg_c & RTC_IRQF )) { - /* Interrupt still being sent. */ - debounce_timer.expires = jiffies + 50; - add_timer(&debounce_timer); - - /* clear interrupt source */ - CMOS_WRITE(xctrl_a & ~DS_XCTRL4A_IFS, DS_B1_XCTRL4A); - CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A); - return; - } - CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A); - - if (has_panicked) - ip32_machine_restart(NULL); + ip32_poweroff(&ip32_rtc_device); +} - enable_irq(MACEISA_RTC_IRQ); +static void power_timeout(unsigned long data) +{ + ip32_poweroff(&ip32_rtc_device); } -static inline void ip32_power_button(void) +void ip32_prepare_poweroff(void) { if (has_panicked) return; - if (shuting_down || kill_cad_pid(SIGINT, 1)) { + if (shutting_down || kill_cad_pid(SIGINT, 1)) { /* No init process or button pressed twice. */ - ip32_machine_power_off(); + ip32_poweroff(&ip32_rtc_device); } - shuting_down = 1; + shutting_down = 1; blink_timer.data = POWERDOWN_FREQ; blink_timeout(POWERDOWN_FREQ); @@ -136,27 +107,6 @@ static inline void ip32_power_button(void) add_timer(&power_timer); } -static irqreturn_t ip32_rtc_int(int irq, void *dev_id) -{ - unsigned char reg_c; - - reg_c = CMOS_READ(RTC_INTR_FLAGS); - if (!(reg_c & RTC_IRQF)) { - printk(KERN_WARNING - "%s: RTC IRQ without RTC_IRQF\n", __func__); - } - /* Wait until interrupt goes away */ - disable_irq_nosync(MACEISA_RTC_IRQ); - init_timer(&debounce_timer); - debounce_timer.function = debounce; - debounce_timer.expires = jiffies + 50; - add_timer(&debounce_timer); - - printk(KERN_DEBUG "Power button pressed\n"); - ip32_power_button(); - return IRQ_HANDLED; -} - static int panic_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -190,15 +140,12 @@ static __init int ip32_reboot_setup(void) _machine_restart = ip32_machine_restart; _machine_halt = ip32_machine_halt; - pm_power_off = ip32_machine_power_off; + pm_power_off = ip32_machine_halt; init_timer(&blink_timer); blink_timer.function = blink_timeout; atomic_notifier_chain_register(&panic_notifier_list, &panic_block); - if (request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL)) - panic("Can't allocate MACEISA RTC IRQ"); - return 0; } diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild index 8686237..12b341d 100644 --- a/arch/parisc/include/asm/Kbuild +++ b/arch/parisc/include/asm/Kbuild @@ -20,6 +20,7 @@ generic-y += param.h generic-y += percpu.h generic-y += poll.h generic-y += preempt.h +generic-y += seccomp.h generic-y += segment.h generic-y += topology.h generic-y += trace_clock.h diff --git a/arch/parisc/include/asm/seccomp.h b/arch/parisc/include/asm/seccomp.h deleted file mode 100644 index 015f788..0000000 --- a/arch/parisc/include/asm/seccomp.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASM_PARISC_SECCOMP_H -#define _ASM_PARISC_SECCOMP_H - -#include <linux/unistd.h> - -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - -#define __NR_seccomp_read_32 __NR_read -#define __NR_seccomp_write_32 __NR_write -#define __NR_seccomp_exit_32 __NR_exit -#define __NR_seccomp_sigreturn_32 __NR_rt_sigreturn - -#endif /* _ASM_PARISC_SECCOMP_H */ diff --git a/arch/powerpc/include/asm/seccomp.h b/arch/powerpc/include/asm/seccomp.h new file mode 100644 index 0000000..c1818e3 --- /dev/null +++ b/arch/powerpc/include/asm/seccomp.h @@ -0,0 +1,10 @@ +#ifndef _ASM_POWERPC_SECCOMP_H +#define _ASM_POWERPC_SECCOMP_H + +#include <linux/unistd.h> + +#define __NR_seccomp_sigreturn_32 __NR_sigreturn + +#include <asm-generic/seccomp.h> + +#endif /* _ASM_POWERPC_SECCOMP_H */ diff --git a/arch/powerpc/include/uapi/asm/Kbuild b/arch/powerpc/include/uapi/asm/Kbuild index 7a3f795..79c4068 100644 --- a/arch/powerpc/include/uapi/asm/Kbuild +++ b/arch/powerpc/include/uapi/asm/Kbuild @@ -25,7 +25,6 @@ header-y += posix_types.h header-y += ps3fb.h header-y += ptrace.h header-y += resource.h -header-y += seccomp.h header-y += sembuf.h header-y += setup.h header-y += shmbuf.h diff --git a/arch/powerpc/include/uapi/asm/seccomp.h b/arch/powerpc/include/uapi/asm/seccomp.h deleted file mode 100644 index 00c1d91..0000000 --- a/arch/powerpc/include/uapi/asm/seccomp.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASM_POWERPC_SECCOMP_H -#define _ASM_POWERPC_SECCOMP_H - -#include <linux/unistd.h> - -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - -#define __NR_seccomp_read_32 __NR_read -#define __NR_seccomp_write_32 __NR_write -#define __NR_seccomp_exit_32 __NR_exit -#define __NR_seccomp_sigreturn_32 __NR_sigreturn - -#endif /* _ASM_POWERPC_SECCOMP_H */ diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c index 1c27831..ed7b097 100644 --- a/arch/powerpc/oprofile/cell/spu_task_sync.c +++ b/arch/powerpc/oprofile/cell/spu_task_sync.c @@ -22,6 +22,7 @@ #include <linux/kref.h> #include <linux/mm.h> #include <linux/fs.h> +#include <linux/file.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/numa.h> @@ -322,18 +323,20 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp, unsigned long app_cookie = 0; unsigned int my_offset = 0; struct vm_area_struct *vma; + struct file *exe_file; struct mm_struct *mm = spu->mm; if (!mm) goto out; - down_read(&mm->mmap_sem); - - if (mm->exe_file) { - app_cookie = fast_get_dcookie(&mm->exe_file->f_path); - pr_debug("got dcookie for %pD\n", mm->exe_file); + exe_file = get_mm_exe_file(mm); + if (exe_file) { + app_cookie = fast_get_dcookie(&exe_file->f_path); + pr_debug("got dcookie for %pD\n", exe_file); + fput(exe_file); } + down_read(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) { if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref) continue; diff --git a/arch/sparc/include/asm/seccomp.h b/arch/sparc/include/asm/seccomp.h index adca1bc..5ef8826 100644 --- a/arch/sparc/include/asm/seccomp.h +++ b/arch/sparc/include/asm/seccomp.h @@ -1,15 +1,10 @@ #ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H #include <linux/unistd.h> -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - -#define __NR_seccomp_read_32 __NR_read -#define __NR_seccomp_write_32 __NR_write -#define __NR_seccomp_exit_32 __NR_exit #define __NR_seccomp_sigreturn_32 __NR_sigreturn +#include <asm-generic/seccomp.h> + #endif /* _ASM_SECCOMP_H */ diff --git a/arch/x86/include/asm/seccomp.h b/arch/x86/include/asm/seccomp.h index 0f3d7f0..0c8c7c8 100644 --- a/arch/x86/include/asm/seccomp.h +++ b/arch/x86/include/asm/seccomp.h @@ -1,5 +1,20 @@ +#ifndef _ASM_X86_SECCOMP_H +#define _ASM_X86_SECCOMP_H + +#include <asm/unistd.h> + #ifdef CONFIG_X86_32 -# include <asm/seccomp_32.h> -#else -# include <asm/seccomp_64.h> +#define __NR_seccomp_sigreturn __NR_sigreturn #endif + +#ifdef CONFIG_COMPAT +#include <asm/ia32_unistd.h> +#define __NR_seccomp_read_32 __NR_ia32_read +#define __NR_seccomp_write_32 __NR_ia32_write +#define __NR_seccomp_exit_32 __NR_ia32_exit +#define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn +#endif + +#include <asm-generic/seccomp.h> + +#endif /* _ASM_X86_SECCOMP_H */ diff --git a/arch/x86/include/asm/seccomp_32.h b/arch/x86/include/asm/seccomp_32.h deleted file mode 100644 index b811d6f..0000000 --- a/arch/x86/include/asm/seccomp_32.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASM_X86_SECCOMP_32_H -#define _ASM_X86_SECCOMP_32_H - -#include <linux/unistd.h> - -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_sigreturn - -#endif /* _ASM_X86_SECCOMP_32_H */ diff --git a/arch/x86/include/asm/seccomp_64.h b/arch/x86/include/asm/seccomp_64.h deleted file mode 100644 index 84ec1bd..0000000 --- a/arch/x86/include/asm/seccomp_64.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _ASM_X86_SECCOMP_64_H -#define _ASM_X86_SECCOMP_64_H - -#include <linux/unistd.h> -#include <asm/ia32_unistd.h> - -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - -#define __NR_seccomp_read_32 __NR_ia32_read -#define __NR_seccomp_write_32 __NR_ia32_write -#define __NR_seccomp_exit_32 __NR_ia32_exit -#define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn - -#endif /* _ASM_X86_SECCOMP_64_H */ diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 05abae8..a0ef4f7 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -15,6 +15,7 @@ #include "clk-kona.h" #include <linux/delay.h> +#include <linux/kernel.h> /* * "Policies" affect the frequencies of bus clocks provided by a @@ -51,21 +52,6 @@ static inline u32 bitfield_replace(u32 reg_val, u32 shift, u32 width, u32 val) /* Divider and scaling helpers */ -/* - * Implement DIV_ROUND_CLOSEST() for 64-bit dividend and both values - * unsigned. Note that unlike do_div(), the remainder is discarded - * and the return value is the quotient (not the remainder). - */ -u64 do_div_round_closest(u64 dividend, unsigned long divisor) -{ - u64 result; - - result = dividend + ((u64)divisor >> 1); - (void)do_div(result, divisor); - - return result; -} - /* Convert a divider into the scaled divisor value it represents. */ static inline u64 scaled_div_value(struct bcm_clk_div *div, u32 reg_div) { @@ -87,7 +73,7 @@ u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths) combined = (u64)div_value * BILLION + billionths; combined <<= div->u.s.frac_width; - return do_div_round_closest(combined, BILLION); + return DIV_ROUND_CLOSEST_ULL(combined, BILLION); } /* The scaled minimum divisor representable by a divider */ @@ -731,7 +717,7 @@ static unsigned long clk_recalc_rate(struct ccu_data *ccu, scaled_rate = scale_rate(pre_div, parent_rate); scaled_rate = scale_rate(div, scaled_rate); scaled_div = divider_read_scaled(ccu, pre_div); - scaled_parent_rate = do_div_round_closest(scaled_rate, + scaled_parent_rate = DIV_ROUND_CLOSEST_ULL(scaled_rate, scaled_div); } else { scaled_parent_rate = scale_rate(div, parent_rate); @@ -743,7 +729,7 @@ static unsigned long clk_recalc_rate(struct ccu_data *ccu, * rate. */ scaled_div = divider_read_scaled(ccu, div); - result = do_div_round_closest(scaled_parent_rate, scaled_div); + result = DIV_ROUND_CLOSEST_ULL(scaled_parent_rate, scaled_div); return (unsigned long)result; } @@ -790,7 +776,7 @@ static long round_rate(struct ccu_data *ccu, struct bcm_clk_div *div, scaled_rate = scale_rate(pre_div, parent_rate); scaled_rate = scale_rate(div, scaled_rate); scaled_pre_div = divider_read_scaled(ccu, pre_div); - scaled_parent_rate = do_div_round_closest(scaled_rate, + scaled_parent_rate = DIV_ROUND_CLOSEST_ULL(scaled_rate, scaled_pre_div); } else { scaled_parent_rate = scale_rate(div, parent_rate); @@ -802,7 +788,7 @@ static long round_rate(struct ccu_data *ccu, struct bcm_clk_div *div, * the best we can do. */ if (!divider_is_fixed(div)) { - best_scaled_div = do_div_round_closest(scaled_parent_rate, + best_scaled_div = DIV_ROUND_CLOSEST_ULL(scaled_parent_rate, rate); min_scaled_div = scaled_div_min(div); max_scaled_div = scaled_div_max(div); @@ -815,7 +801,7 @@ static long round_rate(struct ccu_data *ccu, struct bcm_clk_div *div, } /* OK, figure out the resulting rate */ - result = do_div_round_closest(scaled_parent_rate, best_scaled_div); + result = DIV_ROUND_CLOSEST_ULL(scaled_parent_rate, best_scaled_div); if (scaled_div) *scaled_div = best_scaled_div; diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index 2537b30..6849a64 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h @@ -503,7 +503,6 @@ extern struct clk_ops kona_peri_clk_ops; /* Externally visible functions */ -extern u64 do_div_round_closest(u64 dividend, unsigned long divisor); extern u64 scaled_div_max(struct bcm_clk_div *div); extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths); diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 4058079..b8a5fa1 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -190,12 +190,6 @@ static DEFINE_PER_CPU(struct menu_device, menu_devices); static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); -/* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ -static u64 div_round64(u64 dividend, u32 divisor) -{ - return div_u64(dividend + (divisor / 2), divisor); -} - /* * Try detecting repeating patterns by keeping track of the last 8 * intervals, and checking if the standard deviation of that set @@ -317,7 +311,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * operands are 32 bits. * Make sure to round up for half microseconds. */ - data->predicted_us = div_round64((uint64_t)data->next_timer_us * + data->predicted_us = DIV_ROUND_CLOSEST_ULL((uint64_t)data->next_timer_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eef79cc..ba243db 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -36,9 +36,6 @@ #include <drm/drm_dp_mst_helper.h> #include <drm/drm_rect.h> -#define DIV_ROUND_CLOSEST_ULL(ll, d) \ -({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) - /** * _wait_for - magic (register) wait macro * diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index d8686ce..08532d4 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/kernel.h> #include <linux/moduleparam.h> #include "intel_drv.h" diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index d1542b7..4d28150 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -36,6 +36,7 @@ #include <linux/jiffies.h> #include <linux/of.h> #include <linux/delay.h> +#include <linux/util_macros.h> #include <linux/platform_data/ina2xx.h> @@ -141,19 +142,6 @@ static const struct ina2xx_config ina2xx_config[] = { */ static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 }; -static int ina226_avg_bits(int avg) -{ - int i; - - /* Get the closest average from the tab. */ - for (i = 0; i < ARRAY_SIZE(ina226_avg_tab) - 1; i++) { - if (avg <= (ina226_avg_tab[i] + ina226_avg_tab[i + 1]) / 2) - break; - } - - return i; /* Return 0b0111 for values greater than 1024. */ -} - static int ina226_reg_to_interval(u16 config) { int avg = ina226_avg_tab[INA226_READ_AVG(config)]; @@ -171,7 +159,8 @@ static u16 ina226_interval_to_reg(int interval, u16 config) avg = DIV_ROUND_CLOSEST(interval * 1000, INA226_TOTAL_CONV_TIME_DEFAULT); - avg_bits = ina226_avg_bits(avg); + avg_bits = find_closest(avg, ina226_avg_tab, + ARRAY_SIZE(ina226_avg_tab)); return (config & ~INA226_AVG_RD_MASK) | INA226_SHIFT_AVG(avg_bits); } diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 2b4b419..6ff773f 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -34,6 +34,7 @@ #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> +#include <linux/util_macros.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; @@ -190,15 +191,7 @@ static const int lm85_range_map[] = { static int RANGE_TO_REG(long range) { - int i; - - /* Find the closest match */ - for (i = 0; i < 15; ++i) { - if (range <= (lm85_range_map[i] + lm85_range_map[i + 1]) / 2) - break; - } - - return i; + return find_closest(range, lm85_range_map, ARRAY_SIZE(lm85_range_map)); } #define RANGE_FROM_REG(val) lm85_range_map[(val) & 0x0f] @@ -209,16 +202,12 @@ static const int lm85_freq_map[8] = { /* 1 Hz */ static const int adm1027_freq_map[8] = { /* 1 Hz */ 11, 15, 22, 29, 35, 44, 59, 88 }; +#define FREQ_MAP_LEN 8 -static int FREQ_TO_REG(const int *map, unsigned long freq) +static int FREQ_TO_REG(const int *map, + unsigned int map_size, unsigned long freq) { - int i; - - /* Find the closest match */ - for (i = 0; i < 7; ++i) - if (freq <= (map[i] + map[i + 1]) / 2) - break; - return i; + return find_closest(freq, map, map_size); } static int FREQ_FROM_REG(const int *map, u8 reg) @@ -828,7 +817,8 @@ static ssize_t set_pwm_freq(struct device *dev, data->cfg5 &= ~ADT7468_HFPWM; lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5); } else { /* Low freq. mode */ - data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val); + data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, + FREQ_MAP_LEN, val); lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), (data->zone[nr].range << 4) | data->pwm_freq[nr]); diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 2189413..49276bb 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -35,6 +35,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/jiffies.h> +#include <linux/util_macros.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { @@ -308,11 +309,8 @@ static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) unsigned long best0, best1; /* Best fit for cksel = 0 */ - for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { - if (val > (pwm_freq_cksel0[reg0] + - pwm_freq_cksel0[reg0 + 1]) / 2) - break; - } + reg0 = find_closest_descending(val, pwm_freq_cksel0, + ARRAY_SIZE(pwm_freq_cksel0)); if (val < 375) /* cksel = 1 can't beat this */ return reg0; best0 = pwm_freq_cksel0[reg0]; diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 149fdca..72b0e2db 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -79,7 +79,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) num = if_freq / 1000; /* Hz => kHz */ num *= 0x4000; - if_ctl = 0x4000 - cxd2820r_div_u64_round_closest(num, 41000); + if_ctl = 0x4000 - DIV_ROUND_CLOSEST_ULL(num, 41000); buf[0] = (if_ctl >> 8) & 0x3f; buf[1] = (if_ctl >> 0) & 0xff; diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 422e84b..490e090 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -244,12 +244,6 @@ error: return ret; } -/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */ -u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor) -{ - return div_u64(dividend + (divisor / 2), divisor); -} - static int cxd2820r_set_frontend(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index 7ff5f60..4b42895 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -64,8 +64,6 @@ int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, int len); -u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor); - int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, int len); diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 51401d0..008cb2a 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -103,7 +103,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) num = if_freq / 1000; /* Hz => kHz */ num *= 0x1000000; - if_ctl = cxd2820r_div_u64_round_closest(num, 41000); + if_ctl = DIV_ROUND_CLOSEST_ULL(num, 41000); buf[0] = ((if_ctl >> 16) & 0xff); buf[1] = ((if_ctl >> 8) & 0xff); buf[2] = ((if_ctl >> 0) & 0xff); diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index 9c0c4f4..35fe364 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c @@ -120,7 +120,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) num = if_freq / 1000; /* Hz => kHz */ num *= 0x1000000; - if_ctl = cxd2820r_div_u64_round_closest(num, 41000); + if_ctl = DIV_ROUND_CLOSEST_ULL(num, 41000); buf[0] = ((if_ctl >> 16) & 0xff); buf[1] = ((if_ctl >> 8) & 0xff); buf[2] = ((if_ctl >> 0) & 0xff); diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index fc145d2..922a750 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -758,7 +758,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { if (msb->data_dir == READ) { - for (cnt = 0; cnt < msb->current_seg; cnt++) + for (cnt = 0; cnt < msb->current_seg; cnt++) { t_len += msb->req_sg[cnt].length / msb->page_size; @@ -766,6 +766,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) t_len += msb->current_page - 1; t_len *= msb->page_size; + } } } else t_len = blk_rq_bytes(msb->block_req); diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d93b2b6..82f7000 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -21,6 +21,7 @@ * objects. */ +#include <linux/file.h> #include <linux/mm.h> #include <linux/workqueue.h> #include <linux/notifier.h> @@ -224,10 +225,18 @@ static inline unsigned long fast_get_dcookie(struct path *path) static unsigned long get_exec_dcookie(struct mm_struct *mm) { unsigned long cookie = NO_COOKIE; + struct file *exe_file; - if (mm && mm->exe_file) - cookie = fast_get_dcookie(&mm->exe_file->f_path); + if (!mm) + goto done; + + exe_file = get_mm_exe_file(mm); + if (!exe_file) + goto done; + cookie = fast_get_dcookie(&exe_file->f_path); + fput(exe_file); +done: return cookie; } @@ -236,6 +245,8 @@ static unsigned long get_exec_dcookie(struct mm_struct *mm) * pair that can then be added to the global event buffer. We make * sure to do this lookup before a mm->mmap modification happens so * we don't lose track. + * + * The caller must ensure the mm is not nil (ie: not a kernel thread). */ static unsigned long lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) @@ -243,6 +254,7 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) unsigned long cookie = NO_COOKIE; struct vm_area_struct *vma; + down_read(&mm->mmap_sem); for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { if (addr < vma->vm_start || addr >= vma->vm_end) @@ -262,6 +274,7 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) if (!vma) cookie = INVALID_COOKIE; + up_read(&mm->mmap_sem); return cookie; } @@ -402,20 +415,9 @@ static void release_mm(struct mm_struct *mm) { if (!mm) return; - up_read(&mm->mmap_sem); mmput(mm); } - -static struct mm_struct *take_tasks_mm(struct task_struct *task) -{ - struct mm_struct *mm = get_task_mm(task); - if (mm) - down_read(&mm->mmap_sem); - return mm; -} - - static inline int is_code(unsigned long val) { return val == ESCAPE_CODE; @@ -532,7 +534,7 @@ void sync_buffer(int cpu) new = (struct task_struct *)val; oldmm = mm; release_mm(oldmm); - mm = take_tasks_mm(new); + mm = get_task_mm(new); if (mm != oldmm) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b5b5c3d..6149ae0 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1111,6 +1111,16 @@ config RTC_DRV_DAVINCI This driver can also be built as a module. If so, the module will be called rtc-davinci. +config RTC_DRV_DIGICOLOR + tristate "Conexant Digicolor RTC" + depends on ARCH_DIGICOLOR + help + If you say yes here you get support for the RTC on Conexant + Digicolor platforms. This currently includes the CX92755 SoC. + + This driver can also be built as a module. If so, the module + will be called rtc-digicolor. + config RTC_DRV_IMXDI tristate "Freescale IMX DryIce Real Time Clock" depends on ARCH_MXC @@ -1121,11 +1131,11 @@ config RTC_DRV_IMXDI will be called "rtc-imxdi". config RTC_DRV_OMAP - tristate "TI OMAP1" - depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX || SOC_AM33XX + tristate "TI OMAP Real Time Clock" + depends on ARCH_OMAP || ARCH_DAVINCI help Say "yes" here to support the on chip real time clock - present on TI OMAP1, AM33xx and DA8xx/OMAP-L13x. + present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. This driver can also be built as a module, if so, module will be called rtc-omap. diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 69c8706..c31731c 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o +obj-$(CONFIG_RTC_DRV_DIGICOLOR) += rtc-digicolor.o obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index c29ba7e..ea2a315 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -221,15 +221,15 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; + strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); + dev_set_name(&rtc->dev, "rtc%d", id); + /* Check to see if there is an ALARM already set in hw */ err = __rtc_read_alarm(rtc, &alrm); if (!err && !rtc_valid_tm(&alrm.time)) rtc_initialize_alarm(rtc, &alrm); - strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); - dev_set_name(&rtc->dev, "rtc%d", id); - rtc_dev_prepare(rtc); err = device_register(&rtc->dev); diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index 6c719f2..e1cfa06 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -9,6 +9,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/rtc.h> /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary @@ -32,8 +34,8 @@ static int __init rtc_hctosys(void) struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); if (rtc == NULL) { - pr_err("%s: unable to open rtc device (%s)\n", - __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); + pr_info("unable to open rtc device (%s)\n", + CONFIG_RTC_HCTOSYS_DEVICE); goto err_open; } diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d43ee40..166fc60 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -31,13 +31,14 @@ static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) memset(tm, 0, sizeof(struct rtc_time)); err = rtc->ops->read_time(rtc->dev.parent, tm); if (err < 0) { - dev_err(&rtc->dev, "read_time: fail to read\n"); + dev_dbg(&rtc->dev, "read_time: fail to read: %d\n", + err); return err; } err = rtc_valid_tm(tm); if (err < 0) - dev_err(&rtc->dev, "read_time: rtc_time isn't valid\n"); + dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n"); } return err; } diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index cfc2ef9..b5cbc1b 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -881,7 +881,7 @@ static const struct rtc_class_ops rtc_ops = { .alarm_irq_enable = abb5zes3_rtc_alarm_irq_enable, }; -static struct regmap_config abb5zes3_rtc_regmap_config = { +static const struct regmap_config abb5zes3_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, }; diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index b283a1a..35efd3f 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -37,9 +37,9 @@ #include "rtc-at91rm9200.h" #define at91_rtc_read(field) \ - __raw_readl(at91_rtc_regs + field) + readl_relaxed(at91_rtc_regs + field) #define at91_rtc_write(field, val) \ - __raw_writel((val), at91_rtc_regs + field) + writel_relaxed((val), at91_rtc_regs + field) #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 87647f4..a82556a 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -28,6 +28,9 @@ * interrupts disabled, holding the global rtc_lock, to exclude those * other drivers and utilities on correctly configured systems. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -385,8 +388,7 @@ static bool alarm_disable_quirk; static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) { alarm_disable_quirk = true; - pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); - pr_info("RTC alarms disabled\n"); + pr_info("BIOS has alarm-disable quirk - RTC alarms disabled\n"); return 0; } diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 613c43b..1ba4371 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/err.h> +#include <linux/delay.h> #include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h> @@ -23,6 +24,8 @@ #define rtc_err(rtc, fmt, ...) \ dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) +#define DA9052_GET_TIME_RETRIES 5 + struct da9052_rtc { struct rtc_device *rtc; struct da9052 *da9052; @@ -58,22 +61,43 @@ static irqreturn_t da9052_rtc_irq(int irq, void *data) static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) { int ret; - uint8_t v[5]; + uint8_t v[2][5]; + int idx = 1; + int timeout = DA9052_GET_TIME_RETRIES; - ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v); - if (ret != 0) { + ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, &v[0][0]); + if (ret) { rtc_err(rtc, "Failed to group read ALM: %d\n", ret); return ret; } - rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100; - rtc_tm->tm_mon = (v[3] & DA9052_RTC_MONTH) - 1; - rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY; - rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR; - rtc_tm->tm_min = v[0] & DA9052_RTC_MIN; + do { + ret = da9052_group_read(rtc->da9052, + DA9052_ALARM_MI_REG, 5, &v[idx][0]); + if (ret) { + rtc_err(rtc, "Failed to group read ALM: %d\n", ret); + return ret; + } - ret = rtc_valid_tm(rtc_tm); - return ret; + if (memcmp(&v[0][0], &v[1][0], 5) == 0) { + rtc_tm->tm_year = (v[0][4] & DA9052_RTC_YEAR) + 100; + rtc_tm->tm_mon = (v[0][3] & DA9052_RTC_MONTH) - 1; + rtc_tm->tm_mday = v[0][2] & DA9052_RTC_DAY; + rtc_tm->tm_hour = v[0][1] & DA9052_RTC_HOUR; + rtc_tm->tm_min = v[0][0] & DA9052_RTC_MIN; + + ret = rtc_valid_tm(rtc_tm); + return ret; + } + + idx = (1-idx); + msleep(20); + + } while (timeout--); + + rtc_err(rtc, "Timed out reading alarm time\n"); + + return -EIO; } static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) @@ -135,24 +159,45 @@ static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc) static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) { struct da9052_rtc *rtc = dev_get_drvdata(dev); - uint8_t v[6]; int ret; + uint8_t v[2][6]; + int idx = 1; + int timeout = DA9052_GET_TIME_RETRIES; - ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v); - if (ret < 0) { + ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, &v[0][0]); + if (ret) { rtc_err(rtc, "Failed to read RTC time : %d\n", ret); return ret; } - rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100; - rtc_tm->tm_mon = (v[4] & DA9052_RTC_MONTH) - 1; - rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY; - rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR; - rtc_tm->tm_min = v[1] & DA9052_RTC_MIN; - rtc_tm->tm_sec = v[0] & DA9052_RTC_SEC; + do { + ret = da9052_group_read(rtc->da9052, + DA9052_COUNT_S_REG, 6, &v[idx][0]); + if (ret) { + rtc_err(rtc, "Failed to read RTC time : %d\n", ret); + return ret; + } - ret = rtc_valid_tm(rtc_tm); - return ret; + if (memcmp(&v[0][0], &v[1][0], 6) == 0) { + rtc_tm->tm_year = (v[0][5] & DA9052_RTC_YEAR) + 100; + rtc_tm->tm_mon = (v[0][4] & DA9052_RTC_MONTH) - 1; + rtc_tm->tm_mday = v[0][3] & DA9052_RTC_DAY; + rtc_tm->tm_hour = v[0][2] & DA9052_RTC_HOUR; + rtc_tm->tm_min = v[0][1] & DA9052_RTC_MIN; + rtc_tm->tm_sec = v[0][0] & DA9052_RTC_SEC; + + ret = rtc_valid_tm(rtc_tm); + return ret; + } + + idx = (1-idx); + msleep(20); + + } while (timeout--); + + rtc_err(rtc, "Timed out reading time\n"); + + return -EIO; } static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -161,6 +206,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) uint8_t v[6]; int ret; + /* DA9052 only has 6 bits for year - to represent 2000-2063 */ + if ((tm->tm_year < 100) || (tm->tm_year > 163)) + return -EINVAL; + rtc = dev_get_drvdata(dev); v[0] = tm->tm_sec; @@ -198,6 +247,10 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; struct da9052_rtc *rtc = dev_get_drvdata(dev); + /* DA9052 only has 6 bits for year - to represent 2000-2063 */ + if ((tm->tm_year < 100) || (tm->tm_year > 163)) + return -EINVAL; + ret = da9052_rtc_enable_alarm(rtc, 0); if (ret < 0) return ret; @@ -256,6 +309,8 @@ static int da9052_rtc_probe(struct platform_device *pdev) return ret; } + device_init_wakeup(&pdev->dev, true); + rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &da9052_rtc_ops, THIS_MODULE); return PTR_ERR_OR_ZERO(rtc->rtc); diff --git a/drivers/rtc/rtc-digicolor.c b/drivers/rtc/rtc-digicolor.c new file mode 100644 index 0000000..8d05596 --- /dev/null +++ b/drivers/rtc/rtc-digicolor.c @@ -0,0 +1,227 @@ +/* + * Real Time Clock driver for Conexant Digicolor + * + * Copyright (C) 2015 Paradox Innovation Ltd. + * + * Author: Baruch Siach <baruch@tkos.co.il> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/of.h> + +#define DC_RTC_CONTROL 0x0 +#define DC_RTC_TIME 0x8 +#define DC_RTC_REFERENCE 0xc +#define DC_RTC_ALARM 0x10 +#define DC_RTC_INTFLAG_CLEAR 0x14 +#define DC_RTC_INTENABLE 0x16 + +#define DC_RTC_CMD_MASK 0xf +#define DC_RTC_GO_BUSY BIT(7) + +#define CMD_NOP 0 +#define CMD_RESET 1 +#define CMD_WRITE 3 +#define CMD_READ 4 + +#define CMD_DELAY_US (10*1000) +#define CMD_TIMEOUT_US (500*CMD_DELAY_US) + +struct dc_rtc { + struct rtc_device *rtc_dev; + void __iomem *regs; +}; + +static int dc_rtc_cmds(struct dc_rtc *rtc, const u8 *cmds, int len) +{ + u8 val; + int i, ret; + + for (i = 0; i < len; i++) { + writeb_relaxed((cmds[i] & DC_RTC_CMD_MASK) | DC_RTC_GO_BUSY, + rtc->regs + DC_RTC_CONTROL); + ret = readb_relaxed_poll_timeout( + rtc->regs + DC_RTC_CONTROL, val, + !(val & DC_RTC_GO_BUSY), CMD_DELAY_US, CMD_TIMEOUT_US); + if (ret < 0) + return ret; + } + + return 0; +} + +static int dc_rtc_read(struct dc_rtc *rtc, unsigned long *val) +{ + static const u8 read_cmds[] = {CMD_READ, CMD_NOP}; + u32 reference, time1, time2; + int ret; + + ret = dc_rtc_cmds(rtc, read_cmds, ARRAY_SIZE(read_cmds)); + if (ret < 0) + return ret; + + reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE); + time1 = readl_relaxed(rtc->regs + DC_RTC_TIME); + /* Read twice to ensure consistency */ + while (1) { + time2 = readl_relaxed(rtc->regs + DC_RTC_TIME); + if (time1 == time2) + break; + time1 = time2; + } + + *val = reference + time1; + return 0; +} + +static int dc_rtc_write(struct dc_rtc *rtc, u32 val) +{ + static const u8 write_cmds[] = {CMD_WRITE, CMD_NOP, CMD_RESET, CMD_NOP}; + + writel_relaxed(val, rtc->regs + DC_RTC_REFERENCE); + return dc_rtc_cmds(rtc, write_cmds, ARRAY_SIZE(write_cmds)); +} + +static int dc_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct dc_rtc *rtc = dev_get_drvdata(dev); + unsigned long now; + int ret; + + ret = dc_rtc_read(rtc, &now); + if (ret < 0) + return ret; + rtc_time64_to_tm(now, tm); + + return 0; +} + +static int dc_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct dc_rtc *rtc = dev_get_drvdata(dev); + + return dc_rtc_write(rtc, secs); +} + +static int dc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct dc_rtc *rtc = dev_get_drvdata(dev); + u32 alarm_reg, reference; + unsigned long now; + int ret; + + alarm_reg = readl_relaxed(rtc->regs + DC_RTC_ALARM); + reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE); + rtc_time64_to_tm(reference + alarm_reg, &alarm->time); + + ret = dc_rtc_read(rtc, &now); + if (ret < 0) + return ret; + + alarm->pending = alarm_reg + reference > now; + alarm->enabled = readl_relaxed(rtc->regs + DC_RTC_INTENABLE); + + return 0; +} + +static int dc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct dc_rtc *rtc = dev_get_drvdata(dev); + time64_t alarm_time; + u32 reference; + + alarm_time = rtc_tm_to_time64(&alarm->time); + + reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE); + writel_relaxed(alarm_time - reference, rtc->regs + DC_RTC_ALARM); + + writeb_relaxed(!!alarm->enabled, rtc->regs + DC_RTC_INTENABLE); + + return 0; +} + +static int dc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct dc_rtc *rtc = dev_get_drvdata(dev); + + writeb_relaxed(!!enabled, rtc->regs + DC_RTC_INTENABLE); + + return 0; +} + +static struct rtc_class_ops dc_rtc_ops = { + .read_time = dc_rtc_read_time, + .set_mmss = dc_rtc_set_mmss, + .read_alarm = dc_rtc_read_alarm, + .set_alarm = dc_rtc_set_alarm, + .alarm_irq_enable = dc_rtc_alarm_irq_enable, +}; + +static irqreturn_t dc_rtc_irq(int irq, void *dev_id) +{ + struct dc_rtc *rtc = dev_id; + + writeb_relaxed(1, rtc->regs + DC_RTC_INTFLAG_CLEAR); + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + + return IRQ_HANDLED; +} + +static int __init dc_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct dc_rtc *rtc; + int irq, ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtc->regs)) + return PTR_ERR(rtc->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ret = devm_request_irq(&pdev->dev, irq, dc_rtc_irq, 0, pdev->name, rtc); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, rtc); + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, + &dc_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + return 0; +} + +static const struct of_device_id dc_dt_ids[] = { + { .compatible = "cnxt,cx92755-rtc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dc_dt_ids); + +static struct platform_driver dc_rtc_driver = { + .driver = { + .name = "digicolor_rtc", + .of_match_table = of_match_ptr(dc_dt_ids), + }, +}; +module_platform_driver_probe(dc_rtc_driver, dc_rtc_probe); + +MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); +MODULE_DESCRIPTION("Conexant Digicolor Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 8605fde..167783f 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -18,6 +18,8 @@ * "Sending and receiving", using SMBus level communication is preferred. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -406,7 +408,7 @@ static int ds1374_wdt_settimeout(unsigned int timeout) /* Set new watchdog time */ ret = ds1374_write_rtc(save_client, timeout, DS1374_REG_WDALM0, 3); if (ret) { - pr_info("rtc-ds1374 - couldn't set new watchdog time\n"); + pr_info("couldn't set new watchdog time\n"); goto out; } @@ -539,12 +541,12 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, return -EFAULT; if (options & WDIOS_DISABLECARD) { - pr_info("rtc-ds1374: disable watchdog\n"); + pr_info("disable watchdog\n"); ds1374_wdt_disable(); } if (options & WDIOS_ENABLECARD) { - pr_info("rtc-ds1374: enable watchdog\n"); + pr_info("enable watchdog\n"); ds1374_wdt_settimeout(wdt_margin); ds1374_wdt_ping(); } diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 803869c..818a363 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -16,6 +16,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/bcd.h> #include <linux/delay.h> #include <linux/io.h> @@ -799,7 +801,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq) struct platform_device *pdev = to_platform_device(dev); struct ds1685_priv *rtc = platform_get_drvdata(pdev); u8 ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b, ssn[8]; - char *model = '\0'; + char *model; #ifdef CONFIG_RTC_DS1685_PROC_REGS char bits[NUM_REGS][(NUM_BITS * NUM_SPACES) + NUM_BITS + 1]; #endif @@ -2139,7 +2141,6 @@ ds1685_rtc_remove(struct platform_device *pdev) static struct platform_driver ds1685_rtc_driver = { .driver = { .name = "rtc-ds1685", - .owner = THIS_MODULE, }, .probe = ds1685_rtc_probe, .remove = ds1685_rtc_remove, @@ -2175,7 +2176,7 @@ module_exit(ds1685_rtc_exit); * ds1685_rtc_poweroff - uses the RTC chip to power the system off. * @pdev: pointer to platform_device structure. */ -extern void __noreturn +void __noreturn ds1685_rtc_poweroff(struct platform_device *pdev) { u8 ctrla, ctrl4a, ctrl4b; @@ -2183,7 +2184,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev) /* Check for valid RTC data, else, spin forever. */ if (unlikely(!pdev)) { - pr_emerg("rtc-ds1685: platform device data not available, spinning forever ...\n"); + pr_emerg("platform device data not available, spinning forever ...\n"); unreachable(); } else { /* Get the rtc data. */ diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index adaf06c..7e48e53 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -15,6 +15,8 @@ * "Sending and receiving", using SMBus level communication is preferred. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -373,8 +375,8 @@ static void ds3232_work(struct work_struct *work) if (stat & DS3232_REG_SR_A1F) { control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); if (control < 0) { - pr_warn("Read DS3232 Control Register error." - "Disable IRQ%d.\n", client->irq); + pr_warn("Read Control Register error - Disable IRQ%d\n", + client->irq); } else { /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); diff --git a/drivers/rtc/rtc-efi-platform.c b/drivers/rtc/rtc-efi-platform.c index b40fbe3..1a7f1d1 100644 --- a/drivers/rtc/rtc-efi-platform.c +++ b/drivers/rtc/rtc-efi-platform.c @@ -8,6 +8,9 @@ * Copyright (C) 1999-2000 VA Linux Systems * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com> */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c index fccf366..4f4930a 100644 --- a/drivers/rtc/rtc-em3027.c +++ b/drivers/rtc/rtc-em3027.c @@ -15,6 +15,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/module.h> +#include <linux/of.h> /* Registers */ #define EM3027_REG_ON_OFF_CTRL 0x00 @@ -135,10 +136,20 @@ static struct i2c_device_id em3027_id[] = { { "em3027", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, em3027_id); + +#ifdef CONFIG_OF +static const struct of_device_id em3027_of_match[] = { + { .compatible = "emmicro,em3027", }, + {} +}; +MODULE_DEVICE_TABLE(of, em3027_of_match); +#endif static struct i2c_driver em3027_driver = { .driver = { .name = "rtc-em3027", + .of_match_table = of_match_ptr(em3027_of_match), }, .probe = &em3027_probe, .id_table = em3027_id, diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index b936bb4..0f710e9 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -66,7 +66,7 @@ #define HYM8563_ALM_BIT_DISABLE BIT(7) #define HYM8563_CLKOUT 0x0d -#define HYM8563_CLKOUT_DISABLE BIT(7) +#define HYM8563_CLKOUT_ENABLE BIT(7) #define HYM8563_CLKOUT_32768 0 #define HYM8563_CLKOUT_1024 1 #define HYM8563_CLKOUT_32 2 @@ -309,7 +309,7 @@ static unsigned long hym8563_clkout_recalc_rate(struct clk_hw *hw, struct i2c_client *client = hym8563->client; int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); - if (ret < 0 || ret & HYM8563_CLKOUT_DISABLE) + if (ret < 0) return 0; ret &= HYM8563_CLKOUT_MASK; @@ -360,9 +360,9 @@ static int hym8563_clkout_control(struct clk_hw *hw, bool enable) return ret; if (enable) - ret &= ~HYM8563_CLKOUT_DISABLE; + ret |= HYM8563_CLKOUT_ENABLE; else - ret |= HYM8563_CLKOUT_DISABLE; + ret &= ~HYM8563_CLKOUT_ENABLE; return i2c_smbus_write_byte_data(client, HYM8563_CLKOUT, ret); } @@ -386,7 +386,7 @@ static int hym8563_clkout_is_prepared(struct clk_hw *hw) if (ret < 0) return ret; - return !(ret & HYM8563_CLKOUT_DISABLE); + return !!(ret & HYM8563_CLKOUT_ENABLE); } static const struct clk_ops hym8563_clkout_ops = { @@ -407,7 +407,7 @@ static struct clk *hym8563_clkout_register_clk(struct hym8563 *hym8563) int ret; ret = i2c_smbus_write_byte_data(client, HYM8563_CLKOUT, - HYM8563_CLKOUT_DISABLE); + 0); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 7ff7427..a82937e 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/bcd.h> #include <linux/i2c.h> #include <linux/init.h> @@ -513,12 +515,12 @@ static int wdt_ioctl(struct file *file, unsigned int cmd, return -EFAULT; if (rv & WDIOS_DISABLECARD) { - pr_info("rtc-m41t80: disable watchdog\n"); + pr_info("disable watchdog\n"); wdt_disable(); } if (rv & WDIOS_ENABLECARD) { - pr_info("rtc-m41t80: enable watchdog\n"); + pr_info("enable watchdog\n"); wdt_ping(); } diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 9d71328..7632a87 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -12,6 +12,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/slab.h> #include <linux/rtc.h> #include <linux/delay.h> @@ -103,8 +105,8 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; if (tm->tm_year < 100) { - pr_warn("%s: MAX77686 RTC cannot handle the year %d." - "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); + pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n", + 1900 + tm->tm_year); return -EINVAL; } return 0; diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index 67fbe55..9e02bcd 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -12,6 +12,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/slab.h> #include <linux/rtc.h> #include <linux/delay.h> @@ -107,8 +109,8 @@ static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data) data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; if (tm->tm_year < 100) { - pr_warn("%s: MAX8997 RTC cannot handle the year %d." - "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); + pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n", + 1900 + tm->tm_year); return -EINVAL; } return 0; @@ -424,7 +426,7 @@ static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable) val = 0; max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val); - pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); + pr_info("WTSR_SMPL(0x%02x)\n", val); } static int max8997_rtc_init_reg(struct max8997_rtc_info *info) diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 9bf877b..c1c5c4e 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -7,6 +7,8 @@ * Copyright (C) 1993 Hamish Macdonald */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/delay.h> #include <linux/io.h> #include <linux/kernel.h> @@ -111,7 +113,7 @@ static void msm6242_lock(struct msm6242_priv *priv) } if (!cnt) - pr_warn("msm6242: timed out waiting for RTC (0x%x)\n", + pr_warn("timed out waiting for RTC (0x%x)\n", msm6242_read(priv, MSM6242_CD)); } diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8e5851a..8b6355f 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -118,12 +118,15 @@ #define KICK0_VALUE 0x83e70b13 #define KICK1_VALUE 0x95a4f1e0 +struct omap_rtc; + struct omap_rtc_device_type { bool has_32kclk_en; - bool has_kicker; bool has_irqwakeen; bool has_pmic_mode; bool has_power_up_reset; + void (*lock)(struct omap_rtc *rtc); + void (*unlock)(struct omap_rtc *rtc); }; struct omap_rtc { @@ -156,6 +159,26 @@ static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val) writel(val, rtc->base + reg); } +static void am3352_rtc_unlock(struct omap_rtc *rtc) +{ + rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE); + rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE); +} + +static void am3352_rtc_lock(struct omap_rtc *rtc) +{ + rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); + rtc_writel(rtc, OMAP_RTC_KICK1_REG, 0); +} + +static void default_rtc_unlock(struct omap_rtc *rtc) +{ +} + +static void default_rtc_lock(struct omap_rtc *rtc) +{ +} + /* * We rely on the rtc framework to handle locking (rtc->ops_lock), * so the only other requirement is that register accesses which @@ -186,7 +209,9 @@ static irqreturn_t rtc_irq(int irq, void *dev_id) /* alarm irq? */ if (irq_data & OMAP_RTC_STATUS_ALARM) { + rtc->type->unlock(rtc); rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM); + rtc->type->lock(rtc); events |= RTC_IRQF | RTC_AF; } @@ -218,9 +243,11 @@ static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; } rtc_wait_not_busy(rtc); + rtc->type->unlock(rtc); rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); if (rtc->type->has_irqwakeen) rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); + rtc->type->lock(rtc); local_irq_enable(); return 0; @@ -293,12 +320,14 @@ static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm) local_irq_disable(); rtc_wait_not_busy(rtc); + rtc->type->unlock(rtc); rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year); rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon); rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday); rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour); rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min); rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec); + rtc->type->lock(rtc); local_irq_enable(); @@ -341,6 +370,7 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) local_irq_disable(); rtc_wait_not_busy(rtc); + rtc->type->unlock(rtc); rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year); rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon); rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday); @@ -362,6 +392,7 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); if (rtc->type->has_irqwakeen) rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); + rtc->type->lock(rtc); local_irq_enable(); @@ -391,6 +422,7 @@ static void omap_rtc_power_off(void) unsigned long now; u32 val; + rtc->type->unlock(rtc); /* enable pmic_power_en control */ val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); @@ -423,6 +455,7 @@ static void omap_rtc_power_off(void) val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, val | OMAP_RTC_INTERRUPTS_IT_ALARM2); + rtc->type->lock(rtc); /* * Wait for alarm to trigger (within two seconds) and external PMIC to @@ -442,17 +475,21 @@ static struct rtc_class_ops omap_rtc_ops = { static const struct omap_rtc_device_type omap_rtc_default_type = { .has_power_up_reset = true, + .lock = default_rtc_lock, + .unlock = default_rtc_unlock, }; static const struct omap_rtc_device_type omap_rtc_am3352_type = { .has_32kclk_en = true, - .has_kicker = true, .has_irqwakeen = true, .has_pmic_mode = true, + .lock = am3352_rtc_lock, + .unlock = am3352_rtc_unlock, }; static const struct omap_rtc_device_type omap_rtc_da830_type = { - .has_kicker = true, + .lock = am3352_rtc_lock, + .unlock = am3352_rtc_unlock, }; static const struct platform_device_id omap_rtc_id_table[] = { @@ -484,7 +521,7 @@ static const struct of_device_id omap_rtc_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_rtc_of_match); -static int __init omap_rtc_probe(struct platform_device *pdev) +static int omap_rtc_probe(struct platform_device *pdev) { struct omap_rtc *rtc; struct resource *res; @@ -527,10 +564,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - if (rtc->type->has_kicker) { - rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE); - rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE); - } + rtc->type->unlock(rtc); /* * disable interrupts @@ -593,6 +627,8 @@ static int __init omap_rtc_probe(struct platform_device *pdev) if (reg != new_ctrl) rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); + rtc->type->lock(rtc); + device_init_wakeup(&pdev->dev, true); rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, @@ -626,8 +662,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) err: device_init_wakeup(&pdev->dev, false); - if (rtc->type->has_kicker) - rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); + rtc->type->lock(rtc); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -646,11 +681,11 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); + rtc->type->unlock(rtc); /* leave rtc running, but disable irqs */ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); - if (rtc->type->has_kicker) - rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); + rtc->type->lock(rtc); /* Disable the clock/module */ pm_runtime_put_sync(&pdev->dev); @@ -666,6 +701,7 @@ static int omap_rtc_suspend(struct device *dev) rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + rtc->type->unlock(rtc); /* * FIXME: the RTC alarm is not currently acting as a wakeup event * source on some platforms, and in fact this enable() call is just @@ -675,6 +711,7 @@ static int omap_rtc_suspend(struct device *dev) enable_irq_wake(rtc->irq_alarm); else rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); + rtc->type->lock(rtc); /* Disable the clock/module */ pm_runtime_put_sync(dev); @@ -689,10 +726,12 @@ static int omap_rtc_resume(struct device *dev) /* Enable the clock/module so that we can access the registers */ pm_runtime_get_sync(dev); + rtc->type->unlock(rtc); if (device_may_wakeup(dev)) disable_irq_wake(rtc->irq_alarm); else rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg); + rtc->type->lock(rtc); return 0; } @@ -709,12 +748,15 @@ static void omap_rtc_shutdown(struct platform_device *pdev) * Keep the ALARM interrupt enabled to allow the system to power up on * alarm events. */ + rtc->type->unlock(rtc); mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); mask &= OMAP_RTC_INTERRUPTS_IT_ALARM; rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask); + rtc->type->lock(rtc); } static struct platform_driver omap_rtc_driver = { + .probe = omap_rtc_probe, .remove = __exit_p(omap_rtc_remove), .shutdown = omap_rtc_shutdown, .driver = { @@ -725,7 +767,7 @@ static struct platform_driver omap_rtc_driver = { .id_table = omap_rtc_id_table, }; -module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe); +module_platform_driver(omap_rtc_driver); MODULE_ALIAS("platform:omap_rtc"); MODULE_AUTHOR("George G. Davis (and others)"); diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 95f6521..7061dca 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -16,8 +16,9 @@ * along with this program. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRVNAME "rtc-opal" -#define pr_fmt(fmt) DRVNAME ": " fmt #include <linux/module.h> #include <linux/err.h> diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 96fb32e..0ba7e59 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -246,7 +246,6 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) { struct pcf8563 *pcf8563 = i2c_get_clientdata(client); - int err; unsigned char buf[9]; dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " @@ -272,12 +271,8 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; - err = pcf8563_write_block_data(client, PCF8563_REG_SC, + return pcf8563_write_block_data(client, PCF8563_REG_SC, 9 - PCF8563_REG_SC, buf + PCF8563_REG_SC); - if (err) - return err; - - return 0; } #ifdef CONFIG_RTC_INTF_DEV diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index f4cf685..76cbad7 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -39,7 +39,6 @@ struct s3c_rtc { void __iomem *base; struct clk *rtc_clk; struct clk *rtc_src_clk; - bool enabled; struct s3c_rtc_data *data; @@ -67,26 +66,25 @@ struct s3c_rtc_data { void (*disable) (struct s3c_rtc *info); }; -static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable) +static void s3c_rtc_enable_clk(struct s3c_rtc *info) { unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); - if (enable) { - if (!info->enabled) { - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); - info->enabled = true; - } - } else { - if (info->enabled) { - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - info->enabled = false; - } - } + clk_enable(info->rtc_clk); + if (info->data->needs_src_clk) + clk_enable(info->rtc_src_clk); + spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); +} + +static void s3c_rtc_disable_clk(struct s3c_rtc *info) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); + if (info->data->needs_src_clk) + clk_disable(info->rtc_src_clk); + clk_disable(info->rtc_clk); spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); } @@ -119,20 +117,16 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled); - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + s3c_rtc_enable_clk(info); + tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; if (enabled) tmp |= S3C2410_RTCALM_ALMEN; writeb(tmp, info->base + S3C2410_RTCALM); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - s3c_rtc_alarm_clk_enable(info, enabled); + s3c_rtc_disable_clk(info); return 0; } @@ -143,18 +137,12 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) if (!is_power_of_2(freq)) return -EINVAL; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); spin_lock_irq(&info->pie_lock); if (info->data->set_freq) info->data->set_freq(info, freq); spin_unlock_irq(&info->pie_lock); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); return 0; } @@ -165,9 +153,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) struct s3c_rtc *info = dev_get_drvdata(dev); unsigned int have_retried = 0; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + s3c_rtc_enable_clk(info); retry_get_time: rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN); @@ -194,6 +180,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); + s3c_rtc_disable_clk(info); + rtc_tm->tm_year += 100; dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", @@ -202,10 +190,6 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_mon -= 1; - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - return rtc_valid_tm(rtc_tm); } @@ -225,9 +209,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) return -EINVAL; } - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + s3c_rtc_enable_clk(info); writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC); writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); @@ -236,9 +218,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON); writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); + s3c_rtc_disable_clk(info); return 0; } @@ -249,9 +229,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *alm_tm = &alrm->time; unsigned int alm_en; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + s3c_rtc_enable_clk(info); alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC); alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN); @@ -262,6 +240,8 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alm_en = readb(info->base + S3C2410_RTCALM); + s3c_rtc_disable_clk(info); + alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", @@ -269,9 +249,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); - /* decode the alarm enable field */ - if (alm_en & S3C2410_RTCALM_SECEN) alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); else @@ -304,10 +282,6 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) else alm_tm->tm_year = -1; - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - return 0; } @@ -317,15 +291,13 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned int alrm_en; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); - dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + s3c_rtc_enable_clk(info); + alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; writeb(0x00, info->base + S3C2410_RTCALM); @@ -348,11 +320,9 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(alrm_en, info->base + S3C2410_RTCALM); - s3c_rtc_setaie(dev, alrm->enabled); + s3c_rtc_disable_clk(info); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); + s3c_rtc_setaie(dev, alrm->enabled); return 0; } @@ -361,16 +331,12 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) { struct s3c_rtc *info = dev_get_drvdata(dev); - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + s3c_rtc_enable_clk(info); if (info->data->enable_tick) info->data->enable_tick(info, seq); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); + s3c_rtc_disable_clk(info); return 0; } @@ -388,10 +354,6 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info) { unsigned int con, tmp; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); - con = readw(info->base + S3C2410_RTCCON); /* re-enable the device, and check it is ok */ if ((con & S3C2410_RTCCON_RTCEN) == 0) { @@ -417,20 +379,12 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info) writew(tmp & ~S3C2410_RTCCON_CLKRST, info->base + S3C2410_RTCCON); } - - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); } static void s3c24xx_rtc_disable(struct s3c_rtc *info) { unsigned int con; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); - con = readw(info->base + S3C2410_RTCCON); con &= ~S3C2410_RTCCON_RTCEN; writew(con, info->base + S3C2410_RTCCON); @@ -438,28 +392,16 @@ static void s3c24xx_rtc_disable(struct s3c_rtc *info) con = readb(info->base + S3C2410_TICNT); con &= ~S3C2410_TICNT_ENABLE; writeb(con, info->base + S3C2410_TICNT); - - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); } static void s3c6410_rtc_disable(struct s3c_rtc *info) { unsigned int con; - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); - con = readw(info->base + S3C2410_RTCCON); con &= ~S3C64XX_RTCCON_TICEN; con &= ~S3C2410_RTCCON_RTCEN; writew(con, info->base + S3C2410_RTCCON); - - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); } static int s3c_rtc_remove(struct platform_device *pdev) @@ -554,6 +496,20 @@ static int s3c_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); + /* Check RTC Time */ + if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) { + rtc_tm.tm_year = 100; + rtc_tm.tm_mon = 0; + rtc_tm.tm_mday = 1; + rtc_tm.tm_hour = 0; + rtc_tm.tm_min = 0; + rtc_tm.tm_sec = 0; + + s3c_rtc_settime(&pdev->dev, &rtc_tm); + + dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); + } + /* register RTC and exit */ info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops, THIS_MODULE); @@ -577,36 +533,21 @@ static int s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } - /* Check RTC Time */ - s3c_rtc_gettime(&pdev->dev, &rtc_tm); - - if (rtc_valid_tm(&rtc_tm)) { - rtc_tm.tm_year = 100; - rtc_tm.tm_mon = 0; - rtc_tm.tm_mday = 1; - rtc_tm.tm_hour = 0; - rtc_tm.tm_min = 0; - rtc_tm.tm_sec = 0; - - s3c_rtc_settime(&pdev->dev, &rtc_tm); - - dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); - } - if (info->data->select_tick_clk) info->data->select_tick_clk(info); s3c_rtc_setfreq(info, 1); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); + s3c_rtc_disable_clk(info); return 0; err_nortc: if (info->data->disable) info->data->disable(info); + + if (info->data->needs_src_clk) + clk_disable_unprepare(info->rtc_src_clk); clk_disable_unprepare(info->rtc_clk); return ret; @@ -618,9 +559,7 @@ static int s3c_rtc_suspend(struct device *dev) { struct s3c_rtc *info = dev_get_drvdata(dev); - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + s3c_rtc_enable_clk(info); /* save TICNT for anyone using periodic interrupts */ if (info->data->save_tick_cnt) @@ -636,10 +575,6 @@ static int s3c_rtc_suspend(struct device *dev) dev_err(dev, "enable_irq_wake failed\n"); } - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - return 0; } @@ -647,25 +582,19 @@ static int s3c_rtc_resume(struct device *dev) { struct s3c_rtc *info = dev_get_drvdata(dev); - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); - if (info->data->enable) info->data->enable(info); if (info->data->restore_tick_cnt) info->data->restore_tick_cnt(info); + s3c_rtc_disable_clk(info); + if (device_may_wakeup(dev) && info->wake_en) { disable_irq_wake(info->irq_alarm); info->wake_en = false; } - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - return 0; } #endif @@ -673,29 +602,13 @@ static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask) { - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - - s3c_rtc_alarm_clk_enable(info, false); } static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) { - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); writeb(mask, info->base + S3C2410_INTP); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - - s3c_rtc_alarm_clk_enable(info, false); } static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 4008b84..8c70d78 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -15,6 +15,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/i2c.h> #include <linux/bcd.h> @@ -90,7 +92,7 @@ struct s5m_rtc_info { struct regmap *regmap; struct rtc_device *rtc_dev; int irq; - int device_type; + enum sec_device_type device_type; int rtc_24hr_mode; const struct s5m_rtc_reg_config *regs; }; @@ -146,7 +148,7 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; if (tm->tm_year < 100) { - pr_err("s5m8767 RTC cannot handle the year %d.\n", + pr_err("RTC cannot handle the year %d\n", 1900 + tm->tm_year); return -EINVAL; } else { @@ -187,6 +189,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, val &= S5M_ALARM0_STATUS; break; case S2MPS14X: + case S2MPS13X: ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, &val); val &= S2MPS_ALARM0_STATUS; @@ -252,6 +255,9 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) case S2MPS14X: data |= S2MPS_RTC_RUDR_MASK; break; + case S2MPS13X: + data |= S2MPS13_RTC_AUDR_MASK; + break; default: return -EINVAL; } @@ -265,6 +271,11 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) ret = s5m8767_wait_for_udr_update(info); + /* On S2MPS13 the AUDR is not auto-cleared */ + if (info->device_type == S2MPS13X) + regmap_update_bits(info->regmap, info->regs->rtc_udr_update, + S2MPS13_RTC_AUDR_MASK, 0); + return ret; } @@ -306,7 +317,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) u8 data[info->regs->regs_count]; int ret; - if (info->device_type == S2MPS14X) { + if (info->device_type == S2MPS14X || info->device_type == S2MPS13X) { ret = regmap_update_bits(info->regmap, info->regs->rtc_udr_update, S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); @@ -329,6 +340,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) case S5M8767X: case S2MPS14X: + case S2MPS13X: s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); break; @@ -355,6 +367,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) break; case S5M8767X: case S2MPS14X: + case S2MPS13X: ret = s5m8767_tm_to_data(tm, data); break; default: @@ -402,6 +415,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) case S5M8767X: case S2MPS14X: + case S2MPS13X: s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); alrm->enabled = 0; for (i = 0; i < info->regs->regs_count; i++) { @@ -450,6 +464,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) case S5M8767X: case S2MPS14X: + case S2MPS13X: for (i = 0; i < info->regs->regs_count; i++) data[i] &= ~ALARM_ENABLE_MASK; @@ -494,6 +509,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) case S5M8767X: case S2MPS14X: + case S2MPS13X: data[RTC_SEC] |= ALARM_ENABLE_MASK; data[RTC_MIN] |= ALARM_ENABLE_MASK; data[RTC_HOUR] |= ALARM_ENABLE_MASK; @@ -533,6 +549,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) case S5M8767X: case S2MPS14X: + case S2MPS13X: s5m8767_tm_to_data(&alrm->time, data); break; @@ -615,6 +632,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) break; case S2MPS14X: + case S2MPS13X: data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); break; @@ -650,8 +668,9 @@ static int s5m_rtc_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - switch (pdata->device_type) { + switch (platform_get_device_id(pdev)->driver_data) { case S2MPS14X: + case S2MPS13X: regmap_cfg = &s2mps14_rtc_regmap_config; info->regs = &s2mps_rtc_regs; alarm_irq = S2MPS14_IRQ_RTCA0; @@ -667,7 +686,9 @@ static int s5m_rtc_probe(struct platform_device *pdev) alarm_irq = S5M8767_IRQ_RTCA1; break; default: - dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); + dev_err(&pdev->dev, + "Device type %lu is not supported by RTC driver\n", + platform_get_device_id(pdev)->driver_data); return -ENODEV; } @@ -687,7 +708,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->dev = &pdev->dev; info->s5m87xx = s5m87xx; - info->device_type = s5m87xx->device_type; + info->device_type = platform_get_device_id(pdev)->driver_data; if (s5m87xx->irq_data) { info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); @@ -772,6 +793,7 @@ static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); static const struct platform_device_id s5m_rtc_id[] = { { "s5m-rtc", S5M8767X }, + { "s2mps13-rtc", S2MPS13X }, { "s2mps14-rtc", S2MPS14X }, { }, }; diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 2939cdc..eb09edd 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -42,6 +42,8 @@ #define STMP3XXX_RTC_STAT 0x10 #define STMP3XXX_RTC_STAT_STALE_SHIFT 16 #define STMP3XXX_RTC_STAT_RTC_PRESENT 0x80000000 +#define STMP3XXX_RTC_STAT_XTAL32000_PRESENT 0x10000000 +#define STMP3XXX_RTC_STAT_XTAL32768_PRESENT 0x08000000 #define STMP3XXX_RTC_SECONDS 0x30 @@ -52,9 +54,13 @@ #define STMP3XXX_RTC_PERSISTENT0 0x60 #define STMP3XXX_RTC_PERSISTENT0_SET 0x64 #define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 +#define STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE (1 << 0) +#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN (1 << 1) +#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN (1 << 2) +#define STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP (1 << 4) +#define STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP (1 << 5) +#define STMP3XXX_RTC_PERSISTENT0_XTAL32_FREQ (1 << 6) +#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE (1 << 7) #define STMP3XXX_RTC_PERSISTENT1 0x70 /* missing bitmask in headers */ @@ -248,6 +254,9 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) { struct stmp3xxx_rtc_data *rtc_data; struct resource *r; + u32 rtc_stat; + u32 pers0_set, pers0_clr; + u32 crystalfreq = 0; int err; rtc_data = devm_kzalloc(&pdev->dev, sizeof(*rtc_data), GFP_KERNEL); @@ -268,8 +277,8 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) rtc_data->irq_alarm = platform_get_irq(pdev, 0); - if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) & - STMP3XXX_RTC_STAT_RTC_PRESENT)) { + rtc_stat = readl(rtc_data->io + STMP3XXX_RTC_STAT); + if (!(rtc_stat & STMP3XXX_RTC_STAT_RTC_PRESENT)) { dev_err(&pdev->dev, "no device onboard\n"); return -ENODEV; } @@ -282,9 +291,54 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) return err; } + /* + * Obviously the rtc needs a clock input to be able to run. + * This clock can be provided by an external 32k crystal. If that one is + * missing XTAL must not be disabled in suspend which consumes a + * lot of power. Normally the presence and exact frequency (supported + * are 32000 Hz and 32768 Hz) is detectable from fuses, but as reality + * proves these fuses are not blown correctly on all machines, so the + * frequency can be overridden in the device tree. + */ + if (rtc_stat & STMP3XXX_RTC_STAT_XTAL32000_PRESENT) + crystalfreq = 32000; + else if (rtc_stat & STMP3XXX_RTC_STAT_XTAL32768_PRESENT) + crystalfreq = 32768; + + of_property_read_u32(pdev->dev.of_node, "stmp,crystal-freq", + &crystalfreq); + + switch (crystalfreq) { + case 32000: + /* keep 32kHz crystal running in low-power mode */ + pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL32_FREQ | + STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; + pers0_clr = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP; + break; + case 32768: + /* keep 32.768kHz crystal running in low-power mode */ + pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; + pers0_clr = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_XTAL32_FREQ; + break; + default: + dev_warn(&pdev->dev, + "invalid crystal-freq specified in device-tree. Assuming no crystal\n"); + /* fall-through */ + case 0: + /* keep XTAL on in low-power mode */ + pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP; + pers0_clr = STMP3XXX_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; + } + + writel(pers0_set, rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE | pers0_clr, rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 5baea3f..2dc787d 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -18,6 +18,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> @@ -145,8 +147,7 @@ static int twl_rtc_read_u8(u8 *data, u8 reg) ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); if (ret < 0) - pr_err("twl_rtc: Could not read TWL" - "register %X - error %d\n", reg, ret); + pr_err("Could not read TWL register %X - error %d\n", reg, ret); return ret; } @@ -159,8 +160,8 @@ static int twl_rtc_write_u8(u8 data, u8 reg) ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); if (ret < 0) - pr_err("twl_rtc: Could not write TWL" - "register %X - error %d\n", reg, ret); + pr_err("Could not write TWL register %X - error %d\n", + reg, ret); return ret; } diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index b1de58e..5638b7b 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -22,6 +22,7 @@ #include <linux/rtc.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/bitops.h> #define DRV_VERSION "1.0.8" @@ -366,8 +367,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) * perform sign extension. The formula is * Catr = (atr * 0.25pF) + 11.00pF. */ - if (atr & 0x20) - atr |= 0xC0; + atr = sign_extend32(atr, 5); dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __func__, atr, atr); diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index e90a374..cc3b9d3 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1079,22 +1079,18 @@ bfad_start_ops(struct bfad_s *bfad) { int bfad_worker(void *ptr) { - struct bfad_s *bfad; - unsigned long flags; - - bfad = (struct bfad_s *)ptr; - - while (!kthread_should_stop()) { + struct bfad_s *bfad = ptr; + unsigned long flags; - /* Send event BFAD_E_INIT_SUCCESS */ - bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); + if (kthread_should_stop()) + return 0; - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfad_tsk = NULL; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); + /* Send event BFAD_E_INIT_SUCCESS */ + bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); - break; - } + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfad->bfad_tsk = NULL; + spin_unlock_irqrestore(&bfad->bfad_lock, flags); return 0; } diff --git a/firmware/ihex2fw.c b/firmware/ihex2fw.c index cf38e15..08d90e2 100644 --- a/firmware/ihex2fw.c +++ b/firmware/ihex2fw.c @@ -86,6 +86,7 @@ int main(int argc, char **argv) case 'j': include_jump = 1; break; + default: return usage(); } } diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index f2ba88a..82d14cd 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c @@ -61,6 +61,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct kcalloc(size, sizeof(struct buffer_head *), GFP_KERNEL); if (!bh_fplus) { + ret = -ENOMEM; adfs_error(sb, "not enough memory for" " dir object %X (%d blocks)", id, size); goto out; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 9852bdf..a19c31d 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -316,7 +316,7 @@ static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_di dm = kmalloc(nzones * sizeof(*dm), GFP_KERNEL); if (dm == NULL) { adfs_error(sb, "not enough memory"); - return NULL; + return ERR_PTR(-ENOMEM); } for (zone = 0; zone < nzones; zone++, map_addr++) { @@ -349,7 +349,7 @@ error_free: brelse(dm[zone].dm_bh); kfree(dm); - return NULL; + return ERR_PTR(-EIO); } static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_bits) @@ -370,6 +370,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) unsigned char *b_data; struct adfs_sb_info *asb; struct inode *root; + int ret = -EINVAL; sb->s_flags |= MS_NODIRATIME; @@ -391,6 +392,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) sb_set_blocksize(sb, BLOCK_SIZE); if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) { adfs_error(sb, "unable to read superblock"); + ret = -EIO; goto error; } @@ -400,6 +402,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk("VFS: Can't find an adfs filesystem on dev " "%s.\n", sb->s_id); + ret = -EINVAL; goto error_free_bh; } @@ -412,6 +415,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk("VPS: Can't find an adfs filesystem on dev " "%s.\n", sb->s_id); + ret = -EINVAL; goto error_free_bh; } @@ -421,11 +425,13 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!bh) { adfs_error(sb, "couldn't read superblock on " "2nd try."); + ret = -EIO; goto error; } b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize); if (adfs_checkbblk(b_data)) { adfs_error(sb, "disc record mismatch, very weird!"); + ret = -EINVAL; goto error_free_bh; } dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET); @@ -433,6 +439,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk(KERN_ERR "VFS: Unsupported blocksize on dev " "%s.\n", sb->s_id); + ret = -EINVAL; goto error; } @@ -447,10 +454,12 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) asb->s_size = adfs_discsize(dr, sb->s_blocksize_bits); asb->s_version = dr->format_version; asb->s_log2sharesize = dr->log2sharesize; - + asb->s_map = adfs_read_map(sb, dr); - if (!asb->s_map) + if (IS_ERR(asb->s_map)) { + ret = PTR_ERR(asb->s_map); goto error_free_bh; + } brelse(bh); @@ -499,6 +508,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) brelse(asb->s_map[i].dm_bh); kfree(asb->s_map); adfs_error(sb, "get root inode failed\n"); + ret = -EIO; goto error; } return 0; @@ -508,7 +518,7 @@ error_free_bh: error: sb->s_fs_info = NULL; kfree(asb); - return -EINVAL; + return ret; } static struct dentry *adfs_mount(struct file_system_type *fs_type, diff --git a/fs/affs/affs.h b/fs/affs/affs.h index c8764bd..cffe837 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -106,18 +106,22 @@ struct affs_sb_info { spinlock_t work_lock; /* protects sb_work and work_queued */ }; -#define SF_INTL 0x0001 /* International filesystem. */ -#define SF_BM_VALID 0x0002 /* Bitmap is valid. */ -#define SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */ -#define SF_QUIET 0x0008 /* chmod errors will be not reported */ -#define SF_SETUID 0x0010 /* Ignore Amiga uid */ -#define SF_SETGID 0x0020 /* Ignore Amiga gid */ -#define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */ -#define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */ -#define SF_OFS 0x0200 /* Old filesystem */ -#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ -#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */ -#define SF_NO_TRUNCATE 0x1000 /* Don't truncate filenames */ +#define AFFS_MOUNT_SF_INTL 0x0001 /* International filesystem. */ +#define AFFS_MOUNT_SF_BM_VALID 0x0002 /* Bitmap is valid. */ +#define AFFS_MOUNT_SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */ +#define AFFS_MOUNT_SF_QUIET 0x0008 /* chmod errors will be not reported */ +#define AFFS_MOUNT_SF_SETUID 0x0010 /* Ignore Amiga uid */ +#define AFFS_MOUNT_SF_SETGID 0x0020 /* Ignore Amiga gid */ +#define AFFS_MOUNT_SF_SETMODE 0x0040 /* Ignore Amiga protection bits */ +#define AFFS_MOUNT_SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */ +#define AFFS_MOUNT_SF_OFS 0x0200 /* Old filesystem */ +#define AFFS_MOUNT_SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ +#define AFFS_MOUNT_SF_VERBOSE 0x0800 /* Talk about fs when mounting */ +#define AFFS_MOUNT_SF_NO_TRUNCATE 0x1000 /* Don't truncate filenames */ + +#define affs_clear_opt(o, opt) (o &= ~AFFS_MOUNT_##opt) +#define affs_set_opt(o, opt) (o |= AFFS_MOUNT_##opt) +#define affs_test_opt(o, opt) ((o) & AFFS_MOUNT_##opt) /* short cut to get to the affs specific sb data */ static inline struct affs_sb_info *AFFS_SB(struct super_block *sb) diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 388da1e..5022ac9 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -472,7 +472,8 @@ bool affs_nofilenametruncate(const struct dentry *dentry) { struct inode *inode = dentry->d_inode; - return AFFS_SB(inode->i_sb)->s_flags & SF_NO_TRUNCATE; + + return affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_NO_TRUNCATE); } diff --git a/fs/affs/file.c b/fs/affs/file.c index dcf2795..659c579 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -914,7 +914,7 @@ affs_truncate(struct inode *inode) if (inode->i_size) { AFFS_I(inode)->i_blkcnt = last_blk + 1; AFFS_I(inode)->i_extcnt = ext + 1; - if (AFFS_SB(sb)->s_flags & SF_OFS) { + if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS)) { struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); u32 tmp; if (IS_ERR(bh)) { diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 6f34510..9628003 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -66,23 +66,23 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) AFFS_I(inode)->i_lastalloc = 0; AFFS_I(inode)->i_pa_cnt = 0; - if (sbi->s_flags & SF_SETMODE) + if (affs_test_opt(sbi->s_flags, SF_SETMODE)) inode->i_mode = sbi->s_mode; else inode->i_mode = prot_to_mode(prot); id = be16_to_cpu(tail->uid); - if (id == 0 || sbi->s_flags & SF_SETUID) + if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETUID)) inode->i_uid = sbi->s_uid; - else if (id == 0xFFFF && sbi->s_flags & SF_MUFS) + else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS)) i_uid_write(inode, 0); else i_uid_write(inode, id); id = be16_to_cpu(tail->gid); - if (id == 0 || sbi->s_flags & SF_SETGID) + if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETGID)) inode->i_gid = sbi->s_gid; - else if (id == 0xFFFF && sbi->s_flags & SF_MUFS) + else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS)) i_gid_write(inode, 0); else i_gid_write(inode, id); @@ -94,7 +94,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) /* fall through */ case ST_USERDIR: if (be32_to_cpu(tail->stype) == ST_USERDIR || - sbi->s_flags & SF_SETMODE) { + affs_test_opt(sbi->s_flags, SF_SETMODE)) { if (inode->i_mode & S_IRUSR) inode->i_mode |= S_IXUSR; if (inode->i_mode & S_IRGRP) @@ -133,7 +133,8 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) } if (tail->link_chain) set_nlink(inode, 2); - inode->i_mapping->a_ops = (sbi->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops; + inode->i_mapping->a_ops = affs_test_opt(sbi->s_flags, SF_OFS) ? + &affs_aops_ofs : &affs_aops; inode->i_op = &affs_file_inode_operations; inode->i_fop = &affs_file_operations; break; @@ -190,15 +191,15 @@ affs_write_inode(struct inode *inode, struct writeback_control *wbc) if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) { uid = i_uid_read(inode); gid = i_gid_read(inode); - if (AFFS_SB(sb)->s_flags & SF_MUFS) { + if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_MUFS)) { if (uid == 0 || uid == 0xFFFF) uid = uid ^ ~0; if (gid == 0 || gid == 0xFFFF) gid = gid ^ ~0; } - if (!(AFFS_SB(sb)->s_flags & SF_SETUID)) + if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETUID)) tail->uid = cpu_to_be16(uid); - if (!(AFFS_SB(sb)->s_flags & SF_SETGID)) + if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETGID)) tail->gid = cpu_to_be16(gid); } } @@ -221,11 +222,14 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) if (error) goto out; - if (((attr->ia_valid & ATTR_UID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETUID)) || - ((attr->ia_valid & ATTR_GID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETGID)) || + if (((attr->ia_valid & ATTR_UID) && + affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETUID)) || + ((attr->ia_valid & ATTR_GID) && + affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETGID)) || ((attr->ia_valid & ATTR_MODE) && - (AFFS_SB(inode->i_sb)->s_flags & (SF_SETMODE | SF_IMMUTABLE)))) { - if (!(AFFS_SB(inode->i_sb)->s_flags & SF_QUIET)) + (AFFS_SB(inode->i_sb)->s_flags & + (AFFS_MOUNT_SF_SETMODE | AFFS_MOUNT_SF_IMMUTABLE)))) { + if (!affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_QUIET)) error = -EPERM; goto out; } diff --git a/fs/affs/namei.c b/fs/affs/namei.c index ffb7bd8..ec8ca0e 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -53,7 +53,8 @@ affs_intl_toupper(int ch) static inline toupper_t affs_get_toupper(struct super_block *sb) { - return AFFS_SB(sb)->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper; + return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ? + affs_intl_toupper : affs_toupper; } /* @@ -275,7 +276,8 @@ affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) inode->i_op = &affs_file_inode_operations; inode->i_fop = &affs_file_operations; - inode->i_mapping->a_ops = (AFFS_SB(sb)->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops; + inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ? + &affs_aops_ofs : &affs_aops; error = affs_add_entry(dir, inode, dentry, ST_FILE); if (error) { clear_nlink(inode); diff --git a/fs/affs/super.c b/fs/affs/super.c index 4cf0e91..3f89c9e 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -227,22 +227,22 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, if (match_octal(&args[0], &option)) return 0; *mode = option & 0777; - *mount_opts |= SF_SETMODE; + affs_set_opt(*mount_opts, SF_SETMODE); break; case Opt_mufs: - *mount_opts |= SF_MUFS; + affs_set_opt(*mount_opts, SF_MUFS); break; case Opt_notruncate: - *mount_opts |= SF_NO_TRUNCATE; + affs_set_opt(*mount_opts, SF_NO_TRUNCATE); break; case Opt_prefix: *prefix = match_strdup(&args[0]); if (!*prefix) return 0; - *mount_opts |= SF_PREFIX; + affs_set_opt(*mount_opts, SF_PREFIX); break; case Opt_protect: - *mount_opts |= SF_IMMUTABLE; + affs_set_opt(*mount_opts, SF_IMMUTABLE); break; case Opt_reserved: if (match_int(&args[0], reserved)) @@ -258,7 +258,7 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, *gid = make_kgid(current_user_ns(), option); if (!gid_valid(*gid)) return 0; - *mount_opts |= SF_SETGID; + affs_set_opt(*mount_opts, SF_SETGID); break; case Opt_setuid: if (match_int(&args[0], &option)) @@ -266,10 +266,10 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, *uid = make_kuid(current_user_ns(), option); if (!uid_valid(*uid)) return 0; - *mount_opts |= SF_SETUID; + affs_set_opt(*mount_opts, SF_SETUID); break; case Opt_verbose: - *mount_opts |= SF_VERBOSE; + affs_set_opt(*mount_opts, SF_VERBOSE); break; case Opt_volume: { char *vol = match_strdup(&args[0]); @@ -435,30 +435,31 @@ got_root: case MUFS_FS: case MUFS_INTLFFS: case MUFS_DCFFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); /* fall thru */ case FS_INTLFFS: case FS_DCFFS: - sbi->s_flags |= SF_INTL; + affs_set_opt(sbi->s_flags, SF_INTL); break; case MUFS_FFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); break; case FS_FFS: break; case MUFS_OFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); /* fall thru */ case FS_OFS: - sbi->s_flags |= SF_OFS; + affs_set_opt(sbi->s_flags, SF_OFS); sb->s_flags |= MS_NOEXEC; break; case MUFS_DCOFS: case MUFS_INTLOFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); case FS_DCOFS: case FS_INTLOFS: - sbi->s_flags |= SF_INTL | SF_OFS; + affs_set_opt(sbi->s_flags, SF_INTL); + affs_set_opt(sbi->s_flags, SF_OFS); sb->s_flags |= MS_NOEXEC; break; default: @@ -467,7 +468,7 @@ got_root: return -EINVAL; } - if (mount_flags & SF_VERBOSE) { + if (affs_test_opt(mount_flags, SF_VERBOSE)) { u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0]; pr_notice("Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n", len > 31 ? 31 : len, @@ -478,7 +479,7 @@ got_root: sb->s_flags |= MS_NODEV | MS_NOSUID; sbi->s_data_blksize = sb->s_blocksize; - if (sbi->s_flags & SF_OFS) + if (affs_test_opt(sbi->s_flags, SF_OFS)) sbi->s_data_blksize -= 24; tmp_flags = sb->s_flags; @@ -493,7 +494,7 @@ got_root: if (IS_ERR(root_inode)) return PTR_ERR(root_inode); - if (AFFS_SB(sb)->s_flags & SF_INTL) + if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL)) sb->s_d_op = &affs_intl_dentry_operations; else sb->s_d_op = &affs_dentry_operations; @@ -520,10 +521,14 @@ affs_remount(struct super_block *sb, int *flags, char *data) int root_block; unsigned long mount_flags; int res = 0; - char *new_opts = kstrdup(data, GFP_KERNEL); + char *new_opts; char volume[32]; char *prefix = NULL; + new_opts = kstrdup(data, GFP_KERNEL); + if (!new_opts) + return -ENOMEM; + pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data); sync_filesystem(sb); diff --git a/fs/befs/befs.h b/fs/befs/befs.h index 3a7813a..1fead8d 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -19,16 +19,16 @@ typedef u64 befs_blocknr_t; * BeFS in memory structures */ -typedef struct befs_mount_options { +struct befs_mount_options { kgid_t gid; kuid_t uid; int use_gid; int use_uid; int debug; char *iocharset; -} befs_mount_options; +}; -typedef struct befs_sb_info { +struct befs_sb_info { u32 magic1; u32 block_size; u32 block_shift; @@ -52,12 +52,11 @@ typedef struct befs_sb_info { befs_inode_addr indices; u32 magic3; - befs_mount_options mount_opts; + struct befs_mount_options mount_opts; struct nls_table *nls; +}; -} befs_sb_info; - -typedef struct befs_inode_info { +struct befs_inode_info { u32 i_flags; u32 i_type; @@ -71,8 +70,7 @@ typedef struct befs_inode_info { } i_data; struct inode vfs_inode; - -} befs_inode_info; +}; enum befs_err { BEFS_OK, @@ -105,13 +103,13 @@ void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *); /* Gets a pointer to the private portion of the super_block * structure from the public part */ -static inline befs_sb_info * +static inline struct befs_sb_info * BEFS_SB(const struct super_block *super) { - return (befs_sb_info *) super->s_fs_info; + return (struct befs_sb_info *) super->s_fs_info; } -static inline befs_inode_info * +static inline struct befs_inode_info * BEFS_I(const struct inode *inode) { return list_entry(inode, struct befs_inode_info, vfs_inode); diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 1e8e0b8..ebd5071 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -168,7 +168,7 @@ befs_count_blocks(struct super_block * sb, befs_data_stream * ds) befs_blocknr_t blocks; befs_blocknr_t datablocks; /* File data blocks */ befs_blocknr_t metablocks; /* FS metadata blocks */ - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_debug(sb, "---> %s", __func__); @@ -428,7 +428,7 @@ befs_find_brun_dblindirect(struct super_block *sb, struct buffer_head *indir_block; befs_block_run indir_run; befs_disk_inode_addr *iaddr_array = NULL; - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_blocknr_t indir_start_blk = data->max_indirect_range >> befs_sb->block_shift; diff --git a/fs/befs/io.c b/fs/befs/io.c index 0408a3d..7a5b4ec 100644 --- a/fs/befs/io.c +++ b/fs/befs/io.c @@ -28,7 +28,7 @@ befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr) { struct buffer_head *bh = NULL; befs_blocknr_t block = 0; - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_debug(sb, "---> Enter %s " "[%u, %hu, %hu]", __func__, iaddr.allocation_group, diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e089f19..16e0a48 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -51,7 +51,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, static void befs_put_super(struct super_block *); static int befs_remount(struct super_block *, int *, char *); static int befs_statfs(struct dentry *, struct kstatfs *); -static int parse_options(char *, befs_mount_options *); +static int parse_options(char *, struct befs_mount_options *); static const struct super_operations befs_sops = { .alloc_inode = befs_alloc_inode, /* allocate a new inode */ @@ -304,9 +304,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) { struct buffer_head *bh = NULL; befs_inode *raw_inode = NULL; - - befs_sb_info *befs_sb = BEFS_SB(sb); - befs_inode_info *befs_ino = NULL; + struct befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_inode_info *befs_ino = NULL; struct inode *inode; long ret = -EIO; @@ -472,7 +471,7 @@ static void * befs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dentry->d_sb; - befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + struct befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; char *link; @@ -502,7 +501,8 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd) static void * befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd) { - befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + struct befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + nd_set_link(nd, befs_ino->i_data.symlink); return NULL; } @@ -669,7 +669,7 @@ static const match_table_t befs_tokens = { }; static int -parse_options(char *options, befs_mount_options * opts) +parse_options(char *options, struct befs_mount_options *opts) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -769,7 +769,7 @@ static int befs_fill_super(struct super_block *sb, void *data, int silent) { struct buffer_head *bh; - befs_sb_info *befs_sb; + struct befs_sb_info *befs_sb; befs_super_block *disk_sb; struct inode *root; long ret = -EINVAL; diff --git a/fs/befs/super.c b/fs/befs/super.c index ca40f82..aeafc4d 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -24,7 +24,7 @@ int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) { - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); /* Check the byte order of the filesystem */ if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_LE) @@ -59,7 +59,7 @@ befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) int befs_check_sb(struct super_block *sb) { - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); /* Check magic headers of super block */ if ((befs_sb->magic1 != BEFS_SUPER_MAGIC1) diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 08063ae..7a818277 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -86,7 +86,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode = new_inode(s); if (!inode) - return -ENOSPC; + return -ENOMEM; mutex_lock(&info->bfs_lock); ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1); if (ino > info->si_lasti) { @@ -293,7 +293,7 @@ static int bfs_add_entry(struct inode *dir, const unsigned char *name, for (block = sblock; block <= eblock; block++) { bh = sb_bread(dir->i_sb, block); if (!bh) - return -ENOSPC; + return -EIO; for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { de = (struct bfs_dirent *)(bh->b_data + off); if (!de->ino) { diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 97aff28..9dcb054 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> @@ -521,9 +522,8 @@ static int parse_command(const char __user *buffer, size_t count) static void entry_status(Node *e, char *page) { - char *dp; - char *status = "disabled"; - const char *flags = "flags: "; + char *dp = page; + const char *status = "disabled"; if (test_bit(Enabled, &e->flags)) status = "enabled"; @@ -533,12 +533,10 @@ static void entry_status(Node *e, char *page) return; } - sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter); - dp = page + strlen(page); + dp += sprintf(dp, "%s\ninterpreter %s\n", status, e->interpreter); /* print the special flags */ - sprintf(dp, "%s", flags); - dp += strlen(flags); + dp += sprintf(dp, "flags: "); if (e->flags & MISC_FMT_PRESERVE_ARGV0) *dp++ = 'P'; if (e->flags & MISC_FMT_OPEN_BINARY) @@ -550,21 +548,11 @@ static void entry_status(Node *e, char *page) if (!test_bit(Magic, &e->flags)) { sprintf(dp, "extension .%s\n", e->magic); } else { - int i; - - sprintf(dp, "offset %i\nmagic ", e->offset); - dp = page + strlen(page); - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); - dp += 2; - } + dp += sprintf(dp, "offset %i\nmagic ", e->offset); + dp = bin2hex(dp, e->magic, e->size); if (e->mask) { - sprintf(dp, "\nmask "); - dp += 6; - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); - dp += 2; - } + dp += sprintf(dp, "\nmask "); + dp = bin2hex(dp, e->mask, e->size); } *dp++ = '\n'; *dp = '\0'; @@ -926,10 +926,14 @@ static int de_thread(struct task_struct *tsk) if (!thread_group_leader(tsk)) { struct task_struct *leader = tsk->group_leader; - sig->notify_count = -1; /* for exit_notify() */ for (;;) { threadgroup_change_begin(tsk); write_lock_irq(&tasklist_lock); + /* + * Do this under tasklist_lock to ensure that + * exit_notify() can't miss ->group_exit_task + */ + sig->notify_count = -1; if (likely(leader->exit_state)) break; __set_current_state(TASK_KILLABLE); @@ -1078,7 +1082,13 @@ int flush_old_exec(struct linux_binprm * bprm) if (retval) goto out; + /* + * Must be called _before_ exec_mmap() as bprm->mm is + * not visibile until then. This also enables the update + * to be lockless. + */ set_mm_exe_file(bprm->mm, bprm->file); + /* * Release all of the old mmap stuff */ diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 91ad9e1..93fc622 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -8,9 +8,7 @@ * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. */ -#include <linux/fs.h> #include <linux/slab.h> -#include <linux/buffer_head.h> #include "fat.h" /* this must be > 0. */ diff --git a/fs/fat/dir.c b/fs/fat/dir.c index c5d6bb9..4afc4d9 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -13,13 +13,9 @@ * Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de> */ -#include <linux/module.h> #include <linux/slab.h> -#include <linux/time.h> -#include <linux/buffer_head.h> #include <linux/compat.h> #include <linux/uaccess.h> -#include <linux/kernel.h> #include "fat.h" /* diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 64e295e..be5e153 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -2,11 +2,8 @@ #define _FAT_H #include <linux/buffer_head.h> -#include <linux/string.h> #include <linux/nls.h> -#include <linux/fs.h> #include <linux/hash.h> -#include <linux/mutex.h> #include <linux/ratelimit.h> #include <linux/msdos_fs.h> @@ -66,7 +63,7 @@ struct msdos_sb_info { unsigned short sec_per_clus; /* sectors/cluster */ unsigned short cluster_bits; /* log2(cluster_size) */ unsigned int cluster_size; /* cluster size */ - unsigned char fats, fat_bits; /* number of FATs, FAT bits (12 or 16) */ + unsigned char fats, fat_bits; /* number of FATs, FAT bits (12,16 or 32) */ unsigned short fat_start; unsigned long fat_length; /* FAT start & length (sec.) */ unsigned long dir_start; diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 260705c..8226557 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -3,9 +3,6 @@ * Released under GPL v2. */ -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/msdos_fs.h> #include <linux/blkdev.h> #include "fat.h" diff --git a/fs/fat/file.c b/fs/fat/file.c index 1e98d33..cf50d93 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -10,10 +10,6 @@ #include <linux/module.h> #include <linux/compat.h> #include <linux/mount.h> -#include <linux/time.h> -#include <linux/buffer_head.h> -#include <linux/writeback.h> -#include <linux/backing-dev.h> #include <linux/blkdev.h> #include <linux/fsnotify.h> #include <linux/security.h> diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 41b7299..c067746 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -11,20 +11,12 @@ */ #include <linux/module.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/slab.h> -#include <linux/seq_file.h> #include <linux/pagemap.h> #include <linux/mpage.h> -#include <linux/buffer_head.h> -#include <linux/mount.h> #include <linux/vfs.h> +#include <linux/seq_file.h> #include <linux/parser.h> #include <linux/uio.h> -#include <linux/writeback.h> -#include <linux/log2.h> -#include <linux/hash.h> #include <linux/blkdev.h> #include <asm/unaligned.h> #include "fat.h" @@ -1278,8 +1270,7 @@ out: static int fat_read_root(struct inode *inode) { - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); int error; MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO; diff --git a/fs/fat/misc.c b/fs/fat/misc.c index d8da2d2..c4589e9 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -6,10 +6,6 @@ * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) */ -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/buffer_head.h> -#include <linux/time.h> #include "fat.h" /* diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index a783b0e..cc6a854 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -7,8 +7,6 @@ */ #include <linux/module.h> -#include <linux/time.h> -#include <linux/buffer_head.h> #include "fat.h" /* Characters that are undesirable in an MS-DOS file name */ diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b8b92c2..7e0974e 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -16,10 +16,8 @@ */ #include <linux/module.h> -#include <linux/jiffies.h> #include <linux/ctype.h> #include <linux/slab.h> -#include <linux/buffer_head.h> #include <linux/namei.h> #include "fat.h" @@ -638,8 +638,7 @@ static struct file *__fget(unsigned int fd, fmode_t mask) file = fcheck_files(files, fd); if (file) { /* File object ref couldn't be taken */ - if ((file->f_mode & mask) || - !atomic_long_inc_not_zero(&file->f_count)) + if ((file->f_mode & mask) || !get_file_rcu(file)) file = NULL; } rcu_read_unlock(); diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 1455668..36d1a6a 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -197,7 +197,7 @@ static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode = hfs_new_inode(dir, &dentry->d_name, mode); if (!inode) - return -ENOSPC; + return -ENOMEM; res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); if (res) { @@ -226,7 +226,7 @@ static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); if (!inode) - return -ENOSPC; + return -ENOMEM; res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); if (res) { diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index c1422d9..528e38b 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c @@ -118,9 +118,7 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd, int b, e; int res; - if (!rec_found) - BUG(); - + BUG_ON(!rec_found); b = 0; e = bnode->num_recs - 1; res = -ENOENT; diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 7892e6f..022974a 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -350,10 +350,11 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) &fd.search_key->cat.name.unicode, off + 2, len); fd.search_key->key_len = cpu_to_be16(6 + len); - } else + } else { err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); if (unlikely(err)) goto out; + } err = hfs_brec_find(&fd, hfs_find_rec_by_key); if (err) diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f0235c1..3074609 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -434,7 +434,7 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; - int res = -ENOSPC; + int res = -ENOMEM; mutex_lock(&sbi->vh_mutex); inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO); @@ -476,7 +476,7 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; - int res = -ENOSPC; + int res = -ENOMEM; mutex_lock(&sbi->vh_mutex); inode = hfsplus_new_inode(dir->i_sb, mode); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index a43811f..b0afedb 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -253,6 +253,12 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size != i_size_read(inode)) { inode_dio_wait(inode); + if (attr->ia_size > inode->i_size) { + error = generic_cont_expand_simple(inode, + attr->ia_size); + if (error) + return error; + } truncate_setsize(inode, attr->ia_size); hfsplus_file_truncate(inode); } diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index d3ff5cc..8e98f5d 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -76,7 +76,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) { struct inode *inode = file_inode(file); struct hfsplus_inode_info *hip = HFSPLUS_I(inode); - unsigned int flags; + unsigned int flags, new_fl = 0; int err = 0; err = mnt_want_write_file(file); @@ -110,14 +110,12 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) } if (flags & FS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & FS_APPEND_FL) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; + new_fl |= S_APPEND; + + inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); if (flags & FS_NODUMP_FL) hip->userflags |= HFSPLUS_FLG_NODUMP; diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index d98094a..89f262d 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -44,7 +44,7 @@ static int strcmp_xattr_acl(const char *name) return -1; } -static inline int is_known_namespace(const char *name) +static bool is_known_namespace(const char *name) { if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && @@ -424,6 +424,28 @@ static int copy_name(char *buffer, const char *xattr_name, int name_len) return len; } +int hfsplus_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, + const char *prefix, size_t prefixlen) +{ + char *xattr_name; + int res; + + if (!strcmp(name, "")) + return -EINVAL; + + xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, + GFP_KERNEL); + if (!xattr_name) + return -ENOMEM; + strcpy(xattr_name, prefix); + strcpy(xattr_name + prefixlen, name); + res = __hfsplus_setxattr(dentry->d_inode, xattr_name, value, size, + flags); + kfree(xattr_name); + return res; +} + static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, void *value, size_t size) { @@ -560,6 +582,30 @@ failed_getxattr_init: return res; } +ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size, + const char *prefix, size_t prefixlen) +{ + int res; + char *xattr_name; + + if (!strcmp(name, "")) + return -EINVAL; + + xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, + GFP_KERNEL); + if (!xattr_name) + return -ENOMEM; + + strcpy(xattr_name, prefix); + strcpy(xattr_name + prefixlen, name); + + res = __hfsplus_getxattr(dentry->d_inode, xattr_name, value, size); + kfree(xattr_name); + return res; + +} + static inline int can_list(const char *xattr_name) { if (!xattr_name) @@ -806,9 +852,6 @@ end_removexattr: static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - if (!strcmp(name, "")) return -EINVAL; @@ -818,24 +861,19 @@ static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, */ if (is_known_namespace(name)) return -EOPNOTSUPP; - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN - + XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); - strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + /* + * osx is the namespace we use to indicate an unprefixed + * attribute on the filesystem (like the ones that OS X + * creates), so we pass the name through unmodified (after + * ensuring it doesn't conflict with another namespace). + */ + return __hfsplus_getxattr(dentry->d_inode, name, buffer, size); } static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - if (!strcmp(name, "")) return -EINVAL; @@ -845,16 +883,14 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, */ if (is_known_namespace(name)) return -EOPNOTSUPP; - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN - + XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); - strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + /* + * osx is the namespace we use to indicate an unprefixed + * attribute on the filesystem (like the ones that OS X + * creates), so we pass the name through unmodified (after + * ensuring it doesn't conflict with another namespace). + */ + return __hfsplus_setxattr(dentry->d_inode, name, buffer, size, flags); } static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list, diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h index 288530c..f9b0955 100644 --- a/fs/hfsplus/xattr.h +++ b/fs/hfsplus/xattr.h @@ -21,22 +21,16 @@ extern const struct xattr_handler *hfsplus_xattr_handlers[]; int __hfsplus_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags); -static inline int hfsplus_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - return __hfsplus_setxattr(dentry->d_inode, name, value, size, flags); -} +int hfsplus_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, + const char *prefix, size_t prefixlen); ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, - void *value, size_t size); - -static inline ssize_t hfsplus_getxattr(struct dentry *dentry, - const char *name, - void *value, - size_t size) -{ - return __hfsplus_getxattr(dentry->d_inode, name, value, size); -} + void *value, size_t size); + +ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size, + const char *prefix, size_t prefixlen); ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); diff --git a/fs/hfsplus/xattr_security.c b/fs/hfsplus/xattr_security.c index 6ec5e10..aacff00 100644 --- a/fs/hfsplus/xattr_security.c +++ b/fs/hfsplus/xattr_security.c @@ -16,43 +16,17 @@ static int hfsplus_security_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_SECURITY_PREFIX); - strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); - - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + return hfsplus_getxattr(dentry, name, buffer, size, + XATTR_SECURITY_PREFIX, + XATTR_SECURITY_PREFIX_LEN); } static int hfsplus_security_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_SECURITY_PREFIX); - strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); - - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + return hfsplus_setxattr(dentry, name, buffer, size, flags, + XATTR_SECURITY_PREFIX, + XATTR_SECURITY_PREFIX_LEN); } static size_t hfsplus_security_listxattr(struct dentry *dentry, char *list, diff --git a/fs/hfsplus/xattr_trusted.c b/fs/hfsplus/xattr_trusted.c index 3c5f27e..bcf65089 100644 --- a/fs/hfsplus/xattr_trusted.c +++ b/fs/hfsplus/xattr_trusted.c @@ -14,43 +14,16 @@ static int hfsplus_trusted_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_TRUSTED_PREFIX); - strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); - - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + return hfsplus_getxattr(dentry, name, buffer, size, + XATTR_TRUSTED_PREFIX, + XATTR_TRUSTED_PREFIX_LEN); } static int hfsplus_trusted_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_TRUSTED_PREFIX); - strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); - - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + return hfsplus_setxattr(dentry, name, buffer, size, flags, + XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); } static size_t hfsplus_trusted_listxattr(struct dentry *dentry, char *list, diff --git a/fs/hfsplus/xattr_user.c b/fs/hfsplus/xattr_user.c index 2b625a5..5aa0e6d 100644 --- a/fs/hfsplus/xattr_user.c +++ b/fs/hfsplus/xattr_user.c @@ -14,43 +14,16 @@ static int hfsplus_user_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_USER_PREFIX); - strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); - - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + return hfsplus_getxattr(dentry, name, buffer, size, + XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); } static int hfsplus_user_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_USER_PREFIX); - strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); - - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + return hfsplus_setxattr(dentry, name, buffer, size, flags, + XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); } static size_t hfsplus_user_listxattr(struct dentry *dentry, char *list, @@ -2590,6 +2590,44 @@ static int locks_show(struct seq_file *f, void *v) return 0; } +static void __show_fd_locks(struct seq_file *f, + struct list_head *head, int *id, + struct file *filp, struct files_struct *files) +{ + struct file_lock *fl; + + list_for_each_entry(fl, head, fl_list) { + + if (filp != fl->fl_file) + continue; + if (fl->fl_owner != files && + fl->fl_owner != filp) + continue; + + (*id)++; + seq_puts(f, "lock:\t"); + lock_get_status(f, fl, *id, ""); + } +} + +void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) +{ + struct inode *inode = file_inode(filp); + struct file_lock_context *ctx; + int id = 0; + + ctx = inode->i_flctx; + if (!ctx) + return; + + spin_lock(&ctx->flc_lock); + __show_fd_locks(f, &ctx->flc_flock, &id, filp, files); + __show_fd_locks(f, &ctx->flc_posix, &id, filp, files); + __show_fd_locks(f, &ctx->flc_lease, &id, filp, files); + spin_unlock(&ctx->flc_lock); +} + static void *locks_start(struct seq_file *f, loff_t *pos) __acquires(&blocked_lock_lock) { diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c index 741fd02..8df0f3b 100644 --- a/fs/nilfs2/alloc.c +++ b/fs/nilfs2/alloc.c @@ -405,13 +405,14 @@ nilfs_palloc_rest_groups_in_desc_block(const struct inode *inode, static int nilfs_palloc_count_desc_blocks(struct inode *inode, unsigned long *desc_blocks) { - unsigned long blknum; + __u64 blknum; int ret; ret = nilfs_bmap_last_key(NILFS_I(inode)->i_bmap, &blknum); if (likely(!ret)) *desc_blocks = DIV_ROUND_UP( - blknum, NILFS_MDT(inode)->mi_blocks_per_desc_block); + (unsigned long)blknum, + NILFS_MDT(inode)->mi_blocks_per_desc_block); return ret; } diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index aadbd0b..27f75bc 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -152,9 +152,7 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) * * %-EEXIST - A record associated with @key already exist. */ -int nilfs_bmap_insert(struct nilfs_bmap *bmap, - unsigned long key, - unsigned long rec) +int nilfs_bmap_insert(struct nilfs_bmap *bmap, __u64 key, unsigned long rec) { int ret; @@ -191,19 +189,47 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) return bmap->b_ops->bop_delete(bmap, key); } -int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) +/** + * nilfs_bmap_seek_key - seek a valid entry and return its key + * @bmap: bmap struct + * @start: start key number + * @keyp: place to store valid key + * + * Description: nilfs_bmap_seek_key() seeks a valid key on @bmap + * starting from @start, and stores it to @keyp if found. + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + * + * %-ENOENT - No valid entry was found + */ +int nilfs_bmap_seek_key(struct nilfs_bmap *bmap, __u64 start, __u64 *keyp) { - __u64 lastkey; int ret; down_read(&bmap->b_sem); - ret = bmap->b_ops->bop_last_key(bmap, &lastkey); + ret = bmap->b_ops->bop_seek_key(bmap, start, keyp); + up_read(&bmap->b_sem); + + if (ret < 0) + ret = nilfs_bmap_convert_error(bmap, __func__, ret); + return ret; +} + +int nilfs_bmap_last_key(struct nilfs_bmap *bmap, __u64 *keyp) +{ + int ret; + + down_read(&bmap->b_sem); + ret = bmap->b_ops->bop_last_key(bmap, keyp); up_read(&bmap->b_sem); if (ret < 0) ret = nilfs_bmap_convert_error(bmap, __func__, ret); - else - *key = lastkey; return ret; } @@ -224,7 +250,7 @@ int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) * * %-ENOENT - A record associated with @key does not exist. */ -int nilfs_bmap_delete(struct nilfs_bmap *bmap, unsigned long key) +int nilfs_bmap_delete(struct nilfs_bmap *bmap, __u64 key) { int ret; @@ -235,7 +261,7 @@ int nilfs_bmap_delete(struct nilfs_bmap *bmap, unsigned long key) return nilfs_bmap_convert_error(bmap, __func__, ret); } -static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) +static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, __u64 key) { __u64 lastkey; int ret; @@ -276,7 +302,7 @@ static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) * * %-ENOMEM - Insufficient amount of memory available. */ -int nilfs_bmap_truncate(struct nilfs_bmap *bmap, unsigned long key) +int nilfs_bmap_truncate(struct nilfs_bmap *bmap, __u64 key) { int ret; diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index b89e680..bfa817c 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -76,8 +76,10 @@ struct nilfs_bmap_operations { union nilfs_binfo *); int (*bop_mark)(struct nilfs_bmap *, __u64, int); - /* The following functions are internal use only. */ + int (*bop_seek_key)(const struct nilfs_bmap *, __u64, __u64 *); int (*bop_last_key)(const struct nilfs_bmap *, __u64 *); + + /* The following functions are internal use only. */ int (*bop_check_insert)(const struct nilfs_bmap *, __u64); int (*bop_check_delete)(struct nilfs_bmap *, __u64); int (*bop_gather_data)(struct nilfs_bmap *, __u64 *, __u64 *, int); @@ -153,10 +155,11 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); -int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); -int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); -int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); -int nilfs_bmap_truncate(struct nilfs_bmap *, unsigned long); +int nilfs_bmap_insert(struct nilfs_bmap *bmap, __u64 key, unsigned long rec); +int nilfs_bmap_delete(struct nilfs_bmap *bmap, __u64 key); +int nilfs_bmap_seek_key(struct nilfs_bmap *bmap, __u64 start, __u64 *keyp); +int nilfs_bmap_last_key(struct nilfs_bmap *bmap, __u64 *keyp); +int nilfs_bmap_truncate(struct nilfs_bmap *bmap, __u64 key); void nilfs_bmap_clear(struct nilfs_bmap *); int nilfs_bmap_propagate(struct nilfs_bmap *, struct buffer_head *); void nilfs_bmap_lookup_dirty_buffers(struct nilfs_bmap *, struct list_head *); diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index ecdbae1..059f371 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -633,6 +633,44 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_bmap *btree, return 0; } +/** + * nilfs_btree_get_next_key - get next valid key from btree path array + * @btree: bmap struct of btree + * @path: array of nilfs_btree_path struct + * @minlevel: start level + * @nextkey: place to store the next valid key + * + * Return Value: If a next key was found, 0 is returned. Otherwise, + * -ENOENT is returned. + */ +static int nilfs_btree_get_next_key(const struct nilfs_bmap *btree, + const struct nilfs_btree_path *path, + int minlevel, __u64 *nextkey) +{ + struct nilfs_btree_node *node; + int maxlevel = nilfs_btree_height(btree) - 1; + int index, next_adj, level; + + /* Next index is already set to bp_index for leaf nodes. */ + next_adj = 0; + for (level = minlevel; level <= maxlevel; level++) { + if (level == maxlevel) + node = nilfs_btree_get_root(btree); + else + node = nilfs_btree_get_nonroot_node(path, level); + + index = path[level].bp_index + next_adj; + if (index < nilfs_btree_node_get_nchildren(node)) { + /* Next key is in this node */ + *nextkey = nilfs_btree_node_get_key(node, index); + return 0; + } + /* For non-leaf nodes, next index is stored at bp_index + 1. */ + next_adj = 1; + } + return -ENOENT; +} + static int nilfs_btree_lookup(const struct nilfs_bmap *btree, __u64 key, int level, __u64 *ptrp) { @@ -1563,6 +1601,27 @@ out: return ret; } +static int nilfs_btree_seek_key(const struct nilfs_bmap *btree, __u64 start, + __u64 *keyp) +{ + struct nilfs_btree_path *path; + const int minlevel = NILFS_BTREE_LEVEL_NODE_MIN; + int ret; + + path = nilfs_btree_alloc_path(); + if (!path) + return -ENOMEM; + + ret = nilfs_btree_do_lookup(btree, path, start, NULL, minlevel, 0); + if (!ret) + *keyp = start; + else if (ret == -ENOENT) + ret = nilfs_btree_get_next_key(btree, path, minlevel, keyp); + + nilfs_btree_free_path(path); + return ret; +} + static int nilfs_btree_last_key(const struct nilfs_bmap *btree, __u64 *keyp) { struct nilfs_btree_path *path; @@ -2298,7 +2357,9 @@ static const struct nilfs_bmap_operations nilfs_btree_ops = { .bop_assign = nilfs_btree_assign, .bop_mark = nilfs_btree_mark, + .bop_seek_key = nilfs_btree_seek_key, .bop_last_key = nilfs_btree_last_key, + .bop_check_insert = NULL, .bop_check_delete = nilfs_btree_check_delete, .bop_gather_data = nilfs_btree_gather_data, @@ -2318,7 +2379,9 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_assign = nilfs_btree_assign_gc, .bop_mark = NULL, + .bop_seek_key = NULL, .bop_last_key = NULL, + .bop_check_insert = NULL, .bop_check_delete = NULL, .bop_gather_data = NULL, diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 0d58075..b6596ca 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -53,6 +53,13 @@ nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno) return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); } +static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile, + unsigned long blkoff) +{ + return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff + + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset; +} + static unsigned long nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile, __u64 curr, @@ -146,6 +153,44 @@ static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile, create, nilfs_cpfile_block_init, bhp); } +/** + * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile + * @cpfile: inode of cpfile + * @start_cno: start checkpoint number (inclusive) + * @end_cno: end checkpoint number (inclusive) + * @cnop: place to store the next checkpoint number + * @bhp: place to store a pointer to buffer_head struct + * + * Return Value: On success, it returns 0. On error, the following negative + * error code is returned. + * + * %-ENOMEM - Insufficient memory available. + * + * %-EIO - I/O error + * + * %-ENOENT - no block exists in the range. + */ +static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile, + __u64 start_cno, __u64 end_cno, + __u64 *cnop, + struct buffer_head **bhp) +{ + unsigned long start, end, blkoff; + int ret; + + if (unlikely(start_cno > end_cno)) + return -ENOENT; + + start = nilfs_cpfile_get_blkoff(cpfile, start_cno); + end = nilfs_cpfile_get_blkoff(cpfile, end_cno); + + ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp); + if (!ret) + *cnop = (blkoff == start) ? start_cno : + nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff); + return ret; +} + static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, __u64 cno) { @@ -403,14 +448,15 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, return -ENOENT; /* checkpoint number 0 is invalid */ down_read(&NILFS_MDT(cpfile)->mi_sem); - for (n = 0; cno < cur_cno && n < nci; cno += ncps) { - ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); - ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); + for (n = 0; n < nci; cno += ncps) { + ret = nilfs_cpfile_find_checkpoint_block( + cpfile, cno, cur_cno - 1, &cno, &bh); if (ret < 0) { - if (ret != -ENOENT) - goto out; - continue; /* skip hole */ + if (likely(ret == -ENOENT)) + break; + goto out; } + ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); kaddr = kmap_atomic(bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 82f4865..ebf89fd 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -173,6 +173,21 @@ static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key) return ret; } +static int nilfs_direct_seek_key(const struct nilfs_bmap *direct, __u64 start, + __u64 *keyp) +{ + __u64 key; + + for (key = start; key <= NILFS_DIRECT_KEY_MAX; key++) { + if (nilfs_direct_get_ptr(direct, key) != + NILFS_BMAP_INVALID_PTR) { + *keyp = key; + return 0; + } + } + return -ENOENT; +} + static int nilfs_direct_last_key(const struct nilfs_bmap *direct, __u64 *keyp) { __u64 key, lastkey; @@ -355,7 +370,9 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = { .bop_assign = nilfs_direct_assign, .bop_mark = NULL, + .bop_seek_key = nilfs_direct_seek_key, .bop_last_key = nilfs_direct_last_key, + .bop_check_insert = nilfs_direct_check_insert, .bop_check_delete = NULL, .bop_gather_data = nilfs_direct_gather_data, diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 36f057f..be936df 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -106,7 +106,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, err = nilfs_transaction_begin(inode->i_sb, &ti, 1); if (unlikely(err)) goto out; - err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff, + err = nilfs_bmap_insert(ii->i_bmap, blkoff, (unsigned long)bh_result); if (unlikely(err != 0)) { if (err == -EEXIST) { @@ -441,21 +441,20 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) void nilfs_set_inode_flags(struct inode *inode) { unsigned int flags = NILFS_I(inode)->i_flags; + unsigned int new_fl = 0; - inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | - S_DIRSYNC); if (flags & FS_SYNC_FL) - inode->i_flags |= S_SYNC; + new_fl |= S_SYNC; if (flags & FS_APPEND_FL) - inode->i_flags |= S_APPEND; + new_fl |= S_APPEND; if (flags & FS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & FS_NOATIME_FL) - inode->i_flags |= S_NOATIME; + new_fl |= S_NOATIME; if (flags & FS_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; - mapping_set_gfp_mask(inode->i_mapping, - mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + new_fl |= S_DIRSYNC; + inode_set_flags(inode, new_fl, S_SYNC | S_APPEND | S_IMMUTABLE | + S_NOATIME | S_DIRSYNC); } int nilfs_read_inode_common(struct inode *inode, @@ -540,6 +539,8 @@ static int __nilfs_read_inode(struct super_block *sb, brelse(bh); up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); nilfs_set_inode_flags(inode); + mapping_set_gfp_mask(inode->i_mapping, + mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); return 0; failed_unmap: @@ -712,7 +713,7 @@ void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh, int flags) static void nilfs_truncate_bmap(struct nilfs_inode_info *ii, unsigned long from) { - unsigned long b; + __u64 b; int ret; if (!test_bit(NILFS_I_BMAP, &ii->i_state)) @@ -727,7 +728,7 @@ repeat: if (b < from) return; - b -= min_t(unsigned long, NILFS_MAX_TRUNCATE_BLOCKS, b - from); + b -= min_t(__u64, NILFS_MAX_TRUNCATE_BLOCKS, b - from); ret = nilfs_bmap_truncate(ii->i_bmap, b); nilfs_relax_pressure_in_lock(ii->vfs_inode.i_sb); if (!ret || (ret == -ENOMEM && diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 892cf5f..dee34d9 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -261,6 +261,60 @@ int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create, } /** + * nilfs_mdt_find_block - find and get a buffer on meta data file. + * @inode: inode of the meta data file + * @start: start block offset (inclusive) + * @end: end block offset (inclusive) + * @blkoff: block offset + * @out_bh: place to store a pointer to buffer_head struct + * + * nilfs_mdt_find_block() looks up an existing block in range of + * [@start, @end] and stores pointer to a buffer head of the block to + * @out_bh, and block offset to @blkoff, respectively. @out_bh and + * @blkoff are substituted only when zero is returned. + * + * Return Value: On success, it returns 0. On error, the following negative + * error code is returned. + * + * %-ENOMEM - Insufficient memory available. + * + * %-EIO - I/O error + * + * %-ENOENT - no block was found in the range + */ +int nilfs_mdt_find_block(struct inode *inode, unsigned long start, + unsigned long end, unsigned long *blkoff, + struct buffer_head **out_bh) +{ + __u64 next; + int ret; + + if (unlikely(start > end)) + return -ENOENT; + + ret = nilfs_mdt_read_block(inode, start, true, out_bh); + if (!ret) { + *blkoff = start; + goto out; + } + if (unlikely(ret != -ENOENT || start == ULONG_MAX)) + goto out; + + ret = nilfs_bmap_seek_key(NILFS_I(inode)->i_bmap, start + 1, &next); + if (!ret) { + if (next <= end) { + ret = nilfs_mdt_read_block(inode, next, true, out_bh); + if (!ret) + *blkoff = next; + } else { + ret = -ENOENT; + } + } +out: + return ret; +} + +/** * nilfs_mdt_delete_block - make a hole on the meta data file. * @inode: inode of the meta data file * @block: block offset diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index ab172e8..fe529a8 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -78,6 +78,9 @@ int nilfs_mdt_get_block(struct inode *, unsigned long, int, void (*init_block)(struct inode *, struct buffer_head *, void *), struct buffer_head **); +int nilfs_mdt_find_block(struct inode *inode, unsigned long start, + unsigned long end, unsigned long *blkoff, + struct buffer_head **out_bh); int nilfs_mdt_delete_block(struct inode *, unsigned long); int nilfs_mdt_forget_block(struct inode *, unsigned long); int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); @@ -111,7 +114,10 @@ static inline __u64 nilfs_mdt_cno(struct inode *inode) return ((struct the_nilfs *)inode->i_sb->s_fs_info)->ns_cno; } -#define nilfs_mdt_bgl_lock(inode, bg) \ - (&NILFS_MDT(inode)->mi_bgl->locks[(bg) & (NR_BG_LOCKS-1)].lock) +static inline spinlock_t * +nilfs_mdt_bgl_lock(struct inode *inode, unsigned int block_group) +{ + return bgl_lock_ptr(NILFS_MDT(inode)->mi_bgl, block_group); +} #endif /* _NILFS_MDT_H */ diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 700ecbc..45d650a 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -89,18 +89,16 @@ struct buffer_head *nilfs_grab_buffer(struct inode *inode, void nilfs_forget_buffer(struct buffer_head *bh) { struct page *page = bh->b_page; + const unsigned long clear_bits = + (1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped | + 1 << BH_Async_Write | 1 << BH_NILFS_Volatile | + 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected); lock_buffer(bh); - clear_buffer_nilfs_volatile(bh); - clear_buffer_nilfs_checked(bh); - clear_buffer_nilfs_redirected(bh); - clear_buffer_async_write(bh); - clear_buffer_dirty(bh); + set_mask_bits(&bh->b_state, clear_bits, 0); if (nilfs_page_buffers_clean(page)) __nilfs_clear_page_dirty(page); - clear_buffer_uptodate(bh); - clear_buffer_mapped(bh); bh->b_blocknr = -1; ClearPageUptodate(page); ClearPageMappedToDisk(page); @@ -421,6 +419,10 @@ void nilfs_clear_dirty_page(struct page *page, bool silent) if (page_has_buffers(page)) { struct buffer_head *bh, *head; + const unsigned long clear_bits = + (1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped | + 1 << BH_Async_Write | 1 << BH_NILFS_Volatile | + 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected); bh = head = page_buffers(page); do { @@ -430,13 +432,7 @@ void nilfs_clear_dirty_page(struct page *page, bool silent) "discard block %llu, size %zu", (u64)bh->b_blocknr, bh->b_size); } - clear_buffer_async_write(bh); - clear_buffer_dirty(bh); - clear_buffer_nilfs_volatile(bh); - clear_buffer_nilfs_checked(bh); - clear_buffer_nilfs_redirected(bh); - clear_buffer_uptodate(bh); - clear_buffer_mapped(bh); + set_mask_bits(&bh->b_state, clear_bits, 0); unlock_buffer(bh); } while (bh = bh->b_this_page, bh != head); } diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 0c3f303..c6abbad9 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -24,6 +24,7 @@ #include <linux/pagemap.h> #include <linux/buffer_head.h> #include <linux/writeback.h> +#include <linux/bitops.h> #include <linux/bio.h> #include <linux/completion.h> #include <linux/blkdev.h> @@ -1588,7 +1589,6 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci) list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) { - set_buffer_async_write(bh); if (bh->b_page != bd_page) { if (bd_page) { lock_page(bd_page); @@ -1688,7 +1688,6 @@ static void nilfs_abort_logs(struct list_head *logs, int err) list_for_each_entry(segbuf, logs, sb_list) { list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) { - clear_buffer_async_write(bh); if (bh->b_page != bd_page) { if (bd_page) end_page_writeback(bd_page); @@ -1768,7 +1767,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) b_assoc_buffers) { set_buffer_uptodate(bh); clear_buffer_dirty(bh); - clear_buffer_async_write(bh); if (bh->b_page != bd_page) { if (bd_page) end_page_writeback(bd_page); @@ -1788,12 +1786,13 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) */ list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) { - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); - clear_buffer_async_write(bh); - clear_buffer_delay(bh); - clear_buffer_nilfs_volatile(bh); - clear_buffer_nilfs_redirected(bh); + const unsigned long set_bits = (1 << BH_Uptodate); + const unsigned long clear_bits = + (1 << BH_Dirty | 1 << BH_Async_Write | + 1 << BH_Delay | 1 << BH_NILFS_Volatile | + 1 << BH_NILFS_Redirected); + + set_mask_bits(&bh->b_state, clear_bits, set_bits); if (bh == segbuf->sb_super_root) { if (bh->b_page != bd_page) { end_page_writeback(bd_page); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 5bc2a1c..c1725f20 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1020,7 +1020,7 @@ int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno) struct dentry *dentry; int ret; - if (cno < 0 || cno > nilfs->ns_cno) + if (cno > nilfs->ns_cno) return false; if (cno >= nilfs_last_cno(nilfs)) diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 8e5ad83..af84ad0 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -8,6 +8,7 @@ #include <linux/security.h> #include <linux/file.h> #include <linux/seq_file.h> +#include <linux/fs.h> #include <linux/proc_fs.h> @@ -48,17 +49,23 @@ static int seq_show(struct seq_file *m, void *v) put_files_struct(files); } - if (!ret) { - seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", - (long long)file->f_pos, f_flags, - real_mount(file->f_path.mnt)->mnt_id); - if (file->f_op->show_fdinfo) - file->f_op->show_fdinfo(m, file); - ret = seq_has_overflowed(m); - fput(file); - } + if (ret) + return ret; - return ret; + seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", + (long long)file->f_pos, f_flags, + real_mount(file->f_path.mnt)->mnt_id); + + show_fd_locks(m, file, files); + if (seq_has_overflowed(m)) + goto out; + + if (file->f_op->show_fdinfo) + file->f_op->show_fdinfo(m, file); + +out: + fput(file); + return 0; } static int seq_fdinfo_open(struct inode *inode, struct file *file) diff --git a/include/asm-generic/seccomp.h b/include/asm-generic/seccomp.h index 9fa1f65..c9ccafa 100644 --- a/include/asm-generic/seccomp.h +++ b/include/asm-generic/seccomp.h @@ -17,7 +17,9 @@ #define __NR_seccomp_read_32 __NR_read #define __NR_seccomp_write_32 __NR_write #define __NR_seccomp_exit_32 __NR_exit +#ifndef __NR_seccomp_sigreturn_32 #define __NR_seccomp_sigreturn_32 __NR_rt_sigreturn +#endif #endif /* CONFIG_COMPAT && ! already defined */ #define __NR_seccomp_read __NR_read diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index be4fa5d..ea17cca 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -283,16 +283,16 @@ static inline int bitmap_empty(const unsigned long *src, unsigned nbits) { if (small_const_nbits(nbits)) return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); - else - return __bitmap_empty(src, nbits); + + return find_first_bit(src, nbits) == nbits; } static inline int bitmap_full(const unsigned long *src, unsigned int nbits) { if (small_const_nbits(nbits)) return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); - else - return __bitmap_full(src, nbits); + + return find_first_zero_bit(src, nbits) == nbits; } static inline int bitmap_weight(const unsigned long *src, unsigned int nbits) diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 5d858e0..297f5bd 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -218,9 +218,9 @@ static inline unsigned long __ffs64(u64 word) /** * find_last_bit - find the last set bit in a memory region * @addr: The address to start the search at - * @size: The maximum size to search + * @size: The number of bits to search * - * Returns the bit number of the first set bit, or size. + * Returns the bit number of the last set bit, or size. */ extern unsigned long find_last_bit(const unsigned long *addr, unsigned long size); diff --git a/include/linux/fs.h b/include/linux/fs.h index f4d6354..c7496f2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -875,6 +875,7 @@ static inline struct file *get_file(struct file *f) atomic_long_inc(&f->f_count); return f; } +#define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count) #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) #define file_count(x) atomic_long_read(&(x)->f_count) @@ -1046,6 +1047,9 @@ extern void lease_get_mtime(struct inode *, struct timespec *time); extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); extern int vfs_setlease(struct file *, long, struct file_lock **, void **); extern int lease_modify(struct file_lock *, int, struct list_head *); +struct files_struct; +extern void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files); #else /* !CONFIG_FILE_LOCKING */ static inline int fcntl_getlk(struct file *file, unsigned int cmd, struct flock __user *user) @@ -1182,6 +1186,10 @@ static inline int lease_modify(struct file_lock *fl, int arg, { return -EINVAL; } + +struct files_struct; +static inline void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) {} #endif /* !CONFIG_FILE_LOCKING */ diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index be342b9..63ca8da 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -23,14 +23,6 @@ #define ___config_enabled(__ignored, val, ...) val /* - * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', - * 0 otherwise. - * - */ -#define IS_ENABLED(option) \ - (config_enabled(option) || config_enabled(option##_MODULE)) - -/* * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 * otherwise. For boolean options, this is equivalent to * IS_ENABLED(CONFIG_FOO). @@ -43,4 +35,11 @@ */ #define IS_MODULE(option) config_enabled(option##_MODULE) +/* + * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', + * 0 otherwise. + */ +#define IS_ENABLED(option) \ + (IS_BUILTIN(option) || IS_MODULE(option)) + #endif /* __LINUX_KCONFIG_H */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index d6d630d..3a5b48e 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -103,6 +103,18 @@ (((__x) - ((__d) / 2)) / (__d)); \ } \ ) +/* + * Same as above but for u64 dividends. divisor must be a 32-bit + * number. + */ +#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \ +{ \ + typeof(divisor) __d = divisor; \ + unsigned long long _tmp = (x) + (__d) / 2; \ + do_div(_tmp, __d); \ + _tmp; \ +} \ +) /* * Multiplies an integer by a fraction, while avoiding unnecessary diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h index b6401e7..29c30ac 100644 --- a/include/linux/mfd/samsung/rtc.h +++ b/include/linux/mfd/samsung/rtc.h @@ -105,6 +105,8 @@ enum s2mps_rtc_reg { #define S5M_RTC_UDR_MASK (1 << S5M_RTC_UDR_SHIFT) #define S2MPS_RTC_WUDR_SHIFT 4 #define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT) +#define S2MPS13_RTC_AUDR_SHIFT 1 +#define S2MPS13_RTC_AUDR_MASK (1 << S2MPS13_RTC_AUDR_SHIFT) #define S2MPS_RTC_RUDR_SHIFT 0 #define S2MPS_RTC_RUDR_MASK (1 << S2MPS_RTC_RUDR_SHIFT) #define RTC_TCON_SHIFT 1 diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 590630e..8d37e26 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -429,7 +429,7 @@ struct mm_struct { #endif /* store ref to file /proc/<pid>/exe symlink points to */ - struct file *exe_file; + struct file __rcu *exe_file; #ifdef CONFIG_MMU_NOTIFIER struct mmu_notifier_mm *mmu_notifier_mm; #endif diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index b7361f8..795d5fe 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -212,4 +212,7 @@ static inline void setup_sysctl_set(struct ctl_table_set *p, #endif /* CONFIG_SYSCTL */ +int sysctl_max_threads(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); + #endif /* _LINUX_SYSCTL_H */ diff --git a/include/linux/util_macros.h b/include/linux/util_macros.h new file mode 100644 index 0000000..d5f4fb6 --- /dev/null +++ b/include/linux/util_macros.h @@ -0,0 +1,40 @@ +#ifndef _LINUX_HELPER_MACROS_H_ +#define _LINUX_HELPER_MACROS_H_ + +#define __find_closest(x, a, as, op) \ +({ \ + typeof(as) __fc_i, __fc_as = (as) - 1; \ + typeof(x) __fc_x = (x); \ + typeof(*a) *__fc_a = (a); \ + for (__fc_i = 0; __fc_i < __fc_as; __fc_i++) { \ + if (__fc_x op DIV_ROUND_CLOSEST(__fc_a[__fc_i] + \ + __fc_a[__fc_i + 1], 2)) \ + break; \ + } \ + (__fc_i); \ +}) + +/** + * find_closest - locate the closest element in a sorted array + * @x: The reference value. + * @a: The array in which to look for the closest element. Must be sorted + * in ascending order. + * @as: Size of 'a'. + * + * Returns the index of the element closest to 'x'. + */ +#define find_closest(x, a, as) __find_closest(x, a, as, <=) + +/** + * find_closest_descending - locate the closest element in a sorted array + * @x: The reference value. + * @a: The array in which to look for the closest element. Must be sorted + * in descending order. + * @as: Size of 'a'. + * + * Similar to find_closest() but 'a' is expected to be sorted in descending + * order. + */ +#define find_closest_descending(x, a, as) __find_closest(x, a, as, >=) + +#endif diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h index 1e1ea6e..88e0914c 100644 --- a/include/uapi/asm-generic/errno.h +++ b/include/uapi/asm-generic/errno.h @@ -6,7 +6,16 @@ #define EDEADLK 35 /* Resource deadlock would occur */ #define ENAMETOOLONG 36 /* File name too long */ #define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ + +/* + * This error code is special: arch syscall entry code will return + * -ENOSYS if users try to call a syscall that doesn't exist. To keep + * failures of syscalls that really do exist distinguishable from + * failures due to attempts to use a nonexistent syscall, syscall + * implementations should refrain from returning -ENOSYS. + */ +#define ENOSYS 38 /* Invalid system call number */ + #define ENOTEMPTY 39 /* Directory not empty */ #define ELOOP 40 /* Too many symbolic links encountered */ #define EWOULDBLOCK EAGAIN /* Operation would block */ diff --git a/init/main.c b/init/main.c index a7e969d..2115055 100644 --- a/init/main.c +++ b/init/main.c @@ -91,7 +91,7 @@ static int kernel_init(void *); extern void init_IRQ(void); -extern void fork_init(unsigned long); +extern void fork_init(void); extern void radix_tree_init(void); #ifndef CONFIG_DEBUG_RODATA static inline void mark_rodata_ro(void) { } @@ -645,7 +645,7 @@ asmlinkage __visible void __init start_kernel(void) #endif thread_info_cache_init(); cred_init(); - fork_init(totalram_pages); + fork_init(); proc_caches_init(); buffer_init(); key_init(); diff --git a/kernel/fork.c b/kernel/fork.c index f2c1e73..03c1eaa 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -74,6 +74,7 @@ #include <linux/uprobes.h> #include <linux/aio.h> #include <linux/compiler.h> +#include <linux/sysctl.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -88,6 +89,16 @@ #include <trace/events/task.h> /* + * Minimum number of threads to boot the kernel + */ +#define MIN_THREADS 20 + +/* + * Maximum number of threads + */ +#define MAX_THREADS FUTEX_TID_MASK + +/* * Protected counters by write_lock_irq(&tasklist_lock) */ unsigned long total_forks; /* Handle normal Linux uptimes. */ @@ -253,7 +264,30 @@ EXPORT_SYMBOL_GPL(__put_task_struct); void __init __weak arch_task_cache_init(void) { } -void __init fork_init(unsigned long mempages) +/* + * set_max_threads + */ +static void set_max_threads(unsigned int max_threads_suggested) +{ + u64 threads; + + /* + * The number of threads shall be limited such that the thread + * structures may only consume a small part of the available memory. + */ + if (fls64(totalram_pages) + fls64(PAGE_SIZE) > 64) + threads = MAX_THREADS; + else + threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE, + (u64) THREAD_SIZE * 8UL); + + if (threads > max_threads_suggested) + threads = max_threads_suggested; + + max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS); +} + +void __init fork_init(void) { #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR #ifndef ARCH_MIN_TASKALIGN @@ -268,18 +302,7 @@ void __init fork_init(unsigned long mempages) /* do the arch specific task caches init */ arch_task_cache_init(); - /* - * The default maximum number of threads is set to a safe - * value: the thread structures can take up at most half - * of memory. - */ - max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE); - - /* - * we need to allow at least 20 threads to boot a system - */ - if (max_threads < 20) - max_threads = 20; + set_max_threads(MAX_THREADS); init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2; @@ -380,6 +403,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) */ down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING); + /* No ordering required: file already has been exposed. */ + RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); + mm->total_vm = oldmm->total_vm; mm->shared_vm = oldmm->shared_vm; mm->exec_vm = oldmm->exec_vm; @@ -505,7 +531,13 @@ static inline void mm_free_pgd(struct mm_struct *mm) pgd_free(mm, mm->pgd); } #else -#define dup_mmap(mm, oldmm) (0) +static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) +{ + down_write(&oldmm->mmap_sem); + RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); + up_write(&oldmm->mmap_sem); + return 0; +} #define mm_alloc_pgd(mm) (0) #define mm_free_pgd(mm) #endif /* CONFIG_MMU */ @@ -674,34 +706,53 @@ void mmput(struct mm_struct *mm) } EXPORT_SYMBOL_GPL(mmput); +/** + * set_mm_exe_file - change a reference to the mm's executable file + * + * This changes mm's executable file (shown as symlink /proc/[pid]/exe). + * + * Main users are mmput() and sys_execve(). Callers prevent concurrent + * invocations: in mmput() nobody alive left, in execve task is single + * threaded. sys_prctl(PR_SET_MM_MAP/EXE_FILE) also needs to set the + * mm->exe_file, but does so without using set_mm_exe_file() in order + * to do avoid the need for any locks. + */ void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) { + struct file *old_exe_file; + + /* + * It is safe to dereference the exe_file without RCU as + * this function is only called if nobody else can access + * this mm -- see comment above for justification. + */ + old_exe_file = rcu_dereference_raw(mm->exe_file); + if (new_exe_file) get_file(new_exe_file); - if (mm->exe_file) - fput(mm->exe_file); - mm->exe_file = new_exe_file; + rcu_assign_pointer(mm->exe_file, new_exe_file); + if (old_exe_file) + fput(old_exe_file); } +/** + * get_mm_exe_file - acquire a reference to the mm's executable file + * + * Returns %NULL if mm has no associated executable file. + * User must release file via fput(). + */ struct file *get_mm_exe_file(struct mm_struct *mm) { struct file *exe_file; - /* We need mmap_sem to protect against races with removal of exe_file */ - down_read(&mm->mmap_sem); - exe_file = mm->exe_file; - if (exe_file) - get_file(exe_file); - up_read(&mm->mmap_sem); + rcu_read_lock(); + exe_file = rcu_dereference(mm->exe_file); + if (exe_file && !get_file_rcu(exe_file)) + exe_file = NULL; + rcu_read_unlock(); return exe_file; } - -static void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm) -{ - /* It's safe to write the exe_file pointer without exe_file_lock because - * this is called during fork when the task is not yet in /proc */ - newmm->exe_file = get_mm_exe_file(oldmm); -} +EXPORT_SYMBOL(get_mm_exe_file); /** * get_task_mm - acquire a reference to the task's mm @@ -864,8 +915,6 @@ static struct mm_struct *dup_mm(struct task_struct *tsk) if (!mm_init(mm, tsk)) goto fail_nomem; - dup_mm_exe_file(oldmm, mm); - err = dup_mmap(mm, oldmm); if (err) goto free_pt; @@ -1403,10 +1452,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_cleanup_io; if (pid != &init_struct_pid) { - retval = -ENOMEM; pid = alloc_pid(p->nsproxy->pid_ns_for_children); - if (!pid) + if (IS_ERR(pid)) { + retval = PTR_ERR(pid); goto bad_fork_cleanup_io; + } } p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; @@ -2000,3 +2050,26 @@ int unshare_files(struct files_struct **displaced) task_unlock(task); return 0; } + +int sysctl_max_threads(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table t; + int ret; + int threads = max_threads; + int min = MIN_THREADS; + int max = MAX_THREADS; + + t = *table; + t.data = &threads; + t.extra1 = &min; + t.extra2 = &max; + + ret = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); + if (ret || !write) + return ret; + + set_max_threads(threads); + + return 0; +} diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c index b358a80..a744098 100644 --- a/kernel/gcov/base.c +++ b/kernel/gcov/base.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/sched.h> #include "gcov.h" static int gcov_events_enabled; @@ -107,8 +108,10 @@ void gcov_enable_events(void) gcov_events_enabled = 1; /* Perform event callback for previously registered entries. */ - while ((info = gcov_info_next(info))) + while ((info = gcov_info_next(info))) { gcov_event(GCOV_ADD, info); + cond_resched(); + } mutex_unlock(&gcov_lock); } diff --git a/kernel/pid.c b/kernel/pid.c index cd36a5e..4fd07d5 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -182,7 +182,7 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) spin_unlock_irq(&pidmap_lock); kfree(page); if (unlikely(!map->page)) - break; + return -ENOMEM; } if (likely(atomic_read(&map->nr_free))) { for ( ; ; ) { @@ -210,7 +210,7 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) } pid = mk_pid(pid_ns, map, offset); } - return -1; + return -EAGAIN; } int next_pidmap(struct pid_namespace *pid_ns, unsigned int last) @@ -301,17 +301,20 @@ struct pid *alloc_pid(struct pid_namespace *ns) int i, nr; struct pid_namespace *tmp; struct upid *upid; + int retval = -ENOMEM; pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); if (!pid) - goto out; + return ERR_PTR(retval); tmp = ns; pid->level = ns->level; for (i = ns->level; i >= 0; i--) { nr = alloc_pidmap(tmp); - if (nr < 0) + if (IS_ERR_VALUE(nr)) { + retval = nr; goto out_free; + } pid->numbers[i].nr = nr; pid->numbers[i].ns = tmp; @@ -339,7 +342,6 @@ struct pid *alloc_pid(struct pid_namespace *ns) } spin_unlock_irq(&pidmap_lock); -out: return pid; out_unlock: @@ -351,8 +353,7 @@ out_free: free_pidmap(pid->numbers + i); kmem_cache_free(ns->pid_cachep, pid); - pid = NULL; - goto out; + return ERR_PTR(retval); } void disable_pid_allocation(struct pid_namespace *ns) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 227fec3..c8e0e05 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -456,8 +456,6 @@ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) static int ptrace_detach(struct task_struct *child, unsigned int data) { - bool dead = false; - if (!valid_signal(data)) return -EIO; @@ -467,18 +465,19 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) write_lock_irq(&tasklist_lock); /* - * This child can be already killed. Make sure de_thread() or - * our sub-thread doing do_wait() didn't do release_task() yet. + * We rely on ptrace_freeze_traced(). It can't be killed and + * untraced by another thread, it can't be a zombie. */ - if (child->ptrace) { - child->exit_code = data; - dead = __ptrace_detach(current, child); - } + WARN_ON(!child->ptrace || child->exit_state); + /* + * tasklist_lock avoids the race with wait_task_stopped(), see + * the comment in ptrace_resume(). + */ + child->exit_code = data; + __ptrace_detach(current, child); write_unlock_irq(&tasklist_lock); proc_ptrace_connector(child, PTRACE_DETACH); - if (unlikely(dead)) - release_task(child); return 0; } @@ -697,6 +696,8 @@ static int ptrace_peek_siginfo(struct task_struct *child, static int ptrace_resume(struct task_struct *child, long request, unsigned long data) { + bool need_siglock; + if (!valid_signal(data)) return -EIO; @@ -724,8 +725,26 @@ static int ptrace_resume(struct task_struct *child, long request, user_disable_single_step(child); } + /* + * Change ->exit_code and ->state under siglock to avoid the race + * with wait_task_stopped() in between; a non-zero ->exit_code will + * wrongly look like another report from tracee. + * + * Note that we need siglock even if ->exit_code == data and/or this + * status was not reported yet, the new status must not be cleared by + * wait_task_stopped() after resume. + * + * If data == 0 we do not care if wait_task_stopped() reports the old + * status and clears the code too; this can't race with the tracee, it + * takes siglock after resume. + */ + need_siglock = data && !thread_group_empty(current); + if (need_siglock) + spin_lock_irq(&child->sighand->siglock); child->exit_code = data; wake_up_state(child, __TASK_TRACED); + if (need_siglock) + spin_unlock_irq(&child->sighand->siglock); return 0; } diff --git a/kernel/signal.c b/kernel/signal.c index a390499..d51c5dd 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2992,11 +2992,9 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) * Nor can they impersonate a kill()/tgkill(), which adds source info. */ if ((info->si_code >= 0 || info->si_code == SI_TKILL) && - (task_pid_vnr(current) != pid)) { - /* We used to allow any < 0 si_code */ - WARN_ON_ONCE(info->si_code < 0); + (task_pid_vnr(current) != pid)) return -EPERM; - } + info->si_signo = sig; /* POSIX.1b doesn't mention process groups. */ @@ -3041,12 +3039,10 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) /* Not even root can pretend to send signals from the kernel. * Nor can they impersonate a kill()/tgkill(), which adds source info. */ - if (((info->si_code >= 0 || info->si_code == SI_TKILL)) && - (task_pid_vnr(current) != pid)) { - /* We used to allow any < 0 si_code */ - WARN_ON_ONCE(info->si_code < 0); + if ((info->si_code >= 0 || info->si_code == SI_TKILL) && + (task_pid_vnr(current) != pid)) return -EPERM; - } + info->si_signo = sig; return do_send_specific(tgid, pid, sig, info); diff --git a/kernel/sys.c b/kernel/sys.c index 3be3449..a4e372b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1649,14 +1649,13 @@ SYSCALL_DEFINE1(umask, int, mask) return mask; } -static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd) +static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) { struct fd exe; + struct file *old_exe, *exe_file; struct inode *inode; int err; - VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm); - exe = fdget(fd); if (!exe.file) return -EBADF; @@ -1680,15 +1679,22 @@ static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd) /* * Forbid mm->exe_file change if old file still mapped. */ + exe_file = get_mm_exe_file(mm); err = -EBUSY; - if (mm->exe_file) { + if (exe_file) { struct vm_area_struct *vma; - for (vma = mm->mmap; vma; vma = vma->vm_next) - if (vma->vm_file && - path_equal(&vma->vm_file->f_path, - &mm->exe_file->f_path)) - goto exit; + down_read(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (!vma->vm_file) + continue; + if (path_equal(&vma->vm_file->f_path, + &exe_file->f_path)) + goto exit_err; + } + + up_read(&mm->mmap_sem); + fput(exe_file); } /* @@ -1702,10 +1708,18 @@ static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd) goto exit; err = 0; - set_mm_exe_file(mm, exe.file); /* this grabs a reference to exe.file */ + /* set the new file, lockless */ + get_file(exe.file); + old_exe = xchg(&mm->exe_file, exe.file); + if (old_exe) + fput(old_exe); exit: fdput(exe); return err; +exit_err: + up_read(&mm->mmap_sem); + fput(exe_file); + goto exit; } #ifdef CONFIG_CHECKPOINT_RESTORE @@ -1840,10 +1854,9 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL; } - down_write(&mm->mmap_sem); if (prctl_map.exe_fd != (u32)-1) - error = prctl_set_mm_exe_file_locked(mm, prctl_map.exe_fd); - downgrade_write(&mm->mmap_sem); + error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd); + down_read(&mm->mmap_sem); if (error) goto out; @@ -1909,12 +1922,8 @@ static int prctl_set_mm(int opt, unsigned long addr, if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - if (opt == PR_SET_MM_EXE_FILE) { - down_write(&mm->mmap_sem); - error = prctl_set_mm_exe_file_locked(mm, (unsigned int)addr); - up_write(&mm->mmap_sem); - return error; - } + if (opt == PR_SET_MM_EXE_FILE) + return prctl_set_mm_exe_file(mm, (unsigned int)addr); if (addr >= TASK_SIZE || addr < mmap_min_addr) return -EINVAL; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 42b7fc2..2082b1a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -93,11 +93,9 @@ #include <linux/nmi.h> #endif - #if defined(CONFIG_SYSCTL) /* External variables not in a header file. */ -extern int max_threads; extern int suid_dumpable; #ifdef CONFIG_COREDUMP extern int core_uses_pid; @@ -710,10 +708,10 @@ static struct ctl_table kern_table[] = { #endif { .procname = "threads-max", - .data = &max_threads, + .data = NULL, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = sysctl_max_threads, }, { .procname = "random", @@ -1983,7 +1981,15 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int write, void *data) { if (write) { - *valp = *negp ? -*lvalp : *lvalp; + if (*negp) { + if (*lvalp > (unsigned long) INT_MAX + 1) + return -EINVAL; + *valp = -*lvalp; + } else { + if (*lvalp > (unsigned long) INT_MAX) + return -EINVAL; + *valp = *lvalp; + } } else { int val = *valp; if (val < 0) { diff --git a/lib/Kconfig b/lib/Kconfig index 87da53b..f544022 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -18,9 +18,8 @@ config HAVE_ARCH_BITREVERSE default n depends on BITREVERSE help - This option provides an config for the architecture which have instruction - can do bitreverse operation, we use the hardware instruction if the architecture - have this capability. + This option enables the use of hardware bit-reversal instructions on + architectures which support such operations. config RATIONAL bool diff --git a/lib/Makefile b/lib/Makefile index 58f74d2..da6116b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -25,7 +25,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iov_iter.o clz_ctz.o \ - bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ + bsearch.o find_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o diff --git a/lib/bitmap.c b/lib/bitmap.c index d456f4c1..64c0926 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -42,36 +42,6 @@ * for the best explanations of this ordering. */ -int __bitmap_empty(const unsigned long *bitmap, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - for (k = 0; k < lim; ++k) - if (bitmap[k]) - return 0; - - if (bits % BITS_PER_LONG) - if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) - return 0; - - return 1; -} -EXPORT_SYMBOL(__bitmap_empty); - -int __bitmap_full(const unsigned long *bitmap, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - for (k = 0; k < lim; ++k) - if (~bitmap[k]) - return 0; - - if (bits % BITS_PER_LONG) - if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) - return 0; - - return 1; -} -EXPORT_SYMBOL(__bitmap_full); - int __bitmap_equal(const unsigned long *bitmap1, const unsigned long *bitmap2, unsigned int bits) { diff --git a/lib/cpumask.c b/lib/cpumask.c index b6513a9..5ab1553 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -37,10 +37,11 @@ EXPORT_SYMBOL(__next_cpu_nr); int cpumask_next_and(int n, const struct cpumask *src1p, const struct cpumask *src2p) { - while ((n = cpumask_next(n, src1p)) < nr_cpu_ids) - if (cpumask_test_cpu(n, src2p)) - break; - return n; + struct cpumask tmp; + + if (cpumask_and(&tmp, src1p, src2p)) + return cpumask_next(n, &tmp); + return nr_cpu_ids; } EXPORT_SYMBOL(cpumask_next_and); diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 9722bd2..ae4b65e 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -361,7 +361,7 @@ static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket, unsigned int range = 0; while (range <= max_range) { - entry = __hash_bucket_find(*bucket, &index, containing_match); + entry = __hash_bucket_find(*bucket, ref, containing_match); if (entry) return entry; diff --git a/lib/find_bit.c b/lib/find_bit.c new file mode 100644 index 0000000..18072ea --- /dev/null +++ b/lib/find_bit.c @@ -0,0 +1,193 @@ +/* bit search implementation + * + * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Copyright (C) 2008 IBM Corporation + * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au> + * (Inspired by David Howell's find_next_bit implementation) + * + * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease + * size and improve performance, 2015. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/bitops.h> +#include <linux/bitmap.h> +#include <linux/export.h> +#include <linux/kernel.h> + +#if !defined(find_next_bit) || !defined(find_next_zero_bit) + +/* + * This is a common helper function for find_next_bit and + * find_next_zero_bit. The difference is the "invert" argument, which + * is XORed with each fetched word before searching it for one bits. + */ +static unsigned long _find_next_bit(const unsigned long *addr, + unsigned long nbits, unsigned long start, unsigned long invert) +{ + unsigned long tmp; + + if (!nbits || start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + + /* Handle 1st word. */ + tmp &= BITMAP_FIRST_WORD_MASK(start); + start = round_down(start, BITS_PER_LONG); + + while (!tmp) { + start += BITS_PER_LONG; + if (start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + } + + return min(start + __ffs(tmp), nbits); +} +#endif + +#ifndef find_next_bit +/* + * Find the next set bit in a memory region. + */ +unsigned long find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + return _find_next_bit(addr, size, offset, 0UL); +} +EXPORT_SYMBOL(find_next_bit); +#endif + +#ifndef find_next_zero_bit +unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + return _find_next_bit(addr, size, offset, ~0UL); +} +EXPORT_SYMBOL(find_next_zero_bit); +#endif + +#ifndef find_first_bit +/* + * Find the first set bit in a memory region. + */ +unsigned long find_first_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long idx; + + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { + if (addr[idx]) + return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); + } + + return size; +} +EXPORT_SYMBOL(find_first_bit); +#endif + +#ifndef find_first_zero_bit +/* + * Find the first cleared bit in a memory region. + */ +unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long idx; + + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { + if (addr[idx] != ~0UL) + return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); + } + + return size; +} +EXPORT_SYMBOL(find_first_zero_bit); +#endif + +#ifndef find_last_bit +unsigned long find_last_bit(const unsigned long *addr, unsigned long size) +{ + if (size) { + unsigned long val = BITMAP_LAST_WORD_MASK(size); + unsigned long idx = (size-1) / BITS_PER_LONG; + + do { + val &= addr[idx]; + if (val) + return idx * BITS_PER_LONG + __fls(val); + + val = ~0ul; + } while (idx--); + } + return size; +} +EXPORT_SYMBOL(find_last_bit); +#endif + +#ifdef __BIG_ENDIAN + +/* include/linux/byteorder does not support "unsigned long" type */ +static inline unsigned long ext2_swab(const unsigned long y) +{ +#if BITS_PER_LONG == 64 + return (unsigned long) __swab64((u64) y); +#elif BITS_PER_LONG == 32 + return (unsigned long) __swab32((u32) y); +#else +#error BITS_PER_LONG not defined +#endif +} + +#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) +static unsigned long _find_next_bit_le(const unsigned long *addr, + unsigned long nbits, unsigned long start, unsigned long invert) +{ + unsigned long tmp; + + if (!nbits || start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + + /* Handle 1st word. */ + tmp &= ext2_swab(BITMAP_FIRST_WORD_MASK(start)); + start = round_down(start, BITS_PER_LONG); + + while (!tmp) { + start += BITS_PER_LONG; + if (start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + } + + return min(start + __ffs(ext2_swab(tmp)), nbits); +} +#endif + +#ifndef find_next_zero_bit_le +unsigned long find_next_zero_bit_le(const void *addr, unsigned + long size, unsigned long offset) +{ + return _find_next_bit_le(addr, size, offset, ~0UL); +} +EXPORT_SYMBOL(find_next_zero_bit_le); +#endif + +#ifndef find_next_bit_le +unsigned long find_next_bit_le(const void *addr, unsigned + long size, unsigned long offset) +{ + return _find_next_bit_le(addr, size, offset, 0UL); +} +EXPORT_SYMBOL(find_next_bit_le); +#endif + +#endif /* __BIG_ENDIAN */ diff --git a/lib/find_last_bit.c b/lib/find_last_bit.c index 91ca09f..3e3be40 100644 --- a/lib/find_last_bit.c +++ b/lib/find_last_bit.c @@ -4,6 +4,9 @@ * Written by Rusty Russell <rusty@rustcorp.com.au> * (Inspired by David Howell's find_next_bit implementation) * + * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease + * size and improve performance, 2015. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -11,37 +14,26 @@ */ #include <linux/bitops.h> +#include <linux/bitmap.h> #include <linux/export.h> -#include <asm/types.h> -#include <asm/byteorder.h> +#include <linux/kernel.h> #ifndef find_last_bit unsigned long find_last_bit(const unsigned long *addr, unsigned long size) { - unsigned long words; - unsigned long tmp; - - /* Start at final word. */ - words = size / BITS_PER_LONG; + if (size) { + unsigned long val = BITMAP_LAST_WORD_MASK(size); + unsigned long idx = (size-1) / BITS_PER_LONG; - /* Partial final word? */ - if (size & (BITS_PER_LONG-1)) { - tmp = (addr[words] & (~0UL >> (BITS_PER_LONG - - (size & (BITS_PER_LONG-1))))); - if (tmp) - goto found; - } + do { + val &= addr[idx]; + if (val) + return idx * BITS_PER_LONG + __fls(val); - while (words) { - tmp = addr[--words]; - if (tmp) { -found: - return words * BITS_PER_LONG + __fls(tmp); - } + val = ~0ul; + } while (idx--); } - - /* Not found */ return size; } EXPORT_SYMBOL(find_last_bit); diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c deleted file mode 100644 index 0cbfc0b..0000000 --- a/lib/find_next_bit.c +++ /dev/null @@ -1,285 +0,0 @@ -/* find_next_bit.c: fallback find next bit implementation - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/bitops.h> -#include <linux/export.h> -#include <asm/types.h> -#include <asm/byteorder.h> - -#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) - -#ifndef find_next_bit -/* - * Find the next set bit in a memory region. - */ -unsigned long find_next_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + BITOP_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG-1); - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset %= BITS_PER_LONG; - if (offset) { - tmp = *(p++); - tmp &= (~0UL << offset); - if (size < BITS_PER_LONG) - goto found_first; - if (tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - while (size & ~(BITS_PER_LONG-1)) { - if ((tmp = *(p++))) - goto found_middle; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp &= (~0UL >> (BITS_PER_LONG - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found_middle: - return result + __ffs(tmp); -} -EXPORT_SYMBOL(find_next_bit); -#endif - -#ifndef find_next_zero_bit -/* - * This implementation of find_{first,next}_zero_bit was stolen from - * Linus' asm-alpha/bitops.h. - */ -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + BITOP_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG-1); - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset %= BITS_PER_LONG; - if (offset) { - tmp = *(p++); - tmp |= ~0UL >> (BITS_PER_LONG - offset); - if (size < BITS_PER_LONG) - goto found_first; - if (~tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - while (size & ~(BITS_PER_LONG-1)) { - if (~(tmp = *(p++))) - goto found_middle; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp |= ~0UL << size; - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + ffz(tmp); -} -EXPORT_SYMBOL(find_next_zero_bit); -#endif - -#ifndef find_first_bit -/* - * Find the first set bit in a memory region. - */ -unsigned long find_first_bit(const unsigned long *addr, unsigned long size) -{ - const unsigned long *p = addr; - unsigned long result = 0; - unsigned long tmp; - - while (size & ~(BITS_PER_LONG-1)) { - if ((tmp = *(p++))) - goto found; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - - tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found: - return result + __ffs(tmp); -} -EXPORT_SYMBOL(find_first_bit); -#endif - -#ifndef find_first_zero_bit -/* - * Find the first cleared bit in a memory region. - */ -unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) -{ - const unsigned long *p = addr; - unsigned long result = 0; - unsigned long tmp; - - while (size & ~(BITS_PER_LONG-1)) { - if (~(tmp = *(p++))) - goto found; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - - tmp = (*p) | (~0UL << size); - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. */ -found: - return result + ffz(tmp); -} -EXPORT_SYMBOL(find_first_zero_bit); -#endif - -#ifdef __BIG_ENDIAN - -/* include/linux/byteorder does not support "unsigned long" type */ -static inline unsigned long ext2_swabp(const unsigned long * x) -{ -#if BITS_PER_LONG == 64 - return (unsigned long) __swab64p((u64 *) x); -#elif BITS_PER_LONG == 32 - return (unsigned long) __swab32p((u32 *) x); -#else -#error BITS_PER_LONG not defined -#endif -} - -/* include/linux/byteorder doesn't support "unsigned long" type */ -static inline unsigned long ext2_swab(const unsigned long y) -{ -#if BITS_PER_LONG == 64 - return (unsigned long) __swab64((u64) y); -#elif BITS_PER_LONG == 32 - return (unsigned long) __swab32((u32) y); -#else -#error BITS_PER_LONG not defined -#endif -} - -#ifndef find_next_zero_bit_le -unsigned long find_next_zero_bit_le(const void *addr, unsigned - long size, unsigned long offset) -{ - const unsigned long *p = addr; - unsigned long result = offset & ~(BITS_PER_LONG - 1); - unsigned long tmp; - - if (offset >= size) - return size; - p += BITOP_WORD(offset); - size -= result; - offset &= (BITS_PER_LONG - 1UL); - if (offset) { - tmp = ext2_swabp(p++); - tmp |= (~0UL >> (BITS_PER_LONG - offset)); - if (size < BITS_PER_LONG) - goto found_first; - if (~tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - - while (size & ~(BITS_PER_LONG - 1)) { - if (~(tmp = *(p++))) - goto found_middle_swap; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = ext2_swabp(p); -found_first: - tmp |= ~0UL << size; - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. Skip ffz */ -found_middle: - return result + ffz(tmp); - -found_middle_swap: - return result + ffz(ext2_swab(tmp)); -} -EXPORT_SYMBOL(find_next_zero_bit_le); -#endif - -#ifndef find_next_bit_le -unsigned long find_next_bit_le(const void *addr, unsigned - long size, unsigned long offset) -{ - const unsigned long *p = addr; - unsigned long result = offset & ~(BITS_PER_LONG - 1); - unsigned long tmp; - - if (offset >= size) - return size; - p += BITOP_WORD(offset); - size -= result; - offset &= (BITS_PER_LONG - 1UL); - if (offset) { - tmp = ext2_swabp(p++); - tmp &= (~0UL << offset); - if (size < BITS_PER_LONG) - goto found_first; - if (tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - - while (size & ~(BITS_PER_LONG - 1)) { - tmp = *(p++); - if (tmp) - goto found_middle_swap; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = ext2_swabp(p); -found_first: - tmp &= (~0UL >> (BITS_PER_LONG - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found_middle: - return result + __ffs(tmp); - -found_middle_swap: - return result + __ffs(ext2_swab(tmp)); -} -EXPORT_SYMBOL(find_next_bit_le); -#endif - -#endif /* __BIG_ENDIAN */ diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 3a1e084..da39c60 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -33,6 +33,7 @@ #include <asm/page.h> /* for PAGE_SIZE */ #include <asm/sections.h> /* for dereference_function_descriptor() */ +#include <asm/byteorder.h> /* cpu_to_le16 */ #include <linux/string_helpers.h> #include "kstrtox.h" @@ -122,142 +123,145 @@ int skip_atoi(const char **s) return i; } -/* Decimal conversion is by far the most typical, and is used - * for /proc and /sys data. This directly impacts e.g. top performance - * with many processes running. We optimize it for speed - * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html> - * (with permission from the author, Douglas W. Jones). +/* + * Decimal conversion is by far the most typical, and is used for + * /proc and /sys data. This directly impacts e.g. top performance + * with many processes running. We optimize it for speed by emitting + * two characters at a time, using a 200 byte lookup table. This + * roughly halves the number of multiplications compared to computing + * the digits one at a time. Implementation strongly inspired by the + * previous version, which in turn used ideas described at + * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission + * from the author, Douglas W. Jones). + * + * It turns out there is precisely one 26 bit fixed-point + * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32 + * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual + * range happens to be somewhat larger (x <= 1073741898), but that's + * irrelevant for our purpose. + * + * For dividing a number in the range [10^4, 10^6-1] by 100, we still + * need a 32x32->64 bit multiply, so we simply use the same constant. + * + * For dividing a number in the range [100, 10^4-1] by 100, there are + * several options. The simplest is (x * 0x147b) >> 19, which is valid + * for all x <= 43698. */ -#if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 -/* Formats correctly any integer in [0, 999999999] */ +static const u16 decpair[100] = { +#define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030) + _( 0), _( 1), _( 2), _( 3), _( 4), _( 5), _( 6), _( 7), _( 8), _( 9), + _(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19), + _(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29), + _(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39), + _(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49), + _(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59), + _(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69), + _(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79), + _(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89), + _(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99), +#undef _ +}; + +/* + * This will print a single '0' even if r == 0, since we would + * immediately jump to out_r where two 0s would be written but only + * one of them accounted for in buf. This is needed by ip4_string + * below. All other callers pass a non-zero value of r. +*/ static noinline_for_stack -char *put_dec_full9(char *buf, unsigned q) +char *put_dec_trunc8(char *buf, unsigned r) { - unsigned r; + unsigned q; - /* - * Possible ways to approx. divide by 10 - * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit) - * (x * 0xcccd) >> 19 x < 81920 (x < 262149 when 64-bit mul) - * (x * 0x6667) >> 18 x < 43699 - * (x * 0x3334) >> 17 x < 16389 - * (x * 0x199a) >> 16 x < 16389 - * (x * 0x0ccd) >> 15 x < 16389 - * (x * 0x0667) >> 14 x < 2739 - * (x * 0x0334) >> 13 x < 1029 - * (x * 0x019a) >> 12 x < 1029 - * (x * 0x00cd) >> 11 x < 1029 shorter code than * 0x67 (on i386) - * (x * 0x0067) >> 10 x < 179 - * (x * 0x0034) >> 9 x < 69 same - * (x * 0x001a) >> 8 x < 69 same - * (x * 0x000d) >> 7 x < 69 same, shortest code (on i386) - * (x * 0x0007) >> 6 x < 19 - * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html> - */ - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 1 */ - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 2 */ - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 3 */ - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 4 */ - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 5 */ - /* Now value is under 10000, can avoid 64-bit multiply */ - q = (r * 0x199a) >> 16; - *buf++ = (r - 10 * q) + '0'; /* 6 */ - r = (q * 0xcd) >> 11; - *buf++ = (q - 10 * r) + '0'; /* 7 */ - q = (r * 0xcd) >> 11; - *buf++ = (r - 10 * q) + '0'; /* 8 */ - *buf++ = q + '0'; /* 9 */ + /* 1 <= r < 10^8 */ + if (r < 100) + goto out_r; + + /* 100 <= r < 10^8 */ + q = (r * (u64)0x28f5c29) >> 32; + *((u16 *)buf) = decpair[r - 100*q]; + buf += 2; + + /* 1 <= q < 10^6 */ + if (q < 100) + goto out_q; + + /* 100 <= q < 10^6 */ + r = (q * (u64)0x28f5c29) >> 32; + *((u16 *)buf) = decpair[q - 100*r]; + buf += 2; + + /* 1 <= r < 10^4 */ + if (r < 100) + goto out_r; + + /* 100 <= r < 10^4 */ + q = (r * 0x147b) >> 19; + *((u16 *)buf) = decpair[r - 100*q]; + buf += 2; +out_q: + /* 1 <= q < 100 */ + r = q; +out_r: + /* 1 <= r < 100 */ + *((u16 *)buf) = decpair[r]; + buf += r < 10 ? 1 : 2; return buf; } -#endif -/* Similar to above but do not pad with zeros. - * Code can be easily arranged to print 9 digits too, but our callers - * always call put_dec_full9() instead when the number has 9 decimal digits. - */ +#if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64 static noinline_for_stack -char *put_dec_trunc8(char *buf, unsigned r) +char *put_dec_full8(char *buf, unsigned r) { unsigned q; - /* Copy of previous function's body with added early returns */ - while (r >= 10000) { - q = r + '0'; - r = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = q - 10*r; - } + /* 0 <= r < 10^8 */ + q = (r * (u64)0x28f5c29) >> 32; + *((u16 *)buf) = decpair[r - 100*q]; + buf += 2; - q = (r * 0x199a) >> 16; /* r <= 9999 */ - *buf++ = (r - 10 * q) + '0'; - if (q == 0) - return buf; - r = (q * 0xcd) >> 11; /* q <= 999 */ - *buf++ = (q - 10 * r) + '0'; - if (r == 0) - return buf; - q = (r * 0xcd) >> 11; /* r <= 99 */ - *buf++ = (r - 10 * q) + '0'; - if (q == 0) - return buf; - *buf++ = q + '0'; /* q <= 9 */ - return buf; -} + /* 0 <= q < 10^6 */ + r = (q * (u64)0x28f5c29) >> 32; + *((u16 *)buf) = decpair[q - 100*r]; + buf += 2; -/* There are two algorithms to print larger numbers. - * One is generic: divide by 1000000000 and repeatedly print - * groups of (up to) 9 digits. It's conceptually simple, - * but requires a (unsigned long long) / 1000000000 division. - * - * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, - * manipulates them cleverly and generates groups of 4 decimal digits. - * It so happens that it does NOT require long long division. - * - * If long is > 32 bits, division of 64-bit values is relatively easy, - * and we will use the first algorithm. - * If long long is > 64 bits (strange architecture with VERY large long long), - * second algorithm can't be used, and we again use the first one. - * - * Else (if long is 32 bits and long long is 64 bits) we use second one. - */ + /* 0 <= r < 10^4 */ + q = (r * 0x147b) >> 19; + *((u16 *)buf) = decpair[r - 100*q]; + buf += 2; -#if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 - -/* First algorithm: generic */ + /* 0 <= q < 100 */ + *((u16 *)buf) = decpair[q]; + buf += 2; + return buf; +} -static +static noinline_for_stack char *put_dec(char *buf, unsigned long long n) { - if (n >= 100*1000*1000) { - while (n >= 1000*1000*1000) - buf = put_dec_full9(buf, do_div(n, 1000*1000*1000)); - if (n >= 100*1000*1000) - return put_dec_full9(buf, n); - } + if (n >= 100*1000*1000) + buf = put_dec_full8(buf, do_div(n, 100*1000*1000)); + /* 1 <= n <= 1.6e11 */ + if (n >= 100*1000*1000) + buf = put_dec_full8(buf, do_div(n, 100*1000*1000)); + /* 1 <= n < 1e8 */ return put_dec_trunc8(buf, n); } -#else +#elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64 -/* Second algorithm: valid only for 64-bit long longs */ - -/* See comment in put_dec_full9 for choice of constants */ -static noinline_for_stack -void put_dec_full4(char *buf, unsigned q) +static void +put_dec_full4(char *buf, unsigned r) { - unsigned r; - r = (q * 0xccd) >> 15; - buf[0] = (q - 10 * r) + '0'; - q = (r * 0xcd) >> 11; - buf[1] = (r - 10 * q) + '0'; - r = (q * 0xcd) >> 11; - buf[2] = (q - 10 * r) + '0'; - buf[3] = r + '0'; + unsigned q; + + /* 0 <= r < 10^4 */ + q = (r * 0x147b) >> 19; + *((u16 *)buf) = decpair[r - 100*q]; + buf += 2; + /* 0 <= q < 100 */ + *((u16 *)buf) = decpair[q]; } /* @@ -265,9 +269,9 @@ void put_dec_full4(char *buf, unsigned q) * The approximation x/10000 == (x * 0x346DC5D7) >> 43 * holds for all x < 1,128,869,999. The largest value this * helper will ever be asked to convert is 1,125,520,955. - * (d1 in the put_dec code, assuming n is all-ones). + * (second call in the put_dec code, assuming n is all-ones). */ -static +static noinline_for_stack unsigned put_dec_helper4(char *buf, unsigned x) { uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; @@ -294,6 +298,8 @@ char *put_dec(char *buf, unsigned long long n) d2 = (h ) & 0xffff; d3 = (h >> 16); /* implicit "& 0xffff" */ + /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0 + = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */ q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); q = put_dec_helper4(buf, q); @@ -323,7 +329,8 @@ char *put_dec(char *buf, unsigned long long n) */ int num_to_str(char *buf, int size, unsigned long long num) { - char tmp[sizeof(num) * 3]; + /* put_dec requires 2-byte alignment of the buffer. */ + char tmp[sizeof(num) * 3] __aligned(2); int idx, len; /* put_dec() may work incorrectly for num = 0 (generate "", not "0") */ @@ -384,7 +391,8 @@ static noinline_for_stack char *number(char *buf, char *end, unsigned long long num, struct printf_spec spec) { - char tmp[3 * sizeof(num)]; + /* put_dec requires 2-byte alignment of the buffer. */ + char tmp[3 * sizeof(num)] __aligned(2); char sign; char locase; int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); @@ -944,7 +952,7 @@ char *ip4_string(char *p, const u8 *addr, const char *fmt) break; } for (i = 0; i < 4; i++) { - char temp[3]; /* hold each IP quad in reverse order */ + char temp[4] __aligned(2); /* hold each IP quad in reverse order */ int digits = put_dec_trunc8(temp, addr[index]) - temp; if (leading_zeros) { if (digits < 3) diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 631619b..3f874d2 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -13,12 +13,16 @@ CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \ --param asan-instrumentation-with-call-threshold=$(call_threshold)) ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),) + ifneq ($(CONFIG_COMPILE_TEST),y) $(warning Cannot use CONFIG_KASAN: \ -fsanitize=kernel-address is not supported by compiler) + endif else ifeq ($(CFLAGS_KASAN),) - $(warning CONFIG_KASAN: compiler does not support all options.\ - Trying minimal configuration) + ifneq ($(CONFIG_COMPILE_TEST),y) + $(warning CONFIG_KASAN: compiler does not support all options.\ + Trying minimal configuration) + endif CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) endif endif diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d124359..89b1df4 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -47,6 +47,8 @@ my $ignore_perl_version = 0; my $minimum_perl_version = 5.10.0; my $min_conf_desc_length = 4; my $spelling_file = "$D/spelling.txt"; +my $codespell = 0; +my $codespellfile = "/usr/local/share/codespell/dictionary.txt"; sub help { my ($exitcode) = @_; @@ -88,6 +90,9 @@ Options: file. It's your fault if there's no backup or git --ignore-perl-version override checking of perl version. expect runtime errors. + --codespell Use the codespell dictionary for spelling/typos + (default:/usr/local/share/codespell/dictionary.txt) + --codespellfile Use this codespell dictionary -h, --help, --version display this help and exit When FILE is - read standard input. @@ -146,6 +151,8 @@ GetOptions( 'ignore-perl-version!' => \$ignore_perl_version, 'debug=s' => \%debug, 'test-only=s' => \$tst_only, + 'codespell!' => \$codespell, + 'codespellfile=s' => \$codespellfile, 'h|help' => \$help, 'version' => \$help ) or help(1); @@ -316,6 +323,7 @@ our $Operators = qr{ our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; +our $BasicType; our $NonptrType; our $NonptrTypeMisordered; our $NonptrTypeWithAttr; @@ -436,6 +444,14 @@ foreach my $entry (@mode_permission_funcs) { $mode_perms_search .= $entry->[0]; } +our $mode_perms_world_writable = qr{ + S_IWUGO | + S_IWOTH | + S_IRWXUGO | + S_IALLUGO | + 0[0-7][0-7][2367] +}x; + our $allowed_asm_includes = qr{(?x: irq| memory| @@ -449,7 +465,6 @@ my $misspellings; my %spelling_fix; if (open(my $spelling, '<', $spelling_file)) { - my @spelling_list; while (<$spelling>) { my $line = $_; @@ -461,21 +476,50 @@ if (open(my $spelling, '<', $spelling_file)) { my ($suspect, $fix) = split(/\|\|/, $line); - push(@spelling_list, $suspect); $spelling_fix{$suspect} = $fix; } close($spelling); - $misspellings = join("|", @spelling_list); } else { warn "No typos will be found - file '$spelling_file': $!\n"; } +if ($codespell) { + if (open(my $spelling, '<', $codespellfile)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + next if ($line =~ m/, disabled/i); + + $line =~ s/,.*$//; + + my ($suspect, $fix) = split(/->/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); + } else { + warn "No codespell typos will be found - file '$codespellfile': $!\n"; + } +} + +$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; + sub build_types { my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)"; my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)"; $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; + $BasicType = qr{ + (?:$typeOtherOSTypedefs\b)| + (?:$typeTypedefs\b)| + (?:${all}\b) + }x; $NonptrType = qr{ (?:$Modifier\s+|const\s+)* (?: @@ -1646,7 +1690,7 @@ sub fix_inserted_deleted_lines { foreach my $old_line (@{$linesRef}) { my $save_line = 1; my $line = $old_line; #don't modify the array - if ($line =~ /^(?:\+\+\+\|\-\-\-)\s+\S+/) { #new filename + if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename $delta_offset = 0; } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk $range_last_linenr = $new_linenr; @@ -1854,6 +1898,7 @@ sub process { my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch + my $commit_log_long_line = 0; my $reported_maintainer_file = 0; my $non_utf8_charset = 0; @@ -2189,6 +2234,14 @@ sub process { "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); } +# Check for line lengths > 75 in commit log, warn once + if ($in_commit_log && !$commit_log_long_line && + length($line) > 75) { + WARN("COMMIT_LOG_LONG_LINE", + "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); + $commit_log_long_line = 1; + } + # Check for git id commit length and improperly formed commit descriptions if ($in_commit_log && $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i) { my $init_char = $1; @@ -2303,8 +2356,9 @@ sub process { } # Check for various typo / spelling mistakes - if (defined($misspellings) && ($in_commit_log || $line =~ /^\+/)) { - while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:$|[^a-z@])/gi) { + if (defined($misspellings) && + ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { + while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:\b|$|[^a-z@])/gi) { my $typo = $1; my $typo_fix = $spelling_fix{lc($typo)}; $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); @@ -2459,8 +2513,9 @@ sub process { #line length limit if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && $rawline !~ /^.\s*\*\s*\@$Ident\s/ && - !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ || - $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && + !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?$String\s*(?:|,|\)\s*;)\s*$/ || + $line =~ /^\+\s*$String\s*(?:\s*|,|\)\s*;)\s*$/ || + $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) && $length > $max_line_length) { WARN("LONG_LINE", @@ -2552,8 +2607,15 @@ sub process { } } - if ($line =~ /^\+.*(\w+\s*)?\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic|[,;:\?\(\{\}\[\<\>]|&&|\|\||\\$)/ && - (!defined($1) || $1 !~ /sizeof\s*/)) { +# check for space after cast like "(int) foo" or "(struct foo) bar" +# avoid checking a few false positives: +# "sizeof(<type>)" or "__alignof__(<type>)" +# function pointer declarations like "(*foo)(int) = bar;" +# structure definitions like "(struct foo) { 0 };" +# multiline macros that define functions +# known attributes or the __attribute__ keyword + if ($line =~ /^\+(.*)\(\s*$Type\s*\)([ \t]++)((?![={]|\\$|$Attribute|__attribute__))/ && + (!defined($1) || $1 !~ /\b(?:sizeof|__alignof__)\s*$/)) { if (CHK("SPACING", "No space is necessary after a cast\n" . $herecurr) && $fix) { @@ -3146,6 +3208,18 @@ sub process { $herecurr); } +# check for const <foo> const where <foo> is not a pointer or array type + if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { + my $found = $1; + if ($sline =~ /\bconst\s+\Q$found\E\s+const\b\s*\*/) { + WARN("CONST_CONST", + "'const $found const *' should probably be 'const $found * const'\n" . $herecurr); + } elsif ($sline !~ /\bconst\s+\Q$found\E\s+const\s+\w+\s*\[/) { + WARN("CONST_CONST", + "'const $found const' should probably be 'const $found'\n" . $herecurr); + } + } + # check for non-global char *foo[] = {"bar", ...} declarations. if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { WARN("STATIC_CONST_CHAR_ARRAY", @@ -3153,6 +3227,19 @@ sub process { $herecurr); } +# check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) + if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { + my $array = $1; + if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { + my $array_div = $1; + if (WARN("ARRAY_SIZE", + "Prefer ARRAY_SIZE($array)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; + } + } + } + # check for function declarations without arguments like "int foo()" if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { if (ERROR("FUNCTION_WITHOUT_ARGS", @@ -3309,6 +3396,14 @@ sub process { "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); } +# ENOSYS means "bad syscall nr" and nothing else. This will have a small +# number of false positives, but assembly files are not checked, so at +# least the arch entry code will not trigger this warning. + if ($line =~ /\bENOSYS\b/) { + WARN("ENOSYS", + "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); + } + # function brace can't be on same line, except for #defines of do while, # or if closed on same line if (($line=~/$Type\s*$Ident\(.*\).*\s*{/) and @@ -3565,7 +3660,7 @@ sub process { # Ignore operators passed as parameters. if ($op_type ne 'V' && - $ca =~ /\s$/ && $cc =~ /^\s*,/) { + $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) { # # Ignore comments # } elsif ($op =~ /^$;+$/) { @@ -3750,6 +3845,14 @@ sub process { $ok = 1; } + # for asm volatile statements + # ignore a colon with another + # colon immediately before or after + if (($op eq ':') && + ($ca =~ /:$/ || $cc =~ /^:/)) { + $ok = 1; + } + # messages are ERROR, but ?: are CHK if ($ok == 0) { my $msg_type = \&ERROR; @@ -3963,12 +4066,12 @@ sub process { } } -# Return of what appears to be an errno should normally be -'ve - if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { +# Return of what appears to be an errno should normally be negative + if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) { my $name = $1; if ($name ne 'EOF' && $name ne 'ERROR') { WARN("USE_NEGATIVE_ERRNO", - "return of an errno should typically be -ve (return -$1)\n" . $herecurr); + "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr); } } @@ -4178,7 +4281,8 @@ sub process { } } -#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line) +# warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes +# itself <asm/foo.h> (uses RAW line) if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) { my $file = "$1.h"; my $checkfile = "include/linux/$file"; @@ -4186,12 +4290,15 @@ sub process { $realfile ne $checkfile && $1 !~ /$allowed_asm_includes/) { - if ($realfile =~ m{^arch/}) { - CHK("ARCH_INCLUDE_LINUX", - "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); - } else { - WARN("INCLUDE_LINUX", - "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + my $asminclude = `grep -Ec "#include\\s+<asm/$file>" $root/$checkfile`; + if ($asminclude > 0) { + if ($realfile =~ m{^arch/}) { + CHK("ARCH_INCLUDE_LINUX", + "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } else { + WARN("INCLUDE_LINUX", + "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } } } } @@ -4700,6 +4807,16 @@ sub process { } } +# check for __read_mostly with const non-pointer (should just be const) + if ($line =~ /\b__read_mostly\b/ && + $line =~ /($Type)\s*$Ident/ && $1 !~ /\*\s*$/ && $1 =~ /\bconst\b/) { + if (ERROR("CONST_READ_MOSTLY", + "Invalid use of __read_mostly with const type\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+__read_mostly\b//; + } + } + # don't use __constant_<foo> functions outside of include/uapi/ if ($realfile !~ m@^include/uapi/@ && $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) { @@ -5261,6 +5378,7 @@ sub process { stacktrace_ops| sysfs_ops| tty_operations| + uart_ops| usb_mon_operations| wd_ops}x; if ($line !~ /\bconst\b/ && @@ -5318,8 +5436,8 @@ sub process { } } - if ($line =~ /debugfs_create_file.*S_IWUGO/ || - $line =~ /DEVICE_ATTR.*S_IWUGO/ ) { + if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || + $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { WARN("EXPORTED_WORLD_WRITABLE", "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); } diff --git a/scripts/spelling.txt b/scripts/spelling.txt index fc7fd52..bb8e4d0 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -825,6 +825,7 @@ retreived||retrieved retreive||retrieve retrive||retrieve retuned||returned +reudce||reduce reuest||request reuqest||request reutnred||returned diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 2952ba5..b974a69 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -948,15 +948,18 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, */ const char *tomoyo_get_exe(void) { + struct file *exe_file; + const char *cp; struct mm_struct *mm = current->mm; - const char *cp = NULL; if (!mm) return NULL; - down_read(&mm->mmap_sem); - if (mm->exe_file) - cp = tomoyo_realpath_from_path(&mm->exe_file->f_path); - up_read(&mm->mmap_sem); + exe_file = get_mm_exe_file(mm); + if (!exe_file) + return NULL; + + cp = tomoyo_realpath_from_path(&exe_file->f_path); + fput(exe_file); return cp; } diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 5a30fdd..e12764d 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/clk.h> +#include <linux/kernel.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -31,8 +32,6 @@ #define DIV_ROUND_DOWN_ULL(ll, d) \ ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) -#define DIV_ROUND_CLOSEST_ULL(ll, d) \ - ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) #define PCM512x_NUM_SUPPLIES 3 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { |