]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
md: Fix - again - partition detection when array becomes active
authorNeilBrown <neilb@suse.de>
Thu, 24 Feb 2011 06:26:41 +0000 (17:26 +1100)
committerAK <andi@firstfloor.org>
Thu, 31 Mar 2011 18:58:54 +0000 (11:58 -0700)
[ upstream commit f0b4f7e2f29af678bd9af43422c537dcb6008603 ]

Revert
    b821eaa572fd737faaf6928ba046e571526c36c6
and
    f3b99be19ded511a1bf05a148276239d9f13eefa

When I wrote the first of these I had a wrong idea about the
lifetime of 'struct block_device'.  It can disappear at any time that
the block device is not open if it falls out of the inode cache.

So relying on the 'size' recorded with it to detect when the
device size has changed and so we need to revalidate, is wrong.

Rather, we really do need the 'changed' attribute stored directly in
the mddev and set/tested as appropriate.

Without this patch, a sequence of:
   mknod / open / close / unlink

(which can cause a block_device to be created and then destroyed)
will result in a rescan of the partition table and consequence removal
and addition of partitions.
Several of these in a row can get udev racing to create and unlink and
other code can get confused.

With the patch, the rescan is only performed when needed and so there
are no races.

This is suitable for any stable kernel from 2.6.35.

Reported-by: "Wojcik, Krzysztof" <krzysztof.wojcik@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: stable@kernel.org
drivers/md/md.c
drivers/md/md.h

index ff1b20d4cf5f19f57b3084ffe8afda9431ac5e16..9ec74cc604f0fe84192495a42546abd4ac1342db 100644 (file)
@@ -4550,6 +4550,7 @@ static int do_md_run(mddev_t *mddev)
 
        set_capacity(mddev->gendisk, mddev->array_sectors);
        revalidate_disk(mddev->gendisk);
+       mddev->changed = 1;
        kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
 out:
        return err;
@@ -4638,6 +4639,7 @@ static void md_clean(mddev_t *mddev)
        mddev->sync_speed_min = mddev->sync_speed_max = 0;
        mddev->recovery = 0;
        mddev->in_sync = 0;
+       mddev->changed = 0;
        mddev->degraded = 0;
        mddev->barriers_work = 0;
        mddev->safemode = 0;
@@ -4744,6 +4746,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
 
                set_capacity(disk, 0);
                revalidate = 1;
+               mddev->changed = 1;
 
                if (mddev->ro)
                        mddev->ro = 0;
@@ -5930,7 +5933,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);
+       check_disk_change(bdev);
  out:
        return err;
 }
@@ -5945,6 +5948,21 @@ static int md_release(struct gendisk *disk, fmode_t mode)
 
        return 0;
 }
+
+static int md_media_changed(struct gendisk *disk)
+{
+       mddev_t *mddev = disk->private_data;
+
+       return mddev->changed;
+}
+
+static int md_revalidate(struct gendisk *disk)
+{
+       mddev_t *mddev = disk->private_data;
+
+       mddev->changed = 0;
+       return 0;
+}
 static const struct block_device_operations md_fops =
 {
        .owner          = THIS_MODULE,
@@ -5955,6 +5973,8 @@ static const struct block_device_operations md_fops =
        .compat_ioctl   = md_compat_ioctl,
 #endif
        .getgeo         = md_getgeo,
+       .media_changed  = md_media_changed,
+       .revalidate_disk= md_revalidate,
 };
 
 static int md_thread(void * arg)
index 9ec208e11fbf8fbae57679d4e5d375f553ee36e5..2e2a3c26c8f8fb4b1715042237c07526abe26f74 100644 (file)
@@ -250,6 +250,8 @@ struct mddev_s
        atomic_t                        active;         /* general refcount */
        atomic_t                        openers;        /* number of active opens */
 
+       int                             changed;        /* True if we might need to
+                                                        * reread partition info */
        int                             degraded;       /* whether md should consider
                                                         * adding a spare
                                                         */