diff options
Diffstat (limited to 'fs/ocfs2/extent_map.c')
-rw-r--r-- | fs/ocfs2/extent_map.c | 386 |
1 files changed, 342 insertions, 44 deletions
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index c58668a326fe..2baedac58234 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,50 @@ 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(inode, last_eb_blk, &eb_bh); | ||
297 | if (ret) { | ||
298 | mlog_errno(ret); | ||
299 | goto out; | ||
300 | } | ||
301 | |||
302 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; | ||
303 | el = &eb->h_list; | ||
304 | |||
305 | if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { | ||
306 | ret = -EROFS; | ||
307 | OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); | ||
308 | goto out; | ||
309 | } | ||
310 | |||
311 | if (el->l_tree_depth) { | ||
312 | ocfs2_error(inode->i_sb, | ||
313 | "Inode %lu has non zero tree depth in " | ||
314 | "leaf block %llu\n", inode->i_ino, | ||
315 | (unsigned long long)eb_bh->b_blocknr); | ||
316 | ret = -EROFS; | ||
317 | goto out; | ||
318 | } | ||
319 | |||
320 | next_free = le16_to_cpu(el->l_next_free_rec); | ||
321 | |||
322 | if (next_free == 0 || | ||
323 | (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) | ||
324 | ret = 1; | ||
325 | |||
326 | out: | ||
327 | brelse(eb_bh); | ||
328 | return ret; | ||
329 | } | ||
330 | |||
285 | /* | 331 | /* |
286 | * Return the 1st index within el which contains an extent start | 332 | * Return the 1st index within el which contains an extent start |
287 | * larger than v_cluster. | 333 | * larger than v_cluster. |
@@ -335,9 +381,9 @@ static int ocfs2_figure_hole_clusters(struct inode *inode, | |||
335 | if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) | 381 | if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) |
336 | goto no_more_extents; | 382 | goto no_more_extents; |
337 | 383 | ||
338 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | 384 | ret = ocfs2_read_block(inode, |
339 | le64_to_cpu(eb->h_next_leaf_blk), | 385 | le64_to_cpu(eb->h_next_leaf_blk), |
340 | &next_eb_bh, OCFS2_BH_CACHED, inode); | 386 | &next_eb_bh); |
341 | if (ret) { | 387 | if (ret) { |
342 | mlog_errno(ret); | 388 | mlog_errno(ret); |
343 | goto out; | 389 | goto out; |
@@ -373,42 +419,28 @@ out: | |||
373 | return ret; | 419 | return ret; |
374 | } | 420 | } |
375 | 421 | ||
376 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | 422 | static int ocfs2_get_clusters_nocache(struct inode *inode, |
377 | u32 *p_cluster, u32 *num_clusters, | 423 | struct buffer_head *di_bh, |
378 | unsigned int *extent_flags) | 424 | u32 v_cluster, unsigned int *hole_len, |
425 | struct ocfs2_extent_rec *ret_rec, | ||
426 | unsigned int *is_last) | ||
379 | { | 427 | { |
380 | int ret, i; | 428 | 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; | 429 | struct ocfs2_dinode *di; |
385 | struct ocfs2_extent_block *eb; | 430 | struct ocfs2_extent_block *uninitialized_var(eb); |
386 | struct ocfs2_extent_list *el; | 431 | struct ocfs2_extent_list *el; |
387 | struct ocfs2_extent_rec *rec; | 432 | struct ocfs2_extent_rec *rec; |
388 | u32 coff; | 433 | 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 | 434 | ||
401 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, | 435 | memset(ret_rec, 0, sizeof(*ret_rec)); |
402 | &di_bh, OCFS2_BH_CACHED, inode); | 436 | if (is_last) |
403 | if (ret) { | 437 | *is_last = 0; |
404 | mlog_errno(ret); | ||
405 | goto out; | ||
406 | } | ||
407 | 438 | ||
408 | di = (struct ocfs2_dinode *) di_bh->b_data; | 439 | di = (struct ocfs2_dinode *) di_bh->b_data; |
409 | el = &di->id2.i_list; | 440 | el = &di->id2.i_list; |
441 | tree_height = le16_to_cpu(el->l_tree_depth); | ||
410 | 442 | ||
411 | if (el->l_tree_depth) { | 443 | if (tree_height > 0) { |
412 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | 444 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); |
413 | if (ret) { | 445 | if (ret) { |
414 | mlog_errno(ret); | 446 | mlog_errno(ret); |
@@ -431,46 +463,202 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | |||
431 | i = ocfs2_search_extent_list(el, v_cluster); | 463 | i = ocfs2_search_extent_list(el, v_cluster); |
432 | if (i == -1) { | 464 | if (i == -1) { |
433 | /* | 465 | /* |
434 | * A hole was found. Return some canned values that | 466 | * Holes can be larger than the maximum size of an |
435 | * callers can key on. If asked for, num_clusters will | 467 | * extent, so we return their lengths in a seperate |
436 | * be populated with the size of the hole. | 468 | * field. |
437 | */ | 469 | */ |
438 | *p_cluster = 0; | 470 | if (hole_len) { |
439 | if (num_clusters) { | ||
440 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, | 471 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, |
441 | v_cluster, | 472 | v_cluster, &len); |
442 | num_clusters); | ||
443 | if (ret) { | 473 | if (ret) { |
444 | mlog_errno(ret); | 474 | mlog_errno(ret); |
445 | goto out; | 475 | goto out; |
446 | } | 476 | } |
477 | |||
478 | *hole_len = len; | ||
479 | } | ||
480 | goto out_hole; | ||
481 | } | ||
482 | |||
483 | rec = &el->l_recs[i]; | ||
484 | |||
485 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); | ||
486 | |||
487 | if (!rec->e_blkno) { | ||
488 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " | ||
489 | "record (%u, %u, 0)", inode->i_ino, | ||
490 | le32_to_cpu(rec->e_cpos), | ||
491 | ocfs2_rec_clusters(el, rec)); | ||
492 | ret = -EROFS; | ||
493 | goto out; | ||
494 | } | ||
495 | |||
496 | *ret_rec = *rec; | ||
497 | |||
498 | /* | ||
499 | * Checking for last extent is potentially expensive - we | ||
500 | * might have to look at the next leaf over to see if it's | ||
501 | * empty. | ||
502 | * | ||
503 | * The first two checks are to see whether the caller even | ||
504 | * cares for this information, and if the extent is at least | ||
505 | * the last in it's list. | ||
506 | * | ||
507 | * If those hold true, then the extent is last if any of the | ||
508 | * additional conditions hold true: | ||
509 | * - Extent list is in-inode | ||
510 | * - Extent list is right-most | ||
511 | * - Extent list is 2nd to rightmost, with empty right-most | ||
512 | */ | ||
513 | if (is_last) { | ||
514 | if (i == (le16_to_cpu(el->l_next_free_rec) - 1)) { | ||
515 | if (tree_height == 0) | ||
516 | *is_last = 1; | ||
517 | else if (eb->h_blkno == di->i_last_eb_blk) | ||
518 | *is_last = 1; | ||
519 | else if (eb->h_next_leaf_blk == di->i_last_eb_blk) { | ||
520 | ret = ocfs2_last_eb_is_empty(inode, di); | ||
521 | if (ret < 0) { | ||
522 | mlog_errno(ret); | ||
523 | goto out; | ||
524 | } | ||
525 | if (ret == 1) | ||
526 | *is_last = 1; | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | |||
531 | out_hole: | ||
532 | ret = 0; | ||
533 | out: | ||
534 | brelse(eb_bh); | ||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | static void ocfs2_relative_extent_offsets(struct super_block *sb, | ||
539 | u32 v_cluster, | ||
540 | struct ocfs2_extent_rec *rec, | ||
541 | u32 *p_cluster, u32 *num_clusters) | ||
542 | |||
543 | { | ||
544 | u32 coff = v_cluster - le32_to_cpu(rec->e_cpos); | ||
545 | |||
546 | *p_cluster = ocfs2_blocks_to_clusters(sb, le64_to_cpu(rec->e_blkno)); | ||
547 | *p_cluster = *p_cluster + coff; | ||
548 | |||
549 | if (num_clusters) | ||
550 | *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff; | ||
551 | } | ||
552 | |||
553 | int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, | ||
554 | u32 *p_cluster, u32 *num_clusters, | ||
555 | struct ocfs2_extent_list *el) | ||
556 | { | ||
557 | int ret = 0, i; | ||
558 | struct buffer_head *eb_bh = NULL; | ||
559 | struct ocfs2_extent_block *eb; | ||
560 | struct ocfs2_extent_rec *rec; | ||
561 | u32 coff; | ||
562 | |||
563 | if (el->l_tree_depth) { | ||
564 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | ||
565 | if (ret) { | ||
566 | mlog_errno(ret); | ||
567 | goto out; | ||
447 | } | 568 | } |
569 | |||
570 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; | ||
571 | el = &eb->h_list; | ||
572 | |||
573 | if (el->l_tree_depth) { | ||
574 | ocfs2_error(inode->i_sb, | ||
575 | "Inode %lu has non zero tree depth in " | ||
576 | "xattr leaf block %llu\n", inode->i_ino, | ||
577 | (unsigned long long)eb_bh->b_blocknr); | ||
578 | ret = -EROFS; | ||
579 | goto out; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | i = ocfs2_search_extent_list(el, v_cluster); | ||
584 | if (i == -1) { | ||
585 | ret = -EROFS; | ||
586 | mlog_errno(ret); | ||
587 | goto out; | ||
448 | } else { | 588 | } else { |
449 | rec = &el->l_recs[i]; | 589 | rec = &el->l_recs[i]; |
450 | |||
451 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); | 590 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); |
452 | 591 | ||
453 | if (!rec->e_blkno) { | 592 | if (!rec->e_blkno) { |
454 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " | 593 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " |
455 | "record (%u, %u, 0)", inode->i_ino, | 594 | "record (%u, %u, 0) in xattr", inode->i_ino, |
456 | le32_to_cpu(rec->e_cpos), | 595 | le32_to_cpu(rec->e_cpos), |
457 | ocfs2_rec_clusters(el, rec)); | 596 | ocfs2_rec_clusters(el, rec)); |
458 | ret = -EROFS; | 597 | ret = -EROFS; |
459 | goto out; | 598 | goto out; |
460 | } | 599 | } |
461 | |||
462 | coff = v_cluster - le32_to_cpu(rec->e_cpos); | 600 | coff = v_cluster - le32_to_cpu(rec->e_cpos); |
463 | |||
464 | *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, | 601 | *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, |
465 | le64_to_cpu(rec->e_blkno)); | 602 | le64_to_cpu(rec->e_blkno)); |
466 | *p_cluster = *p_cluster + coff; | 603 | *p_cluster = *p_cluster + coff; |
467 | |||
468 | if (num_clusters) | 604 | if (num_clusters) |
469 | *num_clusters = ocfs2_rec_clusters(el, rec) - coff; | 605 | *num_clusters = ocfs2_rec_clusters(el, rec) - coff; |
606 | } | ||
607 | out: | ||
608 | if (eb_bh) | ||
609 | brelse(eb_bh); | ||
610 | return ret; | ||
611 | } | ||
612 | |||
613 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | ||
614 | u32 *p_cluster, u32 *num_clusters, | ||
615 | unsigned int *extent_flags) | ||
616 | { | ||
617 | int ret; | ||
618 | unsigned int uninitialized_var(hole_len), flags = 0; | ||
619 | struct buffer_head *di_bh = NULL; | ||
620 | struct ocfs2_extent_rec rec; | ||
621 | |||
622 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
623 | ret = -ERANGE; | ||
624 | mlog_errno(ret); | ||
625 | goto out; | ||
626 | } | ||
627 | |||
628 | ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, | ||
629 | num_clusters, extent_flags); | ||
630 | if (ret == 0) | ||
631 | goto out; | ||
632 | |||
633 | ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh); | ||
634 | if (ret) { | ||
635 | mlog_errno(ret); | ||
636 | goto out; | ||
637 | } | ||
470 | 638 | ||
471 | flags = rec->e_flags; | 639 | ret = ocfs2_get_clusters_nocache(inode, di_bh, v_cluster, &hole_len, |
640 | &rec, NULL); | ||
641 | if (ret) { | ||
642 | mlog_errno(ret); | ||
643 | goto out; | ||
644 | } | ||
645 | |||
646 | if (rec.e_blkno == 0ULL) { | ||
647 | /* | ||
648 | * A hole was found. Return some canned values that | ||
649 | * callers can key on. If asked for, num_clusters will | ||
650 | * be populated with the size of the hole. | ||
651 | */ | ||
652 | *p_cluster = 0; | ||
653 | if (num_clusters) { | ||
654 | *num_clusters = hole_len; | ||
655 | } | ||
656 | } else { | ||
657 | ocfs2_relative_extent_offsets(inode->i_sb, v_cluster, &rec, | ||
658 | p_cluster, num_clusters); | ||
659 | flags = rec.e_flags; | ||
472 | 660 | ||
473 | ocfs2_extent_map_insert_rec(inode, rec); | 661 | ocfs2_extent_map_insert_rec(inode, &rec); |
474 | } | 662 | } |
475 | 663 | ||
476 | if (extent_flags) | 664 | if (extent_flags) |
@@ -478,7 +666,6 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | |||
478 | 666 | ||
479 | out: | 667 | out: |
480 | brelse(di_bh); | 668 | brelse(di_bh); |
481 | brelse(eb_bh); | ||
482 | return ret; | 669 | return ret; |
483 | } | 670 | } |
484 | 671 | ||
@@ -521,3 +708,114 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, | |||
521 | out: | 708 | out: |
522 | return ret; | 709 | return ret; |
523 | } | 710 | } |
711 | |||
712 | static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh, | ||
713 | struct fiemap_extent_info *fieinfo, | ||
714 | u64 map_start) | ||
715 | { | ||
716 | int ret; | ||
717 | unsigned int id_count; | ||
718 | struct ocfs2_dinode *di; | ||
719 | u64 phys; | ||
720 | u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST; | ||
721 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
722 | |||
723 | di = (struct ocfs2_dinode *)di_bh->b_data; | ||
724 | id_count = le16_to_cpu(di->id2.i_data.id_count); | ||
725 | |||
726 | if (map_start < id_count) { | ||
727 | phys = oi->ip_blkno << inode->i_sb->s_blocksize_bits; | ||
728 | phys += offsetof(struct ocfs2_dinode, id2.i_data.id_data); | ||
729 | |||
730 | ret = fiemap_fill_next_extent(fieinfo, 0, phys, id_count, | ||
731 | flags); | ||
732 | if (ret < 0) | ||
733 | return ret; | ||
734 | } | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | #define OCFS2_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC) | ||
740 | |||
741 | int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
742 | u64 map_start, u64 map_len) | ||
743 | { | ||
744 | int ret, is_last; | ||
745 | u32 mapping_end, cpos; | ||
746 | unsigned int hole_size; | ||
747 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
748 | u64 len_bytes, phys_bytes, virt_bytes; | ||
749 | struct buffer_head *di_bh = NULL; | ||
750 | struct ocfs2_extent_rec rec; | ||
751 | |||
752 | ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS); | ||
753 | if (ret) | ||
754 | return ret; | ||
755 | |||
756 | ret = ocfs2_inode_lock(inode, &di_bh, 0); | ||
757 | if (ret) { | ||
758 | mlog_errno(ret); | ||
759 | goto out; | ||
760 | } | ||
761 | |||
762 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
763 | |||
764 | /* | ||
765 | * Handle inline-data separately. | ||
766 | */ | ||
767 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
768 | ret = ocfs2_fiemap_inline(inode, di_bh, fieinfo, map_start); | ||
769 | goto out_unlock; | ||
770 | } | ||
771 | |||
772 | cpos = map_start >> osb->s_clustersize_bits; | ||
773 | mapping_end = ocfs2_clusters_for_bytes(inode->i_sb, | ||
774 | map_start + map_len); | ||
775 | mapping_end -= cpos; | ||
776 | is_last = 0; | ||
777 | while (cpos < mapping_end && !is_last) { | ||
778 | u32 fe_flags; | ||
779 | |||
780 | ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, | ||
781 | &hole_size, &rec, &is_last); | ||
782 | if (ret) { | ||
783 | mlog_errno(ret); | ||
784 | goto out; | ||
785 | } | ||
786 | |||
787 | if (rec.e_blkno == 0ULL) { | ||
788 | cpos += hole_size; | ||
789 | continue; | ||
790 | } | ||
791 | |||
792 | fe_flags = 0; | ||
793 | if (rec.e_flags & OCFS2_EXT_UNWRITTEN) | ||
794 | fe_flags |= FIEMAP_EXTENT_UNWRITTEN; | ||
795 | if (is_last) | ||
796 | fe_flags |= FIEMAP_EXTENT_LAST; | ||
797 | len_bytes = (u64)le16_to_cpu(rec.e_leaf_clusters) << osb->s_clustersize_bits; | ||
798 | phys_bytes = le64_to_cpu(rec.e_blkno) << osb->sb->s_blocksize_bits; | ||
799 | virt_bytes = (u64)le32_to_cpu(rec.e_cpos) << osb->s_clustersize_bits; | ||
800 | |||
801 | ret = fiemap_fill_next_extent(fieinfo, virt_bytes, phys_bytes, | ||
802 | len_bytes, fe_flags); | ||
803 | if (ret) | ||
804 | break; | ||
805 | |||
806 | cpos = le32_to_cpu(rec.e_cpos)+ le16_to_cpu(rec.e_leaf_clusters); | ||
807 | } | ||
808 | |||
809 | if (ret > 0) | ||
810 | ret = 0; | ||
811 | |||
812 | out_unlock: | ||
813 | brelse(di_bh); | ||
814 | |||
815 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
816 | |||
817 | ocfs2_inode_unlock(inode, 0); | ||
818 | out: | ||
819 | |||
820 | return ret; | ||
821 | } | ||