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