| @@ -1086,6 +1086,21 @@ struct numa_group { · 1085 unmodified lines |
| 1086 | unsigned long faults[0]; | 1086 | unsigned long faults[0]; |
| 1087 | }; | 1087 | }; |
| 1088 | | 1088 | |
| | 1089 | /* |
| | 1090 | * For functions that can be called in multiple contexts that permit reading |
| | 1091 | * ->numa_group (see struct task_struct for locking rules). |
| | 1092 | */ |
| | 1093 | static struct numa_group *deref_task_numa_group(struct task_struct *p) |
| | 1094 | { |
| | 1095 | return rcu_dereference_check(p->numa_group, p == current || |
| | 1096 | (lockdep_is_held(&task_rq(p)->lock) && !READ_ONCE(p->on_cpu))); |
| | 1097 | } |
| | 1098 | |
| | 1099 | static struct numa_group *deref_curr_numa_group(struct task_struct *p) |
| | 1100 | { |
| | 1101 | return rcu_dereference_protected(p->numa_group, p == current); |
| | 1102 | } |
| | 1103 | |
| 1089 | static inline unsigned long group_faults_priv(struct numa_group *ng); | 1104 | static inline unsigned long group_faults_priv(struct numa_group *ng); |
| 1090 | static inline unsigned long group_faults_shared(struct numa_group *ng); | 1105 | static inline unsigned long group_faults_shared(struct numa_group *ng); |
| 1091 | | 1106 | |
| @@ -1129,10 +1144,12 @@ static unsigned int task_scan_start(struct task_struct *p) · 37 unmodified lines |
| 1129 | { | 1144 | { |
| 1130 | unsigned long smin = task_scan_min(p); | 1145 | unsigned long smin = task_scan_min(p); |
| 1131 | unsigned long period = smin; | 1146 | unsigned long period = smin; |
| | 1147 | struct numa_group *ng; |
| 1132 | | 1148 | |
| 1133 | /* Scale the maximum scan period with the amount of shared memory. */ | 1149 | /* Scale the maximum scan period with the amount of shared memory. */ |
| 1134 | if (p->numa_group) { | 1150 | rcu_read_lock(); |
| 1135 | struct numa_group *ng = p->numa_group; | 1151 | ng = rcu_dereference(p->numa_group); |
| | 1152 | if (ng) { |
| 1136 | unsigned long shared = group_faults_shared(ng); | 1153 | unsigned long shared = group_faults_shared(ng); |
| 1137 | unsigned long private = group_faults_priv(ng); | 1154 | unsigned long private = group_faults_priv(ng); |
| 1138 | | 1155 | |
| @@ -1140,6 +1157,7 @@ static unsigned int task_scan_start(struct task_struct *p) · 1 unmodified line |
| 1140 | period *= shared + 1; | 1157 | period *= shared + 1; |
| 1141 | period /= private + shared + 1; | 1158 | period /= private + shared + 1; |
| 1142 | } | 1159 | } |
| | 1160 | rcu_read_unlock(); |
| 1143 | | 1161 | |
| 1144 | return max(smin, period); | 1162 | return max(smin, period); |
| 1145 | } | 1163 | } |
| @@ -1148,13 +1166,14 @@ static unsigned int task_scan_max(struct task_struct *p) · 2 unmodified lines |
| 1148 | { | 1166 | { |
| 1149 | unsigned long smin = task_scan_min(p); | 1167 | unsigned long smin = task_scan_min(p); |
| 1150 | unsigned long smax; | 1168 | unsigned long smax; |
| | 1169 | struct numa_group *ng; |
| 1151 | | 1170 | |
| 1152 | /* Watch for min being lower than max due to floor calculations */ | 1171 | /* Watch for min being lower than max due to floor calculations */ |
| 1153 | smax = sysctl_numa_balancing_scan_period_max / task_nr_scan_windows(p); | 1172 | smax = sysctl_numa_balancing_scan_period_max / task_nr_scan_windows(p); |
| 1154 | | 1173 | |
| 1155 | /* Scale the maximum scan period with the amount of shared memory. */ | 1174 | /* Scale the maximum scan period with the amount of shared memory. */ |
| 1156 | if (p->numa_group) { | 1175 | ng = deref_curr_numa_group(p); |
| 1157 | struct numa_group *ng = p->numa_group; | 1176 | if (ng) { |
| 1158 | unsigned long shared = group_faults_shared(ng); | 1177 | unsigned long shared = group_faults_shared(ng); |
| 1159 | unsigned long private = group_faults_priv(ng); | 1178 | unsigned long private = group_faults_priv(ng); |
| 1160 | unsigned long period = smax; | 1179 | unsigned long period = smax; |
| @@ -1186,7 +1205,7 @@ void init_numa_balancing(unsigned long clone_flags, struct task_struct *p) · 25 unmodified lines |
| 1186 | p->numa_scan_period = sysctl_numa_balancing_scan_delay; | 1205 | p->numa_scan_period = sysctl_numa_balancing_scan_delay; |
| 1187 | p->numa_work.next = &p->numa_work; | 1206 | p->numa_work.next = &p->numa_work; |
| 1188 | p->numa_faults = NULL; | 1207 | p->numa_faults = NULL; |
| 1189 | p->numa_group = NULL; | 1208 | RCU_INIT_POINTER(p->numa_group, NULL); |
| 1190 | p->last_task_numa_placement = 0; | 1209 | p->last_task_numa_placement = 0; |
| 1191 | p->last_sum_exec_runtime = 0; | 1210 | p->last_sum_exec_runtime = 0; |
| 1192 | | 1211 | |
| @@ -1233,7 +1252,16 @@ static void account_numa_dequeue(struct rq *rq, struct task_struct *p) · 40 unmodified lines |
| 1233 | | 1252 | |
| 1234 | pid_t task_numa_group_id(struct task_struct *p) | 1253 | pid_t task_numa_group_id(struct task_struct *p) |
| 1235 | { | 1254 | { |
| 1236 | return p->numa_group ? p->numa_group->gid : 0; | 1255 | struct numa_group *ng; |
| | 1256 | pid_t gid = 0; |
| | 1257 | |
| | 1258 | rcu_read_lock(); |
| | 1259 | ng = rcu_dereference(p->numa_group); |
| | 1260 | if (ng) |
| | 1261 | gid = ng->gid; |
| | 1262 | rcu_read_unlock(); |
| | 1263 | |
| | 1264 | return gid; |
| 1237 | } | 1265 | } |
| 1238 | | 1266 | |
| 1239 | /* | 1267 | /* |
| @@ -1258,11 +1286,13 @@ static inline unsigned long task_faults(struct task_struct *p, int nid) · 18 unmodified lines |
| 1258 | | 1286 | |
| 1259 | static inline unsigned long group_faults(struct task_struct *p, int nid) | 1287 | static inline unsigned long group_faults(struct task_struct *p, int nid) |
| 1260 | { | 1288 | { |
| 1261 | if (!p->numa_group) | 1289 | struct numa_group *ng = deref_task_numa_group(p); |
| | 1290 | |
| | 1291 | if (!ng) |
| 1262 | return 0; | 1292 | return 0; |
| 1263 | | 1293 | |
| 1264 | return p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 0)] + | 1294 | return ng->faults[task_faults_idx(NUMA_MEM, nid, 0)] + |
| 1265 | p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 1)]; | 1295 | ng->faults[task_faults_idx(NUMA_MEM, nid, 1)]; |
| 1266 | } | 1296 | } |
| 1267 | | 1297 | |
| 1268 | static inline unsigned long group_faults_cpu(struct numa_group *group, int nid) | 1298 | static inline unsigned long group_faults_cpu(struct numa_group *group, int nid) |
| @@ -1400,12 +1430,13 @@ static inline unsigned long task_weight(struct task_struct *p, int nid, · 131 unmodified lines |
| 1400 | static inline unsigned long group_weight(struct task_struct *p, int nid, | 1430 | static inline unsigned long group_weight(struct task_struct *p, int nid, |
| 1401 | int dist) | 1431 | int dist) |
| 1402 | { | 1432 | { |
| | 1433 | struct numa_group *ng = deref_task_numa_group(p); |
| 1403 | unsigned long faults, total_faults; | 1434 | unsigned long faults, total_faults; |
| 1404 | | 1435 | |
| 1405 | if (!p->numa_group) | 1436 | if (!ng) |
| 1406 | return 0; | 1437 | return 0; |
| 1407 | | 1438 | |
| 1408 | total_faults = p->numa_group->total_faults; | 1439 | total_faults = ng->total_faults; |
| 1409 | | 1440 | |
| 1410 | if (!total_faults) | 1441 | if (!total_faults) |
| 1411 | return 0; | 1442 | return 0; |
| @@ -1419,7 +1450,7 @@ static inline unsigned long group_weight(struct task_struct *p, int nid, · 7 unmodified lines |
| 1419 | bool should_numa_migrate_memory(struct task_struct *p, struct page * page, | 1450 | bool should_numa_migrate_memory(struct task_struct *p, struct page * page, |
| 1420 | int src_nid, int dst_cpu) | 1451 | int src_nid, int dst_cpu) |
| 1421 | { | 1452 | { |
| 1422 | struct numa_group *ng = p->numa_group; | 1453 | struct numa_group *ng = deref_curr_numa_group(p); |
| 1423 | int dst_nid = cpu_to_node(dst_cpu); | 1454 | int dst_nid = cpu_to_node(dst_cpu); |
| 1424 | int last_cpupid, this_cpupid; | 1455 | int last_cpupid, this_cpupid; |
| 1425 | | 1456 | |
| @@ -1600,13 +1631,14 @@ static bool load_too_imbalanced(long src_load, long dst_load, · 174 unmodified lines |
| 1600 | static void task_numa_compare(struct task_numa_env *env, | 1631 | static void task_numa_compare(struct task_numa_env *env, |
| 1601 | long taskimp, long groupimp, bool maymove) | 1632 | long taskimp, long groupimp, bool maymove) |
| 1602 | { | 1633 | { |
| | 1634 | struct numa_group *cur_ng, *p_ng = deref_curr_numa_group(env->p); |
| 1603 | struct rq *dst_rq = cpu_rq(env->dst_cpu); | 1635 | struct rq *dst_rq = cpu_rq(env->dst_cpu); |
| | 1636 | long imp = p_ng ? groupimp : taskimp; |
| 1604 | struct task_struct *cur; | 1637 | struct task_struct *cur; |
| 1605 | long src_load, dst_load; | 1638 | long src_load, dst_load; |
| 1606 | long load; | | |
| 1607 | long imp = env->p->numa_group ? groupimp : taskimp; | | |
| 1608 | long moveimp = imp; | | |
| 1609 | int dist = env->dist; | 1639 | int dist = env->dist; |
| | 1640 | long moveimp = imp; |
| | 1641 | long load; |
| 1610 | | 1642 | |
| 1611 | if (READ_ONCE(dst_rq->numa_migrate_on)) | 1643 | if (READ_ONCE(dst_rq->numa_migrate_on)) |
| 1612 | return; | 1644 | return; |
| @@ -1645,21 +1677,22 @@ static void task_numa_compare(struct task_numa_env *env, · 32 unmodified lines |
| 1645 | * If dst and source tasks are in the same NUMA group, or not | 1677 | * If dst and source tasks are in the same NUMA group, or not |
| 1646 | * in any group then look only at task weights. | 1678 | * in any group then look only at task weights. |
| 1647 | */ | 1679 | */ |
| 1648 | if (cur->numa_group == env->p->numa_group) { | 1680 | cur_ng = rcu_dereference(cur->numa_group); |
| | 1681 | if (cur_ng == p_ng) { |
| 1649 | imp = taskimp + task_weight(cur, env->src_nid, dist) - | 1682 | imp = taskimp + task_weight(cur, env->src_nid, dist) - |
| 1650 | task_weight(cur, env->dst_nid, dist); | 1683 | task_weight(cur, env->dst_nid, dist); |
| 1651 | /* | 1684 | /* |
| 1652 | * Add some hysteresis to prevent swapping the | 1685 | * Add some hysteresis to prevent swapping the |
| 1653 | * tasks within a group over tiny differences. | 1686 | * tasks within a group over tiny differences. |
| 1654 | */ | 1687 | */ |
| 1655 | if (cur->numa_group) | 1688 | if (cur_ng) |
| 1656 | imp -= imp / 16; | 1689 | imp -= imp / 16; |
| 1657 | } else { | 1690 | } else { |
| 1658 | /* | 1691 | /* |
| 1659 | * Compare the group weights. If a task is all by itself | 1692 | * Compare the group weights. If a task is all by itself |
| 1660 | * (not part of a group), use the task weight instead. | 1693 | * (not part of a group), use the task weight instead. |
| 1661 | */ | 1694 | */ |
| 1662 | if (cur->numa_group && env->p->numa_group) | 1695 | if (cur_ng && p_ng) |
| 1663 | imp += group_weight(cur, env->src_nid, dist) - | 1696 | imp += group_weight(cur, env->src_nid, dist) - |
| 1664 | group_weight(cur, env->dst_nid, dist); | 1697 | group_weight(cur, env->dst_nid, dist); |
| 1665 | else | 1698 | else |
| @@ -1757,11 +1790,12 @@ static int task_numa_migrate(struct task_struct *p) · 91 unmodified lines |
| 1757 | .best_imp = 0, | 1790 | .best_imp = 0, |
| 1758 | .best_cpu = -1, | 1791 | .best_cpu = -1, |
| 1759 | }; | 1792 | }; |
| | 1793 | unsigned long taskweight, groupweight; |
| 1760 | struct sched_domain *sd; | 1794 | struct sched_domain *sd; |
| | 1795 | long taskimp, groupimp; |
| | 1796 | struct numa_group *ng; |
| 1761 | struct rq *best_rq; | 1797 | struct rq *best_rq; |
| 1762 | unsigned long taskweight, groupweight; | | |
| 1763 | int nid, ret, dist; | 1798 | int nid, ret, dist; |
| 1764 | long taskimp, groupimp; | | |
| 1765 | | 1799 | |
| 1766 | /* | 1800 | /* |
| 1767 | * Pick the lowest SD_NUMA domain, as that would have the smallest | 1801 | * Pick the lowest SD_NUMA domain, as that would have the smallest |
| @@ -1807,7 +1841,8 @@ static int task_numa_migrate(struct task_struct *p) · 39 unmodified lines |
| 1807 | * multiple NUMA nodes; in order to better consolidate the group, | 1841 | * multiple NUMA nodes; in order to better consolidate the group, |
| 1808 | * we need to check other locations. | 1842 | * we need to check other locations. |
| 1809 | */ | 1843 | */ |
| 1810 | if (env.best_cpu == -1 || (p->numa_group && p->numa_group->active_nodes > 1)) { | 1844 | ng = deref_curr_numa_group(p); |
| | 1845 | if (env.best_cpu == -1 || (ng && ng->active_nodes > 1)) { |
| 1811 | for_each_online_node(nid) { | 1846 | for_each_online_node(nid) { |
| 1812 | if (nid == env.src_nid || nid == p->numa_preferred_nid) | 1847 | if (nid == env.src_nid || nid == p->numa_preferred_nid) |
| 1813 | continue; | 1848 | continue; |
| @@ -1840,7 +1875,7 @@ static int task_numa_migrate(struct task_struct *p) · 26 unmodified lines |
| 1840 | * A task that migrated to a second choice node will be better off | 1875 | * A task that migrated to a second choice node will be better off |
| 1841 | * trying for a better one later. Do not set the preferred node here. | 1876 | * trying for a better one later. Do not set the preferred node here. |
| 1842 | */ | 1877 | */ |
| 1843 | if (p->numa_group) { | 1878 | if (ng) { |
| 1844 | if (env.best_cpu == -1) | 1879 | if (env.best_cpu == -1) |
| 1845 | nid = env.src_nid; | 1880 | nid = env.src_nid; |
| 1846 | else | 1881 | else |
| @@ -2135,6 +2170,7 @@ static void task_numa_placement(struct task_struct *p) · 288 unmodified lines |
| 2135 | unsigned long total_faults; | 2170 | unsigned long total_faults; |
| 2136 | u64 runtime, period; | 2171 | u64 runtime, period; |
| 2137 | spinlock_t *group_lock = NULL; | 2172 | spinlock_t *group_lock = NULL; |
| | 2173 | struct numa_group *ng; |
| 2138 | | 2174 | |
| 2139 | /* | 2175 | /* |
| 2140 | * The p->mm->numa_scan_seq field gets updated without | 2176 | * The p->mm->numa_scan_seq field gets updated without |
| @@ -2152,8 +2188,9 @@ static void task_numa_placement(struct task_struct *p) · 11 unmodified lines |
| 2152 | runtime = numa_get_avg_runtime(p, &period); | 2188 | runtime = numa_get_avg_runtime(p, &period); |
| 2153 | | 2189 | |
| 2154 | /* If the task is part of a group prevent parallel updates to group stats */ | 2190 | /* If the task is part of a group prevent parallel updates to group stats */ |
| 2155 | if (p->numa_group) { | 2191 | ng = deref_curr_numa_group(p); |
| 2156 | group_lock = &p->numa_group->lock; | 2192 | if (ng) { |
| | 2193 | group_lock = &ng->lock; |
| 2157 | spin_lock_irq(group_lock); | 2194 | spin_lock_irq(group_lock); |
| 2158 | } | 2195 | } |
| 2159 | | 2196 | |
| @@ -2194,7 +2231,7 @@ static void task_numa_placement(struct task_struct *p) · 34 unmodified lines |
| 2194 | p->numa_faults[cpu_idx] += f_diff; | 2231 | p->numa_faults[cpu_idx] += f_diff; |
| 2195 | faults += p->numa_faults[mem_idx]; | 2232 | faults += p->numa_faults[mem_idx]; |
| 2196 | p->total_numa_faults += diff; | 2233 | p->total_numa_faults += diff; |
| 2197 | if (p->numa_group) { | 2234 | if (ng) { |
| 2198 | /* | 2235 | /* |
| 2199 | * safe because we can only change our own group | 2236 | * safe because we can only change our own group |
| 2200 | * | 2237 | * |
| @@ -2202,14 +2239,14 @@ static void task_numa_placement(struct task_struct *p) · 1 unmodified line |
| 2202 | * nid and priv in a specific region because it | 2239 | * nid and priv in a specific region because it |
| 2203 | * is at the beginning of the numa_faults array. | 2240 | * is at the beginning of the numa_faults array. |
| 2204 | */ | 2241 | */ |
| 2205 | p->numa_group->faults[mem_idx] += diff; | 2242 | ng->faults[mem_idx] += diff; |
| 2206 | p->numa_group->faults_cpu[mem_idx] += f_diff; | 2243 | ng->faults_cpu[mem_idx] += f_diff; |
| 2207 | p->numa_group->total_faults += diff; | 2244 | ng->total_faults += diff; |
| 2208 | group_faults += p->numa_group->faults[mem_idx]; | 2245 | group_faults += ng->faults[mem_idx]; |
| 2209 | } | 2246 | } |
| 2210 | } | 2247 | } |
| 2211 | | 2248 | |
| 2212 | if (!p->numa_group) { | 2249 | if (!ng) { |
| 2213 | if (faults > max_faults) { | 2250 | if (faults > max_faults) { |
| 2214 | max_faults = faults; | 2251 | max_faults = faults; |
| 2215 | max_nid = nid; | 2252 | max_nid = nid; |
| @@ -2220,8 +2257,8 @@ static void task_numa_placement(struct task_struct *p) · 4 unmodified lines |
| 2220 | } | 2257 | } |
| 2221 | } | 2258 | } |
| 2222 | | 2259 | |
| 2223 | if (p->numa_group) { | 2260 | if (ng) { |
| 2224 | numa_group_count_active_nodes(p->numa_group); | 2261 | numa_group_count_active_nodes(ng); |
| 2225 | spin_unlock_irq(group_lock); | 2262 | spin_unlock_irq(group_lock); |
| 2226 | max_nid = preferred_group_nid(p, max_nid); | 2263 | max_nid = preferred_group_nid(p, max_nid); |
| 2227 | } | 2264 | } |
| @@ -2255,7 +2292,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags, · 27 unmodified lines |
| 2255 | int cpu = cpupid_to_cpu(cpupid); | 2292 | int cpu = cpupid_to_cpu(cpupid); |
| 2256 | int i; | 2293 | int i; |
| 2257 | | 2294 | |
| 2258 | if (unlikely(!p->numa_group)) { | 2295 | if (unlikely(!deref_curr_numa_group(p))) { |
| 2259 | unsigned int size = sizeof(struct numa_group) + | 2296 | unsigned int size = sizeof(struct numa_group) + |
| 2260 | 4*nr_node_ids*sizeof(unsigned long); | 2297 | 4*nr_node_ids*sizeof(unsigned long); |
| 2261 | | 2298 | |
| @@ -2291,7 +2328,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags, · 29 unmodified lines |
| 2291 | if (!grp) | 2328 | if (!grp) |
| 2292 | goto no_join; | 2329 | goto no_join; |
| 2293 | | 2330 | |
| 2294 | my_grp = p->numa_group; | 2331 | my_grp = deref_curr_numa_group(p); |
| 2295 | if (grp == my_grp) | 2332 | if (grp == my_grp) |
| 2296 | goto no_join; | 2333 | goto no_join; |
| 2297 | | 2334 | |
| @@ -2353,13 +2390,24 @@ no_join: · 55 unmodified lines |
| 2353 | return; | 2390 | return; |
| 2354 | } | 2391 | } |
| 2355 | | 2392 | |
| 2356 | void task_numa_free(struct task_struct *p) | 2393 | /* |
| | 2394 | * Get rid of NUMA staticstics associated with a task (either current or dead). |
| | 2395 | * If @final is set, the task is dead and has reached refcount zero, so we can |
| | 2396 | * safely free all relevant data structures. Otherwise, there might be |
| | 2397 | * concurrent reads from places like load balancing and procfs, and we should |
| | 2398 | * reset the data back to default state without freeing ->numa_faults. |
| | 2399 | */ |
| | 2400 | void task_numa_free(struct task_struct *p, bool final) |
| 2357 | { | 2401 | { |
| 2358 | struct numa_group *grp = p->numa_group; | 2402 | /* safe: p either is current or is being freed by current */ |
| 2359 | void *numa_faults = p->numa_faults; | 2403 | struct numa_group *grp = rcu_dereference_raw(p->numa_group); |
| | 2404 | unsigned long *numa_faults = p->numa_faults; |
| 2360 | unsigned long flags; | 2405 | unsigned long flags; |
| 2361 | int i; | 2406 | int i; |
| 2362 | | 2407 | |
| | 2408 | if (!numa_faults) |
| | 2409 | return; |
| | 2410 | |
| 2363 | if (grp) { | 2411 | if (grp) { |
| 2364 | spin_lock_irqsave(&grp->lock, flags); | 2412 | spin_lock_irqsave(&grp->lock, flags); |
| 2365 | for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) | 2413 | for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) |
| @@ -2372,8 +2420,14 @@ void task_numa_free(struct task_struct *p) · 6 unmodified lines |
| 2372 | put_numa_group(grp); | 2420 | put_numa_group(grp); |
| 2373 | } | 2421 | } |
| 2374 | | 2422 | |
| 2375 | p->numa_faults = NULL; | 2423 | if (final) { |
| 2376 | kfree(numa_faults); | 2424 | p->numa_faults = NULL; |
| | 2425 | kfree(numa_faults); |
| | 2426 | } else { |
| | 2427 | p->total_numa_faults = 0; |
| | 2428 | for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) |
| | 2429 | numa_faults[i] = 0; |
| | 2430 | } |
| 2377 | } | 2431 | } |
| 2378 | | 2432 | |
| 2379 | /* | 2433 | /* |
| @@ -2426,7 +2480,7 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags) · 46 unmodified lines |
| 2426 | * actively using should be counted as local. This allows the | 2480 | * actively using should be counted as local. This allows the |
| 2427 | * scan rate to slow down when a workload has settled down. | 2481 | * scan rate to slow down when a workload has settled down. |
| 2428 | */ | 2482 | */ |
| 2429 | ng = p->numa_group; | 2483 | ng = deref_curr_numa_group(p); |
| 2430 | if (!priv && !local && ng && ng->active_nodes > 1 && | 2484 | if (!priv && !local && ng && ng->active_nodes > 1 && |
| 2431 | numa_is_active_node(cpu_node, ng) && | 2485 | numa_is_active_node(cpu_node, ng) && |
| 2432 | numa_is_active_node(mem_node, ng)) | 2486 | numa_is_active_node(mem_node, ng)) |
| @@ -10444,18 +10498,22 @@ void show_numa_stats(struct task_struct *p, struct seq_file *m) · 8011 unmodified lines |
| 10444 | { | 10498 | { |
| 10445 | int node; | 10499 | int node; |
| 10446 | unsigned long tsf = 0, tpf = 0, gsf = 0, gpf = 0; | 10500 | unsigned long tsf = 0, tpf = 0, gsf = 0, gpf = 0; |
| | 10501 | struct numa_group *ng; |
| 10447 | | 10502 | |
| | 10503 | rcu_read_lock(); |
| | 10504 | ng = rcu_dereference(p->numa_group); |
| 10448 | for_each_online_node(node) { | 10505 | for_each_online_node(node) { |
| 10449 | if (p->numa_faults) { | 10506 | if (p->numa_faults) { |
| 10450 | tsf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 0)]; | 10507 | tsf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 0)]; |
| 10451 | tpf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 1)]; | 10508 | tpf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 1)]; |
| 10452 | } | 10509 | } |
| 10453 | if (p->numa_group) { | 10510 | if (ng) { |
| 10454 | gsf = p->numa_group->faults[task_faults_idx(NUMA_MEM, node, 0)], | 10511 | gsf = ng->faults[task_faults_idx(NUMA_MEM, node, 0)], |
| 10455 | gpf = p->numa_group->faults[task_faults_idx(NUMA_MEM, node, 1)]; | 10512 | gpf = ng->faults[task_faults_idx(NUMA_MEM, node, 1)]; |
| 10456 | } | 10513 | } |
| 10457 | print_numa_stats(m, node, tsf, tpf, gsf, gpf); | 10514 | print_numa_stats(m, node, tsf, tpf, gsf, gpf); |
| 10458 | } | 10515 | } |
| | 10516 | rcu_read_unlock(); |
| 10459 | } | 10517 | } |
| 10460 | #endif /* CONFIG_NUMA_BALANCING */ | 10518 | #endif /* CONFIG_NUMA_BALANCING */ |
| 10461 | #endif /* CONFIG_SCHED_DEBUG */ | 10519 | #endif /* CONFIG_SCHED_DEBUG */ |