aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-02-15 12:47:21 -0500
committerTheodore Ts'o <tytso@mit.edu>2008-02-15 12:47:21 -0500
commit55bd725aa3a83b3935988f37275b5a80e10d4169 (patch)
tree9e4c092830eafbb0036892d578d4075689ef81df
parent642be6ec218b956fbae88304449720f76ba0d578 (diff)
ext4: Fix locking hierarchy violation in ext4_fallocate()
ext4_fallocate() was trying to acquire i_data_sem outside of jbd2_start_transaction/jbd2_journal_stop, which violates ext4's locking hierarchy. So we take i_mutex to prevent writes and truncates during the complete fallocate operation, and use ext4_get_block_wrap() which acquires and releases i_data_sem for each block allocation. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/extents.c10
1 files changed, 3 insertions, 7 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index bc7081f1fbe8..e856f660fc30 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2623,7 +2623,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
2623 * modify 1 super block, 1 block bitmap and 1 group descriptor. 2623 * modify 1 super block, 1 block bitmap and 1 group descriptor.
2624 */ 2624 */
2625 credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3; 2625 credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
2626 down_write((&EXT4_I(inode)->i_data_sem)); 2626 mutex_lock(&inode->i_mutex);
2627retry: 2627retry:
2628 while (ret >= 0 && ret < max_blocks) { 2628 while (ret >= 0 && ret < max_blocks) {
2629 block = block + ret; 2629 block = block + ret;
@@ -2634,7 +2634,7 @@ retry:
2634 break; 2634 break;
2635 } 2635 }
2636 2636
2637 ret = ext4_ext_get_blocks(handle, inode, block, 2637 ret = ext4_get_blocks_wrap(handle, inode, block,
2638 max_blocks, &map_bh, 2638 max_blocks, &map_bh,
2639 EXT4_CREATE_UNINITIALIZED_EXT, 0); 2639 EXT4_CREATE_UNINITIALIZED_EXT, 0);
2640 WARN_ON(ret <= 0); 2640 WARN_ON(ret <= 0);
@@ -2680,7 +2680,6 @@ retry:
2680 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 2680 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
2681 goto retry; 2681 goto retry;
2682 2682
2683 up_write((&EXT4_I(inode)->i_data_sem));
2684 /* 2683 /*
2685 * Time to update the file size. 2684 * Time to update the file size.
2686 * Update only when preallocation was requested beyond the file size. 2685 * Update only when preallocation was requested beyond the file size.
@@ -2692,21 +2691,18 @@ retry:
2692 * if no error, we assume preallocation succeeded 2691 * if no error, we assume preallocation succeeded
2693 * completely 2692 * completely
2694 */ 2693 */
2695 mutex_lock(&inode->i_mutex);
2696 i_size_write(inode, offset + len); 2694 i_size_write(inode, offset + len);
2697 EXT4_I(inode)->i_disksize = i_size_read(inode); 2695 EXT4_I(inode)->i_disksize = i_size_read(inode);
2698 mutex_unlock(&inode->i_mutex);
2699 } else if (ret < 0 && nblocks) { 2696 } else if (ret < 0 && nblocks) {
2700 /* Handle partial allocation scenario */ 2697 /* Handle partial allocation scenario */
2701 loff_t newsize; 2698 loff_t newsize;
2702 2699
2703 mutex_lock(&inode->i_mutex);
2704 newsize = (nblocks << blkbits) + i_size_read(inode); 2700 newsize = (nblocks << blkbits) + i_size_read(inode);
2705 i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits)); 2701 i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
2706 EXT4_I(inode)->i_disksize = i_size_read(inode); 2702 EXT4_I(inode)->i_disksize = i_size_read(inode);
2707 mutex_unlock(&inode->i_mutex);
2708 } 2703 }
2709 } 2704 }
2710 2705
2706 mutex_unlock(&inode->i_mutex);
2711 return ret > 0 ? ret2 : ret; 2707 return ret > 0 ? ret2 : ret;
2712} 2708}