]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ext4/inode.c
ext4: Mark the buffer_heads as dirty and uptodate after prepare_write
[linux-2.6-omap-h63xx.git] / fs / ext4 / inode.c
index 9b4ec9decfd1b6020c13bbd57d86af7eab46006b..be21a5ae33cb01261a8fe1ce0e2377654a940d3b 100644 (file)
@@ -1648,6 +1648,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
        int ret = 0, err, nr_pages, i;
        unsigned long index, end;
        struct pagevec pvec;
+       long pages_skipped;
 
        BUG_ON(mpd->next_page <= mpd->first_page);
        pagevec_init(&pvec, 0);
@@ -1655,20 +1656,30 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
        end = mpd->next_page - 1;
 
        while (index <= end) {
-               /* XXX: optimize tail */
-               nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE);
+               /*
+                * We can use PAGECACHE_TAG_DIRTY lookup here because
+                * even though we have cleared the dirty flag on the page
+                * We still keep the page in the radix tree with tag
+                * PAGECACHE_TAG_DIRTY. See clear_page_dirty_for_io.
+                * The PAGECACHE_TAG_DIRTY is cleared in set_page_writeback
+                * which is called via the below writepage callback.
+                */
+               nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                                       PAGECACHE_TAG_DIRTY,
+                                       min(end - index,
+                                       (pgoff_t)PAGEVEC_SIZE-1) + 1);
                if (nr_pages == 0)
                        break;
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
 
-                       index = page->index;
-                       if (index > end)
-                               break;
-                       index++;
-
+                       pages_skipped = mpd->wbc->pages_skipped;
                        err = mapping->a_ops->writepage(page, mpd->wbc);
-                       if (!err)
+                       if (!err && (pages_skipped == mpd->wbc->pages_skipped))
+                               /*
+                                * have successfully written the page
+                                * without skipping the same
+                                */
                                mpd->pages_written++;
                        /*
                         * In error case, we have to continue because
@@ -2104,7 +2115,6 @@ static int mpage_da_writepages(struct address_space *mapping,
                               struct writeback_control *wbc,
                               struct mpage_da_data *mpd)
 {
-       long to_write;
        int ret;
 
        if (!mpd->get_block)
@@ -2119,19 +2129,18 @@ static int mpage_da_writepages(struct address_space *mapping,
        mpd->pages_written = 0;
        mpd->retval = 0;
 
-       to_write = wbc->nr_to_write;
-
        ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd);
-
        /*
         * Handle last extent of pages
         */
        if (!mpd->io_done && mpd->next_page != mpd->first_page) {
                if (mpage_da_map_blocks(mpd) == 0)
                        mpage_da_submit_io(mpd);
-       }
 
-       wbc->nr_to_write = to_write - mpd->pages_written;
+               mpd->io_done = 1;
+               ret = MPAGE_DA_EXTENT_TAIL;
+       }
+       wbc->nr_to_write -= mpd->pages_written;
        return ret;
 }
 
@@ -2320,6 +2329,8 @@ static int ext4_da_writepage(struct page *page,
                        unlock_page(page);
                        return 0;
                }
+               /* now mark the buffer_heads as dirty and uptodate */
+               block_commit_write(page, 0, PAGE_CACHE_SIZE);
        }
 
        if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
@@ -2360,12 +2371,14 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
 static int ext4_da_writepages(struct address_space *mapping,
                              struct writeback_control *wbc)
 {
+       pgoff_t index;
+       int range_whole = 0;
        handle_t *handle = NULL;
-       loff_t range_start = 0;
        struct mpage_da_data mpd;
        struct inode *inode = mapping->host;
+       int no_nrwrite_index_update;
+       long pages_written = 0, pages_skipped;
        int needed_blocks, ret = 0, nr_to_writebump = 0;
-       long to_write, pages_skipped = 0;
        struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
 
        /*
@@ -2385,23 +2398,26 @@ static int ext4_da_writepages(struct address_space *mapping,
                nr_to_writebump = sbi->s_mb_stream_request - wbc->nr_to_write;
                wbc->nr_to_write = sbi->s_mb_stream_request;
        }
+       if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+               range_whole = 1;
 
-       if (!wbc->range_cyclic)
-               /*
-                * If range_cyclic is not set force range_cont
-                * and save the old writeback_index
-                */
-               wbc->range_cont = 1;
-
-       range_start =  wbc->range_start;
-       pages_skipped = wbc->pages_skipped;
+       if (wbc->range_cyclic)
+               index = mapping->writeback_index;
+       else
+               index = wbc->range_start >> PAGE_CACHE_SHIFT;
 
        mpd.wbc = wbc;
        mpd.inode = mapping->host;
 
-restart_loop:
-       to_write = wbc->nr_to_write;
-       while (!ret && to_write > 0) {
+       /*
+        * we don't want write_cache_pages to update
+        * nr_to_write and writeback_index
+        */
+       no_nrwrite_index_update = wbc->no_nrwrite_index_update;
+       wbc->no_nrwrite_index_update = 1;
+       pages_skipped = wbc->pages_skipped;
+
+       while (!ret && wbc->nr_to_write > 0) {
 
                /*
                 * we  insert one extent at a time. So we need
@@ -2422,48 +2438,53 @@ restart_loop:
                        dump_stack();
                        goto out_writepages;
                }
-               to_write -= wbc->nr_to_write;
-
                mpd.get_block = ext4_da_get_block_write;
                ret = mpage_da_writepages(mapping, wbc, &mpd);
 
                ext4_journal_stop(handle);
 
-               if (mpd.retval == -ENOSPC)
+               if (mpd.retval == -ENOSPC) {
+                       /* commit the transaction which would
+                        * free blocks released in the transaction
+                        * and try again
+                        */
                        jbd2_journal_force_commit_nested(sbi->s_journal);
-
-               /* reset the retry count */
-               if (ret == MPAGE_DA_EXTENT_TAIL) {
+                       wbc->pages_skipped = pages_skipped;
+                       ret = 0;
+               } else if (ret == MPAGE_DA_EXTENT_TAIL) {
                        /*
                         * got one extent now try with
                         * rest of the pages
                         */
-                       to_write += wbc->nr_to_write;
+                       pages_written += mpd.pages_written;
+                       wbc->pages_skipped = pages_skipped;
                        ret = 0;
-               } else if (wbc->nr_to_write) {
+               } else if (wbc->nr_to_write)
                        /*
                         * There is no more writeout needed
                         * or we requested for a noblocking writeout
                         * and we found the device congested
                         */
-                       to_write += wbc->nr_to_write;
                        break;
-               }
-               wbc->nr_to_write = to_write;
-       }
-
-       if (wbc->range_cont && (pages_skipped != wbc->pages_skipped)) {
-               /* We skipped pages in this loop */
-               wbc->range_start = range_start;
-               wbc->nr_to_write = to_write +
-                               wbc->pages_skipped - pages_skipped;
-               wbc->pages_skipped = pages_skipped;
-               goto restart_loop;
        }
+       if (pages_skipped != wbc->pages_skipped)
+               printk(KERN_EMERG "This should not happen leaving %s "
+                               "with nr_to_write = %ld ret = %d\n",
+                               __func__, wbc->nr_to_write, ret);
+
+       /* Update index */
+       index += pages_written;
+       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
+               /*
+                * set the writeback_index so that range_cyclic
+                * mode will write it back later
+                */
+               mapping->writeback_index = index;
 
 out_writepages:
-       wbc->nr_to_write = to_write - nr_to_writebump;
-       wbc->range_start = range_start;
+       if (!no_nrwrite_index_update)
+               wbc->no_nrwrite_index_update = 0;
+       wbc->nr_to_write -= nr_to_writebump;
        return ret;
 }
 
@@ -4175,7 +4196,6 @@ static int ext4_inode_blocks_set(handle_t *handle,
        struct inode *inode = &(ei->vfs_inode);
        u64 i_blocks = inode->i_blocks;
        struct super_block *sb = inode->i_sb;
-       int err = 0;
 
        if (i_blocks <= ~0U) {
                /*
@@ -4185,36 +4205,27 @@ static int ext4_inode_blocks_set(handle_t *handle,
                raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
                raw_inode->i_blocks_high = 0;
                ei->i_flags &= ~EXT4_HUGE_FILE_FL;
-       } else if (i_blocks <= 0xffffffffffffULL) {
+               return 0;
+       }
+       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
+               return -EFBIG;
+
+       if (i_blocks <= 0xffffffffffffULL) {
                /*
                 * i_blocks can be represented in a 48 bit variable
                 * as multiple of 512 bytes
                 */
-               err = ext4_update_rocompat_feature(handle, sb,
-                                           EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
-               if (err)
-                       goto  err_out;
-               /* i_block is stored in the split  48 bit fields */
                raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
                raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
                ei->i_flags &= ~EXT4_HUGE_FILE_FL;
        } else {
-               /*
-                * i_blocks should be represented in a 48 bit variable
-                * as multiple of  file system block size
-                */
-               err = ext4_update_rocompat_feature(handle, sb,
-                                           EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
-               if (err)
-                       goto  err_out;
                ei->i_flags |= EXT4_HUGE_FILE_FL;
                /* i_block is stored in file system block size */
                i_blocks = i_blocks >> (inode->i_blkbits - 9);
                raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
                raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
        }
-err_out:
-       return err;
+       return 0;
 }
 
 /*
@@ -4571,9 +4582,10 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks,
 static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
 {
        if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
-               return ext4_indirect_trans_blocks(inode, nrblocks, 0);
-       return ext4_ext_index_trans_blocks(inode, nrblocks, 0);
+               return ext4_indirect_trans_blocks(inode, nrblocks, chunk);
+       return ext4_ext_index_trans_blocks(inode, nrblocks, chunk);
 }
+
 /*
  * Account for index blocks, block groups bitmaps and block group
  * descriptor blocks if modify datablocks and index blocks