/* Lookup extent status tree firstly */
        if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) {
-               if (ext4_es_is_hole(&es)) {
-                       down_read(&EXT4_I(inode)->i_data_sem);
+               if (ext4_es_is_hole(&es))
                        goto add_delayed;
-               }
 
                /*
                 * Delayed extent could be allocated by fallocate.
                retval = ext4_ext_map_blocks(NULL, inode, map, 0);
        else
                retval = ext4_ind_map_blocks(NULL, inode, map, 0);
-       if (retval < 0)
-               goto out_unlock;
+       if (retval < 0) {
+               up_read(&EXT4_I(inode)->i_data_sem);
+               return retval;
+       }
        if (retval > 0) {
                unsigned int status;
 
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
                                      map->m_pblk, status);
-               goto out_unlock;
+               up_read(&EXT4_I(inode)->i_data_sem);
+               return retval;
        }
+       up_read(&EXT4_I(inode)->i_data_sem);
 
 add_delayed:
-       /*
-        * XXX: __block_prepare_write() unmaps passed block,
-        * is it OK?
-        */
+       down_write(&EXT4_I(inode)->i_data_sem);
        retval = ext4_insert_delayed_block(inode, map->m_lblk);
+       up_write(&EXT4_I(inode)->i_data_sem);
        if (retval)
-               goto out_unlock;
+               return retval;
 
        map_bh(bh, inode->i_sb, invalid_block);
        set_buffer_new(bh);
        set_buffer_delay(bh);
-
-out_unlock:
-       up_read((&EXT4_I(inode)->i_data_sem));
        return retval;
 }