2 * Copyright (C) 2007 Oracle. All rights reserved.
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.
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.
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.
21 #include "transaction.h"
24 static int find_name_in_backref(struct btrfs_path
*path
, const char * name
,
25 int name_len
, struct btrfs_inode_ref
**ref_ret
)
27 struct extent_buffer
*leaf
;
28 struct btrfs_inode_ref
*ref
;
30 unsigned long name_ptr
;
35 leaf
= path
->nodes
[0];
36 item_size
= btrfs_item_size_nr(leaf
, path
->slots
[0]);
37 ptr
= btrfs_item_ptr_offset(leaf
, path
->slots
[0]);
38 while (cur_offset
< item_size
) {
39 ref
= (struct btrfs_inode_ref
*)(ptr
+ cur_offset
);
40 len
= btrfs_inode_ref_name_len(leaf
, ref
);
41 name_ptr
= (unsigned long)(ref
+ 1);
42 cur_offset
+= len
+ sizeof(*ref
);
45 if (memcmp_extent_buffer(leaf
, name
, name_ptr
, name_len
) == 0) {
53 int btrfs_insert_inode_ref(struct btrfs_trans_handle
*trans
,
54 struct btrfs_root
*root
,
55 const char *name
, int name_len
,
56 u64 inode_objectid
, u64 ref_objectid
, u64 index
)
58 struct btrfs_path
*path
;
60 struct btrfs_inode_ref
*ref
;
63 int ins_len
= name_len
+ sizeof(*ref
);
65 key
.objectid
= inode_objectid
;
66 key
.offset
= ref_objectid
;
67 btrfs_set_key_type(&key
, BTRFS_INODE_REF_KEY
);
69 path
= btrfs_alloc_path();
73 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
78 if (find_name_in_backref(path
, name
, name_len
, &ref
))
81 old_size
= btrfs_item_size_nr(path
->nodes
[0], path
->slots
[0]);
82 ret
= btrfs_extend_item(trans
, root
, path
, ins_len
);
84 ref
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
85 struct btrfs_inode_ref
);
86 ref
= (struct btrfs_inode_ref
*)((unsigned long)ref
+ old_size
);
87 btrfs_set_inode_ref_name_len(path
->nodes
[0], ref
, name_len
);
88 btrfs_set_inode_ref_index(path
->nodes
[0], ref
, index
);
89 ptr
= (unsigned long)(ref
+ 1);
94 ref
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
95 struct btrfs_inode_ref
);
96 btrfs_set_inode_ref_name_len(path
->nodes
[0], ref
, name_len
);
97 btrfs_set_inode_ref_index(path
->nodes
[0], ref
, index
);
98 ptr
= (unsigned long)(ref
+ 1);
100 write_extent_buffer(path
->nodes
[0], name
, ptr
, name_len
);
101 btrfs_mark_buffer_dirty(path
->nodes
[0]);
104 btrfs_free_path(path
);
108 int btrfs_lookup_inode(struct btrfs_trans_handle
*trans
, struct btrfs_root
109 *root
, struct btrfs_path
*path
,
110 struct btrfs_key
*location
, int mod
)
112 int ins_len
= mod
< 0 ? -1 : 0;
116 struct extent_buffer
*leaf
;
117 struct btrfs_key found_key
;
119 ret
= btrfs_search_slot(trans
, root
, location
, path
, ins_len
, cow
);
120 if (ret
> 0 && btrfs_key_type(location
) == BTRFS_ROOT_ITEM_KEY
&&
121 location
->offset
== (u64
)-1 && path
->slots
[0] != 0) {
122 slot
= path
->slots
[0] - 1;
123 leaf
= path
->nodes
[0];
124 btrfs_item_key_to_cpu(leaf
, &found_key
, slot
);
125 if (found_key
.objectid
== location
->objectid
&&
126 btrfs_key_type(&found_key
) == btrfs_key_type(location
)) {
134 int btrfs_insert_inode(struct btrfs_trans_handle
*trans
, struct btrfs_root
135 *root
, u64 objectid
, struct btrfs_inode_item
139 struct btrfs_key key
;
141 key
.objectid
= objectid
;
142 key
.type
= BTRFS_INODE_ITEM_KEY
;
145 ret
= btrfs_insert_item(trans
, root
, &key
, inode_item
,
146 sizeof(*inode_item
));
150 static inline u64
btrfs_extref_hash(u64 parent_ino
, const char *name
,
153 return (u64
)btrfs_crc32c(parent_ino
, name
, namelen
);
156 static int btrfs_find_name_in_ext_backref(struct btrfs_path
*path
,
157 u64 parent_ino
, const char *name
, int namelen
,
158 struct btrfs_inode_extref
**extref_ret
)
160 struct extent_buffer
*node
;
161 struct btrfs_inode_extref
*extref
;
163 unsigned long name_ptr
;
169 node
= path
->nodes
[0];
170 slot
= path
->slots
[0];
171 item_size
= btrfs_item_size_nr(node
, slot
);
172 ptr
= btrfs_item_ptr_offset(node
, slot
);
175 * Search all extended backrefs in this item. We're only looking
176 * through any collisions so most of the time this is just going to
177 * compare against one buffer. If all is well, we'll return success and
178 * the inode ref object.
180 while (cur_offset
< item_size
) {
181 extref
= (struct btrfs_inode_extref
*) (ptr
+ cur_offset
);
182 name_ptr
= (unsigned long)(&extref
->name
);
183 ref_name_len
= btrfs_inode_extref_name_len(node
, extref
);
185 if (ref_name_len
== namelen
&&
186 btrfs_inode_extref_parent(node
, extref
) == parent_ino
&&
187 (memcmp_extent_buffer(node
, name
, name_ptr
, namelen
) == 0))
190 *extref_ret
= extref
;
194 cur_offset
+= ref_name_len
+ sizeof(*extref
);
200 struct btrfs_inode_extref
*btrfs_lookup_inode_extref(struct btrfs_trans_handle
201 *trans
, struct btrfs_path
*path
, struct btrfs_root
*root
,
202 u64 ino
, u64 parent_ino
, u64 index
, const char *name
,
203 int namelen
, int ins_len
)
205 struct btrfs_key key
;
206 struct btrfs_inode_extref
*extref
;
210 key
.type
= BTRFS_INODE_EXTREF_KEY
;
211 key
.offset
= btrfs_extref_hash(parent_ino
, name
, namelen
);
213 ret
= btrfs_search_slot(trans
, root
, &key
, path
, ins_len
,
219 if (!btrfs_find_name_in_ext_backref(path
, parent_ino
, name
,
226 int btrfs_del_inode_extref(struct btrfs_trans_handle
*trans
,
227 struct btrfs_root
*root
,
228 const char *name
, int name_len
,
229 u64 inode_objectid
, u64 ref_objectid
,
232 struct btrfs_path
*path
;
233 struct btrfs_key key
;
234 struct btrfs_inode_extref
*extref
;
235 struct extent_buffer
*leaf
;
237 int del_len
= name_len
+ sizeof(*extref
);
239 unsigned long item_start
;
242 key
.objectid
= inode_objectid
;
243 key
.type
= BTRFS_INODE_EXTREF_KEY
;
244 key
.offset
= btrfs_extref_hash(ref_objectid
, name
, name_len
);
246 path
= btrfs_alloc_path();
250 ret
= btrfs_search_slot(trans
, root
, &key
, path
, -1, 1);
257 * Sanity check - did we find the right item for this name? This
258 * should always succeed so error here will make the FS readonly.
260 if (!btrfs_find_name_in_ext_backref(path
, ref_objectid
,
261 name
, name_len
, &extref
)) {
266 leaf
= path
->nodes
[0];
267 item_size
= btrfs_item_size_nr(leaf
, path
->slots
[0]);
269 *index
= btrfs_inode_extref_index(leaf
, extref
);
271 if (del_len
== item_size
) {
273 * Common case only one ref in the item, remove the whole item.
275 ret
= btrfs_del_item(trans
, root
, path
);
279 ptr
= (unsigned long)extref
;
280 item_start
= btrfs_item_ptr_offset(leaf
, path
->slots
[0]);
282 memmove_extent_buffer(leaf
, ptr
, ptr
+ del_len
,
283 item_size
- (ptr
+ del_len
- item_start
));
285 btrfs_truncate_item(trans
, root
, path
, item_size
- del_len
, 1);
288 btrfs_free_path(path
);
294 * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
296 * The caller must have checked against BTRFS_LINK_MAX already.
298 int btrfs_insert_inode_extref(struct btrfs_trans_handle
*trans
,
299 struct btrfs_root
*root
,
300 const char *name
, int name_len
,
301 u64 inode_objectid
, u64 ref_objectid
, u64 index
)
303 struct btrfs_inode_extref
*extref
;
305 int ins_len
= name_len
+ sizeof(*extref
);
307 struct btrfs_path
*path
;
308 struct btrfs_key key
;
309 struct extent_buffer
*leaf
;
310 struct btrfs_item
*item
;
312 key
.objectid
= inode_objectid
;
313 key
.type
= BTRFS_INODE_EXTREF_KEY
;
314 key
.offset
= btrfs_extref_hash(ref_objectid
, name
, name_len
);
316 path
= btrfs_alloc_path();
320 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
322 if (ret
== -EEXIST
) {
323 if (btrfs_find_name_in_ext_backref(path
, ref_objectid
,
324 name
, name_len
, NULL
))
327 btrfs_extend_item(trans
, root
, path
, ins_len
);
334 leaf
= path
->nodes
[0];
335 item
= btrfs_item_nr(path
->slots
[0]);
336 ptr
= (unsigned long)btrfs_item_ptr(leaf
, path
->slots
[0], char);
337 ptr
+= btrfs_item_size(leaf
, item
) - ins_len
;
338 extref
= (struct btrfs_inode_extref
*)ptr
;
340 btrfs_set_inode_extref_name_len(path
->nodes
[0], extref
, name_len
);
341 btrfs_set_inode_extref_index(path
->nodes
[0], extref
, index
);
342 btrfs_set_inode_extref_parent(path
->nodes
[0], extref
, ref_objectid
);
344 ptr
= (unsigned long)&extref
->name
;
345 write_extent_buffer(path
->nodes
[0], name
, ptr
, name_len
);
346 btrfs_mark_buffer_dirty(path
->nodes
[0]);
349 btrfs_free_path(path
);