Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
inode-item.c
Go to the documentation of this file.
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 
19 #include "ctree.h"
20 #include "disk-io.h"
21 #include "hash.h"
22 #include "transaction.h"
23 #include "print-tree.h"
24 
25 static int find_name_in_backref(struct btrfs_path *path, const char *name,
26  int name_len, struct btrfs_inode_ref **ref_ret)
27 {
28  struct extent_buffer *leaf;
29  struct btrfs_inode_ref *ref;
30  unsigned long ptr;
31  unsigned long name_ptr;
32  u32 item_size;
33  u32 cur_offset = 0;
34  int len;
35 
36  leaf = path->nodes[0];
37  item_size = btrfs_item_size_nr(leaf, path->slots[0]);
38  ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
39  while (cur_offset < item_size) {
40  ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
41  len = btrfs_inode_ref_name_len(leaf, ref);
42  name_ptr = (unsigned long)(ref + 1);
43  cur_offset += len + sizeof(*ref);
44  if (len != name_len)
45  continue;
46  if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
47  *ref_ret = ref;
48  return 1;
49  }
50  }
51  return 0;
52 }
53 
54 int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
55  const char *name, int name_len,
56  struct btrfs_inode_extref **extref_ret)
57 {
58  struct extent_buffer *leaf;
59  struct btrfs_inode_extref *extref;
60  unsigned long ptr;
61  unsigned long name_ptr;
62  u32 item_size;
63  u32 cur_offset = 0;
64  int ref_name_len;
65 
66  leaf = path->nodes[0];
67  item_size = btrfs_item_size_nr(leaf, path->slots[0]);
68  ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
69 
70  /*
71  * Search all extended backrefs in this item. We're only
72  * looking through any collisions so most of the time this is
73  * just going to compare against one buffer. If all is well,
74  * we'll return success and the inode ref object.
75  */
76  while (cur_offset < item_size) {
77  extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
78  name_ptr = (unsigned long)(&extref->name);
79  ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
80 
81  if (ref_name_len == name_len &&
82  btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
83  (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) {
84  if (extref_ret)
85  *extref_ret = extref;
86  return 1;
87  }
88 
89  cur_offset += ref_name_len + sizeof(*extref);
90  }
91  return 0;
92 }
93 
94 static struct btrfs_inode_ref *
95 btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
96  struct btrfs_root *root,
97  struct btrfs_path *path,
98  const char *name, int name_len,
99  u64 inode_objectid, u64 ref_objectid, int ins_len,
100  int cow)
101 {
102  int ret;
103  struct btrfs_key key;
104  struct btrfs_inode_ref *ref;
105 
106  key.objectid = inode_objectid;
107  key.type = BTRFS_INODE_REF_KEY;
108  key.offset = ref_objectid;
109 
110  ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
111  if (ret < 0)
112  return ERR_PTR(ret);
113  if (ret > 0)
114  return NULL;
115  if (!find_name_in_backref(path, name, name_len, &ref))
116  return NULL;
117  return ref;
118 }
119 
120 /* Returns NULL if no extref found */
121 struct btrfs_inode_extref *
123  struct btrfs_root *root,
124  struct btrfs_path *path,
125  const char *name, int name_len,
126  u64 inode_objectid, u64 ref_objectid, int ins_len,
127  int cow)
128 {
129  int ret;
130  struct btrfs_key key;
131  struct btrfs_inode_extref *extref;
132 
133  key.objectid = inode_objectid;
135  key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
136 
137  ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
138  if (ret < 0)
139  return ERR_PTR(ret);
140  if (ret > 0)
141  return NULL;
142  if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref))
143  return NULL;
144  return extref;
145 }
146 
148  struct btrfs_root *root,
149  struct btrfs_path *path,
150  const char *name, int name_len,
151  u64 inode_objectid, u64 ref_objectid, int mod,
152  u64 *ret_index)
153 {
154  struct btrfs_inode_ref *ref;
155  struct btrfs_inode_extref *extref;
156  int ins_len = mod < 0 ? -1 : 0;
157  int cow = mod != 0;
158 
159  ref = btrfs_lookup_inode_ref(trans, root, path, name, name_len,
160  inode_objectid, ref_objectid, ins_len,
161  cow);
162  if (IS_ERR(ref))
163  return PTR_ERR(ref);
164 
165  if (ref != NULL) {
166  *ret_index = btrfs_inode_ref_index(path->nodes[0], ref);
167  return 0;
168  }
169 
170  btrfs_release_path(path);
171 
172  extref = btrfs_lookup_inode_extref(trans, root, path, name,
173  name_len, inode_objectid,
174  ref_objectid, ins_len, cow);
175  if (IS_ERR(extref))
176  return PTR_ERR(extref);
177 
178  if (extref) {
179  *ret_index = btrfs_inode_extref_index(path->nodes[0], extref);
180  return 0;
181  }
182 
183  return -ENOENT;
184 }
185 
187  struct btrfs_root *root,
188  const char *name, int name_len,
189  u64 inode_objectid, u64 ref_objectid, u64 *index)
190 {
191  struct btrfs_path *path;
192  struct btrfs_key key;
193  struct btrfs_inode_extref *extref;
194  struct extent_buffer *leaf;
195  int ret;
196  int del_len = name_len + sizeof(*extref);
197  unsigned long ptr;
198  unsigned long item_start;
199  u32 item_size;
200 
201  key.objectid = inode_objectid;
202  btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
203  key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
204 
205  path = btrfs_alloc_path();
206  if (!path)
207  return -ENOMEM;
208 
209  path->leave_spinning = 1;
210 
211  ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
212  if (ret > 0)
213  ret = -ENOENT;
214  if (ret < 0)
215  goto out;
216 
217  /*
218  * Sanity check - did we find the right item for this name?
219  * This should always succeed so error here will make the FS
220  * readonly.
221  */
222  if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
223  name, name_len, &extref)) {
224  btrfs_std_error(root->fs_info, -ENOENT);
225  ret = -EROFS;
226  goto out;
227  }
228 
229  leaf = path->nodes[0];
230  item_size = btrfs_item_size_nr(leaf, path->slots[0]);
231  if (index)
232  *index = btrfs_inode_extref_index(leaf, extref);
233 
234  if (del_len == item_size) {
235  /*
236  * Common case only one ref in the item, remove the
237  * whole item.
238  */
239  ret = btrfs_del_item(trans, root, path);
240  goto out;
241  }
242 
243  ptr = (unsigned long)extref;
244  item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
245 
246  memmove_extent_buffer(leaf, ptr, ptr + del_len,
247  item_size - (ptr + del_len - item_start));
248 
249  btrfs_truncate_item(trans, root, path, item_size - del_len, 1);
250 
251 out:
252  btrfs_free_path(path);
253 
254  return ret;
255 }
256 
258  struct btrfs_root *root,
259  const char *name, int name_len,
260  u64 inode_objectid, u64 ref_objectid, u64 *index)
261 {
262  struct btrfs_path *path;
263  struct btrfs_key key;
264  struct btrfs_inode_ref *ref;
265  struct extent_buffer *leaf;
266  unsigned long ptr;
267  unsigned long item_start;
268  u32 item_size;
269  u32 sub_item_len;
270  int ret;
271  int search_ext_refs = 0;
272  int del_len = name_len + sizeof(*ref);
273 
274  key.objectid = inode_objectid;
275  key.offset = ref_objectid;
276  btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
277 
278  path = btrfs_alloc_path();
279  if (!path)
280  return -ENOMEM;
281 
282  path->leave_spinning = 1;
283 
284  ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
285  if (ret > 0) {
286  ret = -ENOENT;
287  search_ext_refs = 1;
288  goto out;
289  } else if (ret < 0) {
290  goto out;
291  }
292  if (!find_name_in_backref(path, name, name_len, &ref)) {
293  ret = -ENOENT;
294  search_ext_refs = 1;
295  goto out;
296  }
297  leaf = path->nodes[0];
298  item_size = btrfs_item_size_nr(leaf, path->slots[0]);
299 
300  if (index)
301  *index = btrfs_inode_ref_index(leaf, ref);
302 
303  if (del_len == item_size) {
304  ret = btrfs_del_item(trans, root, path);
305  goto out;
306  }
307  ptr = (unsigned long)ref;
308  sub_item_len = name_len + sizeof(*ref);
309  item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
310  memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
311  item_size - (ptr + sub_item_len - item_start));
312  btrfs_truncate_item(trans, root, path, item_size - sub_item_len, 1);
313 out:
314  btrfs_free_path(path);
315 
316  if (search_ext_refs) {
317  /*
318  * No refs were found, or we could not find the
319  * name in our ref array. Find and remove the extended
320  * inode ref then.
321  */
322  return btrfs_del_inode_extref(trans, root, name, name_len,
323  inode_objectid, ref_objectid, index);
324  }
325 
326  return ret;
327 }
328 
329 /*
330  * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
331  *
332  * The caller must have checked against BTRFS_LINK_MAX already.
333  */
334 static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
335  struct btrfs_root *root,
336  const char *name, int name_len,
337  u64 inode_objectid, u64 ref_objectid, u64 index)
338 {
339  struct btrfs_inode_extref *extref;
340  int ret;
341  int ins_len = name_len + sizeof(*extref);
342  unsigned long ptr;
343  struct btrfs_path *path;
344  struct btrfs_key key;
345  struct extent_buffer *leaf;
346  struct btrfs_item *item;
347 
348  key.objectid = inode_objectid;
350  key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
351 
352  path = btrfs_alloc_path();
353  if (!path)
354  return -ENOMEM;
355 
356  path->leave_spinning = 1;
357  ret = btrfs_insert_empty_item(trans, root, path, &key,
358  ins_len);
359  if (ret == -EEXIST) {
360  if (btrfs_find_name_in_ext_backref(path, ref_objectid,
361  name, name_len, NULL))
362  goto out;
363 
364  btrfs_extend_item(trans, root, path, ins_len);
365  ret = 0;
366  }
367  if (ret < 0)
368  goto out;
369 
370  leaf = path->nodes[0];
371  item = btrfs_item_nr(leaf, path->slots[0]);
372  ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
373  ptr += btrfs_item_size(leaf, item) - ins_len;
374  extref = (struct btrfs_inode_extref *)ptr;
375 
376  btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
377  btrfs_set_inode_extref_index(path->nodes[0], extref, index);
378  btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
379 
380  ptr = (unsigned long)&extref->name;
381  write_extent_buffer(path->nodes[0], name, ptr, name_len);
382  btrfs_mark_buffer_dirty(path->nodes[0]);
383 
384 out:
385  btrfs_free_path(path);
386  return ret;
387 }
388 
389 /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
391  struct btrfs_root *root,
392  const char *name, int name_len,
393  u64 inode_objectid, u64 ref_objectid, u64 index)
394 {
395  struct btrfs_path *path;
396  struct btrfs_key key;
397  struct btrfs_inode_ref *ref;
398  unsigned long ptr;
399  int ret;
400  int ins_len = name_len + sizeof(*ref);
401 
402  key.objectid = inode_objectid;
403  key.offset = ref_objectid;
404  btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
405 
406  path = btrfs_alloc_path();
407  if (!path)
408  return -ENOMEM;
409 
410  path->leave_spinning = 1;
411  ret = btrfs_insert_empty_item(trans, root, path, &key,
412  ins_len);
413  if (ret == -EEXIST) {
414  u32 old_size;
415 
416  if (find_name_in_backref(path, name, name_len, &ref))
417  goto out;
418 
419  old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
420  btrfs_extend_item(trans, root, path, ins_len);
421  ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
422  struct btrfs_inode_ref);
423  ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
424  btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
425  btrfs_set_inode_ref_index(path->nodes[0], ref, index);
426  ptr = (unsigned long)(ref + 1);
427  ret = 0;
428  } else if (ret < 0) {
429  if (ret == -EOVERFLOW)
430  ret = -EMLINK;
431  goto out;
432  } else {
433  ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
434  struct btrfs_inode_ref);
435  btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
436  btrfs_set_inode_ref_index(path->nodes[0], ref, index);
437  ptr = (unsigned long)(ref + 1);
438  }
439  write_extent_buffer(path->nodes[0], name, ptr, name_len);
440  btrfs_mark_buffer_dirty(path->nodes[0]);
441 
442 out:
443  btrfs_free_path(path);
444 
445  if (ret == -EMLINK) {
446  struct btrfs_super_block *disk_super = root->fs_info->super_copy;
447  /* We ran out of space in the ref array. Need to
448  * add an extended ref. */
449  if (btrfs_super_incompat_flags(disk_super)
451  ret = btrfs_insert_inode_extref(trans, root, name,
452  name_len,
453  inode_objectid,
454  ref_objectid, index);
455  }
456 
457  return ret;
458 }
459 
461  struct btrfs_root *root,
462  struct btrfs_path *path, u64 objectid)
463 {
464  struct btrfs_key key;
465  int ret;
466  key.objectid = objectid;
467  btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
468  key.offset = 0;
469 
470  ret = btrfs_insert_empty_item(trans, root, path, &key,
471  sizeof(struct btrfs_inode_item));
472  return ret;
473 }
474 
476  *root, struct btrfs_path *path,
477  struct btrfs_key *location, int mod)
478 {
479  int ins_len = mod < 0 ? -1 : 0;
480  int cow = mod != 0;
481  int ret;
482  int slot;
483  struct extent_buffer *leaf;
484  struct btrfs_key found_key;
485 
486  ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
487  if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY &&
488  location->offset == (u64)-1 && path->slots[0] != 0) {
489  slot = path->slots[0] - 1;
490  leaf = path->nodes[0];
491  btrfs_item_key_to_cpu(leaf, &found_key, slot);
492  if (found_key.objectid == location->objectid &&
493  btrfs_key_type(&found_key) == btrfs_key_type(location)) {
494  path->slots[0]--;
495  return 0;
496  }
497  }
498  return ret;
499 }