Commit 7ea394f1 authored by Yan Zheng's avatar Yan Zheng Committed by Chris Mason

Btrfs: Fix nodatacow for the new data=ordered mode

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 00e4e6b3
...@@ -1403,7 +1403,8 @@ static inline struct dentry *fdentry(struct file *file) { ...@@ -1403,7 +1403,8 @@ static inline struct dentry *fdentry(struct file *file) {
} }
/* extent-tree.c */ /* extent-tree.c */
int btrfs_cross_ref_exists(struct btrfs_root *root, int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_key *key, u64 bytenr); struct btrfs_key *key, u64 bytenr);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans, int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
......
...@@ -893,10 +893,10 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr, ...@@ -893,10 +893,10 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
return ret; return ret;
} }
int btrfs_cross_ref_exists(struct btrfs_root *root, int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_key *key, u64 bytenr) struct btrfs_key *key, u64 bytenr)
{ {
struct btrfs_trans_handle *trans;
struct btrfs_root *old_root; struct btrfs_root *old_root;
struct btrfs_path *path = NULL; struct btrfs_path *path = NULL;
struct extent_buffer *eb; struct extent_buffer *eb;
...@@ -908,6 +908,7 @@ int btrfs_cross_ref_exists(struct btrfs_root *root, ...@@ -908,6 +908,7 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
int level; int level;
int ret; int ret;
BUG_ON(trans == NULL);
BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY); BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY);
ret = get_reference_status(root, bytenr, 0, key->objectid, ret = get_reference_status(root, bytenr, 0, key->objectid,
&min_generation, &ref_count); &min_generation, &ref_count);
...@@ -917,7 +918,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root, ...@@ -917,7 +918,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
if (ref_count != 1) if (ref_count != 1)
return 1; return 1;
trans = btrfs_start_transaction(root, 0);
old_root = root->dirty_root->root; old_root = root->dirty_root->root;
ref_generation = old_root->root_key.offset; ref_generation = old_root->root_key.offset;
...@@ -973,7 +973,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root, ...@@ -973,7 +973,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
out: out:
if (path) if (path)
btrfs_free_path(path); btrfs_free_path(path);
btrfs_end_transaction(trans, root);
return ret; return ret;
} }
...@@ -3320,7 +3319,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) ...@@ -3320,7 +3319,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
mutex_unlock(&root->fs_info->alloc_mutex); mutex_unlock(&root->fs_info->alloc_mutex);
btrfs_start_delalloc_inodes(root); btrfs_start_delalloc_inodes(root);
btrfs_wait_ordered_extents(tree_root); btrfs_wait_ordered_extents(tree_root, 0);
mutex_lock(&root->fs_info->alloc_mutex); mutex_lock(&root->fs_info->alloc_mutex);
...@@ -3407,7 +3406,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) ...@@ -3407,7 +3406,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
btrfs_clean_old_snapshots(tree_root); btrfs_clean_old_snapshots(tree_root);
btrfs_start_delalloc_inodes(root); btrfs_start_delalloc_inodes(root);
btrfs_wait_ordered_extents(tree_root); btrfs_wait_ordered_extents(tree_root, 0);
trans = btrfs_start_transaction(tree_root, 1); trans = btrfs_start_transaction(tree_root, 1);
btrfs_commit_transaction(trans, tree_root); btrfs_commit_transaction(trans, tree_root);
......
...@@ -166,7 +166,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) ...@@ -166,7 +166,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
cur_alloc_size = ins.offset; cur_alloc_size = ins.offset;
ret = btrfs_add_ordered_extent(inode, start, ins.objectid, ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
ins.offset); ins.offset, 0);
BUG_ON(ret); BUG_ON(ret);
if (num_bytes < cur_alloc_size) { if (num_bytes < cur_alloc_size) {
printk("num_bytes %Lu cur_alloc %Lu\n", num_bytes, 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,31 +187,32 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
u64 extent_start; u64 extent_start;
u64 extent_end; u64 extent_end;
u64 bytenr; u64 bytenr;
u64 cow_end;
u64 loops = 0; u64 loops = 0;
u64 total_fs_bytes; u64 total_fs_bytes;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
struct btrfs_trans_handle *trans;
struct extent_buffer *leaf; struct extent_buffer *leaf;
int found_type; int found_type;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_file_extent_item *item; struct btrfs_file_extent_item *item;
int ret; int ret;
int err; int err = 0;
struct btrfs_key found_key; struct btrfs_key found_key;
total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); BUG_ON(!path);
trans = btrfs_join_transaction(root, 1);
BUG_ON(!trans);
again: again:
ret = btrfs_lookup_file_extent(NULL, root, path, ret = btrfs_lookup_file_extent(NULL, root, path,
inode->i_ino, start, 0); inode->i_ino, start, 0);
if (ret < 0) { if (ret < 0) {
btrfs_free_path(path); err = ret;
return ret; goto out;
} }
cow_end = end;
if (ret != 0) { if (ret != 0) {
if (path->slots[0] == 0) if (path->slots[0] == 0)
goto not_found; goto not_found;
...@@ -244,12 +245,11 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) ...@@ -244,12 +245,11 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
if (start < extent_start || start >= extent_end) if (start < extent_start || start >= extent_end)
goto not_found; goto not_found;
cow_end = min(end, extent_end - 1);
bytenr = btrfs_file_extent_disk_bytenr(leaf, item); bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
if (bytenr == 0) if (bytenr == 0)
goto not_found; goto not_found;
if (btrfs_cross_ref_exists(root, &found_key, bytenr)) if (btrfs_cross_ref_exists(trans, root, &found_key, bytenr))
goto not_found; goto not_found;
/* /*
* we may be called by the resizer, make sure we're inside * we may be called by the resizer, make sure we're inside
...@@ -260,24 +260,32 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) ...@@ -260,24 +260,32 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
if (!block_group || block_group->ro) if (!block_group || block_group->ro)
goto not_found; goto not_found;
bytenr += btrfs_file_extent_offset(leaf, item);
extent_num_bytes = min(end + 1, extent_end) - start;
ret = btrfs_add_ordered_extent(inode, start, bytenr,
extent_num_bytes, 1);
if (ret) {
err = ret;
goto out;
}
btrfs_release_path(root, path);
start = extent_end; start = extent_end;
if (start <= end) {
loops++;
goto again;
}
} else { } else {
goto not_found; not_found:
} btrfs_end_transaction(trans, root);
loop:
if (start > end) {
btrfs_free_path(path); btrfs_free_path(path);
return 0; return cow_file_range(inode, start, end);
} }
btrfs_release_path(root, path); out:
loops++; WARN_ON(err);
goto again; btrfs_end_transaction(trans, root);
btrfs_free_path(path);
not_found: return err;
btrfs_release_path(root, path);
cow_file_range(inode, start, end);
start = end + 1;
goto loop;
} }
static int run_delalloc_range(struct inode *inode, u64 start, u64 end) static 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,6 +393,11 @@ int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
goto mapit; goto mapit;
} }
if (btrfs_test_opt(root, NODATASUM) ||
btrfs_test_flag(inode, NODATASUM)) {
goto mapit;
}
return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
inode, rw, bio, mirror_num, inode, rw, bio, mirror_num,
__btrfs_submit_bio_hook); __btrfs_submit_bio_hook);
...@@ -527,6 +540,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -527,6 +540,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ordered_extent = btrfs_lookup_ordered_extent(inode, start); ordered_extent = btrfs_lookup_ordered_extent(inode, start);
BUG_ON(!ordered_extent); BUG_ON(!ordered_extent);
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
goto nocow;
lock_extent(io_tree, ordered_extent->file_offset, lock_extent(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1, 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,6 +582,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
unlock_extent(io_tree, ordered_extent->file_offset, unlock_extent(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1, ordered_extent->file_offset + ordered_extent->len - 1,
GFP_NOFS); GFP_NOFS);
nocow:
add_pending_csums(trans, inode, ordered_extent->file_offset, add_pending_csums(trans, inode, ordered_extent->file_offset,
&ordered_extent->list); &ordered_extent->list);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/bit_spinlock.h> #include <linux/bit_spinlock.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/vmalloc.h>
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
#include "transaction.h" #include "transaction.h"
......
...@@ -152,7 +152,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, ...@@ -152,7 +152,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
* inserted. * inserted.
*/ */
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len) u64 start, u64 len, int nocow)
{ {
struct btrfs_ordered_inode_tree *tree; struct btrfs_ordered_inode_tree *tree;
struct rb_node *node; struct rb_node *node;
...@@ -168,6 +168,8 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, ...@@ -168,6 +168,8 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
entry->start = start; entry->start = start;
entry->len = len; entry->len = len;
entry->inode = inode; entry->inode = inode;
if (nocow)
set_bit(BTRFS_ORDERED_NOCOW, &entry->flags);
/* one ref for the tree */ /* one ref for the tree */
atomic_set(&entry->refs, 1); atomic_set(&entry->refs, 1);
...@@ -303,10 +305,11 @@ int btrfs_remove_ordered_extent(struct inode *inode, ...@@ -303,10 +305,11 @@ int btrfs_remove_ordered_extent(struct inode *inode,
return 0; return 0;
} }
int btrfs_wait_ordered_extents(struct btrfs_root *root) int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
{ {
struct list_head splice; struct list_head splice;
struct list_head *cur; struct list_head *cur;
struct list_head *tmp;
struct btrfs_ordered_extent *ordered; struct btrfs_ordered_extent *ordered;
struct inode *inode; struct inode *inode;
...@@ -314,10 +317,16 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root) ...@@ -314,10 +317,16 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root)
spin_lock(&root->fs_info->ordered_extent_lock); spin_lock(&root->fs_info->ordered_extent_lock);
list_splice_init(&root->fs_info->ordered_extents, &splice); list_splice_init(&root->fs_info->ordered_extents, &splice);
while(!list_empty(&splice)) { list_for_each_safe(cur, tmp, &splice) {
cur = splice.next; cur = splice.next;
ordered = list_entry(cur, struct btrfs_ordered_extent, ordered = list_entry(cur, struct btrfs_ordered_extent,
root_extent_list); root_extent_list);
if (nocow_only &&
!test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
cond_resched_lock(&root->fs_info->ordered_extent_lock);
continue;
}
list_del_init(&ordered->root_extent_list); list_del_init(&ordered->root_extent_list);
atomic_inc(&ordered->refs); atomic_inc(&ordered->refs);
inode = ordered->inode; inode = ordered->inode;
...@@ -338,6 +347,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root) ...@@ -338,6 +347,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root)
spin_lock(&root->fs_info->ordered_extent_lock); spin_lock(&root->fs_info->ordered_extent_lock);
} }
list_splice_init(&splice, &root->fs_info->ordered_extents);
spin_unlock(&root->fs_info->ordered_extent_lock); spin_unlock(&root->fs_info->ordered_extent_lock);
return 0; return 0;
} }
......
...@@ -64,6 +64,8 @@ struct btrfs_ordered_sum { ...@@ -64,6 +64,8 @@ struct btrfs_ordered_sum {
#define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */ #define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */
#define BTRFS_ORDERED_NOCOW 2 /* set when we want to write in place */
struct btrfs_ordered_extent { struct btrfs_ordered_extent {
/* logical offset in the file */ /* logical offset in the file */
u64 file_offset; u64 file_offset;
...@@ -125,7 +127,7 @@ int btrfs_remove_ordered_extent(struct inode *inode, ...@@ -125,7 +127,7 @@ int btrfs_remove_ordered_extent(struct inode *inode,
int btrfs_dec_test_ordered_pending(struct inode *inode, int btrfs_dec_test_ordered_pending(struct inode *inode,
u64 file_offset, u64 io_size); u64 file_offset, u64 io_size);
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len); u64 start, u64 len, int nocow);
int btrfs_add_ordered_sum(struct inode *inode, int btrfs_add_ordered_sum(struct inode *inode,
struct btrfs_ordered_extent *entry, struct btrfs_ordered_extent *entry,
struct btrfs_ordered_sum *sum); struct btrfs_ordered_sum *sum);
...@@ -143,5 +145,5 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping, ...@@ -143,5 +145,5 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
pgoff_t start, pgoff_t end); pgoff_t start, pgoff_t end);
int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start, int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
loff_t end, int sync_mode); loff_t end, int sync_mode);
int btrfs_wait_ordered_extents(struct btrfs_root *root); int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
#endif #endif
...@@ -438,6 +438,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, ...@@ -438,6 +438,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
free_extent_buffer(root->commit_root); free_extent_buffer(root->commit_root);
root->commit_root = NULL; root->commit_root = NULL;
root->dirty_root = NULL;
spin_lock(&root->list_lock); spin_lock(&root->list_lock);
list_del_init(&dirty->root->dead_list); list_del_init(&dirty->root->dead_list);
...@@ -461,6 +462,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, ...@@ -461,6 +462,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
sizeof(struct btrfs_disk_key)); sizeof(struct btrfs_disk_key));
root->root_item.drop_level = 0; root->root_item.drop_level = 0;
root->commit_root = NULL; root->commit_root = NULL;
root->dirty_root = NULL;
root->root_key.offset = root->fs_info->generation; root->root_key.offset = root->fs_info->generation;
btrfs_set_root_bytenr(&root->root_item, btrfs_set_root_bytenr(&root->root_item,
root->node->start); root->node->start);
...@@ -762,7 +764,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -762,7 +764,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
} }
do { do {
int snap_pending = 0;
joined = cur_trans->num_joined; joined = cur_trans->num_joined;
if (!list_empty(&trans->transaction->pending_snapshots))
snap_pending = 1;
WARN_ON(cur_trans != trans->transaction); WARN_ON(cur_trans != trans->transaction);
prepare_to_wait(&cur_trans->writer_wait, &wait, prepare_to_wait(&cur_trans->writer_wait, &wait,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
...@@ -774,6 +780,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -774,6 +780,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
if (snap_pending) {
ret = btrfs_wait_ordered_extents(root, 1);
BUG_ON(ret);
}
schedule_timeout(timeout); schedule_timeout(timeout);
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment