aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-01 11:21:32 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commit63b10fc4874a014e22bc4c64e3d92b71180661fe (patch)
tree683a7b414f269f8b999b666d5f2d6c9fb74a1ee8 /fs/btrfs
parent2d2ae547979854d10b75d557b3abdb3eb7511bbc (diff)
Reorder the flags field in struct btrfs_header and record a flag on writeout
This allows detection of blocks that have already been written in the running transaction so they can be recowed instead of modified again. It is step one in trusting the transid field of the block pointers. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c10
-rw-r--r--fs/btrfs/ctree.h28
-rw-r--r--fs/btrfs/disk-io.c13
3 files changed, 42 insertions, 9 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 70b6ddfe15a1..6ba5394834be 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -124,6 +124,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
124 btrfs_set_header_bytenr(cow, cow->start); 124 btrfs_set_header_bytenr(cow, cow->start);
125 btrfs_set_header_generation(cow, trans->transid); 125 btrfs_set_header_generation(cow, trans->transid);
126 btrfs_set_header_owner(cow, new_root_objectid); 126 btrfs_set_header_owner(cow, new_root_objectid);
127 btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
127 128
128 WARN_ON(btrfs_header_generation(buf) > trans->transid); 129 WARN_ON(btrfs_header_generation(buf) > trans->transid);
129 ret = btrfs_inc_ref(trans, new_root, buf); 130 ret = btrfs_inc_ref(trans, new_root, buf);
@@ -183,6 +184,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
183 btrfs_set_header_bytenr(cow, cow->start); 184 btrfs_set_header_bytenr(cow, cow->start);
184 btrfs_set_header_generation(cow, trans->transid); 185 btrfs_set_header_generation(cow, trans->transid);
185 btrfs_set_header_owner(cow, root->root_key.objectid); 186 btrfs_set_header_owner(cow, root->root_key.objectid);
187 btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
186 188
187 WARN_ON(btrfs_header_generation(buf) > trans->transid); 189 WARN_ON(btrfs_header_generation(buf) > trans->transid);
188 if (btrfs_header_generation(buf) != trans->transid) { 190 if (btrfs_header_generation(buf) != trans->transid) {
@@ -245,11 +247,14 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
245 } 247 }
246 248
247 header_trans = btrfs_header_generation(buf); 249 header_trans = btrfs_header_generation(buf);
248 if (header_trans == trans->transid) { 250 spin_lock(&root->fs_info->hash_lock);
251 if (header_trans == trans->transid &&
252 !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
249 *cow_ret = buf; 253 *cow_ret = buf;
254 spin_unlock(&root->fs_info->hash_lock);
250 return 0; 255 return 0;
251 } 256 }
252 257 spin_unlock(&root->fs_info->hash_lock);
253 search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); 258 search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1);
254 ret = __btrfs_cow_block(trans, root, buf, parent, 259 ret = __btrfs_cow_block(trans, root, buf, parent,
255 parent_slot, cow_ret, search_start, 0); 260 parent_slot, cow_ret, search_start, 0);
@@ -1494,6 +1499,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
1494 btrfs_set_header_bytenr(split, split->start); 1499 btrfs_set_header_bytenr(split, split->start);
1495 btrfs_set_header_generation(split, trans->transid); 1500 btrfs_set_header_generation(split, trans->transid);
1496 btrfs_set_header_owner(split, root->root_key.objectid); 1501 btrfs_set_header_owner(split, root->root_key.objectid);
1502 btrfs_set_header_flags(split, 0);
1497 write_extent_buffer(split, root->fs_info->fsid, 1503 write_extent_buffer(split, root->fs_info->fsid,
1498 (unsigned long)btrfs_header_fsid(split), 1504 (unsigned long)btrfs_header_fsid(split),
1499 BTRFS_FSID_SIZE); 1505 BTRFS_FSID_SIZE);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fec96ba7c23b..67d533cf8f47 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -193,6 +193,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
193} 193}
194 194
195#define BTRFS_FSID_SIZE 16 195#define BTRFS_FSID_SIZE 16
196#define BTRFS_HEADER_FLAG_WRITTEN (1 << 0)
197
196/* 198/*
197 * every tree block (leaf or node) starts with this header. 199 * every tree block (leaf or node) starts with this header.
198 */ 200 */
@@ -200,10 +202,10 @@ struct btrfs_header {
200 u8 csum[BTRFS_CSUM_SIZE]; 202 u8 csum[BTRFS_CSUM_SIZE];
201 u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ 203 u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
202 __le64 bytenr; /* which block this node is supposed to live in */ 204 __le64 bytenr; /* which block this node is supposed to live in */
205 __le64 flags;
203 __le64 generation; 206 __le64 generation;
204 __le64 owner; 207 __le64 owner;
205 __le32 nritems; 208 __le32 nritems;
206 __le16 flags;
207 u8 level; 209 u8 level;
208} __attribute__ ((__packed__)); 210} __attribute__ ((__packed__));
209 211
@@ -229,9 +231,10 @@ struct btrfs_header {
229 */ 231 */
230struct btrfs_super_block { 232struct btrfs_super_block {
231 u8 csum[BTRFS_CSUM_SIZE]; 233 u8 csum[BTRFS_CSUM_SIZE];
232 /* the first 3 fields must match struct btrfs_header */ 234 /* the first 4 fields must match struct btrfs_header */
233 u8 fsid[16]; /* FS specific uuid */ 235 u8 fsid[16]; /* FS specific uuid */
234 __le64 bytenr; /* this block number */ 236 __le64 bytenr; /* this block number */
237 __le64 flags;
235 __le64 magic; 238 __le64 magic;
236 __le64 generation; 239 __le64 generation;
237 __le64 root; 240 __le64 root;
@@ -1045,9 +1048,28 @@ BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
1045 generation, 64); 1048 generation, 64);
1046BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); 1049BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
1047BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); 1050BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
1048BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 16); 1051BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
1049BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); 1052BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
1050 1053
1054static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
1055{
1056 return (btrfs_header_flags(eb) & flag) == flag;
1057}
1058
1059static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag)
1060{
1061 u64 flags = btrfs_header_flags(eb);
1062 btrfs_set_header_flags(eb, flags | flag);
1063 return (flags & flag) == flag;
1064}
1065
1066static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
1067{
1068 u64 flags = btrfs_header_flags(eb);
1069 btrfs_set_header_flags(eb, flags & ~flag);
1070 return (flags & flag) == flag;
1071}
1072
1051static inline u8 *btrfs_header_fsid(struct extent_buffer *eb) 1073static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
1052{ 1074{
1053 unsigned long ptr = offsetof(struct btrfs_header, fsid); 1075 unsigned long ptr = offsetof(struct btrfs_header, fsid);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1c5e097a4df2..709e33d08bb5 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -159,17 +159,19 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
159 from_this_trans = 1; 159 from_this_trans = 1;
160 160
161 /* FIXME, this is not good */ 161 /* FIXME, this is not good */
162 if (from_this_trans == 0 && 162 if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
163 memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
164 u32 val; 163 u32 val;
165 u32 found = 0; 164 u32 found = 0;
166 memcpy(&found, result, BTRFS_CRC32_SIZE); 165 memcpy(&found, result, BTRFS_CRC32_SIZE);
167 166
168 read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); 167 read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE);
168 WARN_ON(1);
169 printk("btrfs: %s checksum verify failed on %llu " 169 printk("btrfs: %s checksum verify failed on %llu "
170 "wanted %X found %X from_this_trans %d\n", 170 "wanted %X found %X from_this_trans %d "
171 "level %d\n",
171 root->fs_info->sb->s_id, 172 root->fs_info->sb->s_id,
172 buf->start, val, found, from_this_trans); 173 buf->start, val, found, from_this_trans,
174 btrfs_header_level(buf));
173 return 1; 175 return 1;
174 } 176 }
175 } else { 177 } else {
@@ -220,6 +222,9 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
220 goto err; 222 goto err;
221 } 223 }
222 found_level = btrfs_header_level(eb); 224 found_level = btrfs_header_level(eb);
225 spin_lock(&root->fs_info->hash_lock);
226 btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
227 spin_unlock(&root->fs_info->hash_lock);
223 csum_tree_block(root, eb, 0); 228 csum_tree_block(root, eb, 0);
224err: 229err:
225 free_extent_buffer(eb); 230 free_extent_buffer(eb);