| @@ -1,6 +1,7 @@ |
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | #include "cgroup-internal.h" |
| 3 | 3 | |
| 4 | +#include <linux/cpumask.h> |
| 4 | 5 | #include <linux/sched/cputime.h> |
| 5 | 6 | |
| 6 | 7 | #include <linux/bpf.h> |
| @@ -53,7 +54,7 @@ static inline struct llist_head *ss_lhead_cpu(struct cgroup_subsys *ss, int cpu) · 46 unmodified lines |
| 53 | 54 | } |
| 54 | 55 | |
| 55 | 56 | /** |
| 56 | | − * css_rstat_updated - keep track of updated rstat_cpu |
| 57 | + * __css_rstat_updated - keep track of updated rstat_cpu |
| 57 | 58 | * @css: target cgroup subsystem state |
| 58 | 59 | * @cpu: cpu on which rstat_cpu was updated |
| 59 | 60 | * |
| @@ -63,20 +64,17 @@ static inline struct llist_head *ss_lhead_cpu(struct cgroup_subsys *ss, int cpu) · 3 unmodified lines |
| 63 | 64 | * |
| 64 | 65 | * NOTE: if the user needs the guarantee that the updater either add itself in |
| 65 | 66 | * the lockless list or the concurrent flusher flushes its updated stats, a |
| 66 | | − * memory barrier is needed before the call to css_rstat_updated() i.e. a |
| 67 | + * memory barrier is needed before the call to __css_rstat_updated() i.e. a |
| 67 | 68 | * barrier after updating the per-cpu stats and before calling |
| 68 | | − * css_rstat_updated(). |
| 69 | + * __css_rstat_updated(). |
| 69 | 70 | */ |
| 70 | | −__bpf_kfunc void css_rstat_updated(struct cgroup_subsys_state *css, int cpu) |
| 71 | +void __css_rstat_updated(struct cgroup_subsys_state *css, int cpu) |
| 71 | 72 | { |
| 72 | 73 | struct llist_head *lhead; |
| 73 | 74 | struct css_rstat_cpu *rstatc; |
| 74 | 75 | struct llist_node *self; |
| 75 | 76 | |
| 76 | | − /* |
| 77 | | − * Since bpf programs can call this function, prevent access to |
| 78 | | − * uninitialized rstat pointers. |
| 79 | | − */ |
| 77 | + /* Prevent access to uninitialized rstat pointers. */ |
| 80 | 78 | if (!css_uses_rstat(css)) |
| 81 | 79 | return; |
| 82 | 80 | |
| @@ -125,6 +123,18 @@ __bpf_kfunc void css_rstat_updated(struct cgroup_subsys_state *css, int cpu) · 42 unmodified lines |
| 125 | 123 | llist_add(&rstatc->lnode, lhead); |
| 126 | 124 | } |
| 127 | 125 | |
| 126 | +/* |
| 127 | + * BPF-facing wrapper for __css_rstat_updated(). Validate the caller-provided |
| 128 | + * CPU before passing it to the internal rstat updater. |
| 129 | + */ |
| 130 | +__bpf_kfunc void css_rstat_updated(struct cgroup_subsys_state *css, int cpu) |
| 131 | +{ |
| 132 | + if (unlikely(cpu < 0 || cpu >= nr_cpu_ids || !cpu_possible(cpu))) |
| 133 | + return; |
| 134 | + |
| 135 | + __css_rstat_updated(css, cpu); |
| 136 | +} |
| 137 | + |
| 128 | 138 | static void __css_process_update_tree(struct cgroup_subsys_state *css, int cpu) |
| 129 | 139 | { |
| 130 | 140 | /* put @css and all ancestors on the corresponding updated lists */ |
| @@ -170,7 +180,7 @@ static void css_process_update_tree(struct cgroup_subsys *ss, int cpu) · 39 unmodified lines |
| 170 | 180 | * flusher flush the stats updated by the updater who have |
| 171 | 181 | * observed that they are already on the list. The |
| 172 | 182 | * corresponding barrier pair for this one should be before |
| 173 | | − * css_rstat_updated() by the user. |
| 183 | + * __css_rstat_updated() by the user. |
| 174 | 184 | * |
| 175 | 185 | * For now, there aren't any such user, so not adding the |
| 176 | 186 | * barrier here but if such a use-case arise, please add |
| @@ -614,7 +624,7 @@ static void cgroup_base_stat_cputime_account_end(struct cgroup *cgrp, · 437 unmodified lines |
| 614 | 624 | unsigned long flags) |
| 615 | 625 | { |
| 616 | 626 | u64_stats_update_end_irqrestore(&rstatbc->bsync, flags); |
| 617 | | − css_rstat_updated(&cgrp->self, smp_processor_id()); |
| 627 | + __css_rstat_updated(&cgrp->self, smp_processor_id()); |
| 618 | 628 | put_cpu_ptr(rstatbc); |
| 619 | 629 | } |
| 620 | 630 | |