Skip to content

Commit

Permalink
md/linear: use call_rcu to free obsolete 'conf' structures.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
NeilBrown committed Jun 17, 2009
1 parent af11c39 commit 495d357
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 9 deletions.
21 changes: 13 additions & 8 deletions drivers/md/linear.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/linear.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};


Expand Down

0 comments on commit 495d357

Please sign in to comment.