aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-08-05 13:05:02 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:06 -0400
commit7ea394f1192bee1af67ea4762c88ef4b7b0487a8 (patch)
treee2c593d054d802bc71e86508a5b7523ff80cc1ea /fs
parent00e4e6b33a0f78aab4b788d6d31c884fd8bf88da (diff)
Btrfs: Fix nodatacow for the new data=ordered mode
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/extent-tree.c11
-rw-r--r--fs/btrfs/inode.c60
-rw-r--r--fs/btrfs/ioctl.c1
-rw-r--r--fs/btrfs/ordered-data.c16
-rw-r--r--fs/btrfs/ordered-data.h6
-rw-r--r--fs/btrfs/transaction.c11
7 files changed, 74 insertions, 34 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 116aee21bf77..f90e5a7ac161 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1403,7 +1403,8 @@ static inline struct dentry *fdentry(struct file *file) {
1403} 1403}
1404 1404
1405/* extent-tree.c */ 1405/* extent-tree.c */
1406int btrfs_cross_ref_exists(struct btrfs_root *root, 1406int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
1407 struct btrfs_root *root,
1407 struct btrfs_key *key, u64 bytenr); 1408 struct btrfs_key *key, u64 bytenr);
1408int btrfs_extent_post_op(struct btrfs_trans_handle *trans, 1409int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
1409 struct btrfs_root *root); 1410 struct btrfs_root *root);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 33cb2ac4cb28..fff219ed61d9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -893,10 +893,10 @@ out:
893 return ret; 893 return ret;
894} 894}
895 895
896int btrfs_cross_ref_exists(struct btrfs_root *root, 896int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
897 struct btrfs_root *root,
897 struct btrfs_key *key, u64 bytenr) 898 struct btrfs_key *key, u64 bytenr)
898{ 899{
899 struct btrfs_trans_handle *trans;
900 struct btrfs_root *old_root; 900 struct btrfs_root *old_root;
901 struct btrfs_path *path = NULL; 901 struct btrfs_path *path = NULL;
902 struct extent_buffer *eb; 902 struct extent_buffer *eb;
@@ -908,6 +908,7 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
908 int level; 908 int level;
909 int ret; 909 int ret;
910 910
911 BUG_ON(trans == NULL);
911 BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY); 912 BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY);
912 ret = get_reference_status(root, bytenr, 0, key->objectid, 913 ret = get_reference_status(root, bytenr, 0, key->objectid,
913 &min_generation, &ref_count); 914 &min_generation, &ref_count);
@@ -917,7 +918,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
917 if (ref_count != 1) 918 if (ref_count != 1)
918 return 1; 919 return 1;
919 920
920 trans = btrfs_start_transaction(root, 0);
921 old_root = root->dirty_root->root; 921 old_root = root->dirty_root->root;
922 ref_generation = old_root->root_key.offset; 922 ref_generation = old_root->root_key.offset;
923 923
@@ -973,7 +973,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
973out: 973out:
974 if (path) 974 if (path)
975 btrfs_free_path(path); 975 btrfs_free_path(path);
976 btrfs_end_transaction(trans, root);
977 return ret; 976 return ret;
978} 977}
979 978
@@ -3320,7 +3319,7 @@ again:
3320 mutex_unlock(&root->fs_info->alloc_mutex); 3319 mutex_unlock(&root->fs_info->alloc_mutex);
3321 3320
3322 btrfs_start_delalloc_inodes(root); 3321 btrfs_start_delalloc_inodes(root);
3323 btrfs_wait_ordered_extents(tree_root); 3322 btrfs_wait_ordered_extents(tree_root, 0);
3324 3323
3325 mutex_lock(&root->fs_info->alloc_mutex); 3324 mutex_lock(&root->fs_info->alloc_mutex);
3326 3325
@@ -3407,7 +3406,7 @@ next:
3407 btrfs_clean_old_snapshots(tree_root); 3406 btrfs_clean_old_snapshots(tree_root);
3408 3407
3409 btrfs_start_delalloc_inodes(root); 3408 btrfs_start_delalloc_inodes(root);
3410 btrfs_wait_ordered_extents(tree_root); 3409 btrfs_wait_ordered_extents(tree_root, 0);
3411 3410
3412 trans = btrfs_start_transaction(tree_root, 1); 3411 trans = btrfs_start_transaction(tree_root, 1);
3413 btrfs_commit_transaction(trans, tree_root); 3412 btrfs_commit_transaction(trans, tree_root);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 4d8ffc01931e..c33053ba3816 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -166,7 +166,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
166 166
167 cur_alloc_size = ins.offset; 167 cur_alloc_size = ins.offset;
168 ret = btrfs_add_ordered_extent(inode, start, ins.objectid, 168 ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
169 ins.offset); 169 ins.offset, 0);
170 BUG_ON(ret); 170 BUG_ON(ret);
171 if (num_bytes < cur_alloc_size) { 171 if (num_bytes < cur_alloc_size) {
172 printk("num_bytes %Lu cur_alloc %Lu\n", num_bytes, 172 printk("num_bytes %Lu cur_alloc %Lu\n", num_bytes,
@@ -187,31 +187,32 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
187 u64 extent_start; 187 u64 extent_start;
188 u64 extent_end; 188 u64 extent_end;
189 u64 bytenr; 189 u64 bytenr;
190 u64 cow_end;
191 u64 loops = 0; 190 u64 loops = 0;
192 u64 total_fs_bytes; 191 u64 total_fs_bytes;
193 struct btrfs_root *root = BTRFS_I(inode)->root; 192 struct btrfs_root *root = BTRFS_I(inode)->root;
194 struct btrfs_block_group_cache *block_group; 193 struct btrfs_block_group_cache *block_group;
194 struct btrfs_trans_handle *trans;
195 struct extent_buffer *leaf; 195 struct extent_buffer *leaf;
196 int found_type; 196 int found_type;
197 struct btrfs_path *path; 197 struct btrfs_path *path;
198 struct btrfs_file_extent_item *item; 198 struct btrfs_file_extent_item *item;
199 int ret; 199 int ret;
200 int err; 200 int err = 0;
201 struct btrfs_key found_key; 201 struct btrfs_key found_key;
202 202
203 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); 203 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
204 path = btrfs_alloc_path(); 204 path = btrfs_alloc_path();
205 BUG_ON(!path); 205 BUG_ON(!path);
206 trans = btrfs_join_transaction(root, 1);
207 BUG_ON(!trans);
206again: 208again:
207 ret = btrfs_lookup_file_extent(NULL, root, path, 209 ret = btrfs_lookup_file_extent(NULL, root, path,
208 inode->i_ino, start, 0); 210 inode->i_ino, start, 0);
209 if (ret < 0) { 211 if (ret < 0) {
210 btrfs_free_path(path); 212 err = ret;
211 return ret; 213 goto out;
212 } 214 }
213 215
214 cow_end = end;
215 if (ret != 0) { 216 if (ret != 0) {
216 if (path->slots[0] == 0) 217 if (path->slots[0] == 0)
217 goto not_found; 218 goto not_found;
@@ -244,12 +245,11 @@ again:
244 if (start < extent_start || start >= extent_end) 245 if (start < extent_start || start >= extent_end)
245 goto not_found; 246 goto not_found;
246 247
247 cow_end = min(end, extent_end - 1);
248 bytenr = btrfs_file_extent_disk_bytenr(leaf, item); 248 bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
249 if (bytenr == 0) 249 if (bytenr == 0)
250 goto not_found; 250 goto not_found;
251 251
252 if (btrfs_cross_ref_exists(root, &found_key, bytenr)) 252 if (btrfs_cross_ref_exists(trans, root, &found_key, bytenr))
253 goto not_found; 253 goto not_found;
254 /* 254 /*
255 * we may be called by the resizer, make sure we're inside 255 * we may be called by the resizer, make sure we're inside
@@ -260,24 +260,32 @@ again:
260 if (!block_group || block_group->ro) 260 if (!block_group || block_group->ro)
261 goto not_found; 261 goto not_found;
262 262
263 bytenr += btrfs_file_extent_offset(leaf, item);
264 extent_num_bytes = min(end + 1, extent_end) - start;
265 ret = btrfs_add_ordered_extent(inode, start, bytenr,
266 extent_num_bytes, 1);
267 if (ret) {
268 err = ret;
269 goto out;
270 }
271
272 btrfs_release_path(root, path);
263 start = extent_end; 273 start = extent_end;
274 if (start <= end) {
275 loops++;
276 goto again;
277 }
264 } else { 278 } else {
265 goto not_found; 279not_found:
266 } 280 btrfs_end_transaction(trans, root);
267loop:
268 if (start > end) {
269 btrfs_free_path(path); 281 btrfs_free_path(path);
270 return 0; 282 return cow_file_range(inode, start, end);
271 } 283 }
272 btrfs_release_path(root, path); 284out:
273 loops++; 285 WARN_ON(err);
274 goto again; 286 btrfs_end_transaction(trans, root);
275 287 btrfs_free_path(path);
276not_found: 288 return err;
277 btrfs_release_path(root, path);
278 cow_file_range(inode, start, end);
279 start = end + 1;
280 goto loop;
281} 289}
282 290
283static int run_delalloc_range(struct inode *inode, u64 start, u64 end) 291static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
@@ -385,6 +393,11 @@ int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
385 goto mapit; 393 goto mapit;
386 } 394 }
387 395
396 if (btrfs_test_opt(root, NODATASUM) ||
397 btrfs_test_flag(inode, NODATASUM)) {
398 goto mapit;
399 }
400
388 return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, 401 return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
389 inode, rw, bio, mirror_num, 402 inode, rw, bio, mirror_num,
390 __btrfs_submit_bio_hook); 403 __btrfs_submit_bio_hook);
@@ -527,6 +540,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
527 540
528 ordered_extent = btrfs_lookup_ordered_extent(inode, start); 541 ordered_extent = btrfs_lookup_ordered_extent(inode, start);
529 BUG_ON(!ordered_extent); 542 BUG_ON(!ordered_extent);
543 if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
544 goto nocow;
530 545
531 lock_extent(io_tree, ordered_extent->file_offset, 546 lock_extent(io_tree, ordered_extent->file_offset,
532 ordered_extent->file_offset + ordered_extent->len - 1, 547 ordered_extent->file_offset + ordered_extent->len - 1,
@@ -567,6 +582,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
567 unlock_extent(io_tree, ordered_extent->file_offset, 582 unlock_extent(io_tree, ordered_extent->file_offset,
568 ordered_extent->file_offset + ordered_extent->len - 1, 583 ordered_extent->file_offset + ordered_extent->len - 1,
569 GFP_NOFS); 584 GFP_NOFS);
585nocow:
570 add_pending_csums(trans, inode, ordered_extent->file_offset, 586 add_pending_csums(trans, inode, ordered_extent->file_offset,
571 &ordered_extent->list); 587 &ordered_extent->list);
572 588
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 3932c7cd0fae..59b64c738fd1 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -36,6 +36,7 @@
36#include <linux/bit_spinlock.h> 36#include <linux/bit_spinlock.h>
37#include <linux/version.h> 37#include <linux/version.h>
38#include <linux/xattr.h> 38#include <linux/xattr.h>
39#include <linux/vmalloc.h>
39#include "ctree.h" 40#include "ctree.h"
40#include "disk-io.h" 41#include "disk-io.h"
41#include "transaction.h" 42#include "transaction.h"
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index db200e6baf7e..da6d43eb41db 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -152,7 +152,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
152 * inserted. 152 * inserted.
153 */ 153 */
154int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, 154int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
155 u64 start, u64 len) 155 u64 start, u64 len, int nocow)
156{ 156{
157 struct btrfs_ordered_inode_tree *tree; 157 struct btrfs_ordered_inode_tree *tree;
158 struct rb_node *node; 158 struct rb_node *node;
@@ -168,6 +168,8 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
168 entry->start = start; 168 entry->start = start;
169 entry->len = len; 169 entry->len = len;
170 entry->inode = inode; 170 entry->inode = inode;
171 if (nocow)
172 set_bit(BTRFS_ORDERED_NOCOW, &entry->flags);
171 173
172 /* one ref for the tree */ 174 /* one ref for the tree */
173 atomic_set(&entry->refs, 1); 175 atomic_set(&entry->refs, 1);
@@ -303,10 +305,11 @@ int btrfs_remove_ordered_extent(struct inode *inode,
303 return 0; 305 return 0;
304} 306}
305 307
306int btrfs_wait_ordered_extents(struct btrfs_root *root) 308int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
307{ 309{
308 struct list_head splice; 310 struct list_head splice;
309 struct list_head *cur; 311 struct list_head *cur;
312 struct list_head *tmp;
310 struct btrfs_ordered_extent *ordered; 313 struct btrfs_ordered_extent *ordered;
311 struct inode *inode; 314 struct inode *inode;
312 315
@@ -314,10 +317,16 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root)
314 317
315 spin_lock(&root->fs_info->ordered_extent_lock); 318 spin_lock(&root->fs_info->ordered_extent_lock);
316 list_splice_init(&root->fs_info->ordered_extents, &splice); 319 list_splice_init(&root->fs_info->ordered_extents, &splice);
317 while(!list_empty(&splice)) { 320 list_for_each_safe(cur, tmp, &splice) {
318 cur = splice.next; 321 cur = splice.next;
319 ordered = list_entry(cur, struct btrfs_ordered_extent, 322 ordered = list_entry(cur, struct btrfs_ordered_extent,
320 root_extent_list); 323 root_extent_list);
324 if (nocow_only &&
325 !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
326 cond_resched_lock(&root->fs_info->ordered_extent_lock);
327 continue;
328 }
329
321 list_del_init(&ordered->root_extent_list); 330 list_del_init(&ordered->root_extent_list);
322 atomic_inc(&ordered->refs); 331 atomic_inc(&ordered->refs);
323 inode = ordered->inode; 332 inode = ordered->inode;
@@ -338,6 +347,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root)
338 347
339 spin_lock(&root->fs_info->ordered_extent_lock); 348 spin_lock(&root->fs_info->ordered_extent_lock);
340 } 349 }
350 list_splice_init(&splice, &root->fs_info->ordered_extents);
341 spin_unlock(&root->fs_info->ordered_extent_lock); 351 spin_unlock(&root->fs_info->ordered_extent_lock);
342 return 0; 352 return 0;
343} 353}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 5efe6b63c74c..fd45519f30a8 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -64,6 +64,8 @@ struct btrfs_ordered_sum {
64 64
65#define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */ 65#define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */
66 66
67#define BTRFS_ORDERED_NOCOW 2 /* set when we want to write in place */
68
67struct btrfs_ordered_extent { 69struct btrfs_ordered_extent {
68 /* logical offset in the file */ 70 /* logical offset in the file */
69 u64 file_offset; 71 u64 file_offset;
@@ -125,7 +127,7 @@ int btrfs_remove_ordered_extent(struct inode *inode,
125int btrfs_dec_test_ordered_pending(struct inode *inode, 127int btrfs_dec_test_ordered_pending(struct inode *inode,
126 u64 file_offset, u64 io_size); 128 u64 file_offset, u64 io_size);
127int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, 129int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
128 u64 start, u64 len); 130 u64 start, u64 len, int nocow);
129int btrfs_add_ordered_sum(struct inode *inode, 131int btrfs_add_ordered_sum(struct inode *inode,
130 struct btrfs_ordered_extent *entry, 132 struct btrfs_ordered_extent *entry,
131 struct btrfs_ordered_sum *sum); 133 struct btrfs_ordered_sum *sum);
@@ -143,5 +145,5 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
143 pgoff_t start, pgoff_t end); 145 pgoff_t start, pgoff_t end);
144int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start, 146int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
145 loff_t end, int sync_mode); 147 loff_t end, int sync_mode);
146int btrfs_wait_ordered_extents(struct btrfs_root *root); 148int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
147#endif 149#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index ebf5362da1d2..9d3d08e9f8d1 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -438,6 +438,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
438 438
439 free_extent_buffer(root->commit_root); 439 free_extent_buffer(root->commit_root);
440 root->commit_root = NULL; 440 root->commit_root = NULL;
441 root->dirty_root = NULL;
441 442
442 spin_lock(&root->list_lock); 443 spin_lock(&root->list_lock);
443 list_del_init(&dirty->root->dead_list); 444 list_del_init(&dirty->root->dead_list);
@@ -461,6 +462,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
461 sizeof(struct btrfs_disk_key)); 462 sizeof(struct btrfs_disk_key));
462 root->root_item.drop_level = 0; 463 root->root_item.drop_level = 0;
463 root->commit_root = NULL; 464 root->commit_root = NULL;
465 root->dirty_root = NULL;
464 root->root_key.offset = root->fs_info->generation; 466 root->root_key.offset = root->fs_info->generation;
465 btrfs_set_root_bytenr(&root->root_item, 467 btrfs_set_root_bytenr(&root->root_item,
466 root->node->start); 468 root->node->start);
@@ -762,7 +764,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
762 } 764 }
763 765
764 do { 766 do {
767 int snap_pending = 0;
765 joined = cur_trans->num_joined; 768 joined = cur_trans->num_joined;
769 if (!list_empty(&trans->transaction->pending_snapshots))
770 snap_pending = 1;
771
766 WARN_ON(cur_trans != trans->transaction); 772 WARN_ON(cur_trans != trans->transaction);
767 prepare_to_wait(&cur_trans->writer_wait, &wait, 773 prepare_to_wait(&cur_trans->writer_wait, &wait,
768 TASK_UNINTERRUPTIBLE); 774 TASK_UNINTERRUPTIBLE);
@@ -774,6 +780,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
774 780
775 mutex_unlock(&root->fs_info->trans_mutex); 781 mutex_unlock(&root->fs_info->trans_mutex);
776 782
783 if (snap_pending) {
784 ret = btrfs_wait_ordered_extents(root, 1);
785 BUG_ON(ret);
786 }
787
777 schedule_timeout(timeout); 788 schedule_timeout(timeout);
778 789
779 mutex_lock(&root->fs_info->trans_mutex); 790 mutex_lock(&root->fs_info->trans_mutex);