From: Greg Kroah-Hartman Date: Thu, 1 Nov 2012 17:12:59 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.51~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bfcd2ab46d11cc9ce5651635c4e3b75530e1d11d;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: alsa-avoid-endless-sleep-after-disconnect.patch alsa-pcm-fix-some-races-at-disconnection.patch mm-fix-xfs-oops-due-to-dirty-pages-without-buffers-on-s390.patch --- diff --git a/queue-3.0/alsa-avoid-endless-sleep-after-disconnect.patch b/queue-3.0/alsa-avoid-endless-sleep-after-disconnect.patch new file mode 100644 index 00000000000..fb63cae7425 --- /dev/null +++ b/queue-3.0/alsa-avoid-endless-sleep-after-disconnect.patch @@ -0,0 +1,182 @@ +From 0914f7961babbf28aaa2f19b453951fb4841c03f Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 16 Oct 2012 16:43:39 +0200 +Subject: ALSA: Avoid endless sleep after disconnect + +From: Takashi Iwai + +commit 0914f7961babbf28aaa2f19b453951fb4841c03f upstream. + +When disconnect callback is called, each component should wake up +sleepers and check card->shutdown flag for avoiding the endless sleep +blocking the proper resource release. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/control.c | 2 ++ + sound/core/hwdep.c | 7 +++++++ + sound/core/oss/pcm_oss.c | 4 ++++ + sound/core/pcm.c | 6 +++++- + sound/core/pcm_native.c | 8 ++++++++ + sound/core/rawmidi.c | 20 ++++++++++++++++++++ + 6 files changed, 46 insertions(+), 1 deletion(-) + +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -1360,6 +1360,8 @@ static ssize_t snd_ctl_read(struct file + spin_unlock_irq(&ctl->read_lock); + schedule(); + remove_wait_queue(&ctl->change_sleep, &wait); ++ if (ctl->card->shutdown) ++ return -ENODEV; + if (signal_pending(current)) + return -ERESTARTSYS; + spin_lock_irq(&ctl->read_lock); +--- a/sound/core/hwdep.c ++++ b/sound/core/hwdep.c +@@ -128,6 +128,10 @@ static int snd_hwdep_open(struct inode * + mutex_unlock(&hw->open_mutex); + schedule(); + mutex_lock(&hw->open_mutex); ++ if (hw->card->shutdown) { ++ err = -ENODEV; ++ break; ++ } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; +@@ -451,12 +455,15 @@ static int snd_hwdep_dev_disconnect(stru + mutex_unlock(®ister_mutex); + return -EINVAL; + } ++ mutex_lock(&hwdep->open_mutex); ++ wake_up(&hwdep->open_wait); + #ifdef CONFIG_SND_OSSEMUL + if (hwdep->ossreg) + snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); + #endif + snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); + list_del_init(&hwdep->list); ++ mutex_unlock(&hwdep->open_mutex); + mutex_unlock(®ister_mutex); + return 0; + } +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode + mutex_unlock(&pcm->open_mutex); + schedule(); + mutex_lock(&pcm->open_mutex); ++ if (pcm->card->shutdown) { ++ err = -ENODEV; ++ break; ++ } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -1046,12 +1046,16 @@ static int snd_pcm_dev_disconnect(struct + goto unlock; + + mutex_lock(&pcm->open_mutex); ++ wake_up(&pcm->open_wait); + list_del_init(&pcm->list); + for (cidx = 0; cidx < 2; cidx++) + for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { + snd_pcm_stream_lock_irq(substream); +- if (substream->runtime) ++ if (substream->runtime) { + substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; ++ wake_up(&substream->runtime->sleep); ++ wake_up(&substream->runtime->tsleep); ++ } + snd_pcm_stream_unlock_irq(substream); + } + list_for_each_entry(notify, &snd_pcm_notify_list, list) { +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1507,6 +1507,10 @@ static int snd_pcm_drain(struct snd_pcm_ + down_read(&snd_pcm_link_rwsem); + snd_pcm_stream_lock_irq(substream); + remove_wait_queue(&to_check->sleep, &wait); ++ if (card->shutdown) { ++ result = -ENODEV; ++ break; ++ } + if (tout == 0) { + if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) + result = -ESTRPIPE; +@@ -2153,6 +2157,10 @@ static int snd_pcm_open(struct file *fil + mutex_unlock(&pcm->open_mutex); + schedule(); + mutex_lock(&pcm->open_mutex); ++ if (pcm->card->shutdown) { ++ err = -ENODEV; ++ break; ++ } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -437,6 +437,10 @@ static int snd_rawmidi_open(struct inode + mutex_unlock(&rmidi->open_mutex); + schedule(); + mutex_lock(&rmidi->open_mutex); ++ if (rmidi->card->shutdown) { ++ err = -ENODEV; ++ break; ++ } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; +@@ -1006,6 +1010,8 @@ static ssize_t snd_rawmidi_read(struct f + spin_unlock_irq(&runtime->lock); + schedule(); + remove_wait_queue(&runtime->sleep, &wait); ++ if (rfile->rmidi->card->shutdown) ++ return -ENODEV; + if (signal_pending(current)) + return result > 0 ? result : -ERESTARTSYS; + if (!runtime->avail) +@@ -1249,6 +1255,8 @@ static ssize_t snd_rawmidi_write(struct + spin_unlock_irq(&runtime->lock); + timeout = schedule_timeout(30 * HZ); + remove_wait_queue(&runtime->sleep, &wait); ++ if (rfile->rmidi->card->shutdown) ++ return -ENODEV; + if (signal_pending(current)) + return result > 0 ? result : -ERESTARTSYS; + if (!runtime->avail && !timeout) +@@ -1624,9 +1632,20 @@ static int snd_rawmidi_dev_register(stru + static int snd_rawmidi_dev_disconnect(struct snd_device *device) + { + struct snd_rawmidi *rmidi = device->device_data; ++ int dir; + + mutex_lock(®ister_mutex); ++ mutex_lock(&rmidi->open_mutex); ++ wake_up(&rmidi->open_wait); + list_del_init(&rmidi->list); ++ for (dir = 0; dir < 2; dir++) { ++ struct snd_rawmidi_substream *s; ++ list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { ++ if (s->runtime) ++ wake_up(&s->runtime->sleep); ++ } ++ } ++ + #ifdef CONFIG_SND_OSSEMUL + if (rmidi->ossreg) { + if ((int)rmidi->device == midi_map[rmidi->card->number]) { +@@ -1641,6 +1660,7 @@ static int snd_rawmidi_dev_disconnect(st + } + #endif /* CONFIG_SND_OSSEMUL */ + snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); ++ mutex_unlock(&rmidi->open_mutex); + mutex_unlock(®ister_mutex); + return 0; + } diff --git a/queue-3.0/alsa-pcm-fix-some-races-at-disconnection.patch b/queue-3.0/alsa-pcm-fix-some-races-at-disconnection.patch new file mode 100644 index 00000000000..5a9709ef9e7 --- /dev/null +++ b/queue-3.0/alsa-pcm-fix-some-races-at-disconnection.patch @@ -0,0 +1,103 @@ +From 9b0573c07f278e9888c352aa9724035c75784ea0 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 12 Oct 2012 15:07:34 +0200 +Subject: ALSA: PCM: Fix some races at disconnection + +From: Takashi Iwai + +commit 9b0573c07f278e9888c352aa9724035c75784ea0 upstream. + +Fix races at PCM disconnection: +- while a PCM device is being opened or closed +- while the PCM state is being changed without lock in prepare, + hw_params, hw_free ops + +Reported-by: Matthieu CASTET +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/pcm.c | 7 ++++++- + sound/core/pcm_native.c | 16 ++++++++++++---- + 2 files changed, 18 insertions(+), 5 deletions(-) + +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -1045,11 +1045,15 @@ static int snd_pcm_dev_disconnect(struct + if (list_empty(&pcm->list)) + goto unlock; + ++ mutex_lock(&pcm->open_mutex); + list_del_init(&pcm->list); + for (cidx = 0; cidx < 2; cidx++) +- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) ++ for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { ++ snd_pcm_stream_lock_irq(substream); + if (substream->runtime) + substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; ++ snd_pcm_stream_unlock_irq(substream); ++ } + list_for_each_entry(notify, &snd_pcm_notify_list, list) { + notify->n_disconnect(pcm); + } +@@ -1065,6 +1069,7 @@ static int snd_pcm_dev_disconnect(struct + } + snd_unregister_device(devtype, pcm->card, pcm->device); + } ++ mutex_unlock(&pcm->open_mutex); + unlock: + mutex_unlock(®ister_mutex); + return 0; +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -368,6 +368,14 @@ static int period_to_usecs(struct snd_pc + return usecs; + } + ++static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state) ++{ ++ snd_pcm_stream_lock_irq(substream); ++ if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) ++ substream->runtime->status->state = state; ++ snd_pcm_stream_unlock_irq(substream); ++} ++ + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) + { +@@ -451,7 +459,7 @@ static int snd_pcm_hw_params(struct snd_ + runtime->boundary *= 2; + + snd_pcm_timer_resolution_change(substream); +- runtime->status->state = SNDRV_PCM_STATE_SETUP; ++ snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); + + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); +@@ -463,7 +471,7 @@ static int snd_pcm_hw_params(struct snd_ + /* hardware might be unusable from this time, + so we force application to retry to set + the correct hardware parameter settings */ +- runtime->status->state = SNDRV_PCM_STATE_OPEN; ++ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); + if (substream->ops->hw_free != NULL) + substream->ops->hw_free(substream); + return err; +@@ -511,7 +519,7 @@ static int snd_pcm_hw_free(struct snd_pc + return -EBADFD; + if (substream->ops->hw_free) + result = substream->ops->hw_free(substream); +- runtime->status->state = SNDRV_PCM_STATE_OPEN; ++ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); + pm_qos_remove_request(&substream->latency_pm_qos_req); + return result; + } +@@ -1319,7 +1327,7 @@ static void snd_pcm_post_prepare(struct + { + struct snd_pcm_runtime *runtime = substream->runtime; + runtime->control->appl_ptr = runtime->status->hw_ptr; +- runtime->status->state = SNDRV_PCM_STATE_PREPARED; ++ snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); + } + + static struct action_ops snd_pcm_action_prepare = { diff --git a/queue-3.0/mm-fix-xfs-oops-due-to-dirty-pages-without-buffers-on-s390.patch b/queue-3.0/mm-fix-xfs-oops-due-to-dirty-pages-without-buffers-on-s390.patch new file mode 100644 index 00000000000..dcf2a00313c --- /dev/null +++ b/queue-3.0/mm-fix-xfs-oops-due-to-dirty-pages-without-buffers-on-s390.patch @@ -0,0 +1,109 @@ +From ef5d437f71afdf4afdbab99213add99f4b1318fd Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 25 Oct 2012 13:37:31 -0700 +Subject: mm: fix XFS oops due to dirty pages without buffers on s390 + +From: Jan Kara + +commit ef5d437f71afdf4afdbab99213add99f4b1318fd upstream. + +On s390 any write to a page (even from kernel itself) sets architecture +specific page dirty bit. Thus when a page is written to via buffered +write, HW dirty bit gets set and when we later map and unmap the page, +page_remove_rmap() finds the dirty bit and calls set_page_dirty(). + +Dirtying of a page which shouldn't be dirty can cause all sorts of +problems to filesystems. The bug we observed in practice is that +buffers from the page get freed, so when the page gets later marked as +dirty and writeback writes it, XFS crashes due to an assertion +BUG_ON(!PagePrivate(page)) in page_buffers() called from +xfs_count_page_state(). + +Similar problem can also happen when zero_user_segment() call from +xfs_vm_writepage() (or block_write_full_page() for that matter) set the +hardware dirty bit during writeback, later buffers get freed, and then +page unmapped. + +Fix the issue by ignoring s390 HW dirty bit for page cache pages of +mappings with mapping_cap_account_dirty(). This is safe because for +such mappings when a page gets marked as writeable in PTE it is also +marked dirty in do_wp_page() or do_page_fault(). When the dirty bit is +cleared by clear_page_dirty_for_io(), the page gets writeprotected in +page_mkclean(). So pagecache page is writeable if and only if it is +dirty. + +Thanks to Hugh Dickins for pointing out mapping has to have +mapping_cap_account_dirty() for things to work and proposing a cleaned +up variant of the patch. + +The patch has survived about two hours of running fsx-linux on tmpfs +while heavily swapping and several days of running on out build machines +where the original problem was triggered. + +Signed-off-by: Jan Kara +Cc: Martin Schwidefsky +Cc: Mel Gorman +Cc: Hugh Dickins +Cc: Heiko Carstens +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + + +--- + mm/rmap.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + + #include + +@@ -936,11 +937,8 @@ int page_mkclean(struct page *page) + + if (page_mapped(page)) { + struct address_space *mapping = page_mapping(page); +- if (mapping) { ++ if (mapping) + ret = page_mkclean_file(mapping, page); +- if (page_test_and_clear_dirty(page_to_pfn(page), 1)) +- ret = 1; +- } + } + + return ret; +@@ -1121,6 +1119,8 @@ void page_add_file_rmap(struct page *pag + */ + void page_remove_rmap(struct page *page) + { ++ struct address_space *mapping = page_mapping(page); ++ + /* page still mapped by someone else? */ + if (!atomic_add_negative(-1, &page->_mapcount)) + return; +@@ -1131,8 +1131,19 @@ void page_remove_rmap(struct page *page) + * this if the page is anon, so about to be freed; but perhaps + * not if it's in swapcache - there might be another pte slot + * containing the swap entry, but page not yet written to swap. ++ * ++ * And we can skip it on file pages, so long as the filesystem ++ * participates in dirty tracking; but need to catch shm and tmpfs ++ * and ramfs pages which have been modified since creation by read ++ * fault. ++ * ++ * Note that mapping must be decided above, before decrementing ++ * mapcount (which luckily provides a barrier): once page is unmapped, ++ * it could be truncated and page->mapping reset to NULL at any moment. ++ * Note also that we are relying on page_mapping(page) to set mapping ++ * to &swapper_space when PageSwapCache(page). + */ +- if ((!PageAnon(page) || PageSwapCache(page)) && ++ if (mapping && !mapping_cap_account_dirty(mapping) && + page_test_and_clear_dirty(page_to_pfn(page), 1)) + set_page_dirty(page); + /* diff --git a/queue-3.0/series b/queue-3.0/series index 03c0890b13e..71dbbf87c0e 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -1,2 +1,5 @@ floppy-do-put_disk-on-current-dr-if-blk_init_queue-fails.patch x86-remove-the-ancient-and-deprecated-disable_hlt-and-enable_hlt-facility.patch +alsa-pcm-fix-some-races-at-disconnection.patch +alsa-avoid-endless-sleep-after-disconnect.patch +mm-fix-xfs-oops-due-to-dirty-pages-without-buffers-on-s390.patch