]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
md/linear: use call_rcu to free obsolete 'conf' structures.
authorNeilBrown <neilb@suse.de>
Wed, 17 Jun 2009 22:49:42 +0000 (08:49 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 17 Jun 2009 22:49:42 +0000 (08:49 +1000)
Current, when we update the 'conf' structure, when adding a
drive to a linear array, we keep the old version around until
the array is finally stopped, as it is not safe to free it
immediately.

Now that we have rcu protection on all accesses to 'conf',
we can use call_rcu to free it more promptly.

Signed-off-by: NeilBrown <neilb@suse.de>
drivers/md/linear.c
drivers/md/linear.h

index 93f2b1d183985945f41226af8a808f999c49810b..15c8b7b25a9b9a053a7296e0ab7abc91efa88e05 100644 (file)
@@ -223,6 +223,12 @@ static int linear_run (mddev_t *mddev)
        return 0;
 }
 
+static void free_conf(struct rcu_head *head)
+{
+       linear_conf_t *conf = container_of(head, linear_conf_t, rcu);
+       kfree(conf);
+}
+
 static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
 {
        /* Adding a drive to a linear array allows the array to grow.
@@ -233,7 +239,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
         * The current one is never freed until the array is stopped.
         * This avoids races.
         */
-       linear_conf_t *newconf;
+       linear_conf_t *newconf, *oldconf;
 
        if (rdev->saved_raid_disk != mddev->raid_disks)
                return -EINVAL;
@@ -245,11 +251,12 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
        if (!newconf)
                return -ENOMEM;
 
-       newconf->prev = mddev->private;
+       oldconf = rcu_dereference(mddev->private);
        mddev->raid_disks++;
        rcu_assign_pointer(mddev->private, newconf);
        md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
        set_capacity(mddev->gendisk, mddev->array_sectors);
+       call_rcu(&oldconf->rcu, free_conf);
        return 0;
 }
 
@@ -261,14 +268,12 @@ static int linear_stop (mddev_t *mddev)
         * We do not require rcu protection here since
         * we hold reconfig_mutex for both linear_add and
         * linear_stop, so they cannot race.
+        * We should make sure any old 'conf's are properly
+        * freed though.
         */
-
+       rcu_barrier();
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
-       do {
-               linear_conf_t *t = conf->prev;
-               kfree(conf);
-               conf = t;
-       } while (conf);
+       kfree(conf);
 
        return 0;
 }
index 599e5c1bbb018c75a0893b1d0d4f1012079cd4b2..0ce29b61605a29904608c43a1cf57d87c6f25d43 100644 (file)
@@ -10,9 +10,9 @@ typedef struct dev_info dev_info_t;
 
 struct linear_private_data
 {
-       struct linear_private_data *prev;       /* earlier version */
        sector_t                array_sectors;
        dev_info_t              disks[0];
+       struct rcu_head         rcu;
 };