diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-12-17 20:14:01 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:58 -0400 |
commit | be20aa9dbadc8c06283784ee12bbc0d97dea3418 (patch) | |
tree | 52bd8b7e21b36d10dbb48f8b163eea992c9cfd4a /fs/btrfs/inode.c | |
parent | b6cda9bcb4df7544c67fc3548a53bc1607d59f46 (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/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 122 |
1 files changed, 108 insertions, 14 deletions
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 | ||
75 | static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | 75 | static 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); |
107 | out: | 108 | out: |
108 | btrfs_end_transaction(trans, root); | 109 | btrfs_end_transaction(trans, root); |
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static 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); | ||
130 | again: | ||
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 | } | ||
181 | loop: | ||
182 | if (start > end) { | ||
183 | btrfs_free_path(path); | ||
184 | return 0; | ||
185 | } | ||
186 | btrfs_release_path(root, path); | ||
187 | goto again; | ||
188 | |||
189 | not_found: | ||
190 | cow_file_range(inode, start, cow_end); | ||
191 | start = cow_end + 1; | ||
192 | goto loop; | ||
193 | } | ||
194 | |||
195 | static 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; | ||
2113 | fail: | 2207 | fail: |
2114 | nr = trans->blocks_used; | 2208 | nr = trans->blocks_used; |
2115 | err = btrfs_commit_transaction(trans, root); | 2209 | err = btrfs_commit_transaction(trans, root); |