Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://neil.brown.name/md
Browse files Browse the repository at this point in the history
* 'for-linus' of git://neil.brown.name/md:
  md/raid5: don't include 'spare' drives when reshaping to fewer devices.
  md/raid5: add a missing 'continue' in a loop.
  md/raid5: Allow recovered part of partially recovered devices to be in-sync
  md/raid5: More careful check for "has array failed".
  md: Don't update ->recovery_offset when reshaping an array to fewer devices.
  md/raid5: avoid oops when number of devices is reduced then increased.
  md: enable raid4->raid0 takeover
  md: clear layout after ->raid0 takeover
  md: fix raid10 takeover: use new_layout for setup_conf
  md: fix handling of array level takeover that re-arranges devices.
  md: raid10: Fix null pointer dereference in fix_read_error()
  Restore partition detection of newly created md arrays.
  • Loading branch information
Linus Torvalds committed Jun 28, 2010
2 parents b4322e7 + 3424bf6 commit 9341625
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 79 deletions.
38 changes: 33 additions & 5 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
/* First make sure individual recovery_offsets are correct */
list_for_each_entry(rdev, &mddev->disks, same_set) {
if (rdev->raid_disk >= 0 &&
mddev->delta_disks >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
mddev->curr_resync_completed > rdev->recovery_offset)
rdev->recovery_offset = mddev->curr_resync_completed;
Expand Down Expand Up @@ -3001,6 +3002,9 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
return -EINVAL;
}

list_for_each_entry(rdev, &mddev->disks, same_set)
rdev->new_raid_disk = rdev->raid_disk;

/* ->takeover must set new_* and/or delta_disks
* if it succeeds, and may set them when it fails.
*/
Expand Down Expand Up @@ -3051,13 +3055,35 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
mddev->safemode = 0;
}

module_put(mddev->pers->owner);
/* Invalidate devices that are now superfluous */
list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= mddev->raid_disks) {
rdev->raid_disk = -1;
list_for_each_entry(rdev, &mddev->disks, same_set) {
char nm[20];
if (rdev->raid_disk < 0)
continue;
if (rdev->new_raid_disk > mddev->raid_disks)
rdev->new_raid_disk = -1;
if (rdev->new_raid_disk == rdev->raid_disk)
continue;
sprintf(nm, "rd%d", rdev->raid_disk);
sysfs_remove_link(&mddev->kobj, nm);
}
list_for_each_entry(rdev, &mddev->disks, same_set) {
if (rdev->raid_disk < 0)
continue;
if (rdev->new_raid_disk == rdev->raid_disk)
continue;
rdev->raid_disk = rdev->new_raid_disk;
if (rdev->raid_disk < 0)
clear_bit(In_sync, &rdev->flags);
else {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
if(sysfs_create_link(&mddev->kobj, &rdev->kobj, nm))
printk("md: cannot register %s for %s after level change\n",
nm, mdname(mddev));
}
}

module_put(mddev->pers->owner);
mddev->pers = pers;
mddev->private = priv;
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
Expand Down Expand Up @@ -5895,6 +5921,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
atomic_inc(&mddev->openers);
mutex_unlock(&mddev->open_mutex);

check_disk_size_change(mddev->gendisk, bdev);
out:
return err;
}
Expand Down Expand Up @@ -6846,6 +6873,7 @@ void md_do_sync(mddev_t *mddev)
rcu_read_lock();
list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
mddev->delta_disks >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
rdev->recovery_offset < mddev->curr_resync)
Expand Down
3 changes: 3 additions & 0 deletions drivers/md/md.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ struct mdk_rdev_s

int desc_nr; /* descriptor index in the superblock */
int raid_disk; /* role of device in array */
int new_raid_disk; /* role that the device will have in
* the array after a level-change completes.
*/
int saved_raid_disk; /* role that device used to have in the
* array and could again if we did a partial
* resync from the bitmap
Expand Down
21 changes: 11 additions & 10 deletions drivers/md/raid0.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,11 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf)
list_for_each_entry(rdev1, &mddev->disks, same_set) {
int j = rdev1->raid_disk;

if (mddev->level == 10)
if (mddev->level == 10) {
/* taking over a raid10-n2 array */
j /= 2;
rdev1->new_raid_disk = j;
}

if (j < 0 || j >= mddev->raid_disks) {
printk(KERN_ERR "md/raid0:%s: bad disk number %d - "
Expand Down Expand Up @@ -361,12 +363,6 @@ static int raid0_run(mddev_t *mddev)
mddev->private = conf;
}
conf = mddev->private;
if (conf->scale_raid_disks) {
int i;
for (i=0; i < conf->strip_zone[0].nb_dev; i++)
conf->devlist[i]->raid_disk /= conf->scale_raid_disks;
/* FIXME update sysfs rd links */
}

/* calculate array device size */
md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));
Expand Down Expand Up @@ -573,7 +569,7 @@ static void raid0_status(struct seq_file *seq, mddev_t *mddev)
return;
}

static void *raid0_takeover_raid5(mddev_t *mddev)
static void *raid0_takeover_raid45(mddev_t *mddev)
{
mdk_rdev_t *rdev;
raid0_conf_t *priv_conf;
Expand All @@ -596,6 +592,7 @@ static void *raid0_takeover_raid5(mddev_t *mddev)

/* Set new parameters */
mddev->new_level = 0;
mddev->new_layout = 0;
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->raid_disks--;
mddev->delta_disks = -1;
Expand Down Expand Up @@ -635,6 +632,7 @@ static void *raid0_takeover_raid10(mddev_t *mddev)

/* Set new parameters */
mddev->new_level = 0;
mddev->new_layout = 0;
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->delta_disks = - mddev->raid_disks / 2;
mddev->raid_disks += mddev->delta_disks;
Expand All @@ -643,19 +641,22 @@ static void *raid0_takeover_raid10(mddev_t *mddev)
mddev->recovery_cp = MaxSector;

create_strip_zones(mddev, &priv_conf);
priv_conf->scale_raid_disks = 2;
return priv_conf;
}

static void *raid0_takeover(mddev_t *mddev)
{
/* raid0 can take over:
* raid4 - if all data disks are active.
* raid5 - providing it is Raid4 layout and one disk is faulty
* raid10 - assuming we have all necessary active disks
*/
if (mddev->level == 4)
return raid0_takeover_raid45(mddev);

if (mddev->level == 5) {
if (mddev->layout == ALGORITHM_PARITY_N)
return raid0_takeover_raid5(mddev);
return raid0_takeover_raid45(mddev);

printk(KERN_ERR "md/raid0:%s: Raid can only takeover Raid5 with layout: %d\n",
mdname(mddev), ALGORITHM_PARITY_N);
Expand Down
3 changes: 0 additions & 3 deletions drivers/md/raid0.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ struct raid0_private_data
struct strip_zone *strip_zone;
mdk_rdev_t **devlist; /* lists of rdevs, pointed to by strip_zone->dev */
int nr_strip_zones;
int scale_raid_disks; /* divide rdev->raid_disks by this in run()
* to handle conversion from raid10
*/
};

typedef struct raid0_private_data raid0_conf_t;
Expand Down
46 changes: 18 additions & 28 deletions drivers/md/raid10.c
Original file line number Diff line number Diff line change
Expand Up @@ -1482,14 +1482,14 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
int sectors = r10_bio->sectors;
mdk_rdev_t*rdev;
int max_read_errors = atomic_read(&mddev->max_corr_read_errors);
int d = r10_bio->devs[r10_bio->read_slot].devnum;

rcu_read_lock();
{
int d = r10_bio->devs[r10_bio->read_slot].devnum;
rdev = rcu_dereference(conf->mirrors[d].rdev);
if (rdev) { /* If rdev is not NULL */
char b[BDEVNAME_SIZE];
int cur_read_error_count = 0;

rdev = rcu_dereference(conf->mirrors[d].rdev);
bdevname(rdev->bdev, b);

if (test_bit(Faulty, &rdev->flags)) {
Expand Down Expand Up @@ -1530,7 +1530,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)

rcu_read_lock();
do {
int d = r10_bio->devs[sl].devnum;
d = r10_bio->devs[sl].devnum;
rdev = rcu_dereference(conf->mirrors[d].rdev);
if (rdev &&
test_bit(In_sync, &rdev->flags)) {
Expand Down Expand Up @@ -1564,7 +1564,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
rcu_read_lock();
while (sl != r10_bio->read_slot) {
char b[BDEVNAME_SIZE];
int d;

if (sl==0)
sl = conf->copies;
sl--;
Expand Down Expand Up @@ -1601,7 +1601,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
}
sl = start;
while (sl != r10_bio->read_slot) {
int d;

if (sl==0)
sl = conf->copies;
sl--;
Expand Down Expand Up @@ -2161,22 +2161,22 @@ static conf_t *setup_conf(mddev_t *mddev)
sector_t stride, size;
int err = -EINVAL;

if (mddev->chunk_sectors < (PAGE_SIZE >> 9) ||
!is_power_of_2(mddev->chunk_sectors)) {
if (mddev->new_chunk_sectors < (PAGE_SIZE >> 9) ||
!is_power_of_2(mddev->new_chunk_sectors)) {
printk(KERN_ERR "md/raid10:%s: chunk size must be "
"at least PAGE_SIZE(%ld) and be a power of 2.\n",
mdname(mddev), PAGE_SIZE);
goto out;
}

nc = mddev->layout & 255;
fc = (mddev->layout >> 8) & 255;
fo = mddev->layout & (1<<16);
nc = mddev->new_layout & 255;
fc = (mddev->new_layout >> 8) & 255;
fo = mddev->new_layout & (1<<16);

if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
(mddev->layout >> 17)) {
(mddev->new_layout >> 17)) {
printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n",
mdname(mddev), mddev->layout);
mdname(mddev), mddev->new_layout);
goto out;
}

Expand Down Expand Up @@ -2241,7 +2241,6 @@ static conf_t *setup_conf(mddev_t *mddev)
if (!conf->thread)
goto out;

conf->scale_disks = 0;
conf->mddev = mddev;
return conf;

Expand Down Expand Up @@ -2300,11 +2299,6 @@ static int run(mddev_t *mddev)
if (disk_idx >= conf->raid_disks
|| disk_idx < 0)
continue;
if (conf->scale_disks) {
disk_idx *= conf->scale_disks;
rdev->raid_disk = disk_idx;
/* MOVE 'rd%d' link !! */
}
disk = conf->mirrors + disk_idx;

disk->rdev = rdev;
Expand Down Expand Up @@ -2435,26 +2429,22 @@ static void *raid10_takeover_raid0(mddev_t *mddev)
return ERR_PTR(-EINVAL);
}

/* Update slot numbers to obtain
* degraded raid10 with missing mirrors
*/
list_for_each_entry(rdev, &mddev->disks, same_set) {
rdev->raid_disk *= 2;
}

/* Set new parameters */
mddev->new_level = 10;
/* new layout: far_copies = 1, near_copies = 2 */
mddev->new_layout = (1<<8) + 2;
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->delta_disks = mddev->raid_disks;
mddev->degraded = mddev->raid_disks;
mddev->raid_disks *= 2;
/* make sure it will be not marked as dirty */
mddev->recovery_cp = MaxSector;

conf = setup_conf(mddev);
conf->scale_disks = 2;
if (!IS_ERR(conf))
list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0)
rdev->new_raid_disk = rdev->raid_disk * 2;

return conf;
}

Expand Down
5 changes: 0 additions & 5 deletions drivers/md/raid10.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ struct r10_private_data_s {
int chunk_shift; /* shift from chunks to sectors */
sector_t chunk_mask;

int scale_disks; /* When starting array, multiply
* each ->raid_disk by this.
* Need for raid0->raid10 migration
*/

struct list_head retry_list;
/* queue pending writes and submit them on unplug */
struct bio_list pending_bio_list;
Expand Down
Loading

0 comments on commit 9341625

Please sign in to comment.