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