btrfs-progs: check: Avoid reading beyond item boundary for dir_item and dir_index
[platform/upstream/btrfs-progs.git] / root-tree.c
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 "transaction.h"
21 #include "disk-io.h"
22 #include "print-tree.h"
23
24 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
25                         struct btrfs_root_item *item, struct btrfs_key *key)
26 {
27         struct btrfs_path *path;
28         struct btrfs_key search_key;
29         struct btrfs_key found_key;
30         struct extent_buffer *l;
31         int ret;
32         int slot;
33
34         path = btrfs_alloc_path();
35         if (!path)
36                 return -ENOMEM;
37
38         search_key.objectid = objectid;
39         search_key.type = BTRFS_ROOT_ITEM_KEY;
40         search_key.offset = (u64)-1;
41
42         ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
43         if (ret < 0)
44                 goto out;
45         if (path->slots[0] == 0) {
46                 ret = -ENOENT;
47                 goto out;
48         }
49
50         BUG_ON(ret == 0);
51         l = path->nodes[0];
52         slot = path->slots[0] - 1;
53         btrfs_item_key_to_cpu(l, &found_key, slot);
54         if (found_key.type != BTRFS_ROOT_ITEM_KEY ||
55             found_key.objectid != objectid) {
56                 ret = -ENOENT;
57                 goto out;
58         }
59         read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
60                            sizeof(*item));
61         memcpy(key, &found_key, sizeof(found_key));
62         ret = 0;
63 out:
64         btrfs_free_path(path);
65         return ret;
66 }
67
68 int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
69                       *root, struct btrfs_key *key, struct btrfs_root_item
70                       *item)
71 {
72         struct btrfs_path *path;
73         struct extent_buffer *l;
74         int ret;
75         int slot;
76         unsigned long ptr;
77         u32 old_len;
78
79         path = btrfs_alloc_path();
80         if (!path)
81                 return -ENOMEM;
82
83         ret = btrfs_search_slot(trans, root, key, path, 0, 1);
84         if (ret < 0)
85                 goto out;
86         BUG_ON(ret != 0);
87         l = path->nodes[0];
88         slot = path->slots[0];
89         ptr = btrfs_item_ptr_offset(l, slot);
90         old_len = btrfs_item_size_nr(l, slot);
91
92         /*
93          * If this is the first time we update the root item which originated
94          * from an older kernel, we need to enlarge the item size to make room
95          * for the added fields.
96          */
97         if (old_len < sizeof(*item)) {
98                 btrfs_release_path(path);
99                 ret = btrfs_search_slot(trans, root, key, path,
100                                 -1, 1);
101                 if (ret < 0) {
102                         goto out;
103                 }
104
105                 ret = btrfs_del_item(trans, root, path);
106                 if (ret < 0) {
107                         goto out;
108                 }
109                 btrfs_release_path(path);
110                 ret = btrfs_insert_empty_item(trans, root, path,
111                                 key, sizeof(*item));
112                 if (ret < 0) {
113                         goto out;
114                 }
115                 l = path->nodes[0];
116                 slot = path->slots[0];
117                 ptr = btrfs_item_ptr_offset(l, slot);
118         }
119
120         /*
121          * Update generation_v2 so at the next mount we know the new root
122          * fields are valid.
123          */
124         btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
125
126         write_extent_buffer(l, item, ptr, sizeof(*item));
127         btrfs_mark_buffer_dirty(path->nodes[0]);
128 out:
129         btrfs_free_path(path);
130         return ret;
131 }
132
133 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
134                       *root, struct btrfs_key *key, struct btrfs_root_item
135                       *item)
136 {
137         int ret;
138
139         /*
140          * Make sure generation v1 and v2 match. See update_root for details.
141          */
142         btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
143         ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
144         return ret;
145 }
146
147 /* drop the root item for 'key' from 'root' */
148 int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
149                    struct btrfs_key *key)
150 {
151         struct btrfs_path *path;
152         int ret;
153
154         path = btrfs_alloc_path();
155         if (!path)
156                 return -ENOMEM;
157         ret = btrfs_search_slot(trans, root, key, path, -1, 1);
158         if (ret < 0)
159                 goto out;
160
161         if (ret != 0) {
162                 ret = -ENOENT;
163                 goto out;
164         }
165
166         ret = btrfs_del_item(trans, root, path);
167 out:
168         btrfs_free_path(path);
169         return ret;
170 }
171
172 /*
173  * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
174  * or BTRFS_ROOT_BACKREF_KEY.
175  *
176  * The dirid, sequence, name and name_len refer to the directory entry
177  * that is referencing the root.
178  *
179  * For a forward ref, the root_id is the id of the tree referencing
180  * the root and ref_id is the id of the subvol  or snapshot.
181  *
182  * For a back ref the root_id is the id of the subvol or snapshot and
183  * ref_id is the id of the tree referencing it.
184  */
185 int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
186                        struct btrfs_root *tree_root,
187                        u64 root_id, u8 type, u64 ref_id,
188                        u64 dirid, u64 sequence,
189                        const char *name, int name_len)
190 {
191         struct btrfs_key key;
192         int ret;
193         struct btrfs_path *path;
194         struct btrfs_root_ref *ref;
195         struct extent_buffer *leaf;
196         unsigned long ptr;
197
198
199         path = btrfs_alloc_path();
200         if (!path)
201                 return -ENOMEM;
202
203         key.objectid = root_id;
204         key.type = type;
205         key.offset = ref_id;
206
207         ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
208                                       sizeof(*ref) + name_len);
209         BUG_ON(ret);
210
211         leaf = path->nodes[0];
212         ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
213         btrfs_set_root_ref_dirid(leaf, ref, dirid);
214         btrfs_set_root_ref_sequence(leaf, ref, sequence);
215         btrfs_set_root_ref_name_len(leaf, ref, name_len);
216         ptr = (unsigned long)(ref + 1);
217         write_extent_buffer(leaf, name, ptr, name_len);
218         btrfs_mark_buffer_dirty(leaf);
219
220         btrfs_free_path(path);
221         return ret;
222 }