ext4: Take read lock during overwrite case.
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Tue, 29 Jan 2008 04:58:29 +0000 (23:58 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 29 Jan 2008 04:58:29 +0000 (23:58 -0500)
When we are overwriting a file and not actually allocating new file system
blocks we need to take only the read lock on i_data_sem.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
fs/ext4/inode.c

index a7eb8bb4bdd4afa7b864789e63dcca52df6cd0a8..89cd35386ff582f01d58afe5c8078f2acef413fc 100644 (file)
@@ -901,11 +901,31 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
                        int create, int extend_disksize)
 {
        int retval;
-       if (create) {
-               down_write((&EXT4_I(inode)->i_data_sem));
+       /*
+        * Try to see if we can get  the block without requesting
+        * for new file system block.
+        */
+       down_read((&EXT4_I(inode)->i_data_sem));
+       if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
+               retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
+                               bh, 0, 0);
        } else {
-               down_read((&EXT4_I(inode)->i_data_sem));
+               retval = ext4_get_blocks_handle(handle,
+                               inode, block, max_blocks, bh, 0, 0);
        }
+       up_read((&EXT4_I(inode)->i_data_sem));
+       if (!create || (retval > 0))
+               return retval;
+
+       /*
+        * We need to allocate new blocks which will result
+        * in i_data update
+        */
+       down_write((&EXT4_I(inode)->i_data_sem));
+       /*
+        * We need to check for EXT4 here because migrate
+        * could have changed the inode type in between
+        */
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
                                bh, create, extend_disksize);
@@ -913,11 +933,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
                retval = ext4_get_blocks_handle(handle, inode, block,
                                max_blocks, bh, create, extend_disksize);
        }
-       if (create) {
-               up_write((&EXT4_I(inode)->i_data_sem));
-       } else {
-               up_read((&EXT4_I(inode)->i_data_sem));
-       }
+       up_write((&EXT4_I(inode)->i_data_sem));
        return retval;
 }