aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file-item.c
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-12-12 10:03:38 -0500
committerChris Mason <chris.mason@oracle.com>2008-12-12 10:03:38 -0500
commit17d217fe970d34720f4f1633dca73a6aa2f3d9d1 (patch)
tree4e2e716400cc45a6697475629f4c046b96ff76e7 /fs/btrfs/file-item.c
parente4404d6e8da678d852b7f767f665f8edf76c9e9f (diff)
Btrfs: fix nodatasum handling in balancing code
Checksums on data can be disabled by mount option, so it's possible some data extents don't have checksums or have invalid checksums. This causes trouble for data relocation. This patch contains following things to make data relocation work. 1) make nodatasum/nodatacow mount option only affects new files. Checksums and COW on data are only controlled by the inode flags. 2) check the existence of checksum in the nodatacow checker. If checksums exist, force COW the data extent. This ensure that checksum for a given block is either valid or does not exist. 3) update data relocation code to properly handle the case of checksum missing. Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r--fs/btrfs/file-item.c114
1 files changed, 111 insertions, 3 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 3ebef871ee6c..df0447632dbd 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -140,6 +140,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
140 return ret; 140 return ret;
141} 141}
142 142
143
143int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 144int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
144 struct bio *bio, u32 *dst) 145 struct bio *bio, u32 *dst)
145{ 146{
@@ -185,9 +186,16 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
185 if (ret == -ENOENT || ret == -EFBIG) 186 if (ret == -ENOENT || ret == -EFBIG)
186 ret = 0; 187 ret = 0;
187 sum = 0; 188 sum = 0;
188 printk("no csum found for inode %lu start " 189 if (BTRFS_I(inode)->root->root_key.objectid ==
189 "%llu\n", inode->i_ino, 190 BTRFS_DATA_RELOC_TREE_OBJECTID) {
190 (unsigned long long)offset); 191 set_extent_bits(io_tree, offset,
192 offset + bvec->bv_len - 1,
193 EXTENT_NODATASUM, GFP_NOFS);
194 } else {
195 printk("no csum found for inode %lu "
196 "start %llu\n", inode->i_ino,
197 (unsigned long long)offset);
198 }
191 item = NULL; 199 item = NULL;
192 btrfs_release_path(root, path); 200 btrfs_release_path(root, path);
193 goto found; 201 goto found;
@@ -228,6 +236,106 @@ found:
228 return 0; 236 return 0;
229} 237}
230 238
239int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
240 struct list_head *list)
241{
242 struct btrfs_key key;
243 struct btrfs_path *path;
244 struct extent_buffer *leaf;
245 struct btrfs_ordered_sum *sums;
246 struct btrfs_sector_sum *sector_sum;
247 struct btrfs_csum_item *item;
248 unsigned long offset;
249 int ret;
250 size_t size;
251 u64 csum_end;
252 u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy);
253
254 path = btrfs_alloc_path();
255 BUG_ON(!path);
256
257 key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
258 key.offset = start;
259 key.type = BTRFS_EXTENT_CSUM_KEY;
260
261 ret = btrfs_search_slot(NULL, root->fs_info->csum_root,
262 &key, path, 0, 0);
263 if (ret < 0)
264 goto fail;
265 if (ret > 0 && path->slots[0] > 0) {
266 leaf = path->nodes[0];
267 btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
268 if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
269 key.type == BTRFS_EXTENT_CSUM_KEY) {
270 offset = (start - key.offset) >>
271 root->fs_info->sb->s_blocksize_bits;
272 if (offset * csum_size <
273 btrfs_item_size_nr(leaf, path->slots[0] - 1))
274 path->slots[0]--;
275 }
276 }
277
278 while (start <= end) {
279 leaf = path->nodes[0];
280 if (path->slots[0] >= btrfs_header_nritems(leaf)) {
281 ret = btrfs_next_leaf(root->fs_info->csum_root, path);
282 if (ret < 0)
283 goto fail;
284 if (ret > 0)
285 break;
286 leaf = path->nodes[0];
287 }
288
289 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
290 if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
291 key.type != BTRFS_EXTENT_CSUM_KEY)
292 break;
293
294 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
295 if (key.offset > end)
296 break;
297
298 if (key.offset > start)
299 start = key.offset;
300
301 size = btrfs_item_size_nr(leaf, path->slots[0]);
302 csum_end = key.offset + (size / csum_size) * root->sectorsize;
303
304 size = min(csum_end, end + 1) - start;
305 sums = kzalloc(btrfs_ordered_sum_size(root, size), GFP_NOFS);
306 BUG_ON(!sums);
307
308 sector_sum = sums->sums;
309 sums->bytenr = start;
310 sums->len = size;
311
312 offset = (start - key.offset) >>
313 root->fs_info->sb->s_blocksize_bits;
314 offset *= csum_size;
315
316 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
317 struct btrfs_csum_item);
318 while (size > 0) {
319 read_extent_buffer(path->nodes[0], &sector_sum->sum,
320 ((unsigned long)item) + offset,
321 csum_size);
322 sector_sum->bytenr = start;
323
324 size -= root->sectorsize;
325 start += root->sectorsize;
326 offset += csum_size;
327 sector_sum++;
328 }
329 list_add_tail(&sums->list, list);
330
331 path->slots[0]++;
332 }
333 ret = 0;
334fail:
335 btrfs_free_path(path);
336 return ret;
337}
338
231int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, 339int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
232 struct bio *bio, u64 file_start, int contig) 340 struct bio *bio, u64 file_start, int contig)
233{ 341{