diff --git a/arch/arm/configs/msm8909-y560_defconfig b/arch/arm/configs/msm8909-y560_defconfig index f5c5e7ad9f89..25fe0fed93f8 100644 --- a/arch/arm/configs/msm8909-y560_defconfig +++ b/arch/arm/configs/msm8909-y560_defconfig @@ -32,7 +32,7 @@ CONFIG_BUILDTIME_EXTABLE_SORT=y # CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_CROSS_COMPILE="" -CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION="-Vanilla" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y @@ -1310,7 +1310,6 @@ CONFIG_SCSI_MOD=y # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_DMA=y -CONFIG_SCSI_TGT=y # CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y @@ -1321,12 +1320,8 @@ CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set # CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set -CONFIG_CHR_DEV_SG=y -CONFIG_CHR_DEV_SCH=y CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_LOWLEVEL is not set # # SCSI Transports diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 20e1c994669e..5705ac7df197 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -100,6 +100,8 @@ static inline void set_fs(mm_segment_t fs) extern int __get_user_1(void *); extern int __get_user_2(void *); extern int __get_user_4(void *); +extern int __get_user_lo8(void *); +extern int __get_user_8(void *); #define __GUP_CLOBBER_1 "lr", "cc" #ifdef CONFIG_CPU_USE_DOMAINS @@ -108,6 +110,8 @@ extern int __get_user_4(void *); #define __GUP_CLOBBER_2 "lr", "cc" #endif #define __GUP_CLOBBER_4 "lr", "cc" +#define __GUP_CLOBBER_lo8 "lr", "cc" +#define __GUP_CLOBBER_8 "lr", "cc" #define __get_user_x(__r2,__p,__e,__l,__s) \ __asm__ __volatile__ ( \ @@ -118,11 +122,19 @@ extern int __get_user_4(void *); : "0" (__p), "r" (__l) \ : __GUP_CLOBBER_##__s) +/* narrowing a double-word get into a single 32bit word register: */ +#ifdef __ARMEB__ +#define __get_user_xb(__r2, __p, __e, __l, __s) \ + __get_user_x(__r2, __p, __e, __l, lo8) +#else +#define __get_user_xb __get_user_x +#endif + #define __get_user_check(x,p) \ ({ \ unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ - register unsigned long __r2 asm("r2"); \ + register typeof(x) __r2 asm("r2"); \ register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ @@ -135,6 +147,12 @@ extern int __get_user_4(void *); case 4: \ __get_user_x(__r2, __p, __e, __l, 4); \ break; \ + case 8: \ + if (sizeof((x)) < 8) \ + __get_user_xb(__r2, __p, __e, __l, 4); \ + else \ + __get_user_x(__r2, __p, __e, __l, 8); \ + break; \ default: __e = __get_user_bad(); break; \ } \ x = (typeof(*(p))) __r2; \ diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 9b06bb41fca6..82b024a13051 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -18,7 +18,7 @@ * Inputs: r0 contains the address * r1 contains the address limit, which must be preserved * Outputs: r0 is the error code - * r2 contains the zero-extended value + * r2, r3 contains the zero-extended value * lr corrupted * * No other registers must be altered. (see @@ -66,15 +66,50 @@ ENTRY(__get_user_4) mov pc, lr ENDPROC(__get_user_4) +ENTRY(__get_user_8) + check_uaccess r0, 8, r1, r2, __get_user_bad +#ifdef CONFIG_THUMB2_KERNEL +5: TUSER(ldr) r2, [r0] +6: TUSER(ldr) r3, [r0, #4] +#else +5: TUSER(ldr) r2, [r0], #4 +6: TUSER(ldr) r3, [r0] +#endif + mov r0, #0 + mov pc, lr +ENDPROC(__get_user_8) + +#ifdef __ARMEB__ +ENTRY(__get_user_lo8) + check_uaccess r0, 8, r1, r2, __get_user_bad +#ifdef CONFIG_CPU_USE_DOMAINS + add r0, r0, #4 +7: ldrt r2, [r0] +#else +7: ldr r2, [r0, #4] +#endif + mov r0, #0 + mov pc, lr +ENDPROC(__get_user_lo8) +#endif + +__get_user_bad8: + mov r3, #0 __get_user_bad: mov r2, #0 mov r0, #-EFAULT mov pc, lr ENDPROC(__get_user_bad) +ENDPROC(__get_user_bad8) .pushsection __ex_table, "a" .long 1b, __get_user_bad .long 2b, __get_user_bad .long 3b, __get_user_bad .long 4b, __get_user_bad + .long 5b, __get_user_bad8 + .long 6b, __get_user_bad8 +#ifdef __ARMEB__ + .long 7b, __get_user_bad +#endif .popsection diff --git a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c index 45e74363aaa9..84bfd0573494 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c +++ b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c @@ -69,16 +69,16 @@ static int osiris_dvs_notify(struct notifier_block *nb, switch (val) { case CPUFREQ_PRECHANGE: - if (old_dvs & !new_dvs || - cur_dvs & !new_dvs) { + if ((old_dvs && !new_dvs) || + (cur_dvs && !new_dvs)) { pr_debug("%s: exiting dvs\n", __func__); cur_dvs = false; gpio_set_value(OSIRIS_GPIO_DVS, 1); } break; case CPUFREQ_POSTCHANGE: - if (!old_dvs & new_dvs || - !cur_dvs & new_dvs) { + if ((!old_dvs && new_dvs) || + (!cur_dvs && new_dvs)) { pr_debug("entering dvs\n"); cur_dvs = true; gpio_set_value(OSIRIS_GPIO_DVS, 0); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b86e85b6f2c8..27a07852b9bb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -60,7 +60,6 @@ config ARM64 select PERF_USE_VMALLOC select POWER_RESET select POWER_SUPPLY - select RTC_LIB select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE select MSM_JTAGV8 if CORESIGHT_ETMV4 diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 22b45a4955cd..db5575c69792 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -757,6 +757,9 @@ fast_exception_return: mtcr r10 lwz r10,_LINK(r11) mtlr r10 + /* Clear the exception_marker on the stack to avoid confusing stacktrace */ + li r10, 0 + stw r10, 8(r11) REST_GPR(10, r11) mtspr SPRN_SRR1,r9 mtspr SPRN_SRR0,r12 @@ -987,6 +990,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX) mtcrf 0xFF,r10 mtlr r11 + /* Clear the exception_marker on the stack to avoid confusing stacktrace */ + li r10, 0 + stw r10, 8(r1) /* * Once we put values in SRR0 and SRR1, we are in a state * where exceptions are not recoverable, since taking an @@ -1024,6 +1030,9 @@ exc_exit_restart_end: mtlr r11 lwz r10,_CCR(r1) mtcrf 0xff,r10 + /* Clear the exception_marker on the stack to avoid confusing stacktrace */ + li r10, 0 + stw r10, 8(r1) REST_2GPRS(9, r1) .globl exc_exit_restart exc_exit_restart: diff --git a/arch/powerpc/platforms/83xx/suspend-asm.S b/arch/powerpc/platforms/83xx/suspend-asm.S index 3d1ecd211776..8137f77abad5 100644 --- a/arch/powerpc/platforms/83xx/suspend-asm.S +++ b/arch/powerpc/platforms/83xx/suspend-asm.S @@ -26,13 +26,13 @@ #define SS_MSR 0x74 #define SS_SDR1 0x78 #define SS_LR 0x7c -#define SS_SPRG 0x80 /* 4 SPRGs */ -#define SS_DBAT 0x90 /* 8 DBATs */ -#define SS_IBAT 0xd0 /* 8 IBATs */ -#define SS_TB 0x110 -#define SS_CR 0x118 -#define SS_GPREG 0x11c /* r12-r31 */ -#define STATE_SAVE_SIZE 0x16c +#define SS_SPRG 0x80 /* 8 SPRGs */ +#define SS_DBAT 0xa0 /* 8 DBATs */ +#define SS_IBAT 0xe0 /* 8 IBATs */ +#define SS_TB 0x120 +#define SS_CR 0x128 +#define SS_GPREG 0x12c /* r12-r31 */ +#define STATE_SAVE_SIZE 0x17c .section .data .align 5 @@ -103,6 +103,16 @@ _GLOBAL(mpc83xx_enter_deep_sleep) stw r7, SS_SPRG+12(r3) stw r8, SS_SDR1(r3) + mfspr r4, SPRN_SPRG4 + mfspr r5, SPRN_SPRG5 + mfspr r6, SPRN_SPRG6 + mfspr r7, SPRN_SPRG7 + + stw r4, SS_SPRG+16(r3) + stw r5, SS_SPRG+20(r3) + stw r6, SS_SPRG+24(r3) + stw r7, SS_SPRG+28(r3) + mfspr r4, SPRN_DBAT0U mfspr r5, SPRN_DBAT0L mfspr r6, SPRN_DBAT1U @@ -493,6 +503,16 @@ mpc83xx_deep_resume: mtspr SPRN_IBAT7U, r6 mtspr SPRN_IBAT7L, r7 + lwz r4, SS_SPRG+16(r3) + lwz r5, SS_SPRG+20(r3) + lwz r6, SS_SPRG+24(r3) + lwz r7, SS_SPRG+28(r3) + + mtspr SPRN_SPRG4, r4 + mtspr SPRN_SPRG5, r5 + mtspr SPRN_SPRG6, r6 + mtspr SPRN_SPRG7, r7 + lwz r4, SS_SPRG+0(r3) lwz r5, SS_SPRG+4(r3) lwz r6, SS_SPRG+8(r3) diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c index 6d8dadf19f0b..545affadae05 100644 --- a/arch/powerpc/platforms/embedded6xx/wii.c +++ b/arch/powerpc/platforms/embedded6xx/wii.c @@ -104,6 +104,10 @@ unsigned long __init wii_mmu_mapin_mem2(unsigned long top) /* MEM2 64MB@0x10000000 */ delta = wii_hole_start + wii_hole_size; size = top - delta; + + if (__map_without_bats) + return delta; + for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > size) break; diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index 2cd89be6bb4a..288ed9a810fb 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -89,8 +89,8 @@ static unsigned long mmap_base(unsigned long rnd) gap = MIN_GAP; else if (gap > MAX_GAP) gap = MAX_GAP; - - return PAGE_ALIGN(TASK_SIZE - gap - rnd); + + return PAGE_ALIGN(TASK_SIZE - gap - mmap_rnd()); } /* @@ -110,7 +110,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) mm->mmap_base = mm->mmap_legacy_base; mm->get_unmapped_area = arch_get_unmapped_area; } else { - mm->mmap_base = mmap_base(random_factor); + mm->mmap_base = mmap_base(); mm->get_unmapped_area = arch_get_unmapped_area_topdown; } } diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 2e58ebb1f6c0..6686053b66b1 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o +obj-$(CONFIG_BOEFFLA_WL_BLOCKER) += boeffla_wl_blocker.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/power/boeffla_wl_blocker.c b/drivers/base/power/boeffla_wl_blocker.c new file mode 100644 index 000000000000..e9c93ce97ce9 --- /dev/null +++ b/drivers/base/power/boeffla_wl_blocker.c @@ -0,0 +1,236 @@ +/* + * Author: andip71, 01.09.2017 + * + * Version 1.1.0 + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Change log: + * + * 1.1.0 (01.09.2017) + * - By default, the following wakelocks are blocked in an own list + * qcom_rx_wakelock, wlan, wlan_wow_wl, wlan_extscan_wl, NETLINK + * + * 1.0.1 (29.08.2017) + * - Add killing wakelock when currently active + * + * 1.0.0 (28.08.2017) + * - Initial version + * + */ + +#include +#include +#include +#include +#include +#include +#include "boeffla_wl_blocker.h" + + +/*****************************************/ +// Variables +/*****************************************/ + +char list_wl[LENGTH_LIST_WL] = {0}; +char list_wl_default[LENGTH_LIST_WL_DEFAULT] = {0}; + +extern char list_wl_search[LENGTH_LIST_WL_SEARCH]; +extern bool wl_blocker_active; +extern bool wl_blocker_debug; + + +/*****************************************/ +// internal functions +/*****************************************/ + +static void build_search_string(char *list1, char *list2) +{ + // store wakelock list and search string (with semicolons added at start and end) + sprintf(list_wl_search, ";%s;%s;", list1, list2); + + // set flag if wakelock blocker should be active (for performance reasons) + if (strlen(list_wl_search) > 5) + wl_blocker_active = true; + else + wl_blocker_active = false; +} + + +/*****************************************/ +// sysfs interface functions +/*****************************************/ + +// show list of user configured wakelocks +static ssize_t wakelock_blocker_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // return list of wakelocks to be blocked + return sprintf(buf, "%s\n", list_wl); +} + + +// store list of user configured wakelocks +static ssize_t wakelock_blocker_store(struct device * dev, struct device_attribute *attr, + const char * buf, size_t n) +{ + int len = n; + + // check if string is too long to be stored + if (len > LENGTH_LIST_WL) + return -EINVAL; + + // store user configured wakelock list and rebuild search string + sscanf(buf, "%s", list_wl); + build_search_string(list_wl_default, list_wl); + + return n; +} + + +// show list of default, predefined wakelocks +static ssize_t wakelock_blocker_default_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // return list of wakelocks to be blocked + return sprintf(buf, "%s\n", list_wl_default); +} + + +// store list of default, predefined wakelocks +static ssize_t wakelock_blocker_default_store(struct device * dev, struct device_attribute *attr, + const char * buf, size_t n) +{ + int len = n; + + // check if string is too long to be stored + if (len > LENGTH_LIST_WL_DEFAULT) + return -EINVAL; + + // store default, predefined wakelock list and rebuild search string + sscanf(buf, "%s", list_wl_default); + build_search_string(list_wl_default, list_wl); + + return n; +} + + +// show debug information of driver internals +static ssize_t debug_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // return current debug status + return sprintf(buf, "Debug status: %d\n\nUser list: %s\nDefault list: %s\nSearch list: %s\nActive: %d\n", + wl_blocker_debug, list_wl, list_wl_default, list_wl_search, wl_blocker_active); +} + + +// store debug mode on/off (1/0) +static ssize_t debug_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int ret = -EINVAL; + unsigned int val; + + // check data and store if valid + ret = sscanf(buf, "%d", &val); + + if (ret != 1) + return -EINVAL; + + if (val == 1) + wl_blocker_debug = true; + else + wl_blocker_debug = false; + + return count; +} + + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // return version information + return sprintf(buf, "%s\n", BOEFFLA_WL_BLOCKER_VERSION); +} + + + +/*****************************************/ +// Initialize sysfs objects +/*****************************************/ + +// define objects +static DEVICE_ATTR(wakelock_blocker, 0644, wakelock_blocker_show, wakelock_blocker_store); +static DEVICE_ATTR(wakelock_blocker_default, 0644, wakelock_blocker_default_show, wakelock_blocker_default_store); +static DEVICE_ATTR(debug, 0664, debug_show, debug_store); +static DEVICE_ATTR(version, 0664, version_show, NULL); + +// define attributes +static struct attribute *boeffla_wl_blocker_attributes[] = { + &dev_attr_wakelock_blocker.attr, + &dev_attr_wakelock_blocker_default.attr, + &dev_attr_debug.attr, + &dev_attr_version.attr, + NULL +}; + +// define attribute group +static struct attribute_group boeffla_wl_blocker_control_group = { + .attrs = boeffla_wl_blocker_attributes, +}; + +// define control device +static struct miscdevice boeffla_wl_blocker_control_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "boeffla_wakelock_blocker", +}; + + +/*****************************************/ +// Driver init and exit functions +/*****************************************/ + +static int boeffla_wl_blocker_init(void) +{ + // register boeffla wakelock blocker control device + misc_register(&boeffla_wl_blocker_control_device); + if (sysfs_create_group(&boeffla_wl_blocker_control_device.this_device->kobj, + &boeffla_wl_blocker_control_group) < 0) { + printk("Boeffla WL blocker: failed to create sys fs object.\n"); + return 0; + } + + // initialize default list + sprintf(list_wl_default, "%s", LIST_WL_DEFAULT); + build_search_string(list_wl_default, list_wl); + + // Print debug info + printk("Boeffla WL blocker: driver version %s started\n", BOEFFLA_WL_BLOCKER_VERSION); + + return 0; +} + + +static void boeffla_wl_blocker_exit(void) +{ + // remove boeffla wakelock blocker control device + sysfs_remove_group(&boeffla_wl_blocker_control_device.this_device->kobj, + &boeffla_wl_blocker_control_group); + + // Print debug info + printk("Boeffla WL blocker: driver stopped\n"); +} + + +/* define driver entry points */ +module_init(boeffla_wl_blocker_init); +module_exit(boeffla_wl_blocker_exit); diff --git a/drivers/base/power/boeffla_wl_blocker.h b/drivers/base/power/boeffla_wl_blocker.h new file mode 100644 index 000000000000..8e1eb59d17d2 --- /dev/null +++ b/drivers/base/power/boeffla_wl_blocker.h @@ -0,0 +1,23 @@ +/* + * Author: andip71, 01.09.2017 + * + * Version 1.1.0 + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define BOEFFLA_WL_BLOCKER_VERSION "1.1.0" + +#define LIST_WL_DEFAULT "qcom_rx_wakelock;wlan;wlan_wow_wl;wlan_extscan_wl;netmgr_wl;NETLINK;wcnss_filter_lock;wlan_ipa;wlan_pno_wl;IPA_WS;[timerfd];wlan_rx_wake;wlan_wake;wlan_ctrl_wake;NETLINK;wlan_txfl_wake;bluetooth_timer;BT_bt_wake;BT_host_wake" + +#define LENGTH_LIST_WL 255 +#define LENGTH_LIST_WL_DEFAULT 100 +#define LENGTH_LIST_WL_SEARCH LENGTH_LIST_WL + LENGTH_LIST_WL_DEFAULT + 5 diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 22d0499e4b22..d7cbe83ed3a4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -594,6 +594,10 @@ static void dpm_resume_early(pm_message_t state) { ktime_t starttime = ktime_get(); +#ifdef CONFIG_BOEFFLA_WL_BLOCKER + pm_print_active_wakeup_sources(); +#endif + mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_late_early_list)) { struct device *dev = to_device(dpm_late_early_list.next); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 79715e7fa43e..6f16c98b820d 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -18,6 +18,16 @@ #include "power.h" +#ifdef CONFIG_BOEFFLA_WL_BLOCKER +#include "boeffla_wl_blocker.h" + +char list_wl_search[LENGTH_LIST_WL_SEARCH] = {0}; +bool wl_blocker_active = false; +bool wl_blocker_debug = false; + +static void wakeup_source_deactivate(struct wakeup_source *ws); +#endif + /* * If set, the suspend/hibernate code will abort transitions to a sleep state * if wakeup events are registered during or immediately before the transition. @@ -121,6 +131,15 @@ void wakeup_source_destroy(struct wakeup_source *ws) } EXPORT_SYMBOL_GPL(wakeup_source_destroy); +/** + * wakeup_source_destroy_cb + * defer processing until all rcu references have expired + */ +static void wakeup_source_destroy_cb(struct rcu_head *head) +{ + wakeup_source_destroy(container_of(head, struct wakeup_source, rcu)); +} + /** * wakeup_source_add - Add given object to the list of wakeup sources. * @ws: Wakeup source object to add to the list. @@ -161,6 +180,26 @@ void wakeup_source_remove(struct wakeup_source *ws) } EXPORT_SYMBOL_GPL(wakeup_source_remove); +/** + * wakeup_source_remove_async - Remove given object from the wakeup sources + * list. + * @ws: Wakeup source object to remove from the list. + * + * Use only for wakeup source objects created with wakeup_source_create(). + * Memory for ws must be freed via rcu. + */ +static void wakeup_source_remove_async(struct wakeup_source *ws) +{ + unsigned long flags; + + if (WARN_ON(!ws)) + return; + + spin_lock_irqsave(&events_lock, flags); + list_del_rcu(&ws->entry); + spin_unlock_irqrestore(&events_lock, flags); +} + /** * wakeup_source_register - Create wakeup source and add it to the list. * @name: Name of the wakeup source to register. @@ -184,8 +223,8 @@ EXPORT_SYMBOL_GPL(wakeup_source_register); void wakeup_source_unregister(struct wakeup_source *ws) { if (ws) { - wakeup_source_remove(ws); - wakeup_source_destroy(ws); + wakeup_source_remove_async(ws); + call_rcu(&ws->rcu, wakeup_source_destroy_cb); } } EXPORT_SYMBOL_GPL(wakeup_source_unregister); @@ -400,19 +439,77 @@ static void wakeup_source_activate(struct wakeup_source *ws) trace_wakeup_source_activate(ws->name, cec); } +#ifdef CONFIG_BOEFFLA_WL_BLOCKER +// AP: Function to check if a wakelock is on the wakelock blocker list +static bool check_for_block(struct wakeup_source *ws) +{ + char wakelock_name[52] = {0}; + int length; + + // if debug mode on, print every wakelock requested + if (wl_blocker_debug) + printk("Boeffla WL blocker: %s requested\n", ws->name); + + // if there is no list of wakelocks to be blocked, exit without futher checking + if (!wl_blocker_active) + return false; + + // only if ws structure is valid + if (ws) + { + // wake lock names handled have maximum length=50 and minimum=1 + length = strlen(ws->name); + if ((length > 50) || (length < 1)) + return false; + + // check if wakelock is in wake lock list to be blocked + sprintf(wakelock_name, ";%s;", ws->name); + + if(strstr(list_wl_search, wakelock_name) == NULL) + return false; + + // wake lock is in list, print it if debug mode on + if (wl_blocker_debug) + printk("Boeffla WL blocker: %s blocked\n", ws->name); + + // if it is currently active, deactivate it immediately + log in debug mode + if (ws->active) + { + wakeup_source_deactivate(ws); + + if (wl_blocker_debug) + printk("Boeffla WL blocker: %s killed\n", ws->name); + } + + // finally block it + return true; + } + + // there was no valid ws structure, do not block by default + return false; +} +#endif + /** * wakeup_source_report_event - Report wakeup event using the given source. * @ws: Wakeup source to report the event for. */ static void wakeup_source_report_event(struct wakeup_source *ws) { - ws->event_count++; - /* This is racy, but the counter is approximate anyway. */ - if (events_check_enabled) - ws->wakeup_count++; - - if (!ws->active) - wakeup_source_activate(ws); +#ifdef CONFIG_BOEFFLA_WL_BLOCKER + if (!check_for_block(ws)) // AP: check if wakelock is on wakelock blocker list + { +#endif + ws->event_count++; + /* This is racy, but the counter is approximate anyway. */ + if (events_check_enabled) + ws->wakeup_count++; + + if (!ws->active) + wakeup_source_activate(ws); +#ifdef CONFIG_BOEFFLA_WL_BLOCKER + } +#endif } /** @@ -669,7 +766,10 @@ static void print_active_wakeup_sources(void) list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active) { pr_info("active wakeup source: %s\n", ws->name); - active = 1; +#ifdef CONFIG_BOEFFLA_WL_BLOCKER + if (!check_for_block(ws)) // AP: check if wakelock is on wakelock blocker list +#endif + active = 1; } else if (!active && (!last_activity_ws || ktime_to_ns(ws->last_time) > diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 9999ff5cd838..9d3ab5b4e80e 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -718,7 +718,8 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx) pgstart->size = obuf->size; for (i = 0; i < inbufs + outbufs; ++i) { void *buf; - int len, num; + int num; + ssize_t len; list[i].num = 0; list[i].pgidx = 0; diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 09914b971138..22ff4e8a760a 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1782,6 +1782,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_hash_final(&qcedev_areq, handle); if (err) return err; + + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + return -EINVAL; + } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], @@ -1813,6 +1819,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_hash_final(&qcedev_areq, handle); if (err) return err; + + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + return -EINVAL; + } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e1d0233ab027..9580325993d0 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2619,9 +2619,9 @@ long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, /* Commit the pointer to the context in context_idr */ write_lock(&device->context_lock); idr_replace(&device->context_idr, context, context->id); + param->drawctxt_id = context->id; write_unlock(&device->context_lock); - param->drawctxt_id = context->id; done: mutex_unlock(&device->mutex); return result; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 9aa1b60f7fdd..168e9adc3735 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -669,6 +669,12 @@ static const struct i2c_algorithm tegra_i2c_algo = { .functionality = tegra_i2c_func, }; +/* payload size is only 12 bit */ +static struct i2c_adapter_quirks tegra_i2c_quirks = { + .max_read_len = 4096, + .max_write_len = 4096 - 12, +}; + static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_continue_xfer_support = false, .has_per_pkt_xfer_complete_irq = false, @@ -740,6 +746,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->base = base; i2c_dev->div_clk = div_clk; i2c_dev->adapter.algo = &tegra_i2c_algo; + i2c_dev->adapter.quirks = &tegra_i2c_quirks; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b4de9c3e5ca4..eb89dc691e58 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3805,6 +3805,8 @@ static int run(struct mddev *mddev) set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); mddev->sync_thread = md_register_thread(md_do_sync, mddev, "reshape"); + if (!mddev->sync_thread) + goto out_free_conf; } return 0; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index c0d6d9c7a26e..8cf4ffce2b31 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5570,6 +5570,8 @@ static int run(struct mddev *mddev) set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); mddev->sync_thread = md_register_thread(md_do_sync, mddev, "reshape"); + if (!mddev->sync_thread) + goto abort; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0eb2334fd27d..b8d572200250 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -69,8 +69,8 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; * performance cost, and for other reasons may not always be desired. * So we allow it it to be disabled. */ -bool use_spi_crc = 1; -module_param(use_spi_crc, bool, 0); +bool use_spi_crc = 0; +module_param(use_spi_crc, bool, 0644); /* * We normally treat cards as removed during suspend if they are not diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c index 88ccc8b14f0a..f587cfe25006 100644 --- a/drivers/net/ethernet/8390/mac8390.c +++ b/drivers/net/ethernet/8390/mac8390.c @@ -156,8 +156,6 @@ static void dayna_block_output(struct net_device *dev, int count, #define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c)) #define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c)) -#define memcmp_withio(a, b, c) memcmp((a), (void *)(b), (c)) - /* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */ static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -243,19 +241,26 @@ static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) static enum mac8390_access __init mac8390_testio(volatile unsigned long membase) { - unsigned long outdata = 0xA5A0B5B0; - unsigned long indata = 0x00000000; + u32 outdata = 0xA5A0B5B0; + u32 indata = 0; + /* Try writing 32 bits */ - memcpy_toio(membase, &outdata, 4); - /* Now compare them */ - if (memcmp_withio(&outdata, membase, 4) == 0) + nubus_writel(outdata, membase); + /* Now read it back */ + indata = nubus_readl(membase); + if (outdata == indata) return ACCESS_32; + + outdata = 0xC5C0D5D0; + indata = 0; + /* Write 16 bit output */ word_memcpy_tocard(membase, &outdata, 4); /* Now read it back */ word_memcpy_fromcard(&indata, membase, 4); if (outdata == indata) return ACCESS_16; + return ACCESS_UNKNOWN; } diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index b0a0d5389f41..3f5a30cc6e75 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1377,7 +1377,7 @@ static struct superio_struct *find_superio(struct parport *p) { int i; for (i = 0; i < NR_SUPERIOS; i++) - if (superios[i].io != p->base) + if (superios[i].io == p->base) return &superios[i]; return NULL; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2cb295f02e0b..3480c4f0d119 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -984,7 +984,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) result = get_user(val, ip); if (result) return result; - if (val > SG_MAX_CDB_SIZE) + if (val > MAX_COMMAND_SIZE) return -ENOMEM; sfp->next_cmd_len = (val > 0) ? val : 0; return 0; diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 94a9cc8ff77e..bd06a787931e 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -704,10 +704,12 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case ASHMEM_SET_SIZE: ret = -EINVAL; + mutex_lock(&ashmem_mutex); if (!asma->file) { ret = 0; asma->size = (size_t) arg; } + mutex_unlock(&ashmem_mutex); break; case ASHMEM_GET_SIZE: ret = asma->size; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index e94674f0b9f6..6ace1f48dee3 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -982,21 +982,28 @@ VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCa #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) { - struct station_info staInfo; v_U16_t iesLen = pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.iesLen; - memset(&staInfo, 0, sizeof(staInfo)); if (iesLen <= MAX_ASSOC_IND_IE_LEN ) { - staInfo.assoc_req_ies = + struct station_info *stainfo; + stainfo = vos_mem_malloc(sizeof(*stainfo)); + if (stainfo == NULL) { + hddLog(LOGE, FL("alloc station_info failed")); + return VOS_STATUS_E_NOMEM; + } + memset(stainfo, 0, sizeof(*stainfo)); + + stainfo->assoc_req_ies = (const u8 *)&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.ies[0]; - staInfo.assoc_req_ies_len = iesLen; + stainfo->assoc_req_ies_len = iesLen; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,31)) - staInfo.filled |= STATION_INFO_ASSOC_REQ_IES; + stainfo->filled |= STATION_INFO_ASSOC_REQ_IES; #endif cfg80211_new_sta(dev, (const u8 *)&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staMac.bytes[0], - &staInfo, GFP_KERNEL); + stainfo, GFP_KERNEL); + vos_mem_free(stainfo); } else { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 40d9a1a90d0b..829e1657e599 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -3565,8 +3565,15 @@ static int iw_softap_set_channel_range( struct net_device *dev, tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + if (!capable(CAP_NET_ADMIN)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("permission check failed")); + return -EPERM; + } status = WLANSAP_SetChannelRange(hHal, startChannel, endChannel, band); + if (VOS_STATUS_SUCCESS != status) { ret = -EINVAL; diff --git a/fs/Kconfig b/fs/Kconfig index 3b5e7c5be37e..e63baf068cb2 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -273,4 +273,10 @@ endif # NETWORK_FILESYSTEMS source "fs/nls/Kconfig" source "fs/dlm/Kconfig" +config DYNAMIC_FSYNC + bool "dynamic file sync control" + default n + help + An experimental file sync control using Android's early suspend / late resume drivers + endmenu diff --git a/fs/Makefile b/fs/Makefile index 7594e22a39d4..f596f3189020 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -127,6 +127,7 @@ obj-y += exofs/ # Multiple modules obj-$(CONFIG_CEPH_FS) += ceph/ obj-$(CONFIG_PSTORE) += pstore/ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ +obj-$(CONFIG_DYNAMIC_FSYNC) += dyn_sync_cntrl.o # Patched by YAFFS obj-$(CONFIG_YAFFS_FS) += yaffs2/ diff --git a/fs/dyn_sync_cntrl.c b/fs/dyn_sync_cntrl.c new file mode 100644 index 000000000000..b5c54284ca99 --- /dev/null +++ b/fs/dyn_sync_cntrl.c @@ -0,0 +1,202 @@ +/* + * Author: Paul Reioux aka Faux123 + * + * Copyright 2013 Paul Reioux + * Copyright 2012 Paul Reioux + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DYN_FSYNC_VERSION_MAJOR 2 +#define DYN_FSYNC_VERSION_MINOR 0 + +static DEFINE_MUTEX(fsync_mutex); + +bool power_suspend_active __read_mostly = false; +bool dyn_fsync_active __read_mostly = true; + +static ssize_t dyn_fsync_active_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", (dyn_fsync_active ? 1 : 0)); +} + +static ssize_t dyn_fsync_active_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int data; + + if(sscanf(buf, "%u\n", &data) == 1) { + if (data == 1) { + pr_info("%s: dynamic fsync enabled\n", __FUNCTION__); + dyn_fsync_active = true; + } + else if (data == 0) { + pr_info("%s: dyanamic fsync disabled\n", __FUNCTION__); + dyn_fsync_active = false; + } + else + pr_info("%s: bad value: %u\n", __FUNCTION__, data); + } else + pr_info("%s: unknown input!\n", __FUNCTION__); + + return count; +} + +static ssize_t dyn_fsync_version_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "version: %u.%u\n", + DYN_FSYNC_VERSION_MAJOR, + DYN_FSYNC_VERSION_MINOR); +} + +static ssize_t dyn_fsync_powersuspend_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "power suspend active: %u\n", power_suspend_active); +} + +static struct kobj_attribute dyn_fsync_active_attribute = + __ATTR(Dyn_fsync_active, 0666, + dyn_fsync_active_show, + dyn_fsync_active_store); + +static struct kobj_attribute dyn_fsync_version_attribute = + __ATTR(Dyn_fsync_version, 0444, dyn_fsync_version_show, NULL); + +static struct kobj_attribute dyn_fsync_powersuspend_attribute = + __ATTR(Dyn_fsync_powersuspend, 0444, dyn_fsync_powersuspend_show, NULL); + +static struct attribute *dyn_fsync_active_attrs[] = + { + &dyn_fsync_active_attribute.attr, + &dyn_fsync_version_attribute.attr, + &dyn_fsync_powersuspend_attribute.attr, + NULL, + }; + +static struct attribute_group dyn_fsync_active_attr_group = + { + .attrs = dyn_fsync_active_attrs, + }; + +static struct kobject *dyn_fsync_kobj; + +static void dyn_fsync_force_flush(void) +{ + /* flush all outstanding buffers */ + wakeup_flusher_threads(0, WB_REASON_SYNC); + sync_filesystems(0); + sync_filesystems(1); +} + +static void dyn_fsync_power_suspend(struct power_suspend *h) +{ + mutex_lock(&fsync_mutex); + if (dyn_fsync_active) { + power_suspend_active = true; + dyn_fsync_force_flush(); + } + mutex_unlock(&fsync_mutex); +} + +static void dyn_fsync_resume(struct power_suspend *h) +{ + mutex_lock(&fsync_mutex); + power_suspend_active = false; + mutex_unlock(&fsync_mutex); +} + +static struct power_suspend dyn_fsync_power_suspend_handler = + { + .suspend = dyn_fsync_power_suspend, + .resume = dyn_fsync_resume, + }; + +static int dyn_fsync_panic_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + power_suspend_active = true; + dyn_fsync_force_flush(); + //pr_warn("dyn fsync: panic: force flush!\n"); + + return NOTIFY_DONE; +} + +static struct notifier_block dyn_fsync_panic_block = { + .notifier_call = dyn_fsync_panic_event, + .priority = INT_MAX, +}; + +static int dyn_fsync_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + power_suspend_active = true; + dyn_fsync_force_flush(); + //pr_warn("dyn fsync: reboot: force flush!\n"); + } + return NOTIFY_DONE; +} + +static struct notifier_block dyn_fsync_notifier = { + .notifier_call = dyn_fsync_notify_sys, +}; + +static int dyn_fsync_init(void) +{ + int sysfs_result; + + register_power_suspend(&dyn_fsync_power_suspend_handler); + register_reboot_notifier(&dyn_fsync_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &dyn_fsync_panic_block); + + dyn_fsync_kobj = kobject_create_and_add("dyn_fsync", kernel_kobj); + if (!dyn_fsync_kobj) { + pr_err("%s dyn_fsync kobject create failed!\n", __FUNCTION__); + return -ENOMEM; + } + + sysfs_result = sysfs_create_group(dyn_fsync_kobj, + &dyn_fsync_active_attr_group); + + if (sysfs_result) { + pr_info("%s dyn_fsync sysfs create failed!\n", __FUNCTION__); + kobject_put(dyn_fsync_kobj); + } + return sysfs_result; +} + +static void dyn_fsync_exit(void) +{ + unregister_power_suspend(&dyn_fsync_power_suspend_handler); + unregister_reboot_notifier(&dyn_fsync_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &dyn_fsync_panic_block); + + if (dyn_fsync_kobj != NULL) + kobject_put(dyn_fsync_kobj); +} +MODULE_AUTHOR("Paul Reioux "); +MODULE_AUTHOR("Varun Chitre common, nfs3svc_encode_entry); memcpy(resp->verf, argp->verf, 8); resp->count = resp->buffer - argp->buffer; - if (resp->offset) - xdr_encode_hyper(resp->offset, argp->cookie); + if (resp->offset) { + loff_t offset = argp->cookie; + + if (unlikely(resp->offset1)) { + /* we ended up with offset on a page boundary */ + *resp->offset = htonl(offset >> 32); + *resp->offset1 = htonl(offset & 0xffffffff); + resp->offset1 = NULL; + } else { + xdr_encode_hyper(resp->offset, offset); + } + resp->offset = NULL; + } RETURN_STATUS(nfserr); } @@ -501,6 +512,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, } else { xdr_encode_hyper(resp->offset, offset); } + resp->offset = NULL; } RETURN_STATUS(nfserr); diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 14d9ecb96cff..c92662b46feb 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -896,6 +896,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, } else { xdr_encode_hyper(cd->offset, offset64); } + cd->offset = NULL; } /* diff --git a/fs/sync.c b/fs/sync.c index 905f3f6b3d85..d2a3f259f80a 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -17,6 +17,11 @@ #include #include "internal.h" +#ifdef CONFIG_DYNAMIC_FSYNC +extern bool power_suspend_active; +extern bool dyn_fsync_active; +#endif + #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) @@ -89,6 +94,22 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg) filemap_fdatawait(bdev->bd_inode->i_mapping); } + +#ifdef CONFIG_DYNAMIC_FSYNC +/* + * Sync all the data for all the filesystems (called by sys_sync() and + * emergency sync) + */ +void sync_filesystems(int wait) +{ + iterate_supers(sync_inodes_one_sb, NULL); + iterate_supers(sync_fs_one_sb, &wait); + iterate_supers(sync_fs_one_sb, &wait); + iterate_bdevs(fdatawrite_one_bdev, NULL); + iterate_bdevs(fdatawait_one_bdev, NULL); +} +#endif + /* * Sync everything. We start by waking flusher threads so that most of * writeback runs on all devices in parallel. Then we sync all inodes reliably @@ -177,9 +198,17 @@ SYSCALL_DEFINE1(syncfs, int, fd) */ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) { +#ifdef CONFIG_DYNAMIC_FSYNC + if (likely(dyn_fsync_active && !power_suspend_active)) + return 0; + else { +#endif if (!file->f_op || !file->f_op->fsync) return -EINVAL; return file->f_op->fsync(file, start, end, datasync); +#ifdef CONFIG_DYNAMIC_FSYNC + } +#endif } EXPORT_SYMBOL(vfs_fsync_range); @@ -211,6 +240,11 @@ static int do_fsync(unsigned int fd, int datasync) SYSCALL_DEFINE1(fsync, unsigned int, fd) { +#ifdef CONFIG_DYNAMIC_FSYNC + if (likely(dyn_fsync_active && !power_suspend_active)) + return 0; + else +#endif return do_fsync(fd, 0); } @@ -286,6 +320,11 @@ EXPORT_SYMBOL(generic_write_sync); SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, unsigned int, flags) { +#ifdef CONFIG_DYNAMIC_FSYNC + if (likely(dyn_fsync_active && !power_suspend_active)) + return 0; + else { +#endif int ret; struct fd f; struct address_space *mapping; @@ -352,7 +391,8 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, } if (flags & SYNC_FILE_RANGE_WRITE) { - ret = filemap_fdatawrite_range(mapping, offset, endbyte); + ret = __filemap_fdatawrite_range(mapping, offset, endbyte, + WB_SYNC_NONE); if (ret < 0) goto out_put; } @@ -364,6 +404,9 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, fdput(f); out: return ret; +#ifdef CONFIG_DYNAMIC_FSYNC + } +#endif } /* It would be nice if people remember that not all the world's an i386 @@ -371,5 +414,10 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags, loff_t, offset, loff_t, nbytes) { +#ifdef CONFIG_DYNAMIC_FSYNC + if (likely(dyn_fsync_active && !power_suspend_active)) + return 0; + else +#endif return sys_sync_file_range(fd, offset, nbytes, flags); } diff --git a/fs/timerfd.c b/fs/timerfd.c index 0013142c0475..a8e2e9092650 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -39,6 +39,7 @@ struct timerfd_ctx { int clockid; struct rcu_head rcu; struct list_head clist; + spinlock_t cancel_lock; bool might_cancel; }; @@ -111,7 +112,7 @@ void timerfd_clock_was_set(void) rcu_read_unlock(); } -static void timerfd_remove_cancel(struct timerfd_ctx *ctx) +static void __timerfd_remove_cancel(struct timerfd_ctx *ctx) { if (ctx->might_cancel) { ctx->might_cancel = false; @@ -121,6 +122,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx) } } +static void timerfd_remove_cancel(struct timerfd_ctx *ctx) +{ + spin_lock(&ctx->cancel_lock); + __timerfd_remove_cancel(ctx); + spin_unlock(&ctx->cancel_lock); +} + static bool timerfd_canceled(struct timerfd_ctx *ctx) { if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) @@ -131,6 +139,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx) static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) { + spin_lock(&ctx->cancel_lock); if ((ctx->clockid == CLOCK_REALTIME || ctx->clockid == CLOCK_REALTIME_ALARM) && (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) { @@ -140,9 +149,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) list_add_rcu(&ctx->clist, &cancel_list); spin_unlock(&cancel_lock); } - } else if (ctx->might_cancel) { - timerfd_remove_cancel(ctx); - } + } else { + __timerfd_remove_cancel(ctx); + } + spin_unlock(&ctx->cancel_lock); } static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) @@ -326,6 +336,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) return -ENOMEM; init_waitqueue_head(&ctx->wqh); + spin_lock_init(&ctx->cancel_lock); ctx->clockid = clockid; if (isalarm(ctx)) diff --git a/include/linux/fs.h b/include/linux/fs.h index 15817daf8fa8..1f6b967af2f4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2101,6 +2101,7 @@ static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void #endif extern int sync_filesystem(struct super_block *); extern const struct file_operations def_blk_fops; +extern void sync_filesystems(int wait); extern const struct file_operations def_chr_fops; extern const struct file_operations bad_sock_fops; #ifdef CONFIG_BLOCK diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index 569781faa504..1c73e4b49c66 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -46,6 +46,7 @@ struct wakeup_source { const char *name; struct list_head entry; + struct rcu_head rcu; spinlock_t lock; struct timer_list timer; unsigned long timer_expires; diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 4106721c4e5e..317480af15b5 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -384,6 +384,42 @@ static inline void hlist_add_head_rcu(struct hlist_node *n, first->pprev = &n->next; } +/** + * hlist_add_tail_rcu + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * Description: + * Adds the specified element to the specified hlist, + * while permitting racing traversals. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry_rcu(), used to prevent memory-consistency + * problems on Alpha CPUs. Regardless of the type of CPU, the + * list-traversal primitive must be guarded by rcu_read_lock(). + */ +static inline void hlist_add_tail_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *i, *last = NULL; + + for (i = hlist_first_rcu(h); i; i = hlist_next_rcu(i)) + last = i; + + if (last) { + n->next = last->next; + n->pprev = &last->next; + rcu_assign_pointer(hlist_next_rcu(last), n); + } else { + hlist_add_head_rcu(n, h); + } +} + /** * hlist_add_before_rcu * @n: the new element to add to the hash list. diff --git a/include/net/sock.h b/include/net/sock.h index 0c411d311a02..ba3d446e48ec 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -588,6 +588,12 @@ static inline void sk_add_node_rcu(struct sock *sk, struct hlist_head *list) hlist_add_head_rcu(&sk->sk_node, list); } +static inline void sk_add_node_tail_rcu(struct sock *sk, struct hlist_head *list) +{ + sock_hold(sk); + hlist_add_tail_rcu(&sk->sk_node, list); +} + static inline void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) { hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 9b7cf67ea7b2..fc40525622ad 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -288,3 +288,8 @@ config SUSPEND_TIME Prints the time spent in suspend in the kernel log, and keeps statistics on the time spent in suspend in /sys/kernel/debug/suspend_time + +config BOEFFLA_WL_BLOCKER + bool "Boeffla generic wakelock blocker driver" + depends on PM + default N diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3163e6fef132..0349527d2bc6 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2313,7 +2313,16 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, { struct do_proc_dointvec_minmax_conv_param *param = data; if (write) { - int val = *negp ? -*lvalp : *lvalp; + int val; + if (*negp) { + if (*lvalp > (unsigned long) INT_MAX + 1) + return -EINVAL; + val = -*lvalp; + } else { + if (*lvalp > (unsigned long) INT_MAX) + return -EINVAL; + val = *lvalp; + } if ((param->min && *param->min > val) || (param->max && *param->max < val)) return -EINVAL; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index bbd2707f4721..f5ccd6fba14d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2674,7 +2674,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, } mutex_lock(&net->packet.sklist_lock); - sk_add_node_rcu(sk, &net->packet.sklist); + sk_add_node_tail_rcu(sk, &net->packet.sklist); mutex_unlock(&net->packet.sklist_lock); preempt_disable(); @@ -3607,7 +3607,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order) struct pgv *pg_vec; int i; - pg_vec = kcalloc(block_nr, sizeof(struct pgv), GFP_KERNEL); + pg_vec = kcalloc(block_nr, sizeof(struct pgv), GFP_KERNEL | __GFP_NOWARN); if (unlikely(!pg_vec)) goto out; diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 7ca57741b2fb..7849f286bb93 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c @@ -105,16 +105,17 @@ void rose_write_internal(struct sock *sk, int frametype) struct sk_buff *skb; unsigned char *dptr; unsigned char lci1, lci2; - char buffer[100]; - int len, faclen = 0; + int maxfaclen = 0; + int len, faclen; + int reserve; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1; + reserve = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1; + len = ROSE_MIN_LEN; switch (frametype) { case ROSE_CALL_REQUEST: len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN; - faclen = rose_create_facilities(buffer, rose); - len += faclen; + maxfaclen = 256; break; case ROSE_CALL_ACCEPTED: case ROSE_CLEAR_REQUEST: @@ -123,15 +124,16 @@ void rose_write_internal(struct sock *sk, int frametype) break; } - if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) + skb = alloc_skb(reserve + len + maxfaclen, GFP_ATOMIC); + if (!skb) return; /* * Space for AX.25 header and PID. */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1); + skb_reserve(skb, reserve); - dptr = skb_put(skb, skb_tailroom(skb)); + dptr = skb_put(skb, len); lci1 = (rose->lci >> 8) & 0x0F; lci2 = (rose->lci >> 0) & 0xFF; @@ -146,7 +148,8 @@ void rose_write_internal(struct sock *sk, int frametype) dptr += ROSE_ADDR_LEN; memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); dptr += ROSE_ADDR_LEN; - memcpy(dptr, buffer, faclen); + faclen = rose_create_facilities(dptr, rose); + skb_put(skb, faclen); dptr += faclen; break; diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 547e15daf03d..32ccb85cd394 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -106,16 +106,30 @@ as-option = $(call try-run,\ as-instr = $(call try-run,\ printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) +# __cc-option +# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586) +__cc-option = $(call try-run,\ + $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4)) + +# Do not attempt to build with gcc plugins during cc-option tests. +# (And this uses delayed resolution so the flags will be up to date.) +CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) + # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) -cc-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) +cc-option = $(call __cc-option, $(CC),\ + $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS),$(1),$(2)) + +# hostcc-option +# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586) +hostcc-option = $(call __cc-option, $(HOSTCC),\ + $(HOSTCFLAGS) $(HOST_EXTRACFLAGS),$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) cc-option-yn = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) + $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) # cc-option-align # Prefix align with either -falign or -malign @@ -125,7 +139,7 @@ cc-option-align = $(subst -functions=0,,\ # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) cc-disable-warning = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) + $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) # cc-version # Usage gcc-ver := $(call cc-version) @@ -143,12 +157,13 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) cc-ldoption = $(call try-run,\ - $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(1) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) # ld-option # Usage: LDFLAGS += $(call ld-option, -X) ld-option = $(call try-run,\ - $(CC) -x c /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -x c /dev/null -c -o "$$TMPO"; \ + $(LD) $(LDFLAGS) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) # ar-option # Usage: KBUILD_ARFLAGS := $(call ar-option,D) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 35e0f164ef81..04c556bb05e4 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -734,7 +734,7 @@ int conf_write(const char *name) struct menu *menu; const char *basename; const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; char *env; dirname[0] = 0; diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 8fcc5ce05726..09ad65a0c161 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -184,7 +184,7 @@ else # LOCALVERSION= is not specified if test "${LOCALVERSION+set}" != "set"; then scm=$(scm_version --short) - res="$res${scm:++}" + res="$res" fi fi diff --git a/scripts/sortextable.c b/scripts/sortextable.c index f9ce1160419b..7c2310c5b996 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -64,14 +64,6 @@ fail_file(void) longjmp(jmpenv, SJ_FAIL); } -static void __attribute__((noreturn)) -succeed_file(void) -{ - cleanup(); - longjmp(jmpenv, SJ_SUCCEED); -} - - /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap