diff options
Diffstat (limited to 'fs/btrfs/ordered-data.c')
| -rw-r--r-- | fs/btrfs/ordered-data.c | 128 |
1 files changed, 98 insertions, 30 deletions
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 5c2a9e78a949..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; |
| @@ -174,7 +183,6 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
| 174 | if (!entry) | 183 | if (!entry) |
| 175 | return -ENOMEM; | 184 | return -ENOMEM; |
| 176 | 185 | ||
| 177 | mutex_lock(&tree->mutex); | ||
| 178 | entry->file_offset = file_offset; | 186 | entry->file_offset = file_offset; |
| 179 | entry->start = start; | 187 | entry->start = start; |
| 180 | entry->len = len; | 188 | entry->len = len; |
| @@ -184,26 +192,44 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
| 184 | if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) | 192 | if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) |
| 185 | set_bit(type, &entry->flags); | 193 | set_bit(type, &entry->flags); |
| 186 | 194 | ||
| 195 | if (dio) | ||
| 196 | set_bit(BTRFS_ORDERED_DIRECT, &entry->flags); | ||
| 197 | |||
| 187 | /* one ref for the tree */ | 198 | /* one ref for the tree */ |
| 188 | atomic_set(&entry->refs, 1); | 199 | atomic_set(&entry->refs, 1); |
| 189 | init_waitqueue_head(&entry->wait); | 200 | init_waitqueue_head(&entry->wait); |
| 190 | INIT_LIST_HEAD(&entry->list); | 201 | INIT_LIST_HEAD(&entry->list); |
| 191 | INIT_LIST_HEAD(&entry->root_extent_list); | 202 | INIT_LIST_HEAD(&entry->root_extent_list); |
| 192 | 203 | ||
| 204 | spin_lock(&tree->lock); | ||
| 193 | node = tree_insert(&tree->tree, file_offset, | 205 | node = tree_insert(&tree->tree, file_offset, |
| 194 | &entry->rb_node); | 206 | &entry->rb_node); |
| 195 | BUG_ON(node); | 207 | BUG_ON(node); |
| 208 | spin_unlock(&tree->lock); | ||
| 196 | 209 | ||
| 197 | spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); | 210 | spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); |
| 198 | list_add_tail(&entry->root_extent_list, | 211 | list_add_tail(&entry->root_extent_list, |
| 199 | &BTRFS_I(inode)->root->fs_info->ordered_extents); | 212 | &BTRFS_I(inode)->root->fs_info->ordered_extents); |
| 200 | spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); | 213 | spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); |
| 201 | 214 | ||
| 202 | mutex_unlock(&tree->mutex); | ||
| 203 | BUG_ON(node); | 215 | BUG_ON(node); |
| 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 |
| @@ -216,9 +242,9 @@ int btrfs_add_ordered_sum(struct inode *inode, | |||
| 216 | struct btrfs_ordered_inode_tree *tree; | 242 | struct btrfs_ordered_inode_tree *tree; |
| 217 | 243 | ||
| 218 | tree = &BTRFS_I(inode)->ordered_tree; | 244 | tree = &BTRFS_I(inode)->ordered_tree; |
| 219 | mutex_lock(&tree->mutex); | 245 | spin_lock(&tree->lock); |
| 220 | list_add_tail(&sum->list, &entry->list); | 246 | list_add_tail(&sum->list, &entry->list); |
| 221 | mutex_unlock(&tree->mutex); | 247 | spin_unlock(&tree->lock); |
| 222 | return 0; | 248 | return 0; |
| 223 | } | 249 | } |
| 224 | 250 | ||
| @@ -232,15 +258,16 @@ int btrfs_add_ordered_sum(struct inode *inode, | |||
| 232 | * to make sure this function only returns 1 once for a given ordered extent. | 258 | * to make sure this function only returns 1 once for a given ordered extent. |
| 233 | */ | 259 | */ |
| 234 | int btrfs_dec_test_ordered_pending(struct inode *inode, | 260 | int btrfs_dec_test_ordered_pending(struct inode *inode, |
| 261 | struct btrfs_ordered_extent **cached, | ||
| 235 | u64 file_offset, u64 io_size) | 262 | u64 file_offset, u64 io_size) |
| 236 | { | 263 | { |
| 237 | struct btrfs_ordered_inode_tree *tree; | 264 | struct btrfs_ordered_inode_tree *tree; |
| 238 | struct rb_node *node; | 265 | struct rb_node *node; |
| 239 | struct btrfs_ordered_extent *entry; | 266 | struct btrfs_ordered_extent *entry = NULL; |
| 240 | int ret; | 267 | int ret; |
| 241 | 268 | ||
| 242 | tree = &BTRFS_I(inode)->ordered_tree; | 269 | tree = &BTRFS_I(inode)->ordered_tree; |
| 243 | mutex_lock(&tree->mutex); | 270 | spin_lock(&tree->lock); |
| 244 | node = tree_search(tree, file_offset); | 271 | node = tree_search(tree, file_offset); |
| 245 | if (!node) { | 272 | if (!node) { |
| 246 | ret = 1; | 273 | ret = 1; |
| @@ -264,7 +291,11 @@ int btrfs_dec_test_ordered_pending(struct inode *inode, | |||
| 264 | else | 291 | else |
| 265 | ret = 1; | 292 | ret = 1; |
| 266 | out: | 293 | out: |
| 267 | mutex_unlock(&tree->mutex); | 294 | if (!ret && cached && entry) { |
| 295 | *cached = entry; | ||
| 296 | atomic_inc(&entry->refs); | ||
| 297 | } | ||
| 298 | spin_unlock(&tree->lock); | ||
| 268 | return ret == 0; | 299 | return ret == 0; |
| 269 | } | 300 | } |
| 270 | 301 | ||
| @@ -291,13 +322,14 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry) | |||
| 291 | 322 | ||
| 292 | /* | 323 | /* |
| 293 | * remove an ordered extent from the tree. No references are dropped | 324 | * remove an ordered extent from the tree. No references are dropped |
| 294 | * and you must wake_up entry->wait. You must hold the tree mutex | 325 | * and you must wake_up entry->wait. You must hold the tree lock |
| 295 | * while you call this function. | 326 | * while you call this function. |
| 296 | */ | 327 | */ |
| 297 | static int __btrfs_remove_ordered_extent(struct inode *inode, | 328 | static int __btrfs_remove_ordered_extent(struct inode *inode, |
| 298 | struct btrfs_ordered_extent *entry) | 329 | struct btrfs_ordered_extent *entry) |
| 299 | { | 330 | { |
| 300 | struct btrfs_ordered_inode_tree *tree; | 331 | struct btrfs_ordered_inode_tree *tree; |
| 332 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
| 301 | struct rb_node *node; | 333 | struct rb_node *node; |
| 302 | 334 | ||
| 303 | tree = &BTRFS_I(inode)->ordered_tree; | 335 | tree = &BTRFS_I(inode)->ordered_tree; |
| @@ -306,13 +338,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, | |||
| 306 | tree->last = NULL; | 338 | tree->last = NULL; |
| 307 | set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags); | 339 | set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags); |
| 308 | 340 | ||
| 309 | spin_lock(&BTRFS_I(inode)->accounting_lock); | 341 | spin_lock(&root->fs_info->ordered_extent_lock); |
| 310 | BTRFS_I(inode)->outstanding_extents--; | ||
| 311 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | ||
| 312 | btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root, | ||
| 313 | inode, 1); | ||
| 314 | |||
| 315 | spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); | ||
| 316 | list_del_init(&entry->root_extent_list); | 342 | list_del_init(&entry->root_extent_list); |
| 317 | 343 | ||
| 318 | /* | 344 | /* |
| @@ -324,7 +350,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, | |||
| 324 | !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) { | 350 | !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) { |
| 325 | list_del_init(&BTRFS_I(inode)->ordered_operations); | 351 | list_del_init(&BTRFS_I(inode)->ordered_operations); |
| 326 | } | 352 | } |
| 327 | spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); | 353 | spin_unlock(&root->fs_info->ordered_extent_lock); |
| 328 | 354 | ||
| 329 | return 0; | 355 | return 0; |
| 330 | } | 356 | } |
| @@ -340,9 +366,9 @@ int btrfs_remove_ordered_extent(struct inode *inode, | |||
| 340 | int ret; | 366 | int ret; |
| 341 | 367 | ||
| 342 | tree = &BTRFS_I(inode)->ordered_tree; | 368 | tree = &BTRFS_I(inode)->ordered_tree; |
| 343 | mutex_lock(&tree->mutex); | 369 | spin_lock(&tree->lock); |
| 344 | ret = __btrfs_remove_ordered_extent(inode, entry); | 370 | ret = __btrfs_remove_ordered_extent(inode, entry); |
| 345 | mutex_unlock(&tree->mutex); | 371 | spin_unlock(&tree->lock); |
| 346 | wake_up(&entry->wait); | 372 | wake_up(&entry->wait); |
| 347 | 373 | ||
| 348 | return ret; | 374 | return ret; |
| @@ -485,7 +511,8 @@ void btrfs_start_ordered_extent(struct inode *inode, | |||
| 485 | * 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 |
| 486 | * for pdflush to find them | 512 | * for pdflush to find them |
| 487 | */ | 513 | */ |
| 488 | 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); | ||
| 489 | if (wait) { | 516 | if (wait) { |
| 490 | wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE, | 517 | wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE, |
| 491 | &entry->flags)); | 518 | &entry->flags)); |
| @@ -567,7 +594,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, | |||
| 567 | struct btrfs_ordered_extent *entry = NULL; | 594 | struct btrfs_ordered_extent *entry = NULL; |
| 568 | 595 | ||
| 569 | tree = &BTRFS_I(inode)->ordered_tree; | 596 | tree = &BTRFS_I(inode)->ordered_tree; |
| 570 | mutex_lock(&tree->mutex); | 597 | spin_lock(&tree->lock); |
| 571 | node = tree_search(tree, file_offset); | 598 | node = tree_search(tree, file_offset); |
| 572 | if (!node) | 599 | if (!node) |
| 573 | goto out; | 600 | goto out; |
| @@ -578,7 +605,48 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, | |||
| 578 | if (entry) | 605 | if (entry) |
| 579 | atomic_inc(&entry->refs); | 606 | atomic_inc(&entry->refs); |
| 580 | out: | 607 | out: |
| 581 | mutex_unlock(&tree->mutex); | 608 | spin_unlock(&tree->lock); |
| 609 | return entry; | ||
| 610 | } | ||
| 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); | ||
| 582 | return entry; | 650 | return entry; |
| 583 | } | 651 | } |
| 584 | 652 | ||
| @@ -594,7 +662,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset) | |||
| 594 | struct btrfs_ordered_extent *entry = NULL; | 662 | struct btrfs_ordered_extent *entry = NULL; |
| 595 | 663 | ||
| 596 | tree = &BTRFS_I(inode)->ordered_tree; | 664 | tree = &BTRFS_I(inode)->ordered_tree; |
| 597 | mutex_lock(&tree->mutex); | 665 | spin_lock(&tree->lock); |
| 598 | node = tree_search(tree, file_offset); | 666 | node = tree_search(tree, file_offset); |
| 599 | if (!node) | 667 | if (!node) |
| 600 | goto out; | 668 | goto out; |
| @@ -602,7 +670,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset) | |||
| 602 | entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); | 670 | entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); |
| 603 | atomic_inc(&entry->refs); | 671 | atomic_inc(&entry->refs); |
| 604 | out: | 672 | out: |
| 605 | mutex_unlock(&tree->mutex); | 673 | spin_unlock(&tree->lock); |
| 606 | return entry; | 674 | return entry; |
| 607 | } | 675 | } |
| 608 | 676 | ||
| @@ -629,7 +697,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, | |||
| 629 | else | 697 | else |
| 630 | offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize); | 698 | offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize); |
| 631 | 699 | ||
| 632 | mutex_lock(&tree->mutex); | 700 | spin_lock(&tree->lock); |
| 633 | disk_i_size = BTRFS_I(inode)->disk_i_size; | 701 | disk_i_size = BTRFS_I(inode)->disk_i_size; |
| 634 | 702 | ||
| 635 | /* truncate file */ | 703 | /* truncate file */ |
| @@ -735,7 +803,7 @@ out: | |||
| 735 | */ | 803 | */ |
| 736 | if (ordered) | 804 | if (ordered) |
| 737 | __btrfs_remove_ordered_extent(inode, ordered); | 805 | __btrfs_remove_ordered_extent(inode, ordered); |
| 738 | mutex_unlock(&tree->mutex); | 806 | spin_unlock(&tree->lock); |
| 739 | if (ordered) | 807 | if (ordered) |
| 740 | wake_up(&ordered->wait); | 808 | wake_up(&ordered->wait); |
| 741 | return ret; | 809 | return ret; |
| @@ -762,7 +830,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, | |||
| 762 | if (!ordered) | 830 | if (!ordered) |
| 763 | return 1; | 831 | return 1; |
| 764 | 832 | ||
| 765 | mutex_lock(&tree->mutex); | 833 | spin_lock(&tree->lock); |
| 766 | list_for_each_entry_reverse(ordered_sum, &ordered->list, list) { | 834 | list_for_each_entry_reverse(ordered_sum, &ordered->list, list) { |
| 767 | if (disk_bytenr >= ordered_sum->bytenr) { | 835 | if (disk_bytenr >= ordered_sum->bytenr) { |
| 768 | num_sectors = ordered_sum->len / sectorsize; | 836 | num_sectors = ordered_sum->len / sectorsize; |
| @@ -777,7 +845,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, | |||
| 777 | } | 845 | } |
| 778 | } | 846 | } |
| 779 | out: | 847 | out: |
| 780 | mutex_unlock(&tree->mutex); | 848 | spin_unlock(&tree->lock); |
| 781 | btrfs_put_ordered_extent(ordered); | 849 | btrfs_put_ordered_extent(ordered); |
| 782 | return ret; | 850 | return ret; |
| 783 | } | 851 | } |
