|
@@ -50,7 +50,10 @@ struct extent_page_data {
|
|
/* tells writepage not to lock the state bits for this range
|
|
/* tells writepage not to lock the state bits for this range
|
|
* it still does the unlocking
|
|
* 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)
|
|
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;
|
|
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
|
|
* the writepage semantics are similar to regular writepage. extent
|
|
* records are inserted to lock ranges in the tree, and as dirty areas
|
|
* 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;
|
|
u64 delalloc_end;
|
|
int page_started;
|
|
int page_started;
|
|
int compressed;
|
|
int compressed;
|
|
|
|
+ int write_flags;
|
|
unsigned long nr_written = 0;
|
|
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));
|
|
WARN_ON(!PageLocked(page));
|
|
pg_offset = i_size & (PAGE_CACHE_SIZE - 1);
|
|
pg_offset = i_size & (PAGE_CACHE_SIZE - 1);
|
|
if (page->index > end_index ||
|
|
if (page->index > end_index ||
|
|
@@ -2164,6 +2183,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
|
delalloc_end = 0;
|
|
delalloc_end = 0;
|
|
page_started = 0;
|
|
page_started = 0;
|
|
if (!epd->extent_locked) {
|
|
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) {
|
|
while (delalloc_end < page_end) {
|
|
nr_delalloc = find_lock_delalloc_range(inode, tree,
|
|
nr_delalloc = find_lock_delalloc_range(inode, tree,
|
|
page,
|
|
page,
|
|
@@ -2185,7 +2210,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
|
*/
|
|
*/
|
|
if (page_started) {
|
|
if (page_started) {
|
|
ret = 0;
|
|
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);
|
|
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) {
|
|
if (ret == -EAGAIN) {
|
|
unlock_extent(tree, start, page_end, GFP_NOFS);
|
|
unlock_extent(tree, start, page_end, GFP_NOFS);
|
|
redirty_page_for_writepage(wbc, page);
|
|
redirty_page_for_writepage(wbc, page);
|
|
|
|
+ update_nr_written(page, wbc, nr_written);
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
ret = 0;
|
|
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;
|
|
end = page_end;
|
|
if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0))
|
|
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);
|
|
(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,
|
|
end_bio_extent_writepage,
|
|
0, 0, 0);
|
|
0, 0, 0);
|
|
if (ret)
|
|
if (ret)
|
|
@@ -2336,11 +2372,8 @@ done:
|
|
unlock_extent(tree, unlock_start, page_end, GFP_NOFS);
|
|
unlock_extent(tree, unlock_start, page_end, GFP_NOFS);
|
|
unlock_page(page);
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2460,15 +2493,23 @@ retry:
|
|
return ret;
|
|
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) {
|
|
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;
|
|
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,
|
|
int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
|
|
get_extent_t *get_extent,
|
|
get_extent_t *get_extent,
|
|
struct writeback_control *wbc)
|
|
struct writeback_control *wbc)
|
|
@@ -2480,23 +2521,22 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
|
|
.tree = tree,
|
|
.tree = tree,
|
|
.get_extent = get_extent,
|
|
.get_extent = get_extent,
|
|
.extent_locked = 0,
|
|
.extent_locked = 0,
|
|
|
|
+ .sync_io = wbc->sync_mode == WB_SYNC_ALL,
|
|
};
|
|
};
|
|
struct writeback_control wbc_writepages = {
|
|
struct writeback_control wbc_writepages = {
|
|
.bdi = wbc->bdi,
|
|
.bdi = wbc->bdi,
|
|
- .sync_mode = WB_SYNC_NONE,
|
|
|
|
|
|
+ .sync_mode = wbc->sync_mode,
|
|
.older_than_this = NULL,
|
|
.older_than_this = NULL,
|
|
.nr_to_write = 64,
|
|
.nr_to_write = 64,
|
|
.range_start = page_offset(page) + PAGE_CACHE_SIZE,
|
|
.range_start = page_offset(page) + PAGE_CACHE_SIZE,
|
|
.range_end = (loff_t)-1,
|
|
.range_end = (loff_t)-1,
|
|
};
|
|
};
|
|
|
|
|
|
-
|
|
|
|
ret = __extent_writepage(page, wbc, &epd);
|
|
ret = __extent_writepage(page, wbc, &epd);
|
|
|
|
|
|
extent_write_cache_pages(tree, mapping, &wbc_writepages,
|
|
extent_write_cache_pages(tree, mapping, &wbc_writepages,
|
|
__extent_writepage, &epd, flush_write_bio);
|
|
__extent_writepage, &epd, flush_write_bio);
|
|
- if (epd.bio)
|
|
|
|
- submit_one_bio(WRITE, epd.bio, 0, 0);
|
|
|
|
|
|
+ flush_epd_write_bio(&epd);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2515,6 +2555,7 @@ int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode,
|
|
.tree = tree,
|
|
.tree = tree,
|
|
.get_extent = get_extent,
|
|
.get_extent = get_extent,
|
|
.extent_locked = 1,
|
|
.extent_locked = 1,
|
|
|
|
+ .sync_io = mode == WB_SYNC_ALL,
|
|
};
|
|
};
|
|
struct writeback_control wbc_writepages = {
|
|
struct writeback_control wbc_writepages = {
|
|
.bdi = inode->i_mapping->backing_dev_info,
|
|
.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;
|
|
start += PAGE_CACHE_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
- if (epd.bio)
|
|
|
|
- submit_one_bio(WRITE, epd.bio, 0, 0);
|
|
|
|
|
|
+ flush_epd_write_bio(&epd);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2556,13 +2596,13 @@ int extent_writepages(struct extent_io_tree *tree,
|
|
.tree = tree,
|
|
.tree = tree,
|
|
.get_extent = get_extent,
|
|
.get_extent = get_extent,
|
|
.extent_locked = 0,
|
|
.extent_locked = 0,
|
|
|
|
+ .sync_io = wbc->sync_mode == WB_SYNC_ALL,
|
|
};
|
|
};
|
|
|
|
|
|
ret = extent_write_cache_pages(tree, mapping, wbc,
|
|
ret = extent_write_cache_pages(tree, mapping, wbc,
|
|
__extent_writepage, &epd,
|
|
__extent_writepage, &epd,
|
|
flush_write_bio);
|
|
flush_write_bio);
|
|
- if (epd.bio)
|
|
|
|
- submit_one_bio(WRITE, epd.bio, 0, 0);
|
|
|
|
|
|
+ flush_epd_write_bio(&epd);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|