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]

Reply via email to