]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 28 Mar 2012 22:31:51 +0000 (15:31 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 28 Mar 2012 22:31:51 +0000 (15:31 -0700)
added patches:
ext4-check-for-zero-length-extent.patch
ext4-ignore-ext4_inode_journal_data-flag-with-delalloc.patch
vfs-fix-d_ancestor-case-in-d_materialize_unique.patch

queue-3.0/ext4-check-for-zero-length-extent.patch [new file with mode: 0644]
queue-3.0/ext4-ignore-ext4_inode_journal_data-flag-with-delalloc.patch [new file with mode: 0644]
queue-3.0/series
queue-3.0/vfs-fix-d_ancestor-case-in-d_materialize_unique.patch [new file with mode: 0644]

diff --git a/queue-3.0/ext4-check-for-zero-length-extent.patch b/queue-3.0/ext4-check-for-zero-length-extent.patch
new file mode 100644 (file)
index 0000000..32955f9
--- /dev/null
@@ -0,0 +1,39 @@
+From 31d4f3a2f3c73f279ff96a7135d7202ef6833f12 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Sun, 11 Mar 2012 23:30:16 -0400
+Subject: ext4: check for zero length extent
+
+From: Theodore Ts'o <tytso@mit.edu>
+
+commit 31d4f3a2f3c73f279ff96a7135d7202ef6833f12 upstream.
+
+Explicitly test for an extent whose length is zero, and flag that as a
+corrupted extent.
+
+This avoids a kernel BUG_ON assertion failure.
+
+Tested: Without this patch, the file system image found in
+tests/f_ext_zero_len/image.gz in the latest e2fsprogs sources causes a
+kernel panic.  With this patch, an ext4 file system error is noted
+instead, and the file system is marked as being corrupted.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=42859
+
+Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/extents.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -341,6 +341,8 @@ static int ext4_valid_extent(struct inod
+       ext4_fsblk_t block = ext4_ext_pblock(ext);
+       int len = ext4_ext_get_actual_len(ext);
++      if (len == 0)
++              return 0;
+       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
+ }
diff --git a/queue-3.0/ext4-ignore-ext4_inode_journal_data-flag-with-delalloc.patch b/queue-3.0/ext4-ignore-ext4_inode_journal_data-flag-with-delalloc.patch
new file mode 100644 (file)
index 0000000..ec8233b
--- /dev/null
@@ -0,0 +1,189 @@
+From 3d2b158262826e8b75bbbfb7b97010838dd92ac7 Mon Sep 17 00:00:00 2001
+From: Lukas Czerner <lczerner@redhat.com>
+Date: Mon, 20 Feb 2012 17:53:00 -0500
+Subject: ext4: ignore EXT4_INODE_JOURNAL_DATA flag with delalloc
+
+From: Lukas Czerner <lczerner@redhat.com>
+
+commit 3d2b158262826e8b75bbbfb7b97010838dd92ac7 upstream.
+
+Ext4 does not support data journalling with delayed allocation enabled.
+We even do not allow to mount the file system with delayed allocation
+and data journalling enabled, however it can be set via FS_IOC_SETFLAGS
+so we can hit the inode with EXT4_INODE_JOURNAL_DATA set even on file
+system mounted with delayed allocation (default) and that's where
+problem arises. The easies way to reproduce this problem is with the
+following set of commands:
+
+ mkfs.ext4 /dev/sdd
+ mount /dev/sdd /mnt/test1
+ dd if=/dev/zero of=/mnt/test1/file bs=1M count=4
+ chattr +j /mnt/test1/file
+ dd if=/dev/zero of=/mnt/test1/file bs=1M count=4 conv=notrunc
+ chattr -j /mnt/test1/file
+
+Additionally it can be reproduced quite reliably with xfstests 272 and
+269. In fact the above reproducer is a part of test 272.
+
+To fix this we should ignore the EXT4_INODE_JOURNAL_DATA inode flag if
+the file system is mounted with delayed allocation. This can be easily
+done by fixing ext4_should_*_data() functions do ignore data journal
+flag when delalloc is set (suggested by Ted). We also have to set the
+appropriate address space operations for the inode (again, ignoring data
+journal flag if delalloc enabled).
+
+Additionally this commit introduces ext4_inode_journal_mode() function
+because ext4_should_*_data() has already had a lot of common code and
+this change is putting it all into one function so it is easier to
+read.
+
+Successfully tested with xfstests in following configurations:
+
+delalloc + data=ordered
+delalloc + data=writeback
+data=journal
+nodelalloc + data=ordered
+nodelalloc + data=writeback
+nodelalloc + data=journal
+
+Signed-off-by: Lukas Czerner <lczerner@redhat.com>
+Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/ext4_jbd2.h |   56 ++++++++++++++++++++++++++--------------------------
+ fs/ext4/inode.c     |   36 ++++++++++++++++++++-------------
+ 2 files changed, 51 insertions(+), 41 deletions(-)
+
+--- a/fs/ext4/ext4_jbd2.h
++++ b/fs/ext4/ext4_jbd2.h
+@@ -261,43 +261,45 @@ static inline void ext4_update_inode_fsy
+ /* super.c */
+ int ext4_force_commit(struct super_block *sb);
+-static inline int ext4_should_journal_data(struct inode *inode)
++/*
++ * Ext4 inode journal modes
++ */
++#define EXT4_INODE_JOURNAL_DATA_MODE  0x01 /* journal data mode */
++#define EXT4_INODE_ORDERED_DATA_MODE  0x02 /* ordered data mode */
++#define EXT4_INODE_WRITEBACK_DATA_MODE        0x04 /* writeback data mode */
++
++static inline int ext4_inode_journal_mode(struct inode *inode)
+ {
+       if (EXT4_JOURNAL(inode) == NULL)
+-              return 0;
+-      if (!S_ISREG(inode->i_mode))
+-              return 1;
+-      if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+-              return 1;
+-      if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+-              return 1;
+-      return 0;
++              return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
++      /* We do not support data journalling with delayed allocation */
++      if (!S_ISREG(inode->i_mode) ||
++          test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
++              return EXT4_INODE_JOURNAL_DATA_MODE;    /* journal data */
++      if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
++          !test_opt(inode->i_sb, DELALLOC))
++              return EXT4_INODE_JOURNAL_DATA_MODE;    /* journal data */
++      if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
++              return EXT4_INODE_ORDERED_DATA_MODE;    /* ordered */
++      if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
++              return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
++      else
++              BUG();
++}
++
++static inline int ext4_should_journal_data(struct inode *inode)
++{
++      return ext4_inode_journal_mode(inode) & EXT4_INODE_JOURNAL_DATA_MODE;
+ }
+ static inline int ext4_should_order_data(struct inode *inode)
+ {
+-      if (EXT4_JOURNAL(inode) == NULL)
+-              return 0;
+-      if (!S_ISREG(inode->i_mode))
+-              return 0;
+-      if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+-              return 0;
+-      if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+-              return 1;
+-      return 0;
++      return ext4_inode_journal_mode(inode) & EXT4_INODE_ORDERED_DATA_MODE;
+ }
+ static inline int ext4_should_writeback_data(struct inode *inode)
+ {
+-      if (EXT4_JOURNAL(inode) == NULL)
+-              return 1;
+-      if (!S_ISREG(inode->i_mode))
+-              return 0;
+-      if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+-              return 0;
+-      if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+-              return 1;
+-      return 0;
++      return ext4_inode_journal_mode(inode) & EXT4_INODE_WRITEBACK_DATA_MODE;
+ }
+ /*
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -3212,13 +3212,14 @@ static int ext4_da_write_end(struct file
+       int write_mode = (int)(unsigned long)fsdata;
+       if (write_mode == FALL_BACK_TO_NONDELALLOC) {
+-              if (ext4_should_order_data(inode)) {
++              switch (ext4_inode_journal_mode(inode)) {
++              case EXT4_INODE_ORDERED_DATA_MODE:
+                       return ext4_ordered_write_end(file, mapping, pos,
+                                       len, copied, page, fsdata);
+-              } else if (ext4_should_writeback_data(inode)) {
++              case EXT4_INODE_WRITEBACK_DATA_MODE:
+                       return ext4_writeback_write_end(file, mapping, pos,
+                                       len, copied, page, fsdata);
+-              } else {
++              default:
+                       BUG();
+               }
+       }
+@@ -3918,18 +3919,25 @@ static const struct address_space_operat
+ void ext4_set_aops(struct inode *inode)
+ {
+-      if (ext4_should_order_data(inode) &&
+-              test_opt(inode->i_sb, DELALLOC))
+-              inode->i_mapping->a_ops = &ext4_da_aops;
+-      else if (ext4_should_order_data(inode))
+-              inode->i_mapping->a_ops = &ext4_ordered_aops;
+-      else if (ext4_should_writeback_data(inode) &&
+-               test_opt(inode->i_sb, DELALLOC))
+-              inode->i_mapping->a_ops = &ext4_da_aops;
+-      else if (ext4_should_writeback_data(inode))
+-              inode->i_mapping->a_ops = &ext4_writeback_aops;
+-      else
++      switch (ext4_inode_journal_mode(inode)) {
++      case EXT4_INODE_ORDERED_DATA_MODE:
++              if (test_opt(inode->i_sb, DELALLOC))
++                      inode->i_mapping->a_ops = &ext4_da_aops;
++              else
++                      inode->i_mapping->a_ops = &ext4_ordered_aops;
++              break;
++      case EXT4_INODE_WRITEBACK_DATA_MODE:
++              if (test_opt(inode->i_sb, DELALLOC))
++                      inode->i_mapping->a_ops = &ext4_da_aops;
++              else
++                      inode->i_mapping->a_ops = &ext4_writeback_aops;
++              break;
++      case EXT4_INODE_JOURNAL_DATA_MODE:
+               inode->i_mapping->a_ops = &ext4_journalled_aops;
++              break;
++      default:
++              BUG();
++      }
+ }
+ /*
index fd103be661422dbe260adccafde1f72c93414680..f0b141f99f283b539f38fbcacc3c9b44f833f31d 100644 (file)
@@ -80,3 +80,6 @@ e1000e-avoid-wrong-check-on-tx-hang.patch
 pm-hibernate-enable-usermodehelpers-in-hibernate-error-path.patch
 ext4-flush-any-pending-end_io-requests-before-dio-reads-w-dioread_nolock.patch
 jbd2-clear-bh_delay-bh_unwritten-in-journal_unmap_buffer.patch
+ext4-ignore-ext4_inode_journal_data-flag-with-delalloc.patch
+ext4-check-for-zero-length-extent.patch
+vfs-fix-d_ancestor-case-in-d_materialize_unique.patch
diff --git a/queue-3.0/vfs-fix-d_ancestor-case-in-d_materialize_unique.patch b/queue-3.0/vfs-fix-d_ancestor-case-in-d_materialize_unique.patch
new file mode 100644 (file)
index 0000000..5d7a27a
--- /dev/null
@@ -0,0 +1,52 @@
+From b18dafc86bb879d2f38a1743985d7ceb283c2f4d Mon Sep 17 00:00:00 2001
+From: Michel Lespinasse <walken@google.com>
+Date: Mon, 26 Mar 2012 17:32:44 -0700
+Subject: vfs: fix d_ancestor() case in d_materialize_unique
+
+From: Michel Lespinasse <walken@google.com>
+
+commit b18dafc86bb879d2f38a1743985d7ceb283c2f4d upstream.
+
+In d_materialise_unique() there are 3 subcases to the 'aliased dentry'
+case; in two subcases the inode i_lock is properly released but this
+does not occur in the -ELOOP subcase.
+
+This seems to have been introduced by commit 1836750115f2 ("fix loop
+checks in d_materialise_unique()").
+
+Signed-off-by: Michel Lespinasse <walken@google.com>
+[ Added a comment, and moved the unlock to where we generate the -ELOOP,
+  which seems to be more natural.
+
+  You probably can't actually trigger this without a buggy network file
+  server - d_materialize_unique() is for finding aliases on non-local
+  filesystems, and the d_ancestor() case is for a hardlinked directory
+  loop.
+
+  But we should be robust in the case of such buggy servers anyway. ]
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/dcache.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -2433,6 +2433,7 @@ struct dentry *d_materialise_unique(stru
+                       if (d_ancestor(alias, dentry)) {
+                               /* Check for loops */
+                               actual = ERR_PTR(-ELOOP);
++                              spin_unlock(&inode->i_lock);
+                       } else if (IS_ROOT(alias)) {
+                               /* Is this an anonymous mountpoint that we
+                                * could splice into our tree? */
+@@ -2442,7 +2443,7 @@ struct dentry *d_materialise_unique(stru
+                               goto found;
+                       } else {
+                               /* Nope, but we must(!) avoid directory
+-                               * aliasing */
++                               * aliasing. This drops inode->i_lock */
+                               actual = __d_unalias(inode, dentry, alias);
+                       }
+                       write_sequnlock(&rename_lock);