diff options
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 351 |
1 files changed, 328 insertions, 23 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index fb17f7fe4c66..acccdfabd2d6 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -99,12 +99,25 @@ struct ocfs2_xattr_search { | |||
99 | */ | 99 | */ |
100 | struct buffer_head *xattr_bh; | 100 | struct buffer_head *xattr_bh; |
101 | struct ocfs2_xattr_header *header; | 101 | struct ocfs2_xattr_header *header; |
102 | struct ocfs2_xattr_bucket bucket; | ||
102 | void *base; | 103 | void *base; |
103 | void *end; | 104 | void *end; |
104 | struct ocfs2_xattr_entry *here; | 105 | struct ocfs2_xattr_entry *here; |
105 | int not_found; | 106 | int not_found; |
106 | }; | 107 | }; |
107 | 108 | ||
109 | static int ocfs2_xattr_bucket_get_name_value(struct inode *inode, | ||
110 | struct ocfs2_xattr_header *xh, | ||
111 | int index, | ||
112 | int *block_off, | ||
113 | int *new_offset); | ||
114 | |||
115 | static int ocfs2_xattr_index_block_find(struct inode *inode, | ||
116 | struct buffer_head *root_bh, | ||
117 | int name_index, | ||
118 | const char *name, | ||
119 | struct ocfs2_xattr_search *xs); | ||
120 | |||
108 | static int ocfs2_xattr_tree_list_index_block(struct inode *inode, | 121 | static int ocfs2_xattr_tree_list_index_block(struct inode *inode, |
109 | struct ocfs2_xattr_tree_root *xt, | 122 | struct ocfs2_xattr_tree_root *xt, |
110 | char *buffer, | 123 | char *buffer, |
@@ -604,7 +617,7 @@ static int ocfs2_xattr_find_entry(int name_index, | |||
604 | } | 617 | } |
605 | 618 | ||
606 | static int ocfs2_xattr_get_value_outside(struct inode *inode, | 619 | static int ocfs2_xattr_get_value_outside(struct inode *inode, |
607 | struct ocfs2_xattr_search *xs, | 620 | struct ocfs2_xattr_value_root *xv, |
608 | void *buffer, | 621 | void *buffer, |
609 | size_t len) | 622 | size_t len) |
610 | { | 623 | { |
@@ -613,12 +626,8 @@ static int ocfs2_xattr_get_value_outside(struct inode *inode, | |||
613 | int i, ret = 0; | 626 | int i, ret = 0; |
614 | size_t cplen, blocksize; | 627 | size_t cplen, blocksize; |
615 | struct buffer_head *bh = NULL; | 628 | struct buffer_head *bh = NULL; |
616 | struct ocfs2_xattr_value_root *xv; | ||
617 | struct ocfs2_extent_list *el; | 629 | struct ocfs2_extent_list *el; |
618 | 630 | ||
619 | xv = (struct ocfs2_xattr_value_root *) | ||
620 | (xs->base + le16_to_cpu(xs->here->xe_name_offset) + | ||
621 | OCFS2_XATTR_SIZE(xs->here->xe_name_len)); | ||
622 | el = &xv->xr_list; | 631 | el = &xv->xr_list; |
623 | clusters = le32_to_cpu(xv->xr_clusters); | 632 | clusters = le32_to_cpu(xv->xr_clusters); |
624 | bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); | 633 | bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); |
@@ -668,6 +677,7 @@ static int ocfs2_xattr_ibody_get(struct inode *inode, | |||
668 | { | 677 | { |
669 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 678 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
670 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | 679 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; |
680 | struct ocfs2_xattr_value_root *xv; | ||
671 | size_t size; | 681 | size_t size; |
672 | int ret = 0; | 682 | int ret = 0; |
673 | 683 | ||
@@ -692,7 +702,11 @@ static int ocfs2_xattr_ibody_get(struct inode *inode, | |||
692 | le16_to_cpu(xs->here->xe_name_offset) + | 702 | le16_to_cpu(xs->here->xe_name_offset) + |
693 | OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); | 703 | OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); |
694 | } else { | 704 | } else { |
695 | ret = ocfs2_xattr_get_value_outside(inode, xs, | 705 | xv = (struct ocfs2_xattr_value_root *) |
706 | (xs->base + le16_to_cpu( | ||
707 | xs->here->xe_name_offset) + | ||
708 | OCFS2_XATTR_SIZE(xs->here->xe_name_len)); | ||
709 | ret = ocfs2_xattr_get_value_outside(inode, xv, | ||
696 | buffer, size); | 710 | buffer, size); |
697 | if (ret < 0) { | 711 | if (ret < 0) { |
698 | mlog_errno(ret); | 712 | mlog_errno(ret); |
@@ -714,12 +728,15 @@ static int ocfs2_xattr_block_get(struct inode *inode, | |||
714 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | 728 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; |
715 | struct buffer_head *blk_bh = NULL; | 729 | struct buffer_head *blk_bh = NULL; |
716 | struct ocfs2_xattr_block *xb; | 730 | struct ocfs2_xattr_block *xb; |
731 | struct ocfs2_xattr_value_root *xv; | ||
717 | size_t size; | 732 | size_t size; |
718 | int ret = -ENODATA; | 733 | int ret = -ENODATA, name_offset, name_len, block_off, i; |
719 | 734 | ||
720 | if (!di->i_xattr_loc) | 735 | if (!di->i_xattr_loc) |
721 | return ret; | 736 | return ret; |
722 | 737 | ||
738 | memset(&xs->bucket, 0, sizeof(xs->bucket)); | ||
739 | |||
723 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | 740 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), |
724 | le64_to_cpu(di->i_xattr_loc), | 741 | le64_to_cpu(di->i_xattr_loc), |
725 | &blk_bh, OCFS2_BH_CACHED, inode); | 742 | &blk_bh, OCFS2_BH_CACHED, inode); |
@@ -736,12 +753,19 @@ static int ocfs2_xattr_block_get(struct inode *inode, | |||
736 | 753 | ||
737 | xs->xattr_bh = blk_bh; | 754 | xs->xattr_bh = blk_bh; |
738 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | 755 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; |
739 | xs->header = &xb->xb_attrs.xb_header; | ||
740 | xs->base = (void *)xs->header; | ||
741 | xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; | ||
742 | xs->here = xs->header->xh_entries; | ||
743 | 756 | ||
744 | ret = ocfs2_xattr_find_entry(name_index, name, xs); | 757 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { |
758 | xs->header = &xb->xb_attrs.xb_header; | ||
759 | xs->base = (void *)xs->header; | ||
760 | xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; | ||
761 | xs->here = xs->header->xh_entries; | ||
762 | |||
763 | ret = ocfs2_xattr_find_entry(name_index, name, xs); | ||
764 | } else | ||
765 | ret = ocfs2_xattr_index_block_find(inode, blk_bh, | ||
766 | name_index, | ||
767 | name, xs); | ||
768 | |||
745 | if (ret) | 769 | if (ret) |
746 | goto cleanup; | 770 | goto cleanup; |
747 | size = le64_to_cpu(xs->here->xe_value_size); | 771 | size = le64_to_cpu(xs->here->xe_value_size); |
@@ -749,12 +773,26 @@ static int ocfs2_xattr_block_get(struct inode *inode, | |||
749 | ret = -ERANGE; | 773 | ret = -ERANGE; |
750 | if (size > buffer_size) | 774 | if (size > buffer_size) |
751 | goto cleanup; | 775 | goto cleanup; |
776 | |||
777 | name_offset = le16_to_cpu(xs->here->xe_name_offset); | ||
778 | name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len); | ||
779 | i = xs->here - xs->header->xh_entries; | ||
780 | |||
781 | if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { | ||
782 | ret = ocfs2_xattr_bucket_get_name_value(inode, | ||
783 | xs->bucket.xh, | ||
784 | i, | ||
785 | &block_off, | ||
786 | &name_offset); | ||
787 | xs->base = xs->bucket.bhs[block_off]->b_data; | ||
788 | } | ||
752 | if (ocfs2_xattr_is_local(xs->here)) { | 789 | if (ocfs2_xattr_is_local(xs->here)) { |
753 | memcpy(buffer, (void *)xs->base + | 790 | memcpy(buffer, (void *)xs->base + |
754 | le16_to_cpu(xs->here->xe_name_offset) + | 791 | name_offset + name_len, size); |
755 | OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); | ||
756 | } else { | 792 | } else { |
757 | ret = ocfs2_xattr_get_value_outside(inode, xs, | 793 | xv = (struct ocfs2_xattr_value_root *) |
794 | (xs->base + name_offset + name_len); | ||
795 | ret = ocfs2_xattr_get_value_outside(inode, xv, | ||
758 | buffer, size); | 796 | buffer, size); |
759 | if (ret < 0) { | 797 | if (ret < 0) { |
760 | mlog_errno(ret); | 798 | mlog_errno(ret); |
@@ -764,8 +802,11 @@ static int ocfs2_xattr_block_get(struct inode *inode, | |||
764 | } | 802 | } |
765 | ret = size; | 803 | ret = size; |
766 | cleanup: | 804 | cleanup: |
767 | brelse(blk_bh); | 805 | for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++) |
806 | brelse(xs->bucket.bhs[i]); | ||
807 | memset(&xs->bucket, 0, sizeof(xs->bucket)); | ||
768 | 808 | ||
809 | brelse(blk_bh); | ||
769 | return ret; | 810 | return ret; |
770 | } | 811 | } |
771 | 812 | ||
@@ -1679,6 +1720,7 @@ static int ocfs2_xattr_block_find(struct inode *inode, | |||
1679 | { | 1720 | { |
1680 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | 1721 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; |
1681 | struct buffer_head *blk_bh = NULL; | 1722 | struct buffer_head *blk_bh = NULL; |
1723 | struct ocfs2_xattr_block *xb; | ||
1682 | int ret = 0; | 1724 | int ret = 0; |
1683 | 1725 | ||
1684 | if (!di->i_xattr_loc) | 1726 | if (!di->i_xattr_loc) |
@@ -1699,20 +1741,26 @@ static int ocfs2_xattr_block_find(struct inode *inode, | |||
1699 | } | 1741 | } |
1700 | 1742 | ||
1701 | xs->xattr_bh = blk_bh; | 1743 | xs->xattr_bh = blk_bh; |
1702 | xs->header = &((struct ocfs2_xattr_block *)blk_bh->b_data)-> | 1744 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; |
1703 | xb_attrs.xb_header; | 1745 | |
1704 | xs->base = (void *)xs->header; | 1746 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { |
1705 | xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; | 1747 | xs->header = &xb->xb_attrs.xb_header; |
1706 | xs->here = xs->header->xh_entries; | 1748 | xs->base = (void *)xs->header; |
1749 | xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; | ||
1750 | xs->here = xs->header->xh_entries; | ||
1751 | |||
1752 | ret = ocfs2_xattr_find_entry(name_index, name, xs); | ||
1753 | } else | ||
1754 | ret = ocfs2_xattr_index_block_find(inode, blk_bh, | ||
1755 | name_index, | ||
1756 | name, xs); | ||
1707 | 1757 | ||
1708 | ret = ocfs2_xattr_find_entry(name_index, name, xs); | ||
1709 | if (ret && ret != -ENODATA) { | 1758 | if (ret && ret != -ENODATA) { |
1710 | xs->xattr_bh = NULL; | 1759 | xs->xattr_bh = NULL; |
1711 | goto cleanup; | 1760 | goto cleanup; |
1712 | } | 1761 | } |
1713 | xs->not_found = ret; | 1762 | xs->not_found = ret; |
1714 | return 0; | 1763 | return 0; |
1715 | |||
1716 | cleanup: | 1764 | cleanup: |
1717 | brelse(blk_bh); | 1765 | brelse(blk_bh); |
1718 | 1766 | ||
@@ -1941,6 +1989,18 @@ cleanup: | |||
1941 | return ret; | 1989 | return ret; |
1942 | } | 1990 | } |
1943 | 1991 | ||
1992 | static inline u32 ocfs2_xattr_hash_by_name(struct inode *inode, | ||
1993 | int name_index, | ||
1994 | const char *suffix_name) | ||
1995 | { | ||
1996 | struct xattr_handler *handler = ocfs2_xattr_handler(name_index); | ||
1997 | char *prefix = handler->prefix; | ||
1998 | int prefix_len = strlen(handler->prefix); | ||
1999 | |||
2000 | return ocfs2_xattr_name_hash(inode, prefix, prefix_len, | ||
2001 | (char *)suffix_name, strlen(suffix_name)); | ||
2002 | } | ||
2003 | |||
1944 | /* | 2004 | /* |
1945 | * Find the xattr extent rec which may contains name_hash. | 2005 | * Find the xattr extent rec which may contains name_hash. |
1946 | * e_cpos will be the first name hash of the xattr rec. | 2006 | * e_cpos will be the first name hash of the xattr rec. |
@@ -2010,6 +2070,251 @@ typedef int (xattr_bucket_func)(struct inode *inode, | |||
2010 | struct ocfs2_xattr_bucket *bucket, | 2070 | struct ocfs2_xattr_bucket *bucket, |
2011 | void *para); | 2071 | void *para); |
2012 | 2072 | ||
2073 | static int ocfs2_find_xe_in_bucket(struct inode *inode, | ||
2074 | struct buffer_head *header_bh, | ||
2075 | int name_index, | ||
2076 | const char *name, | ||
2077 | u32 name_hash, | ||
2078 | u16 *xe_index, | ||
2079 | int *found) | ||
2080 | { | ||
2081 | int i, ret = 0, cmp = 1, block_off, new_offset; | ||
2082 | struct ocfs2_xattr_header *xh = | ||
2083 | (struct ocfs2_xattr_header *)header_bh->b_data; | ||
2084 | size_t name_len = strlen(name); | ||
2085 | struct ocfs2_xattr_entry *xe = NULL; | ||
2086 | struct buffer_head *name_bh = NULL; | ||
2087 | char *xe_name; | ||
2088 | |||
2089 | /* | ||
2090 | * We don't use binary search in the bucket because there | ||
2091 | * may be multiple entries with the same name hash. | ||
2092 | */ | ||
2093 | for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { | ||
2094 | xe = &xh->xh_entries[i]; | ||
2095 | |||
2096 | if (name_hash > le32_to_cpu(xe->xe_name_hash)) | ||
2097 | continue; | ||
2098 | else if (name_hash < le32_to_cpu(xe->xe_name_hash)) | ||
2099 | break; | ||
2100 | |||
2101 | cmp = name_index - ocfs2_xattr_get_type(xe); | ||
2102 | if (!cmp) | ||
2103 | cmp = name_len - xe->xe_name_len; | ||
2104 | if (cmp) | ||
2105 | continue; | ||
2106 | |||
2107 | ret = ocfs2_xattr_bucket_get_name_value(inode, | ||
2108 | xh, | ||
2109 | i, | ||
2110 | &block_off, | ||
2111 | &new_offset); | ||
2112 | if (ret) { | ||
2113 | mlog_errno(ret); | ||
2114 | break; | ||
2115 | } | ||
2116 | |||
2117 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | ||
2118 | header_bh->b_blocknr + block_off, | ||
2119 | &name_bh, OCFS2_BH_CACHED, inode); | ||
2120 | if (ret) { | ||
2121 | mlog_errno(ret); | ||
2122 | break; | ||
2123 | } | ||
2124 | xe_name = name_bh->b_data + new_offset; | ||
2125 | |||
2126 | cmp = memcmp(name, xe_name, name_len); | ||
2127 | brelse(name_bh); | ||
2128 | name_bh = NULL; | ||
2129 | |||
2130 | if (cmp == 0) { | ||
2131 | *xe_index = i; | ||
2132 | *found = 1; | ||
2133 | ret = 0; | ||
2134 | break; | ||
2135 | } | ||
2136 | } | ||
2137 | |||
2138 | return ret; | ||
2139 | } | ||
2140 | |||
2141 | /* | ||
2142 | * Find the specified xattr entry in a series of buckets. | ||
2143 | * This series start from p_blkno and last for num_clusters. | ||
2144 | * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains | ||
2145 | * the num of the valid buckets. | ||
2146 | * | ||
2147 | * Return the buffer_head this xattr should reside in. And if the xattr's | ||
2148 | * hash is in the gap of 2 buckets, return the lower bucket. | ||
2149 | */ | ||
2150 | static int ocfs2_xattr_bucket_find(struct inode *inode, | ||
2151 | int name_index, | ||
2152 | const char *name, | ||
2153 | u32 name_hash, | ||
2154 | u64 p_blkno, | ||
2155 | u32 first_hash, | ||
2156 | u32 num_clusters, | ||
2157 | struct ocfs2_xattr_search *xs) | ||
2158 | { | ||
2159 | int ret, found = 0; | ||
2160 | struct buffer_head *bh = NULL; | ||
2161 | struct buffer_head *lower_bh = NULL; | ||
2162 | struct ocfs2_xattr_header *xh = NULL; | ||
2163 | struct ocfs2_xattr_entry *xe = NULL; | ||
2164 | u16 index = 0; | ||
2165 | u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); | ||
2166 | int low_bucket = 0, bucket, high_bucket; | ||
2167 | u32 last_hash; | ||
2168 | u64 blkno; | ||
2169 | |||
2170 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, | ||
2171 | &bh, OCFS2_BH_CACHED, inode); | ||
2172 | if (ret) { | ||
2173 | mlog_errno(ret); | ||
2174 | goto out; | ||
2175 | } | ||
2176 | |||
2177 | xh = (struct ocfs2_xattr_header *)bh->b_data; | ||
2178 | high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1; | ||
2179 | |||
2180 | while (low_bucket <= high_bucket) { | ||
2181 | brelse(bh); | ||
2182 | bh = NULL; | ||
2183 | bucket = (low_bucket + high_bucket) / 2; | ||
2184 | |||
2185 | blkno = p_blkno + bucket * blk_per_bucket; | ||
2186 | |||
2187 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, | ||
2188 | &bh, OCFS2_BH_CACHED, inode); | ||
2189 | if (ret) { | ||
2190 | mlog_errno(ret); | ||
2191 | goto out; | ||
2192 | } | ||
2193 | |||
2194 | xh = (struct ocfs2_xattr_header *)bh->b_data; | ||
2195 | xe = &xh->xh_entries[0]; | ||
2196 | if (name_hash < le32_to_cpu(xe->xe_name_hash)) { | ||
2197 | high_bucket = bucket - 1; | ||
2198 | continue; | ||
2199 | } | ||
2200 | |||
2201 | /* | ||
2202 | * Check whether the hash of the last entry in our | ||
2203 | * bucket is larger than the search one. | ||
2204 | */ | ||
2205 | xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1]; | ||
2206 | last_hash = le32_to_cpu(xe->xe_name_hash); | ||
2207 | |||
2208 | /* record lower_bh which may be the insert place. */ | ||
2209 | brelse(lower_bh); | ||
2210 | lower_bh = bh; | ||
2211 | bh = NULL; | ||
2212 | |||
2213 | if (name_hash > le32_to_cpu(xe->xe_name_hash)) { | ||
2214 | low_bucket = bucket + 1; | ||
2215 | continue; | ||
2216 | } | ||
2217 | |||
2218 | /* the searched xattr should reside in this bucket if exists. */ | ||
2219 | ret = ocfs2_find_xe_in_bucket(inode, lower_bh, | ||
2220 | name_index, name, name_hash, | ||
2221 | &index, &found); | ||
2222 | if (ret) { | ||
2223 | mlog_errno(ret); | ||
2224 | goto out; | ||
2225 | } | ||
2226 | break; | ||
2227 | } | ||
2228 | |||
2229 | /* | ||
2230 | * Record the bucket we have found. | ||
2231 | * When the xattr's hash value is in the gap of 2 buckets, we will | ||
2232 | * always set it to the previous bucket. | ||
2233 | */ | ||
2234 | if (!lower_bh) { | ||
2235 | /* | ||
2236 | * We can't find any bucket whose first name_hash is less | ||
2237 | * than the find name_hash. | ||
2238 | */ | ||
2239 | BUG_ON(bh->b_blocknr != p_blkno); | ||
2240 | lower_bh = bh; | ||
2241 | bh = NULL; | ||
2242 | } | ||
2243 | xs->bucket.bhs[0] = lower_bh; | ||
2244 | xs->bucket.xh = (struct ocfs2_xattr_header *) | ||
2245 | xs->bucket.bhs[0]->b_data; | ||
2246 | lower_bh = NULL; | ||
2247 | |||
2248 | xs->header = xs->bucket.xh; | ||
2249 | xs->base = xs->bucket.bhs[0]->b_data; | ||
2250 | xs->end = xs->base + inode->i_sb->s_blocksize; | ||
2251 | |||
2252 | if (found) { | ||
2253 | /* | ||
2254 | * If we have found the xattr enty, read all the blocks in | ||
2255 | * this bucket. | ||
2256 | */ | ||
2257 | ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), | ||
2258 | xs->bucket.bhs[0]->b_blocknr + 1, | ||
2259 | blk_per_bucket - 1, &xs->bucket.bhs[1], | ||
2260 | OCFS2_BH_CACHED, inode); | ||
2261 | if (ret) { | ||
2262 | mlog_errno(ret); | ||
2263 | goto out; | ||
2264 | } | ||
2265 | |||
2266 | xs->here = &xs->header->xh_entries[index]; | ||
2267 | mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name, | ||
2268 | (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index); | ||
2269 | } else | ||
2270 | ret = -ENODATA; | ||
2271 | |||
2272 | out: | ||
2273 | brelse(bh); | ||
2274 | brelse(lower_bh); | ||
2275 | return ret; | ||
2276 | } | ||
2277 | |||
2278 | static int ocfs2_xattr_index_block_find(struct inode *inode, | ||
2279 | struct buffer_head *root_bh, | ||
2280 | int name_index, | ||
2281 | const char *name, | ||
2282 | struct ocfs2_xattr_search *xs) | ||
2283 | { | ||
2284 | int ret; | ||
2285 | struct ocfs2_xattr_block *xb = | ||
2286 | (struct ocfs2_xattr_block *)root_bh->b_data; | ||
2287 | struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root; | ||
2288 | struct ocfs2_extent_list *el = &xb_root->xt_list; | ||
2289 | u64 p_blkno = 0; | ||
2290 | u32 first_hash, num_clusters = 0; | ||
2291 | u32 name_hash = ocfs2_xattr_hash_by_name(inode, name_index, name); | ||
2292 | |||
2293 | if (le16_to_cpu(el->l_next_free_rec) == 0) | ||
2294 | return -ENODATA; | ||
2295 | |||
2296 | mlog(0, "find xattr %s, hash = %u, index = %d in xattr tree\n", | ||
2297 | name, name_hash, name_index); | ||
2298 | |||
2299 | ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash, | ||
2300 | &num_clusters, el); | ||
2301 | if (ret) { | ||
2302 | mlog_errno(ret); | ||
2303 | goto out; | ||
2304 | } | ||
2305 | |||
2306 | BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash); | ||
2307 | |||
2308 | mlog(0, "find xattr extent rec %u clusters from %llu, the first hash " | ||
2309 | "in the rec is %u\n", num_clusters, p_blkno, first_hash); | ||
2310 | |||
2311 | ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash, | ||
2312 | p_blkno, first_hash, num_clusters, xs); | ||
2313 | |||
2314 | out: | ||
2315 | return ret; | ||
2316 | } | ||
2317 | |||
2013 | static int ocfs2_iterate_xattr_buckets(struct inode *inode, | 2318 | static int ocfs2_iterate_xattr_buckets(struct inode *inode, |
2014 | u64 blkno, | 2319 | u64 blkno, |
2015 | u32 clusters, | 2320 | u32 clusters, |