diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-01-22 16:47:59 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:59 -0400 |
commit | 5f56406aabdf5444d040c5955effc665b1d0dbaf (patch) | |
tree | 59c82cc7f5d5de3b65b6eba24b505684eb7941d6 /fs/btrfs/file.c | |
parent | c1e32da616a17813f11b701a7a87775d35c12e3a (diff) |
Btrfs: Fix hole insertion corner cases
There were a few places that could cause duplicate extent insertion,
this adjusts the code that creates holes to avoid it.
lookup_extent_map is changed to correctly return all of the extents in a
range, even when there are none matching at the start of the range.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 897242e87fa7..1cd8c908811e 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -278,7 +278,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
278 | u64 hole_size; | 278 | u64 hole_size; |
279 | u64 mask = root->sectorsize - 1; | 279 | u64 mask = root->sectorsize - 1; |
280 | last_pos_in_file = (isize + mask) & ~mask; | 280 | last_pos_in_file = (isize + mask) & ~mask; |
281 | hole_size = (start_pos - last_pos_in_file + mask) & ~mask; | 281 | hole_size = (end_pos - last_pos_in_file + mask) & ~mask; |
282 | 282 | ||
283 | if (last_pos_in_file < start_pos) { | 283 | if (last_pos_in_file < start_pos) { |
284 | err = btrfs_drop_extents(trans, root, inode, | 284 | err = btrfs_drop_extents(trans, root, inode, |
@@ -293,6 +293,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
293 | inode->i_ino, | 293 | inode->i_ino, |
294 | last_pos_in_file, | 294 | last_pos_in_file, |
295 | 0, 0, hole_size); | 295 | 0, 0, hole_size); |
296 | btrfs_check_file(root, inode); | ||
296 | } | 297 | } |
297 | if (err) | 298 | if (err) |
298 | goto failed; | 299 | goto failed; |
@@ -378,6 +379,80 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
378 | return 0; | 379 | return 0; |
379 | } | 380 | } |
380 | 381 | ||
382 | int btrfs_check_file(struct btrfs_root *root, struct inode *inode) | ||
383 | { | ||
384 | return 0; | ||
385 | #if 0 | ||
386 | struct btrfs_path *path; | ||
387 | struct btrfs_key found_key; | ||
388 | struct extent_buffer *leaf; | ||
389 | struct btrfs_file_extent_item *extent; | ||
390 | u64 last_offset = 0; | ||
391 | int nritems; | ||
392 | int slot; | ||
393 | int found_type; | ||
394 | int ret; | ||
395 | int err = 0; | ||
396 | u64 extent_end = 0; | ||
397 | |||
398 | path = btrfs_alloc_path(); | ||
399 | ret = btrfs_lookup_file_extent(NULL, root, path, inode->i_ino, | ||
400 | last_offset, 0); | ||
401 | while(1) { | ||
402 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
403 | if (path->slots[0] >= nritems) { | ||
404 | ret = btrfs_next_leaf(root, path); | ||
405 | if (ret) | ||
406 | goto out; | ||
407 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
408 | } | ||
409 | slot = path->slots[0]; | ||
410 | leaf = path->nodes[0]; | ||
411 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
412 | if (found_key.objectid != inode->i_ino) | ||
413 | break; | ||
414 | if (found_key.type != BTRFS_EXTENT_DATA_KEY) | ||
415 | goto out; | ||
416 | |||
417 | if (found_key.offset != last_offset) { | ||
418 | WARN_ON(1); | ||
419 | btrfs_print_leaf(root, leaf); | ||
420 | printk("inode %lu found offset %Lu expected %Lu\n", | ||
421 | inode->i_ino, found_key.offset, last_offset); | ||
422 | err = 1; | ||
423 | goto out; | ||
424 | } | ||
425 | extent = btrfs_item_ptr(leaf, slot, | ||
426 | struct btrfs_file_extent_item); | ||
427 | found_type = btrfs_file_extent_type(leaf, extent); | ||
428 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
429 | extent_end = found_key.offset + | ||
430 | btrfs_file_extent_num_bytes(leaf, extent); | ||
431 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
432 | struct btrfs_item *item; | ||
433 | item = btrfs_item_nr(leaf, slot); | ||
434 | extent_end = found_key.offset + | ||
435 | btrfs_file_extent_inline_len(leaf, item); | ||
436 | extent_end = (extent_end + root->sectorsize - 1) & | ||
437 | ~((u64)root->sectorsize -1 ); | ||
438 | } | ||
439 | last_offset = extent_end; | ||
440 | path->slots[0]++; | ||
441 | } | ||
442 | if (last_offset < inode->i_size) { | ||
443 | WARN_ON(1); | ||
444 | btrfs_print_leaf(root, leaf); | ||
445 | printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino, | ||
446 | last_offset, inode->i_size); | ||
447 | err = 1; | ||
448 | |||
449 | } | ||
450 | out: | ||
451 | btrfs_free_path(path); | ||
452 | return err; | ||
453 | #endif | ||
454 | } | ||
455 | |||
381 | /* | 456 | /* |
382 | * this is very complex, but the basic idea is to drop all extents | 457 | * this is very complex, but the basic idea is to drop all extents |
383 | * in the range start - end. hint_block is filled in with a block number | 458 | * in the range start - end. hint_block is filled in with a block number |
@@ -436,6 +511,7 @@ next_slot: | |||
436 | slot = path->slots[0]; | 511 | slot = path->slots[0]; |
437 | ret = 0; | 512 | ret = 0; |
438 | btrfs_item_key_to_cpu(leaf, &key, slot); | 513 | btrfs_item_key_to_cpu(leaf, &key, slot); |
514 | |||
439 | if (key.offset >= end || key.objectid != inode->i_ino) { | 515 | if (key.offset >= end || key.objectid != inode->i_ino) { |
440 | goto out; | 516 | goto out; |
441 | } | 517 | } |