aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2008-08-18 05:38:51 -0400
committerMark Fasheh <mfasheh@suse.com>2008-10-13 19:57:03 -0400
commit589dc2602f2a1b7fa5e59b90f548af189f128d77 (patch)
tree0a87e16146aa06c72de8db0aed1215c8be72b5fc /fs/ocfs2
parent0c044f0b24b9128ba8c297149d88bd81f2e36af3 (diff)
ocfs2: Add xattr lookup code xattr btrees
Add code to lookup a given extended attribute in the xattr btree. Lookup follows this general scheme: 1. Use ocfs2_xattr_get_rec to find the xattr extent record 2. Find the xattr bucket within the extent which may contain this xattr 3. Iterate the bucket to find the xattr. In ocfs2_xattr_block_get(), we need to recalcuate the block offset and name offset for the right position of name/value. Signed-off-by: Tao Ma <tao.ma@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/xattr.c351
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
109static 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
115static 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
108static int ocfs2_xattr_tree_list_index_block(struct inode *inode, 121static 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
606static int ocfs2_xattr_get_value_outside(struct inode *inode, 619static 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;
766cleanup: 804cleanup:
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
1716cleanup: 1764cleanup:
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
1992static 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
2073static 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 */
2150static 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
2272out:
2273 brelse(bh);
2274 brelse(lower_bh);
2275 return ret;
2276}
2277
2278static 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
2314out:
2315 return ret;
2316}
2317
2013static int ocfs2_iterate_xattr_buckets(struct inode *inode, 2318static int ocfs2_iterate_xattr_buckets(struct inode *inode,
2014 u64 blkno, 2319 u64 blkno,
2015 u32 clusters, 2320 u32 clusters,