diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-03 04:18:23 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-11-03 04:18:23 -0600 |
| commit | 28f64cb2a6607069f7dc03c3bcb233dbef49dc8b (patch) | |
| tree | 9386e1ac1c85522e99c309bdc006361a62d4d755 /kernel | |
| parent | 65485bf038afb364645dcdd28f151fa26f5023cd (diff) | |
| parent | 8a4f90bd10a5326c8da6e1750d041f7befb10eb1 (diff) | |
Promotion of kernel.lnx.4.4-161103.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1084491 Ia9350b9c7810db7eb900957b4ce5dac046ab5e0d ARM: dts: msm: Add qcom,dump-size entry for dumping CPU
1084491 I37ca3aae0471fcd60499615df77093d5b5451bf8 Documentation: arm: add cache DT bindings
1078910 I9cb454cebb74df291479cecc3533d2c684363f77 ion: disable system contig heap
1077179 I5bc6a5a46311206818d70567e31fd84adc0128be leds: qpnp-flash-v2: Fix strobe control settings
1077868 Id568f76e03b93cf411366abf01ea857fb80ff1bf ARM: dts: msm: correct cpu nodes information for msmtrit
1083761 Ib38ecabb3c4bf40fcf5ad368fbbdbe4c44edbf3b msm: vidc: Scale bus bw along with venus clocks
1084236 I4c13601b0fded6de9d8f897c6d471c6a40c90e4d sched/hmp: Automatically add children threads to colocat
1070067 I0d4b9f72a12e91b16f3844ac70db33b7de5e5263 usb_bam: Avoid uninitialized variable errors
1080024 I92bd53432a11241228d2e5ac89a3b20d19b05a31 CHROMIUM: dm: boot time specification of dm=
1049826 I3e11ca7f6df4bb0d928512f81f3e3dc40fed791a msm: camera: cpp: Validate frame message before manipula
1080024 I952d86fd1475f0825f9be1386e3497b36127abd0 ANDROID: dm: Rebase on top of 4.1
1082476 1750919 I3a79950b76c1c38e487471f21dc60590b032dd3f msm: vidc: Correct debugfs directory name
1080024 I4ba1043965d25ec444a833283392ac2394c845f3 Revert "init: do_mounts: Add a dummy definition for dm_t
1084009 Ie1a5038458b0b93dfec3e5bfc350686eb1f8eb1b ASoC: wcd934x: Initialize mbhc pointer before access
1080688 Ia60fc3ecb5c2aba19effe1c8242f2d89fdef3ebd ARM: dts: msm: specify SPI configuration for msmfalcon.
1083524 Ic26fa36bf84bce020ad07ad87de50e684dd7fa5a ARM: dts: msm: Add initial support for msmcobalt V2 QRD
1075835 1075868 I06426109ab39d33e2b11514082c0bc989c4c8167 coresight: tmc: avoid null pointer dereference
1072541 If2b3e241076a4e0eeb87eeb4361398313fca6962 dwc3: gadget: Remove disabling events and ep0 from gadge
1081711 Iee908c56ec530569b35dafa060139e0428efc781 soc: qcom: scm: add check to avoid buffer overflow
1025311 Ie432af1fefc79f88ec67d212f8b9880355c4266d cfg80211: support virtual interfaces with different beac
1043802 I3eb92f83b42b0fa28dc73f6e0d4f74ef50375855 ARM: dts: msm: add support for QBT1000 on msmcobalt
1082843 I6ab3992958a659995b7d5020287fd6e47e28f2a4 clk: msm: clock-debug: Print VDD level in clock_state tr
1082816 I475d1219ae62378a90c69642f2320149d0f13885 ASoc: wcd934x: correct MAD micbias setting
967547 I92b10e62be8129ead5859a285bf964ab0a3ae2fd driver core: fix race between creating/querying glue dir
1084935 I31e8e0b5e9ae240ca031f625cf7c49f1bfe165d4 msm: secure_buffer: fix scm call argument layout
1074738 Ie7f8cee59b90f16f8a844d618a6f903b3e3c2f27 msm: mdss: lock mutex before setting backlight
Change-Id: Id13d60a1768a89563fa5209fc5fe3abfc2ea7bb0
CRs-Fixed: 1077179, 1075868, 1082476, 1083761, 1081711, 1043802, 1084935, 1049826, 1070067, 1082816, 1025311, 1074738, 1083524, 1075835, 1080024, 1750919, 1072541, 1084491, 1084009, 1077868, 967547, 1084236, 1080688, 1078910, 1082843
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched/core.c | 2 | ||||
| -rw-r--r-- | kernel/sched/hmp.c | 145 |
2 files changed, 85 insertions, 62 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c07d844c576e..f3b1688b3be7 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2572,8 +2572,8 @@ void wake_up_new_task(struct task_struct *p) unsigned long flags; struct rq *rq; - raw_spin_lock_irqsave(&p->pi_lock, flags); add_new_task_to_grp(p); + raw_spin_lock_irqsave(&p->pi_lock, flags); /* Initialize new task's runnable average */ init_entity_runnable_average(&p->se); #ifdef CONFIG_SMP diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 1d55e226196f..56f4c60d4d5d 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -1396,16 +1396,6 @@ void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra) } } -/* - * Invoked from three places: - * 1) try_to_wake_up() -> ... -> select_best_cpu() - * 2) scheduler_tick() -> ... -> migration_needed() -> select_best_cpu() - * 3) can_migrate_task() - * - * Its safe to de-reference p->grp in first case (since p->pi_lock is held) - * but not in other cases. p->grp is hence freed after a RCU grace period and - * accessed under rcu_read_lock() - */ int preferred_cluster(struct sched_cluster *cluster, struct task_struct *p) { struct related_thread_group *grp; @@ -3883,7 +3873,12 @@ static void _set_preferred_cluster(struct related_thread_group *grp) void set_preferred_cluster(struct related_thread_group *grp) { - raw_spin_lock(&grp->lock); + /* + * Prevent possible deadlock with update_children(). Not updating + * the preferred cluster once is not a big deal. + */ + if (!raw_spin_trylock(&grp->lock)) + return; _set_preferred_cluster(grp); raw_spin_unlock(&grp->lock); } @@ -3904,7 +3899,7 @@ static int alloc_group_cputime(struct related_thread_group *grp) struct rq *rq = cpu_rq(cpu); u64 window_start = rq->window_start; - grp->cpu_time = alloc_percpu(struct group_cpu_time); + grp->cpu_time = alloc_percpu_gfp(struct group_cpu_time, GFP_ATOMIC); if (!grp->cpu_time) return -ENOMEM; @@ -4088,7 +4083,7 @@ struct related_thread_group *alloc_related_thread_group(int group_id) { struct related_thread_group *grp; - grp = kzalloc(sizeof(*grp), GFP_KERNEL); + grp = kzalloc(sizeof(*grp), GFP_ATOMIC); if (!grp) return ERR_PTR(-ENOMEM); @@ -4127,19 +4122,64 @@ static void free_related_thread_group(struct rcu_head *rcu) kfree(grp); } +/* + * The thread group for a task can change while we are here. However, + * add_new_task_to_grp() will take care of any tasks that we miss here. + * When a parent exits, and a child thread is simultaneously exiting, + * sched_set_group_id() will synchronize those operations. + */ +static void update_children(struct task_struct *leader, + struct related_thread_group *grp, int event) +{ + struct task_struct *child; + struct rq *rq; + unsigned long flags; + + if (!thread_group_leader(leader)) + return; + + if (event == ADD_TASK && !sysctl_sched_enable_thread_grouping) + return; + + if (thread_group_empty(leader)) + return; + + child = next_thread(leader); + + do { + rq = task_rq_lock(child, &flags); + + if (event == REM_TASK && child->grp && grp == child->grp) { + transfer_busy_time(rq, grp, child, event); + list_del_init(&child->grp_list); + rcu_assign_pointer(child->grp, NULL); + } else if (event == ADD_TASK && !child->grp) { + transfer_busy_time(rq, grp, child, event); + list_add(&child->grp_list, &grp->tasks); + rcu_assign_pointer(child->grp, grp); + } + + task_rq_unlock(rq, child, &flags); + } while_each_thread(leader, child); + +} + static void remove_task_from_group(struct task_struct *p) { struct related_thread_group *grp = p->grp; struct rq *rq; int empty_group = 1; + unsigned long flags; raw_spin_lock(&grp->lock); - rq = __task_rq_lock(p); + rq = task_rq_lock(p, &flags); transfer_busy_time(rq, p->grp, p, REM_TASK); list_del_init(&p->grp_list); rcu_assign_pointer(p->grp, NULL); - __task_rq_unlock(rq); + task_rq_unlock(rq, p, &flags); + + update_children(p, grp, REM_TASK); if (!list_empty(&grp->tasks)) { empty_group = 0; @@ -4158,6 +4198,7 @@ static int add_task_to_group(struct task_struct *p, struct related_thread_group *grp) { struct rq *rq; + unsigned long flags; raw_spin_lock(&grp->lock); @@ -4165,11 +4206,13 @@ add_task_to_group(struct task_struct *p, struct related_thread_group *grp) * Change p->grp under rq->lock. Will prevent races with read-side * reference of p->grp in various hot-paths */ - rq = __task_rq_lock(p); + rq = task_rq_lock(p, &flags); transfer_busy_time(rq, grp, p, ADD_TASK); list_add(&p->grp_list, &grp->tasks); rcu_assign_pointer(p->grp, grp); - __task_rq_unlock(rq); + task_rq_unlock(rq, p, &flags); + + update_children(p, grp, ADD_TASK); _set_preferred_cluster(grp); @@ -4192,82 +4235,62 @@ void add_new_task_to_grp(struct task_struct *new) parent = new->group_leader; - /* - * The parent's pi_lock is required here to protect race - * against the parent task being removed from the - * group. - */ - raw_spin_lock_irqsave(&parent->pi_lock, flags); + write_lock_irqsave(&related_thread_group_lock, flags); - /* protected by pi_lock. */ + rcu_read_lock(); grp = task_related_thread_group(parent); - if (!grp) { - raw_spin_unlock_irqrestore(&parent->pi_lock, flags); + rcu_read_unlock(); + + /* Its possible that update_children() already added us to the group */ + if (!grp || new->grp) { + write_unlock_irqrestore(&related_thread_group_lock, flags); return; } + raw_spin_lock(&grp->lock); rcu_assign_pointer(new->grp, grp); list_add(&new->grp_list, &grp->tasks); raw_spin_unlock(&grp->lock); - raw_spin_unlock_irqrestore(&parent->pi_lock, flags); + write_unlock_irqrestore(&related_thread_group_lock, flags); } int sched_set_group_id(struct task_struct *p, unsigned int group_id) { - int rc = 0, destroy = 0; + int rc = 0; unsigned long flags; - struct related_thread_group *grp = NULL, *new = NULL; + struct related_thread_group *grp = NULL; -redo: - raw_spin_lock_irqsave(&p->pi_lock, flags); + /* Prevents tasks from exiting while we are managing groups. */ + write_lock_irqsave(&related_thread_group_lock, flags); + /* Switching from one group to another directly is not permitted */ if ((current != p && p->flags & PF_EXITING) || (!p->grp && !group_id) || - (p->grp && p->grp->id == group_id)) + (p->grp && group_id)) goto done; - write_lock(&related_thread_group_lock); - if (!group_id) { remove_task_from_group(p); - write_unlock(&related_thread_group_lock); goto done; } - if (p->grp && p->grp->id != group_id) - remove_task_from_group(p); - grp = lookup_related_thread_group(group_id); - if (!grp && !new) { - /* New group */ - write_unlock(&related_thread_group_lock); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); - new = alloc_related_thread_group(group_id); - if (IS_ERR(new)) - return -ENOMEM; - destroy = 1; - /* Rerun checks (like task exiting), since we dropped pi_lock */ - goto redo; - } else if (!grp && new) { - /* New group - use object allocated before */ - destroy = 0; - list_add(&new->list, &related_thread_groups); - grp = new; + if (!grp) { + grp = alloc_related_thread_group(group_id); + if (IS_ERR(grp)) { + rc = -ENOMEM; + goto done; + } + + list_add(&grp->list, &related_thread_groups); } BUG_ON(!grp); rc = add_task_to_group(p, grp); - write_unlock(&related_thread_group_lock); done: - raw_spin_unlock_irqrestore(&p->pi_lock, flags); - - if (new && destroy) { - free_group_cputime(new); - kfree(new); - } - + write_unlock_irqrestore(&related_thread_group_lock, flags); return rc; } |
