diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg index 960b9de2860d2..4dd3b4585033d 100644 --- a/android/configs/android-recommended.cfg +++ b/android/configs/android-recommended.cfg @@ -109,6 +109,10 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y CONFIG_TIMER_STATS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index eb3575b3fbf08..33788cb1ffc64 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1796,11 +1796,11 @@ static void show_floppy(void) if (work_pending(&floppy_work)) pr_info("floppy_work.func=%pf\n", floppy_work.func); if (delayed_work_pending(&fd_timer)) - pr_info("delayed work.function=%p expires=%ld\n", + pr_info("delayed work.function=%pf expires=%ld\n", fd_timer.work.func, fd_timer.timer.expires - jiffies); if (delayed_work_pending(&fd_timeout)) - pr_info("timer_function=%p expires=%ld\n", + pr_info("timer_function=%pf expires=%ld\n", fd_timeout.work.func, fd_timeout.timer.expires - jiffies); @@ -3445,6 +3445,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int (struct floppy_struct **)&outparam); if (ret) return ret; + size = offsetof(struct floppy_struct, name); break; case FDMSGON: UDP->flags |= FTD_MSG; diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 57b43001caec6..444e79849799a 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1099,18 +1099,31 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; - length = *(uint16_t *)(buf + 1); /* total length of event series */ - if (length == 0) { - pr_err("diag: Incoming dci event length is invalid\n"); + if (!buf) { + pr_err("diag: In %s buffer is NULL\n", __func__); return; } - /* Move directly to the start of the event series. 1 byte for - * event code and 2 bytes for the length field. - */ - /* The length field indicates the total length removing the cmd_code + /* + * 1 byte for event code and 2 bytes for the length field. + * The length field indicates the total length removing the cmd_code * and the lenght field. The event parsing in that case should happen * till the end. */ + if (len < 3) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); + return; + } + length = *(uint16_t *)(buf + 1); /* total length of event series */ + if ((length == 0) || (len != (length + 3))) { + pr_err("diag: Incoming dci event length: %d is invalid\n", + length); + return; + } + /* + * Move directly to the start of the event series. + * The event parsing should happen from start of event + * series till the end. + */ temp_len = 3; while (temp_len < length) { event_id_packet = *(uint16_t *)(buf + temp_len); @@ -1127,30 +1140,60 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) * necessary. */ timestamp_len = 8; - memcpy(timestamp, buf + temp_len + 2, timestamp_len); + if ((temp_len + timestamp_len + 2) <= len) + memcpy(timestamp, buf + temp_len + 2, + timestamp_len); + else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } } /* 13th and 14th bit represent the payload length */ if (((event_id_packet & 0x6000) >> 13) == 3) { payload_len_field = 1; - payload_len = *(uint8_t *) + if ((temp_len + timestamp_len + 3) <= len) { + payload_len = *(uint8_t *) (buf + temp_len + 2 + timestamp_len); - if (payload_len < (MAX_EVENT_SIZE - 13)) { - /* copy the payload length and the payload */ + } else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } + if ((payload_len < (MAX_EVENT_SIZE - 13)) && + ((temp_len + timestamp_len + payload_len + 3) <= len)) { + /* + * Copy the payload length and the payload + * after skipping temp_len bytes for already + * parsed packet, timestamp_len for timestamp + * buffer, 2 bytes for event_id_packet. + */ memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, 1); memcpy(event_data + 13, buf + temp_len + 2 + timestamp_len + 1, payload_len); } else { - pr_err("diag: event > %d, payload_len = %d\n", - (MAX_EVENT_SIZE - 13), payload_len); + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 13), payload_len, temp_len); return; } } else { payload_len_field = 0; payload_len = (event_id_packet & 0x6000) >> 13; - /* copy the payload */ - memcpy(event_data + 12, buf + temp_len + 2 + + /* + * Copy the payload after skipping temp_len bytes + * for already parsed packet, timestamp_len for + * timestamp buffer, 2 bytes for event_id_packet. + */ + if ((payload_len < (MAX_EVENT_SIZE - 12)) && + ((temp_len + timestamp_len + payload_len + 2) <= len)) + memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, payload_len); + else { + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 12), payload_len, temp_len); + return; + } } /* Before copying the data to userspace, check if we are still @@ -1266,19 +1309,19 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token) pr_err("diag: In %s buffer is NULL\n", __func__); return; } - - /* The first six bytes for the incoming log packet contains - * Command code (2), the length of the packet (2) and the length - * of the log (2) + /* + * The first eight bytes for the incoming log packet contains + * Command code (2), the length of the packet (2), the length + * of the log (2) and log code (2) */ - log_code = *(uint16_t *)(buf + 6); - read_bytes += sizeof(uint16_t) + 6; - if (read_bytes > len) { - pr_err("diag: Invalid length in %s, len: %d, read: %d", - __func__, len, read_bytes); + if (len < 8) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); return; } + log_code = *(uint16_t *)(buf + 6); + read_bytes += sizeof(uint16_t) + 6; + /* parse through log mask table of each client and check mask */ list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index ba888b776d775..a9ec016a57379 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -435,6 +435,8 @@ static void cpufreq_interactive_timer(unsigned long data) return; if (!ppol->governor_enabled) goto exit; + if (ppol->policy->min == ppol->policy->max) + goto rearm; fcpu = cpumask_first(ppol->policy->related_cpus); now = ktime_to_us(ktime_get()); diff --git a/drivers/devfreq/devfreq_spdm_debugfs.c b/drivers/devfreq/devfreq_spdm_debugfs.c index 94e94f3bbc1c7..1d6a581341a5f 100644 --- a/drivers/devfreq/devfreq_spdm_debugfs.c +++ b/drivers/devfreq/devfreq_spdm_debugfs.c @@ -34,7 +34,7 @@ static ssize_t enable_write(struct file *file, const char __user *data, int i; int next_idx; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { @@ -42,6 +42,8 @@ static ssize_t enable_write(struct file *file, const char __user *data, size = -EINVAL; } + buf[size] = '\0'; + if (sscanf(buf, "%u\n", &i) != 1) { size = -EINVAL; goto err; @@ -105,7 +107,7 @@ static ssize_t pl_write(struct file *file, const char __user *data, int ext_status = 0; int i; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { @@ -113,6 +115,8 @@ static ssize_t pl_write(struct file *file, const char __user *data, goto out; } + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.pl_freqs[0], &spdm_data->config_data.pl_freqs[1]) != 2) { size = -EINVAL; @@ -164,7 +168,7 @@ static ssize_t rejrate_low_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { @@ -172,6 +176,8 @@ static ssize_t rejrate_low_write(struct file *file, const char __user *data, goto out; } + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[0], &spdm_data->config_data.reject_rate[1]) != 2) { size = -EINVAL; @@ -224,13 +230,16 @@ static ssize_t rejrate_med_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[2], &spdm_data->config_data.reject_rate[3]) != 2) { size = -EINVAL; @@ -282,13 +291,16 @@ static ssize_t rejrate_high_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[4], &spdm_data->config_data.reject_rate[5]) != 2) { size = -EINVAL; @@ -340,13 +352,16 @@ static ssize_t resptime_low_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[0], &spdm_data->config_data.response_time_us[1]) != 2) { size = -EINVAL; @@ -398,13 +413,16 @@ static ssize_t resptime_med_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[2], &spdm_data->config_data.response_time_us[3]) != 2) { size = -EINVAL; @@ -456,13 +474,16 @@ static ssize_t resptime_high_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[4], &spdm_data->config_data.response_time_us[5]) != 2) { size = -EINVAL; @@ -515,13 +536,16 @@ static ssize_t cciresptime_low_write(struct file *file, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[0], &spdm_data->config_data.cci_response_time_us[1]) != 2) { @@ -575,13 +599,16 @@ static ssize_t cciresptime_med_write(struct file *file, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[2], &spdm_data->config_data.cci_response_time_us[3]) != 2) { @@ -635,13 +662,16 @@ static ssize_t cciresptime_high_write(struct file *file, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[4], &spdm_data->config_data.cci_response_time_us[5]) != 2){ @@ -694,13 +724,16 @@ static ssize_t cci_max_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u\n", &spdm_data->config_data.max_cci_freq) != 1) { size = -EINVAL; goto out; @@ -748,13 +781,16 @@ static ssize_t vote_cfg_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u %u %u\n", &spdm_data->config_data.upstep, &spdm_data->config_data.downstep, &spdm_data->config_data.max_vote, diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 0711c43c31783..20de789fbd05e 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -30,7 +30,7 @@ /* The number of memstore arrays limits the number of contexts allowed. * If more contexts are needed, update multiple for MEMSTORE_SIZE */ -#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 2)) +#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 8)) #define KGSL_MEMSTORE_GLOBAL (0) #define KGSL_PRIORITY_MAX_RB_LEVELS 4 #define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \ diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index bb469e32c6082..e16f43657689b 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -175,15 +175,12 @@ config INPUT_APMPOWER module will be called apm-power. config INPUT_KEYRESET - tristate "Reset key" + bool "Reset key" depends on INPUT select INPUT_KEYCOMBO ---help--- Say Y here if you want to reboot when some keys are pressed; - To compile this driver as a module, choose M here: the - module will be called keyreset. - config INPUT_KEYCOMBO tristate "Key combo" depends on INPUT diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 38eca8c634eab..775a150a8b4f9 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -756,7 +756,8 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client * dm-bufio is resistant to allocation failures (it just keeps * one buffer reserved in cases all the allocations fail). * So set flags to not try too hard: - * GFP_NOIO: don't recurse into the I/O layer + * GFP_NOWAIT: don't wait; if we need to sleep we'll release our + * mutex and wait ourselves. * __GFP_NORETRY: don't retry and rather return failure * __GFP_NOMEMALLOC: don't use emergency reserves * __GFP_NOWARN: don't print a warning in case of failure @@ -766,7 +767,7 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client */ while (1) { if (dm_bufio_cache_size_latch != 1) { - b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); if (b) return b; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ff1f282a734e4..88b808f346416 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -541,11 +541,12 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. -config UID_CPUTIME - tristate "Per-UID cpu time statistics" - depends on PROFILING +config UID_SYS_STATS + bool "Per-UID statistics" + depends on PROFILING && TASK_XACCT && TASK_IO_ACCOUNTING help Per UID based cpu time statistics exported to /proc/uid_cputime + Per UID based io statistics exported to /proc/uid_io config TSIF depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 94e0fe34ae72f..e873f9bae1953 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o -obj-$(CONFIG_UID_CPUTIME) += uid_cputime.o obj-$(CONFIG_TSIF) += msm_tsif.o obj-$(CONFIG_HAPTIC_ISA1200) += isa1200.o obj-$(CONFIG_QSEECOM) += qseecom.o @@ -72,4 +71,4 @@ obj-y += qcom/ #shankai@bsp, 2015/2/2, Add for :drv2605 kernel support obj-$(CONFIG_TI_DRV2605) += ti_drv2605.o #endif VENDOR_EDIT - +obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 01732976d44f6..1d38f4d7e41aa 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,6 +1,6 @@ /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3448,6 +3448,23 @@ static int qseecom_get_qseos_version(struct qseecom_dev_handle *data, return 0; } +static int qseecom_get_qsee_version(struct qseecom_dev_handle *data, + void __user *argp) +{ + struct qseecom_qsee_version_req req; + + if (copy_from_user(&req, argp, sizeof(req))) { + pr_err("copy_from_user failed\n"); + return -EINVAL; + } + req.qsee_version = qseecom.qsee_version; + if (copy_to_user(argp, &req, sizeof(req))) { + pr_err("copy_to_user failed\n"); + return -EINVAL; + } + return 0; +} + static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce) { int rc = 0; @@ -5312,6 +5329,14 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) atomic_dec(&data->ioctl_count); break; } + case QSEECOM_IOCTL_GET_QSEE_VERSION_REQ: { + atomic_inc(&data->ioctl_count); + ret = qseecom_get_qsee_version(data, argp); + if (ret) + pr_err("qseecom_get_qseos_version: %d\n", ret); + atomic_dec(&data->ioctl_count); + break; + } case QSEECOM_IOCTL_PERF_ENABLE_REQ:{ if ((data->type != QSEECOM_GENERIC) && (data->type != QSEECOM_CLIENT_APP)) { diff --git a/drivers/misc/uid_cputime.c b/drivers/misc/uid_cputime.c deleted file mode 100644 index c751188ce2aba..0000000000000 --- a/drivers/misc/uid_cputime.c +++ /dev/null @@ -1,254 +0,0 @@ -/* drivers/misc/uid_cputime.c - * - * Copyright (C) 2014 - 2015 Google, Inc. - * - * 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 -#include -#include -#include -#include - -#define UID_HASH_BITS 10 -DECLARE_HASHTABLE(hash_table, UID_HASH_BITS); - -static DEFINE_MUTEX(uid_lock); -static struct proc_dir_entry *parent; - -struct uid_entry { - uid_t uid; - cputime_t utime; - cputime_t stime; - cputime_t active_utime; - cputime_t active_stime; - unsigned long long active_power; - unsigned long long power; - struct hlist_node hash; -}; - -static struct uid_entry *find_uid_entry(uid_t uid) -{ - struct uid_entry *uid_entry; - hash_for_each_possible(hash_table, uid_entry, hash, uid) { - if (uid_entry->uid == uid) - return uid_entry; - } - return NULL; -} - -static struct uid_entry *find_or_register_uid(uid_t uid) -{ - struct uid_entry *uid_entry; - - uid_entry = find_uid_entry(uid); - if (uid_entry) - return uid_entry; - - uid_entry = kzalloc(sizeof(struct uid_entry), GFP_ATOMIC); - if (!uid_entry) - return NULL; - - uid_entry->uid = uid; - - hash_add(hash_table, &uid_entry->hash, uid); - - return uid_entry; -} - -static int uid_stat_show(struct seq_file *m, void *v) -{ - struct uid_entry *uid_entry; - struct task_struct *task, *temp; - cputime_t utime; - cputime_t stime; - unsigned long bkt; - - mutex_lock(&uid_lock); - - hash_for_each(hash_table, bkt, uid_entry, hash) { - uid_entry->active_stime = 0; - uid_entry->active_utime = 0; - uid_entry->active_power = 0; - } - - read_lock(&tasklist_lock); - do_each_thread(temp, task) { - uid_entry = find_or_register_uid(from_kuid_munged( - current_user_ns(), task_uid(task))); - if (!uid_entry) { - read_unlock(&tasklist_lock); - mutex_unlock(&uid_lock); - pr_err("%s: failed to find the uid_entry for uid %d\n", - __func__, from_kuid_munged(current_user_ns(), - task_uid(task))); - return -ENOMEM; - } - /* if this task is exiting, we have already accounted for the - * time and power. - */ - if (task->cpu_power == ULLONG_MAX) - continue; - task_cputime_adjusted(task, &utime, &stime); - uid_entry->active_utime += utime; - uid_entry->active_stime += stime; - uid_entry->active_power += task->cpu_power; - } while_each_thread(temp, task); - read_unlock(&tasklist_lock); - - hash_for_each(hash_table, bkt, uid_entry, hash) { - cputime_t total_utime = uid_entry->utime + - uid_entry->active_utime; - cputime_t total_stime = uid_entry->stime + - uid_entry->active_stime; - unsigned long long total_power = uid_entry->power + - uid_entry->active_power; - seq_printf(m, "%d: %llu %llu %llu\n", uid_entry->uid, - (unsigned long long)jiffies_to_msecs( - cputime_to_jiffies(total_utime)) * USEC_PER_MSEC, - (unsigned long long)jiffies_to_msecs( - cputime_to_jiffies(total_stime)) * USEC_PER_MSEC, - total_power); - } - - mutex_unlock(&uid_lock); - return 0; -} - -static int uid_stat_open(struct inode *inode, struct file *file) -{ - return single_open(file, uid_stat_show, PDE_DATA(inode)); -} - -static const struct file_operations uid_stat_fops = { - .open = uid_stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int uid_remove_open(struct inode *inode, struct file *file) -{ - return single_open(file, NULL, NULL); -} - -static ssize_t uid_remove_write(struct file *file, - const char __user *buffer, size_t count, loff_t *ppos) -{ - struct uid_entry *uid_entry; - struct hlist_node *tmp; - char uids[128]; - char *start_uid, *end_uid = NULL; - long int uid_start = 0, uid_end = 0; - - if (count >= sizeof(uids)) - count = sizeof(uids) - 1; - - if (copy_from_user(uids, buffer, count)) - return -EFAULT; - - uids[count] = '\0'; - end_uid = uids; - start_uid = strsep(&end_uid, "-"); - - if (!start_uid || !end_uid) - return -EINVAL; - - if (kstrtol(start_uid, 10, &uid_start) != 0 || - kstrtol(end_uid, 10, &uid_end) != 0) { - return -EINVAL; - } - mutex_lock(&uid_lock); - - for (; uid_start <= uid_end; uid_start++) { - hash_for_each_possible_safe(hash_table, uid_entry, tmp, - hash, (uid_t)uid_start) { - if (uid_start == uid_entry->uid) { - hash_del(&uid_entry->hash); - kfree(uid_entry); - } - } - } - - mutex_unlock(&uid_lock); - return count; -} - -static const struct file_operations uid_remove_fops = { - .open = uid_remove_open, - .release = single_release, - .write = uid_remove_write, -}; - -static int process_notifier(struct notifier_block *self, - unsigned long cmd, void *v) -{ - struct task_struct *task = v; - struct uid_entry *uid_entry; - cputime_t utime, stime; - uid_t uid; - - if (!task) - return NOTIFY_OK; - - mutex_lock(&uid_lock); - uid = from_kuid_munged(current_user_ns(), task_uid(task)); - uid_entry = find_or_register_uid(uid); - if (!uid_entry) { - pr_err("%s: failed to find uid %d\n", __func__, uid); - goto exit; - } - - task_cputime_adjusted(task, &utime, &stime); - uid_entry->utime += utime; - uid_entry->stime += stime; - uid_entry->power += task->cpu_power; - task->cpu_power = ULLONG_MAX; - -exit: - mutex_unlock(&uid_lock); - return NOTIFY_OK; -} - -static struct notifier_block process_notifier_block = { - .notifier_call = process_notifier, -}; - -static int __init proc_uid_cputime_init(void) -{ - hash_init(hash_table); - - parent = proc_mkdir("uid_cputime", NULL); - if (!parent) { - pr_err("%s: failed to create proc entry\n", __func__); - return -ENOMEM; - } - - proc_create_data("remove_uid_range", S_IWUGO, parent, &uid_remove_fops, - NULL); - - proc_create_data("show_uid_stat", S_IRUGO, parent, &uid_stat_fops, - NULL); - - profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block); - - return 0; -} - -early_initcall(proc_uid_cputime_init); diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c new file mode 100644 index 0000000000000..2aa7246700b16 --- /dev/null +++ b/drivers/misc/uid_sys_stats.c @@ -0,0 +1,512 @@ +/* drivers/misc/uid_sys_stats.c + * + * Copyright (C) 2014 - 2015 Google, Inc. + * + * 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 +#include +#include +#include +#include +#include + +#define UID_HASH_BITS 10 +DECLARE_HASHTABLE(hash_table, UID_HASH_BITS); + +static DEFINE_RT_MUTEX(uid_lock); +static struct proc_dir_entry *cpu_parent; +static struct proc_dir_entry *io_parent; +static struct proc_dir_entry *proc_parent; + +struct io_stats { + u64 read_bytes; + u64 write_bytes; + u64 rchar; + u64 wchar; + u64 fsync; +}; + +#define UID_STATE_FOREGROUND 0 +#define UID_STATE_BACKGROUND 1 +#define UID_STATE_BUCKET_SIZE 2 + +#define UID_STATE_TOTAL_CURR 2 +#define UID_STATE_TOTAL_LAST 3 +#define UID_STATE_DEAD_TASKS 4 +#define UID_STATE_SIZE 5 + +struct uid_entry { + uid_t uid; + cputime_t utime; + cputime_t stime; + cputime_t active_utime; + cputime_t active_stime; + unsigned long long active_power; + unsigned long long power; + int state; + struct io_stats io[UID_STATE_SIZE]; + struct hlist_node hash; +}; + +static struct uid_entry *find_uid_entry(uid_t uid) +{ + struct uid_entry *uid_entry; + hash_for_each_possible(hash_table, uid_entry, hash, uid) { + if (uid_entry->uid == uid) + return uid_entry; + } + return NULL; +} + +static struct uid_entry *find_or_register_uid(uid_t uid) +{ + struct uid_entry *uid_entry; + + uid_entry = find_uid_entry(uid); + if (uid_entry) + return uid_entry; + + uid_entry = kzalloc(sizeof(struct uid_entry), GFP_ATOMIC); + if (!uid_entry) + return NULL; + + uid_entry->uid = uid; + + hash_add(hash_table, &uid_entry->hash, uid); + + return uid_entry; +} + +static int uid_cputime_show(struct seq_file *m, void *v) +{ + struct uid_entry *uid_entry; + struct task_struct *task, *temp; + struct user_namespace *user_ns = current_user_ns(); + cputime_t utime; + cputime_t stime; + unsigned long bkt; + uid_t uid; + + rt_mutex_lock(&uid_lock); + + hash_for_each(hash_table, bkt, uid_entry, hash) { + uid_entry->active_stime = 0; + uid_entry->active_utime = 0; + uid_entry->active_power = 0; + } + + read_lock(&tasklist_lock); + do_each_thread(temp, task) { + uid = from_kuid_munged(user_ns, task_uid(task)); + uid_entry = find_or_register_uid(uid); + if (!uid_entry) { + read_unlock(&tasklist_lock); + rt_mutex_unlock(&uid_lock); + pr_err("%s: failed to find the uid_entry for uid %d\n", + __func__, uid); + return -ENOMEM; + } + /* if this task is exiting, we have already accounted for the + * time and power. + */ + if (task->cpu_power == ULLONG_MAX) + continue; + task_cputime_adjusted(task, &utime, &stime); + uid_entry->active_utime += utime; + uid_entry->active_stime += stime; + uid_entry->active_power += task->cpu_power; + } while_each_thread(temp, task); + read_unlock(&tasklist_lock); + + hash_for_each(hash_table, bkt, uid_entry, hash) { + cputime_t total_utime = uid_entry->utime + + uid_entry->active_utime; + cputime_t total_stime = uid_entry->stime + + uid_entry->active_stime; + unsigned long long total_power = uid_entry->power + + uid_entry->active_power; + seq_printf(m, "%d: %llu %llu %llu\n", uid_entry->uid, + (unsigned long long)jiffies_to_msecs( + cputime_to_jiffies(total_utime)) * USEC_PER_MSEC, + (unsigned long long)jiffies_to_msecs( + cputime_to_jiffies(total_stime)) * USEC_PER_MSEC, + total_power); + } + + rt_mutex_unlock(&uid_lock); + return 0; +} + +static int uid_cputime_open(struct inode *inode, struct file *file) +{ + return single_open(file, uid_cputime_show, PDE_DATA(inode)); +} + +static const struct file_operations uid_cputime_fops = { + .open = uid_cputime_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int uid_remove_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, NULL); +} + +static ssize_t uid_remove_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + struct uid_entry *uid_entry; + struct hlist_node *tmp; + char uids[128]; + char *start_uid, *end_uid = NULL; + long int uid_start = 0, uid_end = 0; + + if (count >= sizeof(uids)) + count = sizeof(uids) - 1; + + if (copy_from_user(uids, buffer, count)) + return -EFAULT; + + uids[count] = '\0'; + end_uid = uids; + start_uid = strsep(&end_uid, "-"); + + if (!start_uid || !end_uid) + return -EINVAL; + + if (kstrtol(start_uid, 10, &uid_start) != 0 || + kstrtol(end_uid, 10, &uid_end) != 0) { + return -EINVAL; + } + rt_mutex_lock(&uid_lock); + + for (; uid_start <= uid_end; uid_start++) { + hash_for_each_possible_safe(hash_table, uid_entry, tmp, + hash, (uid_t)uid_start) { + if (uid_start == uid_entry->uid) { + hash_del(&uid_entry->hash); + kfree(uid_entry); + } + } + } + + rt_mutex_unlock(&uid_lock); + return count; +} + +static const struct file_operations uid_remove_fops = { + .open = uid_remove_open, + .release = single_release, + .write = uid_remove_write, +}; + +static u64 compute_write_bytes(struct task_struct *task) +{ + if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes) + return 0; + + return task->ioac.write_bytes - task->ioac.cancelled_write_bytes; +} + +static void add_uid_io_stats(struct uid_entry *uid_entry, + struct task_struct *task, int slot) +{ + struct io_stats *io_slot = &uid_entry->io[slot]; + + io_slot->read_bytes += task->ioac.read_bytes; + io_slot->write_bytes += compute_write_bytes(task); + io_slot->rchar += task->ioac.rchar; + io_slot->wchar += task->ioac.wchar; + io_slot->fsync += task->ioac.syscfs; +} + +static void compute_uid_io_bucket_stats(struct io_stats *io_bucket, + struct io_stats *io_curr, + struct io_stats *io_last, + struct io_stats *io_dead) +{ + s64 delta; + + delta = io_curr->read_bytes + io_dead->read_bytes - + io_last->read_bytes; + if (delta > 0) + io_bucket->read_bytes += delta; + + delta = io_curr->write_bytes + io_dead->write_bytes - + io_last->write_bytes; + if (delta > 0) + io_bucket->write_bytes += delta; + + delta = io_curr->rchar + io_dead->rchar - io_last->rchar; + if (delta > 0) + io_bucket->rchar += delta; + + delta = io_curr->wchar + io_dead->wchar - io_last->wchar; + if (delta > 0) + io_bucket->wchar += delta; + + delta = io_curr->fsync + io_dead->fsync - io_last->fsync; + if (delta > 0) + io_bucket->fsync += delta; + + io_last->read_bytes = io_curr->read_bytes; + io_last->write_bytes = io_curr->write_bytes; + io_last->rchar = io_curr->rchar; + io_last->wchar = io_curr->wchar; + io_last->fsync = io_curr->fsync; + + memset(io_dead, 0, sizeof(struct io_stats)); +} + +static void update_io_stats_all_locked(void) +{ + struct uid_entry *uid_entry; + struct task_struct *task, *temp; + struct user_namespace *user_ns = current_user_ns(); + unsigned long bkt; + uid_t uid; + + hash_for_each(hash_table, bkt, uid_entry, hash) + memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, + sizeof(struct io_stats)); + + rcu_read_lock(); + do_each_thread(temp, task) { + uid = from_kuid_munged(user_ns, task_uid(task)); + uid_entry = find_or_register_uid(uid); + if (!uid_entry) + continue; + add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR); + } while_each_thread(temp, task); + rcu_read_unlock(); + + hash_for_each(hash_table, bkt, uid_entry, hash) { + compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state], + &uid_entry->io[UID_STATE_TOTAL_CURR], + &uid_entry->io[UID_STATE_TOTAL_LAST], + &uid_entry->io[UID_STATE_DEAD_TASKS]); + } +} + +static void update_io_stats_uid_locked(struct uid_entry *uid_entry) +{ + struct task_struct *task, *temp; + struct user_namespace *user_ns = current_user_ns(); + + memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, + sizeof(struct io_stats)); + + rcu_read_lock(); + do_each_thread(temp, task) { + if (from_kuid_munged(user_ns, task_uid(task)) != uid_entry->uid) + continue; + add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR); + } while_each_thread(temp, task); + rcu_read_unlock(); + + compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state], + &uid_entry->io[UID_STATE_TOTAL_CURR], + &uid_entry->io[UID_STATE_TOTAL_LAST], + &uid_entry->io[UID_STATE_DEAD_TASKS]); +} + +static int uid_io_show(struct seq_file *m, void *v) +{ + struct uid_entry *uid_entry; + unsigned long bkt; + + rt_mutex_lock(&uid_lock); + + update_io_stats_all_locked(); + + hash_for_each(hash_table, bkt, uid_entry, hash) { + seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + uid_entry->uid, + uid_entry->io[UID_STATE_FOREGROUND].rchar, + uid_entry->io[UID_STATE_FOREGROUND].wchar, + uid_entry->io[UID_STATE_FOREGROUND].read_bytes, + uid_entry->io[UID_STATE_FOREGROUND].write_bytes, + uid_entry->io[UID_STATE_BACKGROUND].rchar, + uid_entry->io[UID_STATE_BACKGROUND].wchar, + uid_entry->io[UID_STATE_BACKGROUND].read_bytes, + uid_entry->io[UID_STATE_BACKGROUND].write_bytes, + uid_entry->io[UID_STATE_FOREGROUND].fsync, + uid_entry->io[UID_STATE_BACKGROUND].fsync); + } + + rt_mutex_unlock(&uid_lock); + + return 0; +} + +static int uid_io_open(struct inode *inode, struct file *file) +{ + return single_open(file, uid_io_show, PDE_DATA(inode)); +} + +static const struct file_operations uid_io_fops = { + .open = uid_io_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int uid_procstat_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, NULL); +} + +static ssize_t uid_procstat_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + struct uid_entry *uid_entry; + uid_t uid; + int argc, state; + char input[128]; + + if (count >= sizeof(input)) + return -EINVAL; + + if (copy_from_user(input, buffer, count)) + return -EFAULT; + + input[count] = '\0'; + + argc = sscanf(input, "%u %d", &uid, &state); + if (argc != 2) + return -EINVAL; + + if (state != UID_STATE_BACKGROUND && state != UID_STATE_FOREGROUND) + return -EINVAL; + + rt_mutex_lock(&uid_lock); + + uid_entry = find_or_register_uid(uid); + if (!uid_entry) { + rt_mutex_unlock(&uid_lock); + return -EINVAL; + } + + if (uid_entry->state == state) { + rt_mutex_unlock(&uid_lock); + return count; + } + + update_io_stats_uid_locked(uid_entry); + + uid_entry->state = state; + + rt_mutex_unlock(&uid_lock); + + return count; +} + +static const struct file_operations uid_procstat_fops = { + .open = uid_procstat_open, + .release = single_release, + .write = uid_procstat_write, +}; + +static int process_notifier(struct notifier_block *self, + unsigned long cmd, void *v) +{ + struct task_struct *task = v; + struct uid_entry *uid_entry; + cputime_t utime, stime; + uid_t uid; + + if (!task) + return NOTIFY_OK; + + rt_mutex_lock(&uid_lock); + uid = from_kuid_munged(current_user_ns(), task_uid(task)); + uid_entry = find_or_register_uid(uid); + if (!uid_entry) { + pr_err("%s: failed to find uid %d\n", __func__, uid); + goto exit; + } + + task_cputime_adjusted(task, &utime, &stime); + uid_entry->utime += utime; + uid_entry->stime += stime; + uid_entry->power += task->cpu_power; + task->cpu_power = ULLONG_MAX; + + add_uid_io_stats(uid_entry, task, UID_STATE_DEAD_TASKS); + +exit: + rt_mutex_unlock(&uid_lock); + return NOTIFY_OK; +} + +static struct notifier_block process_notifier_block = { + .notifier_call = process_notifier, +}; + +static int __init proc_uid_sys_stats_init(void) +{ + hash_init(hash_table); + + cpu_parent = proc_mkdir("uid_cputime", NULL); + if (!cpu_parent) { + pr_err("%s: failed to create uid_cputime proc entry\n", + __func__); + goto err; + } + + proc_create_data("remove_uid_range", 0222, cpu_parent, + &uid_remove_fops, NULL); + proc_create_data("show_uid_stat", 0444, cpu_parent, + &uid_cputime_fops, NULL); + + io_parent = proc_mkdir("uid_io", NULL); + if (!io_parent) { + pr_err("%s: failed to create uid_io proc entry\n", + __func__); + goto err; + } + + proc_create_data("stats", 0444, io_parent, + &uid_io_fops, NULL); + + proc_parent = proc_mkdir("uid_procstat", NULL); + if (!proc_parent) { + pr_err("%s: failed to create uid_procstat proc entry\n", + __func__); + goto err; + } + + proc_create_data("set", 0222, proc_parent, + &uid_procstat_fops, NULL); + + profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block); + + return 0; + +err: + remove_proc_subtree("uid_cputime", NULL); + remove_proc_subtree("uid_io", NULL); + remove_proc_subtree("uid_procstat", NULL); + return -ENOMEM; +} + +early_initcall(proc_uid_sys_stats_init); diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c index 9d2f1df371030..db3c469cb83f2 100644 --- a/drivers/platform/msm/ipa/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_rt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1072,6 +1072,15 @@ int __ipa_del_rt_rule(u32 rule_hdl) return -EINVAL; } + if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) { + IPADBG("Deleting rule from default rt table idx=%u\n", + entry->tbl->idx); + if (entry->tbl->rule_cnt == 1) { + IPAERR("Default tbl last rule cannot be deleted\n"); + return -EINVAL; + } + } + if (entry->hdr) __ipa_release_hdr(entry->hdr->id); else if (entry->proc_ctx) diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 1b9872a4150df..1b98a090c36cd 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -528,7 +528,7 @@ static long msm_core_ioctl(struct file *file, unsigned int cmd, node->sp->voltage, sizeof(uint32_t) * node->sp->num_of_freqs); if (ret) - break; + goto unlock; for (i = 0; i < node->sp->num_of_freqs; i++) { ret = copy_to_user((void __user *)&argp->freq[i], &node->sp->table[i].frequency, diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 446b85110a1fc..09625081b56c0 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -684,6 +684,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); out: + kfree(req); kfree(resp); return res; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index aadd3b048f314..4bd31b6adedef 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -400,6 +400,9 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) struct sg_header *old_hdr = NULL; int retval = 0; + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n", diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index fe54589744061..e05230255d6f0 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,11 @@ static void *dummy_q6_mvm; static void *dummy_q6_cvs; dev_t device_num; +spinlock_t voicesvc_lock; +static bool is_released; static int voice_svc_dummy_reg(void); +static int voice_svc_dummy_dereg(void); + static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data, void *priv); @@ -82,10 +87,16 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) return -EINVAL; } + spin_lock(&voicesvc_lock); + if (is_released) { + spin_unlock(&voicesvc_lock); + return 0; + } prtd = (struct voice_svc_prvt *)priv; if (prtd == NULL) { pr_err("%s: private data is NULL\n", __func__); + spin_unlock(&voicesvc_lock); return -EINVAL; } @@ -128,6 +139,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) spin_unlock_irqrestore(&prtd->response_lock, spin_flags); + spin_unlock(&voicesvc_lock); return -ENOMEM; } @@ -156,6 +168,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) __func__); } + spin_unlock(&voicesvc_lock); return 0; } @@ -614,6 +627,21 @@ static int voice_svc_dummy_reg() return -EINVAL; } +static int voice_svc_dummy_dereg(void) +{ + pr_debug("%s\n", __func__); + if (dummy_q6_mvm != NULL) { + apr_deregister(dummy_q6_mvm); + dummy_q6_mvm = NULL; + } + + if (dummy_q6_cvs != NULL) { + apr_deregister(dummy_q6_cvs); + dummy_q6_cvs = NULL; + } + return 0; +} + static int voice_svc_open(struct inode *inode, struct file *file) { struct voice_svc_prvt *prtd = NULL; @@ -637,6 +665,7 @@ static int voice_svc_open(struct inode *inode, struct file *file) mutex_init(&prtd->response_mutex_lock); file->private_data = (void *)prtd; + is_released = 0; /* Current APR implementation doesn't support session based * multiple service registrations. The apr_deregister() * function sets the destination and client IDs to zero, if @@ -669,6 +698,11 @@ static int voice_svc_release(struct inode *inode, struct file *file) goto done; } + mutex_lock(&prtd->response_mutex_lock); + if (reg_dummy_sess) { + voice_svc_dummy_dereg(); + reg_dummy_sess = 0; + } if (prtd->apr_q6_cvs != NULL) { svc_name = VOICE_SVC_MVM_STR; handle = &prtd->apr_q6_cvs; @@ -685,7 +719,6 @@ static int voice_svc_release(struct inode *inode, struct file *file) pr_err("%s: Failed to dereg MVM %d\n", __func__, ret); } - mutex_lock(&prtd->response_mutex_lock); spin_lock_irqsave(&prtd->response_lock, spin_flags); while (!list_empty(&prtd->response_queue)) { @@ -703,9 +736,11 @@ static int voice_svc_release(struct inode *inode, struct file *file) mutex_destroy(&prtd->response_mutex_lock); + spin_lock(&voicesvc_lock); kfree(file->private_data); file->private_data = NULL; - + is_released = 1; + spin_unlock(&voicesvc_lock); done: return ret; } @@ -774,6 +809,7 @@ static int voice_svc_probe(struct platform_device *pdev) goto add_err; } pr_debug("%s: Device created\n", __func__); + spin_lock_init(&voicesvc_lock); goto done; add_err: diff --git a/drivers/soc/qcom/rpm-smd-debug.c b/drivers/soc/qcom/rpm-smd-debug.c index 1c0a05c87edaf..8194fe0cda5b6 100644 --- a/drivers/soc/qcom/rpm-smd-debug.c +++ b/drivers/soc/qcom/rpm-smd-debug.c @@ -99,23 +99,23 @@ static ssize_t rsc_ops_write(struct file *fp, const char __user *user_buffer, cmp += pos; if (sscanf(cmp, "%5s %n", key_str, &pos) != 1) { pr_err("Invalid number of arguments passed\n"); - goto err; + goto err_request; } if (strlen(key_str) > 4) { pr_err("Key value cannot be more than 4 charecters"); - goto err; + goto err_request; } key = string_to_uint(key_str); if (!key) { pr_err("Key values entered incorrectly\n"); - goto err; + goto err_request; } cmp += pos; if (sscanf(cmp, "%u %n", &data, &pos) != 1) { pr_err("Invalid number of arguments passed\n"); - goto err; + goto err_request; } if (msm_rpm_add_kvp_data(req, key, diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index 001cc25bd4e3a..cd44f5ae6db99 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -969,6 +969,7 @@ static int pil_tz_driver_probe(struct platform_device *pdev) destroy_ramdump_device(d->ramdump_dev); err_ramdump: pil_desc_release(&d->desc); + platform_set_drvdata(pdev, NULL); return rc; } diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h index c608cf59413af..129443fe84b29 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h @@ -6315,6 +6315,9 @@ PREPACK struct htt_txq_group { #define HTT_TX_COMPL_IND_APPEND_GET(_info) \ (((_info) & HTT_TX_COMPL_IND_APPEND_M) >> HTT_TX_COMPL_IND_APPEND_S) +#define HTT_TX_COMPL_HEAD_SZ 4 +#define HTT_TX_COMPL_BYTES_PER_MSDU_ID 2 + #define HTT_TX_COMPL_CTXT_SZ sizeof(A_UINT16) #define HTT_TX_COMPL_CTXT_NUM(_bytes) ((_bytes) >> 1) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c index b736a970c5750..9b2a2f12a6b1d 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c @@ -172,7 +172,7 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) { u_int16_t peer_id; u_int8_t tid; - int seq_num_start, seq_num_end; + u_int16_t seq_num_start, seq_num_end; enum htt_rx_flush_action action; peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word); @@ -297,6 +297,14 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) peer_mac_addr = htt_t2h_mac_addr_deswizzle( (u_int8_t *) (msg_word+1), &mac_addr_deswizzle_buf[0]); + if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { + adf_os_print("%s: HTT_T2H_MSG_TYPE_PEER_MAP," + "invalid peer_id, %u\n", + __FUNCTION__, + peer_id); + break; + } + ol_rx_peer_map_handler( pdev->txrx_pdev, peer_id, vdev_id, peer_mac_addr, 1/*can tx*/); break; @@ -306,6 +314,14 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) u_int16_t peer_id; peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); + if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { + adf_os_print("%s: HTT_T2H_MSG_TYPE_PEER_UNMAP," + "invalid peer_id, %u\n", + __FUNCTION__, + peer_id); + break; + } + ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id); break; } @@ -630,10 +646,26 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { { int num_msdus; enum htt_tx_status status; + int msg_len = adf_nbuf_len(htt_t2h_msg); /* status - no enum translation needed */ status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + adf_os_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + if (num_msdus & 0x1) { struct htt_tx_compl_ind_base *compl = (void *)msg_word; @@ -675,7 +707,7 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { { u_int16_t peer_id; u_int8_t tid, pn_ie_cnt, *pn_ie=NULL; - int seq_num_start, seq_num_end; + u_int16_t seq_num_start, seq_num_end; /*First dword */ peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); @@ -702,8 +734,23 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: { int num_msdus; + int msg_len = adf_nbuf_len(htt_t2h_msg); num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + adf_os_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d,inspect\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + if (num_msdus & 0x1) { struct htt_tx_compl_ind_base *compl = (void *)msg_word; @@ -1077,8 +1124,8 @@ void htt_rx_frag_ind_flush_seq_num_range( htt_pdev_handle pdev, adf_nbuf_t rx_frag_ind_msg, - int *seq_num_start, - int *seq_num_end) + u_int16_t *seq_num_start, + u_int16_t *seq_num_end) { u_int32_t *msg_word; diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c index 3ebe957c5d794..b09445f59fd45 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c @@ -642,6 +642,16 @@ static int tlshim_mgmt_rx_process(void *context, u_int8_t *data, rx_pkt->pkt_meta.mpdu_data_len = hdr->buf_len - rx_pkt->pkt_meta.mpdu_hdr_len; + /* + * If the mpdu_data_len is greater than Max (2k), drop the frame + */ + if (rx_pkt->pkt_meta.mpdu_data_len > WMA_MAX_MGMT_MPDU_LEN) { + TLSHIM_LOGE("Data Len %d greater than max, dropping frame", + rx_pkt->pkt_meta.mpdu_data_len); + vos_mem_free(rx_pkt); + return 0; + } + /* * saved_beacon means this beacon is a duplicate of one * sent earlier. roamCandidateInd flag is used to indicate to diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c index 358d6d660c3bf..420683bf9cf5c 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -192,12 +192,20 @@ ol_rx_frag_indication_handler( u_int8_t tid) { u_int16_t seq_num; - int seq_num_start, seq_num_end; + u_int16_t seq_num_start, seq_num_end; struct ol_txrx_peer_t *peer; htt_pdev_handle htt_pdev; adf_nbuf_t head_msdu, tail_msdu; void *rx_mpdu_desc; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", + __FUNCTION__, + tid); + return; + } + htt_pdev = pdev->htt_pdev; peer = ol_txrx_peer_find_by_id(pdev, peer_id); @@ -245,7 +253,7 @@ ol_rx_reorder_flush_frag( htt_pdev_handle htt_pdev, struct ol_txrx_peer_t *peer, unsigned tid, - int seq_num) + u_int16_t seq_num) { struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; int seq; diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h index 737c299873057..7750f2456fd68 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -165,7 +165,7 @@ ol_rx_reorder_flush_frag( htt_pdev_handle htt_pdev, struct ol_txrx_peer_t *peer, unsigned tid, - int seq_num); + u_int16_t seq_num); static inline void xor_block( diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c index e1ffff092a92f..05f54907bb509 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c @@ -583,6 +583,14 @@ ol_rx_flush_handler( struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; htt_pdev_handle htt_pdev = pdev->htt_pdev; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", + __FUNCTION__, + tid); + return; + } + peer = ol_txrx_peer_find_by_id(pdev, peer_id); if (peer) { vdev = peer->vdev; @@ -622,8 +630,8 @@ ol_rx_pn_ind_handler( ol_txrx_pdev_handle pdev, u_int16_t peer_id, u_int8_t tid, - int seq_num_start, - int seq_num_end, + u_int16_t seq_num_start, + u_int16_t seq_num_end, u_int8_t pn_ie_cnt, u_int8_t *pn_ie) { @@ -635,7 +643,8 @@ ol_rx_pn_ind_handler( adf_nbuf_t head_msdu = NULL; adf_nbuf_t tail_msdu = NULL; htt_pdev_handle htt_pdev = pdev->htt_pdev; - int seq_num, i=0; + u_int16_t seq_num; + int i=0; peer = ol_txrx_peer_find_by_id(pdev, peer_id); diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c index 7cd0917fc95d8..98961ca06d3a3 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c @@ -376,6 +376,9 @@ ol_txrx_pdev_attach( TXRX_STATS_INIT(pdev); TAILQ_INIT(&pdev->vdev_list); + TAILQ_INIT(&pdev->req_list); + pdev->req_list_depth = 0; + adf_os_spinlock_init(&pdev->req_list_spinlock); /* do initial set up of the peer ID -> peer object lookup map */ if (ol_txrx_peer_find_attach(pdev)) { @@ -886,7 +889,9 @@ A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev) void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) { - int i; + int i = 0; + unsigned int page_idx; + struct ol_txrx_stats_req_internal *req; /*checking to ensure txrx pdev structure is not NULL */ if (!pdev) { @@ -899,6 +904,30 @@ ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) /* check that the pdev has no vdevs allocated */ TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list)); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + if (pdev->req_list_depth > 0) + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Warning: the txrx req list is not empty, depth=%d\n", + pdev->req_list_depth + ); + TAILQ_FOREACH(req, &pdev->req_list, req_list_elem) { + TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); + pdev->req_list_depth--; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%d: %p,verbose(%d), concise(%d), up_m(0x%x), reset_m(0x%x)\n", + i++, + req, + req->base.print.verbose, + req->base.print.concise, + req->base.stats_type_upload_mask, + req->base.stats_type_reset_mask + ); + adf_os_mem_free(req); + } + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + + adf_os_spinlock_destroy(&pdev->req_list_spinlock); + OL_RX_REORDER_TIMEOUT_CLEANUP(pdev); if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) { @@ -1961,12 +1990,6 @@ void ol_txrx_print_level_set(unsigned level) #endif } -struct ol_txrx_stats_req_internal { - struct ol_txrx_stats_req base; - int serviced; /* state of this request */ - int offset; -}; - static inline u_int64_t OL_TXRX_STATS_PTR_TO_U64(struct ol_txrx_stats_req_internal *req) { @@ -2028,6 +2051,11 @@ ol_txrx_fw_stats_get( /* use the non-volatile request object's address as the cookie */ cookie = OL_TXRX_STATS_PTR_TO_U64(non_volatile_req); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_INSERT_TAIL(&pdev->req_list, non_volatile_req, req_list_elem); + pdev->req_list_depth++; + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + if (htt_h2t_dbg_stats_get( pdev->htt_pdev, req->stats_type_upload_mask, @@ -2035,14 +2063,15 @@ ol_txrx_fw_stats_get( HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID, 0, cookie)) { + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_REMOVE(&pdev->req_list, non_volatile_req, req_list_elem); + pdev->req_list_depth--; + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + adf_os_mem_free(non_volatile_req); return A_ERROR; } - if (req->wait.blocking) { - while (adf_os_mutex_acquire(pdev->osdev, req->wait.sem_ptr)) {} - } - return A_OK; } #endif @@ -2056,11 +2085,27 @@ ol_txrx_fw_stats_handler( enum htt_dbg_stats_status status; int length; u_int8_t *stats_data; - struct ol_txrx_stats_req_internal *req; + struct ol_txrx_stats_req_internal *req, *tmp; int more = 0; + int found = 0; req = OL_TXRX_U64_TO_STATS_PTR(cookie); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { + if (req == tmp) { + found = 1; + break; + } + } + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + + if (!found) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "req(%p) from firmware can't be found in the list\n", req); + return; + } + do { htt_t2h_dbg_stats_hdr_parse( stats_info_list, &type, &status, &length, &stats_data); @@ -2184,10 +2229,16 @@ ol_txrx_fw_stats_handler( } while (1); if (! more) { - if (req->base.wait.blocking) { - adf_os_mutex_release(pdev->osdev, req->base.wait.sem_ptr); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { + if (req == tmp) { + TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); + pdev->req_list_depth--; + adf_os_mem_free(req); + break; + } } - adf_os_mem_free(req); + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); } } diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h index ff889caff7c04..2873e9d3c3215 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h @@ -544,6 +544,10 @@ struct ol_txrx_pdev_t { /* ol_txrx_vdev list */ TAILQ_HEAD(, ol_txrx_vdev_t) vdev_list; + TAILQ_HEAD(, ol_txrx_stats_req_internal) req_list; + int req_list_depth; + adf_os_spinlock_t req_list_spinlock; + /* peer ID to peer object map (array of pointers to peer objects) */ struct ol_txrx_peer_t **peer_id_to_obj_map; diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c index 28fb6b23e96e2..d2543592861e7 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c @@ -4418,6 +4418,7 @@ static tANI_S32 hdd_ProcessGENIE(hdd_adapter_t *pAdapter, tDot11fIERSN dot11RSNIE; tDot11fIEWPA dot11WPAIE; tANI_U32 i; + tANI_U32 status; tANI_U8 *pRsnIe; tANI_U16 RSNIeLen; tPmkidCacheInfo PMKIDCache[4]; // Local transfer memory @@ -4443,10 +4444,17 @@ static tANI_S32 hdd_ProcessGENIE(hdd_adapter_t *pAdapter, pRsnIe = gen_ie + 2; RSNIeLen = gen_ie_len - 2; // Unpack the RSN IE - dot11fUnpackIeRSN((tpAniSirGlobal) halHandle, + status = dot11fUnpackIeRSN((tpAniSirGlobal) halHandle, pRsnIe, RSNIeLen, &dot11RSNIE); + if (DOT11F_FAILED(status)) + { + hddLog(LOGE, + FL("Parse failure in hdd_ProcessGENIE (0x%08x)"), + status); + return -EINVAL; + } // Copy out the encryption and authentication types hddLog(LOG1, FL("%s: pairwise cipher suite count: %d"), __func__, dot11RSNIE.pwise_cipher_suite_count ); diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h b/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h index 30bb3ca957ecc..ab5487456b62c 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h +++ b/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h @@ -586,6 +586,7 @@ #define SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS 4 #define SIR_MAC_KEY_LENGTH 13 // WEP Maximum key length size #define SIR_MAC_AUTH_CHALLENGE_LENGTH 253 +#define SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH 128 #define SIR_MAC_WEP_IV_LENGTH 4 #define SIR_MAC_WEP_ICV_LENGTH 4 #define SIR_MAC_CHALLENGE_ID_LEN 2 diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c index 943ba48cab560..947f848401406 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c @@ -2712,7 +2712,8 @@ ProcSetReqInternal(tpAniSirGlobal pMac, tANI_U16 length, tANI_U32 *pParam, tANI_ // Process string parameter else { - if (valueLenRoundedUp4 > length) + if ((valueLenRoundedUp4 > length) || + (valueLen > CFG_MAX_STR_LEN)) { PELOGE(cfgLog(pMac, LOGE, FL("Invalid string length %d" "in set param %d (tot %d)"), valueLen, diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c index 05591d0494441..af5411e18eaf6 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c @@ -290,7 +290,8 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse goto free; } - if (frameLen < LIM_ENCR_AUTH_BODY_LEN) + if ((frameLen < LIM_ENCR_AUTH_BODY_LEN_SAP) || + (frameLen > LIM_ENCR_AUTH_BODY_LEN_SAP)) { // Log error limLog(pMac, LOGE, @@ -966,9 +967,9 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse pAuthNode->fTimerStarted = 1; /* - * get random bytes and use as challenge text. + * get random bytes and use as challenge text */ - if( !VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes( 0, (tANI_U8 *)challengeTextArray, SIR_MAC_AUTH_CHALLENGE_LENGTH ) ) ) + if( !VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes( 0, (tANI_U8 *)challengeTextArray, SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH ) ) ) { limLog(pMac, LOGE,FL("Challenge text preparation failed in limProcessAuthFrame")); goto free; @@ -990,11 +991,12 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse pRxAuthFrameBody->authTransactionSeqNumber + 1; authFrame->authStatusCode = eSIR_MAC_SUCCESS_STATUS; + authFrame->type = SIR_MAC_CHALLENGE_TEXT_EID; - authFrame->length = SIR_MAC_AUTH_CHALLENGE_LENGTH; + authFrame->length = SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH; vos_mem_copy(authFrame->challengeText, pAuthNode->challengeText, - SIR_MAC_AUTH_CHALLENGE_LENGTH); + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH); limSendAuthMgmtFrame( pMac, authFrame, @@ -1596,7 +1598,7 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse if (vos_mem_compare(pRxAuthFrameBody->challengeText, pAuthNode->challengeText, - SIR_MAC_AUTH_CHALLENGE_LENGTH)) + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH)) { /// Challenge match. STA is autheticated ! diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c index 4cef79044b99d..b6bb3ee09404f 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c @@ -742,6 +742,10 @@ limSendSmeProbeReqInd(tpAniSirGlobal pMac, MTRACE(macTrace(pMac, TRACE_CODE_TX_SME_MSG, psessionEntry->peSessionId, msgQ.type)); + + if (ProbeReqIELen > sizeof(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE)) + ProbeReqIELen = sizeof(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE); + pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIELen = (tANI_U16)ProbeReqIELen; vos_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE, pProbeReqIE, ProbeReqIELen); diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h index 4fb961c3cebb7..3dd987b1fa9ad 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h @@ -48,6 +48,11 @@ SIR_MAC_WEP_ICV_LENGTH + \ SIR_MAC_CHALLENGE_ID_LEN) +#define LIM_ENCR_AUTH_BODY_LEN_SAP (SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + \ + SIR_MAC_CHALLENGE_ID_LEN + \ + SIR_MAC_AUTH_FRAME_INFO_LEN + \ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH) struct tLimPreAuthNode; tANI_U8 limIsAuthAlgoSupported(tpAniSirGlobal, tAniAuthType, tpPESession); diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c index ac0def36471c6..162d7ed91acf2 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c @@ -3516,10 +3516,11 @@ limSendAuthMgmtFrame(tpAniSirGlobal pMac, * transaction number, status code and 128 bytes * for challenge text. */ - + bodyLen = SIR_MAC_AUTH_FRAME_INFO_LEN + + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + + SIR_MAC_CHALLENGE_ID_LEN; frameLen = sizeof(tSirMacMgmtHdr) + - sizeof(tSirMacAuthFrame); - bodyLen = sizeof(tSirMacAuthFrameBody); + bodyLen; } break; diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h index b8e98250a4be7..ba043dbdc4e65 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h @@ -833,8 +833,8 @@ void htt_rx_frag_ind_flush_seq_num_range( htt_pdev_handle pdev, adf_nbuf_t rx_frag_ind_msg, - int *seq_num_start, - int *seq_num_end); + u_int16_t *seq_num_start, + u_int16_t *seq_num_end); /** * @brief Return the HL rx desc size * @param pdev - the HTT instance the rx data was received on diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h index 7309db33dc865..517bf5f4b3175 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h @@ -76,6 +76,13 @@ struct ol_txrx_stats_req { } wait; }; +struct ol_txrx_stats_req_internal { + struct ol_txrx_stats_req base; + TAILQ_ENTRY(ol_txrx_stats_req_internal) req_list_elem; + int serviced; /* state of this request */ + int offset; +}; + #ifndef TXRX_DEBUG_LEVEL #define TXRX_DEBUG_LEVEL 0 /* no debug info */ #endif diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h index 0baafe0f6bdec..8d42b0f061146 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h @@ -617,8 +617,8 @@ ol_rx_pn_ind_handler( ol_txrx_pdev_handle pdev, u_int16_t peer_id, u_int8_t tid, - int seq_num_start, - int seq_num_end, + u_int16_t seq_num_start, + u_int16_t seq_num_end, u_int8_t pn_ie_cnt, u_int8_t *pn_ie); diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c index a6a88bf2754c8..caae8f0e3c2a5 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c @@ -245,7 +245,8 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, int usb_status; int i; struct HIFSendContext *pSendContext; - int frag_count = 0, head_data_len, tmp_frag_count = 0; + uint8_t frag_count; + uint32_t head_data_len, tmp_frag_count = 0; unsigned char *pData; AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_OUT, ("+%s pipe : %d, buf:0x%p\n", @@ -254,8 +255,15 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, a_mem_trace(buf); frag_count = adf_nbuf_get_num_frags(buf); - if (frag_count > 1) { /* means have extra fragment buf in skb */ - /* header data length should be total sending length substract + if (frag_count == 1) { + /* + * | HIFSendContext | netbuf->data + */ + head_data_len = sizeof(struct HIFSendContext); + } else if ((frag_count - 1) <= CVG_NBUF_MAX_EXTRA_FRAGS) { + /* + * means have extra fragment buf in skb + * header data length should be total sending length substract * internal data length of netbuf * | HIFSendContext | fragments except internal buffer | * netbuf->data @@ -268,10 +276,12 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, tmp_frag_count = tmp_frag_count + 1; } } else { - /* - * | HIFSendContext | netbuf->data - */ - head_data_len = sizeof(struct HIFSendContext); + /* Extra fragments overflow */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( + "%s Extra fragments count overflow : %d\n", + __func__, frag_count)); + status = A_ERROR; + goto exit; } /* Check whether head room is enough to save extra head data */ @@ -366,6 +376,7 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, } while (FALSE); +exit: if (A_FAILED(status) && (status != A_NO_RESOURCE)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb send failed %d\n", status)); diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 0d634a767da18..11aeea337a431 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -498,7 +498,7 @@ static bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, u_int8_t vdev_id) { struct wma_txrx_node *intf = wma->interfaces; - if (vdev_id > wma->max_bssid) { + if (vdev_id >= wma->max_bssid) { WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); VOS_ASSERT(0); return false; @@ -524,7 +524,7 @@ static bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, u_int8_t vdev_id) { struct wma_txrx_node *intf = wma->interfaces; - if (vdev_id > wma->max_bssid) { + if (vdev_id >= wma->max_bssid) { WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); VOS_ASSERT(0); return false; @@ -1141,6 +1141,11 @@ static int wma_vdev_start_resp_handler(void *handle, u_int8_t *cmd_param_info, return -EINVAL; } + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id received from firmware"); + return -EINVAL; + } + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) { adf_os_spin_lock_bh(&wma->dfs_ic->chan_lock); wma->dfs_ic->disable_phy_err_processing = false; @@ -1295,9 +1300,15 @@ static int wma_vdev_start_rsp_ind(tp_wma_handle wma, u_int8_t *buf) return -EINVAL; } + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + iface = &wma->interfaces[resp_event->vdev_id]; - if ((resp_event->vdev_id <= wma->max_bssid) && + if ((resp_event->vdev_id < wma->max_bssid) && (adf_os_atomic_read( &wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) && (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == true)) { @@ -1898,7 +1909,7 @@ static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) ol_txrx_vdev_handle vdev; ol_txrx_peer_handle peer, temp; - if (!wma || vdev_id > wma->max_bssid) + if (!wma || vdev_id >= wma->max_bssid) return; vdev = wma->interfaces[vdev_id].handle; @@ -1940,7 +1951,7 @@ static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id) ol_txrx_vdev_handle vdev; ol_txrx_peer_handle peer, temp; - if (!wma || vdev_id > wma->max_bssid) + if (!wma || vdev_id >= wma->max_bssid) return; vdev = wma->interfaces[vdev_id].handle; @@ -2138,7 +2149,7 @@ static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf) resp_event = (wmi_vdev_stopped_event_fixed_param *)buf; - if ((resp_event->vdev_id <= wma->max_bssid) && + if ((resp_event->vdev_id < wma->max_bssid) && (adf_os_atomic_read(&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) && ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && (wma->interfaces[resp_event->vdev_id].sub_type == 0))) { @@ -2177,7 +2188,7 @@ static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf) tpDeleteBssParams params = (tpDeleteBssParams)req_msg->user_data; struct beacon_info *bcn; - if (resp_event->vdev_id > wma->max_bssid) { + if (resp_event->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: Invalid vdev_id %d", __func__, resp_event->vdev_id); vos_mem_free(params); @@ -3929,7 +3940,7 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, wmi_extscan_wlan_descriptor *src_hotlist; uint32_t numap; int j, ap_found = 0; - + uint32_t buf_len; tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context( VOS_MODULE_ID_PE, wma->vos_context); if (!pMac) { @@ -3959,6 +3970,13 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, __func__, numap); numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES; } + buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) + + WMI_TLV_HDR_SIZE + + (numap * sizeof(wmi_extscan_wlan_descriptor)); + if (buf_len > len) { + WMA_LOGE("Invalid buf len from FW %d numap %d", len, numap); + return -EINVAL; + } dest_hotlist = vos_mem_malloc(sizeof(*dest_hotlist) + sizeof(*dest_ap) * numap); if (!dest_hotlist) { @@ -3994,6 +4012,11 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, dest_ap->ieLength = src_hotlist-> ie_length; WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, dest_ap->bssid); + if (src_hotlist->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGE("%s Invalid SSID len %d, truncating", + __func__, src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + } vos_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, src_hotlist->ssid.ssid_len); dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; @@ -4168,6 +4191,13 @@ static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, ap->bssid); + if (src_hotlist->ssid.ssid_len > + SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGD("%s Invalid SSID len %d, truncating", + __func__, src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = + SIR_MAC_MAX_SSID_LENGTH; + } vos_mem_copy(ap->ssid, src_hotlist->ssid.ssid, src_hotlist->ssid.ssid_len); ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; @@ -4476,9 +4506,13 @@ static int wma_passpoint_match_event_handler(void *handle, WMA_SVC_MSG_MAX_SIZE) { WMA_LOGE("IE Length: %d or ANQP Length: %d is huge", event->ie_length, event->anqp_length); - VOS_ASSERT(0); return -EINVAL; } + if (event->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGD("%s: Invalid ssid len %d, truncating", + __func__, event->ssid.ssid_len); + event->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + } dest_match = vos_mem_malloc(sizeof(*dest_match) + event->ie_length + event->anqp_length); if (!dest_match) { @@ -4570,6 +4604,11 @@ static int wma_unified_link_iface_stats_event_handler(void *handle, WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__); return -EINVAL; } + if (link_stats->num_ac > WIFI_AC_MAX) { + WMA_LOGE("%s: Excess data received from firmware num_ac %d", + __func__, link_stats->num_ac); + return -EINVAL; + } link_stats_size = sizeof(tSirWifiIfaceStat); iface_info_size = sizeof(tSirWifiInterfaceInfo); @@ -5342,6 +5381,12 @@ static void wma_send_bcn_buf_ll(tp_wma_handle wma, WMA_LOGE("%s: Invalid beacon buffer", __func__); return; } + if (WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info) > + WMI_P2P_MAX_NOA_DESCRIPTORS) { + WMA_LOGE("%s: Too many descriptors %d", __func__, + WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info)); + return; + } wmi_buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd)); if (!wmi_buf) { @@ -5968,6 +6013,12 @@ static int wma_p2p_noa_event_handler(void *handle, u_int8_t *event, u_int32_t le descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); noa_ie.num_descriptors = (u_int8_t)descriptors; + if (noa_ie.num_descriptors > WMA_MAX_NOA_DESCRIPTORS) { + WMA_LOGD("Sizing down the no of desc %d to max", + noa_ie.num_descriptors); + noa_ie.num_descriptors = WMA_MAX_NOA_DESCRIPTORS; + } + WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, " "num_descriptors = %u", __func__, noa_ie.index, noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); @@ -6284,7 +6335,8 @@ static int wma_nan_rsp_event_handler(void *handle, u_int8_t *event_buf, alloc_len = sizeof(tSirNanEvent); alloc_len += nan_rsp_event_hdr->data_len; if (nan_rsp_event_hdr->data_len > ((WMA_SVC_MSG_MAX_SIZE - - sizeof(*nan_rsp_event_hdr)) / sizeof(u_int8_t))) { + sizeof(*nan_rsp_event_hdr)) / sizeof(u_int8_t)) || + nan_rsp_event_hdr->data_len > param_buf->num_data) { WMA_LOGE("excess data length:%d", nan_rsp_event_hdr->data_len); VOS_ASSERT(0); return -EINVAL; @@ -9759,7 +9811,7 @@ VOS_STATUS wma_start_scan(tp_wma_handle wma_handle, int len; tSirScanOffloadEvent *scan_event; - if (scan_req->sessionId > wma_handle->max_bssid) { + if (scan_req->sessionId >= wma_handle->max_bssid) { WMA_LOGE("%s: Invalid vdev_id %d, msg_type : 0x%x", __func__, scan_req->sessionId, msg_type); goto error1; @@ -12730,7 +12782,7 @@ void wma_vdev_resp_timer(void *data) struct beacon_info *bcn; struct wma_txrx_node *iface; - if (tgt_req->vdev_id > wma->max_bssid) { + if (tgt_req->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: Invalid vdev_id %d", __func__, tgt_req->vdev_id); vos_mem_free(params); @@ -21467,19 +21519,18 @@ static int wma_wow_wakeup_host_event(void *handle, u_int8_t *event, wake_info = param_buf->fixed_param; - if ((wake_info->wake_reason != WOW_REASON_UNSPECIFIED) || - (wake_info->wake_reason == WOW_REASON_UNSPECIFIED && - !wmi_get_runtime_pm_inprogress(wma->wmi_handle))) { + if (!wmi_get_runtime_pm_inprogress(wma->wmi_handle)) { if (wake_info->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: received invalid vdev_id %d", __func__, wake_info->vdev_id); return -EINVAL; } - WMA_LOGA("WOW wakeup host event received (reason: %s(%d)) for vdev %d", + + WMA_LOGA("WOW (%d) %s vdev:%d", + wake_info->wake_reason, wma_wow_wake_reason_str(wake_info->wake_reason, wma), wake_info->wake_reason, wake_info->vdev_id); - vos_wow_wakeup_host_event(wake_info->wake_reason); } vos_event_set(&wma->wma_resume_event); @@ -21531,6 +21582,12 @@ static int wma_wow_wakeup_host_event(void *handle, u_int8_t *event, #ifdef FEATURE_WLAN_SCAN_PNO case WOW_REASON_NLOD: wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_NLOD); + if (wake_info->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, wake_info->vdev_id); + return -EINVAL; + } + node = &wma->interfaces[wake_info->vdev_id]; if (node) { WMA_LOGD("NLO match happened"); @@ -23194,7 +23251,7 @@ static VOS_STATUS wma_wow_enter(tp_wma_handle wma, WMA_LOGD("wow enable req received for vdev id: %d", info->sessionId); - if (info->sessionId > wma->max_bssid) { + if (info->sessionId >= wma->max_bssid) { WMA_LOGE("Invalid vdev id (%d)", info->sessionId); vos_mem_free(info); return VOS_STATUS_E_INVAL; @@ -23221,7 +23278,7 @@ static VOS_STATUS wma_wow_exit(tp_wma_handle wma, WMA_LOGD("wow disable req received for vdev id: %d", info->sessionId); - if (info->sessionId > wma->max_bssid) { + if (info->sessionId >= wma->max_bssid) { WMA_LOGE("Invalid vdev id (%d)", info->sessionId); vos_mem_free(info); return VOS_STATUS_E_INVAL; @@ -23254,7 +23311,7 @@ static VOS_STATUS wma_suspend_req(tp_wma_handle wma, tpSirWlanSuspendParam info) wma->no_of_suspend_ind++; - if (info->sessionId > wma->max_bssid) { + if (info->sessionId >= wma->max_bssid) { WMA_LOGE("Invalid vdev id (%d)", info->sessionId); vos_mem_free(info); return VOS_STATUS_E_INVAL; @@ -31757,6 +31814,11 @@ static int wma_nlo_match_evt_handler(void *handle, u_int8_t *event, nlo_event = param_buf->fixed_param; WMA_LOGD("PNO match event received for vdev %d", nlo_event->vdev_id); + if (nlo_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id in the NLO event %d", + nlo_event->vdev_id); + return -EINVAL; + } node = &wma->interfaces[nlo_event->vdev_id]; if (node) @@ -31905,7 +31967,8 @@ static int wma_mcc_vdev_tx_pause_evt_handler(void *handle, u_int8_t *event, /* FW mapped vdev from ID * vdev_map = (1 << vdev_id) * So, host should unmap to ID */ - for (vdev_id = 0; vdev_map != 0; vdev_id++) + for (vdev_id = 0; vdev_map != 0 && vdev_id < wma->max_bssid; + vdev_id++) { if (!(vdev_map & 0x1)) { @@ -35108,6 +35171,14 @@ wma_process_utf_event(WMA_HANDLE handle, currentSeq); } + if ((datalen > MAX_UTF_EVENT_LENGTH) || + (wma_handle->utf_event_info.offset > + (MAX_UTF_EVENT_LENGTH - datalen))) { + WMA_LOGE("Excess data from firmware, offset:%zu, len:%d", + wma_handle->utf_event_info.offset, datalen); + return -EINVAL; + } + memcpy(&wma_handle->utf_event_info.data[wma_handle->utf_event_info.offset], &data[sizeof(segHdrInfo)], datalen); diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h index f8f2028f79df4..c210ec094fa6b 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h @@ -101,6 +101,8 @@ #define FRAGMENT_SIZE 3072 +#define WMA_MAX_MGMT_MPDU_LEN 2000 + #define WMA_INVALID_VDEV_ID 0xFF #define MAX_MEM_CHUNKS 32 #define WMA_MAX_VDEV_SIZE 20 diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c index 2d2909e6b3912..f5ea7ac92498f 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c @@ -1138,7 +1138,7 @@ void wma_delete_all_nan_remote_peers(tp_wma_handle wma, uint32_t vdev_id) ol_txrx_vdev_handle vdev; ol_txrx_peer_handle peer, temp; - if (!wma || vdev_id > wma->max_bssid) + if (!wma || vdev_id >= wma->max_bssid) return; vdev = wma->interfaces[vdev_id].handle; diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c index a3c470b678a0d..ed6db1766188b 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -78,6 +78,8 @@ static struct ath_pktlog_info *g_pktlog_info; static struct proc_dir_entry *g_pktlog_pde; +static DEFINE_MUTEX(proc_mutex); + static int pktlog_attach(struct ol_softc *sc); static void pktlog_detach(struct ol_softc *sc); static int pktlog_open(struct inode *i, struct file *f); @@ -226,9 +228,11 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ol_ath_generic_softc_handle scn; struct ol_pktlog_dev_t *pl_dev; + mutex_lock(&proc_mutex); scn = (ol_ath_generic_softc_handle) ctl->extra1; if (!scn) { + mutex_unlock(&proc_mutex); printk("%s: Invalid scn context\n", __func__); ASSERT(0); return -EINVAL; @@ -237,6 +241,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, pl_dev = get_pl_handle((struct ol_softc *)scn); if (!pl_dev) { + mutex_unlock(&proc_mutex); printk("%s: Invalid pktlog context\n", __func__); ASSERT(0); return -ENODEV; @@ -266,6 +271,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ctl->data = NULL; ctl->maxlen = 0; + mutex_unlock(&proc_mutex); return ret; } @@ -283,9 +289,11 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ol_ath_generic_softc_handle scn; struct ol_pktlog_dev_t *pl_dev; + mutex_lock(&proc_mutex); scn = (ol_ath_generic_softc_handle) ctl->extra1; if (!scn) { + mutex_unlock(&proc_mutex); printk("%s: Invalid scn context\n", __func__); ASSERT(0); return -EINVAL; @@ -294,6 +302,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, pl_dev = get_pl_handle((struct ol_softc *)scn); if (!pl_dev) { + mutex_unlock(&proc_mutex); printk("%s: Invalid pktlog handle\n", __func__); ASSERT(0); return -ENODEV; @@ -318,6 +327,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ctl->data = NULL; ctl->maxlen = 0; + mutex_unlock(&proc_mutex); return ret; } diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c index 3db0b8758af21..79c7dc81915be 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c @@ -307,6 +307,10 @@ process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, */ txctl_log.priv.frm_hdr = frm_hdr; adf_os_assert(txctl_log.priv.txdesc_ctl); + adf_os_assert(pl_hdr.size < sizeof(txctl_log.priv.txdesc_ctl)); + pl_hdr.size = (pl_hdr.size > sizeof(txctl_log.priv.txdesc_ctl)) + ? sizeof(txctl_log.priv.txdesc_ctl) : + pl_hdr.size; adf_os_mem_copy((void *)&txctl_log.priv.txdesc_ctl, ((void *)data + sizeof(struct ath_pktlog_hdr)), pl_hdr.size); diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index eb0490a9cad81..ead9765666c84 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -268,6 +268,7 @@ static long msm_thermal_process_voltage_table_req( voltage->voltage_table[idx] = voltage_table_ptr[cluster_id][table_idx]; } + voltage->voltage_table_len = idx; copy_and_return: ret = copy_to_user((void __user *)(*arg), query, diff --git a/drivers/usb/dwc3/dbm-1_4.c b/drivers/usb/dwc3/dbm-1_4.c index 661a938e055c5..1caf7983f60f4 100644 --- a/drivers/usb/dwc3/dbm-1_4.c +++ b/drivers/usb/dwc3/dbm-1_4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -372,7 +372,6 @@ static int msm_dbm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dbm *dbm; struct resource *res; - int ret = 0; dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL); if (!dbm_data) @@ -382,24 +381,21 @@ static int msm_dbm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory base resource\n"); - ret = -ENODEV; - goto free_dbm_data; + return -ENODEV; } dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!dbm_data->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL); if (!dbm) { dev_err(&pdev->dev, "not enough memory\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm->dev = dev; @@ -418,20 +414,6 @@ static int msm_dbm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dbm); return usb_add_dbm(dbm); - -free_dbm_data: - kfree(dbm_data); - return ret; -} - -static int msm_dbm_remove(struct platform_device *pdev) -{ - struct dbm *dbm = platform_get_drvdata(pdev); - - kfree(dbm); - kfree(dbm_data); - - return 0; } static const struct of_device_id msm_dbm_1_4_id_table[] = { @@ -444,7 +426,6 @@ MODULE_DEVICE_TABLE(of, msm_dbm_1_4_id_table); static struct platform_driver msm_dbm_driver = { .probe = msm_dbm_probe, - .remove = msm_dbm_remove, .driver = { .name = "msm-usb-dbm-1-4", .of_match_table = of_match_ptr(msm_dbm_1_4_id_table), diff --git a/drivers/usb/dwc3/dbm-1_5.c b/drivers/usb/dwc3/dbm-1_5.c index 2a3609ef6ffb6..7f6c5f0bfe15d 100644 --- a/drivers/usb/dwc3/dbm-1_5.c +++ b/drivers/usb/dwc3/dbm-1_5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -387,7 +387,6 @@ static int msm_dbm_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct dbm *dbm; struct resource *res; - int ret = 0; dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL); if (!dbm_data) @@ -397,24 +396,21 @@ static int msm_dbm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory base resource\n"); - ret = -ENODEV; - goto free_dbm_data; + return -ENODEV; } dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!dbm_data->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL); if (!dbm) { dev_err(&pdev->dev, "not enough memory\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm_data->dbm_reset_ep_after_lpm = of_property_read_bool(node, @@ -437,20 +433,6 @@ static int msm_dbm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dbm); return usb_add_dbm(dbm); - -free_dbm_data: - kfree(dbm_data); - return ret; -} - -static int msm_dbm_remove(struct platform_device *pdev) -{ - struct dbm *dbm = platform_get_drvdata(pdev); - - kfree(dbm); - kfree(dbm_data); - - return 0; } static const struct of_device_id msm_dbm_1_5_id_table[] = { @@ -463,7 +445,6 @@ MODULE_DEVICE_TABLE(of, msm_dbm_1_5_id_table); static struct platform_driver msm_dbm_driver = { .probe = msm_dbm_probe, - .remove = msm_dbm_remove, .driver = { .name = "msm-usb-dbm-1-5", .of_match_table = of_match_ptr(msm_dbm_1_5_id_table), diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 04851ab4796a4..f0df6eee63ca0 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -653,7 +653,7 @@ static ssize_t dwc3_store_ep_num(struct file *file, const char __user *ubuf, unsigned int num, dir, temp; unsigned long flags; - if (copy_from_user(kbuf, ubuf, count > 10 ? 10 : count)) + if (copy_from_user(kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) return -EFAULT; if (sscanf(kbuf, "%u %u", &num, &dir) != 2) diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c index 69d1644877f2e..bcb44e5b00f2a 100755 --- a/drivers/video/msm/mdss/mdss_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_dsi_panel.c @@ -2048,19 +2048,24 @@ static int mdss_dsi_panel_parse_display_timings(struct device_node *np, timings_np = of_get_child_by_name(np, "qcom,mdss-dsi-display-timings"); if (!timings_np) { - struct dsi_panel_timing pt; - memset(&pt, 0, sizeof(struct dsi_panel_timing)); + struct dsi_panel_timing *pt; + + pt = kzalloc(sizeof(*pt), GFP_KERNEL); + if (!pt) + return -ENOMEM; /* * display timings node is not available, fallback to reading * timings directly from root node instead */ pr_debug("reading display-timings from panel node\n"); - rc = mdss_dsi_panel_timing_from_dt(np, &pt); + rc = mdss_dsi_panel_timing_from_dt(np, pt); if (!rc) { mdss_dsi_panel_config_res_properties(np, - panel_data->panel_info.sim_panel_mode, &pt); - rc = mdss_dsi_panel_timing_switch(ctrl, &pt.timing); + panel_data->panel_info.sim_panel_mode, pt); + rc = mdss_dsi_panel_timing_switch(ctrl, &pt->timing); + } else { + kfree(pt); } return rc; } diff --git a/fs/buffer.c b/fs/buffer.c index 963b348199007..c36b69324ada5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1263,7 +1263,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh) * a local interrupt disable for that. */ -#define BH_LRU_SIZE 8 +#define BH_LRU_SIZE 16 struct bh_lru { struct buffer_head *bhs[BH_LRU_SIZE]; diff --git a/fs/dcache.c b/fs/dcache.c index dcb875bdd1ab3..aa42c7930c14d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -211,15 +211,49 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c return dentry_string_cmp(cs, ct, tcount); } +struct external_name { + union { + atomic_t count; + struct rcu_head head; + } u; + unsigned char name[]; +}; + +static inline struct external_name *external_name(struct dentry *dentry) +{ + return container_of(dentry->d_name.name, struct external_name, name[0]); +} + static void __d_free(struct rcu_head *head) { struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); - if (dname_external(dentry)) - kfree(dentry->d_name.name); kmem_cache_free(dentry_cache, dentry); } +static void __d_free_external(struct rcu_head *head) +{ + struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); + kfree(external_name(dentry)); + kmem_cache_free(dentry_cache, dentry); +} + +static void dentry_free(struct dentry *dentry) +{ + if (unlikely(dname_external(dentry))) { + struct external_name *p = external_name(dentry); + if (likely(atomic_dec_and_test(&p->u.count))) { + call_rcu(&dentry->d_u.d_rcu, __d_free_external); + return; + } + } + /* if dentry was never visible to RCU, immediate free is OK */ + if (!(dentry->d_flags & DCACHE_RCUACCESS)) + __d_free(&dentry->d_u.d_rcu); + else + call_rcu(&dentry->d_u.d_rcu, __d_free); +} + /* * no locks, please. */ @@ -231,11 +265,7 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - /* if dentry was never visible to RCU, immediate free is OK */ - if (!(dentry->d_flags & DCACHE_RCUACCESS)) - __d_free(&dentry->d_u.d_rcu); - else - call_rcu(&dentry->d_u.d_rcu, __d_free); + dentry_free(dentry); } void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) @@ -1295,11 +1325,14 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) */ dentry->d_iname[DNAME_INLINE_LEN-1] = 0; if (name->len > DNAME_INLINE_LEN-1) { - dname = kmalloc(name->len + 1, GFP_KERNEL); - if (!dname) { + size_t size = offsetof(struct external_name, name[1]); + struct external_name *p = kmalloc(size + name->len, GFP_KERNEL); + if (!p) { kmem_cache_free(dentry_cache, dentry); return NULL; } + atomic_set(&p->u.count, 1); + dname = p->name; } else { dname = dentry->d_iname; } @@ -2191,8 +2224,8 @@ EXPORT_SYMBOL(dentry_update_name_case); static void switch_names(struct dentry *dentry, struct dentry *target) { - if (dname_external(target)) { - if (dname_external(dentry)) { + if (unlikely(dname_external(target))) { + if (unlikely(dname_external(dentry))) { /* * Both external: swap the pointers */ @@ -2208,7 +2241,7 @@ static void switch_names(struct dentry *dentry, struct dentry *target) target->d_name.name = target->d_iname; } } else { - if (dname_external(dentry)) { + if (unlikely(dname_external(dentry))) { /* * dentry:external, target:internal. Give dentry's * storage to target and make dentry internal @@ -2230,6 +2263,25 @@ static void switch_names(struct dentry *dentry, struct dentry *target) swap(dentry->d_name.len, target->d_name.len); } +static void copy_name(struct dentry *dentry, struct dentry *target) +{ + struct external_name *old_name = NULL; + if (unlikely(dname_external(dentry))) + old_name = external_name(dentry); + if (unlikely(dname_external(target))) { + atomic_inc(&external_name(target)->u.count); + dentry->d_name = target->d_name; + } else { + memcpy(dentry->d_iname, target->d_name.name, + target->d_name.len + 1); + dentry->d_name.name = dentry->d_iname; + dentry->d_name.len = target->d_name.len; + } + if (old_name && likely(atomic_dec_and_test(&old_name->u.count))) + kfree_rcu(old_name, u.head); +} + + static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) { /* @@ -2316,7 +2368,7 @@ static void __d_move(struct dentry * dentry, struct dentry * target) list_del(&target->d_child); /* Switch the names.. */ - switch_names(dentry, target); + copy_name(dentry, target); swap(dentry->d_name.hash, target->d_name.hash); /* ... and switch the parents */ diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 8a35955534ab3..e33707897cbcc 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -51,7 +51,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) * whether the base obbpath has been changed or not */ if (is_obbpath_invalid(dentry)) { - d_drop(dentry); return 0; } @@ -65,7 +64,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) { err = lower_dentry->d_op->d_revalidate(lower_dentry, flags); if (err == 0) { - d_drop(dentry); goto out; } } @@ -73,14 +71,12 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) spin_lock(&lower_dentry->d_lock); if (d_unhashed(lower_dentry)) { spin_unlock(&lower_dentry->d_lock); - d_drop(dentry); err = 0; goto out; } spin_unlock(&lower_dentry->d_lock); if (parent_lower_dentry != lower_cur_parent_dentry) { - d_drop(dentry); err = 0; goto out; } @@ -94,7 +90,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) } if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) { - __d_drop(dentry); err = 0; } @@ -113,7 +108,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if (inode) { data = top_data_get(SDCARDFS_I(inode)); if (!data || data->abandoned) { - d_drop(dentry); err = 0; } if (data) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index ccca427679deb..7386e1b49d759 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -270,6 +270,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct dentry *lower_dentry; struct vfsmount *lower_mnt; struct dentry *lower_parent_dentry = NULL; + struct dentry *parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; @@ -289,11 +290,14 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* check disk space */ - if (!check_min_free_space(dentry, 0, 1)) { + parent_dentry = dget_parent(dentry); + if (!check_min_free_space(parent_dentry, 0, 1)) { pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; + dput(parent_dentry); goto out_revert; } + dput(parent_dentry); /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); diff --git a/fs/sync.c b/fs/sync.c index 1022b89727e5f..4e93b274a2c18 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -205,6 +205,7 @@ static int do_fsync(unsigned int fd, int datasync) if (f.file) { ret = vfs_fsync(f.file, datasync); fdput(f); + inc_syscfs(current); } return ret; } diff --git a/include/linux/ktime.h b/include/linux/ktime.h index e6aacdbebafda..638794b816ef2 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -71,13 +71,12 @@ typedef union ktime ktime_t; /* Kill this */ * * Return the ktime_t representation of the value */ -static inline ktime_t ktime_set(const long secs, const unsigned long nsecs) +static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs) { -#if (BITS_PER_LONG == 64) if (unlikely(secs >= KTIME_SEC_MAX)) return (ktime_t){ .tv64 = KTIME_MAX }; -#endif - return (ktime_t) { .tv64 = (s64)secs * NSEC_PER_SEC + (s64)nsecs }; + + return (ktime_t) { .tv64 = secs * NSEC_PER_SEC + (s64)nsecs }; } /* Subtract two ktime_t variables. rem = lhs -rhs: */ @@ -317,6 +316,30 @@ static inline u64 ktime_divns(const ktime_t kt, s64 div) # define ktime_divns(kt, div) (u64)((kt).tv64 / (div)) #endif +/** + * ktime_after - Compare if a ktime_t value is bigger than another one. + * @cmp1: comparable1 + * @cmp2: comparable2 + * + * Return: true if cmp1 happened after cmp2. + */ +static inline bool ktime_after(const ktime_t cmp1, const ktime_t cmp2) +{ + return ktime_compare(cmp1, cmp2) > 0; +} + +/** + * ktime_before - Compare if a ktime_t value is smaller than another one. + * @cmp1: comparable1 + * @cmp2: comparable2 + * + * Return: true if cmp1 happened before cmp2. + */ +static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2) +{ + return ktime_compare(cmp1, cmp2) < 0; +} + static inline s64 ktime_to_us(const ktime_t kt) { return ktime_divns(kt, NSEC_PER_USEC); diff --git a/include/linux/sched.h b/include/linux/sched.h index 3bf2401492365..aeb29890c8d57 100755 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -3231,6 +3231,11 @@ static inline void inc_syscw(struct task_struct *tsk) { tsk->ioac.syscw++; } + +static inline void inc_syscfs(struct task_struct *tsk) +{ + tsk->ioac.syscfs++; +} #else static inline void add_rchar(struct task_struct *tsk, ssize_t amt) { @@ -3247,6 +3252,9 @@ static inline void inc_syscr(struct task_struct *tsk) static inline void inc_syscw(struct task_struct *tsk) { } +static inline void inc_syscfs(struct task_struct *tsk) +{ +} #endif #ifndef TASK_SIZE_OF diff --git a/include/linux/task_io_accounting.h b/include/linux/task_io_accounting.h index bdf855c2856fb..2dd338fdf8815 100644 --- a/include/linux/task_io_accounting.h +++ b/include/linux/task_io_accounting.h @@ -18,6 +18,8 @@ struct task_io_accounting { u64 syscr; /* # of write syscalls */ u64 syscw; + /* # of fsync syscalls */ + u64 syscfs; #endif /* CONFIG_TASK_XACCT */ #ifdef CONFIG_TASK_IO_ACCOUNTING diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h index 4d090f9ee6087..1b505c804af34 100644 --- a/include/linux/task_io_accounting_ops.h +++ b/include/linux/task_io_accounting_ops.h @@ -96,6 +96,7 @@ static inline void task_chr_io_accounting_add(struct task_io_accounting *dst, dst->wchar += src->wchar; dst->syscr += src->syscr; dst->syscw += src->syscw; + dst->syscfs += src->syscfs; } #else static inline void task_chr_io_accounting_add(struct task_io_accounting *dst, diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 42d830afcf672..4c0e95b47213f 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -397,6 +397,7 @@ struct snd_pcm_substream { struct snd_pcm_ops *ops; /* -- runtime information -- */ struct snd_pcm_runtime *runtime; + spinlock_t runtime_lock; /* -- timer section -- */ struct snd_timer *timer; /* timer */ unsigned timer_running: 1; /* time is running */ diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index aac13eef45830..fae2e05552280 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -107,6 +107,13 @@ struct qseecom_qseos_version_req { unsigned int qseos_version; /* in */ }; +/* + * struct qseecom_qsee_version_req - get qsee version + * @qsee_version - version number + */ +struct qseecom_qsee_version_req { + unsigned int qsee_version; +}; /* * struct qseecom_qseos_app_load_query - verify if app is loaded in qsee * @app_name[MAX_APP_NAME_SIZE]- name of the app. @@ -293,4 +300,6 @@ extern long qseecom_ioctl(struct file *file, #define QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 33, struct qseecom_qteec_modfd_req) +#define QSEECOM_IOCTL_GET_QSEE_VERSION_REQ \ + _IOWR(QSEECOM_IOC_MAGIC, 37, struct qseecom_qsee_version_req) #endif /* _UAPI_QSEECOM_H_ */ diff --git a/kernel/futex.c b/kernel/futex.c index 191a280d1275e..800994c0b388f 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -254,6 +254,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) return -EINVAL; address -= key->both.offset; + if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) + return -EFAULT; + /* * PROCESS_PRIVATE futexes are fast. * As the mm cannot disappear under us and the 'key' only needs @@ -262,8 +265,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) * but access_ok() should be faster than find_vma() */ if (!fshared) { - if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) - return -EFAULT; key->private.mm = mm; key->private.address = address; get_futex_key_refs(key); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index bbd1dee81fdd8..116b2276032cc 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -480,6 +480,7 @@ void destroy_hrtimer_on_stack(struct hrtimer *timer) { debug_object_free(timer, &hrtimer_debug_descr); } +EXPORT_SYMBOL_GPL(destroy_hrtimer_on_stack); #else static inline void debug_hrtimer_init(struct hrtimer *timer) { } diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 6651a7797d46a..924af39089ead 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -2010,7 +2010,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, if (match_kern) match_kern->match_size = ret; - WARN_ON(type == EBT_COMPAT_TARGET && size_left); + if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) + return -EINVAL; + match32 = (struct compat_ebt_entry_mwt *) buf; } @@ -2067,6 +2069,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, * * offsets are relative to beginning of struct ebt_entry (i.e., 0). */ + for (i = 0; i < 4 ; ++i) { + if (offsets[i] >= *total) + return -EINVAL; + if (i == 0) + continue; + if (offsets[i-1] > offsets[i]) + return -EINVAL; + } + for (i = 0, j = 1 ; j < 4 ; j++, i++) { struct compat_ebt_entry_mwt *match32; unsigned int size; diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c index ffc67fd80c23d..58e59cd3c95c0 100644 --- a/sound/isa/msnd/msnd_midi.c +++ b/sound/isa/msnd/msnd_midi.c @@ -120,24 +120,24 @@ void snd_msndmidi_input_read(void *mpuv) unsigned long flags; struct snd_msndmidi *mpu = mpuv; void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF; + u16 head, tail, size; spin_lock_irqsave(&mpu->input_lock, flags); - while (readw(mpu->dev->MIDQ + JQS_wTail) != - readw(mpu->dev->MIDQ + JQS_wHead)) { - u16 wTmp, val; - val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead)); - - if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, - &mpu->mode)) - snd_rawmidi_receive(mpu->substream_input, - (unsigned char *)&val, 1); - - wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1; - if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize)) - writew(0, mpu->dev->MIDQ + JQS_wHead); - else - writew(wTmp, mpu->dev->MIDQ + JQS_wHead); + head = readw(mpu->dev->MIDQ + JQS_wHead); + tail = readw(mpu->dev->MIDQ + JQS_wTail); + size = readw(mpu->dev->MIDQ + JQS_wSize); + if (head > size || tail > size) + goto out; + while (head != tail) { + unsigned char val = readw(pwMIDQData + 2 * head); + + if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) + snd_rawmidi_receive(mpu->substream_input, &val, 1); + if (++head > size) + head = 0; + writew(head, mpu->dev->MIDQ + JQS_wHead); } + out: spin_unlock_irqrestore(&mpu->input_lock, flags); } EXPORT_SYMBOL(snd_msndmidi_input_read); diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 3a7946ebbe238..f7659ecbba0d8 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -170,23 +170,24 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id) { struct snd_msnd *chip = dev_id; void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF; + u16 head, tail, size; /* Send ack to DSP */ /* inb(chip->io + HP_RXL); */ /* Evaluate queued DSP messages */ - while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) { - u16 wTmp; - - snd_msnd_eval_dsp_msg(chip, - readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead))); - - wTmp = readw(chip->DSPQ + JQS_wHead) + 1; - if (wTmp > readw(chip->DSPQ + JQS_wSize)) - writew(0, chip->DSPQ + JQS_wHead); - else - writew(wTmp, chip->DSPQ + JQS_wHead); + head = readw(chip->DSPQ + JQS_wHead); + tail = readw(chip->DSPQ + JQS_wTail); + size = readw(chip->DSPQ + JQS_wSize); + if (head > size || tail > size) + goto out; + while (head != tail) { + snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head)); + if (++head > size) + head = 0; + writew(head, chip->DSPQ + JQS_wHead); } + out: /* Send ack to DSP */ inb(chip->io + HP_RXL); return IRQ_HANDLED; diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 965caf8d4e8a1..a433bd2b18dcd 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -290,6 +290,14 @@ static int wcd_cpe_load_each_segment(struct wcd_cpe_core *core, goto done; } + if (phdr->p_filesz != split_fw->size) { + dev_err(core->dev, + "%s: %s size mismatch, phdr_size: 0x%x fw_size: 0x%zx", + __func__, split_fname, phdr->p_filesz, split_fw->size); + ret = -EINVAL; + goto done; + } + segment->cpe_addr = phdr->p_paddr; segment->size = phdr->p_filesz; segment->data = (u8 *) split_fw->data; diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index fa27343fd2d20..c3d3814272b5b 100755 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -60,8 +60,13 @@ struct asm_mmap { }; static struct asm_mmap this_mmap; + +struct audio_session { + struct audio_client *ac; + spinlock_t session_lock; +}; /* session id: 0 reserved */ -static struct audio_client *session[SESSION_MAX+1]; +static struct audio_session session[SESSION_MAX + 1]; struct asm_no_wait_node { struct list_head list; @@ -408,8 +413,8 @@ static int q6asm_session_alloc(struct audio_client *ac) { int n; for (n = 1; n <= SESSION_MAX; n++) { - if (!session[n]) { - session[n] = ac; + if (!session[n].ac) { + session[n].ac = ac; return n; } } @@ -417,34 +422,41 @@ static int q6asm_session_alloc(struct audio_client *ac) return -ENOMEM; } -static bool q6asm_is_valid_audio_client(struct audio_client *ac) +static unsigned int q6asm_get_session_id_from_audio_client( + struct audio_client *ac) { - int n; + unsigned int n; + for (n = 1; n <= SESSION_MAX; n++) { - if (session[n] == ac) - return 1; + if (session[n].ac == ac) + return n; } return 0; } +static bool q6asm_is_valid_audio_client(struct audio_client *ac) +{ + return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0; +} + static void q6asm_session_free(struct audio_client *ac) { - struct list_head *ptr, *next; - struct asm_no_wait_node *node; + int session_id; + unsigned long flags; pr_debug("%s: sessionid[%d]\n", __func__, ac->session); + session_id = ac->session; rtac_remove_popp_from_adm_devices(ac->session); - session[ac->session] = 0; + spin_lock_irqsave(&(session[session_id].session_lock), flags); + session[ac->session].ac = NULL; ac->session = 0; ac->perf_mode = LEGACY_PCM_MODE; ac->fptr_cache_ops = NULL; + ac->cb = NULL; + ac->priv = NULL; - list_for_each_safe(ptr, next, &ac->no_wait_que) { - node = list_entry(ptr, struct asm_no_wait_node, list); - list_del(&node->list); - kfree(node); - } - list_del(&ac->no_wait_que); + kfree(ac); + spin_unlock_irqrestore(&(session[session_id].session_lock), flags); return; } @@ -990,8 +1002,6 @@ void q6asm_audio_client_free(struct audio_client *ac) pr_debug("%s: APR De-Register\n", __func__); /*done:*/ - kfree(ac); - ac = NULL; mutex_unlock(&session_lock); return; @@ -1060,6 +1070,7 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) if (n <= 0) { pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n); mutex_unlock(&session_lock); + kfree(ac); goto fail_session; } ac->session = n; @@ -1137,7 +1148,6 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) fail_apr1: q6asm_session_free(ac); fail_session: - kfree(ac); return NULL; } @@ -1152,11 +1162,11 @@ struct audio_client *q6asm_get_audio_client(int session_id) goto err; } - if (!session[session_id]) { + if (!(session[session_id].ac)) { pr_err("%s: session not active: %d\n", __func__, session_id); goto err; } - return session[session_id]; + return session[session_id].ac; err: return NULL; } @@ -1361,6 +1371,7 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) uint32_t i = IN; uint32_t *payload; unsigned long dsp_flags; + unsigned long flags; struct asm_buffer_node *buf_node = NULL; struct list_head *ptr, *next; @@ -1409,9 +1420,16 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) return 0; } sid = (data->token >> 8) & 0x0F; + if ((sid > 0 && sid <= SESSION_MAX)) + spin_lock_irqsave(&(session[sid].session_lock), flags); + ac = q6asm_get_audio_client(sid); if (!ac) { pr_debug("%s: session[%d] already freed\n", __func__, sid); + if ((sid > 0 && + sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); return 0; } @@ -1461,6 +1479,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + if ((sid > 0 && + sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); return 0; } @@ -1496,6 +1518,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); + if ((sid > 0 && sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); + return 0; } @@ -1522,7 +1548,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) uint32_t *payload; uint32_t wakeup_flag = 1; int32_t ret = 0; - + unsigned long flags; + int session_id; if (ac == NULL) { pr_err("%s: ac NULL\n", __func__); @@ -1532,15 +1559,21 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_err("%s: data NULL\n", __func__); return -EINVAL; } - if (!q6asm_is_valid_audio_client(ac)) { - pr_err("%s: audio client pointer is invalid, ac = %pK\n", - __func__, ac); + + session_id = q6asm_get_session_id_from_audio_client(ac); + if (session_id <= 0) { + pr_err("%s: Session ID is invalid, session = %d\n", __func__, + session_id); return -EINVAL; } - if (ac->session <= 0 || ac->session > 8) { - pr_err("%s: Session ID is invalid, session = %d\n", __func__, - ac->session); + spin_lock_irqsave(&(session[session_id].session_lock), flags); + + if (!q6asm_is_valid_audio_client(ac)) { + pr_err("%s: audio client pointer is invalid, ac = %pK\n", + __func__, ac); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return -EINVAL; } @@ -1555,7 +1588,6 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } if (data->opcode == RESET_EVENTS) { - mutex_lock(&ac->cmd_lock); atomic_set(&ac->reset, 1); if (ac->apr == NULL) ac->apr = ac->apr2; @@ -1571,7 +1603,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->cmd_state, 0); wake_up(&ac->time_wait); wake_up(&ac->cmd_wait); - mutex_unlock(&ac->cmd_lock); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1582,9 +1615,16 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->dest_port); if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) && (data->opcode != ASM_DATA_EVENT_EOS) && - (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) + (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) { + if (payload == NULL) { + pr_err("%s: payload is null\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); + return -EINVAL; + } dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", __func__, payload[0], payload[1], data->opcode); + } if (data->opcode == APR_BASIC_RSP_RESULT) { token = data->token; switch (payload[0]) { @@ -1606,6 +1646,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) ret = q6asm_is_valid_session(data, priv); if (ret != 0) { pr_err("%s: session invalid %d\n", __func__, ret); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return ret; } case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2: @@ -1633,6 +1675,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->cmd_state, -payload[1]); wake_up(&ac->cmd_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->cmd_state) && wakeup_flag) { @@ -1653,6 +1698,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->mem_state, -payload[1]); wake_up(&ac->mem_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->mem_state) && wakeup_flag) { @@ -1689,6 +1737,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1702,6 +1753,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -1715,6 +1769,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0], payload[1]); spin_unlock_irqrestore(&port->dsp_lock, dsp_flags); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } token = data->token; @@ -1786,6 +1843,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->io_mode & SYNC_IO_MODE) { if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -1854,7 +1914,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); - + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1996,11 +2057,16 @@ int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac) static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id) { + unsigned long flags; + dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n", __func__, pkt_size, cmd_flg, ac->session, stream_id); mutex_lock(&ac->cmd_lock); + spin_lock_irqsave(&(session[ac->session].session_lock), flags); if (ac->apr == NULL) { pr_err("%s: AC APR handle NULL", __func__); + spin_unlock_irqrestore( + &(session[ac->session].session_lock), flags); mutex_unlock(&ac->cmd_lock); return; } @@ -2018,6 +2084,8 @@ static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, hdr->token = ac->session; } hdr->pkt_size = pkt_size; + spin_unlock_irqrestore( + &(session[ac->session].session_lock), flags); mutex_unlock(&ac->cmd_lock); return; } @@ -6510,7 +6578,7 @@ int q6asm_get_apr_service_id(int session_id) return -EINVAL; } - return ((struct apr_svc *)session[session_id]->apr)->id; + return ((struct apr_svc *)(session[session_id].ac)->apr)->id; } int q6asm_get_asm_topology(void) @@ -6728,7 +6796,10 @@ static int __init q6asm_init(void) int lcnt, ret; pr_debug("%s:\n", __func__); - memset(session, 0, sizeof(session)); + memset(session, 0, sizeof(struct audio_session) * + (SESSION_MAX + 1)); + for (lcnt = 0; lcnt <= SESSION_MAX; lcnt++) + spin_lock_init(&(session[lcnt].session_lock)); set_custom_topology = 1; /*setup common client used for cal mem map */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 83b13d6f6096b..5f5b4fb342a48 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3653,7 +3653,11 @@ int snd_soc_register_card(struct snd_soc_card *card) if (card->rtd == NULL) return -ENOMEM; card->num_rtd = 0; - card->rtd_aux = &card->rtd[card->num_links]; + + if (card->num_aux_devs > 0) + card->rtd_aux = &card->rtd[card->num_links]; + else + card->rtd_aux = NULL; for (i = 0; i < card->num_links; i++) card->rtd[i].dai_link = &card->dai_link[i];