]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
md: Ensure no IO request to get md device before it is properly initialised.
authorNeilBrown <neilb@suse.de>
Thu, 13 Jan 2011 22:14:33 +0000 (09:14 +1100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 17 Feb 2011 22:47:24 +0000 (14:47 -0800)
commit 0ca69886a8273ac1350143d562280bfcbe4760dc upstream.

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 409c57f3801 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.

Signed-off-by: NeilBrown <neilb@suse.de>
Reported-by: "Hawrylewicz Czarnowski, Przemyslaw" <przemyslaw.hawrylewicz.czarnowski@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/md/md.c
drivers/md/md.h

index 3b0e10ce9fa5da5b5e012f214b970fe456eee365..94bb484973a3281744090ecd34af679c3ec44bd2 100644 (file)
@@ -221,10 +221,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
        int rv;
        int cpu;
 
-       if (mddev == NULL || mddev->pers == NULL) {
+       if (mddev == NULL || mddev->pers == NULL
+           || !mddev->ready) {
                bio_io_error(bio);
                return 0;
        }
+       smp_rmb(); /* Ensure implications of  'active' are visible */
        rcu_read_lock();
        if (mddev->suspended || mddev->barrier) {
                DEFINE_WAIT(__wait);
@@ -4554,7 +4556,8 @@ int md_run(mddev_t *mddev)
        mddev->safemode_timer.data = (unsigned long) mddev;
        mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
        mddev->in_sync = 1;
-
+       smp_wmb();
+       mddev->ready = 1;
        list_for_each_entry(rdev, &mddev->disks, same_set)
                if (rdev->raid_disk >= 0) {
                        char nm[20];
@@ -4716,6 +4719,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes);
 
 void md_stop(mddev_t *mddev)
 {
+       mddev->ready = 0;
        mddev->pers->stop(mddev);
        if (mddev->pers->sync_request && mddev->to_remove == NULL)
                mddev->to_remove = &md_redundancy_group;
index 3931299788dcefe14385980c584321289cedc8db..563ede31d5fc7761bbce7fa14fbc0bb8386113e7 100644 (file)
@@ -149,7 +149,8 @@ struct mddev_s
                                                       * are happening, so run/
                                                       * takeover/stop are not safe
                                                       */
-
+       int                             ready; /* See when safe to pass
+                                               * IO requests down */
        struct gendisk                  *gendisk;
 
        struct kobject                  kobj;