diff --git a/chunk-recover.c b/chunk-recover.c
index ac2a437..d103e17 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,
