]> Pileus Git - ~andy/linux/blobdiff - fs/ext4/inode.c
ext4: don't wait for extent conversion in ext4_punch_hole()
[~andy/linux] / fs / ext4 / inode.c
index 736d164dc2ba76d527e3cf7b85f14832313d9ed7..de6dd77f0c569797dc9eed56fb257b07c6ee4242 100644 (file)
@@ -1410,6 +1410,7 @@ static void ext4_da_page_release_reservation(struct page *page,
 struct mpage_da_data {
        struct inode *inode;
        struct writeback_control *wbc;
+
        pgoff_t first_page;     /* The first page to write */
        pgoff_t next_page;      /* Current page to examine */
        pgoff_t last_page;      /* Last page to examine */
@@ -2108,8 +2109,14 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
        err = ext4_map_blocks(handle, inode, map, get_blocks_flags);
        if (err < 0)
                return err;
-       if (map->m_flags & EXT4_MAP_UNINIT)
+       if (map->m_flags & EXT4_MAP_UNINIT) {
+               if (!mpd->io_submit.io_end->handle &&
+                   ext4_handle_valid(handle)) {
+                       mpd->io_submit.io_end->handle = handle->h_rsv_handle;
+                       handle->h_rsv_handle = NULL;
+               }
                ext4_set_io_unwritten_flag(inode, mpd->io_submit.io_end);
+       }
 
        BUG_ON(map->m_len == 0);
        if (map->m_flags & EXT4_MAP_NEW) {
@@ -2351,7 +2358,7 @@ static int ext4_da_writepages(struct address_space *mapping,
        handle_t *handle = NULL;
        struct mpage_da_data mpd;
        struct inode *inode = mapping->host;
-       int needed_blocks, ret = 0;
+       int needed_blocks, rsv_blocks = 0, ret = 0;
        struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
        bool done;
        struct blk_plug plug;
@@ -2379,6 +2386,14 @@ static int ext4_da_writepages(struct address_space *mapping,
        if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED))
                return -EROFS;
 
+       if (ext4_should_dioread_nolock(inode)) {
+               /*
+                * We may need to convert upto one extent per block in
+                * the page and we may dirty the inode.
+                */
+               rsv_blocks = 1 + (PAGE_CACHE_SIZE >> inode->i_blkbits);
+       }
+
        /*
         * If we have inline data and arrive here, it means that
         * we will soon create the block for the 1st page, so
@@ -2438,8 +2453,8 @@ retry:
                needed_blocks = ext4_da_writepages_trans_blocks(inode);
 
                /* start a new transaction */
-               handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE,
-                                           needed_blocks);
+               handle = ext4_journal_start_with_reserve(inode,
+                               EXT4_HT_WRITE_PAGE, needed_blocks, rsv_blocks);
                if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
                        ext4_msg(inode->i_sb, KERN_CRIT, "%s: jbd2_start: "
@@ -3021,11 +3036,18 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
 
        BUG_ON(iocb->private == NULL);
 
+       /*
+        * Make all waiters for direct IO properly wait also for extent
+        * conversion. This also disallows race between truncate() and
+        * overwrite DIO as i_dio_count needs to be incremented under i_mutex.
+        */
+       if (rw == WRITE)
+               atomic_inc(&inode->i_dio_count);
+
        /* If we do a overwrite dio, i_mutex locking can be released */
        overwrite = *((int *)iocb->private);
 
        if (overwrite) {
-               atomic_inc(&inode->i_dio_count);
                down_read(&EXT4_I(inode)->i_data_sem);
                mutex_unlock(&inode->i_mutex);
        }
@@ -3120,7 +3142,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
                 * for non AIO case, since the IO is already
                 * completed, we could do the conversion right here
                 */
-               err = ext4_convert_unwritten_extents(inode,
+               err = ext4_convert_unwritten_extents(NULL, inode,
                                                     offset, ret);
                if (err < 0)
                        ret = err;
@@ -3128,9 +3150,10 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
        }
 
 retake_lock:
+       if (rw == WRITE)
+               inode_dio_done(inode);
        /* take i_mutex locking again if we do a ovewrite dio */
        if (overwrite) {
-               inode_dio_done(inode);
                up_read(&EXT4_I(inode)->i_data_sem);
                mutex_lock(&inode->i_mutex);
        }
@@ -3499,9 +3522,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
 
        /* Wait all existing dio workers, newcomers will block on i_mutex */
        ext4_inode_block_unlocked_dio(inode);
-       ret = ext4_flush_unwritten_io(inode);
-       if (ret)
-               goto out_dio;
        inode_dio_wait(inode);
 
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
@@ -3620,12 +3640,6 @@ void ext4_truncate(struct inode *inode)
                        return;
        }
 
-       /*
-        * finish any pending end_io work so we won't run the risk of
-        * converting any truncated blocks to initialized later
-        */
-       ext4_flush_unwritten_io(inode);
-
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                credits = ext4_writepage_trans_blocks(inode);
        else