Commit a9d0889a authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] md 13 of 22 - First step to tidying mddev recounting and locking.

First step to tidying mddev recounting and locking.

This patches introduces
  mddev_get   which incs the refcount on an mddev
  mddev_put   which decs it and, if it becomes unused, frees it
  mddev_find  which finds or allocated an mddev for a given minor
              This is mostly the old alloc_mddev


free_mddev no longer actually frees it.  It just disconnects all drives
so that mddev_put will do the free.

Now the test for "does an mddev exist" is not "mddev != NULL"
but involves checking if the mddev has disks or a superblock
attached.

This makes the semantics of do_md_stop a bit cleaner.  Previously
if do_md_stop succeed for a real stop (not a read-only stop) then
you didn't have to unlock the mddev, otherwise you did.  Now
you always unlock the mddev after do_md_stop.
parent 932db78f
......@@ -145,13 +145,30 @@ static int md_fail_request (request_queue_t *q, struct bio *bio)
return 0;
}
static mddev_t * alloc_mddev(kdev_t dev)
static inline mddev_t *mddev_get(mddev_t *mddev)
{
atomic_inc(&mddev->active);
return mddev;
}
static void mddev_put(mddev_t *mddev)
{
if (!atomic_dec_and_test(&mddev->active))
return;
if (!mddev->sb && list_empty(&mddev->disks)) {
list_del(&mddev->all_mddevs);
mddev_map[mdidx(mddev)] = NULL;
kfree(mddev);
MOD_DEC_USE_COUNT;
}
}
static mddev_t * mddev_find(int unit)
{
mddev_t *mddev;
if (major(dev) != MD_MAJOR) {
MD_BUG();
return 0;
if ((mddev = mddev_map[unit])) {
return mddev_get(mddev);
}
mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL);
if (!mddev)
......@@ -159,15 +176,15 @@ static mddev_t * alloc_mddev(kdev_t dev)
memset(mddev, 0, sizeof(*mddev));
mddev->__minor = minor(dev);
mddev->__minor = unit;
init_MUTEX(&mddev->reconfig_sem);
init_MUTEX(&mddev->recovery_sem);
init_MUTEX(&mddev->resync_sem);
INIT_LIST_HEAD(&mddev->disks);
INIT_LIST_HEAD(&mddev->all_mddevs);
atomic_set(&mddev->active, 0);
atomic_set(&mddev->active, 1);
mddev_map[mdidx(mddev)] = mddev;
mddev_map[unit] = mddev;
list_add(&mddev->all_mddevs, &all_mddevs);
MOD_INC_USE_COUNT;
......@@ -631,11 +648,6 @@ static void free_mddev(mddev_t *mddev)
schedule();
while (atomic_read(&mddev->recovery_sem.count) != 1)
schedule();
mddev_map[mdidx(mddev)] = NULL;
list_del(&mddev->all_mddevs);
kfree(mddev);
MOD_DEC_USE_COUNT;
}
#undef BAD_CSUM
......@@ -1803,8 +1815,6 @@ static void autorun_devices(kdev_t countdev)
struct list_head *tmp;
mdk_rdev_t *rdev0, *rdev;
mddev_t *mddev;
kdev_t md_kdev;
printk(KERN_INFO "md: autorun ...\n");
while (!list_empty(&pending_raid_disks)) {
......@@ -1831,28 +1841,31 @@ static void autorun_devices(kdev_t countdev)
* mostly sane superblocks. It's time to allocate the
* mddev.
*/
md_kdev = mk_kdev(MD_MAJOR, rdev0->sb->md_minor);
mddev = kdev_to_mddev(md_kdev);
if (mddev) {
mddev = mddev_find(rdev0->sb->md_minor);
if (!mddev) {
printk(KERN_ERR "md: cannot allocate memory for md drive.\n");
ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp)
export_rdev(rdev);
break;
}
if (mddev->sb || !list_empty(&mddev->disks)) {
printk(KERN_WARNING "md: md%d already running, cannot run %s\n",
mdidx(mddev), partition_name(rdev0->dev));
ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp)
export_rdev(rdev);
mddev_put(mddev);
continue;
}
mddev = alloc_mddev(md_kdev);
if (!mddev) {
printk(KERN_ERR "md: cannot allocate memory for md drive.\n");
break;
}
if (kdev_same(md_kdev, countdev))
atomic_inc(&mddev->active);
printk(KERN_INFO "md: created md%d\n", mdidx(mddev));
ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) {
bind_rdev_to_array(rdev, mddev);
list_del_init(&rdev->pending);
}
autorun_array(mddev);
if (minor(countdev) != mdidx(mddev))
mddev_put(mddev);
/* else put will happen at md_close time */
}
printk(KERN_INFO "md: ... autorun DONE.\n");
}
......@@ -2486,29 +2499,16 @@ static int md_ioctl(struct inode *inode, struct file *file,
* Commands creating/starting a new array:
*/
mddev = kdev_to_mddev(dev);
mddev = mddev_find(minor);
switch (cmd)
{
case SET_ARRAY_INFO:
case START_ARRAY:
if (mddev) {
printk(KERN_WARNING "md: array md%d already exists!\n",
mdidx(mddev));
err = -EEXIST;
goto abort;
}
default:;
if (!mddev) {
err = -ENOMEM;
goto abort;
}
switch (cmd)
{
case SET_ARRAY_INFO:
mddev = alloc_mddev(dev);
if (!mddev) {
err = -ENOMEM;
goto abort;
}
atomic_inc(&mddev->active);
/*
* alloc_mddev() should possibly self-lock.
......@@ -2519,7 +2519,12 @@ static int md_ioctl(struct inode *inode, struct file *file,
err, cmd);
goto abort;
}
if (!list_empty(&mddev->disks)) {
printk(KERN_WARNING "md: array md%d already has disks!\n",
mdidx(mddev));
err = -EBUSY;
goto abort_unlock;
}
if (mddev->sb) {
printk(KERN_WARNING "md: array md%d already has a superblock!\n",
mdidx(mddev));
......@@ -2559,10 +2564,6 @@ static int md_ioctl(struct inode *inode, struct file *file,
* Commands querying/configuring an existing array:
*/
if (!mddev) {
err = -ENODEV;
goto abort;
}
err = lock_mddev(mddev);
if (err) {
printk(KERN_INFO "md: ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
......@@ -2592,8 +2593,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
goto done_unlock;
case STOP_ARRAY:
if (!(err = do_md_stop (mddev, 0)))
mddev = NULL;
err = do_md_stop (mddev, 0);
goto done_unlock;
case STOP_ARRAY_RO:
......@@ -2672,8 +2672,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
*/
if (err) {
mddev->sb_dirty = 0;
if (!do_md_stop (mddev, 0))
mddev = NULL;
do_md_stop (mddev, 0);
}
goto done_unlock;
}
......@@ -2688,8 +2687,8 @@ static int md_ioctl(struct inode *inode, struct file *file,
done_unlock:
abort_unlock:
if (mddev)
unlock_mddev(mddev);
unlock_mddev(mddev);
mddev_put(mddev);
return err;
done:
......@@ -2706,7 +2705,7 @@ static int md_open(struct inode *inode, struct file *file)
*/
mddev_t *mddev = kdev_to_mddev(inode->i_rdev);
if (mddev)
atomic_inc(&mddev->active);
mddev_get(mddev);
return (0);
}
......@@ -2714,7 +2713,7 @@ static int md_release(struct inode *inode, struct file * file)
{
mddev_t *mddev = kdev_to_mddev(inode->i_rdev);
if (mddev)
atomic_dec(&mddev->active);
mddev_put(mddev);
return 0;
}
......@@ -3688,19 +3687,20 @@ void __init md_setup_drive(void)
if (!md_setup_args.device_set[minor])
continue;
if (mddev_map[minor]) {
printk(KERN_WARNING
"md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
minor);
continue;
}
printk(KERN_INFO "md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]);
mddev = alloc_mddev(mk_kdev(MD_MAJOR,minor));
mddev = mddev_find(minor);
if (!mddev) {
printk(KERN_ERR "md: kmalloc failed - cannot start array %d\n", minor);
continue;
}
if (mddev->sb || !list_empty(&mddev->disks)) {
printk(KERN_WARNING
"md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
minor);
mddev_put(mddev);
continue;
}
if (md_setup_args.pers[minor]) {
/* non-persistent */
mdu_array_info_t ainfo;
......@@ -3752,6 +3752,7 @@ void __init md_setup_drive(void)
do_md_stop(mddev, 0);
printk(KERN_WARNING "md: starting md%d failed\n", minor);
}
mddev_put(mddev);
}
}
......
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