diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 71c7ad0c6723..a7eb8bb4bdd4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -308,7 +308,7 @@ static int ext4_block_to_path(struct inode *inode, | |||
308 | final = ptrs; | 308 | final = ptrs; |
309 | } else { | 309 | } else { |
310 | ext4_warning(inode->i_sb, "ext4_block_to_path", | 310 | ext4_warning(inode->i_sb, "ext4_block_to_path", |
311 | "block %u > max", | 311 | "block %lu > max", |
312 | i_block + direct_blocks + | 312 | i_block + direct_blocks + |
313 | indirect_blocks + double_blocks); | 313 | indirect_blocks + double_blocks); |
314 | } | 314 | } |
@@ -345,7 +345,7 @@ static int ext4_block_to_path(struct inode *inode, | |||
345 | * the whole chain, all way to the data (returns %NULL, *err == 0). | 345 | * the whole chain, all way to the data (returns %NULL, *err == 0). |
346 | * | 346 | * |
347 | * Need to be called with | 347 | * Need to be called with |
348 | * mutex_lock(&EXT4_I(inode)->truncate_mutex) | 348 | * down_read(&EXT4_I(inode)->i_data_sem) |
349 | */ | 349 | */ |
350 | static Indirect *ext4_get_branch(struct inode *inode, int depth, | 350 | static Indirect *ext4_get_branch(struct inode *inode, int depth, |
351 | ext4_lblk_t *offsets, | 351 | ext4_lblk_t *offsets, |
@@ -777,7 +777,8 @@ err_out: | |||
777 | * | 777 | * |
778 | * | 778 | * |
779 | * Need to be called with | 779 | * Need to be called with |
780 | * mutex_lock(&EXT4_I(inode)->truncate_mutex) | 780 | * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block |
781 | * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem) | ||
781 | */ | 782 | */ |
782 | int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, | 783 | int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, |
783 | ext4_lblk_t iblock, unsigned long maxblocks, | 784 | ext4_lblk_t iblock, unsigned long maxblocks, |
@@ -865,7 +866,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, | |||
865 | err = ext4_splice_branch(handle, inode, iblock, | 866 | err = ext4_splice_branch(handle, inode, iblock, |
866 | partial, indirect_blks, count); | 867 | partial, indirect_blks, count); |
867 | /* | 868 | /* |
868 | * i_disksize growing is protected by truncate_mutex. Don't forget to | 869 | * i_disksize growing is protected by i_data_sem. Don't forget to |
869 | * protect it if you're about to implement concurrent | 870 | * protect it if you're about to implement concurrent |
870 | * ext4_get_block() -bzzz | 871 | * ext4_get_block() -bzzz |
871 | */ | 872 | */ |
@@ -895,6 +896,31 @@ out: | |||
895 | 896 | ||
896 | #define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32) | 897 | #define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32) |
897 | 898 | ||
899 | int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, | ||
900 | unsigned long max_blocks, struct buffer_head *bh, | ||
901 | int create, int extend_disksize) | ||
902 | { | ||
903 | int retval; | ||
904 | if (create) { | ||
905 | down_write((&EXT4_I(inode)->i_data_sem)); | ||
906 | } else { | ||
907 | down_read((&EXT4_I(inode)->i_data_sem)); | ||
908 | } | ||
909 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { | ||
910 | retval = ext4_ext_get_blocks(handle, inode, block, max_blocks, | ||
911 | bh, create, extend_disksize); | ||
912 | } else { | ||
913 | retval = ext4_get_blocks_handle(handle, inode, block, | ||
914 | max_blocks, bh, create, extend_disksize); | ||
915 | } | ||
916 | if (create) { | ||
917 | up_write((&EXT4_I(inode)->i_data_sem)); | ||
918 | } else { | ||
919 | up_read((&EXT4_I(inode)->i_data_sem)); | ||
920 | } | ||
921 | return retval; | ||
922 | } | ||
923 | |||
898 | static int ext4_get_block(struct inode *inode, sector_t iblock, | 924 | static int ext4_get_block(struct inode *inode, sector_t iblock, |
899 | struct buffer_head *bh_result, int create) | 925 | struct buffer_head *bh_result, int create) |
900 | { | 926 | { |
@@ -1399,7 +1425,7 @@ static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) | |||
1399 | * ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ... | 1425 | * ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ... |
1400 | * | 1426 | * |
1401 | * Same applies to ext4_get_block(). We will deadlock on various things like | 1427 | * Same applies to ext4_get_block(). We will deadlock on various things like |
1402 | * lock_journal and i_truncate_mutex. | 1428 | * lock_journal and i_data_sem |
1403 | * | 1429 | * |
1404 | * Setting PF_MEMALLOC here doesn't work - too many internal memory | 1430 | * Setting PF_MEMALLOC here doesn't work - too many internal memory |
1405 | * allocations fail. | 1431 | * allocations fail. |
@@ -2325,7 +2351,7 @@ void ext4_truncate(struct inode *inode) | |||
2325 | * From here we block out all ext4_get_block() callers who want to | 2351 | * From here we block out all ext4_get_block() callers who want to |
2326 | * modify the block allocation tree. | 2352 | * modify the block allocation tree. |
2327 | */ | 2353 | */ |
2328 | mutex_lock(&ei->truncate_mutex); | 2354 | down_write(&ei->i_data_sem); |
2329 | 2355 | ||
2330 | if (n == 1) { /* direct blocks */ | 2356 | if (n == 1) { /* direct blocks */ |
2331 | ext4_free_data(handle, inode, NULL, i_data+offsets[0], | 2357 | ext4_free_data(handle, inode, NULL, i_data+offsets[0], |
@@ -2389,7 +2415,7 @@ do_indirects: | |||
2389 | 2415 | ||
2390 | ext4_discard_reservation(inode); | 2416 | ext4_discard_reservation(inode); |
2391 | 2417 | ||
2392 | mutex_unlock(&ei->truncate_mutex); | 2418 | up_write(&ei->i_data_sem); |
2393 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | 2419 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); |
2394 | ext4_mark_inode_dirty(handle, inode); | 2420 | ext4_mark_inode_dirty(handle, inode); |
2395 | 2421 | ||