Fill missing devices so degraded filesystems can be read
authorChris Mason <chris.mason@oracle.com>
Wed, 15 Dec 2010 21:00:23 +0000 (16:00 -0500)
committerChris Mason <chris.mason@oracle.com>
Fri, 22 Apr 2011 18:52:40 +0000 (14:52 -0400)
When a device is missing, the btrfs tools need to be able to read alternate
copies from the remaining devices.  This creates placeholder devices
that always return -EIO so the tools can limp along.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
disk-io.c
volumes.c

index a6e1000..fef3eda 100644 (file)
--- a/disk-io.c
+++ b/disk-io.c
@@ -204,6 +204,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
                eb->dev_bytenr = multi->stripes[0].physical;
                kfree(multi);
                ret = read_extent_from_disk(eb);
+
                if (ret == 0 && check_tree_block(root, eb) == 0 &&
                    csum_tree_block(root, eb, 1) == 0 &&
                    verify_parent_transid(eb->tree, eb, parent_transid) == 0) {
index 7671855..b8f7167 100644 (file)
--- a/volumes.c
+++ b/volumes.c
@@ -1159,6 +1159,16 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
        return readonly;
 }
 
+static struct btrfs_device *fill_missing_device(u64 devid)
+{
+       struct btrfs_device *device;
+
+       device = kzalloc(sizeof(*device), GFP_NOFS);
+       device->devid = devid;
+       device->fd = -1;
+       return device;
+}
+
 static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                          struct extent_buffer *leaf,
                          struct btrfs_chunk *chunk)
@@ -1209,8 +1219,9 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                map->stripes[i].dev = btrfs_find_device(root, devid, uuid,
                                                        NULL);
                if (!map->stripes[i].dev) {
-                       kfree(map);
-                       return -EIO;
+                       map->stripes[i].dev = fill_missing_device(devid);
+                       printf("warning, device %llu is missing\n",
+                              (unsigned long long)devid);
                }
 
        }