ALSA: seq-oss: Initialize MIDI clients asynchronously
We've got bug reports that the module loading stuck on Debian system with 3.10 kernel. The debugging session revealed that the initial registration of OSS sequencer clients stuck at module loading time, which involves again with request_module() at the init phase. This is triggered only by special --install stuff Debian is using, but it's still not good to have such loops. As a workaround, call the registration part asynchronously. This is a better approach irrespective of the hang fix, in anyway. Reported-and-tested-by: Philipp Matthias Hahn <pmhahn@pmhahn.de> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common variables
|
* common variables
|
||||||
@@ -60,6 +61,14 @@ static void free_devinfo(void *private);
|
|||||||
#define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
|
#define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
|
||||||
|
|
||||||
|
|
||||||
|
/* call snd_seq_oss_midi_lookup_ports() asynchronously */
|
||||||
|
static void async_call_lookup_ports(struct work_struct *work)
|
||||||
|
{
|
||||||
|
snd_seq_oss_midi_lookup_ports(system_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLARE_WORK(async_lookup_work, async_call_lookup_ports);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create sequencer client for OSS sequencer
|
* create sequencer client for OSS sequencer
|
||||||
*/
|
*/
|
||||||
@@ -85,9 +94,6 @@ snd_seq_oss_create_client(void)
|
|||||||
system_client = rc;
|
system_client = rc;
|
||||||
debug_printk(("new client = %d\n", rc));
|
debug_printk(("new client = %d\n", rc));
|
||||||
|
|
||||||
/* look up midi devices */
|
|
||||||
snd_seq_oss_midi_lookup_ports(system_client);
|
|
||||||
|
|
||||||
/* create annoucement receiver port */
|
/* create annoucement receiver port */
|
||||||
memset(port, 0, sizeof(*port));
|
memset(port, 0, sizeof(*port));
|
||||||
strcpy(port->name, "Receiver");
|
strcpy(port->name, "Receiver");
|
||||||
@@ -115,6 +121,9 @@ snd_seq_oss_create_client(void)
|
|||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
|
/* look up midi devices */
|
||||||
|
schedule_work(&async_lookup_work);
|
||||||
|
|
||||||
__error:
|
__error:
|
||||||
kfree(port);
|
kfree(port);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -160,6 +169,7 @@ receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic
|
|||||||
int
|
int
|
||||||
snd_seq_oss_delete_client(void)
|
snd_seq_oss_delete_client(void)
|
||||||
{
|
{
|
||||||
|
cancel_work_sync(&async_lookup_work);
|
||||||
if (system_client >= 0)
|
if (system_client >= 0)
|
||||||
snd_seq_delete_kernel_client(system_client);
|
snd_seq_delete_kernel_client(system_client);
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
|
|||||||
* look up the existing ports
|
* look up the existing ports
|
||||||
* this looks a very exhausting job.
|
* this looks a very exhausting job.
|
||||||
*/
|
*/
|
||||||
int __init
|
int
|
||||||
snd_seq_oss_midi_lookup_ports(int client)
|
snd_seq_oss_midi_lookup_ports(int client)
|
||||||
{
|
{
|
||||||
struct snd_seq_client_info *clinfo;
|
struct snd_seq_client_info *clinfo;
|
||||||
|
Reference in New Issue
Block a user