diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-09-21 01:04:19 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:43 -0400 |
commit | 0129241e2b3b90ff83a8c774353e5612d84bd493 (patch) | |
tree | eec03f874cbdbc4c9eab4900f2de89fd1747a5ee /fs/ocfs2/xattr.c | |
parent | 47bca4950bc40fb54e9d41cbbc8b06cd653d2ae2 (diff) |
ocfs2: Attach xattr clusters to refcount tree.
In ocfs2, when xattr's value is larger than OCFS2_XATTR_INLINE_SIZE,
it will be kept outside of the blocks we store xattr entry. And they
are stored in a b-tree also. So this patch try to attach all these
clusters to refcount tree also.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 291 |
1 files changed, 291 insertions, 0 deletions
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, |