]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/ext4/inode.c
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[karo-tx-linux.git] / fs / ext4 / inode.c
index f0729b0705c710747eefb1e25360c5144eeef933..5834c4d76be80969125a9c2d56309e990ba07e84 100644 (file)
@@ -1643,6 +1643,7 @@ struct mpage_da_data {
         */
        struct ext4_map_blocks map;
        struct ext4_io_submit io_submit;        /* IO submission data */
+       unsigned int do_map:1;
 };
 
 static void mpage_release_unused_pages(struct mpage_da_data *mpd,
@@ -2179,6 +2180,9 @@ static bool mpage_add_bh_to_extent(struct mpage_da_data *mpd, ext4_lblk_t lblk,
 
        /* First block in the extent? */
        if (map->m_len == 0) {
+               /* We cannot map unless handle is started... */
+               if (!mpd->do_map)
+                       return false;
                map->m_lblk = lblk;
                map->m_len = 1;
                map->m_flags = bh->b_state & BH_FLAGS;
@@ -2231,6 +2235,9 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
                        /* Found extent to map? */
                        if (mpd->map.m_len)
                                return 0;
+                       /* Buffer needs mapping and handle is not started? */
+                       if (!mpd->do_map)
+                               return 0;
                        /* Everything mapped so far and we hit EOF */
                        break;
                }
@@ -2747,6 +2754,29 @@ retry:
                tag_pages_for_writeback(mapping, mpd.first_page, mpd.last_page);
        done = false;
        blk_start_plug(&plug);
+
+       /*
+        * First writeback pages that don't need mapping - we can avoid
+        * starting a transaction unnecessarily and also avoid being blocked
+        * in the block layer on device congestion while having transaction
+        * started.
+        */
+       mpd.do_map = 0;
+       mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
+       if (!mpd.io_submit.io_end) {
+               ret = -ENOMEM;
+               goto unplug;
+       }
+       ret = mpage_prepare_extent_to_map(&mpd);
+       /* Submit prepared bio */
+       ext4_io_submit(&mpd.io_submit);
+       ext4_put_io_end_defer(mpd.io_submit.io_end);
+       mpd.io_submit.io_end = NULL;
+       /* Unlock pages we didn't use */
+       mpage_release_unused_pages(&mpd, false);
+       if (ret < 0)
+               goto unplug;
+
        while (!done && mpd.first_page <= mpd.last_page) {
                /* For each extent of pages we use new io_end */
                mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
@@ -2775,8 +2805,10 @@ retry:
                                wbc->nr_to_write, inode->i_ino, ret);
                        /* Release allocated io_end */
                        ext4_put_io_end(mpd.io_submit.io_end);
+                       mpd.io_submit.io_end = NULL;
                        break;
                }
+               mpd.do_map = 1;
 
                trace_ext4_da_write_pages(inode, mpd.first_page, mpd.wbc);
                ret = mpage_prepare_extent_to_map(&mpd);
@@ -2807,6 +2839,7 @@ retry:
                if (!ext4_handle_valid(handle) || handle->h_sync == 0) {
                        ext4_journal_stop(handle);
                        handle = NULL;
+                       mpd.do_map = 0;
                }
                /* Submit prepared bio */
                ext4_io_submit(&mpd.io_submit);
@@ -2824,6 +2857,7 @@ retry:
                        ext4_journal_stop(handle);
                } else
                        ext4_put_io_end(mpd.io_submit.io_end);
+               mpd.io_submit.io_end = NULL;
 
                if (ret == -ENOSPC && sbi->s_journal) {
                        /*
@@ -2839,6 +2873,7 @@ retry:
                if (ret)
                        break;
        }
+unplug:
        blk_finish_plug(&plug);
        if (!ret && !cycled && wbc->nr_to_write > 0) {
                cycled = 1;
@@ -5855,6 +5890,11 @@ int ext4_page_mkwrite(struct vm_fault *vmf)
        file_update_time(vma->vm_file);
 
        down_read(&EXT4_I(inode)->i_mmap_sem);
+
+       ret = ext4_convert_inline_data(inode);
+       if (ret)
+               goto out_ret;
+
        /* Delalloc case is easy... */
        if (test_opt(inode->i_sb, DELALLOC) &&
            !ext4_should_journal_data(inode) &&