btrfs-progs: build: Do not use cp -a to install library links
[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 dev_t decode_dev(u32 dev)
32 {
33         unsigned major = (dev & 0xfff00) >> 8;
34         unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
35
36         return MKDEV(major, minor);
37 }
38
39 int ext2_acl_count(size_t size)
40 {
41         ssize_t s;
42
43         size -= sizeof(ext2_acl_header);
44         s = size - 4 * sizeof(ext2_acl_entry_short);
45         if (s < 0) {
46                 if (size % sizeof(ext2_acl_entry_short))
47                         return -1;
48                 return size / sizeof(ext2_acl_entry_short);
49         } else {
50                 if (s % sizeof(ext2_acl_entry))
51                         return -1;
52                 return s / sizeof(ext2_acl_entry) + 4;
53         }
54 }
55
56 static u64 intersect_with_reserved(u64 bytenr, u64 num_bytes)
57 {
58         int i;
59
60         for (i = 0; i < ARRAY_SIZE(btrfs_reserved_ranges); i++) {
61                 const struct simple_range *range = &btrfs_reserved_ranges[i];
62
63                 if (bytenr < range_end(range) &&
64                     bytenr + num_bytes >= range->start)
65                         return range_end(range);
66         }
67         return 0;
68 }
69
70 void init_convert_context(struct btrfs_convert_context *cctx)
71 {
72         memset(cctx, 0, sizeof(*cctx));
73
74         cache_tree_init(&cctx->used_space);
75         cache_tree_init(&cctx->data_chunks);
76         cache_tree_init(&cctx->free_space);
77 }
78
79 void clean_convert_context(struct btrfs_convert_context *cctx)
80 {
81         free_extent_cache_tree(&cctx->used_space);
82         free_extent_cache_tree(&cctx->data_chunks);
83         free_extent_cache_tree(&cctx->free_space);
84 }
85
86 int block_iterate_proc(u64 disk_block, u64 file_block,
87                               struct blk_iterate_data *idata)
88 {
89         int ret = 0;
90         u64 reserved_boundary;
91         int do_barrier;
92         struct btrfs_root *root = idata->root;
93         struct btrfs_block_group_cache *cache;
94         u32 sectorsize = root->fs_info->sectorsize;
95         u64 bytenr = disk_block * sectorsize;
96
97         reserved_boundary = intersect_with_reserved(bytenr, sectorsize);
98         do_barrier = reserved_boundary || disk_block >= idata->boundary;
99         if ((idata->num_blocks > 0 && do_barrier) ||
100             (file_block > idata->first_block + idata->num_blocks) ||
101             (disk_block != idata->disk_block + idata->num_blocks)) {
102                 if (idata->num_blocks > 0) {
103                         ret = record_file_blocks(idata, idata->first_block,
104                                                  idata->disk_block,
105                                                  idata->num_blocks);
106                         if (ret)
107                                 goto fail;
108                         idata->first_block += idata->num_blocks;
109                         idata->num_blocks = 0;
110                 }
111                 if (file_block > idata->first_block) {
112                         ret = record_file_blocks(idata, idata->first_block,
113                                         0, file_block - idata->first_block);
114                         if (ret)
115                                 goto fail;
116                 }
117
118                 if (reserved_boundary) {
119                         bytenr = reserved_boundary;
120                 } else {
121                         cache = btrfs_lookup_block_group(root->fs_info, bytenr);
122                         BUG_ON(!cache);
123                         bytenr = cache->key.objectid + cache->key.offset;
124                 }
125
126                 idata->first_block = file_block;
127                 idata->disk_block = disk_block;
128                 idata->boundary = bytenr / sectorsize;
129         }
130         idata->num_blocks++;
131 fail:
132         return ret;
133 }
134
135 void init_blk_iterate_data(struct blk_iterate_data *data,
136                                   struct btrfs_trans_handle *trans,
137                                   struct btrfs_root *root,
138                                   struct btrfs_inode_item *inode,
139                                   u64 objectid, int checksum)
140 {
141         struct btrfs_key key;
142
143         data->trans             = trans;
144         data->root              = root;
145         data->inode             = inode;
146         data->objectid          = objectid;
147         data->first_block       = 0;
148         data->disk_block        = 0;
149         data->num_blocks        = 0;
150         data->boundary          = (u64)-1;
151         data->checksum          = checksum;
152         data->errcode           = 0;
153
154         key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
155         key.type = BTRFS_ROOT_ITEM_KEY;
156         key.offset = (u64)-1;
157         data->convert_root = btrfs_read_fs_root(root->fs_info, &key);
158         /* Impossible as we just opened it before */
159         BUG_ON(!data->convert_root || IS_ERR(data->convert_root));
160         data->convert_ino = BTRFS_FIRST_FREE_OBJECTID + 1;
161 }
162
163 int convert_insert_dirent(struct btrfs_trans_handle *trans,
164                                  struct btrfs_root *root,
165                                  const char *name, size_t name_len,
166                                  u64 dir, u64 objectid,
167                                  u8 file_type, u64 index_cnt,
168                                  struct btrfs_inode_item *inode)
169 {
170         int ret;
171         u64 inode_size;
172         struct btrfs_key location = {
173                 .objectid = objectid,
174                 .offset = 0,
175                 .type = BTRFS_INODE_ITEM_KEY,
176         };
177
178         ret = btrfs_insert_dir_item(trans, root, name, name_len,
179                                     dir, &location, file_type, index_cnt);
180         if (ret)
181                 return ret;
182         ret = btrfs_insert_inode_ref(trans, root, name, name_len,
183                                      objectid, dir, index_cnt);
184         if (ret)
185                 return ret;
186         inode_size = btrfs_stack_inode_size(inode) + name_len * 2;
187         btrfs_set_stack_inode_size(inode, inode_size);
188
189         return 0;
190 }
191
192 int read_disk_extent(struct btrfs_root *root, u64 bytenr,
193                             u32 num_bytes, char *buffer)
194 {
195         int ret;
196         struct btrfs_fs_devices *fs_devs = root->fs_info->fs_devices;
197
198         ret = pread(fs_devs->latest_bdev, buffer, num_bytes, bytenr);
199         if (ret != num_bytes)
200                 goto fail;
201         ret = 0;
202 fail:
203         if (ret > 0)
204                 ret = -1;
205         return ret;
206 }
207
208 /*
209  * Record a file extent in original filesystem into btrfs one.
210  * The special point is, old disk_block can point to a reserved range.
211  * So here, we don't use disk_block directly but search convert_root
212  * to get the real disk_bytenr.
213  */
214 int record_file_blocks(struct blk_iterate_data *data,
215                               u64 file_block, u64 disk_block, u64 num_blocks)
216 {
217         int ret = 0;
218         struct btrfs_root *root = data->root;
219         struct btrfs_root *convert_root = data->convert_root;
220         struct btrfs_path path;
221         u32 sectorsize = root->fs_info->sectorsize;
222         u64 file_pos = file_block * sectorsize;
223         u64 old_disk_bytenr = disk_block * sectorsize;
224         u64 num_bytes = num_blocks * sectorsize;
225         u64 cur_off = old_disk_bytenr;
226
227         /* Hole, pass it to record_file_extent directly */
228         if (old_disk_bytenr == 0)
229                 return btrfs_record_file_extent(data->trans, root,
230                                 data->objectid, data->inode, file_pos, 0,
231                                 num_bytes);
232
233         btrfs_init_path(&path);
234
235         /*
236          * Search real disk bytenr from convert root
237          */
238         while (cur_off < old_disk_bytenr + num_bytes) {
239                 struct btrfs_key key;
240                 struct btrfs_file_extent_item *fi;
241                 struct extent_buffer *node;
242                 int slot;
243                 u64 extent_disk_bytenr;
244                 u64 extent_num_bytes;
245                 u64 real_disk_bytenr;
246                 u64 cur_len;
247
248                 key.objectid = data->convert_ino;
249                 key.type = BTRFS_EXTENT_DATA_KEY;
250                 key.offset = cur_off;
251
252                 ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
253                 if (ret < 0)
254                         break;
255                 if (ret > 0) {
256                         ret = btrfs_previous_item(convert_root, &path,
257                                                   data->convert_ino,
258                                                   BTRFS_EXTENT_DATA_KEY);
259                         if (ret < 0)
260                                 break;
261                         if (ret > 0) {
262                                 ret = -ENOENT;
263                                 break;
264                         }
265                 }
266                 node = path.nodes[0];
267                 slot = path.slots[0];
268                 btrfs_item_key_to_cpu(node, &key, slot);
269                 BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY ||
270                        key.objectid != data->convert_ino ||
271                        key.offset > cur_off);
272                 fi = btrfs_item_ptr(node, slot, struct btrfs_file_extent_item);
273                 extent_disk_bytenr = btrfs_file_extent_disk_bytenr(node, fi);
274                 extent_num_bytes = btrfs_file_extent_num_bytes(node, fi);
275                 BUG_ON(cur_off - key.offset >= extent_num_bytes);
276                 btrfs_release_path(&path);
277
278                 if (extent_disk_bytenr)
279                         real_disk_bytenr = cur_off - key.offset +
280                                            extent_disk_bytenr;
281                 else
282                         real_disk_bytenr = 0;
283                 cur_len = min(key.offset + extent_num_bytes,
284                               old_disk_bytenr + num_bytes) - cur_off;
285                 ret = btrfs_record_file_extent(data->trans, data->root,
286                                         data->objectid, data->inode, file_pos,
287                                         real_disk_bytenr, cur_len);
288                 if (ret < 0)
289                         break;
290                 cur_off += cur_len;
291                 file_pos += cur_len;
292
293                 /*
294                  * No need to care about csum
295                  * As every byte of old fs image is calculated for csum, no
296                  * need to waste CPU cycles now.
297                  */
298         }
299         btrfs_release_path(&path);
300         return ret;
301 }
302