diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2008-02-15 12:47:21 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-02-15 12:47:21 -0500 |
commit | 55bd725aa3a83b3935988f37275b5a80e10d4169 (patch) | |
tree | 9e4c092830eafbb0036892d578d4075689ef81df | |
parent | 642be6ec218b956fbae88304449720f76ba0d578 (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.c | 10 |
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); |
2627 | retry: | 2627 | retry: |
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 | } |