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)
committerNeilBrown <neilb@suse.de>
Tue, 11 May 2010 22:25:37 +0000 (08:25 +1000)
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.

Cc: <stable@kernel.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
drivers/md/md.c

index a20a71e..08f6651 100644 (file)
@@ -5489,6 +5489,7 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
        int err = 0;
        void __user *argp = (void __user *)arg;
        mddev_t *mddev = NULL;
+       int ro;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -5624,6 +5625,34 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                        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;
        }
 
        /*