summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chunk-recover.c89
1 files changed, 82 insertions, 7 deletions
diff --git a/chunk-recover.c b/chunk-recover.c
index ac2a4376..d103e172 100644
--- a/chunk-recover.c
+++ b/chunk-recover.c
@@ -26,6 +26,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <uuid/uuid.h>
+#include <pthread.h>
#include "kerncompat.h"
#include "list.h"
@@ -64,6 +65,7 @@ struct recover_control {
struct list_head good_chunks;
struct list_head bad_chunks;
struct list_head unrepaired_chunks;
+ pthread_mutex_t rc_lock;
};
struct extent_record {
@@ -75,6 +77,12 @@ struct extent_record {
int nmirrors;
};
+struct device_scan {
+ struct recover_control *rc;
+ struct btrfs_device *dev;
+ int fd;
+};
+
static struct extent_record *btrfs_new_extent_record(struct extent_buffer *eb)
{
struct extent_record *rec;
@@ -202,6 +210,7 @@ static void init_recover_control(struct recover_control *rc, int verbose,
rc->verbose = verbose;
rc->yes = yes;
+ pthread_mutex_init(&rc->rc_lock, NULL);
}
static void free_recover_control(struct recover_control *rc)
@@ -210,6 +219,7 @@ static void free_recover_control(struct recover_control *rc)
free_chunk_cache_tree(&rc->chunk);
free_device_extent_tree(&rc->devext);
free_extent_record_tree(&rc->eb_cache);
+ pthread_mutex_destroy(&rc->rc_lock);
}
static int process_block_group_item(struct block_group_tree *bg_cache,
@@ -694,14 +704,20 @@ static int extract_metadata_record(struct recover_control *rc,
btrfs_item_key_to_cpu(leaf, &key, i);
switch (key.type) {
case BTRFS_BLOCK_GROUP_ITEM_KEY:
+ pthread_mutex_lock(&rc->rc_lock);
ret = process_block_group_item(&rc->bg, leaf, &key, i);
+ pthread_mutex_unlock(&rc->rc_lock);
break;
case BTRFS_CHUNK_ITEM_KEY:
+ pthread_mutex_lock(&rc->rc_lock);
ret = process_chunk_item(&rc->chunk, leaf, &key, i);
+ pthread_mutex_unlock(&rc->rc_lock);
break;
case BTRFS_DEV_EXTENT_KEY:
+ pthread_mutex_lock(&rc->rc_lock);
ret = process_device_extent_item(&rc->devext, leaf,
&key, i);
+ pthread_mutex_unlock(&rc->rc_lock);
break;
}
if (ret)
@@ -721,12 +737,19 @@ static inline int is_super_block_address(u64 offset)
return 0;
}
-static int scan_one_device(struct recover_control *rc, int fd,
- struct btrfs_device *device)
+static int scan_one_device(void *dev_scan_struct)
{
struct extent_buffer *buf;
u64 bytenr;
int ret = 0;
+ struct device_scan *dev_scan = (struct device_scan *)dev_scan_struct;
+ struct recover_control *rc = dev_scan->rc;
+ struct btrfs_device *device = dev_scan->dev;
+ int fd = dev_scan->fd;
+
+ ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ if (ret)
+ return 1;
buf = malloc(sizeof(*buf) + rc->leafsize);
if (!buf)
@@ -754,7 +777,9 @@ static int scan_one_device(struct recover_control *rc, int fd,
continue;
}
+ pthread_mutex_lock(&rc->rc_lock);
ret = process_extent_buffer(&rc->eb_cache, buf, device, bytenr);
+ pthread_mutex_unlock(&rc->rc_lock);
if (ret)
goto out;
@@ -784,6 +809,7 @@ next_node:
bytenr += rc->leafsize;
}
out:
+ close(fd);
free(buf);
return ret;
}
@@ -793,6 +819,27 @@ static int scan_devices(struct recover_control *rc)
int ret = 0;
int fd;
struct btrfs_device *dev;
+ struct device_scan *dev_scans;
+ pthread_t *t_scans;
+ int *t_rets;
+ int devnr = 0;
+ int devidx = 0;
+ int cancel_from = 0;
+ int cancel_to = 0;
+ int i;
+
+ list_for_each_entry(dev, &rc->fs_devices->devices, dev_list)
+ devnr++;
+ dev_scans = (struct device_scan *)malloc(sizeof(struct device_scan)
+ * devnr);
+ if (!dev_scans)
+ return -ENOMEM;
+ t_scans = (pthread_t *)malloc(sizeof(pthread_t) * devnr);
+ if (!t_scans)
+ return -ENOMEM;
+ t_rets = (int *)malloc(sizeof(int) * devnr);
+ if (!t_rets)
+ return -ENOMEM;
list_for_each_entry(dev, &rc->fs_devices->devices, dev_list) {
fd = open(dev->name, O_RDONLY);
@@ -801,12 +848,40 @@ static int scan_devices(struct recover_control *rc)
dev->name);
return -1;
}
- ret = scan_one_device(rc, fd, dev);
- close(fd);
- if (ret)
- return ret;
+ dev_scans[devidx].rc = rc;
+ dev_scans[devidx].dev = dev;
+ dev_scans[devidx].fd = fd;
+ ret = pthread_create(&t_scans[devidx], NULL,
+ (void *)scan_one_device,
+ (void *)&dev_scans[devidx]);
+ if (ret) {
+ cancel_from = 0;
+ cancel_to = devidx - 1;
+ goto out;
+ }
+ devidx++;
}
- return ret;
+
+ i = 0;
+ while (i < devidx) {
+ ret = pthread_join(t_scans[i], (void **)&t_rets[i]);
+ if (ret || t_rets[i]) {
+ ret = 1;
+ cancel_from = i + 1;
+ cancel_to = devnr - 1;
+ break;
+ }
+ i++;
+ }
+out:
+ while (cancel_from <= cancel_to) {
+ pthread_cancel(t_scans[cancel_from]);
+ cancel_from++;
+ }
+ free(dev_scans);
+ free(t_scans);
+ free(t_rets);
+ return !!ret;
}
static int build_device_map_by_chunk_record(struct btrfs_root *root,