| @@ -1887,6 +1887,89 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) · 1886 unmodified lines |
| 1887 | ctx->generation++; | 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 | static void perf_group_detach(struct perf_event *event) | 1973 | static void perf_group_detach(struct perf_event *event) |
| 1891 | { | 1974 | { |
| 1892 | struct perf_event *sibling, *tmp; | 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 | event->attach_state &= ~PERF_ATTACH_GROUP; | 1986 | event->attach_state &= ~PERF_ATTACH_GROUP; |
| 1904 | | 1987 | |
| | 1988 | perf_put_aux_event(event); |
| | 1989 | |
| 1905 | /* | 1990 | /* |
| 1906 | * If this is a sibling, remove it from its group. | 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 | goto err_ns; | 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 | err = exclusive_event_init(event); | 10520 | err = exclusive_event_init(event); |
| 10430 | if (err) | 10521 | if (err) |
| 10431 | goto err_pmu; | 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 | * Must be under the same ctx::mutex as perf_install_in_context(), | 11180 | * Must be under the same ctx::mutex as perf_install_in_context(), |