md: set mddev readonly flag on blkdev BLKROSET ioctl
authorDan Williams <dan.j.williams@intel.com>
Tue, 11 May 2010 22:25:37 +0000 (08:25 +1000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 5 Jul 2010 18:08:44 +0000 (11:08 -0700)
commit e2218350465e7e0931676b4849b594c978437bce upstream.

When the user sets the block device to readwrite then the mddev should
follow suit.  Otherwise, the BUG_ON in md_write_start() will be set to
trigger.

The reverse direction, setting mddev->ro to match a set readonly
request, can be ignored because the blkdev level readonly flag precludes
the need to have mddev->ro set correctly.  Nevermind the fact that
setting mddev->ro to 1 may fail if the array is in use.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/md/md.c

index b60d328f6b1ead3a8ee3ba6275843785d9170ddd..4d96950c4b2d26382a412664dd61464568e00c05 100644 (file)
@@ -4816,6 +4816,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
        int err = 0;
        void __user *argp = (void __user *)arg;
        mddev_t *mddev = NULL;
+       int ro;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -4951,6 +4952,34 @@ static int md_ioctl(struct inode *inode, struct file *file,
                        err = do_md_stop (mddev, 1, 1);
                        goto done_unlock;
 
+               case BLKROSET:
+                       if (get_user(ro, (int __user *)(arg))) {
+                               err = -EFAULT;
+                               goto done_unlock;
+                       }
+                       err = -EINVAL;
+
+                       /* if the bdev is going readonly the value of mddev->ro
+                        * does not matter, no writes are coming
+                        */
+                       if (ro)
+                               goto done_unlock;
+
+                       /* are we are already prepared for writes? */
+                       if (mddev->ro != 1)
+                               goto done_unlock;
+
+                       /* transitioning to readauto need only happen for
+                        * arrays that call md_write_start
+                        */
+                       if (mddev->pers) {
+                               err = restart_array(mddev);
+                               if (err == 0) {
+                                       mddev->ro = 2;
+                                       set_disk_ro(mddev->gendisk, 0);
+                               }
+                       }
+                       goto done_unlock;
        }
 
        /*