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

Commit d787be40 authored by NeilBrown's avatar NeilBrown Committed by Shaohua Li
Browse files

md: reduce the number of synchronize_rcu() calls when multiple devices fail.



Every time a device is removed with ->hot_remove_disk() a synchronize_rcu() call is made
which can delay several milliseconds in some case.
If lots of devices fail at once - as could happen with a large RAID10 where one set
of devices are removed all at once - these delays can add up to be very inconcenient.

As failure is not reversible we can check for that first, setting a
separate flag if it is found, and then all synchronize_rcu() once for
all the flagged devices.  Then ->hot_remove_disk() function can skip the
synchronize_rcu() step if the flag is set.

fix build error(Shaohua)
Signed-off-by: default avatarNeilBrown <neilb@suse.com>
Signed-off-by: default avatarShaohua Li <shli@fb.com>
parent f5b67ae8
Loading
Loading
Loading
Loading
+26 −3
Original line number Original line Diff line number Diff line
@@ -8180,15 +8180,34 @@ static int remove_and_add_spares(struct mddev *mddev,
	struct md_rdev *rdev;
	struct md_rdev *rdev;
	int spares = 0;
	int spares = 0;
	int removed = 0;
	int removed = 0;
	bool remove_some = false;


	rdev_for_each(rdev, mddev)
	rdev_for_each(rdev, mddev) {
		if ((this == NULL || rdev == this) &&
		if ((this == NULL || rdev == this) &&
		    rdev->raid_disk >= 0 &&
		    rdev->raid_disk >= 0 &&
		    !test_bit(Blocked, &rdev->flags) &&
		    !test_bit(Blocked, &rdev->flags) &&
		    (test_bit(Faulty, &rdev->flags) ||
		    test_bit(Faulty, &rdev->flags) &&
		    atomic_read(&rdev->nr_pending)==0) {
			/* Faulty non-Blocked devices with nr_pending == 0
			 * never get nr_pending incremented,
			 * never get Faulty cleared, and never get Blocked set.
			 * So we can synchronize_rcu now rather than once per device
			 */
			remove_some = true;
			set_bit(RemoveSynchronized, &rdev->flags);
		}
	}

	if (remove_some)
		synchronize_rcu();
	rdev_for_each(rdev, mddev) {
		if ((this == NULL || rdev == this) &&
		    rdev->raid_disk >= 0 &&
		    !test_bit(Blocked, &rdev->flags) &&
		    ((test_bit(RemoveSynchronized, &rdev->flags) ||
		     (!test_bit(In_sync, &rdev->flags) &&
		     (!test_bit(In_sync, &rdev->flags) &&
		      !test_bit(Journal, &rdev->flags))) &&
		      !test_bit(Journal, &rdev->flags))) &&
		    atomic_read(&rdev->nr_pending)==0) {
		    atomic_read(&rdev->nr_pending)==0)) {
			if (mddev->pers->hot_remove_disk(
			if (mddev->pers->hot_remove_disk(
				    mddev, rdev) == 0) {
				    mddev, rdev) == 0) {
				sysfs_unlink_rdev(mddev, rdev);
				sysfs_unlink_rdev(mddev, rdev);
@@ -8196,6 +8215,10 @@ static int remove_and_add_spares(struct mddev *mddev,
				removed++;
				removed++;
			}
			}
		}
		}
		if (remove_some && test_bit(RemoveSynchronized, &rdev->flags))
			clear_bit(RemoveSynchronized, &rdev->flags);
	}

	if (removed && mddev->kobj.sd)
	if (removed && mddev->kobj.sd)
		sysfs_notify(&mddev->kobj, NULL, "degraded");
		sysfs_notify(&mddev->kobj, NULL, "degraded");


+5 −0
Original line number Original line Diff line number Diff line
@@ -163,6 +163,11 @@ enum flag_bits {
				 * than other devices in the array
				 * than other devices in the array
				 */
				 */
	ClusterRemove,
	ClusterRemove,
	RemoveSynchronized,	/* synchronize_rcu() was called after
				 * this device was known to be faulty,
				 * so it is safe to remove without
				 * another synchronize_rcu() call.
				 */
};
};


static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
+8 −6
Original line number Original line Diff line number Diff line
@@ -298,6 +298,7 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
			goto abort;
			goto abort;
		}
		}
		p->rdev = NULL;
		p->rdev = NULL;
		if (!test_bit(RemoveSynchronized, &rdev->flags)) {
			synchronize_rcu();
			synchronize_rcu();
			if (atomic_read(&rdev->nr_pending)) {
			if (atomic_read(&rdev->nr_pending)) {
				/* lost the race, try later */
				/* lost the race, try later */
@@ -305,6 +306,7 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
				p->rdev = rdev;
				p->rdev = rdev;
				goto abort;
				goto abort;
			}
			}
		}
		err = md_integrity_register(mddev);
		err = md_integrity_register(mddev);
	}
	}
abort:
abort:
+10 −7
Original line number Original line Diff line number Diff line
@@ -1656,13 +1656,16 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
			goto abort;
			goto abort;
		}
		}
		p->rdev = NULL;
		p->rdev = NULL;
		if (!test_bit(RemoveSynchronized, &rdev->flags)) {
			synchronize_rcu();
			synchronize_rcu();
			if (atomic_read(&rdev->nr_pending)) {
			if (atomic_read(&rdev->nr_pending)) {
				/* lost the race, try later */
				/* lost the race, try later */
				err = -EBUSY;
				err = -EBUSY;
				p->rdev = rdev;
				p->rdev = rdev;
				goto abort;
				goto abort;
		} else if (conf->mirrors[conf->raid_disks + number].rdev) {
			}
		}
		if (conf->mirrors[conf->raid_disks + number].rdev) {
			/* We just removed a device that is being replaced.
			/* We just removed a device that is being replaced.
			 * Move down the replacement.  We drain all IO before
			 * Move down the replacement.  We drain all IO before
			 * doing this to avoid confusion.
			 * doing this to avoid confusion.
+11 −8
Original line number Original line Diff line number Diff line
@@ -1766,7 +1766,7 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
		err = -EBUSY;
		err = -EBUSY;
		goto abort;
		goto abort;
	}
	}
	/* Only remove faulty devices if recovery
	/* Only remove non-faulty devices if recovery
	 * is not possible.
	 * is not possible.
	 */
	 */
	if (!test_bit(Faulty, &rdev->flags) &&
	if (!test_bit(Faulty, &rdev->flags) &&
@@ -1778,13 +1778,16 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
		goto abort;
		goto abort;
	}
	}
	*rdevp = NULL;
	*rdevp = NULL;
	if (!test_bit(RemoveSynchronized, &rdev->flags)) {
		synchronize_rcu();
		synchronize_rcu();
		if (atomic_read(&rdev->nr_pending)) {
		if (atomic_read(&rdev->nr_pending)) {
			/* lost the race, try later */
			/* lost the race, try later */
			err = -EBUSY;
			err = -EBUSY;
			*rdevp = rdev;
			*rdevp = rdev;
			goto abort;
			goto abort;
	} else if (p->replacement) {
		}
	}
	if (p->replacement) {
		/* We must have just cleared 'rdev' */
		/* We must have just cleared 'rdev' */
		p->rdev = p->replacement;
		p->rdev = p->replacement;
		clear_bit(Replacement, &p->replacement->flags);
		clear_bit(Replacement, &p->replacement->flags);
Loading