Btrfs image tool
[platform/upstream/btrfs-progs.git] / btrfs-image.c
1 /*
2  * Copyright (C) 2008 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #define _XOPEN_SOURCE 500
20 #define _GNU_SOURCE 1
21 #include <pthread.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <zlib.h>
30 #include "kerncompat.h"
31 #include "crc32c.h"
32 #include "ctree.h"
33 #include "disk-io.h"
34 #include "transaction.h"
35 #include "utils.h"
36 #include "version.h"
37
38
39 #define HEADER_MAGIC            0xbd5c25e27295668bULL
40 #define MAX_PENDING_SIZE        (256 * 1024)
41 #define BLOCK_SIZE              1024
42 #define BLOCK_MASK              (BLOCK_SIZE - 1)
43
44 #define COMPRESS_NONE           0
45 #define COMPRESS_ZLIB           1
46
47 struct meta_cluster_item {
48         __le64 bytenr;
49         __le32 size;
50 } __attribute__ ((__packed__));
51
52 struct meta_cluster_header {
53         __le64 magic;
54         __le64 bytenr;
55         __le32 nritems;
56         u8 compress;
57 } __attribute__ ((__packed__));
58
59 /* cluster header + index items + buffers */
60 struct meta_cluster {
61         struct meta_cluster_header header;
62         struct meta_cluster_item items[];
63 } __attribute__ ((__packed__));
64
65 #define ITEMS_PER_CLUSTER ((BLOCK_SIZE - sizeof(struct meta_cluster)) / \
66                            sizeof(struct meta_cluster_item))
67
68 struct async_work {
69         struct list_head list;
70         struct list_head ordered;
71         u64 start;
72         u64 size;
73         u8 *buffer;
74         size_t bufsize;
75 };
76
77 struct metadump_struct {
78         struct btrfs_root *root;
79         FILE *out;
80
81         struct meta_cluster *cluster;
82
83         pthread_t *threads;
84         size_t num_threads;
85         pthread_mutex_t mutex;
86         pthread_cond_t cond;
87
88         struct list_head list;
89         struct list_head ordered;
90         size_t num_items;
91         size_t num_ready;
92
93         u64 pending_start;
94         u64 pending_size;
95
96         int compress_level;
97         int done;
98 };
99
100 struct mdrestore_struct {
101         FILE *in;
102         FILE *out;
103
104         pthread_t *threads;
105         size_t num_threads;
106         pthread_mutex_t mutex;
107         pthread_cond_t cond;
108
109         struct list_head list;
110         size_t num_items;
111
112         int compress_method;
113         int done;
114 };
115
116 static void csum_block(u8 *buf, size_t len)
117 {
118         char result[BTRFS_CRC32_SIZE];
119         u32 crc = ~(u32)0;
120         crc = crc32c(crc, buf + BTRFS_CSUM_SIZE, len - BTRFS_CSUM_SIZE);
121         btrfs_csum_final(crc, result);
122         memcpy(buf, result, BTRFS_CRC32_SIZE);
123 }
124
125 /*
126  * zero inline extents and csum items
127  */
128 static void zero_items(u8 *dst, struct extent_buffer *src)
129 {
130         struct btrfs_file_extent_item *fi;
131         struct btrfs_item *item;
132         struct btrfs_key key;
133         u32 nritems = btrfs_header_nritems(src);
134         size_t size;
135         unsigned long ptr;
136         int i, extent_type;
137
138         for (i = 0; i < nritems; i++) {
139                 item = btrfs_item_nr(src, i);
140                 btrfs_item_key_to_cpu(src, &key, i);
141                 if (key.type == BTRFS_CSUM_ITEM_KEY) {
142                         size = btrfs_item_size_nr(src, i);
143                         memset(dst + btrfs_leaf_data(src) +
144                                btrfs_item_offset_nr(src, i), 0, size);
145                         continue;
146                 }
147                 if (key.type != BTRFS_EXTENT_DATA_KEY)
148                         continue;
149
150                 fi = btrfs_item_ptr(src, i, struct btrfs_file_extent_item);
151                 extent_type = btrfs_file_extent_type(src, fi);
152                 if (extent_type != BTRFS_FILE_EXTENT_INLINE)
153                         continue;
154
155                 ptr = btrfs_file_extent_inline_start(fi);
156                 size = btrfs_file_extent_inline_item_len(src, item);
157                 memset(dst + ptr, 0, size);
158         }
159 }
160
161 /*
162  * copy buffer and zero useless data in the buffer
163  */
164 static void copy_buffer(u8 *dst, struct extent_buffer *src)
165 {
166         int level;
167         size_t size;
168         u32 nritems;
169
170         memcpy(dst, src->data, src->len);
171         if (src->start == BTRFS_SUPER_INFO_OFFSET)
172                 return;
173
174         level = btrfs_header_level(src);
175         nritems = btrfs_header_nritems(src);
176
177         if (nritems == 0) {
178                 size = sizeof(struct btrfs_header);
179                 memset(dst + size, 0, src->len - size);
180         } else if (level == 0) {
181                 size = btrfs_leaf_data(src) +
182                         btrfs_item_offset_nr(src, nritems - 1) -
183                         btrfs_item_nr_offset(nritems);
184                 memset(dst + btrfs_item_nr_offset(nritems), 0, size);
185                 zero_items(dst, src);
186         } else {
187                 size = offsetof(struct btrfs_node, ptrs) +
188                         sizeof(struct btrfs_key_ptr) * nritems;
189                 memset(dst + size, 0, src->len - size);
190         }
191         csum_block(dst, src->len);
192 }
193
194 static void *dump_worker(void *data)
195 {
196         struct metadump_struct *md = (struct metadump_struct *)data;
197         struct async_work *async;
198         int ret;
199
200         while (1) {
201                 pthread_mutex_lock(&md->mutex);
202                 while (list_empty(&md->list)) {
203                         if (md->done) {
204                                 pthread_mutex_unlock(&md->mutex);
205                                 goto out;
206                         }
207                         pthread_cond_wait(&md->cond, &md->mutex);
208                 }
209                 async = list_entry(md->list.next, struct async_work, list);
210                 list_del_init(&async->list);
211                 pthread_mutex_unlock(&md->mutex);
212
213                 if (md->compress_level > 0) {
214                         u8 *orig = async->buffer;
215
216                         async->bufsize = compressBound(async->size);
217                         async->buffer = malloc(async->bufsize);
218
219                         ret = compress2(async->buffer, &async->bufsize, orig,
220                                         async->size, md->compress_level);
221                         BUG_ON(ret != Z_OK);
222
223                         free(orig);
224                 }
225
226                 pthread_mutex_lock(&md->mutex);
227                 md->num_ready++;
228                 pthread_mutex_unlock(&md->mutex);
229         }
230 out:
231         pthread_exit(NULL);
232 }
233
234 static void meta_cluster_init(struct metadump_struct *md, u64 start)
235 {
236         struct meta_cluster_header *header;
237
238         md->num_items = 0;
239         md->num_ready = 0;
240         header = &md->cluster->header;
241         header->magic = cpu_to_le64(HEADER_MAGIC);
242         header->bytenr = cpu_to_le64(start);
243         header->nritems = cpu_to_le32(0);
244         header->compress = md->compress_level > 0 ?
245                            COMPRESS_ZLIB : COMPRESS_NONE;
246 }
247
248 static int metadump_init(struct metadump_struct *md, struct btrfs_root *root,
249                          FILE *out, int num_threads, int compress_level)
250 {
251         int i, ret;
252
253         memset(md, 0, sizeof(*md));
254         pthread_cond_init(&md->cond, NULL);
255         pthread_mutex_init(&md->mutex, NULL);
256         INIT_LIST_HEAD(&md->list);
257         INIT_LIST_HEAD(&md->ordered);
258         md->root = root;
259         md->out = out;
260         md->pending_start = (u64)-1;
261         md->compress_level = compress_level;
262         md->cluster = calloc(1, BLOCK_SIZE);
263         if (!md->cluster)
264                 return -ENOMEM;
265
266         meta_cluster_init(md, 0);
267         if (!num_threads)
268                 return 0;
269
270         md->num_threads = num_threads;
271         md->threads = calloc(num_threads, sizeof(pthread_t));
272         if (!md->threads)
273                 return -ENOMEM;
274         for (i = 0; i < num_threads; i++) {
275                 ret = pthread_create(md->threads + i, NULL, dump_worker, md);
276                 if (ret)
277                         break;
278         }
279         return ret;
280 }
281
282 static void metadump_destroy(struct metadump_struct *md)
283 {
284         int i;
285         pthread_mutex_lock(&md->mutex);
286         md->done = 1;
287         pthread_cond_broadcast(&md->cond);
288         pthread_mutex_unlock(&md->mutex);
289
290         for (i = 0; i < md->num_threads; i++)
291                 pthread_join(md->threads[i], NULL);
292
293         pthread_cond_destroy(&md->cond);
294         pthread_mutex_destroy(&md->mutex);
295         free(md->threads);
296         free(md->cluster);
297 }
298
299 static int write_zero(FILE *out, size_t size)
300 {
301         static char zero[BLOCK_SIZE];
302         return fwrite(zero, size, 1, out);
303 }
304
305 static int write_buffers(struct metadump_struct *md, u64 *next)
306 {
307         struct meta_cluster_header *header = &md->cluster->header;
308         struct meta_cluster_item *item;
309         struct async_work *async;
310         u64 bytenr = 0;
311         u32 nritems = 0;
312         int ret;
313
314         if (list_empty(&md->ordered))
315                 goto out;
316
317         /* wait until all buffers are compressed */
318         while (md->num_items > md->num_ready) {
319                 struct timespec ts = {
320                         .tv_sec = 0,
321                         .tv_nsec = 10000000,
322                 };
323                 pthread_mutex_unlock(&md->mutex);
324                 nanosleep(&ts, NULL);
325                 pthread_mutex_lock(&md->mutex);
326         }
327
328         /* setup and write index block */
329         list_for_each_entry(async, &md->ordered, ordered) {
330                 item = md->cluster->items + nritems;
331                 item->bytenr = cpu_to_le64(async->start);
332                 item->size = cpu_to_le32(async->bufsize);
333                 nritems++;
334         }
335         header->nritems = cpu_to_le32(nritems);
336
337         ret = fwrite(md->cluster, BLOCK_SIZE, 1, md->out);
338         BUG_ON(ret != 1);
339
340         /* write buffers */
341         bytenr += le64_to_cpu(header->bytenr) + BLOCK_SIZE;
342         while (!list_empty(&md->ordered)) {
343                 async = list_entry(md->ordered.next, struct async_work,
344                                    ordered);
345                 list_del_init(&async->ordered);
346
347                 bytenr += async->bufsize;
348                 ret = fwrite(async->buffer, async->bufsize, 1, md->out);
349                 BUG_ON(ret != 1);
350
351                 free(async->buffer);
352                 free(async);
353         }
354
355         /* zero unused space in the last block */
356         if (bytenr & BLOCK_MASK) {
357                 size_t size = BLOCK_SIZE - (bytenr & BLOCK_MASK);
358
359                 bytenr += size;
360                 ret = write_zero(md->out, size);
361                 BUG_ON(ret != 1);
362         }
363 out:
364         *next = bytenr;
365         return 0;
366 }
367
368 static int flush_pending(struct metadump_struct *md, int done)
369 {
370         struct async_work *async = NULL;
371         struct extent_buffer *eb;
372         u64 blocksize = md->root->nodesize;
373         u64 start;
374         u64 size;
375         size_t offset;
376         int ret;
377
378         if (md->pending_size) {
379                 async = calloc(1, sizeof(*async));
380                 if (!async)
381                         return -ENOMEM;
382
383                 async->start = md->pending_start;
384                 async->size = md->pending_size;
385                 async->bufsize = async->size;
386                 async->buffer = malloc(async->bufsize);
387
388                 offset = 0;
389                 start = async->start;
390                 size = async->size;
391                 while (size > 0) {
392                         eb = read_tree_block(md->root, start, blocksize, 0);
393                         BUG_ON(!eb);
394                         copy_buffer(async->buffer + offset, eb);
395                         free_extent_buffer(eb);
396                         start += blocksize;
397                         offset += blocksize;
398                         size -= blocksize;
399                 }
400
401                 md->pending_start = (u64)-1;
402                 md->pending_size = 0;
403         } else if (!done) {
404                 return 0;
405         }
406
407         pthread_mutex_lock(&md->mutex);
408         if (async) {
409                 list_add_tail(&async->ordered, &md->ordered);
410                 md->num_items++;
411                 if (md->compress_level > 0) {
412                         list_add_tail(&async->list, &md->list);
413                         pthread_cond_signal(&md->cond);
414                 } else {
415                         md->num_ready++;
416                 }
417         }
418         if (md->num_items >= ITEMS_PER_CLUSTER || done) {
419                 ret = write_buffers(md, &start);
420                 BUG_ON(ret);
421                 meta_cluster_init(md, start);
422         }
423         pthread_mutex_unlock(&md->mutex);
424         return 0;
425 }
426
427 static int add_metadata(u64 start, u64 size, struct metadump_struct *md)
428 {
429         int ret;
430         if (md->pending_size + size > MAX_PENDING_SIZE ||
431             md->pending_start + md->pending_size != start) {
432                 ret = flush_pending(md, 0);
433                 if (ret)
434                         return ret;
435                 md->pending_start = start;
436         }
437         readahead_tree_block(md->root, start, size, 0);
438         md->pending_size += size;
439         return 0;
440 }
441
442 static int create_metadump(const char *input, FILE *out, int num_threads,
443                            int compress_level)
444 {
445         struct btrfs_root *root;
446         struct btrfs_root *extent_root;
447         struct btrfs_path *path;
448         struct extent_buffer *leaf;
449         struct btrfs_extent_ref *ref_item;
450         struct btrfs_key key;
451         struct metadump_struct metadump;
452         u64 bytenr;
453         u64 num_bytes;
454         u64 ref_objectid;
455         int ret;
456
457         root = open_ctree(input, 0, 0);
458         BUG_ON(root->nodesize != root->leafsize);
459
460         ret = metadump_init(&metadump, root, out, num_threads,
461                             compress_level);
462         BUG_ON(ret);
463
464         ret = add_metadata(BTRFS_SUPER_INFO_OFFSET, 4096, &metadump);
465         BUG_ON(ret);
466
467         extent_root = root->fs_info->extent_root;
468         path = btrfs_alloc_path();
469
470         bytenr = BTRFS_SUPER_INFO_OFFSET + 4096;
471         key.objectid = bytenr;
472         key.type = BTRFS_EXTENT_ITEM_KEY;
473         key.offset = 0;
474
475         ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
476         BUG_ON(ret < 0);
477
478         while (1) {
479                 leaf = path->nodes[0];
480                 if (path->slots[0] >= btrfs_header_nritems(leaf)) {
481                         ret = btrfs_next_leaf(extent_root, path);
482                         BUG_ON(ret < 0);
483                         if (ret > 0)
484                                 break;
485                         leaf = path->nodes[0];
486                 }
487
488                 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
489                 if (key.objectid < bytenr ||
490                     key.type != BTRFS_EXTENT_ITEM_KEY) {
491                         path->slots[0]++;
492                         continue;
493                 }
494
495                 bytenr = key.objectid;
496                 num_bytes = key.offset;
497                 while (1) {
498                         path->slots[0]++;
499                         if (path->slots[0] >= btrfs_header_nritems(leaf)) {
500                                 ret = btrfs_next_leaf(extent_root, path);
501                                 BUG_ON(ret < 0);
502                                 if (ret > 0)
503                                         break;
504                                 leaf = path->nodes[0];
505                         }
506                         btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
507                         if (key.objectid != bytenr)
508                                 break;
509                         if (key.type != BTRFS_EXTENT_REF_KEY)
510                                 continue;
511                         ref_item = btrfs_item_ptr(leaf, path->slots[0],
512                                                   struct btrfs_extent_ref);
513                         ref_objectid = btrfs_ref_objectid(leaf, ref_item);
514                         if (ref_objectid < BTRFS_FIRST_FREE_OBJECTID) {
515                                 ret = add_metadata(bytenr, num_bytes,
516                                                    &metadump);
517                                 BUG_ON(ret);
518                                 break;
519                         }
520                 }
521                 bytenr += num_bytes;
522         }
523
524         ret = flush_pending(&metadump, 1);
525         BUG_ON(ret);
526
527         metadump_destroy(&metadump);
528
529         btrfs_free_path(path);
530         ret = close_ctree(root);
531         return 0;
532 }
533
534 static void update_super(u8 *buffer)
535 {
536         struct btrfs_super_block *super = (struct btrfs_super_block *)buffer;
537         struct btrfs_chunk *chunk;
538         struct btrfs_disk_key *key;
539         u32 sectorsize = btrfs_super_sectorsize(super);
540         u64 flags = btrfs_super_flags(super);
541
542         flags |= BTRFS_SUPER_FLAG_METADUMP;
543         btrfs_set_super_flags(super, flags);
544
545         key = (struct btrfs_disk_key *)(super->sys_chunk_array);
546         chunk = (struct btrfs_chunk *)(super->sys_chunk_array +
547                                        sizeof(struct btrfs_disk_key));
548
549         btrfs_set_disk_key_objectid(key, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
550         btrfs_set_disk_key_type(key, BTRFS_CHUNK_ITEM_KEY);
551         btrfs_set_disk_key_offset(key, 0);
552
553         btrfs_set_stack_chunk_length(chunk, (u64)-1);
554         btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID);
555         btrfs_set_stack_chunk_stripe_len(chunk, 64 * 1024);
556         btrfs_set_stack_chunk_type(chunk, BTRFS_BLOCK_GROUP_SYSTEM);
557         btrfs_set_stack_chunk_io_align(chunk, sectorsize);
558         btrfs_set_stack_chunk_io_width(chunk, sectorsize);
559         btrfs_set_stack_chunk_sector_size(chunk, sectorsize);
560         btrfs_set_stack_chunk_num_stripes(chunk, 1);
561         btrfs_set_stack_chunk_sub_stripes(chunk, 0);
562         chunk->stripe.devid = super->dev_item.devid;
563         chunk->stripe.offset = cpu_to_le64(0);
564         memcpy(chunk->stripe.dev_uuid, super->dev_item.uuid, BTRFS_UUID_SIZE);
565         btrfs_set_super_sys_array_size(super, sizeof(*key) + sizeof(*chunk));
566         csum_block(buffer, 4096);
567 }
568
569 static void *restore_worker(void *data)
570 {
571         struct mdrestore_struct *mdres = (struct mdrestore_struct *)data;
572         struct async_work *async;
573         size_t size;
574         u8 *buffer;
575         u8 *outbuf;
576         int outfd;
577         int ret;
578
579         outfd = fileno(mdres->out);
580         buffer = malloc(MAX_PENDING_SIZE * 2);
581         BUG_ON(!buffer);
582
583         while (1) {
584                 pthread_mutex_lock(&mdres->mutex);
585                 while (list_empty(&mdres->list)) {
586                         if (mdres->done) {
587                                 pthread_mutex_unlock(&mdres->mutex);
588                                 goto out;
589                         }
590                         pthread_cond_wait(&mdres->cond, &mdres->mutex);
591                 }
592                 async = list_entry(mdres->list.next, struct async_work, list);
593                 list_del_init(&async->list);
594                 pthread_mutex_unlock(&mdres->mutex);
595
596                 if (mdres->compress_method == COMPRESS_ZLIB) {
597                         size = MAX_PENDING_SIZE * 2;
598                         ret = uncompress(buffer, &size, async->buffer,
599                                          async->bufsize);
600                         BUG_ON(ret != Z_OK);
601                         outbuf = buffer;
602                 } else {
603                         outbuf = async->buffer;
604                         size = async->bufsize;
605                 }
606
607                 if (async->start == BTRFS_SUPER_INFO_OFFSET)
608                         update_super(outbuf);
609
610                 ret = pwrite64(outfd, outbuf, size, async->start);
611                 BUG_ON(ret != size);
612
613                 pthread_mutex_lock(&mdres->mutex);
614                 mdres->num_items--;
615                 pthread_mutex_unlock(&mdres->mutex);
616
617                 free(async->buffer);
618                 free(async);
619         }
620 out:
621         free(buffer);
622         pthread_exit(NULL);
623 }
624
625 static int mdresotre_init(struct mdrestore_struct *mdres,
626                           FILE *in, FILE *out, int num_threads)
627 {
628         int i, ret = 0;
629
630         memset(mdres, 0, sizeof(*mdres));
631         pthread_cond_init(&mdres->cond, NULL);
632         pthread_mutex_init(&mdres->mutex, NULL);
633         INIT_LIST_HEAD(&mdres->list);
634         mdres->in = in;
635         mdres->out = out;
636
637         if (!num_threads)
638                 return 0;
639
640         mdres->num_threads = num_threads;
641         mdres->threads = calloc(num_threads, sizeof(pthread_t));
642         if (!mdres->threads)
643                 return -ENOMEM;
644         for (i = 0; i < num_threads; i++) {
645                 ret = pthread_create(mdres->threads + i, NULL, restore_worker,
646                                      mdres);
647                 if (ret)
648                         break;
649         }
650         return ret;
651 }
652
653 static void mdresotre_destroy(struct mdrestore_struct *mdres)
654 {
655         int i;
656         pthread_mutex_lock(&mdres->mutex);
657         mdres->done = 1;
658         pthread_cond_broadcast(&mdres->cond);
659         pthread_mutex_unlock(&mdres->mutex);
660
661         for (i = 0; i < mdres->num_threads; i++)
662                 pthread_join(mdres->threads[i], NULL);
663
664         pthread_cond_destroy(&mdres->cond);
665         pthread_mutex_destroy(&mdres->mutex);
666         free(mdres->threads);
667 }
668
669 static int add_cluster(struct meta_cluster *cluster,
670                        struct mdrestore_struct *mdres, u64 *next)
671 {
672         struct meta_cluster_item *item;
673         struct meta_cluster_header *header = &cluster->header;
674         struct async_work *async;
675         u64 bytenr;
676         u32 i, nritems;
677         int ret;
678
679         BUG_ON(mdres->num_items);
680         mdres->compress_method = header->compress;
681
682         bytenr = le64_to_cpu(header->bytenr) + BLOCK_SIZE;
683         nritems = le32_to_cpu(header->nritems);
684         for (i = 0; i < nritems; i++) {
685                 item = &cluster->items[i];
686                 async = calloc(1, sizeof(*async));
687                 async->start = le64_to_cpu(item->bytenr);
688                 async->bufsize = le32_to_cpu(item->size);
689                 async->buffer = malloc(async->bufsize);
690                 ret = fread(async->buffer, async->bufsize, 1, mdres->in);
691                 BUG_ON(ret != 1);
692                 bytenr += async->bufsize;
693
694                 pthread_mutex_lock(&mdres->mutex);
695                 list_add_tail(&async->list, &mdres->list);
696                 mdres->num_items++;
697                 pthread_cond_signal(&mdres->cond);
698                 pthread_mutex_unlock(&mdres->mutex);
699         }
700         if (bytenr & BLOCK_MASK) {
701                 char buffer[BLOCK_MASK];
702                 size_t size = BLOCK_SIZE - (bytenr & BLOCK_MASK);
703
704                 bytenr += size;
705                 ret = fread(buffer, size, 1, mdres->in);
706                 BUG_ON(ret != 1);
707         }
708         *next = bytenr;
709         return 0;
710 }
711
712 static int wait_for_worker(struct mdrestore_struct *mdres)
713 {
714         pthread_mutex_lock(&mdres->mutex);
715         while (mdres->num_items > 0) {
716                 struct timespec ts = {
717                         .tv_sec = 0,
718                         .tv_nsec = 10000000,
719                 };
720                 pthread_mutex_unlock(&mdres->mutex);
721                 nanosleep(&ts, NULL);
722                 pthread_mutex_lock(&mdres->mutex);
723         }
724         pthread_mutex_unlock(&mdres->mutex);
725         return 0;
726 }
727
728 static int restore_metadump(const char *input, FILE *out, int num_threads)
729 {
730         struct meta_cluster *cluster;
731         struct meta_cluster_header *header;
732         struct mdrestore_struct mdrestore;
733         u64 bytenr = 0;
734         FILE *in;
735         int ret;
736
737         if (!strcmp(input, "-")) {
738                 in = stdin;
739         } else {
740                 in = fopen(input, "r");
741                 if (!in) {
742                         perror("unable to open metadump image");
743                         exit(1);
744                 }
745         }
746
747         cluster = malloc(BLOCK_SIZE);
748         BUG_ON(!cluster);
749
750         ret = mdresotre_init(&mdrestore, in, out, num_threads);
751         BUG_ON(ret);
752
753         while (1) {
754                 ret = fread(cluster, BLOCK_SIZE, 1, in);
755                 if (!ret)
756                         break;
757
758                 header = &cluster->header;
759                 if (le64_to_cpu(header->magic) != HEADER_MAGIC ||
760                     le64_to_cpu(header->bytenr) != bytenr) {
761                         fprintf(stderr, "bad header in metadump image\n");
762                         exit(1);
763                 }
764                 ret = add_cluster(cluster, &mdrestore, &bytenr);
765                 BUG_ON(ret);
766
767                 wait_for_worker(&mdrestore);
768         }
769
770         mdresotre_destroy(&mdrestore);
771         free(cluster);
772         if (in != stdin)
773                 fclose(in);
774         return ret;
775 }
776
777 static void print_usage(void)
778 {
779         fprintf(stderr, "usage: btrfs-image [options] source target\n");
780         fprintf(stderr, "\t-r      \trestore metadump image\n");
781         fprintf(stderr, "\t-c value\tcompression level (0 ~ 9)\n");
782         fprintf(stderr, "\t-t value\tnumber of threads (1 ~ 32)\n");
783         exit(1);
784 }
785
786 int main(int argc, char *argv[])
787 {
788         char *source;
789         char *target;
790         int num_threads = 0;
791         int compress_level = 0;
792         int create = 1;
793         int ret;
794         FILE *out;
795
796         while (1) {
797                 int c = getopt(argc, argv, "rc:t:");
798                 if (c < 0)
799                         break;
800                 switch (c) {
801                 case 'r':
802                         create = 0;
803                         break;
804                 case 't':
805                         num_threads = atoi(optarg);
806                         if (num_threads <= 0 || num_threads > 32)
807                                 print_usage();
808                         break;
809                 case 'c':
810                         compress_level = atoi(optarg);
811                         if (compress_level < 0 || compress_level > 9)
812                                 print_usage();
813                         break;
814                 default:
815                         print_usage();
816                 }
817         }
818
819         argc = argc - optind;
820         if (argc != 2)
821                 print_usage();
822         source = argv[optind];
823         target = argv[optind + 1];
824
825         if (create && !strcmp(target, "-")) {
826                 out = stdout;
827         } else {
828                 out = fopen(target, "w+");
829                 if (!out) {
830                         perror("unable to create target file");
831                         exit(1);
832                 }
833         }
834
835         if (num_threads == 0 && compress_level > 0) {
836                 num_threads = sysconf(_SC_NPROCESSORS_ONLN);
837                 if (num_threads <= 0)
838                         num_threads = 1;
839         }
840
841         if (create)
842                 ret = create_metadump(source, out, num_threads,
843                                       compress_level);
844         else
845                 ret = restore_metadump(source, out, 1);
846
847         if (out == stdout)
848                 fflush(out);
849         else
850                 fclose(out);
851
852         exit(0);
853 }