]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 May 2020 11:12:04 +0000 (13:12 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 May 2020 11:12:04 +0000 (13:12 +0200)
added patches:
alsa-pcm-fix-incorrect-hw_base-increase.patch
ext4-lock-the-xattr-block-before-checksuming-it.patch

queue-4.4/alsa-pcm-fix-incorrect-hw_base-increase.patch [new file with mode: 0644]
queue-4.4/ext4-lock-the-xattr-block-before-checksuming-it.patch [new file with mode: 0644]
queue-4.4/series

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 (file)
index 0000000..784415d
--- /dev/null
@@ -0,0 +1,80 @@
+From e7513c5786f8b33f0c107b3759e433bc6cbb2efa Mon Sep 17 00:00:00 2001
+From: Brent Lu <brent.lu@intel.com>
+Date: Mon, 18 May 2020 12:30:38 +0800
+Subject: ALSA: pcm: fix incorrect hw_base increase
+
+From: Brent Lu <brent.lu@intel.com>
+
+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 <brent.lu@intel.com>
+Reviewed-by: Jaroslav Kysela <perex@perex.cz>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/1589776238-23877-1-git-send-email-brent.lu@intel.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..6247794
--- /dev/null
@@ -0,0 +1,159 @@
+From dac7a4b4b1f664934e8b713f529b629f67db313c Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Sat, 25 Mar 2017 17:22:47 -0400
+Subject: ext4: lock the xattr block before checksuming it
+
+From: Theodore Ts'o <tytso@mit.edu>
+
+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 <colin.king@canonical.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+               }
index b6d61579a7437da67e01f4df8f2eb449ae2dbd8a..b3f53099bc3dddd747f009c6fe476676ef63bc35 100644 (file)
@@ -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