Linus (et al), An md device need to know if it is in-use so that it doesn't allow raidstop while still mounted. Previously it did this by looking for a superblock on the device. This is a bit in-elegant and doesn't generalise. With this patch, it tracks opens and closes (get and release) and does not allow raidstop while there is any active access. This leaves open the possibility of syncing out the superblocks on the last close, which might happen in a later patch. One interesting gotcha in this patch is that the START_ARRAY ioctl (used by raidstart) can potentially start a completely different array, as it decides which array to start based on a value in the raid superblock. To get the reference counts right, I needed to tell the code which array I think I am starting. I it actually starts that one, it sets the initial reference count to 1, otherwise it sets it to 0. patch against 2.4.0-test12-pre8 NeilBrown --- ./include/linux/raid/md_k.h 2000/12/10 22:54:16 1.1 +++ ./include/linux/raid/md_k.h 2000/12/10 23:21:26 1.2 @@ -206,6 +206,7 @@ struct semaphore reconfig_sem; struct semaphore recovery_sem; struct semaphore resync_sem; + atomic_t active; atomic_t recovery_active; /* blocks scheduled, but not written */ md_wait_queue_head_t recovery_wait; --- ./drivers/md/md.c 2000/12/10 22:37:18 1.3 +++ ./drivers/md/md.c 2000/12/10 23:21:26 1.4 @@ -203,6 +203,7 @@ init_MUTEX(&mddev->resync_sem); MD_INIT_LIST_HEAD(&mddev->disks); MD_INIT_LIST_HEAD(&mddev->all_mddevs); + atomic_set(&mddev->active, 0); /* * The 'base' mddev is the one with data NULL. @@ -1718,12 +1719,20 @@ #define STILL_MOUNTED KERN_WARNING \ "md: md%d still mounted.\n" +#define STILL_IN_USE \ +"md: md%d still in use.\n" static int do_md_stop (mddev_t * mddev, int ro) { int err = 0, resync_interrupted = 0; kdev_t dev = mddev_to_kdev(mddev); + if (atomic_read(&mddev->active)>1) { + printk(STILL_IN_USE, mdidx(mddev)); + OUT(-EBUSY); + } + + /* this shouldn't be needed as above would have fired */ if (!ro && get_super(dev)) { printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); @@ -1859,8 +1868,10 @@ * the 'same_array' list. Then order this list based on superblock * update time (freshest comes first), kick out 'old' disks and * compare superblocks. If everything's fine then run it. + * + * If "unit" is allocated, then bump its reference count */ -static void autorun_devices (void) +static void autorun_devices (kdev_t countdev) { struct md_list_head candidates; struct md_list_head *tmp; @@ -1902,6 +1913,12 @@ continue; } mddev = alloc_mddev(md_kdev); + if (mddev == NULL) { + printk("md: cannot allocate memory for md drive.\n"); + break; + } + if (md_kdev == countdev) + atomic_inc(&mddev->active); printk("created md%d\n", mdidx(mddev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { bind_rdev_to_array(rdev, mddev); @@ -1945,7 +1962,7 @@ #define AUTORUNNING KERN_INFO \ "md: auto-running md%d.\n" -static int autostart_array (kdev_t startdev) +static int autostart_array (kdev_t startdev, kdev_t countdev) { int err = -EINVAL, i; mdp_super_t *sb = NULL; @@ -2002,7 +2019,7 @@ /* * possibly return codes */ - autorun_devices(); + autorun_devices(countdev); return 0; abort: @@ -2077,7 +2094,7 @@ md_list_add(&rdev->pending, &pending_raid_disks); } - autorun_devices(); + autorun_devices(-1); } dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */ @@ -2607,6 +2624,8 @@ err = -ENOMEM; goto abort; } + atomic_inc(&mddev->active); + /* * alloc_mddev() should possibly self-lock. */ @@ -2640,7 +2659,7 @@ /* * possibly make it lock the array ... */ - err = autostart_array((kdev_t)arg); + err = autostart_array((kdev_t)arg, dev); if (err) { printk("autostart %s failed!\n", partition_name((kdev_t)arg)); @@ -2820,14 +2839,26 @@ static int md_open (struct inode *inode, struct file *file) { /* - * Always succeed + * Always succeed, but increment the usage count */ + mddev_t *mddev = kdev_to_mddev(inode->i_rdev); + if (mddev) + atomic_inc(&mddev->active); return (0); } +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); + return 0; +} + static struct block_device_operations md_fops= { open: md_open, + release: md_release, ioctl: md_ioctl, }; - To unsubscribe from this list: send the line "unsubscribe linux-raid" in the body of a message to [EMAIL PROTECTED]