aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/xattr.c
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2008-08-18 05:38:48 -0400
committerMark Fasheh <mfasheh@suse.com>2008-10-13 19:57:01 -0400
commitf56654c435c06f2b2bd5751889b1a08a3add7d6c (patch)
treeb186d68aedc5dda7afe435f5a68c03937ae382ff /fs/ocfs2/xattr.c
parentac11c827192272eabb68b8f4cf844066461d9690 (diff)
ocfs2: Add extent tree operation for xattr value btrees
Add some thin wrappers around ocfs2_insert_extent() for each of the 3 different btree types, ocfs2_inode_insert_extent(), ocfs2_xattr_value_insert_extent() and ocfs2_xattr_tree_insert_extent(). The last is for the xattr index btree, which will be used in a followup patch. All the old callers in file.c etc will call ocfs2_dinode_insert_extent(), while the other two handle the xattr issue. And the init of extent tree are handled by these functions. When storing xattr value which is too large, we will allocate some clusters for it and here ocfs2_extent_list and ocfs2_extent_rec will also be used. In order to re-use the b-tree operation code, a new parameter named "private" is added into ocfs2_extent_tree and it is used to indicate the root of ocfs2_exent_list. The reason is that we can't deduce the root from the buffer_head now. It may be in an inode, an ocfs2_xattr_block or even worse, in any place in an ocfs2_xattr_bucket. Signed-off-by: Tao Ma <tao.ma@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r--fs/ocfs2/xattr.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
new file mode 100644
index 000000000000..9604a4cd02bb
--- /dev/null
+++ b/fs/ocfs2/xattr.c
@@ -0,0 +1,305 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * xattr.c
5 *
6 * Copyright (C) 2008 Oracle. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 021110-1307, USA.
22 */
23
24#define MLOG_MASK_PREFIX ML_XATTR
25#include <cluster/masklog.h>
26
27#include "ocfs2.h"
28#include "alloc.h"
29#include "dlmglue.h"
30#include "file.h"
31#include "inode.h"
32#include "journal.h"
33#include "ocfs2_fs.h"
34#include "suballoc.h"
35#include "uptodate.h"
36#include "buffer_head_io.h"
37
38static int ocfs2_xattr_extend_allocation(struct inode *inode,
39 u32 clusters_to_add,
40 struct buffer_head *xattr_bh,
41 struct ocfs2_xattr_value_root *xv)
42{
43 int status = 0;
44 int restart_func = 0;
45 int credits = 0;
46 handle_t *handle = NULL;
47 struct ocfs2_alloc_context *data_ac = NULL;
48 struct ocfs2_alloc_context *meta_ac = NULL;
49 enum ocfs2_alloc_restarted why;
50 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
51 struct ocfs2_extent_list *root_el = &xv->xr_list;
52 u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters);
53
54 mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
55
56restart_all:
57
58 status = ocfs2_lock_allocators(inode, xattr_bh, root_el,
59 clusters_to_add, 0, &data_ac,
60 &meta_ac, OCFS2_XATTR_VALUE_EXTENT, xv);
61 if (status) {
62 mlog_errno(status);
63 goto leave;
64 }
65
66 credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add);
67 handle = ocfs2_start_trans(osb, credits);
68 if (IS_ERR(handle)) {
69 status = PTR_ERR(handle);
70 handle = NULL;
71 mlog_errno(status);
72 goto leave;
73 }
74
75restarted_transaction:
76 status = ocfs2_journal_access(handle, inode, xattr_bh,
77 OCFS2_JOURNAL_ACCESS_WRITE);
78 if (status < 0) {
79 mlog_errno(status);
80 goto leave;
81 }
82
83 prev_clusters = le32_to_cpu(xv->xr_clusters);
84 status = ocfs2_add_clusters_in_btree(osb,
85 inode,
86 &logical_start,
87 clusters_to_add,
88 0,
89 xattr_bh,
90 root_el,
91 handle,
92 data_ac,
93 meta_ac,
94 &why,
95 OCFS2_XATTR_VALUE_EXTENT,
96 xv);
97 if ((status < 0) && (status != -EAGAIN)) {
98 if (status != -ENOSPC)
99 mlog_errno(status);
100 goto leave;
101 }
102
103 status = ocfs2_journal_dirty(handle, xattr_bh);
104 if (status < 0) {
105 mlog_errno(status);
106 goto leave;
107 }
108
109 clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters;
110
111 if (why != RESTART_NONE && clusters_to_add) {
112 if (why == RESTART_META) {
113 mlog(0, "restarting function.\n");
114 restart_func = 1;
115 } else {
116 BUG_ON(why != RESTART_TRANS);
117
118 mlog(0, "restarting transaction.\n");
119 /* TODO: This can be more intelligent. */
120 credits = ocfs2_calc_extend_credits(osb->sb,
121 root_el,
122 clusters_to_add);
123 status = ocfs2_extend_trans(handle, credits);
124 if (status < 0) {
125 /* handle still has to be committed at
126 * this point. */
127 status = -ENOMEM;
128 mlog_errno(status);
129 goto leave;
130 }
131 goto restarted_transaction;
132 }
133 }
134
135leave:
136 if (handle) {
137 ocfs2_commit_trans(osb, handle);
138 handle = NULL;
139 }
140 if (data_ac) {
141 ocfs2_free_alloc_context(data_ac);
142 data_ac = NULL;
143 }
144 if (meta_ac) {
145 ocfs2_free_alloc_context(meta_ac);
146 meta_ac = NULL;
147 }
148 if ((!status) && restart_func) {
149 restart_func = 0;
150 goto restart_all;
151 }
152
153 return status;
154}
155
156static int __ocfs2_remove_xattr_range(struct inode *inode,
157 struct buffer_head *root_bh,
158 struct ocfs2_xattr_value_root *xv,
159 u32 cpos, u32 phys_cpos, u32 len,
160 struct ocfs2_cached_dealloc_ctxt *dealloc)
161{
162 int ret;
163 u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
164 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
165 struct inode *tl_inode = osb->osb_tl_inode;
166 handle_t *handle;
167 struct ocfs2_alloc_context *meta_ac = NULL;
168
169 ret = ocfs2_lock_allocators(inode, root_bh, &xv->xr_list,
170 0, 1, NULL, &meta_ac,
171 OCFS2_XATTR_VALUE_EXTENT, xv);
172 if (ret) {
173 mlog_errno(ret);
174 return ret;
175 }
176
177 mutex_lock(&tl_inode->i_mutex);
178
179 if (ocfs2_truncate_log_needs_flush(osb)) {
180 ret = __ocfs2_flush_truncate_log(osb);
181 if (ret < 0) {
182 mlog_errno(ret);
183 goto out;
184 }
185 }
186
187 handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
188 if (IS_ERR(handle)) {
189 ret = PTR_ERR(handle);
190 mlog_errno(ret);
191 goto out;
192 }
193
194 ret = ocfs2_journal_access(handle, inode, root_bh,
195 OCFS2_JOURNAL_ACCESS_WRITE);
196 if (ret) {
197 mlog_errno(ret);
198 goto out_commit;
199 }
200
201 ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac,
202 dealloc, OCFS2_XATTR_VALUE_EXTENT, xv);
203 if (ret) {
204 mlog_errno(ret);
205 goto out_commit;
206 }
207
208 le32_add_cpu(&xv->xr_clusters, -len);
209
210 ret = ocfs2_journal_dirty(handle, root_bh);
211 if (ret) {
212 mlog_errno(ret);
213 goto out_commit;
214 }
215
216 ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
217 if (ret)
218 mlog_errno(ret);
219
220out_commit:
221 ocfs2_commit_trans(osb, handle);
222out:
223 mutex_unlock(&tl_inode->i_mutex);
224
225 if (meta_ac)
226 ocfs2_free_alloc_context(meta_ac);
227
228 return ret;
229}
230
231static int ocfs2_xattr_shrink_size(struct inode *inode,
232 u32 old_clusters,
233 u32 new_clusters,
234 struct buffer_head *root_bh,
235 struct ocfs2_xattr_value_root *xv)
236{
237 int ret = 0;
238 u32 trunc_len, cpos, phys_cpos, alloc_size;
239 u64 block;
240 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
241 struct ocfs2_cached_dealloc_ctxt dealloc;
242
243 ocfs2_init_dealloc_ctxt(&dealloc);
244
245 if (old_clusters <= new_clusters)
246 return 0;
247
248 cpos = new_clusters;
249 trunc_len = old_clusters - new_clusters;
250 while (trunc_len) {
251 ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
252 &alloc_size, &xv->xr_list);
253 if (ret) {
254 mlog_errno(ret);
255 goto out;
256 }
257
258 if (alloc_size > trunc_len)
259 alloc_size = trunc_len;
260
261 ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos,
262 phys_cpos, alloc_size,
263 &dealloc);
264 if (ret) {
265 mlog_errno(ret);
266 goto out;
267 }
268
269 block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
270 ocfs2_remove_xattr_clusters_from_cache(inode, block,
271 alloc_size);
272 cpos += alloc_size;
273 trunc_len -= alloc_size;
274 }
275
276out:
277 ocfs2_schedule_truncate_log_flush(osb, 1);
278 ocfs2_run_deallocs(osb, &dealloc);
279
280 return ret;
281}
282
283static int ocfs2_xattr_value_truncate(struct inode *inode,
284 struct buffer_head *root_bh,
285 struct ocfs2_xattr_value_root *xv,
286 int len)
287{
288 int ret;
289 u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
290 u32 old_clusters = le32_to_cpu(xv->xr_clusters);
291
292 if (new_clusters == old_clusters)
293 return 0;
294
295 if (new_clusters > old_clusters)
296 ret = ocfs2_xattr_extend_allocation(inode,
297 new_clusters - old_clusters,
298 root_bh, xv);
299 else
300 ret = ocfs2_xattr_shrink_size(inode,
301 old_clusters, new_clusters,
302 root_bh, xv);
303
304 return ret;
305}