aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ordered-data.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ordered-data.c')
-rw-r--r--fs/btrfs/ordered-data.c87
1 files changed, 75 insertions, 12 deletions
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index a8ffecd0b491..e56c72bc5add 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -16,7 +16,6 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#include <linux/gfp.h>
20#include <linux/slab.h> 19#include <linux/slab.h>
21#include <linux/blkdev.h> 20#include <linux/blkdev.h>
22#include <linux/writeback.h> 21#include <linux/writeback.h>
@@ -125,6 +124,15 @@ static int offset_in_entry(struct btrfs_ordered_extent *entry, u64 file_offset)
125 return 1; 124 return 1;
126} 125}
127 126
127static int range_overlaps(struct btrfs_ordered_extent *entry, u64 file_offset,
128 u64 len)
129{
130 if (file_offset + len <= entry->file_offset ||
131 entry->file_offset + entry->len <= file_offset)
132 return 0;
133 return 1;
134}
135
128/* 136/*
129 * look find the first ordered struct that has this offset, otherwise 137 * look find the first ordered struct that has this offset, otherwise
130 * the first one less than this offset 138 * the first one less than this offset
@@ -162,8 +170,9 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
162 * The tree is given a single reference on the ordered extent that was 170 * The tree is given a single reference on the ordered extent that was
163 * inserted. 171 * inserted.
164 */ 172 */
165int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, 173static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
166 u64 start, u64 len, u64 disk_len, int type) 174 u64 start, u64 len, u64 disk_len,
175 int type, int dio)
167{ 176{
168 struct btrfs_ordered_inode_tree *tree; 177 struct btrfs_ordered_inode_tree *tree;
169 struct rb_node *node; 178 struct rb_node *node;
@@ -183,6 +192,9 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
183 if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) 192 if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
184 set_bit(type, &entry->flags); 193 set_bit(type, &entry->flags);
185 194
195 if (dio)
196 set_bit(BTRFS_ORDERED_DIRECT, &entry->flags);
197
186 /* one ref for the tree */ 198 /* one ref for the tree */
187 atomic_set(&entry->refs, 1); 199 atomic_set(&entry->refs, 1);
188 init_waitqueue_head(&entry->wait); 200 init_waitqueue_head(&entry->wait);
@@ -204,6 +216,20 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
204 return 0; 216 return 0;
205} 217}
206 218
219int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
220 u64 start, u64 len, u64 disk_len, int type)
221{
222 return __btrfs_add_ordered_extent(inode, file_offset, start, len,
223 disk_len, type, 0);
224}
225
226int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
227 u64 start, u64 len, u64 disk_len, int type)
228{
229 return __btrfs_add_ordered_extent(inode, file_offset, start, len,
230 disk_len, type, 1);
231}
232
207/* 233/*
208 * Add a struct btrfs_ordered_sum into the list of checksums to be inserted 234 * Add a struct btrfs_ordered_sum into the list of checksums to be inserted
209 * when an ordered extent is finished. If the list covers more than one 235 * when an ordered extent is finished. If the list covers more than one
@@ -303,6 +329,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode,
303 struct btrfs_ordered_extent *entry) 329 struct btrfs_ordered_extent *entry)
304{ 330{
305 struct btrfs_ordered_inode_tree *tree; 331 struct btrfs_ordered_inode_tree *tree;
332 struct btrfs_root *root = BTRFS_I(inode)->root;
306 struct rb_node *node; 333 struct rb_node *node;
307 334
308 tree = &BTRFS_I(inode)->ordered_tree; 335 tree = &BTRFS_I(inode)->ordered_tree;
@@ -311,13 +338,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode,
311 tree->last = NULL; 338 tree->last = NULL;
312 set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags); 339 set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
313 340
314 spin_lock(&BTRFS_I(inode)->accounting_lock); 341 spin_lock(&root->fs_info->ordered_extent_lock);
315 BTRFS_I(inode)->outstanding_extents--;
316 spin_unlock(&BTRFS_I(inode)->accounting_lock);
317 btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root,
318 inode, 1);
319
320 spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
321 list_del_init(&entry->root_extent_list); 342 list_del_init(&entry->root_extent_list);
322 343
323 /* 344 /*
@@ -329,7 +350,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode,
329 !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) { 350 !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
330 list_del_init(&BTRFS_I(inode)->ordered_operations); 351 list_del_init(&BTRFS_I(inode)->ordered_operations);
331 } 352 }
332 spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); 353 spin_unlock(&root->fs_info->ordered_extent_lock);
333 354
334 return 0; 355 return 0;
335} 356}
@@ -490,7 +511,8 @@ void btrfs_start_ordered_extent(struct inode *inode,
490 * start IO on any dirty ones so the wait doesn't stall waiting 511 * start IO on any dirty ones so the wait doesn't stall waiting
491 * for pdflush to find them 512 * for pdflush to find them
492 */ 513 */
493 filemap_fdatawrite_range(inode->i_mapping, start, end); 514 if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags))
515 filemap_fdatawrite_range(inode->i_mapping, start, end);
494 if (wait) { 516 if (wait) {
495 wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE, 517 wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE,
496 &entry->flags)); 518 &entry->flags));
@@ -587,6 +609,47 @@ out:
587 return entry; 609 return entry;
588} 610}
589 611
612/* Since the DIO code tries to lock a wide area we need to look for any ordered
613 * extents that exist in the range, rather than just the start of the range.
614 */
615struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
616 u64 file_offset,
617 u64 len)
618{
619 struct btrfs_ordered_inode_tree *tree;
620 struct rb_node *node;
621 struct btrfs_ordered_extent *entry = NULL;
622
623 tree = &BTRFS_I(inode)->ordered_tree;
624 spin_lock(&tree->lock);
625 node = tree_search(tree, file_offset);
626 if (!node) {
627 node = tree_search(tree, file_offset + len);
628 if (!node)
629 goto out;
630 }
631
632 while (1) {
633 entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
634 if (range_overlaps(entry, file_offset, len))
635 break;
636
637 if (entry->file_offset >= file_offset + len) {
638 entry = NULL;
639 break;
640 }
641 entry = NULL;
642 node = rb_next(node);
643 if (!node)
644 break;
645 }
646out:
647 if (entry)
648 atomic_inc(&entry->refs);
649 spin_unlock(&tree->lock);
650 return entry;
651}
652
590/* 653/*
591 * lookup and return any extent before 'file_offset'. NULL is returned 654 * lookup and return any extent before 'file_offset'. NULL is returned
592 * if none is found 655 * if none is found