aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/refcounttree.c
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-23 23:12:02 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:30 -0400
commit8bf396de984e68491569b49770e4fd7aca40ba65 (patch)
tree1c755fa7af20e14722378df729201e6f8497fadb /fs/ocfs2/refcounttree.c
parent374a263e790c4de85844283c098810a92985f623 (diff)
ocfs2: Basic tree root operation.
Add basic refcount tree root operation. Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs/ocfs2/refcounttree.c')
-rw-r--r--fs/ocfs2/refcounttree.c345
1 files changed, 339 insertions, 6 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 8d79de8637b8..d0d6fa312b01 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -27,6 +27,7 @@
27#include "buffer_head_io.h" 27#include "buffer_head_io.h"
28#include "blockcheck.h" 28#include "blockcheck.h"
29#include "refcounttree.h" 29#include "refcounttree.h"
30#include "sysfile.h"
30#include "dlmglue.h" 31#include "dlmglue.h"
31 32
32static inline struct ocfs2_refcount_tree * 33static inline struct ocfs2_refcount_tree *
@@ -272,6 +273,22 @@ static inline void ocfs2_init_refcount_tree_lock(struct ocfs2_super *osb,
272 rf_blkno, generation); 273 rf_blkno, generation);
273} 274}
274 275
276static struct ocfs2_refcount_tree*
277ocfs2_allocate_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno)
278{
279 struct ocfs2_refcount_tree *new;
280
281 new = kzalloc(sizeof(struct ocfs2_refcount_tree), GFP_NOFS);
282 if (!new)
283 return NULL;
284
285 new->rf_blkno = rf_blkno;
286 kref_init(&new->rf_getcnt);
287 ocfs2_init_refcount_tree_ci(new, osb->sb);
288
289 return new;
290}
291
275static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno, 292static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno,
276 struct ocfs2_refcount_tree **ret_tree) 293 struct ocfs2_refcount_tree **ret_tree)
277{ 294{
@@ -291,16 +308,12 @@ static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno,
291 308
292 spin_unlock(&osb->osb_lock); 309 spin_unlock(&osb->osb_lock);
293 310
294 new = kzalloc(sizeof(struct ocfs2_refcount_tree), GFP_NOFS); 311 new = ocfs2_allocate_refcount_tree(osb, rf_blkno);
295 if (!new) { 312 if (!new) {
296 ret = -ENOMEM; 313 ret = -ENOMEM;
314 mlog_errno(ret);
297 return ret; 315 return ret;
298 } 316 }
299
300 new->rf_blkno = rf_blkno;
301 kref_init(&new->rf_getcnt);
302 ocfs2_init_refcount_tree_ci(new, osb->sb);
303
304 /* 317 /*
305 * We need the generation to create the refcount tree lock and since 318 * We need the generation to create the refcount tree lock and since
306 * it isn't changed during the tree modification, we are safe here to 319 * it isn't changed during the tree modification, we are safe here to
@@ -515,3 +528,323 @@ void ocfs2_purge_refcount_trees(struct ocfs2_super *osb)
515 ocfs2_free_refcount_tree(tree); 528 ocfs2_free_refcount_tree(tree);
516 } 529 }
517} 530}
531
532/*
533 * Create a refcount tree for an inode.
534 * We take for granted that the inode is already locked.
535 */
536static int ocfs2_create_refcount_tree(struct inode *inode,
537 struct buffer_head *di_bh)
538{
539 int ret;
540 handle_t *handle = NULL;
541 struct ocfs2_alloc_context *meta_ac = NULL;
542 struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
543 struct ocfs2_inode_info *oi = OCFS2_I(inode);
544 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
545 struct buffer_head *new_bh = NULL;
546 struct ocfs2_refcount_block *rb;
547 struct ocfs2_refcount_tree *new_tree = NULL, *tree = NULL;
548 u16 suballoc_bit_start;
549 u32 num_got;
550 u64 first_blkno;
551
552 BUG_ON(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL);
553
554 mlog(0, "create tree for inode %lu\n", inode->i_ino);
555
556 ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac);
557 if (ret) {
558 mlog_errno(ret);
559 goto out;
560 }
561
562 handle = ocfs2_start_trans(osb, OCFS2_REFCOUNT_TREE_CREATE_CREDITS);
563 if (IS_ERR(handle)) {
564 ret = PTR_ERR(handle);
565 mlog_errno(ret);
566 goto out;
567 }
568
569 ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
570 OCFS2_JOURNAL_ACCESS_WRITE);
571 if (ret) {
572 mlog_errno(ret);
573 goto out_commit;
574 }
575
576 ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1,
577 &suballoc_bit_start, &num_got,
578 &first_blkno);
579 if (ret) {
580 mlog_errno(ret);
581 goto out_commit;
582 }
583
584 new_tree = ocfs2_allocate_refcount_tree(osb, first_blkno);
585 if (!new_tree) {
586 ret = -ENOMEM;
587 mlog_errno(ret);
588 goto out_commit;
589 }
590
591 new_bh = sb_getblk(inode->i_sb, first_blkno);
592 ocfs2_set_new_buffer_uptodate(&new_tree->rf_ci, new_bh);
593
594 ret = ocfs2_journal_access_rb(handle, &new_tree->rf_ci, new_bh,
595 OCFS2_JOURNAL_ACCESS_CREATE);
596 if (ret) {
597 mlog_errno(ret);
598 goto out_commit;
599 }
600
601 /* Initialize ocfs2_refcount_block. */
602 rb = (struct ocfs2_refcount_block *)new_bh->b_data;
603 memset(rb, 0, inode->i_sb->s_blocksize);
604 strcpy((void *)rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE);
605 rb->rf_suballoc_slot = cpu_to_le16(osb->slot_num);
606 rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);
607 rb->rf_fs_generation = cpu_to_le32(osb->fs_generation);
608 rb->rf_blkno = cpu_to_le64(first_blkno);
609 rb->rf_count = cpu_to_le32(1);
610 rb->rf_records.rl_count =
611 cpu_to_le16(ocfs2_refcount_recs_per_rb(osb->sb));
612 spin_lock(&osb->osb_lock);
613 rb->rf_generation = osb->s_next_generation++;
614 spin_unlock(&osb->osb_lock);
615
616 ocfs2_journal_dirty(handle, new_bh);
617
618 spin_lock(&oi->ip_lock);
619 oi->ip_dyn_features |= OCFS2_HAS_REFCOUNT_FL;
620 di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
621 di->i_refcount_loc = cpu_to_le64(first_blkno);
622 spin_unlock(&oi->ip_lock);
623
624 mlog(0, "created tree for inode %lu, refblock %llu\n",
625 inode->i_ino, (unsigned long long)first_blkno);
626
627 ocfs2_journal_dirty(handle, di_bh);
628
629 /*
630 * We have to init the tree lock here since it will use
631 * the generation number to create it.
632 */
633 new_tree->rf_generation = le32_to_cpu(rb->rf_generation);
634 ocfs2_init_refcount_tree_lock(osb, new_tree, first_blkno,
635 new_tree->rf_generation);
636
637 spin_lock(&osb->osb_lock);
638 tree = ocfs2_find_refcount_tree(osb, first_blkno);
639
640 /*
641 * We've just created a new refcount tree in this block. If
642 * we found a refcount tree on the ocfs2_super, it must be
643 * one we just deleted. We free the old tree before
644 * inserting the new tree.
645 */
646 BUG_ON(tree && tree->rf_generation == new_tree->rf_generation);
647 if (tree)
648 ocfs2_erase_refcount_tree_from_list_no_lock(osb, tree);
649 ocfs2_insert_refcount_tree(osb, new_tree);
650 spin_unlock(&osb->osb_lock);
651 new_tree = NULL;
652 if (tree)
653 ocfs2_refcount_tree_put(tree);
654
655out_commit:
656 ocfs2_commit_trans(osb, handle);
657
658out:
659 if (new_tree) {
660 ocfs2_metadata_cache_exit(&new_tree->rf_ci);
661 kfree(new_tree);
662 }
663
664 brelse(new_bh);
665 if (meta_ac)
666 ocfs2_free_alloc_context(meta_ac);
667
668 return ret;
669}
670
671static int ocfs2_set_refcount_tree(struct inode *inode,
672 struct buffer_head *di_bh,
673 u64 refcount_loc)
674{
675 int ret;
676 handle_t *handle = NULL;
677 struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
678 struct ocfs2_inode_info *oi = OCFS2_I(inode);
679 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
680 struct buffer_head *ref_root_bh = NULL;
681 struct ocfs2_refcount_block *rb;
682 struct ocfs2_refcount_tree *ref_tree;
683
684 BUG_ON(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL);
685
686 ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1,
687 &ref_tree, &ref_root_bh);
688 if (ret) {
689 mlog_errno(ret);
690 return ret;
691 }
692
693 handle = ocfs2_start_trans(osb, OCFS2_REFCOUNT_TREE_SET_CREDITS);
694 if (IS_ERR(handle)) {
695 ret = PTR_ERR(handle);
696 mlog_errno(ret);
697 goto out;
698 }
699
700 ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
701 OCFS2_JOURNAL_ACCESS_WRITE);
702 if (ret) {
703 mlog_errno(ret);
704 goto out_commit;
705 }
706
707 ret = ocfs2_journal_access_rb(handle, &ref_tree->rf_ci, ref_root_bh,
708 OCFS2_JOURNAL_ACCESS_WRITE);
709 if (ret) {
710 mlog_errno(ret);
711 goto out_commit;
712 }
713
714 rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data;
715 le32_add_cpu(&rb->rf_count, 1);
716
717 ocfs2_journal_dirty(handle, ref_root_bh);
718
719 spin_lock(&oi->ip_lock);
720 oi->ip_dyn_features |= OCFS2_HAS_REFCOUNT_FL;
721 di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
722 di->i_refcount_loc = cpu_to_le64(refcount_loc);
723 spin_unlock(&oi->ip_lock);
724 ocfs2_journal_dirty(handle, di_bh);
725
726out_commit:
727 ocfs2_commit_trans(osb, handle);
728out:
729 ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
730 brelse(ref_root_bh);
731
732 return ret;
733}
734
735int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh)
736{
737 int ret, delete_tree = 0;
738 handle_t *handle = NULL;
739 struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
740 struct ocfs2_inode_info *oi = OCFS2_I(inode);
741 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
742 struct ocfs2_refcount_block *rb;
743 struct inode *alloc_inode = NULL;
744 struct buffer_head *alloc_bh = NULL;
745 struct buffer_head *blk_bh = NULL;
746 struct ocfs2_refcount_tree *ref_tree;
747 int credits = OCFS2_REFCOUNT_TREE_REMOVE_CREDITS;
748 u64 blk = 0, bg_blkno = 0, ref_blkno = le64_to_cpu(di->i_refcount_loc);
749 u16 bit = 0;
750
751 if (!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL))
752 return 0;
753
754 BUG_ON(!ref_blkno);
755 ret = ocfs2_lock_refcount_tree(osb, ref_blkno, 1, &ref_tree, &blk_bh);
756 if (ret) {
757 mlog_errno(ret);
758 return ret;
759 }
760
761 rb = (struct ocfs2_refcount_block *)blk_bh->b_data;
762
763 /*
764 * If we are the last user, we need to free the block.
765 * So lock the allocator ahead.
766 */
767 if (le32_to_cpu(rb->rf_count) == 1) {
768 blk = le64_to_cpu(rb->rf_blkno);
769 bit = le16_to_cpu(rb->rf_suballoc_bit);
770 bg_blkno = ocfs2_which_suballoc_group(blk, bit);
771
772 alloc_inode = ocfs2_get_system_file_inode(osb,
773 EXTENT_ALLOC_SYSTEM_INODE,
774 le16_to_cpu(rb->rf_suballoc_slot));
775 if (!alloc_inode) {
776 ret = -ENOMEM;
777 mlog_errno(ret);
778 goto out;
779 }
780 mutex_lock(&alloc_inode->i_mutex);
781
782 ret = ocfs2_inode_lock(alloc_inode, &alloc_bh, 1);
783 if (ret) {
784 mlog_errno(ret);
785 goto out_mutex;
786 }
787
788 credits += OCFS2_SUBALLOC_FREE;
789 }
790
791 handle = ocfs2_start_trans(osb, credits);
792 if (IS_ERR(handle)) {
793 ret = PTR_ERR(handle);
794 mlog_errno(ret);
795 goto out_unlock;
796 }
797
798 ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
799 OCFS2_JOURNAL_ACCESS_WRITE);
800 if (ret) {
801 mlog_errno(ret);
802 goto out_commit;
803 }
804
805 ret = ocfs2_journal_access_rb(handle, &ref_tree->rf_ci, blk_bh,
806 OCFS2_JOURNAL_ACCESS_WRITE);
807 if (ret) {
808 mlog_errno(ret);
809 goto out_commit;
810 }
811
812 spin_lock(&oi->ip_lock);
813 oi->ip_dyn_features &= ~OCFS2_HAS_REFCOUNT_FL;
814 di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
815 di->i_refcount_loc = 0;
816 spin_unlock(&oi->ip_lock);
817 ocfs2_journal_dirty(handle, di_bh);
818
819 le32_add_cpu(&rb->rf_count , -1);
820 ocfs2_journal_dirty(handle, blk_bh);
821
822 if (!rb->rf_count) {
823 delete_tree = 1;
824 ocfs2_erase_refcount_tree_from_list(osb, ref_tree);
825 ret = ocfs2_free_suballoc_bits(handle, alloc_inode,
826 alloc_bh, bit, bg_blkno, 1);
827 if (ret)
828 mlog_errno(ret);
829 }
830
831out_commit:
832 ocfs2_commit_trans(osb, handle);
833out_unlock:
834 if (alloc_inode) {
835 ocfs2_inode_unlock(alloc_inode, 1);
836 brelse(alloc_bh);
837 }
838out_mutex:
839 if (alloc_inode) {
840 mutex_unlock(&alloc_inode->i_mutex);
841 iput(alloc_inode);
842 }
843out:
844 ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
845 if (delete_tree)
846 ocfs2_refcount_tree_put(ref_tree);
847 brelse(blk_bh);
848
849 return ret;
850}