diff options
Diffstat (limited to 'fs/ocfs2/extent_map.c')
| -rw-r--r-- | fs/ocfs2/extent_map.c | 346 |
1 files changed, 293 insertions, 53 deletions
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index c58668a326fe..aed268e80b49 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 28 | #include <linux/fiemap.h> | ||
| 28 | 29 | ||
| 29 | #define MLOG_MASK_PREFIX ML_EXTENT_MAP | 30 | #define MLOG_MASK_PREFIX ML_EXTENT_MAP |
| 30 | #include <cluster/masklog.h> | 31 | #include <cluster/masklog.h> |
| @@ -32,6 +33,7 @@ | |||
| 32 | #include "ocfs2.h" | 33 | #include "ocfs2.h" |
| 33 | 34 | ||
| 34 | #include "alloc.h" | 35 | #include "alloc.h" |
| 36 | #include "dlmglue.h" | ||
| 35 | #include "extent_map.h" | 37 | #include "extent_map.h" |
| 36 | #include "inode.h" | 38 | #include "inode.h" |
| 37 | #include "super.h" | 39 | #include "super.h" |
| @@ -282,6 +284,51 @@ out: | |||
| 282 | kfree(new_emi); | 284 | kfree(new_emi); |
| 283 | } | 285 | } |
| 284 | 286 | ||
| 287 | static int ocfs2_last_eb_is_empty(struct inode *inode, | ||
| 288 | struct ocfs2_dinode *di) | ||
| 289 | { | ||
| 290 | int ret, next_free; | ||
| 291 | u64 last_eb_blk = le64_to_cpu(di->i_last_eb_blk); | ||
| 292 | struct buffer_head *eb_bh = NULL; | ||
| 293 | struct ocfs2_extent_block *eb; | ||
| 294 | struct ocfs2_extent_list *el; | ||
| 295 | |||
| 296 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), last_eb_blk, | ||
| 297 | &eb_bh, OCFS2_BH_CACHED, inode); | ||
| 298 | if (ret) { | ||
| 299 | mlog_errno(ret); | ||
| 300 | goto out; | ||
| 301 | } | ||
| 302 | |||
| 303 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; | ||
| 304 | el = &eb->h_list; | ||
| 305 | |||
| 306 | if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { | ||
| 307 | ret = -EROFS; | ||
| 308 | OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); | ||
| 309 | goto out; | ||
| 310 | } | ||
| 311 | |||
| 312 | if (el->l_tree_depth) { | ||
| 313 | ocfs2_error(inode->i_sb, | ||
| 314 | "Inode %lu has non zero tree depth in " | ||
| 315 | "leaf block %llu\n", inode->i_ino, | ||
| 316 | (unsigned long long)eb_bh->b_blocknr); | ||
| 317 | ret = -EROFS; | ||
| 318 | goto out; | ||
| 319 | } | ||
| 320 | |||
| 321 | next_free = le16_to_cpu(el->l_next_free_rec); | ||
| 322 | |||
| 323 | if (next_free == 0 || | ||
| 324 | (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) | ||
| 325 | ret = 1; | ||
| 326 | |||
| 327 | out: | ||
| 328 | brelse(eb_bh); | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 285 | /* | 332 | /* |
| 286 | * Return the 1st index within el which contains an extent start | 333 | * Return the 1st index within el which contains an extent start |
| 287 | * larger than v_cluster. | 334 | * larger than v_cluster. |
| @@ -373,42 +420,28 @@ out: | |||
| 373 | return ret; | 420 | return ret; |
| 374 | } | 421 | } |
| 375 | 422 | ||
| 376 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | 423 | static int ocfs2_get_clusters_nocache(struct inode *inode, |
| 377 | u32 *p_cluster, u32 *num_clusters, | 424 | struct buffer_head *di_bh, |
| 378 | unsigned int *extent_flags) | 425 | u32 v_cluster, unsigned int *hole_len, |
| 426 | struct ocfs2_extent_rec *ret_rec, | ||
| 427 | unsigned int *is_last) | ||
| 379 | { | 428 | { |
| 380 | int ret, i; | 429 | int i, ret, tree_height, len; |
| 381 | unsigned int flags = 0; | ||
| 382 | struct buffer_head *di_bh = NULL; | ||
| 383 | struct buffer_head *eb_bh = NULL; | ||
| 384 | struct ocfs2_dinode *di; | 430 | struct ocfs2_dinode *di; |
| 385 | struct ocfs2_extent_block *eb; | 431 | struct ocfs2_extent_block *uninitialized_var(eb); |
| 386 | struct ocfs2_extent_list *el; | 432 | struct ocfs2_extent_list *el; |
| 387 | struct ocfs2_extent_rec *rec; | 433 | struct ocfs2_extent_rec *rec; |
| 388 | u32 coff; | 434 | struct buffer_head *eb_bh = NULL; |
| 389 | |||
| 390 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
| 391 | ret = -ERANGE; | ||
| 392 | mlog_errno(ret); | ||
| 393 | goto out; | ||
| 394 | } | ||
| 395 | |||
| 396 | ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, | ||
| 397 | num_clusters, extent_flags); | ||
| 398 | if (ret == 0) | ||
| 399 | goto out; | ||
| 400 | 435 | ||
| 401 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, | 436 | memset(ret_rec, 0, sizeof(*ret_rec)); |
| 402 | &di_bh, OCFS2_BH_CACHED, inode); | 437 | if (is_last) |
| 403 | if (ret) { | 438 | *is_last = 0; |
| 404 | mlog_errno(ret); | ||
| 405 | goto out; | ||
| 406 | } | ||
| 407 | 439 | ||
| 408 | di = (struct ocfs2_dinode *) di_bh->b_data; | 440 | di = (struct ocfs2_dinode *) di_bh->b_data; |
| 409 | el = &di->id2.i_list; | 441 | el = &di->id2.i_list; |
| 442 | tree_height = le16_to_cpu(el->l_tree_depth); | ||
| 410 | 443 | ||
| 411 | if (el->l_tree_depth) { | 444 | if (tree_height > 0) { |
| 412 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | 445 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); |
| 413 | if (ret) { | 446 | if (ret) { |
| 414 | mlog_errno(ret); | 447 | mlog_errno(ret); |
| @@ -431,46 +464,143 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | |||
| 431 | i = ocfs2_search_extent_list(el, v_cluster); | 464 | i = ocfs2_search_extent_list(el, v_cluster); |
| 432 | if (i == -1) { | 465 | if (i == -1) { |
| 433 | /* | 466 | /* |
| 434 | * A hole was found. Return some canned values that | 467 | * Holes can be larger than the maximum size of an |
| 435 | * callers can key on. If asked for, num_clusters will | 468 | * extent, so we return their lengths in a seperate |
| 436 | * be populated with the size of the hole. | 469 | * field. |
| 437 | */ | 470 | */ |
| 438 | *p_cluster = 0; | 471 | if (hole_len) { |
| 439 | if (num_clusters) { | ||
| 440 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, | 472 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, |
| 441 | v_cluster, | 473 | v_cluster, &len); |
| 442 | num_clusters); | ||
| 443 | if (ret) { | 474 | if (ret) { |
| 444 | mlog_errno(ret); | 475 | mlog_errno(ret); |
| 445 | goto out; | 476 | goto out; |
| 446 | } | 477 | } |
| 478 | |||
| 479 | *hole_len = len; | ||
| 447 | } | 480 | } |
| 448 | } else { | 481 | goto out_hole; |
| 449 | rec = &el->l_recs[i]; | 482 | } |
| 450 | 483 | ||
| 451 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); | 484 | rec = &el->l_recs[i]; |
| 452 | 485 | ||
| 453 | if (!rec->e_blkno) { | 486 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); |
| 454 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " | 487 | |
| 455 | "record (%u, %u, 0)", inode->i_ino, | 488 | if (!rec->e_blkno) { |
| 456 | le32_to_cpu(rec->e_cpos), | 489 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " |
| 457 | ocfs2_rec_clusters(el, rec)); | 490 | "record (%u, %u, 0)", inode->i_ino, |
| 458 | ret = -EROFS; | 491 | le32_to_cpu(rec->e_cpos), |
| 459 | goto out; | 492 | ocfs2_rec_clusters(el, rec)); |
| 493 | ret = -EROFS; | ||
| 494 | goto out; | ||
| 495 | } | ||
| 496 | |||
| 497 | *ret_rec = *rec; | ||
| 498 | |||
| 499 | /* | ||
| 500 | * Checking for last extent is potentially expensive - we | ||
| 501 | * might have to look at the next leaf over to see if it's | ||
| 502 | * empty. | ||
| 503 | * | ||
| 504 | * The first two checks are to see whether the caller even | ||
| 505 | * cares for this information, and if the extent is at least | ||
| 506 | * the last in it's list. | ||
| 507 | * | ||
| 508 | * If those hold true, then the extent is last if any of the | ||
| 509 | * additional conditions hold true: | ||
| 510 | * - Extent list is in-inode | ||
| 511 | * - Extent list is right-most | ||
| 512 | * - Extent list is 2nd to rightmost, with empty right-most | ||
| 513 | */ | ||
| 514 | if (is_last) { | ||
| 515 | if (i == (le16_to_cpu(el->l_next_free_rec) - 1)) { | ||
| 516 | if (tree_height == 0) | ||
| 517 | *is_last = 1; | ||
| 518 | else if (eb->h_blkno == di->i_last_eb_blk) | ||
| 519 | *is_last = 1; | ||
| 520 | else if (eb->h_next_leaf_blk == di->i_last_eb_blk) { | ||
| 521 | ret = ocfs2_last_eb_is_empty(inode, di); | ||
| 522 | if (ret < 0) { | ||
| 523 | mlog_errno(ret); | ||
| 524 | goto out; | ||
| 525 | } | ||
| 526 | if (ret == 1) | ||
| 527 | *is_last = 1; | ||
| 528 | } | ||
| 460 | } | 529 | } |
| 530 | } | ||
| 531 | |||
| 532 | out_hole: | ||
| 533 | ret = 0; | ||
| 534 | out: | ||
| 535 | brelse(eb_bh); | ||
| 536 | return ret; | ||
| 537 | } | ||
| 538 | |||
| 539 | static void ocfs2_relative_extent_offsets(struct super_block *sb, | ||
| 540 | u32 v_cluster, | ||
| 541 | struct ocfs2_extent_rec *rec, | ||
| 542 | u32 *p_cluster, u32 *num_clusters) | ||
| 543 | |||
| 544 | { | ||
| 545 | u32 coff = v_cluster - le32_to_cpu(rec->e_cpos); | ||
| 546 | |||
| 547 | *p_cluster = ocfs2_blocks_to_clusters(sb, le64_to_cpu(rec->e_blkno)); | ||
| 548 | *p_cluster = *p_cluster + coff; | ||
| 549 | |||
| 550 | if (num_clusters) | ||
| 551 | *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff; | ||
| 552 | } | ||
| 553 | |||
| 554 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | ||
| 555 | u32 *p_cluster, u32 *num_clusters, | ||
| 556 | unsigned int *extent_flags) | ||
| 557 | { | ||
| 558 | int ret; | ||
| 559 | unsigned int uninitialized_var(hole_len), flags = 0; | ||
| 560 | struct buffer_head *di_bh = NULL; | ||
| 561 | struct ocfs2_extent_rec rec; | ||
| 461 | 562 | ||
| 462 | coff = v_cluster - le32_to_cpu(rec->e_cpos); | 563 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { |
| 564 | ret = -ERANGE; | ||
| 565 | mlog_errno(ret); | ||
| 566 | goto out; | ||
| 567 | } | ||
| 463 | 568 | ||
| 464 | *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, | 569 | ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, |
| 465 | le64_to_cpu(rec->e_blkno)); | 570 | num_clusters, extent_flags); |
| 466 | *p_cluster = *p_cluster + coff; | 571 | if (ret == 0) |
| 572 | goto out; | ||
| 467 | 573 | ||
| 468 | if (num_clusters) | 574 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, |
| 469 | *num_clusters = ocfs2_rec_clusters(el, rec) - coff; | 575 | &di_bh, OCFS2_BH_CACHED, inode); |
| 576 | if (ret) { | ||
| 577 | mlog_errno(ret); | ||
| 578 | goto out; | ||
| 579 | } | ||
| 470 | 580 | ||
| 471 | flags = rec->e_flags; | 581 | ret = ocfs2_get_clusters_nocache(inode, di_bh, v_cluster, &hole_len, |
| 582 | &rec, NULL); | ||
| 583 | if (ret) { | ||
| 584 | mlog_errno(ret); | ||
| 585 | goto out; | ||
| 586 | } | ||
| 472 | 587 | ||
| 473 | ocfs2_extent_map_insert_rec(inode, rec); | 588 | if (rec.e_blkno == 0ULL) { |
| 589 | /* | ||
| 590 | * A hole was found. Return some canned values that | ||
| 591 | * callers can key on. If asked for, num_clusters will | ||
| 592 | * be populated with the size of the hole. | ||
| 593 | */ | ||
| 594 | *p_cluster = 0; | ||
| 595 | if (num_clusters) { | ||
| 596 | *num_clusters = hole_len; | ||
| 597 | } | ||
| 598 | } else { | ||
| 599 | ocfs2_relative_extent_offsets(inode->i_sb, v_cluster, &rec, | ||
| 600 | p_cluster, num_clusters); | ||
| 601 | flags = rec.e_flags; | ||
| 602 | |||
| 603 | ocfs2_extent_map_insert_rec(inode, &rec); | ||
| 474 | } | 604 | } |
| 475 | 605 | ||
| 476 | if (extent_flags) | 606 | if (extent_flags) |
| @@ -478,7 +608,6 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | |||
| 478 | 608 | ||
| 479 | out: | 609 | out: |
| 480 | brelse(di_bh); | 610 | brelse(di_bh); |
| 481 | brelse(eb_bh); | ||
| 482 | return ret; | 611 | return ret; |
| 483 | } | 612 | } |
| 484 | 613 | ||
| @@ -521,3 +650,114 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, | |||
| 521 | out: | 650 | out: |
| 522 | return ret; | 651 | return ret; |
| 523 | } | 652 | } |
| 653 | |||
| 654 | static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh, | ||
| 655 | struct fiemap_extent_info *fieinfo, | ||
| 656 | u64 map_start) | ||
| 657 | { | ||
| 658 | int ret; | ||
| 659 | unsigned int id_count; | ||
| 660 | struct ocfs2_dinode *di; | ||
| 661 | u64 phys; | ||
| 662 | u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST; | ||
| 663 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
| 664 | |||
| 665 | di = (struct ocfs2_dinode *)di_bh->b_data; | ||
| 666 | id_count = le16_to_cpu(di->id2.i_data.id_count); | ||
| 667 | |||
| 668 | if (map_start < id_count) { | ||
| 669 | phys = oi->ip_blkno << inode->i_sb->s_blocksize_bits; | ||
| 670 | phys += offsetof(struct ocfs2_dinode, id2.i_data.id_data); | ||
| 671 | |||
| 672 | ret = fiemap_fill_next_extent(fieinfo, 0, phys, id_count, | ||
| 673 | flags); | ||
| 674 | if (ret < 0) | ||
| 675 | return ret; | ||
| 676 | } | ||
| 677 | |||
| 678 | return 0; | ||
| 679 | } | ||
| 680 | |||
| 681 | #define OCFS2_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC) | ||
| 682 | |||
| 683 | int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
| 684 | u64 map_start, u64 map_len) | ||
| 685 | { | ||
| 686 | int ret, is_last; | ||
| 687 | u32 mapping_end, cpos; | ||
| 688 | unsigned int hole_size; | ||
| 689 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
| 690 | u64 len_bytes, phys_bytes, virt_bytes; | ||
| 691 | struct buffer_head *di_bh = NULL; | ||
| 692 | struct ocfs2_extent_rec rec; | ||
| 693 | |||
| 694 | ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS); | ||
| 695 | if (ret) | ||
| 696 | return ret; | ||
| 697 | |||
| 698 | ret = ocfs2_inode_lock(inode, &di_bh, 0); | ||
| 699 | if (ret) { | ||
| 700 | mlog_errno(ret); | ||
| 701 | goto out; | ||
| 702 | } | ||
| 703 | |||
| 704 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
| 705 | |||
| 706 | /* | ||
| 707 | * Handle inline-data separately. | ||
| 708 | */ | ||
| 709 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
| 710 | ret = ocfs2_fiemap_inline(inode, di_bh, fieinfo, map_start); | ||
| 711 | goto out_unlock; | ||
| 712 | } | ||
| 713 | |||
| 714 | cpos = map_start >> osb->s_clustersize_bits; | ||
| 715 | mapping_end = ocfs2_clusters_for_bytes(inode->i_sb, | ||
| 716 | map_start + map_len); | ||
| 717 | mapping_end -= cpos; | ||
| 718 | is_last = 0; | ||
| 719 | while (cpos < mapping_end && !is_last) { | ||
| 720 | u32 fe_flags; | ||
| 721 | |||
| 722 | ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, | ||
| 723 | &hole_size, &rec, &is_last); | ||
| 724 | if (ret) { | ||
| 725 | mlog_errno(ret); | ||
| 726 | goto out; | ||
| 727 | } | ||
| 728 | |||
| 729 | if (rec.e_blkno == 0ULL) { | ||
| 730 | cpos += hole_size; | ||
| 731 | continue; | ||
| 732 | } | ||
| 733 | |||
| 734 | fe_flags = 0; | ||
| 735 | if (rec.e_flags & OCFS2_EXT_UNWRITTEN) | ||
| 736 | fe_flags |= FIEMAP_EXTENT_UNWRITTEN; | ||
| 737 | if (is_last) | ||
| 738 | fe_flags |= FIEMAP_EXTENT_LAST; | ||
| 739 | len_bytes = (u64)le16_to_cpu(rec.e_leaf_clusters) << osb->s_clustersize_bits; | ||
| 740 | phys_bytes = le64_to_cpu(rec.e_blkno) << osb->sb->s_blocksize_bits; | ||
| 741 | virt_bytes = (u64)le32_to_cpu(rec.e_cpos) << osb->s_clustersize_bits; | ||
| 742 | |||
| 743 | ret = fiemap_fill_next_extent(fieinfo, virt_bytes, phys_bytes, | ||
| 744 | len_bytes, fe_flags); | ||
| 745 | if (ret) | ||
| 746 | break; | ||
| 747 | |||
| 748 | cpos = le32_to_cpu(rec.e_cpos)+ le16_to_cpu(rec.e_leaf_clusters); | ||
| 749 | } | ||
| 750 | |||
| 751 | if (ret > 0) | ||
| 752 | ret = 0; | ||
| 753 | |||
| 754 | out_unlock: | ||
| 755 | brelse(di_bh); | ||
| 756 | |||
| 757 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
| 758 | |||
| 759 | ocfs2_inode_unlock(inode, 0); | ||
| 760 | out: | ||
| 761 | |||
| 762 | return ret; | ||
| 763 | } | ||
