linux/fs/ext4
Eric Sandeen 6d6a435190 ext4: fix race in xattr block allocation path
Ceph users reported that when using Ceph on ext4, the filesystem
would often become corrupted, containing inodes with incorrect
i_blocks counters.

I managed to reproduce this with a very hacked-up "streamtest"
binary from the Ceph tree.

Ceph is doing a lot of xattr writes, to out-of-inode blocks.
There is also another thread which does sync_file_range and close,
of the same files.  The problem appears to happen due to this race:

sync/flush thread               xattr-set thread
-----------------               ----------------

do_writepages                   ext4_xattr_set
ext4_da_writepages              ext4_xattr_set_handle
mpage_da_map_blocks             ext4_xattr_block_set
        set DELALLOC_RESERVE
                                ext4_new_meta_blocks
                                        ext4_mb_new_blocks
                                                if (!i_delalloc_reserved_flag)
                                                        vfs_dq_alloc_block
ext4_get_blocks
	down_write(i_data_sem)
        set i_delalloc_reserved_flag
	...
	up_write(i_data_sem)
                                        if (i_delalloc_reserved_flag)
                                                vfs_dq_alloc_block_nofail


In other words, the sync/flush thread pops in and sets
i_delalloc_reserved_flag on the inode, which makes the xattr thread
think that it's in a delalloc path in ext4_new_meta_blocks(),
and add the block for a second time, after already having added
it once in the !i_delalloc_reserved_flag case in ext4_mb_new_blocks

The real problem is that we shouldn't be using the DELALLOC_RESERVED
state flag, and instead we should be passing
EXT4_GET_BLOCKS_DELALLOC_RESERVE down to ext4_map_blocks() instead of
using an inode state flag.  We'll fix this for now with using
i_data_sem to prevent this race, but this is really not the right way
to fix things.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
2011-10-29 10:15:35 -04:00
..
acl.c switch posix_acl_equiv_mode() to umode_t * 2011-08-01 02:10:06 -04:00
acl.h fs: take the ACL checks to common code 2011-07-25 14:30:23 -04:00
balloc.c ext4: rename ext4_has_free_blocks() to ext4_has_free_clusters() 2011-09-09 19:16:51 -04:00
bitmap.c
block_validity.c ext4: move ext4_ind_* functions from inode.c to indirect.c 2011-06-27 19:40:50 -04:00
dir.c ext4: Use ext4_error_file() to print the pathname to the corrupted inode 2011-01-10 12:10:55 -05:00
ext4_extents.h ext4: Fix bigalloc quota accounting and i_blocks value 2011-09-09 19:04:51 -04:00
ext4_jbd2.c jbd2: add debugging information to jbd2_journal_dirty_metadata() 2011-09-04 10:18:14 -04:00
ext4_jbd2.h ext4: Fix ext4_should_writeback_data() for no-journal mode 2011-08-13 11:25:18 -04:00
ext4.h ext4: fix quota accounting during migration 2011-10-29 09:05:00 -04:00
extents.c ext4: trace punch_hole correctly in ext4_ext_map_blocks 2011-10-29 09:39:51 -04:00
file.c ext4: prevent stack overrun in ext4_file_open 2011-10-25 09:18:41 -04:00
fsync.c ext4: functions should not be declared extern 2011-10-18 10:57:51 -04:00
hash.c
ialloc.c ext4: fix quota accounting during migration 2011-10-29 09:05:00 -04:00
indirect.c ext4: enforce bigalloc restrictions (e.g., no online resizing, etc.) 2011-09-09 18:36:51 -04:00
inode.c ext4: let ext4_page_mkwrite stop started handle in failure 2011-10-26 05:00:19 -04:00
ioctl.c ext4: add __user decoration to calls of copy_{from,to}_user() 2011-10-18 10:59:51 -04:00
Kconfig ext4: Don't ask about supporting ext2/3 in ext4 if ext4 is not configured 2009-12-21 10:54:09 -05:00
Makefile ext4: move ext4_ind_* functions from inode.c to indirect.c 2011-06-27 19:40:50 -04:00
mballoc.c ext4: fix a wrong comment in __mb_check_buddy() 2011-10-26 08:48:54 -04:00
mballoc.h ext4: teach ext4_free_blocks() about bigalloc and clusters 2011-09-09 18:50:51 -04:00
migrate.c ext4: fix quota accounting during migration 2011-10-29 09:05:00 -04:00
mmp.c ext4: Fix comparison endianness problem in MMP initialization 2011-10-18 10:53:51 -04:00
move_extent.c ext4: add some tracepoints in ext4/extents.c 2011-09-09 19:18:51 -04:00
namei.c ext4: fix quota accounting during migration 2011-10-29 09:05:00 -04:00
page-io.c ext4: remove i_mutex lock in ext4_evict_inode to fix lockdep complaining 2011-08-31 11:50:51 -04:00
resize.c ext4: Rename ext4_free_blks_{count,set}() to refer to clusters 2011-09-09 19:08:51 -04:00
super.c ext4: optimize ext4_ext_convert_to_initialized() 2011-10-27 11:43:23 -04:00
symlink.c ext4: symlink must be handled via filesystem specific operation 2010-05-16 02:00:00 -04:00
truncate.h ext4: move common truncate functions to header file 2011-06-27 19:16:04 -04:00
xattr_security.c fs/vfs/security: pass last path component to LSM on inode creation 2011-02-01 11:12:29 -05:00
xattr_trusted.c ext4: constify xattr_handler 2010-05-21 18:31:19 -04:00
xattr_user.c ext4: constify xattr_handler 2010-05-21 18:31:19 -04:00
xattr.c ext4: fix race in xattr block allocation path 2011-10-29 10:15:35 -04:00
xattr.h fs/vfs/security: pass last path component to LSM on inode creation 2011-02-01 11:12:29 -05:00