diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 4 | ||||
-rw-r--r-- | fs/btrfs/file.c | 30 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 8 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 68 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.h | 11 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 132 |
7 files changed, 247 insertions, 9 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 547b7b05727f..411c8d97074e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1623,6 +1623,9 @@ struct btrfs_root { | |||
1623 | 1623 | ||
1624 | struct list_head root_list; | 1624 | struct list_head root_list; |
1625 | 1625 | ||
1626 | spinlock_t log_extents_lock[2]; | ||
1627 | struct list_head logged_list[2]; | ||
1628 | |||
1626 | spinlock_t orphan_lock; | 1629 | spinlock_t orphan_lock; |
1627 | atomic_t orphan_inodes; | 1630 | atomic_t orphan_inodes; |
1628 | struct btrfs_block_rsv *orphan_block_rsv; | 1631 | struct btrfs_block_rsv *orphan_block_rsv; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a762f9137610..1db8a9938829 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1178,9 +1178,13 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
1178 | 1178 | ||
1179 | INIT_LIST_HEAD(&root->dirty_list); | 1179 | INIT_LIST_HEAD(&root->dirty_list); |
1180 | INIT_LIST_HEAD(&root->root_list); | 1180 | INIT_LIST_HEAD(&root->root_list); |
1181 | INIT_LIST_HEAD(&root->logged_list[0]); | ||
1182 | INIT_LIST_HEAD(&root->logged_list[1]); | ||
1181 | spin_lock_init(&root->orphan_lock); | 1183 | spin_lock_init(&root->orphan_lock); |
1182 | spin_lock_init(&root->inode_lock); | 1184 | spin_lock_init(&root->inode_lock); |
1183 | spin_lock_init(&root->accounting_lock); | 1185 | spin_lock_init(&root->accounting_lock); |
1186 | spin_lock_init(&root->log_extents_lock[0]); | ||
1187 | spin_lock_init(&root->log_extents_lock[1]); | ||
1184 | mutex_init(&root->objectid_mutex); | 1188 | mutex_init(&root->objectid_mutex); |
1185 | mutex_init(&root->log_mutex); | 1189 | mutex_init(&root->log_mutex); |
1186 | init_waitqueue_head(&root->log_writer_wait); | 1190 | init_waitqueue_head(&root->log_writer_wait); |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index b06d289f998f..083abca56055 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1655,16 +1655,21 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
1655 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1655 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1656 | int ret = 0; | 1656 | int ret = 0; |
1657 | struct btrfs_trans_handle *trans; | 1657 | struct btrfs_trans_handle *trans; |
1658 | bool full_sync = 0; | ||
1658 | 1659 | ||
1659 | trace_btrfs_sync_file(file, datasync); | 1660 | trace_btrfs_sync_file(file, datasync); |
1660 | 1661 | ||
1661 | /* | 1662 | /* |
1662 | * We write the dirty pages in the range and wait until they complete | 1663 | * We write the dirty pages in the range and wait until they complete |
1663 | * out of the ->i_mutex. If so, we can flush the dirty pages by | 1664 | * out of the ->i_mutex. If so, we can flush the dirty pages by |
1664 | * multi-task, and make the performance up. | 1665 | * multi-task, and make the performance up. See |
1666 | * btrfs_wait_ordered_range for an explanation of the ASYNC check. | ||
1665 | */ | 1667 | */ |
1666 | atomic_inc(&BTRFS_I(inode)->sync_writers); | 1668 | atomic_inc(&BTRFS_I(inode)->sync_writers); |
1667 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | 1669 | ret = filemap_fdatawrite_range(inode->i_mapping, start, end); |
1670 | if (!ret && test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, | ||
1671 | &BTRFS_I(inode)->runtime_flags)) | ||
1672 | ret = filemap_fdatawrite_range(inode->i_mapping, start, end); | ||
1668 | atomic_dec(&BTRFS_I(inode)->sync_writers); | 1673 | atomic_dec(&BTRFS_I(inode)->sync_writers); |
1669 | if (ret) | 1674 | if (ret) |
1670 | return ret; | 1675 | return ret; |
@@ -1676,7 +1681,10 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
1676 | * range being left. | 1681 | * range being left. |
1677 | */ | 1682 | */ |
1678 | atomic_inc(&root->log_batch); | 1683 | atomic_inc(&root->log_batch); |
1679 | btrfs_wait_ordered_range(inode, start, end - start + 1); | 1684 | full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, |
1685 | &BTRFS_I(inode)->runtime_flags); | ||
1686 | if (full_sync) | ||
1687 | btrfs_wait_ordered_range(inode, start, end - start + 1); | ||
1680 | atomic_inc(&root->log_batch); | 1688 | atomic_inc(&root->log_batch); |
1681 | 1689 | ||
1682 | /* | 1690 | /* |
@@ -1743,13 +1751,25 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
1743 | 1751 | ||
1744 | if (ret != BTRFS_NO_LOG_SYNC) { | 1752 | if (ret != BTRFS_NO_LOG_SYNC) { |
1745 | if (ret > 0) { | 1753 | if (ret > 0) { |
1754 | /* | ||
1755 | * If we didn't already wait for ordered extents we need | ||
1756 | * to do that now. | ||
1757 | */ | ||
1758 | if (!full_sync) | ||
1759 | btrfs_wait_ordered_range(inode, start, | ||
1760 | end - start + 1); | ||
1746 | ret = btrfs_commit_transaction(trans, root); | 1761 | ret = btrfs_commit_transaction(trans, root); |
1747 | } else { | 1762 | } else { |
1748 | ret = btrfs_sync_log(trans, root); | 1763 | ret = btrfs_sync_log(trans, root); |
1749 | if (ret == 0) | 1764 | if (ret == 0) { |
1750 | ret = btrfs_end_transaction(trans, root); | 1765 | ret = btrfs_end_transaction(trans, root); |
1751 | else | 1766 | } else { |
1767 | if (!full_sync) | ||
1768 | btrfs_wait_ordered_range(inode, start, | ||
1769 | end - | ||
1770 | start + 1); | ||
1752 | ret = btrfs_commit_transaction(trans, root); | 1771 | ret = btrfs_commit_transaction(trans, root); |
1772 | } | ||
1753 | } | 1773 | } |
1754 | } else { | 1774 | } else { |
1755 | ret = btrfs_end_transaction(trans, root); | 1775 | ret = btrfs_end_transaction(trans, root); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 35d152444932..31a871ec48f2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -700,6 +700,8 @@ retry: | |||
700 | em->start = async_extent->start; | 700 | em->start = async_extent->start; |
701 | em->len = async_extent->ram_size; | 701 | em->len = async_extent->ram_size; |
702 | em->orig_start = em->start; | 702 | em->orig_start = em->start; |
703 | em->mod_start = em->start; | ||
704 | em->mod_len = em->len; | ||
703 | 705 | ||
704 | em->block_start = ins.objectid; | 706 | em->block_start = ins.objectid; |
705 | em->block_len = ins.offset; | 707 | em->block_len = ins.offset; |
@@ -892,6 +894,8 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, | |||
892 | em->orig_start = em->start; | 894 | em->orig_start = em->start; |
893 | ram_size = ins.offset; | 895 | ram_size = ins.offset; |
894 | em->len = ins.offset; | 896 | em->len = ins.offset; |
897 | em->mod_start = em->start; | ||
898 | em->mod_len = em->len; | ||
895 | 899 | ||
896 | em->block_start = ins.objectid; | 900 | em->block_start = ins.objectid; |
897 | em->block_len = ins.offset; | 901 | em->block_len = ins.offset; |
@@ -1338,6 +1342,8 @@ out_check: | |||
1338 | em->block_start = disk_bytenr; | 1342 | em->block_start = disk_bytenr; |
1339 | em->orig_block_len = disk_num_bytes; | 1343 | em->orig_block_len = disk_num_bytes; |
1340 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 1344 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
1345 | em->mod_start = em->start; | ||
1346 | em->mod_len = em->len; | ||
1341 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 1347 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
1342 | set_bit(EXTENT_FLAG_FILLING, &em->flags); | 1348 | set_bit(EXTENT_FLAG_FILLING, &em->flags); |
1343 | em->generation = -1; | 1349 | em->generation = -1; |
@@ -5966,6 +5972,8 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start, | |||
5966 | 5972 | ||
5967 | em->start = start; | 5973 | em->start = start; |
5968 | em->orig_start = orig_start; | 5974 | em->orig_start = orig_start; |
5975 | em->mod_start = start; | ||
5976 | em->mod_len = len; | ||
5969 | em->len = len; | 5977 | em->len = len; |
5970 | em->block_len = block_len; | 5978 | em->block_len = block_len; |
5971 | em->block_start = block_start; | 5979 | em->block_start = block_start; |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index e5ed56729607..f14b17432117 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -196,6 +196,9 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
196 | entry->file_offset = file_offset; | 196 | entry->file_offset = file_offset; |
197 | entry->start = start; | 197 | entry->start = start; |
198 | entry->len = len; | 198 | entry->len = len; |
199 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) && | ||
200 | !(type == BTRFS_ORDERED_NOCOW)) | ||
201 | entry->csum_bytes_left = disk_len; | ||
199 | entry->disk_len = disk_len; | 202 | entry->disk_len = disk_len; |
200 | entry->bytes_left = len; | 203 | entry->bytes_left = len; |
201 | entry->inode = igrab(inode); | 204 | entry->inode = igrab(inode); |
@@ -213,6 +216,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
213 | INIT_LIST_HEAD(&entry->root_extent_list); | 216 | INIT_LIST_HEAD(&entry->root_extent_list); |
214 | INIT_LIST_HEAD(&entry->work_list); | 217 | INIT_LIST_HEAD(&entry->work_list); |
215 | init_completion(&entry->completion); | 218 | init_completion(&entry->completion); |
219 | INIT_LIST_HEAD(&entry->log_list); | ||
216 | 220 | ||
217 | trace_btrfs_ordered_extent_add(inode, entry); | 221 | trace_btrfs_ordered_extent_add(inode, entry); |
218 | 222 | ||
@@ -270,6 +274,10 @@ void btrfs_add_ordered_sum(struct inode *inode, | |||
270 | tree = &BTRFS_I(inode)->ordered_tree; | 274 | tree = &BTRFS_I(inode)->ordered_tree; |
271 | spin_lock_irq(&tree->lock); | 275 | spin_lock_irq(&tree->lock); |
272 | list_add_tail(&sum->list, &entry->list); | 276 | list_add_tail(&sum->list, &entry->list); |
277 | WARN_ON(entry->csum_bytes_left < sum->len); | ||
278 | entry->csum_bytes_left -= sum->len; | ||
279 | if (entry->csum_bytes_left == 0) | ||
280 | wake_up(&entry->wait); | ||
273 | spin_unlock_irq(&tree->lock); | 281 | spin_unlock_irq(&tree->lock); |
274 | } | 282 | } |
275 | 283 | ||
@@ -405,6 +413,66 @@ out: | |||
405 | return ret == 0; | 413 | return ret == 0; |
406 | } | 414 | } |
407 | 415 | ||
416 | /* Needs to either be called under a log transaction or the log_mutex */ | ||
417 | void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode) | ||
418 | { | ||
419 | struct btrfs_ordered_inode_tree *tree; | ||
420 | struct btrfs_ordered_extent *ordered; | ||
421 | struct rb_node *n; | ||
422 | int index = log->log_transid % 2; | ||
423 | |||
424 | tree = &BTRFS_I(inode)->ordered_tree; | ||
425 | spin_lock_irq(&tree->lock); | ||
426 | for (n = rb_first(&tree->tree); n; n = rb_next(n)) { | ||
427 | ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); | ||
428 | spin_lock(&log->log_extents_lock[index]); | ||
429 | if (list_empty(&ordered->log_list)) { | ||
430 | list_add_tail(&ordered->log_list, &log->logged_list[index]); | ||
431 | atomic_inc(&ordered->refs); | ||
432 | } | ||
433 | spin_unlock(&log->log_extents_lock[index]); | ||
434 | } | ||
435 | spin_unlock_irq(&tree->lock); | ||
436 | } | ||
437 | |||
438 | void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid) | ||
439 | { | ||
440 | struct btrfs_ordered_extent *ordered; | ||
441 | int index = transid % 2; | ||
442 | |||
443 | spin_lock_irq(&log->log_extents_lock[index]); | ||
444 | while (!list_empty(&log->logged_list[index])) { | ||
445 | ordered = list_first_entry(&log->logged_list[index], | ||
446 | struct btrfs_ordered_extent, | ||
447 | log_list); | ||
448 | list_del_init(&ordered->log_list); | ||
449 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
450 | wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE, | ||
451 | &ordered->flags)); | ||
452 | btrfs_put_ordered_extent(ordered); | ||
453 | spin_lock_irq(&log->log_extents_lock[index]); | ||
454 | } | ||
455 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
456 | } | ||
457 | |||
458 | void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid) | ||
459 | { | ||
460 | struct btrfs_ordered_extent *ordered; | ||
461 | int index = transid % 2; | ||
462 | |||
463 | spin_lock_irq(&log->log_extents_lock[index]); | ||
464 | while (!list_empty(&log->logged_list[index])) { | ||
465 | ordered = list_first_entry(&log->logged_list[index], | ||
466 | struct btrfs_ordered_extent, | ||
467 | log_list); | ||
468 | list_del_init(&ordered->log_list); | ||
469 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
470 | btrfs_put_ordered_extent(ordered); | ||
471 | spin_lock_irq(&log->log_extents_lock[index]); | ||
472 | } | ||
473 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
474 | } | ||
475 | |||
408 | /* | 476 | /* |
409 | * used to drop a reference on an ordered extent. This will free | 477 | * used to drop a reference on an ordered extent. This will free |
410 | * the extent if the last reference is dropped | 478 | * the extent if the last reference is dropped |
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index efc7c2930c17..d523dbd2314d 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h | |||
@@ -79,6 +79,8 @@ struct btrfs_ordered_sum { | |||
79 | #define BTRFS_ORDERED_UPDATED_ISIZE 7 /* indicates wether this ordered extent | 79 | #define BTRFS_ORDERED_UPDATED_ISIZE 7 /* indicates wether this ordered extent |
80 | * has done its due diligence in updating | 80 | * has done its due diligence in updating |
81 | * the isize. */ | 81 | * the isize. */ |
82 | #define BTRFS_ORDERED_LOGGED_CSUM 8 /* We've logged the csums on this ordered | ||
83 | ordered extent */ | ||
82 | 84 | ||
83 | struct btrfs_ordered_extent { | 85 | struct btrfs_ordered_extent { |
84 | /* logical offset in the file */ | 86 | /* logical offset in the file */ |
@@ -96,6 +98,9 @@ struct btrfs_ordered_extent { | |||
96 | /* number of bytes that still need writing */ | 98 | /* number of bytes that still need writing */ |
97 | u64 bytes_left; | 99 | u64 bytes_left; |
98 | 100 | ||
101 | /* number of bytes that still need csumming */ | ||
102 | u64 csum_bytes_left; | ||
103 | |||
99 | /* | 104 | /* |
100 | * the end of the ordered extent which is behind it but | 105 | * the end of the ordered extent which is behind it but |
101 | * didn't update disk_i_size. Please see the comment of | 106 | * didn't update disk_i_size. Please see the comment of |
@@ -118,6 +123,9 @@ struct btrfs_ordered_extent { | |||
118 | /* list of checksums for insertion when the extent io is done */ | 123 | /* list of checksums for insertion when the extent io is done */ |
119 | struct list_head list; | 124 | struct list_head list; |
120 | 125 | ||
126 | /* If we need to wait on this to be done */ | ||
127 | struct list_head log_list; | ||
128 | |||
121 | /* used to wait for the BTRFS_ORDERED_COMPLETE bit */ | 129 | /* used to wait for the BTRFS_ORDERED_COMPLETE bit */ |
122 | wait_queue_head_t wait; | 130 | wait_queue_head_t wait; |
123 | 131 | ||
@@ -194,6 +202,9 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, | |||
194 | struct btrfs_root *root, | 202 | struct btrfs_root *root, |
195 | struct inode *inode); | 203 | struct inode *inode); |
196 | void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput); | 204 | void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput); |
205 | void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode); | ||
206 | void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid); | ||
207 | void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid); | ||
197 | int __init ordered_data_init(void); | 208 | int __init ordered_data_init(void); |
198 | void ordered_data_exit(void); | 209 | void ordered_data_exit(void); |
199 | #endif | 210 | #endif |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9027bb1e7466..7de720d22b74 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2281,6 +2281,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2281 | unsigned long log_transid = 0; | 2281 | unsigned long log_transid = 0; |
2282 | 2282 | ||
2283 | mutex_lock(&root->log_mutex); | 2283 | mutex_lock(&root->log_mutex); |
2284 | log_transid = root->log_transid; | ||
2284 | index1 = root->log_transid % 2; | 2285 | index1 = root->log_transid % 2; |
2285 | if (atomic_read(&root->log_commit[index1])) { | 2286 | if (atomic_read(&root->log_commit[index1])) { |
2286 | wait_log_commit(trans, root, root->log_transid); | 2287 | wait_log_commit(trans, root, root->log_transid); |
@@ -2308,11 +2309,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2308 | /* bail out if we need to do a full commit */ | 2309 | /* bail out if we need to do a full commit */ |
2309 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { | 2310 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { |
2310 | ret = -EAGAIN; | 2311 | ret = -EAGAIN; |
2312 | btrfs_free_logged_extents(log, log_transid); | ||
2311 | mutex_unlock(&root->log_mutex); | 2313 | mutex_unlock(&root->log_mutex); |
2312 | goto out; | 2314 | goto out; |
2313 | } | 2315 | } |
2314 | 2316 | ||
2315 | log_transid = root->log_transid; | ||
2316 | if (log_transid % 2 == 0) | 2317 | if (log_transid % 2 == 0) |
2317 | mark = EXTENT_DIRTY; | 2318 | mark = EXTENT_DIRTY; |
2318 | else | 2319 | else |
@@ -2324,6 +2325,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2324 | ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); | 2325 | ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); |
2325 | if (ret) { | 2326 | if (ret) { |
2326 | btrfs_abort_transaction(trans, root, ret); | 2327 | btrfs_abort_transaction(trans, root, ret); |
2328 | btrfs_free_logged_extents(log, log_transid); | ||
2327 | mutex_unlock(&root->log_mutex); | 2329 | mutex_unlock(&root->log_mutex); |
2328 | goto out; | 2330 | goto out; |
2329 | } | 2331 | } |
@@ -2363,6 +2365,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2363 | } | 2365 | } |
2364 | root->fs_info->last_trans_log_full_commit = trans->transid; | 2366 | root->fs_info->last_trans_log_full_commit = trans->transid; |
2365 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2367 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2368 | btrfs_free_logged_extents(log, log_transid); | ||
2366 | mutex_unlock(&log_root_tree->log_mutex); | 2369 | mutex_unlock(&log_root_tree->log_mutex); |
2367 | ret = -EAGAIN; | 2370 | ret = -EAGAIN; |
2368 | goto out; | 2371 | goto out; |
@@ -2373,6 +2376,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2373 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2376 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2374 | wait_log_commit(trans, log_root_tree, | 2377 | wait_log_commit(trans, log_root_tree, |
2375 | log_root_tree->log_transid); | 2378 | log_root_tree->log_transid); |
2379 | btrfs_free_logged_extents(log, log_transid); | ||
2376 | mutex_unlock(&log_root_tree->log_mutex); | 2380 | mutex_unlock(&log_root_tree->log_mutex); |
2377 | ret = 0; | 2381 | ret = 0; |
2378 | goto out; | 2382 | goto out; |
@@ -2392,6 +2396,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2392 | */ | 2396 | */ |
2393 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { | 2397 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { |
2394 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2398 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2399 | btrfs_free_logged_extents(log, log_transid); | ||
2395 | mutex_unlock(&log_root_tree->log_mutex); | 2400 | mutex_unlock(&log_root_tree->log_mutex); |
2396 | ret = -EAGAIN; | 2401 | ret = -EAGAIN; |
2397 | goto out_wake_log_root; | 2402 | goto out_wake_log_root; |
@@ -2402,10 +2407,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2402 | EXTENT_DIRTY | EXTENT_NEW); | 2407 | EXTENT_DIRTY | EXTENT_NEW); |
2403 | if (ret) { | 2408 | if (ret) { |
2404 | btrfs_abort_transaction(trans, root, ret); | 2409 | btrfs_abort_transaction(trans, root, ret); |
2410 | btrfs_free_logged_extents(log, log_transid); | ||
2405 | mutex_unlock(&log_root_tree->log_mutex); | 2411 | mutex_unlock(&log_root_tree->log_mutex); |
2406 | goto out_wake_log_root; | 2412 | goto out_wake_log_root; |
2407 | } | 2413 | } |
2408 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2414 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2415 | btrfs_wait_logged_extents(log, log_transid); | ||
2409 | 2416 | ||
2410 | btrfs_set_super_log_root(root->fs_info->super_for_commit, | 2417 | btrfs_set_super_log_root(root->fs_info->super_for_commit, |
2411 | log_root_tree->node->start); | 2418 | log_root_tree->node->start); |
@@ -2475,6 +2482,14 @@ static void free_log_tree(struct btrfs_trans_handle *trans, | |||
2475 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); | 2482 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); |
2476 | } | 2483 | } |
2477 | 2484 | ||
2485 | /* | ||
2486 | * We may have short-circuited the log tree with the full commit logic | ||
2487 | * and left ordered extents on our list, so clear these out to keep us | ||
2488 | * from leaking inodes and memory. | ||
2489 | */ | ||
2490 | btrfs_free_logged_extents(log, 0); | ||
2491 | btrfs_free_logged_extents(log, 1); | ||
2492 | |||
2478 | free_extent_buffer(log->node); | 2493 | free_extent_buffer(log->node); |
2479 | kfree(log); | 2494 | kfree(log); |
2480 | } | 2495 | } |
@@ -3271,14 +3286,18 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3271 | struct btrfs_root *log = root->log_root; | 3286 | struct btrfs_root *log = root->log_root; |
3272 | struct btrfs_file_extent_item *fi; | 3287 | struct btrfs_file_extent_item *fi; |
3273 | struct extent_buffer *leaf; | 3288 | struct extent_buffer *leaf; |
3289 | struct btrfs_ordered_extent *ordered; | ||
3274 | struct list_head ordered_sums; | 3290 | struct list_head ordered_sums; |
3275 | struct btrfs_map_token token; | 3291 | struct btrfs_map_token token; |
3276 | struct btrfs_key key; | 3292 | struct btrfs_key key; |
3277 | u64 csum_offset = em->mod_start - em->start; | 3293 | u64 mod_start = em->mod_start; |
3278 | u64 csum_len = em->mod_len; | 3294 | u64 mod_len = em->mod_len; |
3295 | u64 csum_offset; | ||
3296 | u64 csum_len; | ||
3279 | u64 extent_offset = em->start - em->orig_start; | 3297 | u64 extent_offset = em->start - em->orig_start; |
3280 | u64 block_len; | 3298 | u64 block_len; |
3281 | int ret; | 3299 | int ret; |
3300 | int index = log->log_transid % 2; | ||
3282 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3301 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
3283 | 3302 | ||
3284 | INIT_LIST_HEAD(&ordered_sums); | 3303 | INIT_LIST_HEAD(&ordered_sums); |
@@ -3362,6 +3381,92 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3362 | csum_len = block_len; | 3381 | csum_len = block_len; |
3363 | } | 3382 | } |
3364 | 3383 | ||
3384 | /* | ||
3385 | * First check and see if our csums are on our outstanding ordered | ||
3386 | * extents. | ||
3387 | */ | ||
3388 | again: | ||
3389 | spin_lock_irq(&log->log_extents_lock[index]); | ||
3390 | list_for_each_entry(ordered, &log->logged_list[index], log_list) { | ||
3391 | struct btrfs_ordered_sum *sum; | ||
3392 | |||
3393 | if (!mod_len) | ||
3394 | break; | ||
3395 | |||
3396 | if (ordered->inode != inode) | ||
3397 | continue; | ||
3398 | |||
3399 | if (ordered->file_offset + ordered->len <= mod_start || | ||
3400 | mod_start + mod_len <= ordered->file_offset) | ||
3401 | continue; | ||
3402 | |||
3403 | /* | ||
3404 | * We are going to copy all the csums on this ordered extent, so | ||
3405 | * go ahead and adjust mod_start and mod_len in case this | ||
3406 | * ordered extent has already been logged. | ||
3407 | */ | ||
3408 | if (ordered->file_offset > mod_start) { | ||
3409 | if (ordered->file_offset + ordered->len >= | ||
3410 | mod_start + mod_len) | ||
3411 | mod_len = ordered->file_offset - mod_start; | ||
3412 | /* | ||
3413 | * If we have this case | ||
3414 | * | ||
3415 | * |--------- logged extent ---------| | ||
3416 | * |----- ordered extent ----| | ||
3417 | * | ||
3418 | * Just don't mess with mod_start and mod_len, we'll | ||
3419 | * just end up logging more csums than we need and it | ||
3420 | * will be ok. | ||
3421 | */ | ||
3422 | } else { | ||
3423 | if (ordered->file_offset + ordered->len < | ||
3424 | mod_start + mod_len) { | ||
3425 | mod_len = (mod_start + mod_len) - | ||
3426 | (ordered->file_offset + ordered->len); | ||
3427 | mod_start = ordered->file_offset + | ||
3428 | ordered->len; | ||
3429 | } else { | ||
3430 | mod_len = 0; | ||
3431 | } | ||
3432 | } | ||
3433 | |||
3434 | /* | ||
3435 | * To keep us from looping for the above case of an ordered | ||
3436 | * extent that falls inside of the logged extent. | ||
3437 | */ | ||
3438 | if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, | ||
3439 | &ordered->flags)) | ||
3440 | continue; | ||
3441 | atomic_inc(&ordered->refs); | ||
3442 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
3443 | /* | ||
3444 | * we've dropped the lock, we must either break or | ||
3445 | * start over after this. | ||
3446 | */ | ||
3447 | |||
3448 | wait_event(ordered->wait, ordered->csum_bytes_left == 0); | ||
3449 | |||
3450 | list_for_each_entry(sum, &ordered->list, list) { | ||
3451 | ret = btrfs_csum_file_blocks(trans, log, sum); | ||
3452 | if (ret) { | ||
3453 | btrfs_put_ordered_extent(ordered); | ||
3454 | goto unlocked; | ||
3455 | } | ||
3456 | } | ||
3457 | btrfs_put_ordered_extent(ordered); | ||
3458 | goto again; | ||
3459 | |||
3460 | } | ||
3461 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
3462 | unlocked: | ||
3463 | |||
3464 | if (!mod_len || ret) | ||
3465 | return ret; | ||
3466 | |||
3467 | csum_offset = mod_start - em->start; | ||
3468 | csum_len = mod_len; | ||
3469 | |||
3365 | /* block start is already adjusted for the file extent offset. */ | 3470 | /* block start is already adjusted for the file extent offset. */ |
3366 | ret = btrfs_lookup_csums_range(log->fs_info->csum_root, | 3471 | ret = btrfs_lookup_csums_range(log->fs_info->csum_root, |
3367 | em->block_start + csum_offset, | 3472 | em->block_start + csum_offset, |
@@ -3393,6 +3498,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
3393 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | 3498 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; |
3394 | u64 test_gen; | 3499 | u64 test_gen; |
3395 | int ret = 0; | 3500 | int ret = 0; |
3501 | int num = 0; | ||
3396 | 3502 | ||
3397 | INIT_LIST_HEAD(&extents); | 3503 | INIT_LIST_HEAD(&extents); |
3398 | 3504 | ||
@@ -3401,16 +3507,31 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
3401 | 3507 | ||
3402 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) { | 3508 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) { |
3403 | list_del_init(&em->list); | 3509 | list_del_init(&em->list); |
3510 | |||
3511 | /* | ||
3512 | * Just an arbitrary number, this can be really CPU intensive | ||
3513 | * once we start getting a lot of extents, and really once we | ||
3514 | * have a bunch of extents we just want to commit since it will | ||
3515 | * be faster. | ||
3516 | */ | ||
3517 | if (++num > 32768) { | ||
3518 | list_del_init(&tree->modified_extents); | ||
3519 | ret = -EFBIG; | ||
3520 | goto process; | ||
3521 | } | ||
3522 | |||
3404 | if (em->generation <= test_gen) | 3523 | if (em->generation <= test_gen) |
3405 | continue; | 3524 | continue; |
3406 | /* Need a ref to keep it from getting evicted from cache */ | 3525 | /* Need a ref to keep it from getting evicted from cache */ |
3407 | atomic_inc(&em->refs); | 3526 | atomic_inc(&em->refs); |
3408 | set_bit(EXTENT_FLAG_LOGGING, &em->flags); | 3527 | set_bit(EXTENT_FLAG_LOGGING, &em->flags); |
3409 | list_add_tail(&em->list, &extents); | 3528 | list_add_tail(&em->list, &extents); |
3529 | num++; | ||
3410 | } | 3530 | } |
3411 | 3531 | ||
3412 | list_sort(NULL, &extents, extent_cmp); | 3532 | list_sort(NULL, &extents, extent_cmp); |
3413 | 3533 | ||
3534 | process: | ||
3414 | while (!list_empty(&extents)) { | 3535 | while (!list_empty(&extents)) { |
3415 | em = list_entry(extents.next, struct extent_map, list); | 3536 | em = list_entry(extents.next, struct extent_map, list); |
3416 | 3537 | ||
@@ -3513,6 +3634,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3513 | 3634 | ||
3514 | mutex_lock(&BTRFS_I(inode)->log_mutex); | 3635 | mutex_lock(&BTRFS_I(inode)->log_mutex); |
3515 | 3636 | ||
3637 | btrfs_get_logged_extents(log, inode); | ||
3638 | |||
3516 | /* | 3639 | /* |
3517 | * a brute force approach to making sure we get the most uptodate | 3640 | * a brute force approach to making sure we get the most uptodate |
3518 | * copies of everything. | 3641 | * copies of everything. |
@@ -3656,6 +3779,8 @@ log_extents: | |||
3656 | BTRFS_I(inode)->logged_trans = trans->transid; | 3779 | BTRFS_I(inode)->logged_trans = trans->transid; |
3657 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; | 3780 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; |
3658 | out_unlock: | 3781 | out_unlock: |
3782 | if (err) | ||
3783 | btrfs_free_logged_extents(log, log->log_transid); | ||
3659 | mutex_unlock(&BTRFS_I(inode)->log_mutex); | 3784 | mutex_unlock(&BTRFS_I(inode)->log_mutex); |
3660 | 3785 | ||
3661 | btrfs_free_path(path); | 3786 | btrfs_free_path(path); |
@@ -3822,7 +3947,6 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
3822 | end_trans: | 3947 | end_trans: |
3823 | dput(old_parent); | 3948 | dput(old_parent); |
3824 | if (ret < 0) { | 3949 | if (ret < 0) { |
3825 | WARN_ON(ret != -ENOSPC); | ||
3826 | root->fs_info->last_trans_log_full_commit = trans->transid; | 3950 | root->fs_info->last_trans_log_full_commit = trans->transid; |
3827 | ret = 1; | 3951 | ret = 1; |
3828 | } | 3952 | } |