Btrfs-progs: Use /proc/mounts instead of /etc/mtab
[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 = 0;
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                 ret = 0;
222                 goto found;
223         }
224         ret = PTR_ERR(item);
225         if (ret == -EFBIG) {
226                 u32 item_size;
227                 /* we found one, but it isn't big enough yet */
228                 leaf = path->nodes[0];
229                 item_size = btrfs_item_size_nr(leaf, path->slots[0]);
230                 if ((item_size / csum_size) >= MAX_CSUM_ITEMS(root, csum_size)) {
231                         /* already at max size, make a new one */
232                         goto insert;
233                 }
234         } else {
235                 int slot = path->slots[0] + 1;
236                 /* we didn't find a csum item, insert one */
237                 nritems = btrfs_header_nritems(path->nodes[0]);
238                 if (path->slots[0] >= nritems - 1) {
239                         ret = btrfs_next_leaf(root, path);
240                         if (ret == 1)
241                                 found_next = 1;
242                         if (ret != 0)
243                                 goto insert;
244                         slot = 0;
245                 }
246                 btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
247                 if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
248                     found_key.type != BTRFS_EXTENT_CSUM_KEY) {
249                         found_next = 1;
250                         goto insert;
251                 }
252                 next_offset = found_key.offset;
253                 found_next = 1;
254                 goto insert;
255         }
256
257         /*
258          * at this point, we know the tree has an item, but it isn't big
259          * enough yet to put our csum in.  Grow it
260          */
261         btrfs_release_path(root, path);
262         ret = btrfs_search_slot(trans, root, &file_key, path,
263                                 csum_size, 1);
264         if (ret < 0)
265                 goto fail;
266         if (ret == 0) {
267                 BUG();
268         }
269         if (path->slots[0] == 0) {
270                 goto insert;
271         }
272         path->slots[0]--;
273         leaf = path->nodes[0];
274         btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
275         csum_offset = (file_key.offset - found_key.offset) / root->sectorsize;
276         if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
277             found_key.type != BTRFS_EXTENT_CSUM_KEY ||
278             csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
279                 goto insert;
280         }
281         if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
282             csum_size) {
283                 u32 diff = (csum_offset + 1) * csum_size;
284                 diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
285                 if (diff != csum_size)
286                         goto insert;
287                 ret = btrfs_extend_item(trans, root, path, diff);
288                 BUG_ON(ret);
289                 goto csum;
290         }
291
292 insert:
293         btrfs_release_path(root, path);
294         csum_offset = 0;
295         if (found_next) {
296                 u64 tmp = min(alloc_end, next_offset);
297                 tmp -= file_key.offset;
298                 tmp /= root->sectorsize;
299                 tmp = max((u64)1, tmp);
300                 tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
301                 ins_size = csum_size * tmp;
302         } else {
303                 ins_size = csum_size;
304         }
305         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
306                                       ins_size);
307         if (ret < 0)
308                 goto fail;
309         if (ret != 0) {
310                 WARN_ON(1);
311                 goto fail;
312         }
313 csum:
314         leaf = path->nodes[0];
315         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
316         ret = 0;
317         item = (struct btrfs_csum_item *)((unsigned char *)item +
318                                           csum_offset * csum_size);
319 found:
320         csum_result = btrfs_csum_data(root, data, csum_result, len);
321         btrfs_csum_final(csum_result, (char *)&csum_result);
322         if (csum_result == 0) {
323                 printk("csum result is 0 for block %llu\n",
324                        (unsigned long long)bytenr);
325         }
326
327         write_extent_buffer(leaf, &csum_result, (unsigned long)item,
328                             csum_size);
329         btrfs_mark_buffer_dirty(path->nodes[0]);
330 fail:
331         btrfs_release_path(root, path);
332         btrfs_free_path(path);
333         return ret;
334 }
335
336 /*
337  * helper function for csum removal, this expects the
338  * key to describe the csum pointed to by the path, and it expects
339  * the csum to overlap the range [bytenr, len]
340  *
341  * The csum should not be entirely contained in the range and the
342  * range should not be entirely contained in the csum.
343  *
344  * This calls btrfs_truncate_item with the correct args based on the
345  * overlap, and fixes up the key as required.
346  */
347 static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
348                                       struct btrfs_root *root,
349                                       struct btrfs_path *path,
350                                       struct btrfs_key *key,
351                                       u64 bytenr, u64 len)
352 {
353         struct extent_buffer *leaf;
354         u16 csum_size =
355                 btrfs_super_csum_size(root->fs_info->super_copy);
356         u64 csum_end;
357         u64 end_byte = bytenr + len;
358         u32 blocksize = root->sectorsize;
359         int ret;
360
361         leaf = path->nodes[0];
362         csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
363         csum_end *= root->sectorsize;
364         csum_end += key->offset;
365
366         if (key->offset < bytenr && csum_end <= end_byte) {
367                 /*
368                  *         [ bytenr - len ]
369                  *         [   ]
370                  *   [csum     ]
371                  *   A simple truncate off the end of the item
372                  */
373                 u32 new_size = (bytenr - key->offset) / blocksize;
374                 new_size *= csum_size;
375                 ret = btrfs_truncate_item(trans, root, path, new_size, 1);
376                 BUG_ON(ret);
377         } else if (key->offset >= bytenr && csum_end > end_byte &&
378                    end_byte > key->offset) {
379                 /*
380                  *         [ bytenr - len ]
381                  *                 [ ]
382                  *                 [csum     ]
383                  * we need to truncate from the beginning of the csum
384                  */
385                 u32 new_size = (csum_end - end_byte) / blocksize;
386                 new_size *= csum_size;
387
388                 ret = btrfs_truncate_item(trans, root, path, new_size, 0);
389                 BUG_ON(ret);
390
391                 key->offset = end_byte;
392                 ret = btrfs_set_item_key_safe(trans, root, path, key);
393                 BUG_ON(ret);
394         } else {
395                 BUG();
396         }
397         return 0;
398 }
399
400 /*
401  * deletes the csum items from the csum tree for a given
402  * range of bytes.
403  */
404 int btrfs_del_csums(struct btrfs_trans_handle *trans,
405                     struct btrfs_root *root, u64 bytenr, u64 len)
406 {
407         struct btrfs_path *path;
408         struct btrfs_key key;
409         u64 end_byte = bytenr + len;
410         u64 csum_end;
411         struct extent_buffer *leaf;
412         int ret;
413         u16 csum_size =
414                 btrfs_super_csum_size(root->fs_info->super_copy);
415         int blocksize = root->sectorsize;
416
417         root = root->fs_info->csum_root;
418
419         path = btrfs_alloc_path();
420
421         while (1) {
422                 key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
423                 key.offset = end_byte - 1;
424                 key.type = BTRFS_EXTENT_CSUM_KEY;
425
426                 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
427                 if (ret > 0) {
428                         if (path->slots[0] == 0)
429                                 goto out;
430                         path->slots[0]--;
431                 }
432                 leaf = path->nodes[0];
433                 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
434
435                 if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
436                     key.type != BTRFS_EXTENT_CSUM_KEY) {
437                         break;
438                 }
439
440                 if (key.offset >= end_byte)
441                         break;
442
443                 csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
444                 csum_end *= blocksize;
445                 csum_end += key.offset;
446
447                 /* this csum ends before we start, we're done */
448                 if (csum_end <= bytenr)
449                         break;
450
451                 /* delete the entire item, it is inside our range */
452                 if (key.offset >= bytenr && csum_end <= end_byte) {
453                         ret = btrfs_del_item(trans, root, path);
454                         BUG_ON(ret);
455                 } else if (key.offset < bytenr && csum_end > end_byte) {
456                         unsigned long offset;
457                         unsigned long shift_len;
458                         unsigned long item_offset;
459                         /*
460                          *        [ bytenr - len ]
461                          *     [csum                ]
462                          *
463                          * Our bytes are in the middle of the csum,
464                          * we need to split this item and insert a new one.
465                          *
466                          * But we can't drop the path because the
467                          * csum could change, get removed, extended etc.
468                          *
469                          * The trick here is the max size of a csum item leaves
470                          * enough room in the tree block for a single
471                          * item header.  So, we split the item in place,
472                          * adding a new header pointing to the existing
473                          * bytes.  Then we loop around again and we have
474                          * a nicely formed csum item that we can neatly
475                          * truncate.
476                          */
477                         offset = (bytenr - key.offset) / blocksize;
478                         offset *= csum_size;
479
480                         shift_len = (len / blocksize) * csum_size;
481
482                         item_offset = btrfs_item_ptr_offset(leaf,
483                                                             path->slots[0]);
484
485                         memset_extent_buffer(leaf, 0, item_offset + offset,
486                                              shift_len);
487                         key.offset = bytenr;
488
489                         /*
490                          * btrfs_split_item returns -EAGAIN when the
491                          * item changed size or key
492                          */
493                         ret = btrfs_split_item(trans, root, path, &key, offset);
494                         BUG_ON(ret && ret != -EAGAIN);
495
496                         key.offset = end_byte - 1;
497                 } else {
498                         ret = truncate_one_csum(trans, root, path,
499                                                 &key, bytenr, len);
500                         BUG_ON(ret);
501                 }
502                 btrfs_release_path(root, path);
503         }
504 out:
505         btrfs_free_path(path);
506         return 0;
507 }