summaryrefslogtreecommitdiff
path: root/drivers/md/dm-raid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-raid.c')
-rw-r--r--drivers/md/dm-raid.c98
1 files changed, 79 insertions, 19 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index c2907d836e4e..b0ba52459ed7 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -56,7 +56,8 @@ struct raid_dev {
struct raid_set {
struct dm_target *ti;
- uint64_t print_flags;
+ uint32_t bitmap_loaded;
+ uint32_t print_flags;
struct mddev md;
struct raid_type *raid_type;
@@ -603,7 +604,9 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
return 0;
if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
- DMERR("Failed to read device superblock");
+ DMERR("Failed to read superblock of device at position %d",
+ rdev->raid_disk);
+ set_bit(Faulty, &rdev->flags);
return -EINVAL;
}
@@ -614,14 +617,14 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
{
- struct md_rdev *r, *t;
+ struct md_rdev *r;
uint64_t failed_devices;
struct dm_raid_superblock *sb;
sb = page_address(rdev->sb_page);
failed_devices = le64_to_cpu(sb->failed_devices);
- rdev_for_each(r, t, mddev)
+ rdev_for_each(r, mddev)
if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
failed_devices |= (1ULL << r->raid_disk);
@@ -667,7 +670,14 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
return ret;
sb = page_address(rdev->sb_page);
- if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) {
+
+ /*
+ * Two cases that we want to write new superblocks and rebuild:
+ * 1) New device (no matching magic number)
+ * 2) Device specified for rebuild (!In_sync w/ offset == 0)
+ */
+ if ((sb->magic != cpu_to_le32(DM_RAID_MAGIC)) ||
+ (!test_bit(In_sync, &rdev->flags) && !rdev->recovery_offset)) {
super_sync(rdev->mddev, rdev);
set_bit(FirstUse, &rdev->flags);
@@ -699,7 +709,7 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
struct dm_raid_superblock *sb;
uint32_t new_devs = 0;
uint32_t rebuilds = 0;
- struct md_rdev *r, *t;
+ struct md_rdev *r;
struct dm_raid_superblock *sb2;
sb = page_address(rdev->sb_page);
@@ -742,13 +752,10 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
* case the In_sync bit will /not/ be set and
* recovery_cp must be MaxSector.
*/
- rdev_for_each(r, t, mddev) {
+ rdev_for_each(r, mddev) {
if (!test_bit(In_sync, &r->flags)) {
- if (!test_bit(FirstUse, &r->flags))
- DMERR("Superblock area of "
- "rebuild device %d should have been "
- "cleared.", r->raid_disk);
- set_bit(FirstUse, &r->flags);
+ DMINFO("Device %d specified for rebuild: "
+ "Clearing superblock", r->raid_disk);
rebuilds++;
} else if (test_bit(FirstUse, &r->flags))
new_devs++;
@@ -777,7 +784,7 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
* Now we set the Faulty bit for those devices that are
* recorded in the superblock as failed.
*/
- rdev_for_each(r, t, mddev) {
+ rdev_for_each(r, mddev) {
if (!r->sb_page)
continue;
sb2 = page_address(r->sb_page);
@@ -850,11 +857,27 @@ static int super_validate(struct mddev *mddev, struct md_rdev *rdev)
static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
{
int ret;
- struct md_rdev *rdev, *freshest, *tmp;
+ unsigned redundancy = 0;
+ struct raid_dev *dev;
+ struct md_rdev *rdev, *freshest;
struct mddev *mddev = &rs->md;
+ switch (rs->raid_type->level) {
+ case 1:
+ redundancy = rs->md.raid_disks - 1;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ redundancy = rs->raid_type->parity_devs;
+ break;
+ default:
+ ti->error = "Unknown RAID type";
+ return -EINVAL;
+ }
+
freshest = NULL;
- rdev_for_each(rdev, tmp, mddev) {
+ rdev_for_each(rdev, mddev) {
if (!rdev->meta_bdev)
continue;
@@ -867,6 +890,37 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
case 0:
break;
default:
+ dev = container_of(rdev, struct raid_dev, rdev);
+ if (redundancy--) {
+ if (dev->meta_dev)
+ dm_put_device(ti, dev->meta_dev);
+
+ dev->meta_dev = NULL;
+ rdev->meta_bdev = NULL;
+
+ if (rdev->sb_page)
+ put_page(rdev->sb_page);
+
+ rdev->sb_page = NULL;
+
+ rdev->sb_loaded = 0;
+
+ /*
+ * We might be able to salvage the data device
+ * even though the meta device has failed. For
+ * now, we behave as though '- -' had been
+ * set for this device in the table.
+ */
+ if (dev->data_dev)
+ dm_put_device(ti, dev->data_dev);
+
+ dev->data_dev = NULL;
+ rdev->bdev = NULL;
+
+ list_del(&rdev->same_set);
+
+ continue;
+ }
ti->error = "Failed to load superblock";
return ret;
}
@@ -883,7 +937,7 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
if (super_validate(mddev, freshest))
return -EINVAL;
- rdev_for_each(rdev, tmp, mddev)
+ rdev_for_each(rdev, mddev)
if ((rdev != freshest) && super_validate(mddev, rdev))
return -EINVAL;
@@ -970,6 +1024,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
INIT_WORK(&rs->md.event_work, do_table_event);
ti->private = rs;
+ ti->num_flush_requests = 1;
mutex_lock(&rs->md.reconfig_mutex);
ret = md_run(&rs->md);
@@ -1085,7 +1140,7 @@ static int raid_status(struct dm_target *ti, status_type_t type,
raid_param_cnt += 2;
}
- raid_param_cnt += (hweight64(rs->print_flags & ~DMPF_REBUILD) * 2);
+ raid_param_cnt += (hweight32(rs->print_flags & ~DMPF_REBUILD) * 2);
if (rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC))
raid_param_cnt--;
@@ -1197,13 +1252,18 @@ static void raid_resume(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
- bitmap_load(&rs->md);
+ if (!rs->bitmap_loaded) {
+ bitmap_load(&rs->md);
+ rs->bitmap_loaded = 1;
+ } else
+ md_wakeup_thread(rs->md.thread);
+
mddev_resume(&rs->md);
}
static struct target_type raid_target = {
.name = "raid",
- .version = {1, 1, 0},
+ .version = {1, 2, 0},
.module = THIS_MODULE,
.ctr = raid_ctr,
.dtr = raid_dtr,