From: Greg Kroah-Hartman Date: Sat, 23 May 2020 11:12:04 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v4.4.225~55 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a7e0007bcb5ce6c141c17c6a3a88613fe2909a2b;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: alsa-pcm-fix-incorrect-hw_base-increase.patch ext4-lock-the-xattr-block-before-checksuming-it.patch --- diff --git a/queue-4.4/alsa-pcm-fix-incorrect-hw_base-increase.patch b/queue-4.4/alsa-pcm-fix-incorrect-hw_base-increase.patch new file mode 100644 index 00000000000..784415d492c --- /dev/null +++ b/queue-4.4/alsa-pcm-fix-incorrect-hw_base-increase.patch @@ -0,0 +1,80 @@ +From e7513c5786f8b33f0c107b3759e433bc6cbb2efa Mon Sep 17 00:00:00 2001 +From: Brent Lu +Date: Mon, 18 May 2020 12:30:38 +0800 +Subject: ALSA: pcm: fix incorrect hw_base increase + +From: Brent Lu + +commit e7513c5786f8b33f0c107b3759e433bc6cbb2efa upstream. + +There is a corner case that ALSA keeps increasing the hw_ptr but DMA +already stop working/updating the position for a long time. + +In following log we can see the position returned from DMA driver does +not move at all but the hw_ptr got increased at some point of time so +snd_pcm_avail() will return a large number which seems to be a buffer +underrun event from user space program point of view. The program +thinks there is space in the buffer and fill more data. + +[ 418.510086] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 4096 avail 12368 +[ 418.510149] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 6910 avail 9554 +... +[ 418.681052] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 15102 avail 1362 +[ 418.681130] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 16464 avail 0 +[ 418.726515] sound pcmC0D5p: pos 96 hw_ptr 16464 appl_ptr 16464 avail 16368 + +This is because the hw_base will be increased by runtime->buffer_size +frames unconditionally if the hw_ptr is not updated for over half of +buffer time. As the hw_base increases, so does the hw_ptr increased +by the same number. + +The avail value returned from snd_pcm_avail() could exceed the limit +(buffer_size) easily becase the hw_ptr itself got increased by same +buffer_size samples when the corner case happens. In following log, +the buffer_size is 16368 samples but the avail is 21810 samples so +CRAS server complains about it. + +[ 418.851755] sound pcmC0D5p: pos 96 hw_ptr 16464 appl_ptr 27390 avail 5442 +[ 418.926491] sound pcmC0D5p: pos 96 hw_ptr 32832 appl_ptr 27390 avail 21810 + +cras_server[1907]: pcm_avail returned frames larger than buf_size: +sof-glkda7219max: :0,5: 21810 > 16368 + +By updating runtime->hw_ptr_jiffies each time the HWSYNC is called, +the hw_base will keep the same when buffer stall happens at long as +the interval between each HWSYNC call is shorter than half of buffer +time. + +Following is a log captured by a patched kernel. The hw_base/hw_ptr +value is fixed in this corner case and user space program should be +aware of the buffer stall and handle it. + +[ 293.525543] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 4096 avail 12368 +[ 293.525606] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 6880 avail 9584 +[ 293.525975] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 10976 avail 5488 +[ 293.611178] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 15072 avail 1392 +[ 293.696429] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 16464 avail 0 +... +[ 381.139517] sound pcmC0D5p: pos 96 hw_ptr 96 appl_ptr 16464 avail 0 + +Signed-off-by: Brent Lu +Reviewed-by: Jaroslav Kysela +Cc: +Link: https://lore.kernel.org/r/1589776238-23877-1-git-send-email-brent.lu@intel.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/pcm_lib.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/core/pcm_lib.c ++++ b/sound/core/pcm_lib.c +@@ -456,6 +456,7 @@ static int snd_pcm_update_hw_ptr0(struct + + no_delta_check: + if (runtime->status->hw_ptr == new_hw_ptr) { ++ runtime->hw_ptr_jiffies = curr_jiffies; + update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); + return 0; + } diff --git a/queue-4.4/ext4-lock-the-xattr-block-before-checksuming-it.patch b/queue-4.4/ext4-lock-the-xattr-block-before-checksuming-it.patch new file mode 100644 index 00000000000..6247794a6bd --- /dev/null +++ b/queue-4.4/ext4-lock-the-xattr-block-before-checksuming-it.patch @@ -0,0 +1,159 @@ +From dac7a4b4b1f664934e8b713f529b629f67db313c Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sat, 25 Mar 2017 17:22:47 -0400 +Subject: ext4: lock the xattr block before checksuming it + +From: Theodore Ts'o + +commit dac7a4b4b1f664934e8b713f529b629f67db313c upstream. + +We must lock the xattr block before calculating or verifying the +checksum in order to avoid spurious checksum failures. + +https://bugzilla.kernel.org/show_bug.cgi?id=193661 + +Reported-by: Colin Ian King +Signed-off-by: Theodore Ts'o +Cc: stable@vger.kernel.org +Signed-off-by: Sultan Alsawaf +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/xattr.c | 66 +++++++++++++++++++++++++++----------------------------- + 1 file changed, 32 insertions(+), 34 deletions(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -139,31 +139,26 @@ static __le32 ext4_xattr_block_csum(stru + } + + static int ext4_xattr_block_csum_verify(struct inode *inode, +- sector_t block_nr, +- struct ext4_xattr_header *hdr) ++ struct buffer_head *bh) + { +- if (ext4_has_metadata_csum(inode->i_sb) && +- (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr))) +- return 0; +- return 1; +-} +- +-static void ext4_xattr_block_csum_set(struct inode *inode, +- sector_t block_nr, +- struct ext4_xattr_header *hdr) +-{ +- if (!ext4_has_metadata_csum(inode->i_sb)) +- return; ++ struct ext4_xattr_header *hdr = BHDR(bh); ++ int ret = 1; + +- hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr); ++ if (ext4_has_metadata_csum(inode->i_sb)) { ++ lock_buffer(bh); ++ ret = (hdr->h_checksum == ext4_xattr_block_csum(inode, ++ bh->b_blocknr, hdr)); ++ unlock_buffer(bh); ++ } ++ return ret; + } + +-static inline int ext4_handle_dirty_xattr_block(handle_t *handle, +- struct inode *inode, +- struct buffer_head *bh) ++static void ext4_xattr_block_csum_set(struct inode *inode, ++ struct buffer_head *bh) + { +- ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh)); +- return ext4_handle_dirty_metadata(handle, inode, bh); ++ if (ext4_has_metadata_csum(inode->i_sb)) ++ BHDR(bh)->h_checksum = ext4_xattr_block_csum(inode, ++ bh->b_blocknr, BHDR(bh)); + } + + static inline const struct xattr_handler * +@@ -226,7 +221,7 @@ ext4_xattr_check_block(struct inode *ino + if (buffer_verified(bh)) + return 0; + +- if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) ++ if (!ext4_xattr_block_csum_verify(inode, bh)) + return -EFSBADCRC; + error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size, + bh->b_data); +@@ -590,23 +585,23 @@ ext4_xattr_release_block(handle_t *handl + le32_add_cpu(&BHDR(bh)->h_refcount, -1); + if (ce) + mb_cache_entry_release(ce); ++ ++ ext4_xattr_block_csum_set(inode, bh); + /* + * Beware of this ugliness: Releasing of xattr block references + * from different inodes can race and so we have to protect + * from a race where someone else frees the block (and releases + * its journal_head) before we are done dirtying the buffer. In + * nojournal mode this race is harmless and we actually cannot +- * call ext4_handle_dirty_xattr_block() with locked buffer as ++ * call ext4_handle_dirty_metadata() with locked buffer as + * that function can call sync_dirty_buffer() so for that case + * we handle the dirtying after unlocking the buffer. + */ + if (ext4_handle_valid(handle)) +- error = ext4_handle_dirty_xattr_block(handle, inode, +- bh); ++ error = ext4_handle_dirty_metadata(handle, inode, bh); + unlock_buffer(bh); + if (!ext4_handle_valid(handle)) +- error = ext4_handle_dirty_xattr_block(handle, inode, +- bh); ++ error = ext4_handle_dirty_metadata(handle, inode, bh); + if (IS_SYNC(inode)) + ext4_handle_sync(handle); + dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1)); +@@ -837,13 +832,14 @@ ext4_xattr_block_set(handle_t *handle, s + ext4_xattr_rehash(header(s->base), + s->here); + } ++ ext4_xattr_block_csum_set(inode, bs->bh); + unlock_buffer(bs->bh); + if (error == -EFSCORRUPTED) + goto bad_block; + if (!error) +- error = ext4_handle_dirty_xattr_block(handle, +- inode, +- bs->bh); ++ error = ext4_handle_dirty_metadata(handle, ++ inode, ++ bs->bh); + if (error) + goto cleanup; + goto inserted; +@@ -912,10 +908,11 @@ inserted: + le32_add_cpu(&BHDR(new_bh)->h_refcount, 1); + ea_bdebug(new_bh, "reusing; refcount now=%d", + le32_to_cpu(BHDR(new_bh)->h_refcount)); ++ ext4_xattr_block_csum_set(inode, new_bh); + unlock_buffer(new_bh); +- error = ext4_handle_dirty_xattr_block(handle, +- inode, +- new_bh); ++ error = ext4_handle_dirty_metadata(handle, ++ inode, ++ new_bh); + if (error) + goto cleanup_dquot; + } +@@ -965,11 +962,12 @@ getblk_failed: + goto getblk_failed; + } + memcpy(new_bh->b_data, s->base, new_bh->b_size); ++ ext4_xattr_block_csum_set(inode, new_bh); + set_buffer_uptodate(new_bh); + unlock_buffer(new_bh); + ext4_xattr_cache_insert(ext4_mb_cache, new_bh); +- error = ext4_handle_dirty_xattr_block(handle, +- inode, new_bh); ++ error = ext4_handle_dirty_metadata(handle, inode, ++ new_bh); + if (error) + goto cleanup; + } diff --git a/queue-4.4/series b/queue-4.4/series index b6d61579a74..b3f53099bc3 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -27,3 +27,5 @@ sched-fair-cpumask-export-for_each_cpu_wrap.patch padata-replace-delayed-timer-with-immediate-workqueu.patch padata-initialize-pd-cpu-with-effective-cpumask.patch padata-purge-get_cpu-and-reorder_via_wq-from-padata_.patch +alsa-pcm-fix-incorrect-hw_base-increase.patch +ext4-lock-the-xattr-block-before-checksuming-it.patch