forked from Mirrors/btrfs-progs
Btrfs-progs: cleanup error handling in btrfs-image
We use BUG_ON() everywhere in btrfs-image. When users are going to use this command things are pretty dire, so I'd rather have really good error messages so I know what happened rather than figure out which one of the 20 BUG_ON()'s made the stupid thing exit early. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>master
parent
6d37fbfc1f
commit
1bf2717b2f
292
btrfs-image.c
292
btrfs-image.c
|
@ -72,6 +72,7 @@ struct async_work {
|
||||||
u64 size;
|
u64 size;
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct metadump_struct {
|
struct metadump_struct {
|
||||||
|
@ -111,6 +112,7 @@ struct mdrestore_struct {
|
||||||
|
|
||||||
int compress_method;
|
int compress_method;
|
||||||
int done;
|
int done;
|
||||||
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void csum_block(u8 *buf, size_t len)
|
static void csum_block(u8 *buf, size_t len)
|
||||||
|
@ -219,7 +221,9 @@ static void *dump_worker(void *data)
|
||||||
ret = compress2(async->buffer,
|
ret = compress2(async->buffer,
|
||||||
(unsigned long *)&async->bufsize,
|
(unsigned long *)&async->bufsize,
|
||||||
orig, async->size, md->compress_level);
|
orig, async->size, md->compress_level);
|
||||||
BUG_ON(ret != Z_OK);
|
|
||||||
|
if (ret != Z_OK)
|
||||||
|
async->error = 1;
|
||||||
|
|
||||||
free(orig);
|
free(orig);
|
||||||
}
|
}
|
||||||
|
@ -261,8 +265,11 @@ static int metadump_init(struct metadump_struct *md, struct btrfs_root *root,
|
||||||
md->pending_start = (u64)-1;
|
md->pending_start = (u64)-1;
|
||||||
md->compress_level = compress_level;
|
md->compress_level = compress_level;
|
||||||
md->cluster = calloc(1, BLOCK_SIZE);
|
md->cluster = calloc(1, BLOCK_SIZE);
|
||||||
if (!md->cluster)
|
if (!md->cluster) {
|
||||||
|
pthread_cond_destroy(&md->cond);
|
||||||
|
pthread_mutex_destroy(&md->mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
meta_cluster_init(md, 0);
|
meta_cluster_init(md, 0);
|
||||||
if (!num_threads)
|
if (!num_threads)
|
||||||
|
@ -270,13 +277,34 @@ static int metadump_init(struct metadump_struct *md, struct btrfs_root *root,
|
||||||
|
|
||||||
md->num_threads = num_threads;
|
md->num_threads = num_threads;
|
||||||
md->threads = calloc(num_threads, sizeof(pthread_t));
|
md->threads = calloc(num_threads, sizeof(pthread_t));
|
||||||
if (!md->threads)
|
if (!md->threads) {
|
||||||
|
free(md->cluster);
|
||||||
|
pthread_cond_destroy(&md->cond);
|
||||||
|
pthread_mutex_destroy(&md->mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < num_threads; i++) {
|
for (i = 0; i < num_threads; i++) {
|
||||||
ret = pthread_create(md->threads + i, NULL, dump_worker, md);
|
ret = pthread_create(md->threads + i, NULL, dump_worker, md);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pthread_mutex_lock(&md->mutex);
|
||||||
|
md->done = 1;
|
||||||
|
pthread_cond_broadcast(&md->cond);
|
||||||
|
pthread_mutex_unlock(&md->mutex);
|
||||||
|
|
||||||
|
for (i--; i >= 0; i--)
|
||||||
|
pthread_join(md->threads[i], NULL);
|
||||||
|
|
||||||
|
pthread_cond_destroy(&md->cond);
|
||||||
|
pthread_mutex_destroy(&md->mutex);
|
||||||
|
free(md->cluster);
|
||||||
|
free(md->threads);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +339,7 @@ static int write_buffers(struct metadump_struct *md, u64 *next)
|
||||||
u64 bytenr = 0;
|
u64 bytenr = 0;
|
||||||
u32 nritems = 0;
|
u32 nritems = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
if (list_empty(&md->ordered))
|
if (list_empty(&md->ordered))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -336,7 +365,10 @@ static int write_buffers(struct metadump_struct *md, u64 *next)
|
||||||
header->nritems = cpu_to_le32(nritems);
|
header->nritems = cpu_to_le32(nritems);
|
||||||
|
|
||||||
ret = fwrite(md->cluster, BLOCK_SIZE, 1, md->out);
|
ret = fwrite(md->cluster, BLOCK_SIZE, 1, md->out);
|
||||||
BUG_ON(ret != 1);
|
if (ret != 1) {
|
||||||
|
fprintf(stderr, "Error writing out cluster: %d\n", errno);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* write buffers */
|
/* write buffers */
|
||||||
bytenr += le64_to_cpu(header->bytenr) + BLOCK_SIZE;
|
bytenr += le64_to_cpu(header->bytenr) + BLOCK_SIZE;
|
||||||
|
@ -346,24 +378,35 @@ static int write_buffers(struct metadump_struct *md, u64 *next)
|
||||||
list_del_init(&async->ordered);
|
list_del_init(&async->ordered);
|
||||||
|
|
||||||
bytenr += async->bufsize;
|
bytenr += async->bufsize;
|
||||||
ret = fwrite(async->buffer, async->bufsize, 1, md->out);
|
if (!err)
|
||||||
BUG_ON(ret != 1);
|
ret = fwrite(async->buffer, async->bufsize, 1,
|
||||||
|
md->out);
|
||||||
|
if (ret != 1) {
|
||||||
|
err = -EIO;
|
||||||
|
ret = 0;
|
||||||
|
fprintf(stderr, "Error writing out cluster: %d\n",
|
||||||
|
errno);
|
||||||
|
}
|
||||||
|
|
||||||
free(async->buffer);
|
free(async->buffer);
|
||||||
free(async);
|
free(async);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* zero unused space in the last block */
|
/* zero unused space in the last block */
|
||||||
if (bytenr & BLOCK_MASK) {
|
if (!err && bytenr & BLOCK_MASK) {
|
||||||
size_t size = BLOCK_SIZE - (bytenr & BLOCK_MASK);
|
size_t size = BLOCK_SIZE - (bytenr & BLOCK_MASK);
|
||||||
|
|
||||||
bytenr += size;
|
bytenr += size;
|
||||||
ret = write_zero(md->out, size);
|
ret = write_zero(md->out, size);
|
||||||
BUG_ON(ret != 1);
|
if (ret != 1) {
|
||||||
|
fprintf(stderr, "Error zeroing out buffer: %d\n",
|
||||||
|
errno);
|
||||||
|
err = -EIO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
*next = bytenr;
|
*next = bytenr;
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flush_pending(struct metadump_struct *md, int done)
|
static int flush_pending(struct metadump_struct *md, int done)
|
||||||
|
@ -374,7 +417,7 @@ static int flush_pending(struct metadump_struct *md, int done)
|
||||||
u64 start;
|
u64 start;
|
||||||
u64 size;
|
u64 size;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (md->pending_size) {
|
if (md->pending_size) {
|
||||||
async = calloc(1, sizeof(*async));
|
async = calloc(1, sizeof(*async));
|
||||||
|
@ -385,13 +428,22 @@ static int flush_pending(struct metadump_struct *md, int done)
|
||||||
async->size = md->pending_size;
|
async->size = md->pending_size;
|
||||||
async->bufsize = async->size;
|
async->bufsize = async->size;
|
||||||
async->buffer = malloc(async->bufsize);
|
async->buffer = malloc(async->bufsize);
|
||||||
|
if (!async->buffer) {
|
||||||
|
free(async);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
start = async->start;
|
start = async->start;
|
||||||
size = async->size;
|
size = async->size;
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
eb = read_tree_block(md->root, start, blocksize, 0);
|
eb = read_tree_block(md->root, start, blocksize, 0);
|
||||||
BUG_ON(!eb);
|
if (!eb) {
|
||||||
|
free(async->buffer);
|
||||||
|
free(async);
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading metadata block\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
copy_buffer(async->buffer + offset, eb);
|
copy_buffer(async->buffer + offset, eb);
|
||||||
free_extent_buffer(eb);
|
free_extent_buffer(eb);
|
||||||
start += blocksize;
|
start += blocksize;
|
||||||
|
@ -418,11 +470,14 @@ static int flush_pending(struct metadump_struct *md, int done)
|
||||||
}
|
}
|
||||||
if (md->num_items >= ITEMS_PER_CLUSTER || done) {
|
if (md->num_items >= ITEMS_PER_CLUSTER || done) {
|
||||||
ret = write_buffers(md, &start);
|
ret = write_buffers(md, &start);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
meta_cluster_init(md, start);
|
fprintf(stderr, "Error writing buffers %d\n",
|
||||||
|
errno);
|
||||||
|
else
|
||||||
|
meta_cluster_init(md, start);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&md->mutex);
|
pthread_mutex_unlock(&md->mutex);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_metadata(u64 start, u64 size, struct metadump_struct *md)
|
static int add_metadata(u64 start, u64 size, struct metadump_struct *md)
|
||||||
|
@ -455,7 +510,8 @@ static int is_tree_block(struct btrfs_root *extent_root,
|
||||||
path->slots[0]++;
|
path->slots[0]++;
|
||||||
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
||||||
ret = btrfs_next_leaf(extent_root, path);
|
ret = btrfs_next_leaf(extent_root, path);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
break;
|
break;
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
@ -481,7 +537,7 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
|
||||||
{
|
{
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct btrfs_root *extent_root;
|
struct btrfs_root *extent_root;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path = NULL;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_extent_item *ei;
|
struct btrfs_extent_item *ei;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
|
@ -489,38 +545,60 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
|
||||||
u64 bytenr;
|
u64 bytenr;
|
||||||
u64 num_bytes;
|
u64 num_bytes;
|
||||||
int ret;
|
int ret;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
root = open_ctree(input, 0, 0);
|
root = open_ctree(input, 0, 0);
|
||||||
if (!root) {
|
if (!root) {
|
||||||
fprintf(stderr, "Open ctree failed\n");
|
fprintf(stderr, "Open ctree failed\n");
|
||||||
exit(1);
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(root->nodesize != root->leafsize);
|
BUG_ON(root->nodesize != root->leafsize);
|
||||||
|
|
||||||
ret = metadump_init(&metadump, root, out, num_threads,
|
ret = metadump_init(&metadump, root, out, num_threads,
|
||||||
compress_level);
|
compress_level);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
fprintf(stderr, "Error initing metadump %d\n", ret);
|
||||||
|
close_ctree(root);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = add_metadata(BTRFS_SUPER_INFO_OFFSET, 4096, &metadump);
|
ret = add_metadata(BTRFS_SUPER_INFO_OFFSET, 4096, &metadump);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
fprintf(stderr, "Error adding metadata %d\n", ret);
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
extent_root = root->fs_info->extent_root;
|
extent_root = root->fs_info->extent_root;
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
|
if (!path) {
|
||||||
|
fprintf(stderr, "Out of memory allocing path\n");
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
bytenr = BTRFS_SUPER_INFO_OFFSET + 4096;
|
bytenr = BTRFS_SUPER_INFO_OFFSET + 4096;
|
||||||
key.objectid = bytenr;
|
key.objectid = bytenr;
|
||||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||||
key.offset = 0;
|
key.offset = 0;
|
||||||
|
|
||||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error searching extent root %d\n", ret);
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
||||||
ret = btrfs_next_leaf(extent_root, path);
|
ret = btrfs_next_leaf(extent_root, path);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error going to next leaf %d"
|
||||||
|
"\n", ret);
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
break;
|
break;
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
@ -543,30 +621,56 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
|
||||||
BTRFS_EXTENT_FLAG_TREE_BLOCK) {
|
BTRFS_EXTENT_FLAG_TREE_BLOCK) {
|
||||||
ret = add_metadata(bytenr, num_bytes,
|
ret = add_metadata(bytenr, num_bytes,
|
||||||
&metadump);
|
&metadump);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
fprintf(stderr, "Error adding block "
|
||||||
|
"%d\n", ret);
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
|
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
|
||||||
if (is_tree_block(extent_root, path, bytenr)) {
|
ret = is_tree_block(extent_root, path, bytenr);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error checking tree block "
|
||||||
|
"%d\n", ret);
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
ret = add_metadata(bytenr, num_bytes,
|
ret = add_metadata(bytenr, num_bytes,
|
||||||
&metadump);
|
&metadump);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
fprintf(stderr, "Error adding block "
|
||||||
|
"%d\n", ret);
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
BUG_ON(1);
|
fprintf(stderr, "Either extent tree corruption or "
|
||||||
|
"you haven't built with V0 support\n");
|
||||||
|
err = -EIO;
|
||||||
|
goto out;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
bytenr += num_bytes;
|
bytenr += num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
ret = flush_pending(&metadump, 1);
|
ret = flush_pending(&metadump, 1);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
if (!err)
|
||||||
|
ret = err;
|
||||||
|
fprintf(stderr, "Error flushing pending %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
metadump_destroy(&metadump);
|
metadump_destroy(&metadump);
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
ret = close_ctree(root);
|
ret = close_ctree(root);
|
||||||
return 0;
|
return err ? err : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_super(u8 *buffer)
|
static void update_super(u8 *buffer)
|
||||||
|
@ -616,9 +720,18 @@ static void *restore_worker(void *data)
|
||||||
|
|
||||||
outfd = fileno(mdres->out);
|
outfd = fileno(mdres->out);
|
||||||
buffer = malloc(MAX_PENDING_SIZE * 2);
|
buffer = malloc(MAX_PENDING_SIZE * 2);
|
||||||
BUG_ON(!buffer);
|
if (!buffer) {
|
||||||
|
fprintf(stderr, "Error allocing buffer\n");
|
||||||
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
|
if (!mdres->error)
|
||||||
|
mdres->error = -ENOMEM;
|
||||||
|
pthread_mutex_unlock(&mdres->mutex);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&mdres->mutex);
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
while (list_empty(&mdres->list)) {
|
while (list_empty(&mdres->list)) {
|
||||||
if (mdres->done) {
|
if (mdres->done) {
|
||||||
|
@ -635,7 +748,11 @@ static void *restore_worker(void *data)
|
||||||
size = MAX_PENDING_SIZE * 2;
|
size = MAX_PENDING_SIZE * 2;
|
||||||
ret = uncompress(buffer, (unsigned long *)&size,
|
ret = uncompress(buffer, (unsigned long *)&size,
|
||||||
async->buffer, async->bufsize);
|
async->buffer, async->bufsize);
|
||||||
BUG_ON(ret != Z_OK);
|
if (ret != Z_OK) {
|
||||||
|
fprintf(stderr, "Error decompressing %d\n",
|
||||||
|
ret);
|
||||||
|
err = -EIO;
|
||||||
|
}
|
||||||
outbuf = buffer;
|
outbuf = buffer;
|
||||||
} else {
|
} else {
|
||||||
outbuf = async->buffer;
|
outbuf = async->buffer;
|
||||||
|
@ -646,9 +763,20 @@ static void *restore_worker(void *data)
|
||||||
update_super(outbuf);
|
update_super(outbuf);
|
||||||
|
|
||||||
ret = pwrite64(outfd, outbuf, size, async->start);
|
ret = pwrite64(outfd, outbuf, size, async->start);
|
||||||
BUG_ON(ret != size);
|
if (ret < size) {
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error writing to device %d\n",
|
||||||
|
errno);
|
||||||
|
err = errno;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Short write\n");
|
||||||
|
err = -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&mdres->mutex);
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
|
if (err && !mdres->error)
|
||||||
|
mdres->error = err;
|
||||||
mdres->num_items--;
|
mdres->num_items--;
|
||||||
pthread_mutex_unlock(&mdres->mutex);
|
pthread_mutex_unlock(&mdres->mutex);
|
||||||
|
|
||||||
|
@ -660,6 +788,22 @@ out:
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mdrestore_destroy(struct mdrestore_struct *mdres)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
|
mdres->done = 1;
|
||||||
|
pthread_cond_broadcast(&mdres->cond);
|
||||||
|
pthread_mutex_unlock(&mdres->mutex);
|
||||||
|
|
||||||
|
for (i = 0; i < mdres->num_threads; i++)
|
||||||
|
pthread_join(mdres->threads[i], NULL);
|
||||||
|
|
||||||
|
pthread_cond_destroy(&mdres->cond);
|
||||||
|
pthread_mutex_destroy(&mdres->mutex);
|
||||||
|
free(mdres->threads);
|
||||||
|
}
|
||||||
|
|
||||||
static int mdrestore_init(struct mdrestore_struct *mdres,
|
static int mdrestore_init(struct mdrestore_struct *mdres,
|
||||||
FILE *in, FILE *out, int num_threads)
|
FILE *in, FILE *out, int num_threads)
|
||||||
{
|
{
|
||||||
|
@ -685,25 +829,11 @@ static int mdrestore_init(struct mdrestore_struct *mdres,
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
mdrestore_destroy(mdres);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdrestore_destroy(struct mdrestore_struct *mdres)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
pthread_mutex_lock(&mdres->mutex);
|
|
||||||
mdres->done = 1;
|
|
||||||
pthread_cond_broadcast(&mdres->cond);
|
|
||||||
pthread_mutex_unlock(&mdres->mutex);
|
|
||||||
|
|
||||||
for (i = 0; i < mdres->num_threads; i++)
|
|
||||||
pthread_join(mdres->threads[i], NULL);
|
|
||||||
|
|
||||||
pthread_cond_destroy(&mdres->cond);
|
|
||||||
pthread_mutex_destroy(&mdres->mutex);
|
|
||||||
free(mdres->threads);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_cluster(struct meta_cluster *cluster,
|
static int add_cluster(struct meta_cluster *cluster,
|
||||||
struct mdrestore_struct *mdres, u64 *next)
|
struct mdrestore_struct *mdres, u64 *next)
|
||||||
{
|
{
|
||||||
|
@ -722,11 +852,25 @@ static int add_cluster(struct meta_cluster *cluster,
|
||||||
for (i = 0; i < nritems; i++) {
|
for (i = 0; i < nritems; i++) {
|
||||||
item = &cluster->items[i];
|
item = &cluster->items[i];
|
||||||
async = calloc(1, sizeof(*async));
|
async = calloc(1, sizeof(*async));
|
||||||
|
if (!async) {
|
||||||
|
fprintf(stderr, "Error allocating async\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
async->start = le64_to_cpu(item->bytenr);
|
async->start = le64_to_cpu(item->bytenr);
|
||||||
async->bufsize = le32_to_cpu(item->size);
|
async->bufsize = le32_to_cpu(item->size);
|
||||||
async->buffer = malloc(async->bufsize);
|
async->buffer = malloc(async->bufsize);
|
||||||
|
if (!async->buffer) {
|
||||||
|
fprintf(stderr, "Error allocing async buffer\n");
|
||||||
|
free(async);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
ret = fread(async->buffer, async->bufsize, 1, mdres->in);
|
ret = fread(async->buffer, async->bufsize, 1, mdres->in);
|
||||||
BUG_ON(ret != 1);
|
if (ret != 1) {
|
||||||
|
fprintf(stderr, "Error reading buffer %d\n", errno);
|
||||||
|
free(async->buffer);
|
||||||
|
free(async);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
bytenr += async->bufsize;
|
bytenr += async->bufsize;
|
||||||
|
|
||||||
pthread_mutex_lock(&mdres->mutex);
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
|
@ -741,7 +885,10 @@ static int add_cluster(struct meta_cluster *cluster,
|
||||||
|
|
||||||
bytenr += size;
|
bytenr += size;
|
||||||
ret = fread(buffer, size, 1, mdres->in);
|
ret = fread(buffer, size, 1, mdres->in);
|
||||||
BUG_ON(ret != 1);
|
if (ret != 1) {
|
||||||
|
fprintf(stderr, "Error reading in buffer %d\n", errno);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*next = bytenr;
|
*next = bytenr;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -749,8 +896,11 @@ static int add_cluster(struct meta_cluster *cluster,
|
||||||
|
|
||||||
static int wait_for_worker(struct mdrestore_struct *mdres)
|
static int wait_for_worker(struct mdrestore_struct *mdres)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&mdres->mutex);
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
while (mdres->num_items > 0) {
|
ret = mdres->error;
|
||||||
|
while (!ret && mdres->num_items > 0) {
|
||||||
struct timespec ts = {
|
struct timespec ts = {
|
||||||
.tv_sec = 0,
|
.tv_sec = 0,
|
||||||
.tv_nsec = 10000000,
|
.tv_nsec = 10000000,
|
||||||
|
@ -758,9 +908,10 @@ static int wait_for_worker(struct mdrestore_struct *mdres)
|
||||||
pthread_mutex_unlock(&mdres->mutex);
|
pthread_mutex_unlock(&mdres->mutex);
|
||||||
nanosleep(&ts, NULL);
|
nanosleep(&ts, NULL);
|
||||||
pthread_mutex_lock(&mdres->mutex);
|
pthread_mutex_lock(&mdres->mutex);
|
||||||
|
ret = mdres->error;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&mdres->mutex);
|
pthread_mutex_unlock(&mdres->mutex);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int restore_metadump(const char *input, FILE *out, int num_threads)
|
static int restore_metadump(const char *input, FILE *out, int num_threads)
|
||||||
|
@ -770,7 +921,7 @@ static int restore_metadump(const char *input, FILE *out, int num_threads)
|
||||||
struct mdrestore_struct mdrestore;
|
struct mdrestore_struct mdrestore;
|
||||||
u64 bytenr = 0;
|
u64 bytenr = 0;
|
||||||
FILE *in = NULL;
|
FILE *in = NULL;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (!strcmp(input, "-")) {
|
if (!strcmp(input, "-")) {
|
||||||
in = stdin;
|
in = stdin;
|
||||||
|
@ -783,10 +934,21 @@ static int restore_metadump(const char *input, FILE *out, int num_threads)
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster = malloc(BLOCK_SIZE);
|
cluster = malloc(BLOCK_SIZE);
|
||||||
BUG_ON(!cluster);
|
if (!cluster) {
|
||||||
|
fprintf(stderr, "Error allocating cluster\n");
|
||||||
|
if (in != stdin)
|
||||||
|
fclose(in);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
ret = mdrestore_init(&mdrestore, in, out, num_threads);
|
ret = mdrestore_init(&mdrestore, in, out, num_threads);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
fprintf(stderr, "Error initing mdrestore %d\n", ret);
|
||||||
|
if (in != stdin)
|
||||||
|
fclose(in);
|
||||||
|
free(cluster);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = fread(cluster, BLOCK_SIZE, 1, in);
|
ret = fread(cluster, BLOCK_SIZE, 1, in);
|
||||||
|
@ -797,15 +959,23 @@ static int restore_metadump(const char *input, FILE *out, int num_threads)
|
||||||
if (le64_to_cpu(header->magic) != HEADER_MAGIC ||
|
if (le64_to_cpu(header->magic) != HEADER_MAGIC ||
|
||||||
le64_to_cpu(header->bytenr) != bytenr) {
|
le64_to_cpu(header->bytenr) != bytenr) {
|
||||||
fprintf(stderr, "bad header in metadump image\n");
|
fprintf(stderr, "bad header in metadump image\n");
|
||||||
ret = 1;
|
ret = -EIO;
|
||||||
goto out;
|
break;
|
||||||
}
|
}
|
||||||
ret = add_cluster(cluster, &mdrestore, &bytenr);
|
ret = add_cluster(cluster, &mdrestore, &bytenr);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
fprintf(stderr, "Error adding cluster\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
wait_for_worker(&mdrestore);
|
ret = wait_for_worker(&mdrestore);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "One of the threads errored out %d\n",
|
||||||
|
ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
mdrestore_destroy(&mdrestore);
|
mdrestore_destroy(&mdrestore);
|
||||||
free(cluster);
|
free(cluster);
|
||||||
if (in != stdin)
|
if (in != stdin)
|
||||||
|
@ -888,5 +1058,5 @@ int main(int argc, char *argv[])
|
||||||
else
|
else
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
|
||||||
exit(ret);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue