| @@ -1887,6 +1887,89 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) · 1886 unmodified lines |
| 1887 | 1887 | ctx->generation++; |
| 1888 | 1888 | } |
| 1889 | 1889 | |
| 1890 | +static int |
| 1891 | +perf_aux_output_match(struct perf_event *event, struct perf_event *aux_event) |
| 1892 | +{ |
| 1893 | + if (!has_aux(aux_event)) |
| 1894 | + return 0; |
| 1895 | + |
| 1896 | + if (!event->pmu->aux_output_match) |
| 1897 | + return 0; |
| 1898 | + |
| 1899 | + return event->pmu->aux_output_match(aux_event); |
| 1900 | +} |
| 1901 | + |
| 1902 | +static void put_event(struct perf_event *event); |
| 1903 | +static void event_sched_out(struct perf_event *event, |
| 1904 | + struct perf_cpu_context *cpuctx, |
| 1905 | + struct perf_event_context *ctx); |
| 1906 | + |
| 1907 | +static void perf_put_aux_event(struct perf_event *event) |
| 1908 | +{ |
| 1909 | + struct perf_event_context *ctx = event->ctx; |
| 1910 | + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); |
| 1911 | + struct perf_event *iter; |
| 1912 | + |
| 1913 | + /* |
| 1914 | + * If event uses aux_event tear down the link |
| 1915 | + */ |
| 1916 | + if (event->aux_event) { |
| 1917 | + iter = event->aux_event; |
| 1918 | + event->aux_event = NULL; |
| 1919 | + put_event(iter); |
| 1920 | + return; |
| 1921 | + } |
| 1922 | + |
| 1923 | + /* |
| 1924 | + * If the event is an aux_event, tear down all links to |
| 1925 | + * it from other events. |
| 1926 | + */ |
| 1927 | + for_each_sibling_event(iter, event->group_leader) { |
| 1928 | + if (iter->aux_event != event) |
| 1929 | + continue; |
| 1930 | + |
| 1931 | + iter->aux_event = NULL; |
| 1932 | + put_event(event); |
| 1933 | + |
| 1934 | + /* |
| 1935 | + * If it's ACTIVE, schedule it out and put it into ERROR |
| 1936 | + * state so that we don't try to schedule it again. Note |
| 1937 | + * that perf_event_enable() will clear the ERROR status. |
| 1938 | + */ |
| 1939 | + event_sched_out(iter, cpuctx, ctx); |
| 1940 | + perf_event_set_state(event, PERF_EVENT_STATE_ERROR); |
| 1941 | + } |
| 1942 | +} |
| 1943 | + |
| 1944 | +static int perf_get_aux_event(struct perf_event *event, |
| 1945 | + struct perf_event *group_leader) |
| 1946 | +{ |
| 1947 | + /* |
| 1948 | + * Our group leader must be an aux event if we want to be |
| 1949 | + * an aux_output. This way, the aux event will precede its |
| 1950 | + * aux_output events in the group, and therefore will always |
| 1951 | + * schedule first. |
| 1952 | + */ |
| 1953 | + if (!group_leader) |
| 1954 | + return 0; |
| 1955 | + |
| 1956 | + if (!perf_aux_output_match(event, group_leader)) |
| 1957 | + return 0; |
| 1958 | + |
| 1959 | + if (!atomic_long_inc_not_zero(&group_leader->refcount)) |
| 1960 | + return 0; |
| 1961 | + |
| 1962 | + /* |
| 1963 | + * Link aux_outputs to their aux event; this is undone in |
| 1964 | + * perf_group_detach() by perf_put_aux_event(). When the |
| 1965 | + * group in torn down, the aux_output events loose their |
| 1966 | + * link to the aux_event and can't schedule any more. |
| 1967 | + */ |
| 1968 | + event->aux_event = group_leader; |
| 1969 | + |
| 1970 | + return 1; |
| 1971 | +} |
| 1972 | + |
| 1890 | 1973 | static void perf_group_detach(struct perf_event *event) |
| 1891 | 1974 | { |
| 1892 | 1975 | struct perf_event *sibling, *tmp; |
| @@ -1902,6 +1985,8 @@ static void perf_group_detach(struct perf_event *event) · 9 unmodified lines |
| 1902 | 1985 | |
| 1903 | 1986 | event->attach_state &= ~PERF_ATTACH_GROUP; |
| 1904 | 1987 | |
| 1988 | + perf_put_aux_event(event); |
| 1989 | + |
| 1905 | 1990 | /* |
| 1906 | 1991 | * If this is a sibling, remove it from its group. |
| 1907 | 1992 | */ |
| @@ -10426,6 +10511,12 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 8518 unmodified lines |
| 10426 | 10511 | goto err_ns; |
| 10427 | 10512 | } |
| 10428 | 10513 | |
| 10514 | + if (event->attr.aux_output && |
| 10515 | + !(pmu->capabilities & PERF_PMU_CAP_AUX_OUTPUT)) { |
| 10516 | + err = -EOPNOTSUPP; |
| 10517 | + goto err_pmu; |
| 10518 | + } |
| 10519 | + |
| 10429 | 10520 | err = exclusive_event_init(event); |
| 10430 | 10521 | if (err) |
| 10431 | 10522 | goto err_pmu; |
| @@ -11082,6 +11173,8 @@ SYSCALL_DEFINE5(perf_event_open, · 650 unmodified lines |
| 11082 | 11173 | } |
| 11083 | 11174 | } |
| 11084 | 11175 | |
| 11176 | + if (event->attr.aux_output && !perf_get_aux_event(event, group_leader)) |
| 11177 | + goto err_locked; |
| 11085 | 11178 | |
| 11086 | 11179 | /* |
| 11087 | 11180 | * Must be under the same ctx::mutex as perf_install_in_context(), |