diff options
Diffstat (limited to 'fs/btrfs/ordered-data.c')
| -rw-r--r-- | fs/btrfs/ordered-data.c | 87 |
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 | ||
| 127 | static 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 | */ |
| 165 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | 173 | static 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 | ||
| 219 | int 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 | |||
| 226 | int 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 | */ | ||
| 615 | struct 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 | } | ||
| 646 | out: | ||
| 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 |
