8b85f7a07fad33dbd869628a3932420e2371f079
[platform/upstream/btrfs-progs.git] / file-item.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 <stdio.h>
20 #include <stdlib.h>
21 #include "kerncompat.h"
22 #include "radix-tree.h"
23 #include "ctree.h"
24 #include "disk-io.h"
25 #include "transaction.h"
26 #include "print-tree.h"
27 #include "crc32c.h"
28
29 #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
30                                sizeof(struct btrfs_item) * 2) / \
31                                BTRFS_CRC32_SIZE) - 1))
32 int btrfs_create_file(struct btrfs_trans_handle *trans,
33                       struct btrfs_root *root, u64 dirid, u64 *objectid)
34 {
35         return 0;
36 }
37
38 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
39                              struct btrfs_root *root,
40                              u64 objectid, u64 pos, u64 offset,
41                              u64 disk_num_bytes, u64 num_bytes)
42 {
43         int ret = 0;
44         struct btrfs_file_extent_item *item;
45         struct btrfs_key file_key;
46         struct btrfs_path *path;
47         struct extent_buffer *leaf;
48
49         path = btrfs_alloc_path();
50         BUG_ON(!path);
51         file_key.objectid = objectid;
52         file_key.offset = pos;
53         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
54
55         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
56                                       sizeof(*item));
57         if (ret < 0)
58                 goto out;
59         BUG_ON(ret);
60         leaf = path->nodes[0];
61         item = btrfs_item_ptr(leaf, path->slots[0],
62                               struct btrfs_file_extent_item);
63         btrfs_set_file_extent_disk_bytenr(leaf, item, offset);
64         btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes);
65         btrfs_set_file_extent_offset(leaf, item, 0);
66         btrfs_set_file_extent_num_bytes(leaf, item, num_bytes);
67         btrfs_set_file_extent_generation(leaf, item, trans->transid);
68         btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG);
69         btrfs_mark_buffer_dirty(leaf);
70 out:
71         btrfs_free_path(path);
72         return ret;
73 }
74
75 int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
76                                struct btrfs_root *root, u64 objectid,
77                                u64 offset, char *buffer, size_t size)
78 {
79         struct btrfs_key key;
80         struct btrfs_path *path;
81         struct extent_buffer *leaf;
82         unsigned long ptr;
83         struct btrfs_file_extent_item *ei;
84         u32 datasize;
85         int err = 0;
86         int ret;
87
88         path = btrfs_alloc_path();
89         if (!path)
90                 return -ENOMEM;
91
92         key.objectid = objectid;
93         key.offset = offset;
94         btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
95
96         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
97         if (ret < 0) {
98                 err = ret;
99                 goto fail;
100         }
101         if (ret == 1) {
102                 struct btrfs_key found_key;
103
104                 if (path->slots[0] == 0)
105                         goto insert;
106
107                 path->slots[0]--;
108                 leaf = path->nodes[0];
109                 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
110
111                 if (found_key.objectid != objectid)
112                         goto insert;
113
114                 if (found_key.type != BTRFS_EXTENT_DATA_KEY)
115                         goto insert;
116                 ei = btrfs_item_ptr(leaf, path->slots[0],
117                                     struct btrfs_file_extent_item);
118
119                 if (btrfs_file_extent_type(leaf, ei) !=
120                     BTRFS_FILE_EXTENT_INLINE) {
121                         goto insert;
122                 }
123                 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
124                 ret = 0;
125         }
126         if (ret == 0) {
127                 u32 found_size;
128                 u64 found_end;
129
130                 leaf = path->nodes[0];
131                 ei = btrfs_item_ptr(leaf, path->slots[0],
132                                     struct btrfs_file_extent_item);
133
134                 if (btrfs_file_extent_type(leaf, ei) !=
135                     BTRFS_FILE_EXTENT_INLINE) {
136                         err = ret;
137                         btrfs_print_leaf(root, leaf);
138                         printk("found wasn't inline offset %llu inode %llu\n",
139                                offset, objectid);
140                         goto fail;
141                 }
142                 found_size = btrfs_file_extent_inline_len(leaf,
143                                           btrfs_item_nr(leaf, path->slots[0]));
144                 found_end = key.offset + found_size;
145
146                 if (found_end < offset + size) {
147                         btrfs_release_path(root, path);
148                         ret = btrfs_search_slot(trans, root, &key, path,
149                                                 offset + size - found_end, 1);
150                         BUG_ON(ret != 0);
151
152                         ret = btrfs_extend_item(trans, root, path,
153                                                 offset + size - found_end);
154                         if (ret) {
155                                 err = ret;
156                                 goto fail;
157                         }
158                         leaf = path->nodes[0];
159                         ei = btrfs_item_ptr(leaf, path->slots[0],
160                                             struct btrfs_file_extent_item);
161                 }
162                 if (found_end < offset) {
163                         ptr = btrfs_file_extent_inline_start(ei) + found_size;
164                         memset_extent_buffer(leaf, 0, ptr, offset - found_end);
165                 }
166         } else {
167 insert:
168                 btrfs_release_path(root, path);
169                 datasize = offset + size - key.offset;
170                 datasize = btrfs_file_extent_calc_inline_size(datasize);
171                 ret = btrfs_insert_empty_item(trans, root, path, &key,
172                                               datasize);
173                 if (ret) {
174                         err = ret;
175                         printk("got bad ret %d\n", ret);
176                         goto fail;
177                 }
178                 leaf = path->nodes[0];
179                 ei = btrfs_item_ptr(leaf, path->slots[0],
180                                     struct btrfs_file_extent_item);
181                 btrfs_set_file_extent_generation(leaf, ei, trans->transid);
182                 btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
183         }
184         ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset;
185         write_extent_buffer(leaf, buffer, ptr, size);
186         btrfs_mark_buffer_dirty(leaf);
187 fail:
188         btrfs_free_path(path);
189         return err;
190 }
191
192 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
193                                           struct btrfs_root *root,
194                                           struct btrfs_path *path,
195                                           u64 objectid, u64 offset, int cow)
196 {
197         int ret;
198         struct btrfs_key file_key;
199         struct btrfs_key found_key;
200         struct btrfs_csum_item *item;
201         struct extent_buffer *leaf;
202         u64 csum_offset = 0;
203         int csums_in_item;
204
205         file_key.objectid = objectid;
206         file_key.offset = offset;
207         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
208         ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
209         if (ret < 0)
210                 goto fail;
211         leaf = path->nodes[0];
212         if (ret > 0) {
213                 ret = 1;
214                 if (path->slots[0] == 0)
215                         goto fail;
216                 path->slots[0]--;
217                 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
218                 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
219                     found_key.objectid != objectid) {
220                         goto fail;
221                 }
222                 csum_offset = (offset - found_key.offset) >> root->sectorsize;
223                 csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
224                 csums_in_item /= BTRFS_CRC32_SIZE;
225
226                 if (csum_offset >= csums_in_item) {
227                         ret = -EFBIG;
228                         goto fail;
229                 }
230         }
231         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
232         item = (struct btrfs_csum_item *)((unsigned char *)item +
233                                           csum_offset * BTRFS_CRC32_SIZE);
234         return item;
235 fail:
236         if (ret > 0)
237                 ret = -ENOENT;
238         return ERR_PTR(ret);
239 }
240
241
242 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
243                              struct btrfs_root *root,
244                              struct btrfs_path *path, u64 objectid,
245                              u64 offset, int mod)
246 {
247         int ret;
248         struct btrfs_key file_key;
249         int ins_len = mod < 0 ? -1 : 0;
250         int cow = mod != 0;
251
252         file_key.objectid = objectid;
253         file_key.offset = offset;
254         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
255         ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
256         return ret;
257 }
258
259 int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
260                           struct btrfs_root *root,
261                           struct btrfs_inode_item *inode,
262                           u64 objectid, u64 offset,
263                           char *data, size_t len)
264 {
265         int ret;
266         struct btrfs_key file_key;
267         struct btrfs_key found_key;
268         u64 next_offset = (u64)-1;
269         int found_next = 0;
270         struct btrfs_path *path;
271         struct btrfs_csum_item *item;
272         struct extent_buffer *leaf = NULL;
273         u64 csum_offset;
274         u32 csum_result = ~(u32)0;
275         u32 nritems;
276         u32 ins_size;
277
278         path = btrfs_alloc_path();
279         BUG_ON(!path);
280
281         file_key.objectid = objectid;
282         file_key.offset = offset;
283         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
284
285         item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1);
286         if (!IS_ERR(item)) {
287                 leaf = path->nodes[0];
288                 goto found;
289         }
290         ret = PTR_ERR(item);
291         if (ret == -EFBIG) {
292                 u32 item_size;
293                 /* we found one, but it isn't big enough yet */
294                 leaf = path->nodes[0];
295                 item_size = btrfs_item_size_nr(leaf, path->slots[0]);
296                 if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) {
297                         /* already at max size, make a new one */
298                         goto insert;
299                 }
300         } else {
301                 int slot = path->slots[0] + 1;
302                 /* we didn't find a csum item, insert one */
303                 nritems = btrfs_header_nritems(path->nodes[0]);
304                 if (path->slots[0] >= nritems - 1) {
305                         ret = btrfs_next_leaf(root, path);
306                         if (ret == 1)
307                                 found_next = 1;
308                         if (ret != 0)
309                                 goto insert;
310                         slot = 0;
311                 }
312                 btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
313                 if (found_key.objectid != objectid ||
314                     found_key.type != BTRFS_CSUM_ITEM_KEY) {
315                         found_next = 1;
316                         goto insert;
317                 }
318                 next_offset = found_key.offset;
319                 found_next = 1;
320                 goto insert;
321         }
322
323         /*
324          * at this point, we know the tree has an item, but it isn't big
325          * enough yet to put our csum in.  Grow it
326          */
327         btrfs_release_path(root, path);
328         ret = btrfs_search_slot(trans, root, &file_key, path,
329                                 BTRFS_CRC32_SIZE, 1);
330         if (ret < 0)
331                 goto fail;
332         if (ret == 0) {
333                 BUG();
334         }
335         if (path->slots[0] == 0) {
336                 goto insert;
337         }
338         path->slots[0]--;
339         leaf = path->nodes[0];
340         btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
341         csum_offset = (offset - found_key.offset) / root->sectorsize;
342         if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
343             found_key.objectid != objectid ||
344             csum_offset >= MAX_CSUM_ITEMS(root)) {
345                 goto insert;
346         }
347         if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
348             BTRFS_CRC32_SIZE) {
349                 u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
350                 diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
351                 if (diff != BTRFS_CRC32_SIZE)
352                         goto insert;
353                 ret = btrfs_extend_item(trans, root, path, diff);
354                 BUG_ON(ret);
355                 goto csum;
356         }
357
358 insert:
359         btrfs_release_path(root, path);
360         csum_offset = 0;
361         if (found_next) {
362                 u64 tmp = min(btrfs_stack_inode_size(inode), next_offset);
363                 tmp -= offset & ~((u64)root->sectorsize -1);
364                 tmp /= root->sectorsize;
365                 tmp = max((u64)1, tmp);
366                 tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root));
367                 ins_size = BTRFS_CRC32_SIZE * tmp;
368         } else {
369                 ins_size = BTRFS_CRC32_SIZE;
370         }
371         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
372                                       ins_size);
373         if (ret < 0)
374                 goto fail;
375         if (ret != 0) {
376                 WARN_ON(1);
377                 goto fail;
378         }
379 csum:
380         leaf = path->nodes[0];
381         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
382         ret = 0;
383         item = (struct btrfs_csum_item *)((unsigned char *)item +
384                                           csum_offset * BTRFS_CRC32_SIZE);
385 found:
386         csum_result = btrfs_csum_data(root, data, csum_result, len);
387         btrfs_csum_final(csum_result, (char *)&csum_result);
388         if (csum_result == 0) {
389                 printk("csum result is 0 for inode %Lu offset %Lu\n",
390                        objectid, offset);
391         }
392
393         write_extent_buffer(leaf, &csum_result, (unsigned long)item,
394                             BTRFS_CRC32_SIZE);
395         btrfs_mark_buffer_dirty(path->nodes[0]);
396 fail:
397         btrfs_release_path(root, path);
398         btrfs_free_path(path);
399         return ret;
400 }
401
402 int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
403                         struct btrfs_root *root, struct btrfs_path *path,
404                         u64 isize)
405 {
406         struct btrfs_key key;
407         struct extent_buffer *leaf = path->nodes[0];
408         int slot = path->slots[0];
409         int ret;
410         u32 new_item_size;
411         u64 new_item_span;
412         u64 blocks;
413
414         btrfs_item_key_to_cpu(leaf, &key, slot);
415         if (isize <= key.offset)
416                 return 0;
417         new_item_span = isize - key.offset;
418         blocks = (new_item_span + root->sectorsize - 1) / root->sectorsize;
419         new_item_size = blocks * BTRFS_CRC32_SIZE;
420         if (new_item_size >= btrfs_item_size_nr(leaf, slot))
421                 return 0;
422         ret = btrfs_truncate_item(trans, root, path, new_item_size, 1);
423         BUG_ON(ret);
424         return ret;
425 }