diff options
author | Kevin Hilman <khilman@linaro.org> | 2015-06-24 10:40:17 -0700 |
---|---|---|
committer | Kevin Hilman <khilman@linaro.org> | 2015-06-24 10:40:17 -0700 |
commit | dae04c1c00f74dd21cce9d85ce90ff50b26d4741 (patch) | |
tree | dbdf5ba4cb6a362e14db7088abb34998a52382bc | |
parent | f5e3fc58ccc95572560d0beae9e4e7c1bd94ca6d (diff) | |
parent | 1b1c8d6849655e6924c453e5ad377157f65eb950 (diff) |
Merge branch 'linaro-android-3.10-lsk' of git://android.git.linaro.org/kernel/linaro-android into linux-linaro-lsk-v3.10-android
* 'linaro-android-3.10-lsk' of git://android.git.linaro.org/kernel/linaro-android:
sched: cpufreq: update power usage only if cpufreq_stat is enabled
uid_cputime: Extends the cputime functionality to report power per uid
sched: cpufreq: Adds a field cpu_power in the task_struct
cpufreq_stats: Adds the fucntionality to load current values for each frequency for all the cores.
android: drivers: workaround debugfs race in binder
neigh: Better handling of transition to NUD_PROBE state
New Build Breakage in branch: kernel-m-dev-tegra-flounder-3.10 @ 1960706
net/unix: sk_socket can disappear when state is unlocked
selinux: enable genfscon labeling for sysfs and pstore files
selinux: enable per-file labeling for debugfs files.
ext4: don't save the error information if the block device is read-only
suspend: Return error when pending wakeup source is found.
proc: uid_cputime: fix show_uid_stat permission
power: increment wakeup_count when save_wakeup_count failed.
power: validate wakeup source before activating it.
-rw-r--r-- | drivers/android/binder.c | 15 | ||||
-rw-r--r-- | drivers/base/power/wakeup.c | 35 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 186 | ||||
-rw-r--r-- | drivers/misc/uid_cputime.c | 14 | ||||
-rw-r--r-- | fs/ext4/super.c | 2 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 8 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/fork.c | 1 | ||||
-rw-r--r-- | kernel/power/suspend.c | 3 | ||||
-rw-r--r-- | kernel/sched/cputime.c | 11 | ||||
-rw-r--r-- | net/caif/caif_socket.c | 8 | ||||
-rw-r--r-- | net/core/neighbour.c | 3 | ||||
-rw-r--r-- | net/unix/af_unix.c | 8 | ||||
-rw-r--r-- | security/selinux/hooks.c | 45 | ||||
-rw-r--r-- | security/selinux/include/security.h | 1 |
15 files changed, 285 insertions, 56 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index c048624fc6b7..383aa21a0e2a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3598,13 +3598,24 @@ static int binder_transactions_show(struct seq_file *m, void *unused) static int binder_proc_show(struct seq_file *m, void *unused) { + struct binder_proc *itr; struct binder_proc *proc = m->private; int do_lock = !binder_debug_no_lock; + bool valid_proc = false; if (do_lock) binder_lock(__func__); - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, proc, 1); + + hlist_for_each_entry(itr, &binder_procs, proc_node) { + if (itr == proc) { + valid_proc = true; + break; + } + } + if (valid_proc) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, proc, 1); + } if (do_lock) binder_unlock(__func__); return 0; diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4b35cc08c3b6..ebe6c7310c85 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -54,6 +54,8 @@ static LIST_HEAD(wakeup_sources); static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue); +static ktime_t last_read_time; + /** * wakeup_source_prepare - Prepare a new wakeup source for initialization. * @ws: Wakeup source to prepare. @@ -343,6 +345,20 @@ int device_set_wakeup_enable(struct device *dev, bool enable) } EXPORT_SYMBOL_GPL(device_set_wakeup_enable); +/** + * wakeup_source_not_registered - validate the given wakeup source. + * @ws: Wakeup source to be validated. + */ +static bool wakeup_source_not_registered(struct wakeup_source *ws) +{ + /* + * Use timer struct to check if the given source is initialized + * by wakeup_source_add. + */ + return ws->timer.function != pm_wakeup_timer_fn || + ws->timer.data != (unsigned long)ws; +} + /* * The functions below use the observation that each wakeup event starts a * period in which the system should not be suspended. The moment this period @@ -383,6 +399,10 @@ static void wakeup_source_activate(struct wakeup_source *ws) { unsigned int cec; + if (WARN(wakeup_source_not_registered(ws), + "unregistered wakeup source\n")) + return; + /* * active wakeup source should bring the system * out of PM_SUSPEND_FREEZE state @@ -760,10 +780,15 @@ bool pm_wakeup_pending(void) bool pm_get_wakeup_count(unsigned int *count, bool block) { unsigned int cnt, inpr; + unsigned long flags; if (block) { DEFINE_WAIT(wait); + spin_lock_irqsave(&events_lock, flags); + last_read_time = ktime_get(); + spin_unlock_irqrestore(&events_lock, flags); + for (;;) { prepare_to_wait(&wakeup_count_wait_queue, &wait, TASK_INTERRUPTIBLE); @@ -795,6 +820,7 @@ bool pm_save_wakeup_count(unsigned int count) { unsigned int cnt, inpr; unsigned long flags; + struct wakeup_source *ws; events_check_enabled = false; spin_lock_irqsave(&events_lock, flags); @@ -802,6 +828,15 @@ bool pm_save_wakeup_count(unsigned int count) if (cnt == count && inpr == 0) { saved_count = count; events_check_enabled = true; + } else { + rcu_read_lock(); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { + if (ws->active || + ktime_compare(ws->last_time, last_read_time) > 0) { + ws->wakeup_count++; + } + } + rcu_read_unlock(); } spin_unlock_irqrestore(&events_lock, flags); return events_check_enabled; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 690af18f55a9..52b4d526dcff 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -22,6 +22,8 @@ #include <linux/notifier.h> #include <linux/sort.h> #include <linux/err.h> +#include <linux/of.h> +#include <linux/sched.h> #include <asm/cputime.h> #ifdef CONFIG_BL_SWITCHER #include <asm/bL_switcher.h> @@ -49,6 +51,12 @@ struct all_cpufreq_stats { unsigned int *freq_table; }; +struct cpufreq_power_stats { + unsigned int state_num; + unsigned int *curr; + unsigned int *freq_table; +}; + struct all_freq_table { unsigned int *freq_table; unsigned int table_size; @@ -58,6 +66,7 @@ static struct all_freq_table *all_freq_table; static DEFINE_PER_CPU(struct all_cpufreq_stats *, all_cpufreq_stats); static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); +static DEFINE_PER_CPU(struct cpufreq_power_stats *, cpufreq_power_stats); struct cpufreq_stats_attribute { struct attribute attr; @@ -128,6 +137,47 @@ static int get_index_all_cpufreq_stat(struct all_cpufreq_stats *all_stat, return -1; } +void acct_update_power(struct task_struct *task, cputime_t cputime) { + struct cpufreq_power_stats *powerstats; + struct cpufreq_stats *stats; + unsigned int cpu_num, curr; + + if (!task) + return; + cpu_num = task_cpu(task); + powerstats = per_cpu(cpufreq_power_stats, cpu_num); + stats = per_cpu(cpufreq_stats_table, cpu_num); + if (!powerstats || !stats) + return; + + curr = powerstats->curr[stats->last_index]; + task->cpu_power += curr * cputime_to_usecs(cputime); +} +EXPORT_SYMBOL_GPL(acct_update_power); + +static ssize_t show_current_in_state(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t len = 0; + unsigned int i, cpu; + struct cpufreq_power_stats *powerstats; + + spin_lock(&cpufreq_stats_lock); + for_each_possible_cpu(cpu) { + powerstats = per_cpu(cpufreq_power_stats, cpu); + if (!powerstats) + continue; + len += scnprintf(buf + len, PAGE_SIZE - len, "CPU%d:", cpu); + for (i = 0; i < powerstats->state_num; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "%d=%d ", powerstats->freq_table[i], + powerstats->curr[i]); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); + } + spin_unlock(&cpufreq_stats_lock); + return len; +} + static ssize_t show_all_time_in_state(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -237,6 +287,9 @@ static struct attribute_group stats_attr_group = { static struct kobj_attribute _attr_all_time_in_state = __ATTR(all_time_in_state, 0444, show_all_time_in_state, NULL); +static struct kobj_attribute _attr_current_in_state = __ATTR(current_in_state, + 0444, show_current_in_state, NULL); + static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) { int index; @@ -306,10 +359,27 @@ static void cpufreq_allstats_free(void) } } +static void cpufreq_powerstats_free(void) +{ + int cpu; + struct cpufreq_power_stats *powerstats; + + sysfs_remove_file(cpufreq_global_kobject, &_attr_current_in_state.attr); + + for_each_possible_cpu(cpu) { + powerstats = per_cpu(cpufreq_power_stats, cpu); + if (!powerstats) + continue; + kfree(powerstats->curr); + kfree(powerstats); + per_cpu(cpufreq_power_stats, cpu) = NULL; + } +} + static int cpufreq_stats_create_table(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table) + struct cpufreq_frequency_table *table, int count) { - unsigned int i, j, count = 0, ret = 0; + unsigned int i, j, ret = 0; struct cpufreq_stats *stat; struct cpufreq_policy *data; unsigned int alloc_size; @@ -333,12 +403,6 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, stat->cpu = cpu; per_cpu(cpufreq_stats_table, cpu) = stat; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - unsigned int freq = table[i].frequency; - if (freq == CPUFREQ_ENTRY_INVALID) - continue; - count++; - } alloc_size = count * sizeof(int) + count * sizeof(u64); @@ -392,6 +456,54 @@ static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) stat->cpu = policy->cpu; } +static void cpufreq_powerstats_create(unsigned int cpu, + struct cpufreq_frequency_table *table, int count) { + unsigned int alloc_size, i = 0, j = 0, ret = 0; + struct cpufreq_power_stats *powerstats; + struct device_node *cpu_node; + char device_path[16]; + + powerstats = kzalloc(sizeof(struct cpufreq_power_stats), + GFP_KERNEL); + if (!powerstats) + return; + + /* Allocate memory for freq table per cpu as well as clockticks per + * freq*/ + alloc_size = count * sizeof(unsigned int) + + count * sizeof(unsigned int); + powerstats->curr = kzalloc(alloc_size, GFP_KERNEL); + if (!powerstats->curr) { + kfree(powerstats); + return; + } + powerstats->freq_table = powerstats->curr + count; + + spin_lock(&cpufreq_stats_lock); + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END && j < count; i++) { + unsigned int freq = table[i].frequency; + + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + powerstats->freq_table[j++] = freq; + } + powerstats->state_num = j; + + snprintf(device_path, sizeof(device_path), "/cpus/cpu@%d", cpu); + cpu_node = of_find_node_by_path(device_path); + if (cpu_node) { + ret = of_property_read_u32_array(cpu_node, "current", + powerstats->curr, count); + if (ret) { + kfree(powerstats->curr); + kfree(powerstats); + powerstats = NULL; + } + } + per_cpu(cpufreq_power_stats, cpu) = powerstats; + spin_unlock(&cpufreq_stats_lock); +} + static int compare_for_sort(const void *lhs_ptr, const void *rhs_ptr) { unsigned int lhs = *(const unsigned int *)(lhs_ptr); @@ -436,24 +548,14 @@ static void add_all_freq_table(unsigned int freq) all_freq_table->freq_table[all_freq_table->table_size++] = freq; } -static void cpufreq_allstats_create(unsigned int cpu) +static void cpufreq_allstats_create(unsigned int cpu, + struct cpufreq_frequency_table *table, int count) { int i , j = 0; - unsigned int alloc_size, count = 0; - struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(cpu); + unsigned int alloc_size; struct all_cpufreq_stats *all_stat; bool sort_needed = false; - if (!table) - return; - - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - unsigned int freq = table[i].frequency; - if (freq == CPUFREQ_ENTRY_INVALID) - continue; - count++; - } - all_stat = kzalloc(sizeof(struct all_cpufreq_stats), GFP_KERNEL); if (!all_stat) { @@ -495,7 +597,7 @@ static void cpufreq_allstats_create(unsigned int cpu) static int cpufreq_stat_notifier_policy(struct notifier_block *nb, unsigned long val, void *data) { - int ret; + int ret, count = 0, i; struct cpufreq_policy *policy = data; struct cpufreq_frequency_table *table; unsigned int cpu = policy->cpu; @@ -511,10 +613,21 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, if (!table) return 0; + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + unsigned int freq = table[i].frequency; + + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + count++; + } + if (!per_cpu(all_cpufreq_stats, cpu)) - cpufreq_allstats_create(cpu); + cpufreq_allstats_create(cpu, table, count); - ret = cpufreq_stats_create_table(policy, table); + if (!per_cpu(cpufreq_power_stats, cpu)) + cpufreq_powerstats_create(cpu, table, count); + + ret = cpufreq_stats_create_table(policy, table, count); if (ret) return ret; return 0; @@ -560,7 +673,7 @@ static int cpufreq_stats_create_table_cpu(unsigned int cpu) { struct cpufreq_policy *policy; struct cpufreq_frequency_table *table; - int ret = -ENODEV; + int ret = -ENODEV, i, count = 0; policy = cpufreq_cpu_get(cpu); if (!policy) @@ -570,10 +683,21 @@ static int cpufreq_stats_create_table_cpu(unsigned int cpu) if (!table) goto out; + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + unsigned int freq = table[i].frequency; + + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + count++; + } + if (!per_cpu(all_cpufreq_stats, cpu)) - cpufreq_allstats_create(cpu); + cpufreq_allstats_create(cpu, table, count); + + if (!per_cpu(cpufreq_power_stats, cpu)) + cpufreq_powerstats_create(cpu, table, count); - ret = cpufreq_stats_create_table(policy, table); + ret = cpufreq_stats_create_table(policy, table, count); out: cpufreq_cpu_put(policy); @@ -651,7 +775,12 @@ static int cpufreq_stats_setup(void) ret = sysfs_create_file(cpufreq_global_kobject, &_attr_all_time_in_state.attr); if (ret) - pr_warn("Error creating sysfs file for cpufreq stats\n"); + pr_warn("Cannot create sysfs file for cpufreq stats\n"); + + ret = sysfs_create_file(cpufreq_global_kobject, + &_attr_current_in_state.attr); + if (ret) + pr_warn("Cannot create sysfs file for cpufreq current stats\n"); return 0; } @@ -670,6 +799,7 @@ static void cpufreq_stats_cleanup(void) cpufreq_stats_free_sysfs(cpu); } cpufreq_allstats_free(); + cpufreq_powerstats_free(); } #ifdef CONFIG_BL_SWITCHER diff --git a/drivers/misc/uid_cputime.c b/drivers/misc/uid_cputime.c index acd7046ce497..89bfba6c5b6a 100644 --- a/drivers/misc/uid_cputime.c +++ b/drivers/misc/uid_cputime.c @@ -38,6 +38,8 @@ struct uid_entry { cputime_t stime; cputime_t active_utime; cputime_t active_stime; + unsigned long long active_power; + unsigned long long power; struct hlist_node hash; }; @@ -83,6 +85,7 @@ static int uid_stat_show(struct seq_file *m, void *v) 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); @@ -100,6 +103,7 @@ static int uid_stat_show(struct seq_file *m, void *v) task_cputime_adjusted(task, &utime, &stime); uid_entry->active_utime += utime; uid_entry->active_stime += stime; + uid_entry->active_power += task->cpu_power; } read_unlock(&tasklist_lock); @@ -108,9 +112,12 @@ static int uid_stat_show(struct seq_file *m, void *v) uid_entry->active_utime; cputime_t total_stime = uid_entry->stime + uid_entry->active_stime; - seq_printf(m, "%d: %u %u\n", uid_entry->uid, + unsigned long long total_power = uid_entry->power + + uid_entry->active_power; + seq_printf(m, "%d: %u %u %llu\n", uid_entry->uid, cputime_to_usecs(total_utime), - cputime_to_usecs(total_stime)); + cputime_to_usecs(total_stime), + total_power); } mutex_unlock(&uid_lock); @@ -203,6 +210,7 @@ static int process_notifier(struct notifier_block *self, task_cputime_adjusted(task, &utime, &stime); uid_entry->utime += utime; uid_entry->stime += stime; + uid_entry->power += task->cpu_power; exit: mutex_unlock(&uid_lock); @@ -226,7 +234,7 @@ static int __init proc_uid_cputime_init(void) proc_create_data("remove_uid_range", S_IWUGO, parent, &uid_remove_fops, NULL); - proc_create_data("show_uid_stat", S_IWUGO, parent, &uid_stat_fops, + proc_create_data("show_uid_stat", S_IRUGO, parent, &uid_stat_fops, NULL); profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 913a6b279220..064177f6acd9 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -305,6 +305,8 @@ static void __save_error_info(struct super_block *sb, const char *func, struct ext4_super_block *es = EXT4_SB(sb)->s_es; EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + if (bdev_read_only(sb->s_bdev)) + return; es->s_state |= cpu_to_le16(EXT4_ERROR_FS); es->s_last_error_time = cpu_to_le32(get_seconds()); strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func)); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index df55b769f550..55b04003a635 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -21,6 +21,7 @@ #include <linux/workqueue.h> #include <linux/cpumask.h> #include <asm/div64.h> +#include <asm/cputime.h> #define CPUFREQ_NAME_LEN 16 /* Print length for names. Extra 1 space for accomodating '\n' in prints */ @@ -438,4 +439,11 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); void cpufreq_frequency_table_put_attr(unsigned int cpu); + +/********************************************************************* + * CPUFREQ STATS * + *********************************************************************/ + +void acct_update_power(struct task_struct *p, cputime_t cputime); + #endif /* _LINUX_CPUFREQ_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 5229df9d7107..059749ab3943 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1189,6 +1189,7 @@ struct task_struct { cputime_t utime, stime, utimescaled, stimescaled; cputime_t gtime; + unsigned long long cpu_power; #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE struct cputime prev_cputime; #endif diff --git a/kernel/fork.c b/kernel/fork.c index b0663950634b..5f7f0cb420fb 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1299,6 +1299,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->utime = p->stime = p->gtime = 0; p->utimescaled = p->stimescaled = 0; + p->cpu_power = 0; #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE p->prev_cputime.utime = p->prev_cputime.stime = 0; #endif diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 82450c20875c..e2446e08c6b0 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -224,10 +224,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (!(suspend_test(TEST_CORE) || *wakeup)) { error = suspend_ops->enter(state); events_check_enabled = false; - } else { + } else if (*wakeup) { pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN); log_suspend_abort_reason(suspend_abort); + error = -EBUSY; } syscore_resume(); } diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index c23a8fd36149..8cda97c9c872 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -1,3 +1,4 @@ +#include <linux/cpufreq.h> #include <linux/export.h> #include <linux/sched.h> #include <linux/tsacct_kern.h> @@ -149,6 +150,11 @@ void account_user_time(struct task_struct *p, cputime_t cputime, /* Account for user time used */ acct_account_cputime(p); + +#ifdef CONFIG_CPU_FREQ_STAT + /* Account power usage for user time */ + acct_update_power(p, cputime); +#endif } /* @@ -199,6 +205,11 @@ void __account_system_time(struct task_struct *p, cputime_t cputime, /* Account for system time used */ acct_account_cputime(p); + +#ifdef CONFIG_CPU_FREQ_STAT + /* Account power usage for system time */ + acct_update_power(p, cputime); +#endif } /* diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 526bf56f4d31..afeb8e07ee41 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -332,6 +332,10 @@ static long caif_stream_data_wait(struct sock *sk, long timeo) release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); + + if (sock_flag(sk, SOCK_DEAD)) + break; + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } @@ -376,6 +380,10 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; lock_sock(sk); + if (sock_flag(sk, SOCK_DEAD)) { + err = -ECONNRESET; + goto unlock; + } skb = skb_dequeue(&sk->sk_receive_queue); caif_check_flow_release(sk); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b49e8bafab17..cdd77161e99f 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -928,6 +928,7 @@ static void neigh_timer_handler(unsigned long arg) neigh->nud_state = NUD_PROBE; neigh->updated = jiffies; atomic_set(&neigh->probes, 0); + notify = 1; next = now + neigh->parms->retrans_time; } } else { @@ -1155,6 +1156,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, if (new != old) { neigh_del_timer(neigh); + if (new & NUD_PROBE) + atomic_set(&neigh->probes, 0); if (new & NUD_IN_TIMER) neigh_add_timer(neigh, (jiffies + ((new & NUD_REACHABLE) ? diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c80c107139f1..b6ae0e17a546 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1899,6 +1899,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, unix_state_unlock(sk); timeo = freezable_schedule_timeout(timeo); unix_state_lock(sk); + + if (sock_flag(sk, SOCK_DEAD)) + break; + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } @@ -1958,6 +1962,10 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb, *last; unix_state_lock(sk); + if (sock_flag(sk, SOCK_DEAD)) { + err = -ECONNRESET; + goto unlock; + } last = skb = skb_peek(&sk->sk_receive_queue); again: if (skb == NULL) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 607c3d58a691..2cad844f0ad6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -699,7 +699,12 @@ static int selinux_set_mnt_opts(struct super_block *sb, } if (strcmp(sb->s_type->name, "proc") == 0) - sbsec->flags |= SE_SBPROC; + sbsec->flags |= SE_SBPROC | SE_SBGENFS; + + if (!strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore")) + sbsec->flags |= SE_SBGENFS; /* Determine the labeling behavior to use for this filesystem type. */ rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); @@ -1184,12 +1189,13 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_SOCKET; } -#ifdef CONFIG_PROC_FS -static int selinux_proc_get_sid(struct dentry *dentry, - u16 tclass, - u32 *sid) +static int selinux_genfs_get_sid(struct dentry *dentry, + u16 tclass, + u16 flags, + u32 *sid) { int rc; + struct super_block *sb = dentry->d_inode->i_sb; char *buffer, *path; buffer = (char *)__get_free_page(GFP_KERNEL); @@ -1200,26 +1206,20 @@ static int selinux_proc_get_sid(struct dentry *dentry, if (IS_ERR(path)) rc = PTR_ERR(path); else { - /* each process gets a /proc/PID/ entry. Strip off the - * PID part to get a valid selinux labeling. - * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ - while (path[1] >= '0' && path[1] <= '9') { - path[1] = '/'; - path++; + if (flags & SE_SBPROC) { + /* each process gets a /proc/PID/ entry. Strip off the + * PID part to get a valid selinux labeling. + * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ + while (path[1] >= '0' && path[1] <= '9') { + path[1] = '/'; + path++; + } } - rc = security_genfs_sid("proc", path, tclass, sid); + rc = security_genfs_sid(sb->s_type->name, path, tclass, sid); } free_page((unsigned long)buffer); return rc; } -#else -static int selinux_proc_get_sid(struct dentry *dentry, - u16 tclass, - u32 *sid) -{ - return -EINVAL; -} -#endif /* The inode's security attributes must be initialized before first use. */ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) @@ -1374,7 +1374,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; - if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { + if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) { /* We must have a dentry to determine the label on * procfs inodes */ if (opt_dentry) @@ -1397,7 +1397,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent if (!dentry) goto out_unlock; isec->sclass = inode_mode_to_security_class(inode->i_mode); - rc = selinux_proc_get_sid(dentry, isec->sclass, &sid); + rc = selinux_genfs_get_sid(dentry, isec->sclass, + sbsec->flags, &sid); dput(dentry); if (rc) goto out_unlock; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index e72d8de93725..b73ec2a71a7c 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -55,6 +55,7 @@ #define SE_SBINITIALIZED 0x10 #define SE_SBPROC 0x20 #define SE_SBLABELSUPP 0x40 +#define SE_SBGENFS 0x80 #define CONTEXT_STR "context=" #define FSCONTEXT_STR "fscontext=" |