aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2012-02-20 17:53:00 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-02-20 17:53:00 -0500
commit3d2b158262826e8b75bbbfb7b97010838dd92ac7 (patch)
tree946864d7dccfd2046157b174baa89e7ad92c6330 /fs/ext4/inode.c
parent813e57276fd909f7d5a816ef7ca706fca491ee61 (diff)
ext4: ignore EXT4_INODE_JOURNAL_DATA flag with delalloc
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> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c36
1 files changed, 22 insertions, 14 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index feaa82fe629d..a58812ef5ea3 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2482,13 +2482,14 @@ static int ext4_da_write_end(struct file *file,
2482 int write_mode = (int)(unsigned long)fsdata; 2482 int write_mode = (int)(unsigned long)fsdata;
2483 2483
2484 if (write_mode == FALL_BACK_TO_NONDELALLOC) { 2484 if (write_mode == FALL_BACK_TO_NONDELALLOC) {
2485 if (ext4_should_order_data(inode)) { 2485 switch (ext4_inode_journal_mode(inode)) {
2486 case EXT4_INODE_ORDERED_DATA_MODE:
2486 return ext4_ordered_write_end(file, mapping, pos, 2487 return ext4_ordered_write_end(file, mapping, pos,
2487 len, copied, page, fsdata); 2488 len, copied, page, fsdata);
2488 } else if (ext4_should_writeback_data(inode)) { 2489 case EXT4_INODE_WRITEBACK_DATA_MODE:
2489 return ext4_writeback_write_end(file, mapping, pos, 2490 return ext4_writeback_write_end(file, mapping, pos,
2490 len, copied, page, fsdata); 2491 len, copied, page, fsdata);
2491 } else { 2492 default:
2492 BUG(); 2493 BUG();
2493 } 2494 }
2494 } 2495 }
@@ -3086,18 +3087,25 @@ static const struct address_space_operations ext4_da_aops = {
3086 3087
3087void ext4_set_aops(struct inode *inode) 3088void ext4_set_aops(struct inode *inode)
3088{ 3089{
3089 if (ext4_should_order_data(inode) && 3090 switch (ext4_inode_journal_mode(inode)) {
3090 test_opt(inode->i_sb, DELALLOC)) 3091 case EXT4_INODE_ORDERED_DATA_MODE:
3091 inode->i_mapping->a_ops = &ext4_da_aops; 3092 if (test_opt(inode->i_sb, DELALLOC))
3092 else if (ext4_should_order_data(inode)) 3093 inode->i_mapping->a_ops = &ext4_da_aops;
3093 inode->i_mapping->a_ops = &ext4_ordered_aops; 3094 else
3094 else if (ext4_should_writeback_data(inode) && 3095 inode->i_mapping->a_ops = &ext4_ordered_aops;
3095 test_opt(inode->i_sb, DELALLOC)) 3096 break;
3096 inode->i_mapping->a_ops = &ext4_da_aops; 3097 case EXT4_INODE_WRITEBACK_DATA_MODE:
3097 else if (ext4_should_writeback_data(inode)) 3098 if (test_opt(inode->i_sb, DELALLOC))
3098 inode->i_mapping->a_ops = &ext4_writeback_aops; 3099 inode->i_mapping->a_ops = &ext4_da_aops;
3099 else 3100 else
3101 inode->i_mapping->a_ops = &ext4_writeback_aops;
3102 break;
3103 case EXT4_INODE_JOURNAL_DATA_MODE:
3100 inode->i_mapping->a_ops = &ext4_journalled_aops; 3104 inode->i_mapping->a_ops = &ext4_journalled_aops;
3105 break;
3106 default:
3107 BUG();
3108 }
3101} 3109}
3102 3110
3103 3111