aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-07-22 11:18:09 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commitf421950f86bf96a11fef932e167ab2e70d4c43a0 (patch)
treea2b62b942b023e37b6aae39891c2b314d8d8a3fb /fs/btrfs
parenta61e6f29dc7c9d56a776a518eed92bbc61848263 (diff)
Btrfs: Fix some data=ordered related data corruptions
Stress testing was showing data checksum errors, most of which were caused by a lookup bug in the extent_map tree. The tree was caching the last pointer returned, and searches would check the last pointer first. But, search callers also expect the search to return the very first matching extent in the range, which wasn't always true with the last pointer usage. For now, the code to cache the last return value is just removed. It is easy to fix, but I think lookups are rare enough that it isn't required anymore. This commit also replaces do_sync_mapping_range with a local copy of the related functions. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/extent_io.c20
-rw-r--r--fs/btrfs/extent_io.h1
-rw-r--r--fs/btrfs/extent_map.c9
-rw-r--r--fs/btrfs/extent_map.h1
-rw-r--r--fs/btrfs/file.c15
-rw-r--r--fs/btrfs/inode.c54
-rw-r--r--fs/btrfs/ordered-data.c115
-rw-r--r--fs/btrfs/ordered-data.h4
-rw-r--r--fs/btrfs/transaction.c2
10 files changed, 140 insertions, 83 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 96ab2797c09a..f8fccdac3055 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1590,6 +1590,8 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
1590 struct btrfs_root *root, struct btrfs_path *path, 1590 struct btrfs_root *root, struct btrfs_path *path,
1591 u64 isize); 1591 u64 isize);
1592/* inode.c */ 1592/* inode.c */
1593int btrfs_writepages(struct address_space *mapping,
1594 struct writeback_control *wbc);
1593int btrfs_create_subvol_root(struct btrfs_root *new_root, 1595int btrfs_create_subvol_root(struct btrfs_root *new_root,
1594 struct btrfs_trans_handle *trans, u64 new_dirid, 1596 struct btrfs_trans_handle *trans, u64 new_dirid,
1595 struct btrfs_block_group_cache *block_group); 1597 struct btrfs_block_group_cache *block_group);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 7380449cb5b3..9965993748d0 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -97,7 +97,6 @@ void extent_io_tree_init(struct extent_io_tree *tree,
97 spin_lock_init(&tree->lock); 97 spin_lock_init(&tree->lock);
98 spin_lock_init(&tree->buffer_lock); 98 spin_lock_init(&tree->buffer_lock);
99 tree->mapping = mapping; 99 tree->mapping = mapping;
100 tree->last = NULL;
101} 100}
102EXPORT_SYMBOL(extent_io_tree_init); 101EXPORT_SYMBOL(extent_io_tree_init);
103 102
@@ -173,12 +172,6 @@ static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
173 struct tree_entry *entry; 172 struct tree_entry *entry;
174 struct tree_entry *prev_entry = NULL; 173 struct tree_entry *prev_entry = NULL;
175 174
176 if (tree->last) {
177 struct extent_state *state;
178 state = tree->last;
179 if (state->start <= offset && offset <= state->end)
180 return &tree->last->rb_node;
181 }
182 while(n) { 175 while(n) {
183 entry = rb_entry(n, struct tree_entry, rb_node); 176 entry = rb_entry(n, struct tree_entry, rb_node);
184 prev = n; 177 prev = n;
@@ -189,7 +182,6 @@ static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
189 else if (offset > entry->end) 182 else if (offset > entry->end)
190 n = n->rb_right; 183 n = n->rb_right;
191 else { 184 else {
192 tree->last = rb_entry(n, struct extent_state, rb_node);
193 return n; 185 return n;
194 } 186 }
195 } 187 }
@@ -223,10 +215,6 @@ static inline struct rb_node *tree_search(struct extent_io_tree *tree,
223 215
224 ret = __etree_search(tree, offset, &prev, NULL); 216 ret = __etree_search(tree, offset, &prev, NULL);
225 if (!ret) { 217 if (!ret) {
226 if (prev) {
227 tree->last = rb_entry(prev, struct extent_state,
228 rb_node);
229 }
230 return prev; 218 return prev;
231 } 219 }
232 return ret; 220 return ret;
@@ -301,8 +289,6 @@ static int merge_state(struct extent_io_tree *tree,
301 other->state == state->state) { 289 other->state == state->state) {
302 state->start = other->start; 290 state->start = other->start;
303 other->tree = NULL; 291 other->tree = NULL;
304 if (tree->last == other)
305 tree->last = state;
306 rb_erase(&other->rb_node, &tree->state); 292 rb_erase(&other->rb_node, &tree->state);
307 free_extent_state(other); 293 free_extent_state(other);
308 } 294 }
@@ -314,8 +300,6 @@ static int merge_state(struct extent_io_tree *tree,
314 other->state == state->state) { 300 other->state == state->state) {
315 other->start = state->start; 301 other->start = state->start;
316 state->tree = NULL; 302 state->tree = NULL;
317 if (tree->last == state)
318 tree->last = other;
319 rb_erase(&state->rb_node, &tree->state); 303 rb_erase(&state->rb_node, &tree->state);
320 free_extent_state(state); 304 free_extent_state(state);
321 } 305 }
@@ -378,7 +362,6 @@ static int insert_state(struct extent_io_tree *tree,
378 return -EEXIST; 362 return -EEXIST;
379 } 363 }
380 state->tree = tree; 364 state->tree = tree;
381 tree->last = state;
382 merge_state(tree, state); 365 merge_state(tree, state);
383 return 0; 366 return 0;
384} 367}
@@ -444,9 +427,6 @@ static int clear_state_bit(struct extent_io_tree *tree,
444 if (delete || state->state == 0) { 427 if (delete || state->state == 0) {
445 if (state->tree) { 428 if (state->tree) {
446 clear_state_cb(tree, state, state->state); 429 clear_state_cb(tree, state, state->state);
447 if (tree->last == state) {
448 tree->last = extent_state_next(state);
449 }
450 rb_erase(&state->rb_node, &tree->state); 430 rb_erase(&state->rb_node, &tree->state);
451 state->tree = NULL; 431 state->tree = NULL;
452 free_extent_state(state); 432 free_extent_state(state);
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 6c03e6a19938..315cfceae312 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -60,7 +60,6 @@ struct extent_io_tree {
60 spinlock_t lock; 60 spinlock_t lock;
61 spinlock_t buffer_lock; 61 spinlock_t buffer_lock;
62 struct extent_io_ops *ops; 62 struct extent_io_ops *ops;
63 struct extent_state *last;
64}; 63};
65 64
66struct extent_state { 65struct extent_state {
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 71b1ac155355..8a502ee2f231 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -42,7 +42,6 @@ void extent_map_exit(void)
42void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask) 42void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
43{ 43{
44 tree->map.rb_node = NULL; 44 tree->map.rb_node = NULL;
45 tree->last = NULL;
46 spin_lock_init(&tree->lock); 45 spin_lock_init(&tree->lock);
47} 46}
48EXPORT_SYMBOL(extent_map_tree_init); 47EXPORT_SYMBOL(extent_map_tree_init);
@@ -239,7 +238,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
239 merge->in_tree = 0; 238 merge->in_tree = 0;
240 free_extent_map(merge); 239 free_extent_map(merge);
241 } 240 }
242 tree->last = em;
243out: 241out:
244 return ret; 242 return ret;
245} 243}
@@ -273,10 +271,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
273 u64 end = range_end(start, len); 271 u64 end = range_end(start, len);
274 272
275 BUG_ON(spin_trylock(&tree->lock)); 273 BUG_ON(spin_trylock(&tree->lock));
276 em = tree->last;
277 if (em && end > em->start && start < extent_map_end(em))
278 goto found;
279
280 rb_node = __tree_search(&tree->map, start, &prev, &next); 274 rb_node = __tree_search(&tree->map, start, &prev, &next);
281 if (!rb_node && prev) { 275 if (!rb_node && prev) {
282 em = rb_entry(prev, struct extent_map, rb_node); 276 em = rb_entry(prev, struct extent_map, rb_node);
@@ -305,7 +299,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
305 299
306found: 300found:
307 atomic_inc(&em->refs); 301 atomic_inc(&em->refs);
308 tree->last = em;
309out: 302out:
310 return em; 303 return em;
311} 304}
@@ -327,8 +320,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
327 BUG_ON(spin_trylock(&tree->lock)); 320 BUG_ON(spin_trylock(&tree->lock));
328 rb_erase(&em->rb_node, &tree->map); 321 rb_erase(&em->rb_node, &tree->map);
329 em->in_tree = 0; 322 em->in_tree = 0;
330 if (tree->last == em)
331 tree->last = NULL;
332 return ret; 323 return ret;
333} 324}
334EXPORT_SYMBOL(remove_extent_mapping); 325EXPORT_SYMBOL(remove_extent_mapping);
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index a3978ec27846..26ac6fe0b268 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -26,7 +26,6 @@ struct extent_map {
26 26
27struct extent_map_tree { 27struct extent_map_tree {
28 struct rb_root map; 28 struct rb_root map;
29 struct extent_map *last;
30 spinlock_t lock; 29 spinlock_t lock;
31}; 30};
32 31
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 591a30208acd..e5ffb66ad320 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -381,14 +381,13 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
381 break; 381 break;
382 } 382 }
383 if (test_bit(EXTENT_FLAG_PINNED, &em->flags)) { 383 if (test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
384 start = em->start + em->len; 384 printk(KERN_CRIT "inode %lu trying to drop pinned "
385 free_extent_map(em); 385 "extent start %llu end %llu, em [%llu %llu]\n",
386 spin_unlock(&em_tree->lock); 386 inode->i_ino,
387 if (start < end) { 387 (unsigned long long)start,
388 len = end - start + 1; 388 (unsigned long long)end,
389 continue; 389 (unsigned long long)em->start,
390 } 390 (unsigned long long)em->len);
391 break;
392 } 391 }
393 remove_extent_mapping(em_tree, em); 392 remove_extent_mapping(em_tree, em);
394 393
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 60852ada658e..3da12a4d913d 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -485,7 +485,7 @@ int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
485 fixup = kzalloc(sizeof(*fixup), GFP_NOFS); 485 fixup = kzalloc(sizeof(*fixup), GFP_NOFS);
486 if (!fixup) 486 if (!fixup)
487 return -EAGAIN; 487 return -EAGAIN;
488printk("queueing worker to fixup page %lu %Lu\n", inode->i_ino, page_offset(page)); 488
489 SetPageChecked(page); 489 SetPageChecked(page);
490 page_cache_get(page); 490 page_cache_get(page);
491 fixup->work.func = btrfs_writepage_fixup_worker; 491 fixup->work.func = btrfs_writepage_fixup_worker;
@@ -502,11 +502,13 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
502 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 502 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
503 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; 503 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
504 struct extent_map *em; 504 struct extent_map *em;
505 struct extent_map *em_orig;
505 u64 alloc_hint = 0; 506 u64 alloc_hint = 0;
506 u64 clear_start; 507 u64 clear_start;
507 u64 clear_end; 508 u64 clear_end;
508 struct list_head list; 509 struct list_head list;
509 struct btrfs_key ins; 510 struct btrfs_key ins;
511 struct rb_node *rb;
510 int ret; 512 int ret;
511 513
512 ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1); 514 ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1);
@@ -535,6 +537,22 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
535 537
536 mutex_lock(&BTRFS_I(inode)->extent_mutex); 538 mutex_lock(&BTRFS_I(inode)->extent_mutex);
537 539
540 spin_lock(&em_tree->lock);
541 clear_start = ordered_extent->file_offset;
542 clear_end = ordered_extent->file_offset + ordered_extent->len;
543 em = lookup_extent_mapping(em_tree, clear_start,
544 ordered_extent->len);
545 em_orig = em;
546 while(em && clear_start < extent_map_end(em) && clear_end > em->start) {
547 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
548 rb = rb_next(&em->rb_node);
549 if (!rb)
550 break;
551 em = rb_entry(rb, struct extent_map, rb_node);
552 }
553 free_extent_map(em_orig);
554 spin_unlock(&em_tree->lock);
555
538 ret = btrfs_drop_extents(trans, root, inode, 556 ret = btrfs_drop_extents(trans, root, inode,
539 ordered_extent->file_offset, 557 ordered_extent->file_offset,
540 ordered_extent->file_offset + 558 ordered_extent->file_offset +
@@ -548,22 +566,6 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
548 ordered_extent->len, 0); 566 ordered_extent->len, 0);
549 BUG_ON(ret); 567 BUG_ON(ret);
550 568
551 spin_lock(&em_tree->lock);
552 clear_start = ordered_extent->file_offset;
553 clear_end = ordered_extent->file_offset + ordered_extent->len;
554 while(clear_start < clear_end) {
555 em = lookup_extent_mapping(em_tree, clear_start,
556 clear_end - clear_start);
557 if (em) {
558 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
559 clear_start = em->start + em->len;
560 free_extent_map(em);
561 } else {
562 break;
563 }
564 }
565 spin_unlock(&em_tree->lock);
566
567 btrfs_drop_extent_cache(inode, ordered_extent->file_offset, 569 btrfs_drop_extent_cache(inode, ordered_extent->file_offset,
568 ordered_extent->file_offset + 570 ordered_extent->file_offset +
569 ordered_extent->len - 1); 571 ordered_extent->len - 1);
@@ -2318,7 +2320,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
2318 u64 extent_end = 0; 2320 u64 extent_end = 0;
2319 u64 objectid = inode->i_ino; 2321 u64 objectid = inode->i_ino;
2320 u32 found_type; 2322 u32 found_type;
2321 struct btrfs_path *path; 2323 struct btrfs_path *path = NULL;
2322 struct btrfs_root *root = BTRFS_I(inode)->root; 2324 struct btrfs_root *root = BTRFS_I(inode)->root;
2323 struct btrfs_file_extent_item *item; 2325 struct btrfs_file_extent_item *item;
2324 struct extent_buffer *leaf; 2326 struct extent_buffer *leaf;
@@ -2328,9 +2330,6 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
2328 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 2330 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
2329 struct btrfs_trans_handle *trans = NULL; 2331 struct btrfs_trans_handle *trans = NULL;
2330 2332
2331 path = btrfs_alloc_path();
2332 BUG_ON(!path);
2333
2334again: 2333again:
2335 spin_lock(&em_tree->lock); 2334 spin_lock(&em_tree->lock);
2336 em = lookup_extent_mapping(em_tree, start, len); 2335 em = lookup_extent_mapping(em_tree, start, len);
@@ -2354,6 +2353,12 @@ again:
2354 em->bdev = root->fs_info->fs_devices->latest_bdev; 2353 em->bdev = root->fs_info->fs_devices->latest_bdev;
2355 em->start = EXTENT_MAP_HOLE; 2354 em->start = EXTENT_MAP_HOLE;
2356 em->len = (u64)-1; 2355 em->len = (u64)-1;
2356
2357 if (!path) {
2358 path = btrfs_alloc_path();
2359 BUG_ON(!path);
2360 }
2361
2357 ret = btrfs_lookup_file_extent(trans, root, path, 2362 ret = btrfs_lookup_file_extent(trans, root, path,
2358 objectid, start, trans != NULL); 2363 objectid, start, trans != NULL);
2359 if (ret < 0) { 2364 if (ret < 0) {
@@ -2530,7 +2535,8 @@ insert:
2530 } 2535 }
2531 spin_unlock(&em_tree->lock); 2536 spin_unlock(&em_tree->lock);
2532out: 2537out:
2533 btrfs_free_path(path); 2538 if (path)
2539 btrfs_free_path(path);
2534 if (trans) { 2540 if (trans) {
2535 ret = btrfs_end_transaction(trans, root); 2541 ret = btrfs_end_transaction(trans, root);
2536 if (!err) { 2542 if (!err) {
@@ -2643,8 +2649,8 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
2643 return extent_write_full_page(tree, page, btrfs_get_extent, wbc); 2649 return extent_write_full_page(tree, page, btrfs_get_extent, wbc);
2644} 2650}
2645 2651
2646static int btrfs_writepages(struct address_space *mapping, 2652int btrfs_writepages(struct address_space *mapping,
2647 struct writeback_control *wbc) 2653 struct writeback_control *wbc)
2648{ 2654{
2649 struct extent_io_tree *tree; 2655 struct extent_io_tree *tree;
2650 tree = &BTRFS_I(mapping->host)->io_tree; 2656 tree = &BTRFS_I(mapping->host)->io_tree;
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 0d87795fdd8f..830dbaea6853 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -19,6 +19,8 @@
19#include <linux/gfp.h> 19#include <linux/gfp.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/blkdev.h> 21#include <linux/blkdev.h>
22#include <linux/writeback.h>
23#include <linux/pagevec.h>
22#include "ctree.h" 24#include "ctree.h"
23#include "transaction.h" 25#include "transaction.h"
24#include "btrfs_inode.h" 26#include "btrfs_inode.h"
@@ -307,12 +309,7 @@ void btrfs_start_ordered_extent(struct inode *inode,
307 * start IO on any dirty ones so the wait doesn't stall waiting 309 * start IO on any dirty ones so the wait doesn't stall waiting
308 * for pdflush to find them 310 * for pdflush to find them
309 */ 311 */
310#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) 312 btrfs_fdatawrite_range(inode->i_mapping, start, end, WB_SYNC_NONE);
311 do_sync_file_range(file, start, end, SYNC_FILE_RANGE_WRITE);
312#else
313 do_sync_mapping_range(inode->i_mapping, start, end,
314 SYNC_FILE_RANGE_WRITE);
315#endif
316 if (wait) 313 if (wait)
317 wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE, 314 wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE,
318 &entry->flags)); 315 &entry->flags));
@@ -327,28 +324,26 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
327 u64 orig_end; 324 u64 orig_end;
328 u64 wait_end; 325 u64 wait_end;
329 struct btrfs_ordered_extent *ordered; 326 struct btrfs_ordered_extent *ordered;
330 u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
331 327
332 if (start + len < start) { 328 if (start + len < start) {
333 wait_end = (inode->i_size + mask) & ~mask; 329 orig_end = INT_LIMIT(loff_t);
334 orig_end = (u64)-1;
335 } else { 330 } else {
336 orig_end = start + len - 1; 331 orig_end = start + len - 1;
337 wait_end = orig_end; 332 if (orig_end > INT_LIMIT(loff_t))
333 orig_end = INT_LIMIT(loff_t);
338 } 334 }
335 wait_end = orig_end;
339again: 336again:
340 /* start IO across the range first to instantiate any delalloc 337 /* start IO across the range first to instantiate any delalloc
341 * extents 338 * extents
342 */ 339 */
343#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) 340 btrfs_fdatawrite_range(inode->i_mapping, start, orig_end, WB_SYNC_NONE);
344 do_sync_file_range(file, start, wait_end, SYNC_FILE_RANGE_WRITE); 341
345#else 342 btrfs_wait_on_page_writeback_range(inode->i_mapping,
346 do_sync_mapping_range(inode->i_mapping, start, wait_end, 343 start >> PAGE_CACHE_SHIFT,
347 SYNC_FILE_RANGE_WRITE); 344 orig_end >> PAGE_CACHE_SHIFT);
348#endif
349 end = orig_end;
350 wait_on_extent_writeback(&BTRFS_I(inode)->io_tree, start, orig_end);
351 345
346 end = orig_end;
352 while(1) { 347 while(1) {
353 ordered = btrfs_lookup_first_ordered_extent(inode, end); 348 ordered = btrfs_lookup_first_ordered_extent(inode, end);
354 if (!ordered) { 349 if (!ordered) {
@@ -565,3 +560,87 @@ out:
565 return ret; 560 return ret;
566} 561}
567 562
563
564/**
565 * taken from mm/filemap.c because it isn't exported
566 *
567 * __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
568 * @mapping: address space structure to write
569 * @start: offset in bytes where the range starts
570 * @end: offset in bytes where the range ends (inclusive)
571 * @sync_mode: enable synchronous operation
572 *
573 * Start writeback against all of a mapping's dirty pages that lie
574 * within the byte offsets <start, end> inclusive.
575 *
576 * If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as
577 * opposed to a regular memory cleansing writeback. The difference between
578 * these two operations is that if a dirty page/buffer is encountered, it must
579 * be waited upon, and not just skipped over.
580 */
581int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
582 loff_t end, int sync_mode)
583{
584 struct writeback_control wbc = {
585 .sync_mode = sync_mode,
586 .nr_to_write = mapping->nrpages * 2,
587 .range_start = start,
588 .range_end = end,
589 .for_writepages = 1,
590 };
591 return btrfs_writepages(mapping, &wbc);
592}
593
594/**
595 * taken from mm/filemap.c because it isn't exported
596 *
597 * wait_on_page_writeback_range - wait for writeback to complete
598 * @mapping: target address_space
599 * @start: beginning page index
600 * @end: ending page index
601 *
602 * Wait for writeback to complete against pages indexed by start->end
603 * inclusive
604 */
605int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
606 pgoff_t start, pgoff_t end)
607{
608 struct pagevec pvec;
609 int nr_pages;
610 int ret = 0;
611 pgoff_t index;
612
613 if (end < start)
614 return 0;
615
616 pagevec_init(&pvec, 0);
617 index = start;
618 while ((index <= end) &&
619 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
620 PAGECACHE_TAG_WRITEBACK,
621 min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) {
622 unsigned i;
623
624 for (i = 0; i < nr_pages; i++) {
625 struct page *page = pvec.pages[i];
626
627 /* until radix tree lookup accepts end_index */
628 if (page->index > end)
629 continue;
630
631 wait_on_page_writeback(page);
632 if (PageError(page))
633 ret = -EIO;
634 }
635 pagevec_release(&pvec);
636 cond_resched();
637 }
638
639 /* Check for outstanding write errors */
640 if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
641 ret = -ENOSPC;
642 if (test_and_clear_bit(AS_EIO, &mapping->flags))
643 ret = -EIO;
644
645 return ret;
646}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 1794efd13ca3..8e8e3c0404f3 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -132,4 +132,8 @@ btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
132int btrfs_ordered_update_i_size(struct inode *inode, 132int btrfs_ordered_update_i_size(struct inode *inode,
133 struct btrfs_ordered_extent *ordered); 133 struct btrfs_ordered_extent *ordered);
134int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum); 134int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum);
135int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
136 pgoff_t start, pgoff_t end);
137int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
138 loff_t end, int sync_mode);
135#endif 139#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 05823904ecba..38c75a0256cb 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -649,7 +649,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
649 extent_io_tree_init(pinned_copy, 649 extent_io_tree_init(pinned_copy,
650 root->fs_info->btree_inode->i_mapping, GFP_NOFS); 650 root->fs_info->btree_inode->i_mapping, GFP_NOFS);
651 651
652printk("commit trans %Lu\n", trans->transid);
653 trans->transaction->in_commit = 1; 652 trans->transaction->in_commit = 1;
654 trans->transaction->blocked = 1; 653 trans->transaction->blocked = 1;
655 cur_trans = trans->transaction; 654 cur_trans = trans->transaction;
@@ -745,7 +744,6 @@ printk("commit trans %Lu\n", trans->transid);
745 list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots); 744 list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
746 745
747 mutex_unlock(&root->fs_info->trans_mutex); 746 mutex_unlock(&root->fs_info->trans_mutex);
748printk("done commit trans %Lu\n", trans->transid);
749 kmem_cache_free(btrfs_trans_handle_cachep, trans); 747 kmem_cache_free(btrfs_trans_handle_cachep, trans);
750 748
751 if (root->fs_info->closing) { 749 if (root->fs_info->closing) {