btrfs: enhance transaction abort infrastructure
[deliverable/linux.git] / fs / btrfs / dir-item.c
CommitLineData
6cbd5570
CM
1/*
2 * Copyright (C) 2007 Oracle. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
62e2749e
CM
19#include "ctree.h"
20#include "disk-io.h"
21#include "hash.h"
e089f05c 22#include "transaction.h"
62e2749e 23
d352ac68
CM
24/*
25 * insert a name into a directory, doing overflow properly if there is a hash
26 * collision. data_size indicates how big the item inserted should be. On
27 * success a struct btrfs_dir_item pointer is returned, otherwise it is
28 * an ERR_PTR.
29 *
30 * The name is not copied into the dir item, you have to do that yourself.
31 */
35b7e476
CM
32static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
33 *trans,
34 struct btrfs_root *root,
35 struct btrfs_path *path,
36 struct btrfs_key *cpu_key,
e06afa83
CM
37 u32 data_size,
38 const char *name,
39 int name_len)
7fcde0e3 40{
7fcde0e3 41 int ret;
7e38180e
CM
42 char *ptr;
43 struct btrfs_item *item;
5f39d397 44 struct extent_buffer *leaf;
7fcde0e3
CM
45
46 ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
7e38180e 47 if (ret == -EEXIST) {
e06afa83
CM
48 struct btrfs_dir_item *di;
49 di = btrfs_match_dir_item_name(root, path, name, name_len);
50 if (di)
51 return ERR_PTR(-EEXIST);
143bede5
JM
52 btrfs_extend_item(trans, root, path, data_size);
53 } else if (ret < 0)
54aa1f4d 54 return ERR_PTR(ret);
7e38180e 55 WARN_ON(ret > 0);
5f39d397
CM
56 leaf = path->nodes[0];
57 item = btrfs_item_nr(leaf, path->slots[0]);
7e38180e 58 ptr = btrfs_item_ptr(leaf, path->slots[0], char);
5f39d397
CM
59 BUG_ON(data_size > btrfs_item_size(leaf, item));
60 ptr += btrfs_item_size(leaf, item) - data_size;
7e38180e 61 return (struct btrfs_dir_item *)ptr;
7fcde0e3
CM
62}
63
d352ac68
CM
64/*
65 * xattrs work a lot like directories, this inserts an xattr item
66 * into the tree
67 */
5103e947 68int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
f34f57a3
YZ
69 struct btrfs_root *root,
70 struct btrfs_path *path, u64 objectid,
71 const char *name, u16 name_len,
72 const void *data, u16 data_len)
5103e947
JB
73{
74 int ret = 0;
5103e947
JB
75 struct btrfs_dir_item *dir_item;
76 unsigned long name_ptr, data_ptr;
77 struct btrfs_key key, location;
78 struct btrfs_disk_key disk_key;
79 struct extent_buffer *leaf;
80 u32 data_size;
81
f34f57a3
YZ
82 BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
83
84 key.objectid = objectid;
5103e947 85 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
df68b8a7 86 key.offset = btrfs_name_hash(name, name_len);
5103e947
JB
87
88 data_size = sizeof(*dir_item) + name_len + data_len;
89 dir_item = insert_with_overflow(trans, root, path, &key, data_size,
90 name, name_len);
fa09200b
JB
91 if (IS_ERR(dir_item))
92 return PTR_ERR(dir_item);
5103e947
JB
93 memset(&location, 0, sizeof(location));
94
95 leaf = path->nodes[0];
96 btrfs_cpu_key_to_disk(&disk_key, &location);
97 btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
98 btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
99 btrfs_set_dir_name_len(leaf, dir_item, name_len);
e02119d5 100 btrfs_set_dir_transid(leaf, dir_item, trans->transid);
5103e947
JB
101 btrfs_set_dir_data_len(leaf, dir_item, data_len);
102 name_ptr = (unsigned long)(dir_item + 1);
103 data_ptr = (unsigned long)((char *)name_ptr + name_len);
104
105 write_extent_buffer(leaf, name, name_ptr, name_len);
106 write_extent_buffer(leaf, data, data_ptr, data_len);
107 btrfs_mark_buffer_dirty(path->nodes[0]);
108
5103e947
JB
109 return ret;
110}
111
d352ac68
CM
112/*
113 * insert a directory item in the tree, doing all the magic for
114 * both indexes. 'dir' indicates which objectid to insert it into,
115 * 'location' is the key to stuff into the directory item, 'type' is the
116 * type of the inode we're pointing to, and 'index' is the sequence number
117 * to use for the second index (if one is created).
118 */
e089f05c 119int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
16cdcec7
MX
120 *root, const char *name, int name_len,
121 struct inode *dir, struct btrfs_key *location,
122 u8 type, u64 index)
62e2749e
CM
123{
124 int ret = 0;
e06afa83 125 int ret2 = 0;
5caf2a00 126 struct btrfs_path *path;
62e2749e 127 struct btrfs_dir_item *dir_item;
5f39d397
CM
128 struct extent_buffer *leaf;
129 unsigned long name_ptr;
62e2749e 130 struct btrfs_key key;
5f39d397 131 struct btrfs_disk_key disk_key;
62e2749e
CM
132 u32 data_size;
133
0d0ca30f 134 key.objectid = btrfs_ino(dir);
1d4f6404 135 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
df68b8a7 136 key.offset = btrfs_name_hash(name, name_len);
b9473439 137
5caf2a00 138 path = btrfs_alloc_path();
16cdcec7
MX
139 if (!path)
140 return -ENOMEM;
b9473439
CM
141 path->leave_spinning = 1;
142
16cdcec7
MX
143 btrfs_cpu_key_to_disk(&disk_key, location);
144
62e2749e 145 data_size = sizeof(*dir_item) + name_len;
e06afa83
CM
146 dir_item = insert_with_overflow(trans, root, path, &key, data_size,
147 name, name_len);
7e38180e
CM
148 if (IS_ERR(dir_item)) {
149 ret = PTR_ERR(dir_item);
e06afa83
CM
150 if (ret == -EEXIST)
151 goto second_insert;
c2db1073 152 goto out_free;
7e38180e 153 }
62e2749e 154
5f39d397 155 leaf = path->nodes[0];
5f39d397
CM
156 btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
157 btrfs_set_dir_type(leaf, dir_item, type);
5103e947 158 btrfs_set_dir_data_len(leaf, dir_item, 0);
5f39d397 159 btrfs_set_dir_name_len(leaf, dir_item, name_len);
e02119d5 160 btrfs_set_dir_transid(leaf, dir_item, trans->transid);
5f39d397 161 name_ptr = (unsigned long)(dir_item + 1);
c5739bba 162
5f39d397
CM
163 write_extent_buffer(leaf, name, name_ptr, name_len);
164 btrfs_mark_buffer_dirty(leaf);
7e38180e 165
e06afa83 166second_insert:
7e38180e
CM
167 /* FIXME, use some real flag for selecting the extra index */
168 if (root == root->fs_info->tree_root) {
169 ret = 0;
c2db1073 170 goto out_free;
7e38180e 171 }
b3b4aa74 172 btrfs_release_path(path);
7e38180e 173
16cdcec7
MX
174 ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
175 &disk_key, type, index);
c2db1073 176out_free:
5caf2a00 177 btrfs_free_path(path);
e06afa83
CM
178 if (ret)
179 return ret;
180 if (ret2)
181 return ret2;
182 return 0;
62e2749e
CM
183}
184
d352ac68
CM
185/*
186 * lookup a directory item based on name. 'dir' is the objectid
187 * we're searching in, and 'mod' tells us if you plan on deleting the
188 * item (use mod < 0) or changing the options (use mod > 0)
189 */
7e38180e
CM
190struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
191 struct btrfs_root *root,
192 struct btrfs_path *path, u64 dir,
193 const char *name, int name_len,
194 int mod)
62e2749e 195{
1d4f6404 196 int ret;
62e2749e 197 struct btrfs_key key;
1d4f6404
CM
198 int ins_len = mod < 0 ? -1 : 0;
199 int cow = mod != 0;
62e2749e
CM
200
201 key.objectid = dir;
1d4f6404 202 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
5f39d397 203
df68b8a7 204 key.offset = btrfs_name_hash(name, name_len);
5f39d397 205
7e38180e
CM
206 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
207 if (ret < 0)
208 return ERR_PTR(ret);
85d85a74 209 if (ret > 0)
7e38180e
CM
210 return NULL;
211
212 return btrfs_match_dir_item_name(root, path, name, name_len);
62e2749e
CM
213}
214
d352ac68
CM
215/*
216 * lookup a directory item based on index. 'dir' is the objectid
217 * we're searching in, and 'mod' tells us if you plan on deleting the
218 * item (use mod < 0) or changing the options (use mod > 0)
219 *
220 * The name is used to make sure the index really points to the name you were
221 * looking for.
222 */
7e38180e
CM
223struct btrfs_dir_item *
224btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
225 struct btrfs_root *root,
226 struct btrfs_path *path, u64 dir,
227 u64 objectid, const char *name, int name_len,
228 int mod)
229{
230 int ret;
231 struct btrfs_key key;
232 int ins_len = mod < 0 ? -1 : 0;
233 int cow = mod != 0;
234
235 key.objectid = dir;
7e38180e
CM
236 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
237 key.offset = objectid;
238
239 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
240 if (ret < 0)
241 return ERR_PTR(ret);
242 if (ret > 0)
243 return ERR_PTR(-ENOENT);
244 return btrfs_match_dir_item_name(root, path, name, name_len);
245}
246
4df27c4d
YZ
247struct btrfs_dir_item *
248btrfs_search_dir_index_item(struct btrfs_root *root,
249 struct btrfs_path *path, u64 dirid,
250 const char *name, int name_len)
251{
252 struct extent_buffer *leaf;
253 struct btrfs_dir_item *di;
254 struct btrfs_key key;
255 u32 nritems;
256 int ret;
257
258 key.objectid = dirid;
259 key.type = BTRFS_DIR_INDEX_KEY;
260 key.offset = 0;
261
262 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
263 if (ret < 0)
264 return ERR_PTR(ret);
265
266 leaf = path->nodes[0];
267 nritems = btrfs_header_nritems(leaf);
268
269 while (1) {
270 if (path->slots[0] >= nritems) {
271 ret = btrfs_next_leaf(root, path);
272 if (ret < 0)
273 return ERR_PTR(ret);
274 if (ret > 0)
275 break;
276 leaf = path->nodes[0];
277 nritems = btrfs_header_nritems(leaf);
278 continue;
279 }
280
281 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
282 if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
283 break;
284
285 di = btrfs_match_dir_item_name(root, path, name, name_len);
286 if (di)
287 return di;
288
289 path->slots[0]++;
290 }
291 return NULL;
292}
293
5103e947
JB
294struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
295 struct btrfs_root *root,
296 struct btrfs_path *path, u64 dir,
297 const char *name, u16 name_len,
298 int mod)
299{
300 int ret;
301 struct btrfs_key key;
302 int ins_len = mod < 0 ? -1 : 0;
303 int cow = mod != 0;
5103e947
JB
304
305 key.objectid = dir;
306 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
df68b8a7 307 key.offset = btrfs_name_hash(name, name_len);
5103e947
JB
308 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
309 if (ret < 0)
310 return ERR_PTR(ret);
85d85a74 311 if (ret > 0)
5103e947
JB
312 return NULL;
313
314 return btrfs_match_dir_item_name(root, path, name, name_len);
315}
316
d352ac68
CM
317/*
318 * helper function to look at the directory item pointed to by 'path'
319 * this walks through all the entries in a dir item and finds one
320 * for a specific name.
321 */
7e38180e 322struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
7f5c1516
CM
323 struct btrfs_path *path,
324 const char *name, int name_len)
62e2749e 325{
62e2749e 326 struct btrfs_dir_item *dir_item;
5f39d397 327 unsigned long name_ptr;
7e38180e
CM
328 u32 total_len;
329 u32 cur = 0;
330 u32 this_len;
5f39d397 331 struct extent_buffer *leaf;
a8a2ee0c 332
5f39d397 333 leaf = path->nodes[0];
7e38180e 334 dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
22a94d44
JB
335 if (verify_dir_item(root, leaf, dir_item))
336 return NULL;
337
5f39d397 338 total_len = btrfs_item_size_nr(leaf, path->slots[0]);
d397712b 339 while (cur < total_len) {
5f39d397 340 this_len = sizeof(*dir_item) +
5103e947
JB
341 btrfs_dir_name_len(leaf, dir_item) +
342 btrfs_dir_data_len(leaf, dir_item);
5f39d397 343 name_ptr = (unsigned long)(dir_item + 1);
7e38180e 344
5f39d397
CM
345 if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
346 memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
7e38180e
CM
347 return dir_item;
348
349 cur += this_len;
350 dir_item = (struct btrfs_dir_item *)((char *)dir_item +
351 this_len);
352 }
353 return NULL;
62e2749e 354}
7e38180e 355
d352ac68
CM
356/*
357 * given a pointer into a directory item, delete it. This
358 * handles items that have more than one entry in them.
359 */
7e38180e
CM
360int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
361 struct btrfs_root *root,
362 struct btrfs_path *path,
363 struct btrfs_dir_item *di)
364{
365
5f39d397 366 struct extent_buffer *leaf;
7e38180e
CM
367 u32 sub_item_len;
368 u32 item_len;
54aa1f4d 369 int ret = 0;
7e38180e 370
5f39d397 371 leaf = path->nodes[0];
5103e947
JB
372 sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
373 btrfs_dir_data_len(leaf, di);
5f39d397
CM
374 item_len = btrfs_item_size_nr(leaf, path->slots[0]);
375 if (sub_item_len == item_len) {
7e38180e 376 ret = btrfs_del_item(trans, root, path);
7e38180e 377 } else {
5f39d397
CM
378 /* MARKER */
379 unsigned long ptr = (unsigned long)di;
380 unsigned long start;
381
382 start = btrfs_item_ptr_offset(leaf, path->slots[0]);
383 memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
7e38180e 384 item_len - (ptr + sub_item_len - start));
143bede5
JM
385 btrfs_truncate_item(trans, root, path,
386 item_len - sub_item_len, 1);
7e38180e 387 }
411fc6bc 388 return ret;
7e38180e 389}
22a94d44
JB
390
391int verify_dir_item(struct btrfs_root *root,
392 struct extent_buffer *leaf,
393 struct btrfs_dir_item *dir_item)
394{
395 u16 namelen = BTRFS_NAME_LEN;
396 u8 type = btrfs_dir_type(leaf, dir_item);
397
398 if (type >= BTRFS_FT_MAX) {
399 printk(KERN_CRIT "btrfs: invalid dir item type: %d\n",
400 (int)type);
401 return 1;
402 }
403
404 if (type == BTRFS_FT_XATTR)
405 namelen = XATTR_NAME_MAX;
406
407 if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
9694b3fc 408 printk(KERN_CRIT "btrfs: invalid dir item name len: %u\n",
22a94d44
JB
409 (unsigned)btrfs_dir_data_len(leaf, dir_item));
410 return 1;
411 }
412
413 /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
414 if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) {
415 printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n",
416 (unsigned)btrfs_dir_data_len(leaf, dir_item));
417 return 1;
418 }
419
420 return 0;
421}
This page took 0.357106 seconds and 5 git commands to generate.