]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/btrfs/extent_io.c
NFSD: Refactor portlist socket closing into a helper
[mv-sheeva.git] / fs / btrfs / extent_io.c
index eb2bee8b7fbfb19fb37dc26cbe6fe01ec92ea3ef..05a1c42e25bf6ec5d12c34e32b6a6188e88b2df4 100644 (file)
@@ -50,7 +50,10 @@ struct extent_page_data {
        /* tells writepage not to lock the state bits for this range
         * it still does the unlocking
         */
-       int extent_locked;
+       unsigned int extent_locked:1;
+
+       /* tells the submit_bio code to use a WRITE_SYNC */
+       unsigned int sync_io:1;
 };
 
 int __init extent_io_init(void)
@@ -2101,6 +2104,16 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
        return ret;
 }
 
+static noinline void update_nr_written(struct page *page,
+                                     struct writeback_control *wbc,
+                                     unsigned long nr_written)
+{
+       wbc->nr_to_write -= nr_written;
+       if (wbc->range_cyclic || (wbc->nr_to_write > 0 &&
+           wbc->range_start == 0 && wbc->range_end == LLONG_MAX))
+               page->mapping->writeback_index = page->index + nr_written;
+}
+
 /*
  * the writepage semantics are similar to regular writepage.  extent
  * records are inserted to lock ranges in the tree, and as dirty areas
@@ -2136,8 +2149,14 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
        u64 delalloc_end;
        int page_started;
        int compressed;
+       int write_flags;
        unsigned long nr_written = 0;
 
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               write_flags = WRITE_SYNC_PLUG;
+       else
+               write_flags = WRITE;
+
        WARN_ON(!PageLocked(page));
        pg_offset = i_size & (PAGE_CACHE_SIZE - 1);
        if (page->index > end_index ||
@@ -2164,6 +2183,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
        delalloc_end = 0;
        page_started = 0;
        if (!epd->extent_locked) {
+               /*
+                * make sure the wbc mapping index is at least updated
+                * to this page.
+                */
+               update_nr_written(page, wbc, 0);
+
                while (delalloc_end < page_end) {
                        nr_delalloc = find_lock_delalloc_range(inode, tree,
                                                       page,
@@ -2185,7 +2210,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
                 */
                if (page_started) {
                        ret = 0;
-                       goto update_nr_written;
+                       /*
+                        * we've unlocked the page, so we can't update
+                        * the mapping's writeback index, just update
+                        * nr_to_write.
+                        */
+                       wbc->nr_to_write -= nr_written;
+                       goto done_unlocked;
                }
        }
        lock_extent(tree, start, page_end, GFP_NOFS);
@@ -2198,13 +2229,18 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
                if (ret == -EAGAIN) {
                        unlock_extent(tree, start, page_end, GFP_NOFS);
                        redirty_page_for_writepage(wbc, page);
+                       update_nr_written(page, wbc, nr_written);
                        unlock_page(page);
                        ret = 0;
-                       goto update_nr_written;
+                       goto done_unlocked;
                }
        }
 
-       nr_written++;
+       /*
+        * we don't want to touch the inode after unlocking the page,
+        * so we update the mapping writeback index now
+        */
+       update_nr_written(page, wbc, nr_written + 1);
 
        end = page_end;
        if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0))
@@ -2314,9 +2350,9 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
                                       (unsigned long long)end);
                        }
 
-                       ret = submit_extent_page(WRITE, tree, page, sector,
-                                                iosize, pg_offset, bdev,
-                                                &epd->bio, max_nr,
+                       ret = submit_extent_page(write_flags, tree, page,
+                                                sector, iosize, pg_offset,
+                                                bdev, &epd->bio, max_nr,
                                                 end_bio_extent_writepage,
                                                 0, 0, 0);
                        if (ret)
@@ -2336,11 +2372,8 @@ done:
                unlock_extent(tree, unlock_start, page_end, GFP_NOFS);
        unlock_page(page);
 
-update_nr_written:
-       wbc->nr_to_write -= nr_written;
-       if (wbc->range_cyclic || (wbc->nr_to_write > 0 &&
-           wbc->range_start == 0 && wbc->range_end == LLONG_MAX))
-               page->mapping->writeback_index = page->index + nr_written;
+done_unlocked:
+
        return 0;
 }
 
@@ -2460,15 +2493,23 @@ retry:
        return ret;
 }
 
-static noinline void flush_write_bio(void *data)
+static void flush_epd_write_bio(struct extent_page_data *epd)
 {
-       struct extent_page_data *epd = data;
        if (epd->bio) {
-               submit_one_bio(WRITE, epd->bio, 0, 0);
+               if (epd->sync_io)
+                       submit_one_bio(WRITE_SYNC, epd->bio, 0, 0);
+               else
+                       submit_one_bio(WRITE, epd->bio, 0, 0);
                epd->bio = NULL;
        }
 }
 
+static noinline void flush_write_bio(void *data)
+{
+       struct extent_page_data *epd = data;
+       flush_epd_write_bio(epd);
+}
+
 int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
                          get_extent_t *get_extent,
                          struct writeback_control *wbc)
@@ -2480,23 +2521,22 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
                .tree = tree,
                .get_extent = get_extent,
                .extent_locked = 0,
+               .sync_io = wbc->sync_mode == WB_SYNC_ALL,
        };
        struct writeback_control wbc_writepages = {
                .bdi            = wbc->bdi,
-               .sync_mode      = WB_SYNC_NONE,
+               .sync_mode      = wbc->sync_mode,
                .older_than_this = NULL,
                .nr_to_write    = 64,
                .range_start    = page_offset(page) + PAGE_CACHE_SIZE,
                .range_end      = (loff_t)-1,
        };
 
-
        ret = __extent_writepage(page, wbc, &epd);
 
        extent_write_cache_pages(tree, mapping, &wbc_writepages,
                                 __extent_writepage, &epd, flush_write_bio);
-       if (epd.bio)
-               submit_one_bio(WRITE, epd.bio, 0, 0);
+       flush_epd_write_bio(&epd);
        return ret;
 }
 
@@ -2515,6 +2555,7 @@ int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode,
                .tree = tree,
                .get_extent = get_extent,
                .extent_locked = 1,
+               .sync_io = mode == WB_SYNC_ALL,
        };
        struct writeback_control wbc_writepages = {
                .bdi            = inode->i_mapping->backing_dev_info,
@@ -2540,8 +2581,7 @@ int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode,
                start += PAGE_CACHE_SIZE;
        }
 
-       if (epd.bio)
-               submit_one_bio(WRITE, epd.bio, 0, 0);
+       flush_epd_write_bio(&epd);
        return ret;
 }
 
@@ -2556,13 +2596,13 @@ int extent_writepages(struct extent_io_tree *tree,
                .tree = tree,
                .get_extent = get_extent,
                .extent_locked = 0,
+               .sync_io = wbc->sync_mode == WB_SYNC_ALL,
        };
 
        ret = extent_write_cache_pages(tree, mapping, wbc,
                                       __extent_writepage, &epd,
                                       flush_write_bio);
-       if (epd.bio)
-               submit_one_bio(WRITE, epd.bio, 0, 0);
+       flush_epd_write_bio(&epd);
        return ret;
 }