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