]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-lookup-code-xattr-btr.patch
Merge branch 'master' of git://git.ipfire.org/ipfire-2.x
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / ocfs2-Add-xattr-lookup-code-xattr-btr.patch
1 From: Tao Ma <tao.ma@oracle.com>
2 Subject: [PATCH 12/16] ocfs2: Add xattr lookup code xattr btrees
3 Patch-mainline: 2.6.28?
4 References: FATE302067
5
6 Add code to lookup a given extended attribute in the xattr btree. Lookup
7 follows this general scheme:
8
9 1. Use ocfs2_xattr_get_rec to find the xattr extent record
10
11 2. Find the xattr bucket within the extent which may contain this xattr
12
13 3. Iterate the bucket to find the xattr. In ocfs2_xattr_block_get(), we need
14 to recalcuate the block offset and name offset for the right position of
15 name/value.
16
17 Signed-off-by: Tao Ma <tao.ma@oracle.com>
18 Signed-off-by: Mark Fasheh <mfasheh@suse.com>
19 ---
20 fs/ocfs2/xattr.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++----
21 1 files changed, 328 insertions(+), 23 deletions(-)
22
23 diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
24 index ed41c15..a5ca066 100644
25 --- a/fs/ocfs2/xattr.c
26 +++ b/fs/ocfs2/xattr.c
27 @@ -115,12 +115,25 @@ struct ocfs2_xattr_search {
28 */
29 struct buffer_head *xattr_bh;
30 struct ocfs2_xattr_header *header;
31 + struct ocfs2_xattr_bucket bucket;
32 void *base;
33 void *end;
34 struct ocfs2_xattr_entry *here;
35 int not_found;
36 };
37
38 +static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
39 + struct ocfs2_xattr_header *xh,
40 + int index,
41 + int *block_off,
42 + int *new_offset);
43 +
44 +static int ocfs2_xattr_index_block_find(struct inode *inode,
45 + struct buffer_head *root_bh,
46 + int name_index,
47 + const char *name,
48 + struct ocfs2_xattr_search *xs);
49 +
50 static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
51 struct ocfs2_xattr_tree_root *xt,
52 char *buffer,
53 @@ -620,7 +633,7 @@ static int ocfs2_xattr_find_entry(int name_index,
54 }
55
56 static int ocfs2_xattr_get_value_outside(struct inode *inode,
57 - struct ocfs2_xattr_search *xs,
58 + struct ocfs2_xattr_value_root *xv,
59 void *buffer,
60 size_t len)
61 {
62 @@ -629,12 +642,8 @@ static int ocfs2_xattr_get_value_outside(struct inode *inode,
63 int i, ret = 0;
64 size_t cplen, blocksize;
65 struct buffer_head *bh = NULL;
66 - struct ocfs2_xattr_value_root *xv;
67 struct ocfs2_extent_list *el;
68
69 - xv = (struct ocfs2_xattr_value_root *)
70 - (xs->base + le16_to_cpu(xs->here->xe_name_offset) +
71 - OCFS2_XATTR_SIZE(xs->here->xe_name_len));
72 el = &xv->xr_list;
73 clusters = le32_to_cpu(xv->xr_clusters);
74 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
75 @@ -684,6 +693,7 @@ static int ocfs2_xattr_ibody_get(struct inode *inode,
76 {
77 struct ocfs2_inode_info *oi = OCFS2_I(inode);
78 struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
79 + struct ocfs2_xattr_value_root *xv;
80 size_t size;
81 int ret = 0;
82
83 @@ -708,7 +718,11 @@ static int ocfs2_xattr_ibody_get(struct inode *inode,
84 le16_to_cpu(xs->here->xe_name_offset) +
85 OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
86 } else {
87 - ret = ocfs2_xattr_get_value_outside(inode, xs,
88 + xv = (struct ocfs2_xattr_value_root *)
89 + (xs->base + le16_to_cpu(
90 + xs->here->xe_name_offset) +
91 + OCFS2_XATTR_SIZE(xs->here->xe_name_len));
92 + ret = ocfs2_xattr_get_value_outside(inode, xv,
93 buffer, size);
94 if (ret < 0) {
95 mlog_errno(ret);
96 @@ -730,12 +744,15 @@ static int ocfs2_xattr_block_get(struct inode *inode,
97 struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
98 struct buffer_head *blk_bh = NULL;
99 struct ocfs2_xattr_block *xb;
100 + struct ocfs2_xattr_value_root *xv;
101 size_t size;
102 - int ret = -ENODATA;
103 + int ret = -ENODATA, name_offset, name_len, block_off, i;
104
105 if (!di->i_xattr_loc)
106 return ret;
107
108 + memset(&xs->bucket, 0, sizeof(xs->bucket));
109 +
110 ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
111 le64_to_cpu(di->i_xattr_loc),
112 &blk_bh, OCFS2_BH_CACHED, inode);
113 @@ -752,12 +769,19 @@ static int ocfs2_xattr_block_get(struct inode *inode,
114
115 xs->xattr_bh = blk_bh;
116 xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
117 - xs->header = &xb->xb_attrs.xb_header;
118 - xs->base = (void *)xs->header;
119 - xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
120 - xs->here = xs->header->xh_entries;
121
122 - ret = ocfs2_xattr_find_entry(name_index, name, xs);
123 + if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
124 + xs->header = &xb->xb_attrs.xb_header;
125 + xs->base = (void *)xs->header;
126 + xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
127 + xs->here = xs->header->xh_entries;
128 +
129 + ret = ocfs2_xattr_find_entry(name_index, name, xs);
130 + } else
131 + ret = ocfs2_xattr_index_block_find(inode, blk_bh,
132 + name_index,
133 + name, xs);
134 +
135 if (ret)
136 goto cleanup;
137 size = le64_to_cpu(xs->here->xe_value_size);
138 @@ -765,12 +789,26 @@ static int ocfs2_xattr_block_get(struct inode *inode,
139 ret = -ERANGE;
140 if (size > buffer_size)
141 goto cleanup;
142 +
143 + name_offset = le16_to_cpu(xs->here->xe_name_offset);
144 + name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len);
145 + i = xs->here - xs->header->xh_entries;
146 +
147 + if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
148 + ret = ocfs2_xattr_bucket_get_name_value(inode,
149 + xs->bucket.xh,
150 + i,
151 + &block_off,
152 + &name_offset);
153 + xs->base = xs->bucket.bhs[block_off]->b_data;
154 + }
155 if (ocfs2_xattr_is_local(xs->here)) {
156 memcpy(buffer, (void *)xs->base +
157 - le16_to_cpu(xs->here->xe_name_offset) +
158 - OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
159 + name_offset + name_len, size);
160 } else {
161 - ret = ocfs2_xattr_get_value_outside(inode, xs,
162 + xv = (struct ocfs2_xattr_value_root *)
163 + (xs->base + name_offset + name_len);
164 + ret = ocfs2_xattr_get_value_outside(inode, xv,
165 buffer, size);
166 if (ret < 0) {
167 mlog_errno(ret);
168 @@ -780,8 +818,11 @@ static int ocfs2_xattr_block_get(struct inode *inode,
169 }
170 ret = size;
171 cleanup:
172 - brelse(blk_bh);
173 + for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++)
174 + brelse(xs->bucket.bhs[i]);
175 + memset(&xs->bucket, 0, sizeof(xs->bucket));
176
177 + brelse(blk_bh);
178 return ret;
179 }
180
181 @@ -1695,6 +1736,7 @@ static int ocfs2_xattr_block_find(struct inode *inode,
182 {
183 struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
184 struct buffer_head *blk_bh = NULL;
185 + struct ocfs2_xattr_block *xb;
186 int ret = 0;
187
188 if (!di->i_xattr_loc)
189 @@ -1715,20 +1757,26 @@ static int ocfs2_xattr_block_find(struct inode *inode,
190 }
191
192 xs->xattr_bh = blk_bh;
193 - xs->header = &((struct ocfs2_xattr_block *)blk_bh->b_data)->
194 - xb_attrs.xb_header;
195 - xs->base = (void *)xs->header;
196 - xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
197 - xs->here = xs->header->xh_entries;
198 + xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
199 +
200 + if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
201 + xs->header = &xb->xb_attrs.xb_header;
202 + xs->base = (void *)xs->header;
203 + xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
204 + xs->here = xs->header->xh_entries;
205 +
206 + ret = ocfs2_xattr_find_entry(name_index, name, xs);
207 + } else
208 + ret = ocfs2_xattr_index_block_find(inode, blk_bh,
209 + name_index,
210 + name, xs);
211
212 - ret = ocfs2_xattr_find_entry(name_index, name, xs);
213 if (ret && ret != -ENODATA) {
214 xs->xattr_bh = NULL;
215 goto cleanup;
216 }
217 xs->not_found = ret;
218 return 0;
219 -
220 cleanup:
221 brelse(blk_bh);
222
223 @@ -1957,6 +2005,18 @@ cleanup:
224 return ret;
225 }
226
227 +static inline u32 ocfs2_xattr_hash_by_name(struct inode *inode,
228 + int name_index,
229 + const char *suffix_name)
230 +{
231 + struct xattr_handler *handler = ocfs2_xattr_handler(name_index);
232 + char *prefix = handler->prefix;
233 + int prefix_len = strlen(handler->prefix);
234 +
235 + return ocfs2_xattr_name_hash(inode, prefix, prefix_len,
236 + (char *)suffix_name, strlen(suffix_name));
237 +}
238 +
239 /*
240 * Find the xattr extent rec which may contains name_hash.
241 * e_cpos will be the first name hash of the xattr rec.
242 @@ -2026,6 +2086,251 @@ typedef int (xattr_bucket_func)(struct inode *inode,
243 struct ocfs2_xattr_bucket *bucket,
244 void *para);
245
246 +static int ocfs2_find_xe_in_bucket(struct inode *inode,
247 + struct buffer_head *header_bh,
248 + int name_index,
249 + const char *name,
250 + u32 name_hash,
251 + u16 *xe_index,
252 + int *found)
253 +{
254 + int i, ret = 0, cmp = 1, block_off, new_offset;
255 + struct ocfs2_xattr_header *xh =
256 + (struct ocfs2_xattr_header *)header_bh->b_data;
257 + size_t name_len = strlen(name);
258 + struct ocfs2_xattr_entry *xe = NULL;
259 + struct buffer_head *name_bh = NULL;
260 + char *xe_name;
261 +
262 + /*
263 + * We don't use binary search in the bucket because there
264 + * may be multiple entries with the same name hash.
265 + */
266 + for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
267 + xe = &xh->xh_entries[i];
268 +
269 + if (name_hash > le32_to_cpu(xe->xe_name_hash))
270 + continue;
271 + else if (name_hash < le32_to_cpu(xe->xe_name_hash))
272 + break;
273 +
274 + cmp = name_index - ocfs2_xattr_get_type(xe);
275 + if (!cmp)
276 + cmp = name_len - xe->xe_name_len;
277 + if (cmp)
278 + continue;
279 +
280 + ret = ocfs2_xattr_bucket_get_name_value(inode,
281 + xh,
282 + i,
283 + &block_off,
284 + &new_offset);
285 + if (ret) {
286 + mlog_errno(ret);
287 + break;
288 + }
289 +
290 + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
291 + header_bh->b_blocknr + block_off,
292 + &name_bh, OCFS2_BH_CACHED, inode);
293 + if (ret) {
294 + mlog_errno(ret);
295 + break;
296 + }
297 + xe_name = name_bh->b_data + new_offset;
298 +
299 + cmp = memcmp(name, xe_name, name_len);
300 + brelse(name_bh);
301 + name_bh = NULL;
302 +
303 + if (cmp == 0) {
304 + *xe_index = i;
305 + *found = 1;
306 + ret = 0;
307 + break;
308 + }
309 + }
310 +
311 + return ret;
312 +}
313 +
314 +/*
315 + * Find the specified xattr entry in a series of buckets.
316 + * This series start from p_blkno and last for num_clusters.
317 + * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains
318 + * the num of the valid buckets.
319 + *
320 + * Return the buffer_head this xattr should reside in. And if the xattr's
321 + * hash is in the gap of 2 buckets, return the lower bucket.
322 + */
323 +static int ocfs2_xattr_bucket_find(struct inode *inode,
324 + int name_index,
325 + const char *name,
326 + u32 name_hash,
327 + u64 p_blkno,
328 + u32 first_hash,
329 + u32 num_clusters,
330 + struct ocfs2_xattr_search *xs)
331 +{
332 + int ret, found = 0;
333 + struct buffer_head *bh = NULL;
334 + struct buffer_head *lower_bh = NULL;
335 + struct ocfs2_xattr_header *xh = NULL;
336 + struct ocfs2_xattr_entry *xe = NULL;
337 + u16 index = 0;
338 + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
339 + int low_bucket = 0, bucket, high_bucket;
340 + u32 last_hash;
341 + u64 blkno;
342 +
343 + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
344 + &bh, OCFS2_BH_CACHED, inode);
345 + if (ret) {
346 + mlog_errno(ret);
347 + goto out;
348 + }
349 +
350 + xh = (struct ocfs2_xattr_header *)bh->b_data;
351 + high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1;
352 +
353 + while (low_bucket <= high_bucket) {
354 + brelse(bh);
355 + bh = NULL;
356 + bucket = (low_bucket + high_bucket) / 2;
357 +
358 + blkno = p_blkno + bucket * blk_per_bucket;
359 +
360 + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
361 + &bh, OCFS2_BH_CACHED, inode);
362 + if (ret) {
363 + mlog_errno(ret);
364 + goto out;
365 + }
366 +
367 + xh = (struct ocfs2_xattr_header *)bh->b_data;
368 + xe = &xh->xh_entries[0];
369 + if (name_hash < le32_to_cpu(xe->xe_name_hash)) {
370 + high_bucket = bucket - 1;
371 + continue;
372 + }
373 +
374 + /*
375 + * Check whether the hash of the last entry in our
376 + * bucket is larger than the search one.
377 + */
378 + xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
379 + last_hash = le32_to_cpu(xe->xe_name_hash);
380 +
381 + /* record lower_bh which may be the insert place. */
382 + brelse(lower_bh);
383 + lower_bh = bh;
384 + bh = NULL;
385 +
386 + if (name_hash > le32_to_cpu(xe->xe_name_hash)) {
387 + low_bucket = bucket + 1;
388 + continue;
389 + }
390 +
391 + /* the searched xattr should reside in this bucket if exists. */
392 + ret = ocfs2_find_xe_in_bucket(inode, lower_bh,
393 + name_index, name, name_hash,
394 + &index, &found);
395 + if (ret) {
396 + mlog_errno(ret);
397 + goto out;
398 + }
399 + break;
400 + }
401 +
402 + /*
403 + * Record the bucket we have found.
404 + * When the xattr's hash value is in the gap of 2 buckets, we will
405 + * always set it to the previous bucket.
406 + */
407 + if (!lower_bh) {
408 + /*
409 + * We can't find any bucket whose first name_hash is less
410 + * than the find name_hash.
411 + */
412 + BUG_ON(bh->b_blocknr != p_blkno);
413 + lower_bh = bh;
414 + bh = NULL;
415 + }
416 + xs->bucket.bhs[0] = lower_bh;
417 + xs->bucket.xh = (struct ocfs2_xattr_header *)
418 + xs->bucket.bhs[0]->b_data;
419 + lower_bh = NULL;
420 +
421 + xs->header = xs->bucket.xh;
422 + xs->base = xs->bucket.bhs[0]->b_data;
423 + xs->end = xs->base + inode->i_sb->s_blocksize;
424 +
425 + if (found) {
426 + /*
427 + * If we have found the xattr enty, read all the blocks in
428 + * this bucket.
429 + */
430 + ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
431 + xs->bucket.bhs[0]->b_blocknr + 1,
432 + blk_per_bucket - 1, &xs->bucket.bhs[1],
433 + OCFS2_BH_CACHED, inode);
434 + if (ret) {
435 + mlog_errno(ret);
436 + goto out;
437 + }
438 +
439 + xs->here = &xs->header->xh_entries[index];
440 + mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name,
441 + (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index);
442 + } else
443 + ret = -ENODATA;
444 +
445 +out:
446 + brelse(bh);
447 + brelse(lower_bh);
448 + return ret;
449 +}
450 +
451 +static int ocfs2_xattr_index_block_find(struct inode *inode,
452 + struct buffer_head *root_bh,
453 + int name_index,
454 + const char *name,
455 + struct ocfs2_xattr_search *xs)
456 +{
457 + int ret;
458 + struct ocfs2_xattr_block *xb =
459 + (struct ocfs2_xattr_block *)root_bh->b_data;
460 + struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
461 + struct ocfs2_extent_list *el = &xb_root->xt_list;
462 + u64 p_blkno = 0;
463 + u32 first_hash, num_clusters = 0;
464 + u32 name_hash = ocfs2_xattr_hash_by_name(inode, name_index, name);
465 +
466 + if (le16_to_cpu(el->l_next_free_rec) == 0)
467 + return -ENODATA;
468 +
469 + mlog(0, "find xattr %s, hash = %u, index = %d in xattr tree\n",
470 + name, name_hash, name_index);
471 +
472 + ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash,
473 + &num_clusters, el);
474 + if (ret) {
475 + mlog_errno(ret);
476 + goto out;
477 + }
478 +
479 + BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash);
480 +
481 + mlog(0, "find xattr extent rec %u clusters from %llu, the first hash "
482 + "in the rec is %u\n", num_clusters, p_blkno, first_hash);
483 +
484 + ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash,
485 + p_blkno, first_hash, num_clusters, xs);
486 +
487 +out:
488 + return ret;
489 +}
490 +
491 static int ocfs2_iterate_xattr_buckets(struct inode *inode,
492 u64 blkno,
493 u32 clusters,
494 --
495 1.5.4.5
496