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

ALSA: seq: Use auto-cleanup for client refcounting

The current code manages the refcount of client in a way like:

snd_seq_client *client;
client = clientptr(id);
....
snd_seq_client_unlock(client);

Now we introduce an auto-cleanup macro to manage the unlock
implicitly, namely, the above will be replaced like:

snd_seq_client *client __free(snd_seq_client) = NULL;
client = clientptr(id);

and we can forget the unref call.

A part of the code in snd_seq_deliver_single_event() is factored out
to a function, so that the auto-cleanups can be applied cleanly.

This also allows us to replace some left mutex lock/unlock with
guard(), and also reduce scoped_guard() to the normal guard(), too.

Only code refactoring, and no behavior change.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250827080520.7544-5-tiwai@suse.de

+86 -146
+81 -133
sound/core/seq/seq_clientmgr.c
··· 495 495 */ 496 496 static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event) 497 497 { 498 - struct snd_seq_client *dest; 498 + struct snd_seq_client *dest __free(snd_seq_client) = NULL; 499 499 500 500 dest = snd_seq_client_use_ptr(event->dest.client); 501 501 if (dest == NULL) 502 502 return NULL; 503 503 if (! dest->accept_input) 504 - goto __not_avail; 504 + return NULL; 505 505 if (snd_seq_ev_is_ump(event)) 506 - return dest; /* ok - no filter checks */ 506 + return no_free_ptr(dest); /* ok - no filter checks */ 507 507 508 508 if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) && 509 509 ! test_bit(event->type, dest->event_filter)) 510 - goto __not_avail; 510 + return NULL; 511 511 512 - return dest; /* ok - accessible */ 513 - __not_avail: 514 - snd_seq_client_unlock(dest); 515 - return NULL; 512 + return no_free_ptr(dest); /* ok - accessible */ 516 513 } 517 514 518 515 ··· 606 609 return 0; 607 610 } 608 611 609 - /* 610 - * deliver an event to the specified destination. 611 - * if filter is non-zero, client filter bitmap is tested. 612 - * 613 - * RETURN VALUE: 0 : if succeeded 614 - * <0 : error 615 - */ 616 - static int snd_seq_deliver_single_event(struct snd_seq_client *client, 617 - struct snd_seq_event *event, 618 - int atomic, int hop) 612 + /* deliver a single event; called from snd_seq_deliver_single_event() */ 613 + static int _snd_seq_deliver_single_event(struct snd_seq_client *client, 614 + struct snd_seq_event *event, 615 + int atomic, int hop) 619 616 { 620 - struct snd_seq_client *dest = NULL; 617 + struct snd_seq_client *dest __free(snd_seq_client) = NULL; 621 618 struct snd_seq_client_port *dest_port = NULL; 622 619 int result = -ENOENT; 623 - int direct; 624 - 625 - direct = snd_seq_ev_is_direct(event); 626 620 627 621 dest = get_event_dest_client(event); 628 622 if (dest == NULL) ··· 627 639 result = -EPERM; 628 640 goto __skip; 629 641 } 630 - 642 + 631 643 if (dest_port->timestamping) 632 644 update_timestamp_of_queue(event, dest_port->time_queue, 633 645 dest_port->time_real); ··· 658 670 __skip: 659 671 if (dest_port) 660 672 snd_seq_port_unlock(dest_port); 661 - if (dest) 662 - snd_seq_client_unlock(dest); 673 + return result; 674 + } 663 675 664 - if (result < 0 && !direct) { 665 - result = bounce_error_event(client, event, result, atomic, hop); 666 - } 676 + /* 677 + * deliver an event to the specified destination. 678 + * if filter is non-zero, client filter bitmap is tested. 679 + * 680 + * RETURN VALUE: 0 : if succeeded 681 + * <0 : error 682 + */ 683 + static int snd_seq_deliver_single_event(struct snd_seq_client *client, 684 + struct snd_seq_event *event, 685 + int atomic, int hop) 686 + { 687 + int result = _snd_seq_deliver_single_event(client, event, atomic, hop); 688 + 689 + if (result < 0 && !snd_seq_ev_is_direct(event)) 690 + return bounce_error_event(client, event, result, atomic, hop); 667 691 return result; 668 692 } 669 693 ··· 817 817 */ 818 818 int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) 819 819 { 820 - struct snd_seq_client *client; 820 + struct snd_seq_client *client __free(snd_seq_client) = NULL; 821 821 int result; 822 822 823 823 if (snd_BUG_ON(!cell)) ··· 879 879 snd_seq_cell_free(cell); 880 880 } 881 881 882 - snd_seq_client_unlock(client); 883 882 return result; 884 883 } 885 884 ··· 1170 1171 static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg) 1171 1172 { 1172 1173 struct snd_seq_running_info *info = arg; 1173 - struct snd_seq_client *cptr; 1174 - int err = 0; 1174 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 1175 1175 1176 1176 /* requested client number */ 1177 1177 cptr = client_load_and_use_ptr(info->client); ··· 1178 1180 return -ENOENT; /* don't change !!! */ 1179 1181 1180 1182 #ifdef SNDRV_BIG_ENDIAN 1181 - if (!info->big_endian) { 1182 - err = -EINVAL; 1183 - goto __err; 1184 - } 1183 + if (!info->big_endian) 1184 + return -EINVAL; 1185 1185 #else 1186 - if (info->big_endian) { 1187 - err = -EINVAL; 1188 - goto __err; 1189 - } 1190 - 1186 + if (info->big_endian) 1187 + return -EINVAL; 1191 1188 #endif 1192 - if (info->cpu_mode > sizeof(long)) { 1193 - err = -EINVAL; 1194 - goto __err; 1195 - } 1189 + if (info->cpu_mode > sizeof(long)) 1190 + return -EINVAL; 1196 1191 cptr->convert32 = (info->cpu_mode < sizeof(long)); 1197 - __err: 1198 - snd_seq_client_unlock(cptr); 1199 - return err; 1192 + return 0; 1200 1193 } 1201 1194 1202 1195 /* CLIENT_INFO ioctl() */ ··· 1223 1234 void *arg) 1224 1235 { 1225 1236 struct snd_seq_client_info *client_info = arg; 1226 - struct snd_seq_client *cptr; 1237 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 1227 1238 1228 1239 /* requested client number */ 1229 1240 cptr = client_load_and_use_ptr(client_info->client); ··· 1231 1242 return -ENOENT; /* don't change !!! */ 1232 1243 1233 1244 get_client_info(cptr, client_info); 1234 - snd_seq_client_unlock(cptr); 1235 - 1236 1245 return 0; 1237 1246 } 1238 1247 ··· 1360 1373 static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) 1361 1374 { 1362 1375 struct snd_seq_port_info *info = arg; 1363 - struct snd_seq_client *cptr; 1376 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 1364 1377 struct snd_seq_client_port *port; 1365 1378 1366 1379 cptr = client_load_and_use_ptr(info->addr.client); ··· 1368 1381 return -ENXIO; 1369 1382 1370 1383 port = snd_seq_port_use_ptr(cptr, info->addr.port); 1371 - if (port == NULL) { 1372 - snd_seq_client_unlock(cptr); 1384 + if (port == NULL) 1373 1385 return -ENOENT; /* don't change */ 1374 - } 1375 1386 1376 1387 /* get port info */ 1377 1388 snd_seq_get_port_info(port, info); 1378 1389 snd_seq_port_unlock(port); 1379 - snd_seq_client_unlock(cptr); 1380 - 1381 1390 return 0; 1382 1391 } 1383 1392 ··· 1461 1478 static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, 1462 1479 void *arg) 1463 1480 { 1464 - struct snd_seq_port_subscribe *subs = arg; 1465 1481 int result = -EINVAL; 1466 - struct snd_seq_client *receiver = NULL, *sender = NULL; 1482 + struct snd_seq_port_subscribe *subs = arg; 1483 + struct snd_seq_client *receiver __free(snd_seq_client) = NULL; 1484 + struct snd_seq_client *sender __free(snd_seq_client) = NULL; 1467 1485 struct snd_seq_client_port *sport = NULL, *dport = NULL; 1468 1486 1469 1487 receiver = client_load_and_use_ptr(subs->dest.client); ··· 1494 1510 snd_seq_port_unlock(sport); 1495 1511 if (dport) 1496 1512 snd_seq_port_unlock(dport); 1497 - if (sender) 1498 - snd_seq_client_unlock(sender); 1499 - if (receiver) 1500 - snd_seq_client_unlock(receiver); 1501 1513 return result; 1502 1514 } 1503 1515 ··· 1504 1524 static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, 1505 1525 void *arg) 1506 1526 { 1507 - struct snd_seq_port_subscribe *subs = arg; 1508 1527 int result = -ENXIO; 1509 - struct snd_seq_client *receiver = NULL, *sender = NULL; 1528 + struct snd_seq_port_subscribe *subs = arg; 1529 + struct snd_seq_client *receiver __free(snd_seq_client) = NULL; 1530 + struct snd_seq_client *sender __free(snd_seq_client) = NULL; 1510 1531 struct snd_seq_client_port *sport = NULL, *dport = NULL; 1511 1532 1512 1533 receiver = snd_seq_client_use_ptr(subs->dest.client); ··· 1536 1555 snd_seq_port_unlock(sport); 1537 1556 if (dport) 1538 1557 snd_seq_port_unlock(dport); 1539 - if (sender) 1540 - snd_seq_client_unlock(sender); 1541 - if (receiver) 1542 - snd_seq_client_unlock(receiver); 1543 1558 return result; 1544 1559 } 1545 1560 ··· 1826 1849 void *arg) 1827 1850 { 1828 1851 struct snd_seq_client_pool *info = arg; 1829 - struct snd_seq_client *cptr; 1852 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 1830 1853 1831 1854 cptr = client_load_and_use_ptr(info->client); 1832 1855 if (cptr == NULL) ··· 1845 1868 info->input_pool = 0; 1846 1869 info->input_free = 0; 1847 1870 } 1848 - snd_seq_client_unlock(cptr); 1849 1871 1850 1872 return 0; 1851 1873 } ··· 1927 1951 { 1928 1952 struct snd_seq_port_subscribe *subs = arg; 1929 1953 int result; 1930 - struct snd_seq_client *sender = NULL; 1954 + struct snd_seq_client *sender __free(snd_seq_client) = NULL; 1931 1955 struct snd_seq_client_port *sport = NULL; 1932 1956 1933 1957 result = -EINVAL; ··· 1942 1966 __end: 1943 1967 if (sport) 1944 1968 snd_seq_port_unlock(sport); 1945 - if (sender) 1946 - snd_seq_client_unlock(sender); 1947 1969 1948 1970 return result; 1949 1971 } ··· 1954 1980 { 1955 1981 struct snd_seq_query_subs *subs = arg; 1956 1982 int result = -ENXIO; 1957 - struct snd_seq_client *cptr = NULL; 1983 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 1958 1984 struct snd_seq_client_port *port = NULL; 1959 1985 struct snd_seq_port_subs_info *group; 1960 1986 struct list_head *p; ··· 2005 2031 __end: 2006 2032 if (port) 2007 2033 snd_seq_port_unlock(port); 2008 - if (cptr) 2009 - snd_seq_client_unlock(cptr); 2010 2034 2011 2035 return result; 2012 2036 } ··· 2017 2045 void *arg) 2018 2046 { 2019 2047 struct snd_seq_client_info *info = arg; 2020 - struct snd_seq_client *cptr = NULL; 2048 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 2021 2049 2022 2050 /* search for next client */ 2023 2051 if (info->client < INT_MAX) ··· 2026 2054 info->client = 0; 2027 2055 for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) { 2028 2056 cptr = client_load_and_use_ptr(info->client); 2029 - if (cptr) 2030 - break; /* found */ 2057 + if (cptr) { 2058 + get_client_info(cptr, info); 2059 + return 0; /* found */ 2060 + } 2031 2061 } 2032 - if (cptr == NULL) 2033 - return -ENOENT; 2034 - 2035 - get_client_info(cptr, info); 2036 - snd_seq_client_unlock(cptr); 2037 - 2038 - return 0; 2062 + return -ENOENT; 2039 2063 } 2040 2064 2041 2065 /* ··· 2041 2073 void *arg) 2042 2074 { 2043 2075 struct snd_seq_port_info *info = arg; 2044 - struct snd_seq_client *cptr; 2076 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 2045 2077 struct snd_seq_client_port *port = NULL; 2046 2078 2047 2079 cptr = client_load_and_use_ptr(info->addr.client); ··· 2051 2083 /* search for next port */ 2052 2084 info->addr.port++; 2053 2085 port = snd_seq_port_query_nearest(cptr, info); 2054 - if (port == NULL) { 2055 - snd_seq_client_unlock(cptr); 2086 + if (port == NULL) 2056 2087 return -ENOENT; 2057 - } 2058 2088 2059 2089 /* get port info */ 2060 2090 info->addr = port->addr; 2061 2091 snd_seq_get_port_info(port, info); 2062 2092 snd_seq_port_unlock(port); 2063 - snd_seq_client_unlock(cptr); 2064 2093 2065 2094 return 0; 2066 2095 } ··· 2122 2157 { 2123 2158 struct snd_seq_client_ump_info __user *argp = 2124 2159 (struct snd_seq_client_ump_info __user *)arg; 2125 - struct snd_seq_client *cptr; 2160 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 2126 2161 int client, type, err = 0; 2127 2162 size_t size; 2128 2163 void *p; ··· 2145 2180 scoped_guard(mutex, &cptr->ioctl_mutex) { 2146 2181 if (!cptr->midi_version) { 2147 2182 err = -EBADFD; 2148 - goto error; 2183 + break; 2149 2184 } 2150 2185 2151 2186 if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) { ··· 2155 2190 p = cptr->ump_info[type]; 2156 2191 if (!p) { 2157 2192 err = -ENODEV; 2158 - goto error; 2193 + break; 2159 2194 } 2160 2195 if (copy_to_user(argp->info, p, size)) { 2161 2196 err = -EFAULT; 2162 - goto error; 2197 + break; 2163 2198 } 2164 2199 } else { 2165 2200 if (cptr->type != USER_CLIENT) { 2166 2201 err = -EBADFD; 2167 - goto error; 2202 + break; 2168 2203 } 2169 2204 if (!cptr->ump_info) { 2170 2205 cptr->ump_info = kcalloc(NUM_UMP_INFOS, 2171 2206 sizeof(void *), GFP_KERNEL); 2172 2207 if (!cptr->ump_info) { 2173 2208 err = -ENOMEM; 2174 - goto error; 2209 + break; 2175 2210 } 2176 2211 } 2177 2212 p = memdup_user(argp->info, size); 2178 2213 if (IS_ERR(p)) { 2179 2214 err = PTR_ERR(p); 2180 - goto error; 2215 + break; 2181 2216 } 2182 2217 kfree(cptr->ump_info[type]); 2183 2218 terminate_ump_info_strings(p, type); 2184 2219 cptr->ump_info[type] = p; 2185 2220 } 2186 - } 2187 2221 2188 - error: 2189 - snd_seq_client_unlock(cptr); 2222 + } 2190 2223 if (!err && cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO) { 2191 2224 if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) 2192 2225 snd_seq_system_ump_notify(client, 0, ··· 2397 2434 int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, 2398 2435 struct file *file, bool blocking) 2399 2436 { 2400 - struct snd_seq_client *cptr; 2401 - int result; 2437 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 2402 2438 2403 2439 if (snd_BUG_ON(!ev)) 2404 2440 return -EINVAL; ··· 2420 2458 return -EINVAL; 2421 2459 2422 2460 if (!cptr->accept_output) { 2423 - result = -EPERM; 2461 + return -EPERM; 2424 2462 } else { /* send it */ 2425 2463 guard(mutex)(&cptr->ioctl_mutex); 2426 - result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, 2427 - false, 0, 2428 - &cptr->ioctl_mutex); 2464 + return snd_seq_client_enqueue_event(cptr, ev, file, blocking, 2465 + false, 0, 2466 + &cptr->ioctl_mutex); 2429 2467 } 2430 - 2431 - snd_seq_client_unlock(cptr); 2432 - return result; 2433 2468 } 2434 2469 EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); 2435 2470 ··· 2440 2481 int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, 2441 2482 int atomic, int hop) 2442 2483 { 2443 - struct snd_seq_client *cptr; 2444 - int result; 2484 + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; 2445 2485 2446 2486 if (snd_BUG_ON(!ev)) 2447 2487 return -EINVAL; ··· 2457 2499 return -EINVAL; 2458 2500 2459 2501 if (!cptr->accept_output) 2460 - result = -EPERM; 2502 + return -EPERM; 2461 2503 else 2462 - result = snd_seq_deliver_event(cptr, ev, atomic, hop); 2463 - 2464 - snd_seq_client_unlock(cptr); 2465 - return result; 2504 + return snd_seq_deliver_event(cptr, ev, atomic, hop); 2466 2505 } 2467 2506 EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); 2468 2507 ··· 2505 2550 /* a similar like above but taking locks; used only from OSS sequencer layer */ 2506 2551 int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg) 2507 2552 { 2508 - struct snd_seq_client *client; 2509 - int ret; 2553 + struct snd_seq_client *client __free(snd_seq_client) = NULL; 2510 2554 2511 2555 client = client_load_and_use_ptr(clientid); 2512 2556 if (!client) 2513 2557 return -ENXIO; 2514 - scoped_guard(mutex, &client->ioctl_mutex) { 2515 - ret = call_seq_client_ctl(client, cmd, arg); 2516 - } 2517 - snd_seq_client_unlock(client); 2518 - return ret; 2558 + guard(mutex)(&client->ioctl_mutex); 2559 + return call_seq_client_ctl(client, cmd, arg); 2519 2560 } 2520 2561 EXPORT_SYMBOL_GPL(snd_seq_kernel_client_ioctl); 2521 2562 ··· 2541 2590 void snd_seq_kernel_client_put(struct snd_seq_client *cptr) 2542 2591 { 2543 2592 if (cptr) 2544 - snd_seq_client_unlock(cptr); 2593 + snd_seq_client_unref(cptr); 2545 2594 } 2546 2595 EXPORT_SYMBOL_GPL(snd_seq_kernel_client_put); 2547 2596 ··· 2643 2692 struct snd_info_buffer *buffer) 2644 2693 { 2645 2694 int c; 2646 - struct snd_seq_client *client; 2647 2695 2648 2696 snd_iprintf(buffer, "Client info\n"); 2649 2697 snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur); ··· 2652 2702 2653 2703 /* list the client table */ 2654 2704 for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) { 2705 + struct snd_seq_client *client __free(snd_seq_client) = NULL; 2706 + 2655 2707 client = client_load_and_use_ptr(c); 2656 2708 if (client == NULL) 2657 2709 continue; 2658 - if (client->type == NO_CLIENT) { 2659 - snd_seq_client_unlock(client); 2710 + if (client->type == NO_CLIENT) 2660 2711 continue; 2661 - } 2662 2712 2663 - mutex_lock(&client->ioctl_mutex); 2713 + guard(mutex)(&client->ioctl_mutex); 2664 2714 snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n", 2665 2715 c, client->name, 2666 2716 client->type == USER_CLIENT ? "User" : "Kernel", ··· 2678 2728 snd_iprintf(buffer, " Input pool :\n"); 2679 2729 snd_seq_info_pool(buffer, client->data.user.fifo->pool, " "); 2680 2730 } 2681 - mutex_unlock(&client->ioctl_mutex); 2682 - snd_seq_client_unlock(client); 2683 2731 } 2684 2732 } 2685 2733 #endif /* CONFIG_SND_PROC_FS */
+1 -1
sound/core/seq/seq_clientmgr.h
··· 91 91 snd_use_lock_free(&client->use_lock); 92 92 } 93 93 94 - #define snd_seq_client_unlock(c) snd_seq_client_unref(c) 94 + DEFINE_FREE(snd_seq_client, struct snd_seq_client *, if (!IS_ERR_OR_NULL(_T)) snd_seq_client_unref(_T)) 95 95 96 96 /* dispatch event to client(s) */ 97 97 int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop);
+4 -12
sound/core/seq/seq_ports.c
··· 178 178 static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, 179 179 struct snd_seq_client **cp) 180 180 { 181 - struct snd_seq_client_port *p; 182 181 *cp = snd_seq_client_use_ptr(addr->client); 183 - if (*cp) { 184 - p = snd_seq_port_use_ptr(*cp, addr->port); 185 - if (! p) { 186 - snd_seq_client_unlock(*cp); 187 - *cp = NULL; 188 - } 189 - return p; 190 - } 191 - return NULL; 182 + if (!*cp) 183 + return NULL; 184 + return snd_seq_port_use_ptr(*cp, addr->port); 192 185 } 193 186 194 187 static void delete_and_unsubscribe_port(struct snd_seq_client *client, ··· 211 218 212 219 list_for_each_safe(p, n, &grp->list_head) { 213 220 struct snd_seq_subscribers *subs; 214 - struct snd_seq_client *c; 221 + struct snd_seq_client *c __free(snd_seq_client) = NULL; 215 222 struct snd_seq_client_port *aport; 216 223 217 224 subs = get_subscriber(p, is_src); ··· 235 242 delete_and_unsubscribe_port(c, aport, subs, !is_src, true); 236 243 kfree(subs); 237 244 snd_seq_port_unlock(aport); 238 - snd_seq_client_unlock(c); 239 245 } 240 246 } 241 247