diff options
Diffstat (limited to 'meta/recipes-devtools/btrfs-tools/btrfs-tools/upstream-tmp/0013-btrfs-progs-Add-new-feature-to-mkfs.btrfs-to-make-fi.patch')
-rw-r--r-- | meta/recipes-devtools/btrfs-tools/btrfs-tools/upstream-tmp/0013-btrfs-progs-Add-new-feature-to-mkfs.btrfs-to-make-fi.patch | 1108 |
1 files changed, 1108 insertions, 0 deletions
diff --git a/meta/recipes-devtools/btrfs-tools/btrfs-tools/upstream-tmp/0013-btrfs-progs-Add-new-feature-to-mkfs.btrfs-to-make-fi.patch b/meta/recipes-devtools/btrfs-tools/btrfs-tools/upstream-tmp/0013-btrfs-progs-Add-new-feature-to-mkfs.btrfs-to-make-fi.patch new file mode 100644 index 0000000000..215106edb8 --- /dev/null +++ b/meta/recipes-devtools/btrfs-tools/btrfs-tools/upstream-tmp/0013-btrfs-progs-Add-new-feature-to-mkfs.btrfs-to-make-fi.patch | |||
@@ -0,0 +1,1108 @@ | |||
1 | Upstream-Status: Inappropriate [Backport] | ||
2 | From e3736c698e8b490bea1375576b718a2de6e89603 Mon Sep 17 00:00:00 2001 | ||
3 | From: Donggeun Kim <dg77.kim@samsung.com> | ||
4 | Date: Thu, 8 Jul 2010 09:17:59 +0000 | ||
5 | Subject: [PATCH 13/15] btrfs-progs: Add new feature to mkfs.btrfs to make file system image file from source directory | ||
6 | |||
7 | Changes from V1 to V2: | ||
8 | - support extended attributes | ||
9 | - move btrfs_alloc_data_chunk function to volumes.c | ||
10 | - fix an execution error when additional useless parameters are specified | ||
11 | - fix traverse_directory function so that the insertion functions for the common items are invoked in a single point | ||
12 | |||
13 | The extended attributes is implemented through llistxattr and getxattr function calls. | ||
14 | |||
15 | Thanks | ||
16 | |||
17 | Signed-off-by: Donggeun Kim <dg77.kim@samsung.com> | ||
18 | Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> | ||
19 | Signed-off-by: Chris Mason <chris.mason@oracle.com> | ||
20 | --- | ||
21 | mkfs.c | 864 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- | ||
22 | volumes.c | 104 ++++++++ | ||
23 | volumes.h | 3 + | ||
24 | 3 files changed, 947 insertions(+), 24 deletions(-) | ||
25 | |||
26 | diff --git a/mkfs.c b/mkfs.c | ||
27 | index 04de93a..57c88f9 100644 | ||
28 | --- a/mkfs.c | ||
29 | +++ b/mkfs.c | ||
30 | @@ -29,12 +29,14 @@ | ||
31 | #include <stdlib.h> | ||
32 | #include <sys/types.h> | ||
33 | #include <sys/stat.h> | ||
34 | +#include <sys/dir.h> | ||
35 | #include <fcntl.h> | ||
36 | #include <unistd.h> | ||
37 | #include <getopt.h> | ||
38 | #include <uuid/uuid.h> | ||
39 | #include <linux/fs.h> | ||
40 | #include <ctype.h> | ||
41 | +#include <attr/xattr.h> | ||
42 | #include "kerncompat.h" | ||
43 | #include "ctree.h" | ||
44 | #include "disk-io.h" | ||
45 | @@ -43,6 +45,15 @@ | ||
46 | #include "utils.h" | ||
47 | #include "version.h" | ||
48 | |||
49 | +static u64 index_cnt = 2; | ||
50 | + | ||
51 | +struct directory_name_entry { | ||
52 | + char *dir_name; | ||
53 | + char *path; | ||
54 | + ino_t inum; | ||
55 | + struct list_head list; | ||
56 | +}; | ||
57 | + | ||
58 | static u64 parse_size(char *s) | ||
59 | { | ||
60 | int len = strlen(s); | ||
61 | @@ -298,6 +309,7 @@ static void print_usage(void) | ||
62 | fprintf(stderr, "\t -M --mixed mix metadata and data together\n"); | ||
63 | fprintf(stderr, "\t -n --nodesize size of btree nodes\n"); | ||
64 | fprintf(stderr, "\t -s --sectorsize min block allocation\n"); | ||
65 | + fprintf(stderr, "\t -r --rootdir the source directory\n"); | ||
66 | fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); | ||
67 | exit(1); | ||
68 | } | ||
69 | @@ -355,9 +367,768 @@ static struct option long_options[] = { | ||
70 | { "sectorsize", 1, NULL, 's' }, | ||
71 | { "data", 1, NULL, 'd' }, | ||
72 | { "version", 0, NULL, 'V' }, | ||
73 | + { "rootdir", 1, NULL, 'r' }, | ||
74 | { 0, 0, 0, 0} | ||
75 | }; | ||
76 | |||
77 | +static int add_directory_items(struct btrfs_trans_handle *trans, | ||
78 | + struct btrfs_root *root, u64 objectid, | ||
79 | + ino_t parent_inum, const char *name, | ||
80 | + struct stat *st, int *dir_index_cnt) | ||
81 | +{ | ||
82 | + int ret; | ||
83 | + int name_len; | ||
84 | + struct btrfs_key location; | ||
85 | + u8 filetype = 0; | ||
86 | + | ||
87 | + name_len = strlen(name); | ||
88 | + | ||
89 | + location.objectid = objectid; | ||
90 | + location.offset = 0; | ||
91 | + btrfs_set_key_type(&location, BTRFS_INODE_ITEM_KEY); | ||
92 | + | ||
93 | + if (S_ISDIR(st->st_mode)) | ||
94 | + filetype = BTRFS_FT_DIR; | ||
95 | + if (S_ISREG(st->st_mode)) | ||
96 | + filetype = BTRFS_FT_REG_FILE; | ||
97 | + if (S_ISLNK(st->st_mode)) | ||
98 | + filetype = BTRFS_FT_SYMLINK; | ||
99 | + | ||
100 | + ret = btrfs_insert_dir_item(trans, root, name, name_len, | ||
101 | + parent_inum, &location, | ||
102 | + filetype, index_cnt); | ||
103 | + | ||
104 | + *dir_index_cnt = index_cnt; | ||
105 | + index_cnt++; | ||
106 | + | ||
107 | + return ret; | ||
108 | +} | ||
109 | + | ||
110 | +static int fill_inode_item(struct btrfs_trans_handle *trans, | ||
111 | + struct btrfs_root *root, | ||
112 | + struct btrfs_inode_item *dst, struct stat *src) | ||
113 | +{ | ||
114 | + u64 blocks = 0; | ||
115 | + u64 sectorsize = root->sectorsize; | ||
116 | + | ||
117 | + btrfs_set_stack_inode_generation(dst, trans->transid); | ||
118 | + btrfs_set_stack_inode_size(dst, src->st_size); | ||
119 | + btrfs_set_stack_inode_nbytes(dst, 0); | ||
120 | + btrfs_set_stack_inode_block_group(dst, 0); | ||
121 | + btrfs_set_stack_inode_nlink(dst, src->st_nlink); | ||
122 | + btrfs_set_stack_inode_uid(dst, src->st_uid); | ||
123 | + btrfs_set_stack_inode_gid(dst, src->st_gid); | ||
124 | + btrfs_set_stack_inode_mode(dst, src->st_mode); | ||
125 | + btrfs_set_stack_inode_rdev(dst, 0); | ||
126 | + btrfs_set_stack_inode_flags(dst, 0); | ||
127 | + btrfs_set_stack_timespec_sec(&dst->atime, src->st_atime); | ||
128 | + btrfs_set_stack_timespec_nsec(&dst->atime, 0); | ||
129 | + btrfs_set_stack_timespec_sec(&dst->ctime, src->st_ctime); | ||
130 | + btrfs_set_stack_timespec_nsec(&dst->ctime, 0); | ||
131 | + btrfs_set_stack_timespec_sec(&dst->mtime, src->st_mtime); | ||
132 | + btrfs_set_stack_timespec_nsec(&dst->mtime, 0); | ||
133 | + btrfs_set_stack_timespec_sec(&dst->otime, 0); | ||
134 | + btrfs_set_stack_timespec_nsec(&dst->otime, 0); | ||
135 | + | ||
136 | + if (S_ISDIR(src->st_mode)) { | ||
137 | + btrfs_set_stack_inode_size(dst, 0); | ||
138 | + btrfs_set_stack_inode_nlink(dst, 1); | ||
139 | + } | ||
140 | + if (S_ISREG(src->st_mode)) { | ||
141 | + btrfs_set_stack_inode_size(dst, (u64)src->st_size); | ||
142 | + if (src->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(root)) | ||
143 | + btrfs_set_stack_inode_nbytes(dst, src->st_size); | ||
144 | + else { | ||
145 | + blocks = src->st_size / sectorsize; | ||
146 | + if (src->st_size % sectorsize) | ||
147 | + blocks += 1; | ||
148 | + blocks *= sectorsize; | ||
149 | + btrfs_set_stack_inode_nbytes(dst, blocks); | ||
150 | + } | ||
151 | + } | ||
152 | + if (S_ISLNK(src->st_mode)) | ||
153 | + btrfs_set_stack_inode_nbytes(dst, src->st_size + 1); | ||
154 | + | ||
155 | + return 0; | ||
156 | +} | ||
157 | + | ||
158 | +static int directory_select(const struct direct *entry) | ||
159 | +{ | ||
160 | + if ((strncmp(entry->d_name, ".", entry->d_reclen) == 0) || | ||
161 | + (strncmp(entry->d_name, "..", entry->d_reclen) == 0)) | ||
162 | + return 0; | ||
163 | + else | ||
164 | + return 1; | ||
165 | +} | ||
166 | + | ||
167 | +static u64 calculate_dir_inode_size(char *dirname) | ||
168 | +{ | ||
169 | + int count, i; | ||
170 | + struct direct **files, *cur_file; | ||
171 | + u64 dir_inode_size = 0; | ||
172 | + | ||
173 | + count = scandir(dirname, &files, directory_select, NULL); | ||
174 | + | ||
175 | + for (i = 0; i < count; i++) { | ||
176 | + cur_file = files[i]; | ||
177 | + dir_inode_size += strlen(cur_file->d_name); | ||
178 | + } | ||
179 | + | ||
180 | + dir_inode_size *= 2; | ||
181 | + return dir_inode_size; | ||
182 | +} | ||
183 | + | ||
184 | +static int add_inode_items(struct btrfs_trans_handle *trans, | ||
185 | + struct btrfs_root *root, | ||
186 | + struct stat *st, char *name, | ||
187 | + u64 self_objectid, ino_t parent_inum, | ||
188 | + int dir_index_cnt, struct btrfs_inode_item *inode_ret) | ||
189 | +{ | ||
190 | + int ret; | ||
191 | + struct btrfs_key inode_key; | ||
192 | + struct btrfs_inode_item btrfs_inode; | ||
193 | + u64 objectid; | ||
194 | + u64 inode_size = 0; | ||
195 | + int name_len; | ||
196 | + | ||
197 | + name_len = strlen(name); | ||
198 | + fill_inode_item(trans, root, &btrfs_inode, st); | ||
199 | + objectid = self_objectid; | ||
200 | + | ||
201 | + if (S_ISDIR(st->st_mode)) { | ||
202 | + inode_size = calculate_dir_inode_size(name); | ||
203 | + btrfs_set_stack_inode_size(&btrfs_inode, inode_size); | ||
204 | + } | ||
205 | + | ||
206 | + inode_key.objectid = objectid; | ||
207 | + inode_key.offset = 0; | ||
208 | + btrfs_set_key_type(&inode_key, BTRFS_INODE_ITEM_KEY); | ||
209 | + | ||
210 | + ret = btrfs_insert_inode(trans, root, objectid, &btrfs_inode); | ||
211 | + if (ret) | ||
212 | + goto fail; | ||
213 | + | ||
214 | + ret = btrfs_insert_inode_ref(trans, root, name, name_len, | ||
215 | + objectid, parent_inum, dir_index_cnt); | ||
216 | + if (ret) | ||
217 | + goto fail; | ||
218 | + | ||
219 | + *inode_ret = btrfs_inode; | ||
220 | +fail: | ||
221 | + return ret; | ||
222 | +} | ||
223 | + | ||
224 | +static int add_xattr_item(struct btrfs_trans_handle *trans, | ||
225 | + struct btrfs_root *root, u64 objectid, | ||
226 | + const char *file_name) | ||
227 | +{ | ||
228 | + int ret; | ||
229 | + int cur_name_len; | ||
230 | + char xattr_list[XATTR_LIST_MAX]; | ||
231 | + char *cur_name; | ||
232 | + char cur_value[XATTR_SIZE_MAX]; | ||
233 | + char delimiter = '\0'; | ||
234 | + char *next_location = xattr_list; | ||
235 | + | ||
236 | + ret = llistxattr(file_name, xattr_list, XATTR_LIST_MAX); | ||
237 | + if (ret < 0) { | ||
238 | + fprintf(stderr, "get a list of xattr failed for %s\n", | ||
239 | + file_name); | ||
240 | + return ret; | ||
241 | + } | ||
242 | + if (ret == 0) | ||
243 | + return ret; | ||
244 | + | ||
245 | + cur_name = strtok(xattr_list, &delimiter); | ||
246 | + while (cur_name != NULL) { | ||
247 | + cur_name_len = strlen(cur_name); | ||
248 | + next_location += cur_name_len + 1; | ||
249 | + | ||
250 | + ret = getxattr(file_name, cur_name, cur_value, XATTR_SIZE_MAX); | ||
251 | + if (ret < 0) { | ||
252 | + fprintf(stderr, "get a xattr value failed for %s\n", | ||
253 | + cur_name); | ||
254 | + } | ||
255 | + | ||
256 | + ret = btrfs_insert_xattr_item(trans, root, cur_name, | ||
257 | + cur_name_len, cur_value, | ||
258 | + ret, objectid); | ||
259 | + if (ret) { | ||
260 | + fprintf(stderr, "insert a xattr item failed for %s\n", | ||
261 | + file_name); | ||
262 | + } | ||
263 | + | ||
264 | + cur_name = strtok(next_location, &delimiter); | ||
265 | + } | ||
266 | + | ||
267 | + return ret; | ||
268 | +} | ||
269 | + | ||
270 | +static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes, | ||
271 | + u64 hint_byte, struct btrfs_key *ins) | ||
272 | +{ | ||
273 | + u64 start; | ||
274 | + u64 end; | ||
275 | + u64 last = hint_byte; | ||
276 | + int ret; | ||
277 | + int wrapped = 0; | ||
278 | + struct btrfs_block_group_cache *cache; | ||
279 | + | ||
280 | + while (1) { | ||
281 | + ret = find_first_extent_bit(&root->fs_info->free_space_cache, | ||
282 | + last, &start, &end, EXTENT_DIRTY); | ||
283 | + if (ret) { | ||
284 | + if (wrapped++ == 0) { | ||
285 | + last = 0; | ||
286 | + continue; | ||
287 | + } else { | ||
288 | + goto fail; | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | + start = max(last, start); | ||
293 | + last = end + 1; | ||
294 | + if (last - start < num_bytes) | ||
295 | + continue; | ||
296 | + | ||
297 | + last = start + num_bytes; | ||
298 | + if (test_range_bit(&root->fs_info->pinned_extents, | ||
299 | + start, last - 1, EXTENT_DIRTY, 0)) | ||
300 | + continue; | ||
301 | + | ||
302 | + cache = btrfs_lookup_block_group(root->fs_info, start); | ||
303 | + BUG_ON(!cache); | ||
304 | + if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM || | ||
305 | + last > cache->key.objectid + cache->key.offset) { | ||
306 | + last = cache->key.objectid + cache->key.offset; | ||
307 | + continue; | ||
308 | + } | ||
309 | + | ||
310 | + if (cache->flags & (BTRFS_BLOCK_GROUP_SYSTEM | | ||
311 | + BTRFS_BLOCK_GROUP_METADATA)) { | ||
312 | + last = cache->key.objectid + cache->key.offset; | ||
313 | + continue; | ||
314 | + } | ||
315 | + | ||
316 | + clear_extent_dirty(&root->fs_info->free_space_cache, | ||
317 | + start, start + num_bytes - 1, 0); | ||
318 | + | ||
319 | + ins->objectid = start; | ||
320 | + ins->offset = num_bytes; | ||
321 | + ins->type = BTRFS_EXTENT_ITEM_KEY; | ||
322 | + return 0; | ||
323 | + } | ||
324 | +fail: | ||
325 | + fprintf(stderr, "not enough free space\n"); | ||
326 | + return -ENOSPC; | ||
327 | +} | ||
328 | + | ||
329 | +static int record_file_extent(struct btrfs_trans_handle *trans, | ||
330 | + struct btrfs_root *root, u64 objectid, | ||
331 | + struct btrfs_inode_item *inode, | ||
332 | + u64 file_pos, u64 disk_bytenr, | ||
333 | + u64 num_bytes) | ||
334 | +{ | ||
335 | + int ret; | ||
336 | + struct btrfs_fs_info *info = root->fs_info; | ||
337 | + struct btrfs_root *extent_root = info->extent_root; | ||
338 | + struct extent_buffer *leaf; | ||
339 | + struct btrfs_file_extent_item *fi; | ||
340 | + struct btrfs_key ins_key; | ||
341 | + struct btrfs_path path; | ||
342 | + struct btrfs_extent_item *ei; | ||
343 | + | ||
344 | + btrfs_init_path(&path); | ||
345 | + | ||
346 | + ins_key.objectid = objectid; | ||
347 | + ins_key.offset = 0; | ||
348 | + btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY); | ||
349 | + ret = btrfs_insert_empty_item(trans, root, &path, &ins_key, | ||
350 | + sizeof(*fi)); | ||
351 | + if (ret) | ||
352 | + goto fail; | ||
353 | + leaf = path.nodes[0]; | ||
354 | + fi = btrfs_item_ptr(leaf, path.slots[0], | ||
355 | + struct btrfs_file_extent_item); | ||
356 | + btrfs_set_file_extent_generation(leaf, fi, trans->transid); | ||
357 | + btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); | ||
358 | + btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr); | ||
359 | + btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes); | ||
360 | + btrfs_set_file_extent_offset(leaf, fi, 0); | ||
361 | + btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); | ||
362 | + btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); | ||
363 | + btrfs_set_file_extent_compression(leaf, fi, 0); | ||
364 | + btrfs_set_file_extent_encryption(leaf, fi, 0); | ||
365 | + btrfs_set_file_extent_other_encoding(leaf, fi, 0); | ||
366 | + btrfs_mark_buffer_dirty(leaf); | ||
367 | + | ||
368 | + btrfs_release_path(root, &path); | ||
369 | + | ||
370 | + ins_key.objectid = disk_bytenr; | ||
371 | + ins_key.offset = num_bytes; | ||
372 | + ins_key.type = BTRFS_EXTENT_ITEM_KEY; | ||
373 | + | ||
374 | + ret = btrfs_insert_empty_item(trans, extent_root, &path, | ||
375 | + &ins_key, sizeof(*ei)); | ||
376 | + if (ret == 0) { | ||
377 | + leaf = path.nodes[0]; | ||
378 | + ei = btrfs_item_ptr(leaf, path.slots[0], | ||
379 | + struct btrfs_extent_item); | ||
380 | + | ||
381 | + btrfs_set_extent_refs(leaf, ei, 0); | ||
382 | + btrfs_set_extent_generation(leaf, ei, trans->transid); | ||
383 | + btrfs_set_extent_flags(leaf, ei, BTRFS_EXTENT_FLAG_DATA); | ||
384 | + | ||
385 | + btrfs_mark_buffer_dirty(leaf); | ||
386 | + ret = btrfs_update_block_group(trans, root, disk_bytenr, | ||
387 | + num_bytes, 1, 0); | ||
388 | + if (ret) | ||
389 | + goto fail; | ||
390 | + } else if (ret != -EEXIST) { | ||
391 | + goto fail; | ||
392 | + } | ||
393 | + | ||
394 | + ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, 0, | ||
395 | + root->root_key.objectid, | ||
396 | + objectid, 0); | ||
397 | +fail: | ||
398 | + btrfs_release_path(root, &path); | ||
399 | + return ret; | ||
400 | +} | ||
401 | + | ||
402 | +static int add_symbolic_link(struct btrfs_trans_handle *trans, | ||
403 | + struct btrfs_root *root, | ||
404 | + u64 objectid, const char *path_name) | ||
405 | +{ | ||
406 | + int ret; | ||
407 | + u64 sectorsize = root->sectorsize; | ||
408 | + char *buf = malloc(sectorsize); | ||
409 | + | ||
410 | + ret = readlink(path_name, buf, sectorsize); | ||
411 | + if (ret <= 0) { | ||
412 | + fprintf(stderr, "readlink failed for %s\n", path_name); | ||
413 | + goto fail; | ||
414 | + } | ||
415 | + if (ret > sectorsize) { | ||
416 | + fprintf(stderr, "symlink too long for %s", path_name); | ||
417 | + ret = -1; | ||
418 | + goto fail; | ||
419 | + } | ||
420 | + ret = btrfs_insert_inline_extent(trans, root, objectid, 0, | ||
421 | + buf, ret + 1); | ||
422 | +fail: | ||
423 | + free(buf); | ||
424 | + return ret; | ||
425 | +} | ||
426 | + | ||
427 | +static int add_file_items(struct btrfs_trans_handle *trans, | ||
428 | + struct btrfs_root *root, | ||
429 | + struct btrfs_inode_item *btrfs_inode, u64 objectid, | ||
430 | + ino_t parent_inum, struct stat *st, | ||
431 | + const char *path_name, int out_fd) | ||
432 | +{ | ||
433 | + int ret; | ||
434 | + ssize_t ret_read; | ||
435 | + u64 bytes_read = 0; | ||
436 | + char *buffer = NULL; | ||
437 | + struct btrfs_key key; | ||
438 | + int blocks; | ||
439 | + u32 sectorsize = root->sectorsize; | ||
440 | + u64 first_block = 0; | ||
441 | + u64 num_blocks = 0; | ||
442 | + int fd; | ||
443 | + | ||
444 | + fd = open(path_name, O_RDONLY); | ||
445 | + if (fd == -1) { | ||
446 | + fprintf(stderr, "%s open failed\n", path_name); | ||
447 | + goto end; | ||
448 | + } | ||
449 | + | ||
450 | + blocks = st->st_size / sectorsize; | ||
451 | + if (st->st_size % sectorsize) | ||
452 | + blocks += 1; | ||
453 | + | ||
454 | + if (st->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(root)) { | ||
455 | + buffer = malloc(st->st_size); | ||
456 | + ret_read = pread64(fd, buffer, st->st_size, bytes_read); | ||
457 | + if (ret_read == -1) { | ||
458 | + fprintf(stderr, "%s read failed\n", path_name); | ||
459 | + goto end; | ||
460 | + } | ||
461 | + | ||
462 | + ret = btrfs_insert_inline_extent(trans, root, objectid, 0, | ||
463 | + buffer, st->st_size); | ||
464 | + goto end; | ||
465 | + } | ||
466 | + | ||
467 | + ret = custom_alloc_extent(root, blocks * sectorsize, 0, &key); | ||
468 | + if (ret) | ||
469 | + goto end; | ||
470 | + | ||
471 | + first_block = key.objectid; | ||
472 | + bytes_read = 0; | ||
473 | + buffer = malloc(sectorsize); | ||
474 | + | ||
475 | + do { | ||
476 | + memset(buffer, 0, sectorsize); | ||
477 | + ret_read = pread64(fd, buffer, sectorsize, bytes_read); | ||
478 | + if (ret_read == -1) { | ||
479 | + fprintf(stderr, "%s read failed\n", path_name); | ||
480 | + goto end; | ||
481 | + } | ||
482 | + | ||
483 | + ret = pwrite64(out_fd, buffer, sectorsize, | ||
484 | + first_block + bytes_read); | ||
485 | + if (ret != sectorsize) { | ||
486 | + fprintf(stderr, "output file write failed\n"); | ||
487 | + goto end; | ||
488 | + } | ||
489 | + | ||
490 | + /* checksum for file data */ | ||
491 | + ret = btrfs_csum_file_block(trans, root->fs_info->csum_root, | ||
492 | + first_block + (blocks * sectorsize), | ||
493 | + first_block + bytes_read, | ||
494 | + buffer, sectorsize); | ||
495 | + if (ret) { | ||
496 | + fprintf(stderr, "%s checksum failed\n", path_name); | ||
497 | + goto end; | ||
498 | + } | ||
499 | + | ||
500 | + bytes_read += ret_read; | ||
501 | + num_blocks++; | ||
502 | + } while (ret_read == sectorsize); | ||
503 | + | ||
504 | + if (num_blocks > 0) { | ||
505 | + ret = record_file_extent(trans, root, objectid, btrfs_inode, | ||
506 | + first_block, first_block, | ||
507 | + blocks * sectorsize); | ||
508 | + if (ret) | ||
509 | + goto end; | ||
510 | + } | ||
511 | + | ||
512 | +end: | ||
513 | + if (buffer) | ||
514 | + free(buffer); | ||
515 | + close(fd); | ||
516 | + return ret; | ||
517 | +} | ||
518 | + | ||
519 | +static char *make_path(char *dir, char *name) | ||
520 | +{ | ||
521 | + char *path; | ||
522 | + | ||
523 | + path = malloc(strlen(dir) + strlen(name) + 2); | ||
524 | + if (!path) | ||
525 | + return NULL; | ||
526 | + strcpy(path, dir); | ||
527 | + if (dir[strlen(dir) - 1] != '/') | ||
528 | + strcat(path, "/"); | ||
529 | + strcat(path, name); | ||
530 | + return path; | ||
531 | +} | ||
532 | + | ||
533 | +static int traverse_directory(struct btrfs_trans_handle *trans, | ||
534 | + struct btrfs_root *root, char *dir_name, | ||
535 | + struct directory_name_entry *dir_head, int out_fd) | ||
536 | +{ | ||
537 | + int ret = 0; | ||
538 | + | ||
539 | + struct btrfs_inode_item cur_inode; | ||
540 | + struct btrfs_inode_item *inode_item; | ||
541 | + int count, i, dir_index_cnt; | ||
542 | + struct direct **files; | ||
543 | + struct stat st; | ||
544 | + struct directory_name_entry *dir_entry, *parent_dir_entry; | ||
545 | + struct direct *cur_file; | ||
546 | + ino_t parent_inum, cur_inum; | ||
547 | + ino_t highest_inum = 0; | ||
548 | + char *parent_dir_name; | ||
549 | + struct btrfs_path path; | ||
550 | + struct extent_buffer *leaf; | ||
551 | + struct btrfs_key root_dir_key; | ||
552 | + u64 root_dir_inode_size = 0; | ||
553 | + | ||
554 | + /* Add list for source directory */ | ||
555 | + dir_entry = malloc(sizeof(struct directory_name_entry)); | ||
556 | + dir_entry->dir_name = dir_name; | ||
557 | + dir_entry->path = malloc(strlen(dir_name) + 1); | ||
558 | + strcpy(dir_entry->path, dir_name); | ||
559 | + | ||
560 | + parent_inum = highest_inum + BTRFS_FIRST_FREE_OBJECTID; | ||
561 | + dir_entry->inum = parent_inum; | ||
562 | + list_add_tail(&dir_entry->list, &dir_head->list); | ||
563 | + | ||
564 | + btrfs_init_path(&path); | ||
565 | + | ||
566 | + root_dir_key.objectid = btrfs_root_dirid(&root->root_item); | ||
567 | + root_dir_key.offset = 0; | ||
568 | + btrfs_set_key_type(&root_dir_key, BTRFS_INODE_ITEM_KEY); | ||
569 | + ret = btrfs_lookup_inode(trans, root, &path, &root_dir_key, 1); | ||
570 | + if (ret) { | ||
571 | + fprintf(stderr, "root dir lookup error\n"); | ||
572 | + goto fail; | ||
573 | + } | ||
574 | + | ||
575 | + leaf = path.nodes[0]; | ||
576 | + inode_item = btrfs_item_ptr(leaf, path.slots[0], | ||
577 | + struct btrfs_inode_item); | ||
578 | + | ||
579 | + root_dir_inode_size = calculate_dir_inode_size(dir_name); | ||
580 | + btrfs_set_inode_size(leaf, inode_item, root_dir_inode_size); | ||
581 | + btrfs_mark_buffer_dirty(leaf); | ||
582 | + | ||
583 | + btrfs_release_path(root, &path); | ||
584 | + | ||
585 | + do { | ||
586 | + parent_dir_entry = list_entry(dir_head->list.next, | ||
587 | + struct directory_name_entry, | ||
588 | + list); | ||
589 | + list_del(&parent_dir_entry->list); | ||
590 | + | ||
591 | + parent_inum = parent_dir_entry->inum; | ||
592 | + parent_dir_name = parent_dir_entry->dir_name; | ||
593 | + if (chdir(parent_dir_entry->path)) { | ||
594 | + fprintf(stderr, "chdir error for %s\n", | ||
595 | + parent_dir_name); | ||
596 | + goto fail; | ||
597 | + } | ||
598 | + | ||
599 | + count = scandir(parent_dir_entry->path, &files, | ||
600 | + directory_select, NULL); | ||
601 | + | ||
602 | + for (i = 0; i < count; i++) { | ||
603 | + cur_file = files[i]; | ||
604 | + | ||
605 | + if (lstat(cur_file->d_name, &st) == -1) { | ||
606 | + fprintf(stderr, "lstat failed for file %s\n", | ||
607 | + cur_file->d_name); | ||
608 | + goto fail; | ||
609 | + } | ||
610 | + | ||
611 | + cur_inum = ++highest_inum + BTRFS_FIRST_FREE_OBJECTID; | ||
612 | + ret = add_directory_items(trans, root, | ||
613 | + cur_inum, parent_inum, | ||
614 | + cur_file->d_name, | ||
615 | + &st, &dir_index_cnt); | ||
616 | + if (ret) { | ||
617 | + fprintf(stderr, "add_directory_items failed\n"); | ||
618 | + goto fail; | ||
619 | + } | ||
620 | + | ||
621 | + ret = add_inode_items(trans, root, &st, | ||
622 | + cur_file->d_name, cur_inum, | ||
623 | + parent_inum, dir_index_cnt, | ||
624 | + &cur_inode); | ||
625 | + if (ret) { | ||
626 | + fprintf(stderr, "add_inode_items failed\n"); | ||
627 | + goto fail; | ||
628 | + } | ||
629 | + | ||
630 | + ret = add_xattr_item(trans, root, | ||
631 | + cur_inum, cur_file->d_name); | ||
632 | + if (ret) { | ||
633 | + fprintf(stderr, "add_xattr_item failed\n"); | ||
634 | + goto fail; | ||
635 | + } | ||
636 | + | ||
637 | + if (S_ISDIR(st.st_mode)) { | ||
638 | + dir_entry = malloc(sizeof(struct directory_name_entry)); | ||
639 | + dir_entry->dir_name = cur_file->d_name; | ||
640 | + dir_entry->path = make_path(parent_dir_entry->path, | ||
641 | + cur_file->d_name); | ||
642 | + dir_entry->inum = cur_inum; | ||
643 | + list_add_tail(&dir_entry->list, &dir_head->list); | ||
644 | + } else if (S_ISREG(st.st_mode)) { | ||
645 | + ret = add_file_items(trans, root, &cur_inode, | ||
646 | + cur_inum, parent_inum, &st, | ||
647 | + cur_file->d_name, out_fd); | ||
648 | + if (ret) { | ||
649 | + fprintf(stderr, "add_file_items failed\n"); | ||
650 | + goto fail; | ||
651 | + } | ||
652 | + } else if (S_ISLNK(st.st_mode)) { | ||
653 | + ret = add_symbolic_link(trans, root, | ||
654 | + cur_inum, cur_file->d_name); | ||
655 | + if (ret) { | ||
656 | + fprintf(stderr, "add_symbolic_link failed\n"); | ||
657 | + goto fail; | ||
658 | + } | ||
659 | + } | ||
660 | + } | ||
661 | + | ||
662 | + free(parent_dir_entry->path); | ||
663 | + free(parent_dir_entry); | ||
664 | + | ||
665 | + index_cnt = 2; | ||
666 | + | ||
667 | + } while (!list_empty(&dir_head->list)); | ||
668 | + | ||
669 | + return 0; | ||
670 | +fail: | ||
671 | + free(parent_dir_entry->path); | ||
672 | + free(parent_dir_entry); | ||
673 | + return -1; | ||
674 | +} | ||
675 | + | ||
676 | +static int open_target(char *output_name) | ||
677 | +{ | ||
678 | + int output_fd; | ||
679 | + output_fd = open(output_name, O_CREAT | O_RDWR | O_TRUNC, | ||
680 | + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); | ||
681 | + | ||
682 | + return output_fd; | ||
683 | +} | ||
684 | + | ||
685 | +static int create_chunks(struct btrfs_trans_handle *trans, | ||
686 | + struct btrfs_root *root, u64 num_of_meta_chunks, | ||
687 | + u64 size_of_data) | ||
688 | +{ | ||
689 | + u64 chunk_start; | ||
690 | + u64 chunk_size; | ||
691 | + u64 meta_type = BTRFS_BLOCK_GROUP_METADATA; | ||
692 | + u64 data_type = BTRFS_BLOCK_GROUP_DATA; | ||
693 | + u64 minimum_data_chunk_size = 64 * 1024 * 1024; | ||
694 | + u64 i; | ||
695 | + int ret; | ||
696 | + | ||
697 | + for (i = 0; i < num_of_meta_chunks; i++) { | ||
698 | + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, | ||
699 | + &chunk_start, &chunk_size, meta_type); | ||
700 | + BUG_ON(ret); | ||
701 | + ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0, | ||
702 | + meta_type, BTRFS_FIRST_CHUNK_TREE_OBJECTID, | ||
703 | + chunk_start, chunk_size); | ||
704 | + BUG_ON(ret); | ||
705 | + set_extent_dirty(&root->fs_info->free_space_cache, | ||
706 | + chunk_start, chunk_start + chunk_size - 1, 0); | ||
707 | + } | ||
708 | + | ||
709 | + if (size_of_data < minimum_data_chunk_size) | ||
710 | + size_of_data = minimum_data_chunk_size; | ||
711 | + ret = btrfs_alloc_data_chunk(trans, root->fs_info->extent_root, | ||
712 | + &chunk_start, size_of_data, data_type); | ||
713 | + BUG_ON(ret); | ||
714 | + ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0, | ||
715 | + data_type, BTRFS_FIRST_CHUNK_TREE_OBJECTID, | ||
716 | + chunk_start, size_of_data); | ||
717 | + BUG_ON(ret); | ||
718 | + set_extent_dirty(&root->fs_info->free_space_cache, | ||
719 | + chunk_start, chunk_start + size_of_data - 1, 0); | ||
720 | + return ret; | ||
721 | +} | ||
722 | + | ||
723 | +static int make_image(char *source_dir, struct btrfs_root *root, int out_fd) | ||
724 | +{ | ||
725 | + int ret; | ||
726 | + struct btrfs_trans_handle *trans; | ||
727 | + | ||
728 | + struct stat root_st; | ||
729 | + int root_len; | ||
730 | + | ||
731 | + struct directory_name_entry dir_head; | ||
732 | + | ||
733 | + ret = lstat(source_dir, &root_st); | ||
734 | + if (ret) { | ||
735 | + fprintf(stderr, "unable to lstat the %s\n", source_dir); | ||
736 | + goto fail; | ||
737 | + } | ||
738 | + | ||
739 | + root_len = strlen(source_dir); | ||
740 | + | ||
741 | + INIT_LIST_HEAD(&dir_head.list); | ||
742 | + | ||
743 | + trans = btrfs_start_transaction(root, 1); | ||
744 | + ret = traverse_directory(trans, root, source_dir, &dir_head, out_fd); | ||
745 | + if (ret) { | ||
746 | + fprintf(stderr, "unable to traverse_directory\n"); | ||
747 | + goto fail; | ||
748 | + } | ||
749 | + btrfs_commit_transaction(trans, root); | ||
750 | + | ||
751 | + printf("Making image is completed.\n"); | ||
752 | + return 0; | ||
753 | +fail: | ||
754 | + fprintf(stderr, "Making image is aborted.\n"); | ||
755 | + return -1; | ||
756 | +} | ||
757 | + | ||
758 | +static u64 size_sourcedir(char *dir_name, u64 sectorsize, | ||
759 | + u64 *num_of_meta_chunks_ret, u64 *size_of_data_ret) | ||
760 | +{ | ||
761 | + u64 dir_size = 0; | ||
762 | + u64 total_size = 0; | ||
763 | + int ret; | ||
764 | + char command[1024]; | ||
765 | + char path[512]; | ||
766 | + char *file_name = "temp_file"; | ||
767 | + FILE *file; | ||
768 | + u64 minimum_data_size = 256 * 1024 * 1024; /* 256MB */ | ||
769 | + u64 default_chunk_size = 8 * 1024 * 1024; /* 8MB */ | ||
770 | + u64 allocated_meta_size = 8 * 1024 * 1024; /* 8MB */ | ||
771 | + u64 allocated_total_size = 20 * 1024 * 1024; /* 20MB */ | ||
772 | + u64 num_of_meta_chunks = 0; | ||
773 | + u64 num_of_allocated_meta_chunks = | ||
774 | + allocated_meta_size / default_chunk_size; | ||
775 | + | ||
776 | + ret = sprintf(command, "du -B 4096 -s "); | ||
777 | + if (ret < 0) { | ||
778 | + fprintf(stderr, "error executing sprintf for du command\n"); | ||
779 | + return -1; | ||
780 | + } | ||
781 | + strcat(command, dir_name); | ||
782 | + strcat(command, " > "); | ||
783 | + strcat(command, file_name); | ||
784 | + ret = system(command); | ||
785 | + | ||
786 | + file = fopen(file_name, "r"); | ||
787 | + ret = fscanf(file, "%lld %s\n", &dir_size, path); | ||
788 | + fclose(file); | ||
789 | + remove(file_name); | ||
790 | + | ||
791 | + dir_size *= sectorsize; | ||
792 | + *size_of_data_ret = dir_size; | ||
793 | + | ||
794 | + num_of_meta_chunks = (dir_size / 2) / default_chunk_size; | ||
795 | + if (((dir_size / 2) % default_chunk_size) != 0) | ||
796 | + num_of_meta_chunks++; | ||
797 | + if (num_of_meta_chunks <= num_of_allocated_meta_chunks) | ||
798 | + num_of_meta_chunks = 0; | ||
799 | + else | ||
800 | + num_of_meta_chunks -= num_of_allocated_meta_chunks; | ||
801 | + | ||
802 | + total_size = allocated_total_size + dir_size + | ||
803 | + (num_of_meta_chunks * default_chunk_size); | ||
804 | + | ||
805 | + *num_of_meta_chunks_ret = num_of_meta_chunks; | ||
806 | + | ||
807 | + if (total_size < minimum_data_size) | ||
808 | + total_size = minimum_data_size; | ||
809 | + | ||
810 | + return total_size; | ||
811 | +} | ||
812 | + | ||
813 | +static int zero_output_file(int out_fd, u64 size, u32 sectorsize) | ||
814 | +{ | ||
815 | + int len = sectorsize; | ||
816 | + int loop_num = size / sectorsize; | ||
817 | + u64 location = 0; | ||
818 | + char *buf = malloc(len); | ||
819 | + int ret = 0, i; | ||
820 | + ssize_t written; | ||
821 | + | ||
822 | + if (!buf) | ||
823 | + return -ENOMEM; | ||
824 | + memset(buf, 0, len); | ||
825 | + for (i = 0; i < loop_num; i++) { | ||
826 | + written = pwrite64(out_fd, buf, len, location); | ||
827 | + if (written != len) | ||
828 | + ret = -EIO; | ||
829 | + location += sectorsize; | ||
830 | + } | ||
831 | + free(buf); | ||
832 | + return ret; | ||
833 | +} | ||
834 | + | ||
835 | int main(int ac, char **av) | ||
836 | { | ||
837 | char *file; | ||
838 | @@ -385,9 +1156,15 @@ int main(int ac, char **av) | ||
839 | int data_profile_opt = 0; | ||
840 | int metadata_profile_opt = 0; | ||
841 | |||
842 | + char *source_dir = NULL; | ||
843 | + int source_dir_set = 0; | ||
844 | + char *output = "output.img"; | ||
845 | + u64 num_of_meta_chunks = 0; | ||
846 | + u64 size_of_data = 0; | ||
847 | + | ||
848 | while(1) { | ||
849 | int c; | ||
850 | - c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:VM", long_options, | ||
851 | + c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VM", long_options, | ||
852 | &option_index); | ||
853 | if (c < 0) | ||
854 | break; | ||
855 | @@ -430,6 +1207,10 @@ int main(int ac, char **av) | ||
856 | case 'V': | ||
857 | print_version(); | ||
858 | break; | ||
859 | + case 'r': | ||
860 | + source_dir = optarg; | ||
861 | + source_dir_set = 1; | ||
862 | + break; | ||
863 | default: | ||
864 | print_usage(); | ||
865 | } | ||
866 | @@ -443,6 +1224,8 @@ int main(int ac, char **av) | ||
867 | fprintf(stderr, "Illegal nodesize %u\n", nodesize); | ||
868 | exit(1); | ||
869 | } | ||
870 | + if (source_dir_set) | ||
871 | + ac++; | ||
872 | ac = ac - optind; | ||
873 | if (ac == 0) | ||
874 | print_usage(); | ||
875 | @@ -450,28 +1233,47 @@ int main(int ac, char **av) | ||
876 | printf("\nWARNING! - %s IS EXPERIMENTAL\n", BTRFS_BUILD_VERSION); | ||
877 | printf("WARNING! - see http://btrfs.wiki.kernel.org before using\n\n"); | ||
878 | |||
879 | - file = av[optind++]; | ||
880 | - ret = check_mounted(file); | ||
881 | - if (ret < 0) { | ||
882 | - fprintf(stderr, "error checking %s mount status\n", file); | ||
883 | - exit(1); | ||
884 | - } | ||
885 | - if (ret == 1) { | ||
886 | - fprintf(stderr, "%s is mounted\n", file); | ||
887 | - exit(1); | ||
888 | - } | ||
889 | - ac--; | ||
890 | - fd = open(file, O_RDWR); | ||
891 | - if (fd < 0) { | ||
892 | - fprintf(stderr, "unable to open %s\n", file); | ||
893 | - exit(1); | ||
894 | + if (source_dir == 0) { | ||
895 | + file = av[optind++]; | ||
896 | + ret = check_mounted(file); | ||
897 | + if (ret < 0) { | ||
898 | + fprintf(stderr, "error checking %s mount status\n", file); | ||
899 | + exit(1); | ||
900 | + } | ||
901 | + if (ret == 1) { | ||
902 | + fprintf(stderr, "%s is mounted\n", file); | ||
903 | + exit(1); | ||
904 | + } | ||
905 | + ac--; | ||
906 | + fd = open(file, O_RDWR); | ||
907 | + if (fd < 0) { | ||
908 | + fprintf(stderr, "unable to open %s\n", file); | ||
909 | + exit(1); | ||
910 | + } | ||
911 | + first_fd = fd; | ||
912 | + first_file = file; | ||
913 | + ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, &mixed); | ||
914 | + if (block_count == 0) | ||
915 | + block_count = dev_block_count; | ||
916 | + } else { | ||
917 | + ac = 0; | ||
918 | + fd = open_target(output); | ||
919 | + if (fd < 0) { | ||
920 | + fprintf(stderr, "unable to open the %s\n", file); | ||
921 | + exit(1); | ||
922 | + } | ||
923 | + | ||
924 | + file = output; | ||
925 | + first_fd = fd; | ||
926 | + first_file = file; | ||
927 | + block_count = size_sourcedir(source_dir, sectorsize, | ||
928 | + &num_of_meta_chunks, &size_of_data); | ||
929 | + ret = zero_output_file(fd, block_count, sectorsize); | ||
930 | + if (ret) { | ||
931 | + fprintf(stderr, "unable to zero the output file\n"); | ||
932 | + exit(1); | ||
933 | + } | ||
934 | } | ||
935 | - first_fd = fd; | ||
936 | - first_file = file; | ||
937 | - ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, | ||
938 | - &mixed); | ||
939 | - if (block_count == 0) | ||
940 | - block_count = dev_block_count; | ||
941 | if (mixed) { | ||
942 | if (!metadata_profile_opt) | ||
943 | metadata_profile = 0; | ||
944 | @@ -558,9 +1360,11 @@ int main(int ac, char **av) | ||
945 | } | ||
946 | |||
947 | raid_groups: | ||
948 | - ret = create_raid_groups(trans, root, data_profile, | ||
949 | + if (!source_dir_set) { | ||
950 | + ret = create_raid_groups(trans, root, data_profile, | ||
951 | metadata_profile, mixed); | ||
952 | - BUG_ON(ret); | ||
953 | + BUG_ON(ret); | ||
954 | + } | ||
955 | |||
956 | ret = create_data_reloc_tree(trans, root); | ||
957 | BUG_ON(ret); | ||
958 | @@ -580,6 +1384,18 @@ raid_groups: | ||
959 | |||
960 | printf("%s\n", BTRFS_BUILD_VERSION); | ||
961 | btrfs_commit_transaction(trans, root); | ||
962 | + | ||
963 | + if (source_dir_set) { | ||
964 | + trans = btrfs_start_transaction(root, 1); | ||
965 | + ret = create_chunks(trans, root, | ||
966 | + num_of_meta_chunks, size_of_data); | ||
967 | + BUG_ON(ret); | ||
968 | + btrfs_commit_transaction(trans, root); | ||
969 | + | ||
970 | + ret = make_image(source_dir, root, fd); | ||
971 | + BUG_ON(ret); | ||
972 | + } | ||
973 | + | ||
974 | ret = close_ctree(root); | ||
975 | BUG_ON(ret); | ||
976 | |||
977 | diff --git a/volumes.c b/volumes.c | ||
978 | index 7671855..4bb77e2 100644 | ||
979 | --- a/volumes.c | ||
980 | +++ b/volumes.c | ||
981 | @@ -857,6 +857,110 @@ again: | ||
982 | return ret; | ||
983 | } | ||
984 | |||
985 | +int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans, | ||
986 | + struct btrfs_root *extent_root, u64 *start, | ||
987 | + u64 num_bytes, u64 type) | ||
988 | +{ | ||
989 | + u64 dev_offset; | ||
990 | + struct btrfs_fs_info *info = extent_root->fs_info; | ||
991 | + struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; | ||
992 | + struct btrfs_stripe *stripes; | ||
993 | + struct btrfs_device *device = NULL; | ||
994 | + struct btrfs_chunk *chunk; | ||
995 | + struct list_head *dev_list = &extent_root->fs_info->fs_devices->devices; | ||
996 | + struct list_head *cur; | ||
997 | + struct map_lookup *map; | ||
998 | + u64 physical; | ||
999 | + u64 calc_size = 8 * 1024 * 1024; | ||
1000 | + int num_stripes = 1; | ||
1001 | + int sub_stripes = 0; | ||
1002 | + int ret; | ||
1003 | + int index; | ||
1004 | + int stripe_len = 64 * 1024; | ||
1005 | + struct btrfs_key key; | ||
1006 | + | ||
1007 | + key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; | ||
1008 | + key.type = BTRFS_CHUNK_ITEM_KEY; | ||
1009 | + ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, | ||
1010 | + &key.offset); | ||
1011 | + if (ret) | ||
1012 | + return ret; | ||
1013 | + | ||
1014 | + chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); | ||
1015 | + if (!chunk) | ||
1016 | + return -ENOMEM; | ||
1017 | + | ||
1018 | + map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); | ||
1019 | + if (!map) { | ||
1020 | + kfree(chunk); | ||
1021 | + return -ENOMEM; | ||
1022 | + } | ||
1023 | + | ||
1024 | + stripes = &chunk->stripe; | ||
1025 | + calc_size = num_bytes; | ||
1026 | + | ||
1027 | + index = 0; | ||
1028 | + cur = dev_list->next; | ||
1029 | + device = list_entry(cur, struct btrfs_device, dev_list); | ||
1030 | + | ||
1031 | + while (index < num_stripes) { | ||
1032 | + struct btrfs_stripe *stripe; | ||
1033 | + | ||
1034 | + ret = btrfs_alloc_dev_extent(trans, device, | ||
1035 | + info->chunk_root->root_key.objectid, | ||
1036 | + BTRFS_FIRST_CHUNK_TREE_OBJECTID, key.offset, | ||
1037 | + calc_size, &dev_offset); | ||
1038 | + BUG_ON(ret); | ||
1039 | + | ||
1040 | + device->bytes_used += calc_size; | ||
1041 | + ret = btrfs_update_device(trans, device); | ||
1042 | + BUG_ON(ret); | ||
1043 | + | ||
1044 | + map->stripes[index].dev = device; | ||
1045 | + map->stripes[index].physical = dev_offset; | ||
1046 | + stripe = stripes + index; | ||
1047 | + btrfs_set_stack_stripe_devid(stripe, device->devid); | ||
1048 | + btrfs_set_stack_stripe_offset(stripe, dev_offset); | ||
1049 | + memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); | ||
1050 | + physical = dev_offset; | ||
1051 | + index++; | ||
1052 | + } | ||
1053 | + | ||
1054 | + /* key was set above */ | ||
1055 | + btrfs_set_stack_chunk_length(chunk, num_bytes); | ||
1056 | + btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); | ||
1057 | + btrfs_set_stack_chunk_stripe_len(chunk, stripe_len); | ||
1058 | + btrfs_set_stack_chunk_type(chunk, type); | ||
1059 | + btrfs_set_stack_chunk_num_stripes(chunk, num_stripes); | ||
1060 | + btrfs_set_stack_chunk_io_align(chunk, stripe_len); | ||
1061 | + btrfs_set_stack_chunk_io_width(chunk, stripe_len); | ||
1062 | + btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); | ||
1063 | + btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes); | ||
1064 | + map->sector_size = extent_root->sectorsize; | ||
1065 | + map->stripe_len = stripe_len; | ||
1066 | + map->io_align = stripe_len; | ||
1067 | + map->io_width = stripe_len; | ||
1068 | + map->type = type; | ||
1069 | + map->num_stripes = num_stripes; | ||
1070 | + map->sub_stripes = sub_stripes; | ||
1071 | + | ||
1072 | + ret = btrfs_insert_item(trans, chunk_root, &key, chunk, | ||
1073 | + btrfs_chunk_item_size(num_stripes)); | ||
1074 | + BUG_ON(ret); | ||
1075 | + *start = key.offset; | ||
1076 | + | ||
1077 | + map->ce.start = key.offset; | ||
1078 | + map->ce.size = num_bytes; | ||
1079 | + | ||
1080 | + ret = insert_existing_cache_extent( | ||
1081 | + &extent_root->fs_info->mapping_tree.cache_tree, | ||
1082 | + &map->ce); | ||
1083 | + BUG_ON(ret); | ||
1084 | + | ||
1085 | + kfree(chunk); | ||
1086 | + return ret; | ||
1087 | +} | ||
1088 | + | ||
1089 | void btrfs_mapping_init(struct btrfs_mapping_tree *tree) | ||
1090 | { | ||
1091 | cache_tree_init(&tree->cache_tree); | ||
1092 | diff --git a/volumes.h b/volumes.h | ||
1093 | index bb78751..93b0e48 100644 | ||
1094 | --- a/volumes.h | ||
1095 | +++ b/volumes.h | ||
1096 | @@ -107,6 +107,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root); | ||
1097 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | ||
1098 | struct btrfs_root *extent_root, u64 *start, | ||
1099 | u64 *num_bytes, u64 type); | ||
1100 | +int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans, | ||
1101 | + struct btrfs_root *extent_root, u64 *start, | ||
1102 | + u64 num_bytes, u64 type); | ||
1103 | int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); | ||
1104 | int btrfs_add_device(struct btrfs_trans_handle *trans, | ||
1105 | struct btrfs_root *root, | ||
1106 | -- | ||
1107 | 1.7.2.3 | ||
1108 | |||