Commit 0ca69886 authored by NeilBrown's avatar NeilBrown

md: Ensure no IO request to get md device before it is properly initialised.

When an md device is in the process of coming on line it is possible
for an IO request (typically a partition table probe) to get through
before the array is fully initialised, which can cause unexpected
behaviour (e.g. a crash).

So explicitly record when the array is ready for IO and don't allow IO
through until then.

There is no possibility for a similar problem when the array is going
off-line as there must only be one 'open' at that time, and it is busy
off-lining the array and so cannot send IO requests.  So no memory
barrier is needed in md_stop()

This has been a bug since commit 409c57f3 in 2.6.30 which
introduced md_make_request.  Before then, each personality would
register its own make_request_fn when it was ready.
This is suitable for any stable kernel from 2.6.30.y onwards.

Cc: <stable@kernel.org>
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Reported-by: default avatar"Hawrylewicz Czarnowski, Przemyslaw" <przemyslaw.hawrylewicz.czarnowski@intel.com>
parent 067032bc
...@@ -288,10 +288,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio) ...@@ -288,10 +288,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
int rv; int rv;
int cpu; int cpu;
if (mddev == NULL || mddev->pers == NULL) { if (mddev == NULL || mddev->pers == NULL
|| !mddev->ready) {
bio_io_error(bio); bio_io_error(bio);
return 0; return 0;
} }
smp_rmb(); /* Ensure implications of 'active' are visible */
rcu_read_lock(); rcu_read_lock();
if (mddev->suspended) { if (mddev->suspended) {
DEFINE_WAIT(__wait); DEFINE_WAIT(__wait);
...@@ -4564,7 +4566,8 @@ int md_run(mddev_t *mddev) ...@@ -4564,7 +4566,8 @@ int md_run(mddev_t *mddev)
mddev->safemode_timer.data = (unsigned long) mddev; mddev->safemode_timer.data = (unsigned long) mddev;
mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1; mddev->in_sync = 1;
smp_wmb();
mddev->ready = 1;
list_for_each_entry(rdev, &mddev->disks, same_set) list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0) { if (rdev->raid_disk >= 0) {
char nm[20]; char nm[20];
...@@ -4725,6 +4728,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes); ...@@ -4725,6 +4728,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes);
void md_stop(mddev_t *mddev) void md_stop(mddev_t *mddev)
{ {
mddev->ready = 0;
mddev->pers->stop(mddev); mddev->pers->stop(mddev);
if (mddev->pers->sync_request && mddev->to_remove == NULL) if (mddev->pers->sync_request && mddev->to_remove == NULL)
mddev->to_remove = &md_redundancy_group; mddev->to_remove = &md_redundancy_group;
......
...@@ -148,7 +148,8 @@ struct mddev_s ...@@ -148,7 +148,8 @@ struct mddev_s
* are happening, so run/ * are happening, so run/
* takeover/stop are not safe * takeover/stop are not safe
*/ */
int ready; /* See when safe to pass
* IO requests down */
struct gendisk *gendisk; struct gendisk *gendisk;
struct kobject kobj; struct kobject kobj;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment