diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-06-03 15:43:29 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-06-03 17:33:28 -0400 |
commit | 872c78202c58d26596e25743791ee81a7d24abad (patch) | |
tree | 5cca75beabf74f82a26b5649e2ae9aa23e4996fb /sound | |
parent | 10a8ebbb08c4b08292598947bbe534e04d6ee705 (diff) |
ALSA: Fix double locking of card list in snd_card_register()
The introduction of snd_card_set_id() added a lock on the card list
to the old choose_default_id() function when using it to implement
the new API call. This lock is needed to allow us to walk the list
and check to see if our new name is a duplicate. Unfortunately this
causes a lockup when called from snd_card_register() (in cases
where no ID is supplied for the card) since the card list is already
locked there.
Fix this fairly hideously by factoring out the implementation and
using a flag to indicate if the lock should be held. A better fix
would probably be to refactor snd_card_register() to move the
_set_id() outside the locking region but I can't immediately see
anything I can convince myself is safe.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/init.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/sound/core/init.c b/sound/core/init.c index 6557dd85e191..a578d05f9e13 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -476,15 +476,8 @@ int snd_card_free(struct snd_card *card) | |||
476 | 476 | ||
477 | EXPORT_SYMBOL(snd_card_free); | 477 | EXPORT_SYMBOL(snd_card_free); |
478 | 478 | ||
479 | /** | 479 | static void snd_card_set_id_internal(struct snd_card *card, const char *nid, |
480 | * snd_card_set_id - set card identification name | 480 | int do_locking) |
481 | * @card: soundcard structure | ||
482 | * @nid: new identification string | ||
483 | * | ||
484 | * This function sets the card identification and checks for name | ||
485 | * collisions. | ||
486 | */ | ||
487 | void snd_card_set_id(struct snd_card *card, const char *nid) | ||
488 | { | 481 | { |
489 | int i, len, idx_flag = 0, loops = SNDRV_CARDS; | 482 | int i, len, idx_flag = 0, loops = SNDRV_CARDS; |
490 | const char *spos, *src; | 483 | const char *spos, *src; |
@@ -529,14 +522,16 @@ void snd_card_set_id(struct snd_card *card, const char *nid) | |||
529 | } | 522 | } |
530 | if (!snd_info_check_reserved_words(id)) | 523 | if (!snd_info_check_reserved_words(id)) |
531 | goto __change; | 524 | goto __change; |
532 | mutex_lock(&snd_card_mutex); | 525 | if (do_locking) |
526 | mutex_lock(&snd_card_mutex); | ||
533 | for (i = 0; i < snd_ecards_limit; i++) { | 527 | for (i = 0; i < snd_ecards_limit; i++) { |
534 | if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) { | 528 | if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) { |
535 | mutex_unlock(&snd_card_mutex); | 529 | mutex_unlock(&snd_card_mutex); |
536 | goto __change; | 530 | goto __change; |
537 | } | 531 | } |
538 | } | 532 | } |
539 | mutex_unlock(&snd_card_mutex); | 533 | if (do_locking) |
534 | mutex_unlock(&snd_card_mutex); | ||
540 | break; | 535 | break; |
541 | 536 | ||
542 | __change: | 537 | __change: |
@@ -561,6 +556,18 @@ void snd_card_set_id(struct snd_card *card, const char *nid) | |||
561 | } | 556 | } |
562 | } | 557 | } |
563 | 558 | ||
559 | /** | ||
560 | * snd_card_set_id - set card identification name | ||
561 | * @card: soundcard structure | ||
562 | * @nid: new identification string | ||
563 | * | ||
564 | * This function sets the card identification and checks for name | ||
565 | * collisions. | ||
566 | */ | ||
567 | void snd_card_set_id(struct snd_card *card, const char *nid) | ||
568 | { | ||
569 | snd_card_set_id_internal(card, nid, 1); | ||
570 | } | ||
564 | EXPORT_SYMBOL(snd_card_set_id); | 571 | EXPORT_SYMBOL(snd_card_set_id); |
565 | 572 | ||
566 | #ifndef CONFIG_SYSFS_DEPRECATED | 573 | #ifndef CONFIG_SYSFS_DEPRECATED |
@@ -657,7 +664,7 @@ int snd_card_register(struct snd_card *card) | |||
657 | return 0; | 664 | return 0; |
658 | } | 665 | } |
659 | if (card->id[0] == '\0') | 666 | if (card->id[0] == '\0') |
660 | snd_card_set_id(card, NULL); | 667 | snd_card_set_id_internal(card, NULL, 0); |
661 | snd_cards[card->number] = card; | 668 | snd_cards[card->number] = card; |
662 | mutex_unlock(&snd_card_mutex); | 669 | mutex_unlock(&snd_card_mutex); |
663 | init_info_for_card(card); | 670 | init_info_for_card(card); |