Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / drivers / md / md.c
index 21e2a7b0884157b8b3016c7a2ac8e74ebfd9fe76..e85fa75a7912e5c17879e819e21b835b22bce942 100644 (file)
@@ -1633,7 +1633,8 @@ repeat:
         * and 'events' is odd, we can roll back to the previous clean state */
        if (nospares
            && (mddev->in_sync && mddev->recovery_cp == MaxSector)
-           && (mddev->events & 1))
+           && (mddev->events & 1)
+           && mddev->events != 1)
                mddev->events--;
        else {
                /* otherwise we have to go forward and ... */
@@ -1792,7 +1793,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                else {
                        mddev_t *mddev = rdev->mddev;
                        kick_rdev_from_array(rdev);
-                       md_update_sb(mddev, 1);
+                       if (mddev->pers)
+                               md_update_sb(mddev, 1);
                        md_new_event(mddev);
                        err = 0;
                }
@@ -2004,6 +2006,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
 
        rdev->desc_nr = -1;
        rdev->saved_raid_disk = -1;
+       rdev->raid_disk = -1;
        rdev->flags = 0;
        rdev->data_offset = 0;
        rdev->sb_events = 0;
@@ -2233,7 +2236,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks);
 static ssize_t
 raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
 {
-       /* can only set raid_disks if array is not yet active */
        char *e;
        int rv = 0;
        unsigned long n = simple_strtoul(buf, &e, 10);
@@ -2631,7 +2633,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
                return -EINVAL;
        buf = e+1;
        minor = simple_strtoul(buf, &e, 10);
-       if (e==buf || *e != '\n')
+       if (e==buf || (*e && *e != '\n') )
                return -EINVAL;
        if (major >= sizeof(super_types)/sizeof(super_types[0]) ||
            super_types[major].name == NULL)
@@ -3562,6 +3564,8 @@ static int get_bitmap_file(mddev_t * mddev, void __user * arg)
        char *ptr, *buf = NULL;
        int err = -ENOMEM;
 
+       md_allow_write(mddev);
+
        file = kmalloc(sizeof(*file), GFP_KERNEL);
        if (!file)
                goto out;
@@ -3980,6 +3984,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
                mddev->major_version = info->major_version;
                mddev->minor_version = info->minor_version;
                mddev->patch_version = info->patch_version;
+               mddev->persistent = !info->not_persistent;
                return 0;
        }
        mddev->major_version = MD_MAJOR_VERSION;
@@ -4304,9 +4309,10 @@ static int md_ioctl(struct inode *inode, struct file *file,
         * Commands querying/configuring an existing array:
         */
        /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
-        * RUN_ARRAY, and SET_BITMAP_FILE are allowed */
+        * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
        if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
-                       && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE) {
+                       && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
+                       && cmd != GET_BITMAP_FILE) {
                err = -ENODEV;
                goto abort_unlock;
        }
@@ -4914,7 +4920,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
        return mask;
 }
 
-static struct file_operations md_seq_fops = {
+static const struct file_operations md_seq_fops = {
        .owner          = THIS_MODULE,
        .open           = md_seq_open,
        .read           = seq_read,
@@ -5028,6 +5034,33 @@ void md_write_end(mddev_t *mddev)
        }
 }
 
+/* md_allow_write(mddev)
+ * Calling this ensures that the array is marked 'active' so that writes
+ * may proceed without blocking.  It is important to call this before
+ * attempting a GFP_KERNEL allocation while holding the mddev lock.
+ * Must be called with mddev_lock held.
+ */
+void md_allow_write(mddev_t *mddev)
+{
+       if (!mddev->pers)
+               return;
+       if (mddev->ro)
+               return;
+
+       spin_lock_irq(&mddev->write_lock);
+       if (mddev->in_sync) {
+               mddev->in_sync = 0;
+               set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+               if (mddev->safemode_delay &&
+                   mddev->safemode == 0)
+                       mddev->safemode = 1;
+               spin_unlock_irq(&mddev->write_lock);
+               md_update_sb(mddev, 0);
+       } else
+               spin_unlock_irq(&mddev->write_lock);
+}
+EXPORT_SYMBOL_GPL(md_allow_write);
+
 static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
 
 #define SYNC_MARKS     10