]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-empty-bucket-support-in-xattr.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-empty-bucket-support-in-xattr.patch
1 From: Tao Ma <tao.ma@oracle.com>
2 Subject: ocfs2: Add empty bucket support in xattr.
3 Patch-mainline: 2.6.28
4
5 As Mark mentioned, it may be time-consuming when we remove the
6 empty xattr bucket, so this patch try to let empty bucket exist
7 in xattr operation. The modification includes:
8 1. Remove the functin of bucket and extent record deletion during
9 xattr delete.
10 2. In xattr set:
11 1) Don't clean the last entry so that if the bucket is empty,
12 the hash value of the bucket is the hash value of the entry
13 which is deleted last.
14 2) During insert, if we meet with an empty bucket, just use the
15 1st entry.
16 3. In binary search of xattr bucket, use the bucket hash value(which
17 stored in the 1st xattr entry) to find the right place.
18
19 Signed-off-by: Tao Ma <tao.ma@oracle.com>
20 Signed-off-by: Mark Fasheh <mfasheh@suse.com>
21 ---
22 fs/ocfs2/xattr.c | 197 ++++++++++++------------------------------------------
23 1 files changed, 43 insertions(+), 154 deletions(-)
24
25 Index: linux-2.6.27/fs/ocfs2/xattr.c
26 ===================================================================
27 --- linux-2.6.27.orig/fs/ocfs2/xattr.c
28 +++ linux-2.6.27/fs/ocfs2/xattr.c
29 @@ -2317,9 +2317,12 @@ static int ocfs2_xattr_bucket_find(struc
30
31 /*
32 * Check whether the hash of the last entry in our
33 - * bucket is larger than the search one.
34 + * bucket is larger than the search one. for an empty
35 + * bucket, the last one is also the first one.
36 */
37 - xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
38 + if (xh->xh_count)
39 + xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
40 +
41 last_hash = le32_to_cpu(xe->xe_name_hash);
42
43 /* record lower_bh which may be the insert place. */
44 @@ -2466,7 +2469,8 @@ static int ocfs2_iterate_xattr_buckets(s
45 if (i == 0)
46 num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets);
47
48 - mlog(0, "iterating xattr bucket %llu\n", blkno);
49 + mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno,
50 + le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
51 if (func) {
52 ret = func(inode, &bucket, para);
53 if (ret) {
54 @@ -3931,8 +3935,6 @@ static inline char *ocfs2_xattr_bucket_g
55
56 /*
57 * Handle the normal xattr set, including replace, delete and new.
58 - * When the bucket is empty, "is_empty" is set and the caller can
59 - * free this bucket.
60 *
61 * Note: "local" indicates the real data's locality. So we can't
62 * just its bucket locality by its length.
63 @@ -3941,8 +3943,7 @@ static void ocfs2_xattr_set_entry_normal
64 struct ocfs2_xattr_info *xi,
65 struct ocfs2_xattr_search *xs,
66 u32 name_hash,
67 - int local,
68 - int *is_empty)
69 + int local)
70 {
71 struct ocfs2_xattr_entry *last, *xe;
72 int name_len = strlen(xi->name);
73 @@ -3995,14 +3996,23 @@ static void ocfs2_xattr_set_entry_normal
74 ocfs2_xattr_set_local(xe, local);
75 return;
76 } else {
77 - /* Remove the old entry. */
78 + /*
79 + * Remove the old entry if there is more than one.
80 + * We don't remove the last entry so that we can
81 + * use it to indicate the hash value of the empty
82 + * bucket.
83 + */
84 last -= 1;
85 - memmove(xe, xe + 1,
86 - (void *)last - (void *)xe);
87 - memset(last, 0, sizeof(struct ocfs2_xattr_entry));
88 le16_add_cpu(&xh->xh_count, -1);
89 - if (xh->xh_count == 0 && is_empty)
90 - *is_empty = 1;
91 + if (xh->xh_count) {
92 + memmove(xe, xe + 1,
93 + (void *)last - (void *)xe);
94 + memset(last, 0,
95 + sizeof(struct ocfs2_xattr_entry));
96 + } else
97 + xh->xh_free_start =
98 + cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
99 +
100 return;
101 }
102 } else {
103 @@ -4010,7 +4020,7 @@ static void ocfs2_xattr_set_entry_normal
104 int low = 0, high = count - 1, tmp;
105 struct ocfs2_xattr_entry *tmp_xe;
106
107 - while (low <= high) {
108 + while (low <= high && count) {
109 tmp = (low + high) / 2;
110 tmp_xe = &xh->xh_entries[tmp];
111
112 @@ -4106,8 +4116,7 @@ static int ocfs2_xattr_set_entry_in_buck
113 struct ocfs2_xattr_info *xi,
114 struct ocfs2_xattr_search *xs,
115 u32 name_hash,
116 - int local,
117 - int *bucket_empty)
118 + int local)
119 {
120 int i, ret;
121 handle_t *handle = NULL;
122 @@ -4146,8 +4155,7 @@ static int ocfs2_xattr_set_entry_in_buck
123 }
124 }
125
126 - ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash,
127 - local, bucket_empty);
128 + ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local);
129
130 /*Only dirty the blocks we have touched in set xattr. */
131 ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs,
132 @@ -4296,69 +4304,6 @@ static int ocfs2_xattr_bucket_set_value_
133 return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len);
134 }
135
136 -/*
137 - * Remove the xattr bucket pointed by bucket_bh.
138 - * All the buckets after it in the same xattr extent rec will be
139 - * move forward one by one.
140 - */
141 -static int ocfs2_rm_xattr_bucket(struct inode *inode,
142 - struct buffer_head *first_bh,
143 - struct ocfs2_xattr_bucket *bucket)
144 -{
145 - int ret = 0, credits;
146 - struct ocfs2_xattr_header *xh =
147 - (struct ocfs2_xattr_header *)first_bh->b_data;
148 - u16 bucket_num = le16_to_cpu(xh->xh_num_buckets);
149 - u64 end, start = bucket->bhs[0]->b_blocknr;
150 - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
151 - handle_t *handle;
152 - u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
153 -
154 - end = first_bh->b_blocknr + (bucket_num - 1) * blk_per_bucket;
155 -
156 - mlog(0, "rm xattr bucket %llu\n", start);
157 - /*
158 - * We need to update the first xattr_header and all the buckets starting
159 - * from start in this xattr rec.
160 - *
161 - * XXX: Should we empty the old last bucket here?
162 - */
163 - credits = 1 + end - start;
164 - handle = ocfs2_start_trans(osb, credits);
165 - if (IS_ERR(handle)) {
166 - ret = PTR_ERR(handle);
167 - mlog_errno(ret);
168 - return ret;
169 - }
170 -
171 - ret = ocfs2_journal_access(handle, inode, first_bh,
172 - OCFS2_JOURNAL_ACCESS_WRITE);
173 - if (ret) {
174 - mlog_errno(ret);
175 - goto out_commit;
176 - }
177 -
178 -
179 - while (start < end) {
180 - ret = ocfs2_cp_xattr_bucket(inode, handle,
181 - start + blk_per_bucket,
182 - start, 0);
183 - if (ret) {
184 - mlog_errno(ret);
185 - goto out_commit;
186 - }
187 - start += blk_per_bucket;
188 - }
189 -
190 - /* update the first_bh. */
191 - xh->xh_num_buckets = cpu_to_le16(bucket_num - 1);
192 - ocfs2_journal_dirty(handle, first_bh);
193 -
194 -out_commit:
195 - ocfs2_commit_trans(osb, handle);
196 - return ret;
197 -}
198 -
199 static int ocfs2_rm_xattr_cluster(struct inode *inode,
200 struct buffer_head *root_bh,
201 u64 blkno,
202 @@ -4448,57 +4393,6 @@ out:
203 return ret;
204 }
205
206 -/*
207 - * Free the xattr bucket indicated by xs->bucket and if all the buckets
208 - * in the clusters is free, free the clusters also.
209 - */
210 -static int ocfs2_xattr_bucket_shrink(struct inode *inode,
211 - struct ocfs2_xattr_info *xi,
212 - struct ocfs2_xattr_search *xs,
213 - u32 name_hash)
214 -{
215 - int ret;
216 - u32 e_cpos, num_clusters;
217 - u64 p_blkno;
218 - struct buffer_head *first_bh = NULL;
219 - struct ocfs2_xattr_header *first_xh;
220 - struct ocfs2_xattr_block *xb =
221 - (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
222 -
223 - BUG_ON(xs->header->xh_count != 0);
224 -
225 - ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
226 - &e_cpos, &num_clusters,
227 - &xb->xb_attrs.xb_root.xt_list);
228 - if (ret) {
229 - mlog_errno(ret);
230 - return ret;
231 - }
232 -
233 - ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
234 - &first_bh, OCFS2_BH_CACHED, inode);
235 - if (ret) {
236 - mlog_errno(ret);
237 - return ret;
238 - }
239 -
240 - ret = ocfs2_rm_xattr_bucket(inode, first_bh, &xs->bucket);
241 - if (ret) {
242 - mlog_errno(ret);
243 - goto out;
244 - }
245 -
246 - first_xh = (struct ocfs2_xattr_header *)first_bh->b_data;
247 - if (first_xh->xh_num_buckets == 0)
248 - ret = ocfs2_rm_xattr_cluster(inode, xs->xattr_bh,
249 - p_blkno, e_cpos,
250 - num_clusters);
251 -
252 -out:
253 - brelse(first_bh);
254 - return ret;
255 -}
256 -
257 static void ocfs2_xattr_bucket_remove_xs(struct inode *inode,
258 struct ocfs2_xattr_search *xs)
259 {
260 @@ -4550,7 +4444,7 @@ static int ocfs2_xattr_set_in_bucket(str
261 struct ocfs2_xattr_info *xi,
262 struct ocfs2_xattr_search *xs)
263 {
264 - int ret, local = 1, bucket_empty = 0;
265 + int ret, local = 1;
266 size_t value_len;
267 char *val = (char *)xi->value;
268 struct ocfs2_xattr_entry *xe = xs->here;
269 @@ -4596,34 +4490,29 @@ static int ocfs2_xattr_set_in_bucket(str
270 xi->value_len = OCFS2_XATTR_ROOT_SIZE;
271 }
272
273 - ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash,
274 - local, &bucket_empty);
275 + ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local);
276 if (ret) {
277 mlog_errno(ret);
278 goto out;
279 }
280
281 - if (value_len > OCFS2_XATTR_INLINE_SIZE) {
282 - /* allocate the space now for the outside block storage. */
283 - ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
284 - value_len);
285 - if (ret) {
286 - mlog_errno(ret);
287 + if (value_len <= OCFS2_XATTR_INLINE_SIZE)
288 + goto out;
289
290 - if (xs->not_found) {
291 - /*
292 - * We can't allocate enough clusters for outside
293 - * storage and we have allocated xattr already,
294 - * so need to remove it.
295 - */
296 - ocfs2_xattr_bucket_remove_xs(inode, xs);
297 - }
298 - goto out;
299 + /* allocate the space now for the outside block storage. */
300 + ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
301 + value_len);
302 + if (ret) {
303 + mlog_errno(ret);
304 +
305 + if (xs->not_found) {
306 + /*
307 + * We can't allocate enough clusters for outside
308 + * storage and we have allocated xattr already,
309 + * so need to remove it.
310 + */
311 + ocfs2_xattr_bucket_remove_xs(inode, xs);
312 }
313 - } else {
314 - if (bucket_empty)
315 - ret = ocfs2_xattr_bucket_shrink(inode, xi,
316 - xs, name_hash);
317 goto out;
318 }
319