Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93416253 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://neil.brown.name/md

* '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.
parents b4322e70 3424bf6a
Loading
Loading
Loading
Loading
+33 −5
Original line number Diff line number Diff line
@@ -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;
@@ -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.
	 */
@@ -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));
@@ -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;
}
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -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
+11 −10
Original line number Diff line number Diff line
@@ -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 - "
@@ -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));
@@ -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;
@@ -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;
@@ -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;
@@ -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);
+0 −3
Original line number Diff line number Diff line
@@ -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;
+18 −28
Original line number Diff line number Diff line
@@ -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)) {
@@ -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)) {
@@ -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--;
@@ -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--;
@@ -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;
	}

@@ -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;

@@ -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;
@@ -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;
}

Loading