diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/refcounttree.c | 29 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 7 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 291 | ||||
-rw-r--r-- | fs/ocfs2/xattr.h | 6 |
4 files changed, 329 insertions, 4 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index a5b5bef054a7..a85c01c6629d 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -3547,7 +3547,8 @@ int ocfs2_add_refcount_flag(struct inode *inode, | |||
3547 | struct ocfs2_caching_info *ref_ci, | 3547 | struct ocfs2_caching_info *ref_ci, |
3548 | struct buffer_head *ref_root_bh, | 3548 | struct buffer_head *ref_root_bh, |
3549 | u32 cpos, u32 p_cluster, u32 num_clusters, | 3549 | u32 cpos, u32 p_cluster, u32 num_clusters, |
3550 | struct ocfs2_cached_dealloc_ctxt *dealloc) | 3550 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
3551 | struct ocfs2_post_refcount *post) | ||
3551 | { | 3552 | { |
3552 | int ret; | 3553 | int ret; |
3553 | handle_t *handle; | 3554 | handle_t *handle; |
@@ -3576,6 +3577,9 @@ int ocfs2_add_refcount_flag(struct inode *inode, | |||
3576 | } | 3577 | } |
3577 | } | 3578 | } |
3578 | 3579 | ||
3580 | if (post) | ||
3581 | credits += post->credits; | ||
3582 | |||
3579 | handle = ocfs2_start_trans(osb, credits); | 3583 | handle = ocfs2_start_trans(osb, credits); |
3580 | if (IS_ERR(handle)) { | 3584 | if (IS_ERR(handle)) { |
3581 | ret = PTR_ERR(handle); | 3585 | ret = PTR_ERR(handle); |
@@ -3594,8 +3598,16 @@ int ocfs2_add_refcount_flag(struct inode *inode, | |||
3594 | ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh, | 3598 | ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh, |
3595 | p_cluster, num_clusters, | 3599 | p_cluster, num_clusters, |
3596 | meta_ac, dealloc); | 3600 | meta_ac, dealloc); |
3597 | if (ret) | 3601 | if (ret) { |
3598 | mlog_errno(ret); | 3602 | mlog_errno(ret); |
3603 | goto out_commit; | ||
3604 | } | ||
3605 | |||
3606 | if (post && post->func) { | ||
3607 | ret = post->func(inode, handle, post->para); | ||
3608 | if (ret) | ||
3609 | mlog_errno(ret); | ||
3610 | } | ||
3599 | 3611 | ||
3600 | out_commit: | 3612 | out_commit: |
3601 | ocfs2_commit_trans(osb, handle); | 3613 | ocfs2_commit_trans(osb, handle); |
@@ -3688,7 +3700,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, | |||
3688 | &ref_tree->rf_ci, | 3700 | &ref_tree->rf_ci, |
3689 | ref_root_bh, cpos, | 3701 | ref_root_bh, cpos, |
3690 | p_cluster, num_clusters, | 3702 | p_cluster, num_clusters, |
3691 | &dealloc); | 3703 | &dealloc, NULL); |
3692 | if (ret) { | 3704 | if (ret) { |
3693 | mlog_errno(ret); | 3705 | mlog_errno(ret); |
3694 | goto unlock; | 3706 | goto unlock; |
@@ -3699,6 +3711,17 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, | |||
3699 | cpos += num_clusters; | 3711 | cpos += num_clusters; |
3700 | } | 3712 | } |
3701 | 3713 | ||
3714 | if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) { | ||
3715 | ret = ocfs2_xattr_attach_refcount_tree(inode, di_bh, | ||
3716 | &ref_tree->rf_ci, | ||
3717 | ref_root_bh, | ||
3718 | &dealloc); | ||
3719 | if (ret) { | ||
3720 | mlog_errno(ret); | ||
3721 | goto unlock; | ||
3722 | } | ||
3723 | } | ||
3724 | |||
3702 | if (data_changed) { | 3725 | if (data_changed) { |
3703 | ret = ocfs2_change_ctime(inode, di_bh); | 3726 | ret = ocfs2_change_ctime(inode, di_bh); |
3704 | if (ret) | 3727 | if (ret) |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index d09d64b29810..7d6900c904d4 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -83,4 +83,11 @@ int ocfs2_refcount_cow_xattr(struct inode *inode, | |||
83 | struct buffer_head *ref_root_bh, | 83 | struct buffer_head *ref_root_bh, |
84 | u32 cpos, u32 write_len, | 84 | u32 cpos, u32 write_len, |
85 | struct ocfs2_post_refcount *post); | 85 | struct ocfs2_post_refcount *post); |
86 | int ocfs2_add_refcount_flag(struct inode *inode, | ||
87 | struct ocfs2_extent_tree *data_et, | ||
88 | struct ocfs2_caching_info *ref_ci, | ||
89 | struct buffer_head *ref_root_bh, | ||
90 | u32 cpos, u32 p_cluster, u32 num_clusters, | ||
91 | struct ocfs2_cached_dealloc_ctxt *dealloc, | ||
92 | struct ocfs2_post_refcount *post); | ||
86 | #endif /* OCFS2_REFCOUNTTREE_H */ | 93 | #endif /* OCFS2_REFCOUNTTREE_H */ |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index bfa7ee208855..501539a733f4 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -5551,6 +5551,297 @@ out: | |||
5551 | } | 5551 | } |
5552 | 5552 | ||
5553 | /* | 5553 | /* |
5554 | * Add the REFCOUNTED flags for all the extent rec in ocfs2_xattr_value_root. | ||
5555 | * The physical clusters will be added to refcount tree. | ||
5556 | */ | ||
5557 | static int ocfs2_xattr_value_attach_refcount(struct inode *inode, | ||
5558 | struct ocfs2_xattr_value_root *xv, | ||
5559 | struct ocfs2_extent_tree *value_et, | ||
5560 | struct ocfs2_caching_info *ref_ci, | ||
5561 | struct buffer_head *ref_root_bh, | ||
5562 | struct ocfs2_cached_dealloc_ctxt *dealloc, | ||
5563 | struct ocfs2_post_refcount *refcount) | ||
5564 | { | ||
5565 | int ret = 0; | ||
5566 | u32 clusters = le32_to_cpu(xv->xr_clusters); | ||
5567 | u32 cpos, p_cluster, num_clusters; | ||
5568 | struct ocfs2_extent_list *el = &xv->xr_list; | ||
5569 | unsigned int ext_flags; | ||
5570 | |||
5571 | cpos = 0; | ||
5572 | while (cpos < clusters) { | ||
5573 | ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster, | ||
5574 | &num_clusters, el, &ext_flags); | ||
5575 | |||
5576 | cpos += num_clusters; | ||
5577 | if ((ext_flags & OCFS2_EXT_REFCOUNTED)) | ||
5578 | continue; | ||
5579 | |||
5580 | BUG_ON(!p_cluster); | ||
5581 | |||
5582 | ret = ocfs2_add_refcount_flag(inode, value_et, | ||
5583 | ref_ci, ref_root_bh, | ||
5584 | cpos - num_clusters, | ||
5585 | p_cluster, num_clusters, | ||
5586 | dealloc, refcount); | ||
5587 | if (ret) { | ||
5588 | mlog_errno(ret); | ||
5589 | break; | ||
5590 | } | ||
5591 | } | ||
5592 | |||
5593 | return ret; | ||
5594 | } | ||
5595 | |||
5596 | /* | ||
5597 | * Given a normal ocfs2_xattr_header, refcount all the entries which | ||
5598 | * have value stored outside. | ||
5599 | * Used for xattrs stored in inode and ocfs2_xattr_block. | ||
5600 | */ | ||
5601 | static int ocfs2_xattr_attach_refcount_normal(struct inode *inode, | ||
5602 | struct ocfs2_xattr_value_buf *vb, | ||
5603 | struct ocfs2_xattr_header *header, | ||
5604 | struct ocfs2_caching_info *ref_ci, | ||
5605 | struct buffer_head *ref_root_bh, | ||
5606 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
5607 | { | ||
5608 | |||
5609 | struct ocfs2_xattr_entry *xe; | ||
5610 | struct ocfs2_xattr_value_root *xv; | ||
5611 | struct ocfs2_extent_tree et; | ||
5612 | int i, ret = 0; | ||
5613 | |||
5614 | for (i = 0; i < le16_to_cpu(header->xh_count); i++) { | ||
5615 | xe = &header->xh_entries[i]; | ||
5616 | |||
5617 | if (ocfs2_xattr_is_local(xe)) | ||
5618 | continue; | ||
5619 | |||
5620 | xv = (struct ocfs2_xattr_value_root *)((void *)header + | ||
5621 | le16_to_cpu(xe->xe_name_offset) + | ||
5622 | OCFS2_XATTR_SIZE(xe->xe_name_len)); | ||
5623 | |||
5624 | vb->vb_xv = xv; | ||
5625 | ocfs2_init_xattr_value_extent_tree(&et, INODE_CACHE(inode), vb); | ||
5626 | |||
5627 | ret = ocfs2_xattr_value_attach_refcount(inode, xv, &et, | ||
5628 | ref_ci, ref_root_bh, | ||
5629 | dealloc, NULL); | ||
5630 | if (ret) { | ||
5631 | mlog_errno(ret); | ||
5632 | break; | ||
5633 | } | ||
5634 | } | ||
5635 | |||
5636 | return ret; | ||
5637 | } | ||
5638 | |||
5639 | static int ocfs2_xattr_inline_attach_refcount(struct inode *inode, | ||
5640 | struct buffer_head *fe_bh, | ||
5641 | struct ocfs2_caching_info *ref_ci, | ||
5642 | struct buffer_head *ref_root_bh, | ||
5643 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
5644 | { | ||
5645 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data; | ||
5646 | struct ocfs2_xattr_header *header = (struct ocfs2_xattr_header *) | ||
5647 | (fe_bh->b_data + inode->i_sb->s_blocksize - | ||
5648 | le16_to_cpu(di->i_xattr_inline_size)); | ||
5649 | struct ocfs2_xattr_value_buf vb = { | ||
5650 | .vb_bh = fe_bh, | ||
5651 | .vb_access = ocfs2_journal_access_di, | ||
5652 | }; | ||
5653 | |||
5654 | return ocfs2_xattr_attach_refcount_normal(inode, &vb, header, | ||
5655 | ref_ci, ref_root_bh, dealloc); | ||
5656 | } | ||
5657 | |||
5658 | struct ocfs2_xattr_tree_value_refcount_para { | ||
5659 | struct ocfs2_caching_info *ref_ci; | ||
5660 | struct buffer_head *ref_root_bh; | ||
5661 | struct ocfs2_cached_dealloc_ctxt *dealloc; | ||
5662 | }; | ||
5663 | |||
5664 | static int ocfs2_get_xattr_tree_value_root(struct super_block *sb, | ||
5665 | struct ocfs2_xattr_bucket *bucket, | ||
5666 | int offset, | ||
5667 | struct ocfs2_xattr_value_root **xv, | ||
5668 | struct buffer_head **bh) | ||
5669 | { | ||
5670 | int ret, block_off, name_offset; | ||
5671 | struct ocfs2_xattr_header *xh = bucket_xh(bucket); | ||
5672 | struct ocfs2_xattr_entry *xe = &xh->xh_entries[offset]; | ||
5673 | void *base; | ||
5674 | |||
5675 | ret = ocfs2_xattr_bucket_get_name_value(sb, | ||
5676 | bucket_xh(bucket), | ||
5677 | offset, | ||
5678 | &block_off, | ||
5679 | &name_offset); | ||
5680 | if (ret) { | ||
5681 | mlog_errno(ret); | ||
5682 | goto out; | ||
5683 | } | ||
5684 | |||
5685 | base = bucket_block(bucket, block_off); | ||
5686 | |||
5687 | *xv = (struct ocfs2_xattr_value_root *)(base + name_offset + | ||
5688 | OCFS2_XATTR_SIZE(xe->xe_name_len)); | ||
5689 | |||
5690 | if (bh) | ||
5691 | *bh = bucket->bu_bhs[block_off]; | ||
5692 | out: | ||
5693 | return ret; | ||
5694 | } | ||
5695 | |||
5696 | /* | ||
5697 | * For a given xattr bucket, refcount all the entries which | ||
5698 | * have value stored outside. | ||
5699 | */ | ||
5700 | static int ocfs2_xattr_bucket_value_refcount(struct inode *inode, | ||
5701 | struct ocfs2_xattr_bucket *bucket, | ||
5702 | void *para) | ||
5703 | { | ||
5704 | int i, ret = 0; | ||
5705 | struct ocfs2_extent_tree et; | ||
5706 | struct ocfs2_xattr_tree_value_refcount_para *ref = | ||
5707 | (struct ocfs2_xattr_tree_value_refcount_para *)para; | ||
5708 | struct ocfs2_xattr_header *xh = | ||
5709 | (struct ocfs2_xattr_header *)bucket->bu_bhs[0]->b_data; | ||
5710 | struct ocfs2_xattr_entry *xe; | ||
5711 | struct ocfs2_xattr_value_buf vb = { | ||
5712 | .vb_access = ocfs2_journal_access, | ||
5713 | }; | ||
5714 | struct ocfs2_post_refcount refcount = { | ||
5715 | .credits = bucket->bu_blocks, | ||
5716 | .para = bucket, | ||
5717 | .func = ocfs2_xattr_bucket_post_refcount, | ||
5718 | }; | ||
5719 | struct ocfs2_post_refcount *p = NULL; | ||
5720 | |||
5721 | /* We only need post_refcount if we support metaecc. */ | ||
5722 | if (ocfs2_meta_ecc(OCFS2_SB(inode->i_sb))) | ||
5723 | p = &refcount; | ||
5724 | |||
5725 | mlog(0, "refcount bucket %llu, count = %u\n", | ||
5726 | (unsigned long long)bucket_blkno(bucket), | ||
5727 | le16_to_cpu(xh->xh_count)); | ||
5728 | for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { | ||
5729 | xe = &xh->xh_entries[i]; | ||
5730 | |||
5731 | if (ocfs2_xattr_is_local(xe)) | ||
5732 | continue; | ||
5733 | |||
5734 | ret = ocfs2_get_xattr_tree_value_root(inode->i_sb, bucket, i, | ||
5735 | &vb.vb_xv, &vb.vb_bh); | ||
5736 | if (ret) { | ||
5737 | mlog_errno(ret); | ||
5738 | break; | ||
5739 | } | ||
5740 | |||
5741 | ocfs2_init_xattr_value_extent_tree(&et, | ||
5742 | INODE_CACHE(inode), &vb); | ||
5743 | |||
5744 | ret = ocfs2_xattr_value_attach_refcount(inode, vb.vb_xv, | ||
5745 | &et, ref->ref_ci, | ||
5746 | ref->ref_root_bh, | ||
5747 | ref->dealloc, p); | ||
5748 | if (ret) { | ||
5749 | mlog_errno(ret); | ||
5750 | break; | ||
5751 | } | ||
5752 | } | ||
5753 | |||
5754 | return ret; | ||
5755 | |||
5756 | } | ||
5757 | |||
5758 | static int ocfs2_refcount_xattr_tree_rec(struct inode *inode, | ||
5759 | struct buffer_head *root_bh, | ||
5760 | u64 blkno, u32 cpos, u32 len, void *para) | ||
5761 | { | ||
5762 | return ocfs2_iterate_xattr_buckets(inode, blkno, len, | ||
5763 | ocfs2_xattr_bucket_value_refcount, | ||
5764 | para); | ||
5765 | } | ||
5766 | |||
5767 | static int ocfs2_xattr_block_attach_refcount(struct inode *inode, | ||
5768 | struct buffer_head *blk_bh, | ||
5769 | struct ocfs2_caching_info *ref_ci, | ||
5770 | struct buffer_head *ref_root_bh, | ||
5771 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
5772 | { | ||
5773 | int ret = 0; | ||
5774 | struct ocfs2_xattr_block *xb = | ||
5775 | (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
5776 | |||
5777 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { | ||
5778 | struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header; | ||
5779 | struct ocfs2_xattr_value_buf vb = { | ||
5780 | .vb_bh = blk_bh, | ||
5781 | .vb_access = ocfs2_journal_access_xb, | ||
5782 | }; | ||
5783 | |||
5784 | ret = ocfs2_xattr_attach_refcount_normal(inode, &vb, header, | ||
5785 | ref_ci, ref_root_bh, | ||
5786 | dealloc); | ||
5787 | } else { | ||
5788 | struct ocfs2_xattr_tree_value_refcount_para para = { | ||
5789 | .ref_ci = ref_ci, | ||
5790 | .ref_root_bh = ref_root_bh, | ||
5791 | .dealloc = dealloc, | ||
5792 | }; | ||
5793 | |||
5794 | ret = ocfs2_iterate_xattr_index_block(inode, blk_bh, | ||
5795 | ocfs2_refcount_xattr_tree_rec, | ||
5796 | ¶); | ||
5797 | } | ||
5798 | |||
5799 | return ret; | ||
5800 | } | ||
5801 | |||
5802 | int ocfs2_xattr_attach_refcount_tree(struct inode *inode, | ||
5803 | struct buffer_head *fe_bh, | ||
5804 | struct ocfs2_caching_info *ref_ci, | ||
5805 | struct buffer_head *ref_root_bh, | ||
5806 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
5807 | { | ||
5808 | int ret = 0; | ||
5809 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
5810 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data; | ||
5811 | struct buffer_head *blk_bh = NULL; | ||
5812 | |||
5813 | if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { | ||
5814 | ret = ocfs2_xattr_inline_attach_refcount(inode, fe_bh, | ||
5815 | ref_ci, ref_root_bh, | ||
5816 | dealloc); | ||
5817 | if (ret) { | ||
5818 | mlog_errno(ret); | ||
5819 | goto out; | ||
5820 | } | ||
5821 | } | ||
5822 | |||
5823 | if (!di->i_xattr_loc) | ||
5824 | goto out; | ||
5825 | |||
5826 | ret = ocfs2_read_xattr_block(inode, le64_to_cpu(di->i_xattr_loc), | ||
5827 | &blk_bh); | ||
5828 | if (ret < 0) { | ||
5829 | mlog_errno(ret); | ||
5830 | goto out; | ||
5831 | } | ||
5832 | |||
5833 | ret = ocfs2_xattr_block_attach_refcount(inode, blk_bh, ref_ci, | ||
5834 | ref_root_bh, dealloc); | ||
5835 | if (ret) | ||
5836 | mlog_errno(ret); | ||
5837 | |||
5838 | brelse(blk_bh); | ||
5839 | out: | ||
5840 | |||
5841 | return ret; | ||
5842 | } | ||
5843 | |||
5844 | /* | ||
5554 | * 'security' attributes support | 5845 | * 'security' attributes support |
5555 | */ | 5846 | */ |
5556 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, | 5847 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, |
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index 1ca7e9a1b7bc..a3295d705cea 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h | |||
@@ -83,5 +83,9 @@ struct ocfs2_xattr_value_buf { | |||
83 | struct ocfs2_xattr_value_root *vb_xv; | 83 | struct ocfs2_xattr_value_root *vb_xv; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | 86 | int ocfs2_xattr_attach_refcount_tree(struct inode *inode, | |
87 | struct buffer_head *fe_bh, | ||
88 | struct ocfs2_caching_info *ref_ci, | ||
89 | struct buffer_head *ref_root_bh, | ||
90 | struct ocfs2_cached_dealloc_ctxt *dealloc); | ||
87 | #endif /* OCFS2_XATTR_H */ | 91 | #endif /* OCFS2_XATTR_H */ |