Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing/user_events: Prepare find/delete for same name events

The current code for finding and deleting events assumes that there will
never be cases when user_events are registered with the same name, but
different formats. Scenarios exist where programs want to use the same
name but have different formats. An example is multiple versions of a
program running side-by-side using the same event name, but with updated
formats in each version.

This change does not yet allow for multi-format events. If user_events
are registered with the same name but different arguments the programs
see the same return values as before. This change simply makes it
possible to easily accommodate for this.

Update find_user_event() to take in argument parameters and register
flags to accommodate future multi-format event scenarios. Have find
validate argument matching and return error pointers to cover when
an existing event has the same name but different format. Update
callers to handle error pointer logic.

Move delete_user_event() to use hash walking directly now that
find_user_event() has changed. Delete all events found that match the
register name, stop if an error occurs and report back to the user.

Update user_fields_match() to cover list_empty() scenarios now that
find_user_event() uses it directly. This makes the logic consistent
across several callsites.

Link: https://lore.kernel.org/linux-trace-kernel/20240222001807.1463-2-beaub@linux.microsoft.com

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Beau Belgrave and committed by
Steven Rostedt (Google)
1e953de9 180e4e39

+59 -48
+59 -48
kernel/trace/trace_events_user.c
··· 202 202 static struct user_event_mm *user_event_mm_get_all(struct user_event *user); 203 203 static void user_event_mm_put(struct user_event_mm *mm); 204 204 static int destroy_user_event(struct user_event *user); 205 + static bool user_fields_match(struct user_event *user, int argc, 206 + const char **argv); 205 207 206 208 static u32 user_event_key(char *name) 207 209 { ··· 1495 1493 } 1496 1494 1497 1495 static struct user_event *find_user_event(struct user_event_group *group, 1498 - char *name, u32 *outkey) 1496 + char *name, int argc, const char **argv, 1497 + u32 flags, u32 *outkey) 1499 1498 { 1500 1499 struct user_event *user; 1501 1500 u32 key = user_event_key(name); 1502 1501 1503 1502 *outkey = key; 1504 1503 1505 - hash_for_each_possible(group->register_table, user, node, key) 1506 - if (!strcmp(EVENT_NAME(user), name)) 1504 + hash_for_each_possible(group->register_table, user, node, key) { 1505 + if (strcmp(EVENT_NAME(user), name)) 1506 + continue; 1507 + 1508 + if (user_fields_match(user, argc, argv)) 1507 1509 return user_event_get(user); 1510 + 1511 + return ERR_PTR(-EADDRINUSE); 1512 + } 1508 1513 1509 1514 return NULL; 1510 1515 } ··· 1869 1860 struct list_head *head = &user->fields; 1870 1861 int i = 0; 1871 1862 1863 + if (argc == 0) 1864 + return list_empty(head); 1865 + 1872 1866 list_for_each_entry_reverse(field, head, link) { 1873 1867 if (!user_field_match(field, argc, argv, &i)) 1874 1868 return false; ··· 1892 1880 match = strcmp(EVENT_NAME(user), event) == 0 && 1893 1881 (!system || strcmp(system, USER_EVENTS_SYSTEM) == 0); 1894 1882 1895 - if (match && argc > 0) 1883 + if (match) 1896 1884 match = user_fields_match(user, argc, argv); 1897 - else if (match && argc == 0) 1898 - match = list_empty(&user->fields); 1899 1885 1900 1886 return match; 1901 1887 } ··· 1932 1922 char *args, char *flags, 1933 1923 struct user_event **newuser, int reg_flags) 1934 1924 { 1925 + struct user_event *user; 1926 + char **argv = NULL; 1927 + int argc = 0; 1935 1928 int ret; 1936 1929 u32 key; 1937 - struct user_event *user; 1938 - int argc = 0; 1939 - char **argv; 1940 1930 1941 1931 /* Currently don't support any text based flags */ 1942 1932 if (flags != NULL) ··· 1945 1935 if (!user_event_capable(reg_flags)) 1946 1936 return -EPERM; 1947 1937 1938 + if (args) { 1939 + argv = argv_split(GFP_KERNEL, args, &argc); 1940 + 1941 + if (!argv) 1942 + return -ENOMEM; 1943 + } 1944 + 1948 1945 /* Prevent dyn_event from racing */ 1949 1946 mutex_lock(&event_mutex); 1950 - user = find_user_event(group, name, &key); 1947 + user = find_user_event(group, name, argc, (const char **)argv, 1948 + reg_flags, &key); 1951 1949 mutex_unlock(&event_mutex); 1952 1950 1951 + if (argv) 1952 + argv_free(argv); 1953 + 1954 + if (IS_ERR(user)) 1955 + return PTR_ERR(user); 1956 + 1953 1957 if (user) { 1954 - if (args) { 1955 - argv = argv_split(GFP_KERNEL, args, &argc); 1956 - if (!argv) { 1957 - ret = -ENOMEM; 1958 - goto error; 1959 - } 1960 - 1961 - ret = user_fields_match(user, argc, (const char **)argv); 1962 - argv_free(argv); 1963 - 1964 - } else 1965 - ret = list_empty(&user->fields); 1966 - 1967 - if (ret) { 1968 - *newuser = user; 1969 - /* 1970 - * Name is allocated by caller, free it since it already exists. 1971 - * Caller only worries about failure cases for freeing. 1972 - */ 1973 - kfree(name); 1974 - } else { 1975 - ret = -EADDRINUSE; 1976 - goto error; 1977 - } 1958 + *newuser = user; 1959 + /* 1960 + * Name is allocated by caller, free it since it already exists. 1961 + * Caller only worries about failure cases for freeing. 1962 + */ 1963 + kfree(name); 1978 1964 1979 1965 return 0; 1980 - error: 1981 - user_event_put(user, false); 1982 - return ret; 1983 1966 } 1984 1967 1985 1968 user = kzalloc(sizeof(*user), GFP_KERNEL_ACCOUNT); ··· 2055 2052 } 2056 2053 2057 2054 /* 2058 - * Deletes a previously created event if it is no longer being used. 2055 + * Deletes previously created events if they are no longer being used. 2059 2056 */ 2060 2057 static int delete_user_event(struct user_event_group *group, char *name) 2061 2058 { 2062 - u32 key; 2063 - struct user_event *user = find_user_event(group, name, &key); 2059 + struct user_event *user; 2060 + struct hlist_node *tmp; 2061 + u32 key = user_event_key(name); 2062 + int ret = -ENOENT; 2064 2063 2065 - if (!user) 2066 - return -ENOENT; 2064 + /* Attempt to delete all event(s) with the name passed in */ 2065 + hash_for_each_possible_safe(group->register_table, user, tmp, node, key) { 2066 + if (strcmp(EVENT_NAME(user), name)) 2067 + continue; 2067 2068 2068 - user_event_put(user, true); 2069 + if (!user_event_last_ref(user)) 2070 + return -EBUSY; 2069 2071 2070 - if (!user_event_last_ref(user)) 2071 - return -EBUSY; 2072 + if (!user_event_capable(user->reg_flags)) 2073 + return -EPERM; 2072 2074 2073 - if (!user_event_capable(user->reg_flags)) 2074 - return -EPERM; 2075 + ret = destroy_user_event(user); 2075 2076 2076 - return destroy_user_event(user); 2077 + if (ret) 2078 + goto out; 2079 + } 2080 + out: 2081 + return ret; 2077 2082 } 2078 2083 2079 2084 /*