The current ALSA sequencer core tries to register the new kernel
sequencer port on the list at first, then fill up the port
information. This means that user-space may sneak the wrong
information before the actual data is filled, which isn't ideal.
Although the user-space should try to query the port info after the
port registration notification is sent out, it'd be still better to
have a port available with the full info from the beginning.
This patch changes the sequencer port creation and registration
procedure; now split to two steps, for creation and insertion, and the
port is registered after the information is filled.
Link: https://sashiko.dev/#/patchset/20260518194023.1667857-1-maoyixie.tju%40gmail.com
Link: https://patch.msgid.link/20260519094254.465041-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
port_idx = -1;
if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN)
return -EINVAL;
port_idx = -1;
if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN)
return -EINVAL;
- err = snd_seq_create_port(client, port_idx, &port);
+ err = snd_seq_create_port(client, &port);
info->addr = port->addr;
snd_seq_set_port_info(port, info);
info->addr = port->addr;
snd_seq_set_port_info(port, info);
+ err = snd_seq_insert_port(client, port_idx, port);
+ if (err < 0) {
+ kfree(port);
+ return err;
+ }
if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT)
client->ump_endpoint_port = port->addr.port;
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT)
client->ump_endpoint_port = port->addr.port;
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
-/* create a port, port number or a negative error code is returned
+/* create a port, 0 on success or a negative error code is returned
* the caller needs to unref the port via snd_seq_port_unlock() appropriately
*/
* the caller needs to unref the port via snd_seq_port_unlock() appropriately
*/
-int snd_seq_create_port(struct snd_seq_client *client, int port,
+int snd_seq_create_port(struct snd_seq_client *client,
struct snd_seq_client_port **port_ret)
{
struct snd_seq_client_port **port_ret)
{
- struct snd_seq_client_port *new_port, *p;
- int num;
+ struct snd_seq_client_port *new_port;
port_subs_info_init(&new_port->c_dest);
snd_use_lock_use(&new_port->use_lock);
port_subs_info_init(&new_port->c_dest);
snd_use_lock_use(&new_port->use_lock);
+ *port_ret = new_port;
+
+ return 0;
+}
+
+/* insert the port; return the port address or a negative error code */
+int snd_seq_insert_port(struct snd_seq_client *client, int port,
+ struct snd_seq_client_port *new_port)
+{
+ struct snd_seq_client_port *p;
+ int num;
+
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
guard(write_lock_irq)(&client->ports_lock);
struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
guard(write_lock_irq)(&client->ports_lock);
struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
- if (p->addr.port == port) {
- kfree(new_port);
+ if (p->addr.port == port)
if (p->addr.port > num) {
insert_before = &p->list;
break;
if (p->addr.port > num) {
insert_before = &p->list;
break;
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
DEFINE_FREE(snd_seq_port, struct snd_seq_client_port *, if (!IS_ERR_OR_NULL(_T)) snd_seq_port_unlock(_T))
DEFINE_FREE(snd_seq_port, struct snd_seq_client_port *, if (!IS_ERR_OR_NULL(_T)) snd_seq_port_unlock(_T))
-/* create a port, port number or a negative error code is returned */
-int snd_seq_create_port(struct snd_seq_client *client, int port_index,
+/* create a port, 0 on success or a negative error code is returned */
+int snd_seq_create_port(struct snd_seq_client *client,
struct snd_seq_client_port **port_ret);
struct snd_seq_client_port **port_ret);
+/* insert the port; return the port address or a negative error code */
+int snd_seq_insert_port(struct snd_seq_client *client, int port,
+ struct snd_seq_client_port *new_port);
+
/* delete a port */
int snd_seq_delete_port(struct snd_seq_client *client, int port);
/* delete a port */
int snd_seq_delete_port(struct snd_seq_client *client, int port);