]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ext4: Fix locking hierarchy violation in ext4_fallocate()
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Fri, 15 Feb 2008 17:47:21 +0000 (12:47 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 15 Feb 2008 17:47:21 +0000 (12:47 -0500)
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>
fs/ext4/extents.c

index bc7081f1fbe80dd5add381c5746b1bbc74e4883a..e856f660fc301dcefcead1bc995a115f8e59d6d5 100644 (file)
@@ -2623,7 +2623,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
         * modify 1 super block, 1 block bitmap and 1 group descriptor.
         */
        credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
-       down_write((&EXT4_I(inode)->i_data_sem));
+       mutex_lock(&inode->i_mutex);
 retry:
        while (ret >= 0 && ret < max_blocks) {
                block = block + ret;
@@ -2634,7 +2634,7 @@ retry:
                        break;
                }
 
-               ret = ext4_ext_get_blocks(handle, inode, block,
+               ret = ext4_get_blocks_wrap(handle, inode, block,
                                          max_blocks, &map_bh,
                                          EXT4_CREATE_UNINITIALIZED_EXT, 0);
                WARN_ON(ret <= 0);
@@ -2680,7 +2680,6 @@ retry:
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
 
-       up_write((&EXT4_I(inode)->i_data_sem));
        /*
         * Time to update the file size.
         * Update only when preallocation was requested beyond the file size.
@@ -2692,21 +2691,18 @@ retry:
                         * if no error, we assume preallocation succeeded
                         * completely
                         */
-                       mutex_lock(&inode->i_mutex);
                        i_size_write(inode, offset + len);
                        EXT4_I(inode)->i_disksize = i_size_read(inode);
-                       mutex_unlock(&inode->i_mutex);
                } else if (ret < 0 && nblocks) {
                        /* Handle partial allocation scenario */
                        loff_t newsize;
 
-                       mutex_lock(&inode->i_mutex);
                        newsize  = (nblocks << blkbits) + i_size_read(inode);
                        i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
                        EXT4_I(inode)->i_disksize = i_size_read(inode);
-                       mutex_unlock(&inode->i_mutex);
                }
        }
 
+       mutex_unlock(&inode->i_mutex);
        return ret > 0 ? ret2 : ret;
 }