Btrfs: directory inode index is back
[safe/jmp/linux-2.6] / fs / btrfs / dir-item.c
1 #include <linux/module.h>
2 #include "ctree.h"
3 #include "disk-io.h"
4 #include "hash.h"
5 #include "transaction.h"
6
7 struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle *trans,
8                                             struct btrfs_root *root,
9                                             struct btrfs_path *path,
10                                             struct btrfs_key *cpu_key,
11                                             u32 data_size)
12 {
13         int ret;
14         char *ptr;
15         struct btrfs_item *item;
16         struct btrfs_leaf *leaf;
17
18         ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
19         if (ret == -EEXIST) {
20                 ret = btrfs_extend_item(trans, root, path, data_size);
21                 WARN_ON(ret > 0);
22                 if (ret)
23                         return ERR_PTR(ret);
24         }
25         WARN_ON(ret > 0);
26         leaf = btrfs_buffer_leaf(path->nodes[0]);
27         item = leaf->items + path->slots[0];
28         ptr = btrfs_item_ptr(leaf, path->slots[0], char);
29         BUG_ON(data_size > btrfs_item_size(item));
30         ptr += btrfs_item_size(item) - data_size;
31         return (struct btrfs_dir_item *)ptr;
32 }
33
34 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
35                           *root, const char *name, int name_len, u64 dir,
36                           struct btrfs_key *location, u8 type)
37 {
38         int ret = 0;
39         struct btrfs_path *path;
40         struct btrfs_dir_item *dir_item;
41         char *name_ptr;
42         struct btrfs_key key;
43         u32 data_size;
44
45         key.objectid = dir;
46         key.flags = 0;
47         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
48         ret = btrfs_name_hash(name, name_len, &key.offset);
49         BUG_ON(ret);
50         path = btrfs_alloc_path();
51         btrfs_init_path(path);
52         data_size = sizeof(*dir_item) + name_len;
53         dir_item = insert_with_overflow(trans, root, path, &key, data_size);
54         if (IS_ERR(dir_item)) {
55                 ret = PTR_ERR(dir_item);
56                 goto out;
57         }
58
59         btrfs_cpu_key_to_disk(&dir_item->location, location);
60         btrfs_set_dir_type(dir_item, type);
61         btrfs_set_dir_flags(dir_item, 0);
62         btrfs_set_dir_name_len(dir_item, name_len);
63         name_ptr = (char *)(dir_item + 1);
64
65         btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
66         btrfs_mark_buffer_dirty(path->nodes[0]);
67
68         /* FIXME, use some real flag for selecting the extra index */
69         if (root == root->fs_info->tree_root) {
70                 ret = 0;
71                 goto out;
72         }
73
74         btrfs_release_path(root, path);
75
76         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
77         key.offset = location->objectid;
78         dir_item = insert_with_overflow(trans, root, path, &key, data_size);
79         if (IS_ERR(dir_item)) {
80                 ret = PTR_ERR(dir_item);
81                 goto out;
82         }
83         btrfs_cpu_key_to_disk(&dir_item->location, location);
84         btrfs_set_dir_type(dir_item, type);
85         btrfs_set_dir_flags(dir_item, 0);
86         btrfs_set_dir_name_len(dir_item, name_len);
87         name_ptr = (char *)(dir_item + 1);
88         btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
89         btrfs_mark_buffer_dirty(path->nodes[0]);
90 out:
91         btrfs_free_path(path);
92         return ret;
93 }
94
95 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
96                                              struct btrfs_root *root,
97                                              struct btrfs_path *path, u64 dir,
98                                              const char *name, int name_len,
99                                              int mod)
100 {
101         int ret;
102         struct btrfs_key key;
103         int ins_len = mod < 0 ? -1 : 0;
104         int cow = mod != 0;
105         struct btrfs_disk_key *found_key;
106         struct btrfs_leaf *leaf;
107
108         key.objectid = dir;
109         key.flags = 0;
110         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
111         ret = btrfs_name_hash(name, name_len, &key.offset);
112         BUG_ON(ret);
113         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
114         if (ret < 0)
115                 return ERR_PTR(ret);
116         if (ret > 0) {
117                 if (path->slots[0] == 0)
118                         return NULL;
119                 path->slots[0]--;
120         }
121         leaf = btrfs_buffer_leaf(path->nodes[0]);
122         found_key = &leaf->items[path->slots[0]].key;
123
124         if (btrfs_disk_key_objectid(found_key) != dir ||
125             btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
126             btrfs_disk_key_offset(found_key) != key.offset)
127                 return NULL;
128
129         return btrfs_match_dir_item_name(root, path, name, name_len);
130 }
131
132 struct btrfs_dir_item *
133 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
134                             struct btrfs_root *root,
135                             struct btrfs_path *path, u64 dir,
136                             u64 objectid, const char *name, int name_len,
137                             int mod)
138 {
139         int ret;
140         struct btrfs_key key;
141         int ins_len = mod < 0 ? -1 : 0;
142         int cow = mod != 0;
143
144         key.objectid = dir;
145         key.flags = 0;
146         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
147         key.offset = objectid;
148
149         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
150         if (ret < 0)
151                 return ERR_PTR(ret);
152         if (ret > 0)
153                 return ERR_PTR(-ENOENT);
154         return btrfs_match_dir_item_name(root, path, name, name_len);
155 }
156
157 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
158                               struct btrfs_path *path,
159                               const char *name, int name_len)
160 {
161         struct btrfs_dir_item *dir_item;
162         char *name_ptr;
163         u32 total_len;
164         u32 cur = 0;
165         u32 this_len;
166         struct btrfs_leaf *leaf;
167
168         leaf = btrfs_buffer_leaf(path->nodes[0]);
169         dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
170         total_len = btrfs_item_size(leaf->items + path->slots[0]);
171         while(cur < total_len) {
172                 this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item);
173                 name_ptr = (char *)(dir_item + 1);
174
175                 if (btrfs_dir_name_len(dir_item) == name_len &&
176                     memcmp(name_ptr, name, name_len) == 0)
177                         return dir_item;
178
179                 cur += this_len;
180                 dir_item = (struct btrfs_dir_item *)((char *)dir_item +
181                                                      this_len);
182         }
183         return NULL;
184 }
185
186 int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
187                               struct btrfs_root *root,
188                               struct btrfs_path *path,
189                               struct btrfs_dir_item *di)
190 {
191
192         struct btrfs_leaf *leaf;
193         u32 sub_item_len;
194         u32 item_len;
195         int ret;
196
197         leaf = btrfs_buffer_leaf(path->nodes[0]);
198         sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
199         item_len = btrfs_item_size(leaf->items + path->slots[0]);
200         if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
201                 ret = btrfs_del_item(trans, root, path);
202                 BUG_ON(ret);
203         } else {
204                 char *ptr = (char *)di;
205                 char *start = btrfs_item_ptr(leaf, path->slots[0], char);
206                 btrfs_memmove(root, leaf, ptr, ptr + sub_item_len,
207                         item_len - (ptr + sub_item_len - start));
208                 ret = btrfs_truncate_item(trans, root, path,
209                                           item_len - sub_item_len);
210                 BUG_ON(ret);
211         }
212         return 0;
213 }
214