btrfs-progs: mkfs: delete un-used parameter fd
[platform/upstream/btrfs-progs.git] / convert / source-fs.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public
4  * License v2 as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9  * General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the
13  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14  * Boston, MA 021110-1307, USA.
15  */
16
17 #include "kerncompat.h"
18 #include <unistd.h>
19 #include "internal.h"
20 #include "disk-io.h"
21 #include "volumes.h"
22 #include "convert/common.h"
23 #include "convert/source-fs.h"
24
25 const struct simple_range btrfs_reserved_ranges[3] = {
26         { 0,                         SZ_1M },
27         { BTRFS_SB_MIRROR_OFFSET(1), SZ_64K },
28         { BTRFS_SB_MIRROR_OFFSET(2), SZ_64K }
29 };
30
31 static int intersect_with_sb(u64 bytenr, u64 num_bytes)
32 {
33         int i;
34         u64 offset;
35
36         for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
37                 offset = btrfs_sb_offset(i);
38                 offset &= ~((u64)BTRFS_STRIPE_LEN - 1);
39
40                 if (bytenr < offset + BTRFS_STRIPE_LEN &&
41                     bytenr + num_bytes > offset)
42                         return 1;
43         }
44         return 0;
45 }
46
47 void init_convert_context(struct btrfs_convert_context *cctx)
48 {
49         memset(cctx, 0, sizeof(*cctx));
50
51         cache_tree_init(&cctx->used_space);
52         cache_tree_init(&cctx->data_chunks);
53         cache_tree_init(&cctx->free_space);
54 }
55
56 void clean_convert_context(struct btrfs_convert_context *cctx)
57 {
58         free_extent_cache_tree(&cctx->used_space);
59         free_extent_cache_tree(&cctx->data_chunks);
60         free_extent_cache_tree(&cctx->free_space);
61 }
62
63 int block_iterate_proc(u64 disk_block, u64 file_block,
64                               struct blk_iterate_data *idata)
65 {
66         int ret = 0;
67         int sb_region;
68         int do_barrier;
69         struct btrfs_root *root = idata->root;
70         struct btrfs_block_group_cache *cache;
71         u32 sectorsize = root->fs_info->sectorsize;
72         u64 bytenr = disk_block * sectorsize;
73
74         sb_region = intersect_with_sb(bytenr, sectorsize);
75         do_barrier = sb_region || disk_block >= idata->boundary;
76         if ((idata->num_blocks > 0 && do_barrier) ||
77             (file_block > idata->first_block + idata->num_blocks) ||
78             (disk_block != idata->disk_block + idata->num_blocks)) {
79                 if (idata->num_blocks > 0) {
80                         ret = record_file_blocks(idata, idata->first_block,
81                                                  idata->disk_block,
82                                                  idata->num_blocks);
83                         if (ret)
84                                 goto fail;
85                         idata->first_block += idata->num_blocks;
86                         idata->num_blocks = 0;
87                 }
88                 if (file_block > idata->first_block) {
89                         ret = record_file_blocks(idata, idata->first_block,
90                                         0, file_block - idata->first_block);
91                         if (ret)
92                                 goto fail;
93                 }
94
95                 if (sb_region) {
96                         bytenr += BTRFS_STRIPE_LEN - 1;
97                         bytenr &= ~((u64)BTRFS_STRIPE_LEN - 1);
98                 } else {
99                         cache = btrfs_lookup_block_group(root->fs_info, bytenr);
100                         BUG_ON(!cache);
101                         bytenr = cache->key.objectid + cache->key.offset;
102                 }
103
104                 idata->first_block = file_block;
105                 idata->disk_block = disk_block;
106                 idata->boundary = bytenr / sectorsize;
107         }
108         idata->num_blocks++;
109 fail:
110         return ret;
111 }
112
113 void init_blk_iterate_data(struct blk_iterate_data *data,
114                                   struct btrfs_trans_handle *trans,
115                                   struct btrfs_root *root,
116                                   struct btrfs_inode_item *inode,
117                                   u64 objectid, int checksum)
118 {
119         struct btrfs_key key;
120
121         data->trans             = trans;
122         data->root              = root;
123         data->inode             = inode;
124         data->objectid          = objectid;
125         data->first_block       = 0;
126         data->disk_block        = 0;
127         data->num_blocks        = 0;
128         data->boundary          = (u64)-1;
129         data->checksum          = checksum;
130         data->errcode           = 0;
131
132         key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
133         key.type = BTRFS_ROOT_ITEM_KEY;
134         key.offset = (u64)-1;
135         data->convert_root = btrfs_read_fs_root(root->fs_info, &key);
136         /* Impossible as we just opened it before */
137         BUG_ON(!data->convert_root || IS_ERR(data->convert_root));
138         data->convert_ino = BTRFS_FIRST_FREE_OBJECTID + 1;
139 }
140
141 int convert_insert_dirent(struct btrfs_trans_handle *trans,
142                                  struct btrfs_root *root,
143                                  const char *name, size_t name_len,
144                                  u64 dir, u64 objectid,
145                                  u8 file_type, u64 index_cnt,
146                                  struct btrfs_inode_item *inode)
147 {
148         int ret;
149         u64 inode_size;
150         struct btrfs_key location = {
151                 .objectid = objectid,
152                 .offset = 0,
153                 .type = BTRFS_INODE_ITEM_KEY,
154         };
155
156         ret = btrfs_insert_dir_item(trans, root, name, name_len,
157                                     dir, &location, file_type, index_cnt);
158         if (ret)
159                 return ret;
160         ret = btrfs_insert_inode_ref(trans, root, name, name_len,
161                                      objectid, dir, index_cnt);
162         if (ret)
163                 return ret;
164         inode_size = btrfs_stack_inode_size(inode) + name_len * 2;
165         btrfs_set_stack_inode_size(inode, inode_size);
166
167         return 0;
168 }
169
170 int read_disk_extent(struct btrfs_root *root, u64 bytenr,
171                             u32 num_bytes, char *buffer)
172 {
173         int ret;
174         struct btrfs_fs_devices *fs_devs = root->fs_info->fs_devices;
175
176         ret = pread(fs_devs->latest_bdev, buffer, num_bytes, bytenr);
177         if (ret != num_bytes)
178                 goto fail;
179         ret = 0;
180 fail:
181         if (ret > 0)
182                 ret = -1;
183         return ret;
184 }
185
186 /*
187  * Record a file extent in original filesystem into btrfs one.
188  * The special point is, old disk_block can point to a reserved range.
189  * So here, we don't use disk_block directly but search convert_root
190  * to get the real disk_bytenr.
191  */
192 int record_file_blocks(struct blk_iterate_data *data,
193                               u64 file_block, u64 disk_block, u64 num_blocks)
194 {
195         int ret = 0;
196         struct btrfs_root *root = data->root;
197         struct btrfs_root *convert_root = data->convert_root;
198         struct btrfs_path path;
199         u32 sectorsize = root->fs_info->sectorsize;
200         u64 file_pos = file_block * sectorsize;
201         u64 old_disk_bytenr = disk_block * sectorsize;
202         u64 num_bytes = num_blocks * sectorsize;
203         u64 cur_off = old_disk_bytenr;
204
205         /* Hole, pass it to record_file_extent directly */
206         if (old_disk_bytenr == 0)
207                 return btrfs_record_file_extent(data->trans, root,
208                                 data->objectid, data->inode, file_pos, 0,
209                                 num_bytes);
210
211         btrfs_init_path(&path);
212
213         /*
214          * Search real disk bytenr from convert root
215          */
216         while (cur_off < old_disk_bytenr + num_bytes) {
217                 struct btrfs_key key;
218                 struct btrfs_file_extent_item *fi;
219                 struct extent_buffer *node;
220                 int slot;
221                 u64 extent_disk_bytenr;
222                 u64 extent_num_bytes;
223                 u64 real_disk_bytenr;
224                 u64 cur_len;
225
226                 key.objectid = data->convert_ino;
227                 key.type = BTRFS_EXTENT_DATA_KEY;
228                 key.offset = cur_off;
229
230                 ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
231                 if (ret < 0)
232                         break;
233                 if (ret > 0) {
234                         ret = btrfs_previous_item(convert_root, &path,
235                                                   data->convert_ino,
236                                                   BTRFS_EXTENT_DATA_KEY);
237                         if (ret < 0)
238                                 break;
239                         if (ret > 0) {
240                                 ret = -ENOENT;
241                                 break;
242                         }
243                 }
244                 node = path.nodes[0];
245                 slot = path.slots[0];
246                 btrfs_item_key_to_cpu(node, &key, slot);
247                 BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY ||
248                        key.objectid != data->convert_ino ||
249                        key.offset > cur_off);
250                 fi = btrfs_item_ptr(node, slot, struct btrfs_file_extent_item);
251                 extent_disk_bytenr = btrfs_file_extent_disk_bytenr(node, fi);
252                 extent_num_bytes = btrfs_file_extent_num_bytes(node, fi);
253                 BUG_ON(cur_off - key.offset >= extent_num_bytes);
254                 btrfs_release_path(&path);
255
256                 if (extent_disk_bytenr)
257                         real_disk_bytenr = cur_off - key.offset +
258                                            extent_disk_bytenr;
259                 else
260                         real_disk_bytenr = 0;
261                 cur_len = min(key.offset + extent_num_bytes,
262                               old_disk_bytenr + num_bytes) - cur_off;
263                 ret = btrfs_record_file_extent(data->trans, data->root,
264                                         data->objectid, data->inode, file_pos,
265                                         real_disk_bytenr, cur_len);
266                 if (ret < 0)
267                         break;
268                 cur_off += cur_len;
269                 file_pos += cur_len;
270
271                 /*
272                  * No need to care about csum
273                  * As every byte of old fs image is calculated for csum, no
274                  * need to waste CPU cycles now.
275                  */
276         }
277         btrfs_release_path(&path);
278         return ret;
279 }
280