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