ocfs2: Add extent tree operation for xattr value btrees
[safe/jmp/linux-2.6] / fs / ocfs2 / xattr.c
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
38 static 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
56 restart_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
75 restarted_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
135 leave:
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
156 static 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
220 out_commit:
221         ocfs2_commit_trans(osb, handle);
222 out:
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
231 static 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
276 out:
277         ocfs2_schedule_truncate_log_flush(osb, 1);
278         ocfs2_run_deallocs(osb, &dealloc);
279
280         return ret;
281 }
282
283 static 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 }