Fix isize/nbytes update bugs in btrfs-convert
[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,size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
30                                sizeof(struct btrfs_item) * 2) / \
31                                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_ram_bytes(leaf, item, num_bytes);
68         btrfs_set_file_extent_generation(leaf, item, trans->transid);
69         btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG);
70         btrfs_set_file_extent_compression(leaf, item, 0);
71         btrfs_set_file_extent_encryption(leaf, item, 0);
72         btrfs_set_file_extent_other_encoding(leaf, item, 0);
73         btrfs_mark_buffer_dirty(leaf);
74 out:
75         btrfs_free_path(path);
76         return ret;
77 }
78
79 int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
80                                struct btrfs_root *root, u64 objectid,
81                                u64 offset, char *buffer, size_t size)
82 {
83         struct btrfs_key key;
84         struct btrfs_path *path;
85         struct extent_buffer *leaf;
86         unsigned long ptr;
87         struct btrfs_file_extent_item *ei;
88         u32 datasize;
89         int err = 0;
90         int ret;
91
92         path = btrfs_alloc_path();
93         if (!path)
94                 return -ENOMEM;
95
96         key.objectid = objectid;
97         key.offset = offset;
98         btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
99
100         datasize = btrfs_file_extent_calc_inline_size(size);
101         ret = btrfs_insert_empty_item(trans, root, path, &key, datasize);
102         if (ret) {
103                 err = ret;
104                 goto fail;
105         }
106
107         leaf = path->nodes[0];
108         ei = btrfs_item_ptr(leaf, path->slots[0],
109                             struct btrfs_file_extent_item);
110         btrfs_set_file_extent_generation(leaf, ei, trans->transid);
111         btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
112         btrfs_set_file_extent_ram_bytes(leaf, ei, size);
113         btrfs_set_file_extent_compression(leaf, ei, 0);
114         btrfs_set_file_extent_encryption(leaf, ei, 0);
115         btrfs_set_file_extent_other_encoding(leaf, ei, 0);
116
117         ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset;
118         write_extent_buffer(leaf, buffer, ptr, size);
119         btrfs_mark_buffer_dirty(leaf);
120 fail:
121         btrfs_free_path(path);
122         return err;
123 }
124
125 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
126                                           struct btrfs_root *root,
127                                           struct btrfs_path *path,
128                                           u64 bytenr, int cow)
129 {
130         int ret;
131         struct btrfs_key file_key;
132         struct btrfs_key found_key;
133         struct btrfs_csum_item *item;
134         struct extent_buffer *leaf;
135         u64 csum_offset = 0;
136         u16 csum_size =
137                 btrfs_super_csum_size(&root->fs_info->super_copy);
138         int csums_in_item;
139
140         file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
141         file_key.offset = bytenr;
142         btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
143         ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
144         if (ret < 0)
145                 goto fail;
146         leaf = path->nodes[0];
147         if (ret > 0) {
148                 ret = 1;
149                 if (path->slots[0] == 0)
150                         goto fail;
151                 path->slots[0]--;
152                 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
153                 if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY)
154                         goto fail;
155
156                 csum_offset = (bytenr - found_key.offset) / root->sectorsize;
157                 csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
158                 csums_in_item /= csum_size;
159
160                 if (csum_offset >= csums_in_item) {
161                         ret = -EFBIG;
162                         goto fail;
163                 }
164         }
165         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
166         item = (struct btrfs_csum_item *)((unsigned char *)item +
167                                           csum_offset * csum_size);
168         return item;
169 fail:
170         if (ret > 0)
171                 ret = -ENOENT;
172         return ERR_PTR(ret);
173 }
174
175 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
176                              struct btrfs_root *root,
177                              struct btrfs_path *path, u64 objectid,
178                              u64 offset, int mod)
179 {
180         int ret;
181         struct btrfs_key file_key;
182         int ins_len = mod < 0 ? -1 : 0;
183         int cow = mod != 0;
184
185         file_key.objectid = objectid;
186         file_key.offset = offset;
187         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
188         ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
189         return ret;
190 }
191
192 int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
193                           struct btrfs_root *root, u64 alloc_end,
194                           u64 bytenr, char *data, size_t len)
195 {
196         int ret;
197         struct btrfs_key file_key;
198         struct btrfs_key found_key;
199         u64 next_offset = (u64)-1;
200         int found_next = 0;
201         struct btrfs_path *path;
202         struct btrfs_csum_item *item;
203         struct extent_buffer *leaf = NULL;
204         u64 csum_offset;
205         u32 csum_result = ~(u32)0;
206         u32 nritems;
207         u32 ins_size;
208         u16 csum_size =
209                 btrfs_super_csum_size(&root->fs_info->super_copy);
210
211         path = btrfs_alloc_path();
212         BUG_ON(!path);
213
214         file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
215         file_key.offset = bytenr;
216         file_key.type = BTRFS_EXTENT_CSUM_KEY;
217
218         item = btrfs_lookup_csum(trans, root, path, bytenr, 1);
219         if (!IS_ERR(item)) {
220                 leaf = path->nodes[0];
221                 goto found;
222         }
223         ret = PTR_ERR(item);
224         if (ret == -EFBIG) {
225                 u32 item_size;
226                 /* we found one, but it isn't big enough yet */
227                 leaf = path->nodes[0];
228                 item_size = btrfs_item_size_nr(leaf, path->slots[0]);
229                 if ((item_size / csum_size) >= MAX_CSUM_ITEMS(root, csum_size)) {
230                         /* already at max size, make a new one */
231                         goto insert;
232                 }
233         } else {
234                 int slot = path->slots[0] + 1;
235                 /* we didn't find a csum item, insert one */
236                 nritems = btrfs_header_nritems(path->nodes[0]);
237                 if (path->slots[0] >= nritems - 1) {
238                         ret = btrfs_next_leaf(root, path);
239                         if (ret == 1)
240                                 found_next = 1;
241                         if (ret != 0)
242                                 goto insert;
243                         slot = 0;
244                 }
245                 btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
246                 if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
247                     found_key.type != BTRFS_EXTENT_CSUM_KEY) {
248                         found_next = 1;
249                         goto insert;
250                 }
251                 next_offset = found_key.offset;
252                 found_next = 1;
253                 goto insert;
254         }
255
256         /*
257          * at this point, we know the tree has an item, but it isn't big
258          * enough yet to put our csum in.  Grow it
259          */
260         btrfs_release_path(root, path);
261         ret = btrfs_search_slot(trans, root, &file_key, path,
262                                 csum_size, 1);
263         if (ret < 0)
264                 goto fail;
265         if (ret == 0) {
266                 BUG();
267         }
268         if (path->slots[0] == 0) {
269                 goto insert;
270         }
271         path->slots[0]--;
272         leaf = path->nodes[0];
273         btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
274         csum_offset = (file_key.offset - found_key.offset) / root->sectorsize;
275         if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
276             found_key.type != BTRFS_EXTENT_CSUM_KEY ||
277             csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
278                 goto insert;
279         }
280         if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
281             csum_size) {
282                 u32 diff = (csum_offset + 1) * csum_size;
283                 diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
284                 if (diff != csum_size)
285                         goto insert;
286                 ret = btrfs_extend_item(trans, root, path, diff);
287                 BUG_ON(ret);
288                 goto csum;
289         }
290
291 insert:
292         btrfs_release_path(root, path);
293         csum_offset = 0;
294         if (found_next) {
295                 u64 tmp = min(alloc_end, next_offset);
296                 tmp -= file_key.offset;
297                 tmp /= root->sectorsize;
298                 tmp = max((u64)1, tmp);
299                 tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
300                 ins_size = csum_size * tmp;
301         } else {
302                 ins_size = csum_size;
303         }
304         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
305                                       ins_size);
306         if (ret < 0)
307                 goto fail;
308         if (ret != 0) {
309                 WARN_ON(1);
310                 goto fail;
311         }
312 csum:
313         leaf = path->nodes[0];
314         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
315         ret = 0;
316         item = (struct btrfs_csum_item *)((unsigned char *)item +
317                                           csum_offset * csum_size);
318 found:
319         csum_result = btrfs_csum_data(root, data, csum_result, len);
320         btrfs_csum_final(csum_result, (char *)&csum_result);
321         if (csum_result == 0) {
322                 printk("csum result is 0 for block %llu\n",
323                        (unsigned long long)bytenr);
324         }
325
326         write_extent_buffer(leaf, &csum_result, (unsigned long)item,
327                             csum_size);
328         btrfs_mark_buffer_dirty(path->nodes[0]);
329 fail:
330         btrfs_release_path(root, path);
331         btrfs_free_path(path);
332         return ret;
333 }
334
335 /*
336  * helper function for csum removal, this expects the
337  * key to describe the csum pointed to by the path, and it expects
338  * the csum to overlap the range [bytenr, len]
339  *
340  * The csum should not be entirely contained in the range and the
341  * range should not be entirely contained in the csum.
342  *
343  * This calls btrfs_truncate_item with the correct args based on the
344  * overlap, and fixes up the key as required.
345  */
346 static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
347                                       struct btrfs_root *root,
348                                       struct btrfs_path *path,
349                                       struct btrfs_key *key,
350                                       u64 bytenr, u64 len)
351 {
352         struct extent_buffer *leaf;
353         u16 csum_size =
354                 btrfs_super_csum_size(&root->fs_info->super_copy);
355         u64 csum_end;
356         u64 end_byte = bytenr + len;
357         u32 blocksize = root->sectorsize;
358         int ret;
359
360         leaf = path->nodes[0];
361         csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
362         csum_end *= root->sectorsize;
363         csum_end += key->offset;
364
365         if (key->offset < bytenr && csum_end <= end_byte) {
366                 /*
367                  *         [ bytenr - len ]
368                  *         [   ]
369                  *   [csum     ]
370                  *   A simple truncate off the end of the item
371                  */
372                 u32 new_size = (bytenr - key->offset) / blocksize;
373                 new_size *= csum_size;
374                 ret = btrfs_truncate_item(trans, root, path, new_size, 1);
375                 BUG_ON(ret);
376         } else if (key->offset >= bytenr && csum_end > end_byte &&
377                    end_byte > key->offset) {
378                 /*
379                  *         [ bytenr - len ]
380                  *                 [ ]
381                  *                 [csum     ]
382                  * we need to truncate from the beginning of the csum
383                  */
384                 u32 new_size = (csum_end - end_byte) / blocksize;
385                 new_size *= csum_size;
386
387                 ret = btrfs_truncate_item(trans, root, path, new_size, 0);
388                 BUG_ON(ret);
389
390                 key->offset = end_byte;
391                 ret = btrfs_set_item_key_safe(trans, root, path, key);
392                 BUG_ON(ret);
393         } else {
394                 BUG();
395         }
396         return 0;
397 }
398
399 /*
400  * deletes the csum items from the csum tree for a given
401  * range of bytes.
402  */
403 int btrfs_del_csums(struct btrfs_trans_handle *trans,
404                     struct btrfs_root *root, u64 bytenr, u64 len)
405 {
406         struct btrfs_path *path;
407         struct btrfs_key key;
408         u64 end_byte = bytenr + len;
409         u64 csum_end;
410         struct extent_buffer *leaf;
411         int ret;
412         u16 csum_size =
413                 btrfs_super_csum_size(&root->fs_info->super_copy);
414         int blocksize = root->sectorsize;
415
416         root = root->fs_info->csum_root;
417
418         path = btrfs_alloc_path();
419
420         while (1) {
421                 key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
422                 key.offset = end_byte - 1;
423                 key.type = BTRFS_EXTENT_CSUM_KEY;
424
425                 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
426                 if (ret > 0) {
427                         if (path->slots[0] == 0)
428                                 goto out;
429                         path->slots[0]--;
430                 }
431                 leaf = path->nodes[0];
432                 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
433
434                 if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
435                     key.type != BTRFS_EXTENT_CSUM_KEY) {
436                         break;
437                 }
438
439                 if (key.offset >= end_byte)
440                         break;
441
442                 csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
443                 csum_end *= blocksize;
444                 csum_end += key.offset;
445
446                 /* this csum ends before we start, we're done */
447                 if (csum_end <= bytenr)
448                         break;
449
450                 /* delete the entire item, it is inside our range */
451                 if (key.offset >= bytenr && csum_end <= end_byte) {
452                         ret = btrfs_del_item(trans, root, path);
453                         BUG_ON(ret);
454                 } else if (key.offset < bytenr && csum_end > end_byte) {
455                         unsigned long offset;
456                         unsigned long shift_len;
457                         unsigned long item_offset;
458                         /*
459                          *        [ bytenr - len ]
460                          *     [csum                ]
461                          *
462                          * Our bytes are in the middle of the csum,
463                          * we need to split this item and insert a new one.
464                          *
465                          * But we can't drop the path because the
466                          * csum could change, get removed, extended etc.
467                          *
468                          * The trick here is the max size of a csum item leaves
469                          * enough room in the tree block for a single
470                          * item header.  So, we split the item in place,
471                          * adding a new header pointing to the existing
472                          * bytes.  Then we loop around again and we have
473                          * a nicely formed csum item that we can neatly
474                          * truncate.
475                          */
476                         offset = (bytenr - key.offset) / blocksize;
477                         offset *= csum_size;
478
479                         shift_len = (len / blocksize) * csum_size;
480
481                         item_offset = btrfs_item_ptr_offset(leaf,
482                                                             path->slots[0]);
483
484                         memset_extent_buffer(leaf, 0, item_offset + offset,
485                                              shift_len);
486                         key.offset = bytenr;
487
488                         /*
489                          * btrfs_split_item returns -EAGAIN when the
490                          * item changed size or key
491                          */
492                         ret = btrfs_split_item(trans, root, path, &key, offset);
493                         BUG_ON(ret && ret != -EAGAIN);
494
495                         key.offset = end_byte - 1;
496                 } else {
497                         ret = truncate_one_csum(trans, root, path,
498                                                 &key, bytenr, len);
499                         BUG_ON(ret);
500                 }
501                 btrfs_release_path(root, path);
502         }
503 out:
504         btrfs_free_path(path);
505         return 0;
506 }