Btrfs: symlinks and hard links
[linux-2.6] / fs / btrfs / file-item.c
1 #include <linux/module.h>
2 #include "ctree.h"
3 #include "disk-io.h"
4 #include "transaction.h"
5
6 #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
7                                sizeof(struct btrfs_item) * 2) / \
8                                BTRFS_CRC32_SIZE) - 1))
9 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
10                                struct btrfs_root *root,
11                                u64 objectid, u64 pos,
12                                u64 offset, u64 num_blocks)
13 {
14         int ret = 0;
15         struct btrfs_file_extent_item *item;
16         struct btrfs_key file_key;
17         struct btrfs_path *path;
18
19         path = btrfs_alloc_path();
20         BUG_ON(!path);
21         btrfs_init_path(path);
22         file_key.objectid = objectid;
23         file_key.offset = pos;
24         file_key.flags = 0;
25         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
26
27         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
28                                       sizeof(*item));
29         BUG_ON(ret);
30         item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
31                               struct btrfs_file_extent_item);
32         btrfs_set_file_extent_disk_blocknr(item, offset);
33         btrfs_set_file_extent_disk_num_blocks(item, num_blocks);
34         btrfs_set_file_extent_offset(item, 0);
35         btrfs_set_file_extent_num_blocks(item, num_blocks);
36         btrfs_set_file_extent_generation(item, trans->transid);
37         btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG);
38         btrfs_mark_buffer_dirty(path->nodes[0]);
39
40         btrfs_release_path(root, path);
41         btrfs_free_path(path);
42         return 0;
43 }
44
45 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
46                                           struct btrfs_root *root,
47                                           struct btrfs_path *path,
48                                           u64 objectid, u64 offset,
49                                           int cow)
50 {
51         int ret;
52         struct btrfs_key file_key;
53         struct btrfs_key found_key;
54         struct btrfs_csum_item *item;
55         struct btrfs_leaf *leaf;
56         u64 csum_offset = 0;
57         int csums_in_item;
58
59         file_key.objectid = objectid;
60         file_key.offset = offset;
61         file_key.flags = 0;
62         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
63         ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
64         if (ret < 0)
65                 goto fail;
66         leaf = btrfs_buffer_leaf(path->nodes[0]);
67         if (ret > 0) {
68                 ret = 1;
69                 if (path->slots[0] == 0)
70                         goto fail;
71                 path->slots[0]--;
72                 btrfs_disk_key_to_cpu(&found_key,
73                                       &leaf->items[path->slots[0]].key);
74                 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
75                     found_key.objectid != objectid) {
76                         goto fail;
77                 }
78                 csum_offset = (offset - found_key.offset) >>
79                                 root->fs_info->sb->s_blocksize_bits;
80                 csums_in_item = btrfs_item_size(leaf->items + path->slots[0]);
81                 csums_in_item /= BTRFS_CRC32_SIZE;
82
83                 if (csum_offset >= csums_in_item) {
84                         ret = -EFBIG;
85                         goto fail;
86                 }
87         }
88         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
89         item = (struct btrfs_csum_item *)((unsigned char *)item +
90                                           csum_offset * BTRFS_CRC32_SIZE);
91         return item;
92 fail:
93         if (ret > 0)
94                 ret = -ENOENT;
95         return ERR_PTR(ret);
96 }
97
98
99 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
100                              struct btrfs_root *root,
101                              struct btrfs_path *path, u64 objectid,
102                              u64 offset, int mod)
103 {
104         int ret;
105         struct btrfs_key file_key;
106         int ins_len = mod < 0 ? -1 : 0;
107         int cow = mod != 0;
108
109         file_key.objectid = objectid;
110         file_key.offset = offset;
111         file_key.flags = 0;
112         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
113         ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
114         return ret;
115 }
116
117 int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
118                           struct btrfs_root *root,
119                           u64 objectid, u64 offset,
120                           char *data, size_t len)
121 {
122         int ret;
123         struct btrfs_key file_key;
124         struct btrfs_key found_key;
125         struct btrfs_path *path;
126         struct btrfs_csum_item *item;
127         struct btrfs_leaf *leaf;
128         u64 csum_offset;
129
130         path = btrfs_alloc_path();
131         BUG_ON(!path);
132
133         file_key.objectid = objectid;
134         file_key.offset = offset;
135         file_key.flags = 0;
136         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
137
138         item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1);
139         if (!IS_ERR(item))
140                 goto found;
141         ret = PTR_ERR(item);
142         if (ret == -EFBIG) {
143                 u32 item_size;
144                 /* we found one, but it isn't big enough yet */
145                 leaf = btrfs_buffer_leaf(path->nodes[0]);
146                 item_size = btrfs_item_size(leaf->items + path->slots[0]);
147                 if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) {
148                         /* already at max size, make a new one */
149                         goto insert;
150                 }
151         } else {
152                 /* we didn't find a csum item, insert one */
153                 goto insert;
154         }
155
156         /*
157          * at this point, we know the tree has an item, but it isn't big
158          * enough yet to put our csum in.  Grow it
159          */
160         btrfs_release_path(root, path);
161         ret = btrfs_search_slot(trans, root, &file_key, path,
162                                 BTRFS_CRC32_SIZE, 1);
163         if (ret < 0)
164                 goto fail;
165         if (ret == 0) {
166                 BUG();
167         }
168         if (path->slots[0] == 0) {
169                 goto insert;
170         }
171         path->slots[0]--;
172         leaf = btrfs_buffer_leaf(path->nodes[0]);
173         btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
174         csum_offset = (offset - found_key.offset) >>
175                         root->fs_info->sb->s_blocksize_bits;
176         if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
177             found_key.objectid != objectid ||
178             csum_offset >= MAX_CSUM_ITEMS(root)) {
179                 WARN_ON(1);
180                 goto insert;
181         }
182         if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) /
183             BTRFS_CRC32_SIZE) {
184                 u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
185                 diff = diff - btrfs_item_size(leaf->items + path->slots[0]);
186                 WARN_ON(diff != BTRFS_CRC32_SIZE);
187                 ret = btrfs_extend_item(trans, root, path, diff);
188                 BUG_ON(ret);
189                 goto csum;
190         }
191
192 insert:
193         btrfs_release_path(root, path);
194         csum_offset = 0;
195         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
196                                       BTRFS_CRC32_SIZE);
197         if (ret != 0) {
198                 printk("at insert for %Lu %u %Lu ret is %d\n", file_key.objectid, file_key.flags, file_key.offset, ret);
199                 WARN_ON(1);
200                 goto fail;
201         }
202 csum:
203         item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
204                               struct btrfs_csum_item);
205         ret = 0;
206         item = (struct btrfs_csum_item *)((unsigned char *)item +
207                                           csum_offset * BTRFS_CRC32_SIZE);
208 found:
209         btrfs_check_bounds(&item->csum, BTRFS_CRC32_SIZE,
210                            path->nodes[0]->b_data,
211                            root->fs_info->sb->s_blocksize);
212         ret = btrfs_csum_data(root, data, len, &item->csum);
213         btrfs_mark_buffer_dirty(path->nodes[0]);
214 fail:
215         btrfs_release_path(root, path);
216         btrfs_free_path(path);
217         return ret;
218 }
219
220 int btrfs_csum_verify_file_block(struct btrfs_root *root,
221                                  u64 objectid, u64 offset,
222                                  char *data, size_t len)
223 {
224         int ret;
225         struct btrfs_key file_key;
226         struct btrfs_path *path;
227         struct btrfs_csum_item *item;
228         char result[BTRFS_CRC32_SIZE];
229
230         path = btrfs_alloc_path();
231         BUG_ON(!path);
232         btrfs_init_path(path);
233         file_key.objectid = objectid;
234         file_key.offset = offset;
235         file_key.flags = 0;
236         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
237         mutex_lock(&root->fs_info->fs_mutex);
238
239         item = btrfs_lookup_csum(NULL, root, path, objectid, offset, 0);
240         if (IS_ERR(item)) {
241                 ret = PTR_ERR(item);
242                 /* a csum that isn't present is a preallocated region. */
243                 if (ret == -ENOENT || ret == -EFBIG)
244                         ret = 1;
245                 goto fail;
246         }
247
248         ret = btrfs_csum_data(root, data, len, result);
249         WARN_ON(ret);
250         if (memcmp(result, &item->csum, BTRFS_CRC32_SIZE))
251                 ret = 1;
252 fail:
253         btrfs_release_path(root, path);
254         btrfs_free_path(path);
255         mutex_unlock(&root->fs_info->fs_mutex);
256         return ret;
257 }
258