aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-12-17 20:14:01 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:58 -0400
commitbe20aa9dbadc8c06283784ee12bbc0d97dea3418 (patch)
tree52bd8b7e21b36d10dbb48f8b163eea992c9cfd4a /fs/btrfs
parentb6cda9bcb4df7544c67fc3548a53bc1607d59f46 (diff)
Btrfs: Add mount option to turn off data cow
A number of workloads do not require copy on write data or checksumming. mount -o nodatasum to disable checksums and -o nodatacow to disable both copy on write and checksumming. In nodatacow mode, copy on write is still performed when a given extent is under snapshot. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c53
-rw-r--r--fs/btrfs/ctree.h8
-rw-r--r--fs/btrfs/extent-tree.c101
-rw-r--r--fs/btrfs/inode.c122
-rw-r--r--fs/btrfs/super.c34
5 files changed, 293 insertions, 25 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index fd8233e05cf4..585f279d1112 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -70,7 +70,58 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
70 memset(p, 0, sizeof(*p)); 70 memset(p, 0, sizeof(*p));
71} 71}
72 72
73static int __btrfs_cow_block(struct btrfs_trans_handle *trans, 73int btrfs_copy_root(struct btrfs_trans_handle *trans,
74 struct btrfs_root *root,
75 struct extent_buffer *buf,
76 struct extent_buffer **cow_ret, u64 new_root_objectid)
77{
78 struct extent_buffer *cow;
79 u32 nritems;
80 int ret = 0;
81 int level;
82 struct btrfs_key first_key;
83 struct btrfs_root new_root;
84
85 memcpy(&new_root, root, sizeof(new_root));
86 new_root.root_key.objectid = new_root_objectid;
87
88 WARN_ON(root->ref_cows && trans->transid !=
89 root->fs_info->running_transaction->transid);
90 WARN_ON(root->ref_cows && trans->transid != root->last_trans);
91
92 level = btrfs_header_level(buf);
93 nritems = btrfs_header_nritems(buf);
94 if (nritems) {
95 if (level == 0)
96 btrfs_item_key_to_cpu(buf, &first_key, 0);
97 else
98 btrfs_node_key_to_cpu(buf, &first_key, 0);
99 } else {
100 first_key.objectid = 0;
101 }
102 cow = __btrfs_alloc_free_block(trans, &new_root, buf->len,
103 new_root_objectid,
104 trans->transid, first_key.objectid,
105 level, buf->start, 0);
106 if (IS_ERR(cow))
107 return PTR_ERR(cow);
108
109 copy_extent_buffer(cow, buf, 0, 0, cow->len);
110 btrfs_set_header_bytenr(cow, cow->start);
111 btrfs_set_header_generation(cow, trans->transid);
112 btrfs_set_header_owner(cow, new_root_objectid);
113
114 WARN_ON(btrfs_header_generation(buf) > trans->transid);
115 ret = btrfs_inc_ref(trans, &new_root, buf);
116 if (ret)
117 return ret;
118
119 btrfs_mark_buffer_dirty(cow);
120 *cow_ret = cow;
121 return 0;
122}
123
124int __btrfs_cow_block(struct btrfs_trans_handle *trans,
74 struct btrfs_root *root, 125 struct btrfs_root *root,
75 struct extent_buffer *buf, 126 struct extent_buffer *buf,
76 struct extent_buffer *parent, int parent_slot, 127 struct extent_buffer *parent, int parent_slot,
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 5e255cabfd10..b51b021fff85 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -431,6 +431,7 @@ struct btrfs_root {
431#define BTRFS_STRING_ITEM_KEY 253 431#define BTRFS_STRING_ITEM_KEY 253
432 432
433#define BTRFS_MOUNT_NODATASUM 0x1 433#define BTRFS_MOUNT_NODATASUM 0x1
434#define BTRFS_MOUNT_NODATACOW 0x2
434 435
435#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) 436#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
436#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) 437#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
@@ -915,6 +916,9 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {
915 btrfs_item_offset_nr(leaf, slot))) 916 btrfs_item_offset_nr(leaf, slot)))
916 917
917/* extent-tree.c */ 918/* extent-tree.c */
919u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
920 struct btrfs_path *count_path,
921 u64 first_extent);
918int btrfs_extent_post_op(struct btrfs_trans_handle *trans, 922int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
919 struct btrfs_root *root); 923 struct btrfs_root *root);
920int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy); 924int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy);
@@ -974,6 +978,10 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
974 struct btrfs_root *root, struct extent_buffer *buf, 978 struct btrfs_root *root, struct extent_buffer *buf,
975 struct extent_buffer *parent, int parent_slot, 979 struct extent_buffer *parent, int parent_slot,
976 struct extent_buffer **cow_ret); 980 struct extent_buffer **cow_ret);
981int btrfs_copy_root(struct btrfs_trans_handle *trans,
982 struct btrfs_root *root,
983 struct extent_buffer *buf,
984 struct extent_buffer **cow_ret, u64 new_root_objectid);
977int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root 985int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
978 *root, struct btrfs_path *path, u32 data_size); 986 *root, struct btrfs_path *path, u32 data_size);
979int btrfs_truncate_item(struct btrfs_trans_handle *trans, 987int btrfs_truncate_item(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 00414836e963..1412d556313f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -679,6 +679,104 @@ out:
679 return 0; 679 return 0;
680} 680}
681 681
682u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
683 struct btrfs_path *count_path,
684 u64 first_extent)
685{
686 struct btrfs_root *extent_root = root->fs_info->extent_root;
687 struct btrfs_path *path;
688 u64 bytenr;
689 u64 found_objectid;
690 u64 root_objectid = 0;
691 u32 total_count = 0;
692 u32 cur_count;
693 u32 refs;
694 u32 nritems;
695 int ret;
696 struct btrfs_key key;
697 struct btrfs_key found_key;
698 struct extent_buffer *l;
699 struct btrfs_extent_item *item;
700 struct btrfs_extent_ref *ref_item;
701 int level = -1;
702
703 path = btrfs_alloc_path();
704again:
705 if (level == -1)
706 bytenr = first_extent;
707 else
708 bytenr = count_path->nodes[level]->start;
709
710 cur_count = 0;
711 key.objectid = bytenr;
712 key.offset = 0;
713
714 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
715 ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
716 if (ret < 0)
717 goto out;
718 BUG_ON(ret == 0);
719
720 l = path->nodes[0];
721 btrfs_item_key_to_cpu(l, &found_key, path->slots[0]);
722
723 if (found_key.objectid != bytenr ||
724 found_key.type != BTRFS_EXTENT_ITEM_KEY) {
725 goto out;
726 }
727
728 item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
729 refs = btrfs_extent_refs(l, item);
730 while (1) {
731 nritems = btrfs_header_nritems(l);
732 if (path->slots[0] >= nritems) {
733 ret = btrfs_next_leaf(extent_root, path);
734 if (ret == 0)
735 continue;
736 break;
737 }
738 btrfs_item_key_to_cpu(l, &found_key, path->slots[0]);
739 if (found_key.objectid != bytenr)
740 break;
741 if (found_key.type != BTRFS_EXTENT_REF_KEY) {
742 path->slots[0]++;
743 continue;
744 }
745
746 cur_count++;
747 ref_item = btrfs_item_ptr(l, path->slots[0],
748 struct btrfs_extent_ref);
749 found_objectid = btrfs_ref_root(l, ref_item);
750
751 if (found_objectid != root_objectid)
752 total_count++;
753
754 if (total_count > 1)
755 goto out;
756
757 if (root_objectid == 0)
758 root_objectid = found_objectid;
759
760 path->slots[0]++;
761 }
762 if (cur_count == 0) {
763 total_count = 0;
764 goto out;
765 }
766 if (total_count > 1)
767 goto out;
768 if (level >= 0 && root->node == count_path->nodes[level])
769 goto out;
770 level++;
771 btrfs_release_path(root, path);
772 goto again;
773
774out:
775 btrfs_free_path(path);
776 return total_count;
777
778}
779
682int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, 780int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
683 struct btrfs_root *root, u64 owner_objectid) 781 struct btrfs_root *root, u64 owner_objectid)
684{ 782{
@@ -1127,9 +1225,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
1127 if (!path) 1225 if (!path)
1128 return -ENOMEM; 1226 return -ENOMEM;
1129 1227
1130 if (ref_generation && owner_objectid == 0 && root_objectid == 3) {
1131//printk("drop backref root %Lu gen %Lu byte %Lu\n", root_objectid, ref_generation, bytenr );
1132 }
1133 ret = lookup_extent_backref(trans, extent_root, path, 1228 ret = lookup_extent_backref(trans, extent_root, path,
1134 bytenr, root_objectid, 1229 bytenr, root_objectid,
1135 ref_generation, 1230 ref_generation,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 11885cb114e2..91f3fc43e2a9 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -72,21 +72,22 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
72 [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, 72 [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK,
73}; 73};
74 74
75static int run_delalloc_range(struct inode *inode, u64 start, u64 end) 75static int cow_file_range(struct inode *inode, u64 start, u64 end)
76{ 76{
77 struct btrfs_root *root = BTRFS_I(inode)->root; 77 struct btrfs_root *root = BTRFS_I(inode)->root;
78 struct btrfs_trans_handle *trans; 78 struct btrfs_trans_handle *trans;
79 struct btrfs_key ins;
80 u64 alloc_hint = 0; 79 u64 alloc_hint = 0;
81 u64 num_bytes; 80 u64 num_bytes;
82 int ret;
83 u64 blocksize = root->sectorsize; 81 u64 blocksize = root->sectorsize;
82 struct btrfs_key ins;
83 int ret;
84 84
85 mutex_lock(&root->fs_info->fs_mutex);
86 trans = btrfs_start_transaction(root, 1); 85 trans = btrfs_start_transaction(root, 1);
87 btrfs_set_trans_block_group(trans, inode);
88 BUG_ON(!trans); 86 BUG_ON(!trans);
87 btrfs_set_trans_block_group(trans, inode);
88
89 num_bytes = (end - start + blocksize) & ~(blocksize - 1); 89 num_bytes = (end - start + blocksize) & ~(blocksize - 1);
90 num_bytes = max(blocksize, num_bytes);
90 ret = btrfs_drop_extents(trans, root, inode, 91 ret = btrfs_drop_extents(trans, root, inode,
91 start, start + num_bytes, start, &alloc_hint); 92 start, start + num_bytes, start, &alloc_hint);
92 93
@@ -106,6 +107,101 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
106 ins.offset); 107 ins.offset);
107out: 108out:
108 btrfs_end_transaction(trans, root); 109 btrfs_end_transaction(trans, root);
110 return ret;
111}
112
113static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
114{
115 u64 extent_start;
116 u64 extent_end;
117 u64 bytenr;
118 u64 cow_end;
119 struct btrfs_root *root = BTRFS_I(inode)->root;
120 struct extent_buffer *leaf;
121 int found_type;
122 struct btrfs_path *path;
123 struct btrfs_file_extent_item *item;
124 int ret;
125 int err;
126 struct btrfs_key found_key;
127
128 path = btrfs_alloc_path();
129 BUG_ON(!path);
130again:
131 ret = btrfs_lookup_file_extent(NULL, root, path,
132 inode->i_ino, start, 0);
133 if (ret < 0) {
134 btrfs_free_path(path);
135 return ret;
136 }
137
138 cow_end = end;
139 if (ret != 0) {
140 if (path->slots[0] == 0)
141 goto not_found;
142 path->slots[0]--;
143 }
144
145 leaf = path->nodes[0];
146 item = btrfs_item_ptr(leaf, path->slots[0],
147 struct btrfs_file_extent_item);
148
149 /* are we inside the extent that was found? */
150 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
151 found_type = btrfs_key_type(&found_key);
152 if (found_key.objectid != inode->i_ino ||
153 found_type != BTRFS_EXTENT_DATA_KEY) {
154 goto not_found;
155 }
156
157 found_type = btrfs_file_extent_type(leaf, item);
158 extent_start = found_key.offset;
159 if (found_type == BTRFS_FILE_EXTENT_REG) {
160 extent_end = extent_start +
161 btrfs_file_extent_num_bytes(leaf, item);
162 err = 0;
163
164 if (start < extent_start || start >= extent_end)
165 goto not_found;
166
167 cow_end = min(end, extent_end - 1);
168 bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
169 if (bytenr == 0)
170 goto not_found;
171
172 bytenr += btrfs_file_extent_offset(leaf, item);
173 if (btrfs_count_snapshots_in_path(root, path, bytenr) != 1) {
174 goto not_found;
175 }
176
177 start = extent_end;
178 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
179 goto not_found;
180 }
181loop:
182 if (start > end) {
183 btrfs_free_path(path);
184 return 0;
185 }
186 btrfs_release_path(root, path);
187 goto again;
188
189not_found:
190 cow_file_range(inode, start, cow_end);
191 start = cow_end + 1;
192 goto loop;
193}
194
195static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
196{
197 struct btrfs_root *root = BTRFS_I(inode)->root;
198 int ret;
199
200 mutex_lock(&root->fs_info->fs_mutex);
201 if (btrfs_test_opt(root, NODATACOW))
202 ret = run_delalloc_nocow(inode, start, end);
203 else
204 ret = cow_file_range(inode, start, end);
109 mutex_unlock(&root->fs_info->fs_mutex); 205 mutex_unlock(&root->fs_info->fs_mutex);
110 return ret; 206 return ret;
111} 207}
@@ -1907,9 +2003,6 @@ int btrfs_commit_write(struct file *file, struct page *page,
1907 2003
1908 btrfs_cow_one_page(inode, page, PAGE_CACHE_SIZE); 2004 btrfs_cow_one_page(inode, page, PAGE_CACHE_SIZE);
1909 2005
1910 set_page_extent_mapped(page);
1911 set_page_dirty(page);
1912
1913 if (pos > inode->i_size) { 2006 if (pos > inode->i_size) {
1914 i_size_write(inode, pos); 2007 i_size_write(inode, pos);
1915 mark_inode_dirty(inode); 2008 mark_inode_dirty(inode);
@@ -2078,13 +2171,18 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2078 key.objectid = objectid; 2171 key.objectid = objectid;
2079 key.offset = 1; 2172 key.offset = 1;
2080 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); 2173 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
2174
2081 extent_buffer_get(root->node); 2175 extent_buffer_get(root->node);
2082 btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); 2176 btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp);
2083 free_extent_buffer(tmp); 2177 free_extent_buffer(tmp);
2084 btrfs_set_root_bytenr(&new_root_item, root->node->start); 2178
2085 btrfs_set_root_level(&new_root_item, btrfs_header_level(root->node)); 2179 btrfs_copy_root(trans, root, root->node, &tmp, objectid);
2180
2181 btrfs_set_root_bytenr(&new_root_item, tmp->start);
2182 btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp));
2086 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, 2183 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2087 &new_root_item); 2184 &new_root_item);
2185 free_extent_buffer(tmp);
2088 if (ret) 2186 if (ret)
2089 goto fail; 2187 goto fail;
2090 2188
@@ -2106,10 +2204,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2106 2204
2107 if (ret) 2205 if (ret)
2108 goto fail; 2206 goto fail;
2109
2110 ret = btrfs_inc_root_ref(trans, root, objectid);
2111 if (ret)
2112 goto fail;
2113fail: 2207fail:
2114 nr = trans->blocks_used; 2208 nr = trans->blocks_used;
2115 err = btrfs_commit_transaction(trans, root); 2209 err = btrfs_commit_transaction(trans, root);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index ad4f280ec777..2116728d1f98 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -61,12 +61,13 @@ static void btrfs_put_super (struct super_block * sb)
61} 61}
62 62
63enum { 63enum {
64 Opt_subvol, Opt_nodatasum, Opt_err, 64 Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_err,
65}; 65};
66 66
67static match_table_t tokens = { 67static match_table_t tokens = {
68 {Opt_subvol, "subvol=%s"}, 68 {Opt_subvol, "subvol=%s"},
69 {Opt_nodatasum, "nodatasum"}, 69 {Opt_nodatasum, "nodatasum"},
70 {Opt_nodatacow, "nodatacow"},
70 {Opt_err, NULL} 71 {Opt_err, NULL}
71}; 72};
72 73
@@ -78,12 +79,20 @@ static int parse_options (char * options,
78 struct btrfs_fs_info *info = NULL; 79 struct btrfs_fs_info *info = NULL;
79 substring_t args[MAX_OPT_ARGS]; 80 substring_t args[MAX_OPT_ARGS];
80 81
81 if (root)
82 info = root->fs_info;
83
84 if (!options) 82 if (!options)
85 return 1; 83 return 1;
86 84
85 /*
86 * strsep changes the string, duplicate it because parse_options
87 * gets called twice
88 */
89 options = kstrdup(options, GFP_NOFS);
90 if (!options)
91 return -ENOMEM;
92
93 if (root)
94 info = root->fs_info;
95
87 while ((p = strsep (&options, ",")) != NULL) { 96 while ((p = strsep (&options, ",")) != NULL) {
88 int token; 97 int token;
89 if (!*p) 98 if (!*p)
@@ -92,17 +101,28 @@ static int parse_options (char * options,
92 token = match_token(p, tokens, args); 101 token = match_token(p, tokens, args);
93 switch (token) { 102 switch (token) {
94 case Opt_subvol: 103 case Opt_subvol:
95 if (subvol_name) 104 if (subvol_name) {
96 *subvol_name = match_strdup(&args[0]); 105 *subvol_name = match_strdup(&args[0]);
106 }
97 break; 107 break;
98 case Opt_nodatasum: 108 case Opt_nodatasum:
99 if (root) 109 if (info) {
110 printk("btrfs: setting nodatacsum\n");
100 btrfs_set_opt(info->mount_opt, NODATASUM); 111 btrfs_set_opt(info->mount_opt, NODATASUM);
112 }
113 break;
114 case Opt_nodatacow:
115 if (info) {
116 printk("btrfs: setting nodatacow\n");
117 btrfs_set_opt(info->mount_opt, NODATACOW);
118 btrfs_set_opt(info->mount_opt, NODATASUM);
119 }
101 break; 120 break;
102 default: 121 default:
103 return 0; 122 break;
104 } 123 }
105 } 124 }
125 kfree(options);
106 return 1; 126 return 1;
107} 127}
108 128