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.
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.
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.
17 #include "kerncompat.h"
22 #include "convert/common.h"
23 #include "convert/source-fs.h"
25 static int intersect_with_sb(u64 bytenr, u64 num_bytes)
30 for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
31 offset = btrfs_sb_offset(i);
32 offset &= ~((u64)BTRFS_STRIPE_LEN - 1);
34 if (bytenr < offset + BTRFS_STRIPE_LEN &&
35 bytenr + num_bytes > offset)
41 void init_convert_context(struct btrfs_convert_context *cctx)
43 memset(cctx, 0, sizeof(*cctx));
45 cache_tree_init(&cctx->used_space);
46 cache_tree_init(&cctx->data_chunks);
47 cache_tree_init(&cctx->free_space);
50 void clean_convert_context(struct btrfs_convert_context *cctx)
52 free_extent_cache_tree(&cctx->used_space);
53 free_extent_cache_tree(&cctx->data_chunks);
54 free_extent_cache_tree(&cctx->free_space);
57 int block_iterate_proc(u64 disk_block, u64 file_block,
58 struct blk_iterate_data *idata)
63 struct btrfs_root *root = idata->root;
64 struct btrfs_block_group_cache *cache;
65 u64 bytenr = disk_block * root->sectorsize;
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,
78 idata->first_block += idata->num_blocks;
79 idata->num_blocks = 0;
81 if (file_block > idata->first_block) {
82 ret = record_file_blocks(idata, idata->first_block,
83 0, file_block - idata->first_block);
89 bytenr += BTRFS_STRIPE_LEN - 1;
90 bytenr &= ~((u64)BTRFS_STRIPE_LEN - 1);
92 cache = btrfs_lookup_block_group(root->fs_info, bytenr);
94 bytenr = cache->key.objectid + cache->key.offset;
97 idata->first_block = file_block;
98 idata->disk_block = disk_block;
99 idata->boundary = bytenr / root->sectorsize;
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)
112 struct btrfs_key key;
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;
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;
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)
143 struct btrfs_key location = {
144 .objectid = objectid,
146 .type = BTRFS_INODE_ITEM_KEY,
149 ret = btrfs_insert_dir_item(trans, root, name, name_len,
150 dir, &location, file_type, index_cnt);
153 ret = btrfs_insert_inode_ref(trans, root, name, name_len,
154 objectid, dir, index_cnt);
157 inode_size = btrfs_stack_inode_size(inode) + name_len * 2;
158 btrfs_set_stack_inode_size(inode, inode_size);
163 int read_disk_extent(struct btrfs_root *root, u64 bytenr,
164 u32 num_bytes, char *buffer)
167 struct btrfs_fs_devices *fs_devs = root->fs_info->fs_devices;
169 ret = pread(fs_devs->latest_bdev, buffer, num_bytes, bytenr);
170 if (ret != num_bytes)
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.
185 int record_file_blocks(struct blk_iterate_data *data,
186 u64 file_block, u64 disk_block, u64 num_blocks)
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;
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,
203 btrfs_init_path(&path);
206 * Search real disk bytenr from convert root
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;
213 u64 extent_disk_bytenr;
214 u64 extent_num_bytes;
215 u64 real_disk_bytenr;
218 key.objectid = data->convert_ino;
219 key.type = BTRFS_EXTENT_DATA_KEY;
220 key.offset = cur_off;
222 ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
226 ret = btrfs_previous_item(convert_root, &path,
228 BTRFS_EXTENT_DATA_KEY);
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);
248 if (extent_disk_bytenr)
249 real_disk_bytenr = cur_off - key.offset +
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);
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.
269 btrfs_release_path(&path);