Merge master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
[safe/jmp/linux-2.6] / drivers / md / md.c
index 3ce7a5d..2b4315d 100644 (file)
@@ -1296,27 +1296,17 @@ static struct super_type super_types[] = {
                .sync_super     = super_1_sync,
        },
 };
-       
-static mdk_rdev_t * match_dev_unit(mddev_t *mddev, mdk_rdev_t *dev)
-{
-       struct list_head *tmp;
-       mdk_rdev_t *rdev;
-
-       ITERATE_RDEV(mddev,rdev,tmp)
-               if (rdev->bdev->bd_contains == dev->bdev->bd_contains)
-                       return rdev;
-
-       return NULL;
-}
 
 static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
 {
-       struct list_head *tmp;
-       mdk_rdev_t *rdev;
+       struct list_head *tmp, *tmp2;
+       mdk_rdev_t *rdev, *rdev2;
 
        ITERATE_RDEV(mddev1,rdev,tmp)
-               if (match_dev_unit(mddev2, rdev))
-                       return 1;
+               ITERATE_RDEV(mddev2, rdev2, tmp2)
+                       if (rdev->bdev->bd_contains ==
+                           rdev2->bdev->bd_contains)
+                               return 1;
 
        return 0;
 }
@@ -1325,10 +1315,10 @@ static LIST_HEAD(pending_raid_disks);
 
 static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 {
-       mdk_rdev_t *same_pdev;
-       char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
+       char b[BDEVNAME_SIZE];
        struct kobject *ko;
        char *s;
+       int err;
 
        if (rdev->mddev) {
                MD_BUG();
@@ -1342,14 +1332,6 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                else
                        mddev->size = rdev->size;
        }
-       same_pdev = match_dev_unit(mddev, rdev);
-       if (same_pdev)
-               printk(KERN_WARNING
-                       "%s: WARNING: %s appears to be on the same physical"
-                       " disk as %s. True\n     protection against single-disk"
-                       " failure might be compromised.\n",
-                       mdname(mddev), bdevname(rdev->bdev,b),
-                       bdevname(same_pdev->bdev,b2));
 
        /* Verify rdev->desc_nr is unique.
         * If it is -1, assign a free number, else
@@ -1371,20 +1353,35 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
        while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL)
                *s = '!';
                        
-       list_add(&rdev->same_set, &mddev->disks);
        rdev->mddev = mddev;
        printk(KERN_INFO "md: bind<%s>\n", b);
 
        rdev->kobj.parent = &mddev->kobj;
-       kobject_add(&rdev->kobj);
+       if ((err = kobject_add(&rdev->kobj)))
+               goto fail;
 
        if (rdev->bdev->bd_part)
                ko = &rdev->bdev->bd_part->kobj;
        else
                ko = &rdev->bdev->bd_disk->kobj;
-       sysfs_create_link(&rdev->kobj, ko, "block");
+       if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
+               kobject_del(&rdev->kobj);
+               goto fail;
+       }
+       list_add(&rdev->same_set, &mddev->disks);
        bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
        return 0;
+
+ fail:
+       printk(KERN_WARNING "md: failed to register dev-%s for %s\n",
+              b, mdname(mddev));
+       return err;
+}
+
+static void delayed_delete(struct work_struct *ws)
+{
+       mdk_rdev_t *rdev = container_of(ws, mdk_rdev_t, del_work);
+       kobject_del(&rdev->kobj);
 }
 
 static void unbind_rdev_from_array(mdk_rdev_t * rdev)
@@ -1399,7 +1396,12 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
        printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
        rdev->mddev = NULL;
        sysfs_remove_link(&rdev->kobj, "block");
-       kobject_del(&rdev->kobj);
+
+       /* We need to delay this, otherwise we can deadlock when
+        * writing to 'remove' to "dev/state"
+        */
+       INIT_WORK(&rdev->del_work, delayed_delete);
+       schedule_work(&rdev->del_work);
 }
 
 /*
@@ -1633,7 +1635,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 +1795,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 +2008,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 +2238,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 +2635,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)
@@ -2983,7 +2987,9 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
        mddev->kobj.k_name = NULL;
        snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
        mddev->kobj.ktype = &md_ktype;
-       kobject_register(&mddev->kobj);
+       if (kobject_register(&mddev->kobj))
+               printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
+                      disk->disk_name);
        return NULL;
 }
 
@@ -3074,7 +3080,7 @@ static int do_md_run(mddev_t * mddev)
                if (test_bit(Faulty, &rdev->flags))
                        continue;
                sync_blockdev(rdev->bdev);
-               invalidate_bdev(rdev->bdev, 0);
+               invalidate_bdev(rdev->bdev);
        }
 
        md_probe(mddev->unit, NULL, NULL);
@@ -3107,6 +3113,36 @@ static int do_md_run(mddev_t * mddev)
                return -EINVAL;
        }
 
+       if (pers->sync_request) {
+               /* Warn if this is a potentially silly
+                * configuration.
+                */
+               char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
+               mdk_rdev_t *rdev2;
+               struct list_head *tmp2;
+               int warned = 0;
+               ITERATE_RDEV(mddev, rdev, tmp) {
+                       ITERATE_RDEV(mddev, rdev2, tmp2) {
+                               if (rdev < rdev2 &&
+                                   rdev->bdev->bd_contains ==
+                                   rdev2->bdev->bd_contains) {
+                                       printk(KERN_WARNING
+                                              "%s: WARNING: %s appears to be"
+                                              " on the same physical disk as"
+                                              " %s.\n",
+                                              mdname(mddev),
+                                              bdevname(rdev->bdev,b),
+                                              bdevname(rdev2->bdev,b2));
+                                       warned = 1;
+                               }
+                       }
+               }
+               if (warned)
+                       printk(KERN_WARNING
+                              "True protection against single-disk"
+                              " failure might be compromised.\n");
+       }
+
        mddev->recovery = 0;
        mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
        mddev->barriers_work = 1;
@@ -3131,9 +3167,12 @@ static int do_md_run(mddev_t * mddev)
                bitmap_destroy(mddev);
                return err;
        }
-       if (mddev->pers->sync_request)
-               sysfs_create_group(&mddev->kobj, &md_redundancy_group);
-       else if (mddev->ro == 2) /* auto-readonly not meaningful */
+       if (mddev->pers->sync_request) {
+               if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
+                       printk(KERN_WARNING
+                              "md: cannot register extra attributes for %s\n",
+                              mdname(mddev));
+       } else if (mddev->ro == 2) /* auto-readonly not meaningful */
                mddev->ro = 0;
 
        atomic_set(&mddev->writes_pending,0);
@@ -3147,7 +3186,9 @@ static int do_md_run(mddev_t * mddev)
                if (rdev->raid_disk >= 0) {
                        char nm[20];
                        sprintf(nm, "rd%d", rdev->raid_disk);
-                       sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
+                       if (sysfs_create_link(&mddev->kobj, &rdev->kobj, nm))
+                               printk("md: cannot register %s for %s\n",
+                                      nm, mdname(mddev));
                }
        
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -3309,11 +3350,19 @@ static int do_md_stop(mddev_t * mddev, int mode)
                                set_disk_ro(disk, 0);
                        blk_queue_make_request(mddev->queue, md_fail_request);
                        mddev->pers->stop(mddev);
+                       mddev->queue->merge_bvec_fn = NULL;
+                       mddev->queue->unplug_fn = NULL;
+                       mddev->queue->issue_flush_fn = NULL;
+                       mddev->queue->backing_dev_info.congested_fn = NULL;
                        if (mddev->pers->sync_request)
                                sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
 
                        module_put(mddev->pers->owner);
                        mddev->pers = NULL;
+
+                       set_capacity(disk, 0);
+                       mddev->changed = 1;
+
                        if (mddev->ro)
                                mddev->ro = 0;
                }
@@ -3333,7 +3382,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
        if (mode == 0) {
                mdk_rdev_t *rdev;
                struct list_head *tmp;
-               struct gendisk *disk;
+
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
                bitmap_destroy(mddev);
@@ -3351,6 +3400,9 @@ static int do_md_stop(mddev_t * mddev, int mode)
                                sysfs_remove_link(&mddev->kobj, nm);
                        }
 
+               /* make sure all delayed_delete calls have finished */
+               flush_scheduled_work();
+
                export_array(mddev);
 
                mddev->array_size = 0;
@@ -3358,10 +3410,6 @@ static int do_md_stop(mddev_t * mddev, int mode)
                mddev->raid_disks = 0;
                mddev->recovery_cp = 0;
 
-               disk = mddev->gendisk;
-               if (disk)
-                       set_capacity(disk, 0);
-               mddev->changed = 1;
        } else if (mddev->pers)
                printk(KERN_INFO "md: %s switched to read-only mode.\n",
                        mdname(mddev));
@@ -3371,6 +3419,7 @@ out:
        return err;
 }
 
+#ifndef MODULE
 static void autorun_array(mddev_t *mddev)
 {
        mdk_rdev_t *rdev;
@@ -3485,6 +3534,7 @@ static void autorun_devices(int part)
        }
        printk(KERN_INFO "md: ... autorun DONE.\n");
 }
+#endif /* !MODULE */
 
 static int get_version(void __user * arg)
 {
@@ -3560,6 +3610,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;
@@ -3722,6 +3774,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                if (err)
                        export_rdev(rdev);
 
+               md_update_sb(mddev, 1);
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                md_wakeup_thread(mddev->thread);
                return err;
@@ -3977,6 +4030,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;
@@ -4301,9 +4355,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;
        }
@@ -4846,8 +4901,8 @@ static int md_seq_show(struct seq_file *seq, void *v)
                                chunk_kb ? "KB" : "B");
                        if (bitmap->file) {
                                seq_printf(seq, ", file: ");
-                               seq_path(seq, bitmap->file->f_vfsmnt,
-                                        bitmap->file->f_dentry," \t\n");
+                               seq_path(seq, bitmap->file->f_path.mnt,
+                                        bitmap->file->f_path.dentry," \t\n");
                        }
 
                        seq_printf(seq, "\n");
@@ -4911,7 +4966,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,
@@ -5025,6 +5080,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
@@ -5273,7 +5355,6 @@ void md_do_sync(mddev_t *mddev)
        mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
 
        if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
-           test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
            !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
            mddev->curr_resync > 2) {
                if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
@@ -5297,6 +5378,7 @@ void md_do_sync(mddev_t *mddev)
                                        rdev->recovery_offset = mddev->curr_resync;
                }
        }
+       set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
  skip:
        mddev->curr_resync = 0;
@@ -5307,6 +5389,48 @@ void md_do_sync(mddev_t *mddev)
 EXPORT_SYMBOL_GPL(md_do_sync);
 
 
+static int remove_and_add_spares(mddev_t *mddev)
+{
+       mdk_rdev_t *rdev;
+       struct list_head *rtmp;
+       int spares = 0;
+
+       ITERATE_RDEV(mddev,rdev,rtmp)
+               if (rdev->raid_disk >= 0 &&
+                   (test_bit(Faulty, &rdev->flags) ||
+                    ! test_bit(In_sync, &rdev->flags)) &&
+                   atomic_read(&rdev->nr_pending)==0) {
+                       if (mddev->pers->hot_remove_disk(
+                                   mddev, rdev->raid_disk)==0) {
+                               char nm[20];
+                               sprintf(nm,"rd%d", rdev->raid_disk);
+                               sysfs_remove_link(&mddev->kobj, nm);
+                               rdev->raid_disk = -1;
+                       }
+               }
+
+       if (mddev->degraded) {
+               ITERATE_RDEV(mddev,rdev,rtmp)
+                       if (rdev->raid_disk < 0
+                           && !test_bit(Faulty, &rdev->flags)) {
+                               rdev->recovery_offset = 0;
+                               if (mddev->pers->hot_add_disk(mddev,rdev)) {
+                                       char nm[20];
+                                       sprintf(nm, "rd%d", rdev->raid_disk);
+                                       if (sysfs_create_link(&mddev->kobj,
+                                                             &rdev->kobj, nm))
+                                               printk(KERN_WARNING
+                                                      "md: cannot register "
+                                                      "%s for %s\n",
+                                                      nm, mdname(mddev));
+                                       spares++;
+                                       md_new_event(mddev);
+                               } else
+                                       break;
+                       }
+       }
+       return spares;
+}
 /*
  * This routine is regularly called by all per-raid-array threads to
  * deal with generic issues like resync and super-block update.
@@ -5361,7 +5485,7 @@ void md_check_recovery(mddev_t *mddev)
                return;
 
        if (mddev_trylock(mddev)) {
-               int spares =0;
+               int spares = 0;
 
                spin_lock_irq(&mddev->write_lock);
                if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
@@ -5424,35 +5548,13 @@ void md_check_recovery(mddev_t *mddev)
                 * Spare are also removed and re-added, to allow
                 * the personality to fail the re-add.
                 */
-               ITERATE_RDEV(mddev,rdev,rtmp)
-                       if (rdev->raid_disk >= 0 &&
-                           (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) &&
-                           atomic_read(&rdev->nr_pending)==0) {
-                               if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) {
-                                       char nm[20];
-                                       sprintf(nm,"rd%d", rdev->raid_disk);
-                                       sysfs_remove_link(&mddev->kobj, nm);
-                                       rdev->raid_disk = -1;
-                               }
-                       }
 
-               if (mddev->degraded) {
-                       ITERATE_RDEV(mddev,rdev,rtmp)
-                               if (rdev->raid_disk < 0
-                                   && !test_bit(Faulty, &rdev->flags)) {
-                                       rdev->recovery_offset = 0;
-                                       if (mddev->pers->hot_add_disk(mddev,rdev)) {
-                                               char nm[20];
-                                               sprintf(nm, "rd%d", rdev->raid_disk);
-                                               sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
-                                               spares++;
-                                               md_new_event(mddev);
-                                       } else
-                                               break;
-                               }
-               }
-
-               if (spares) {
+               if (mddev->reshape_position != MaxSector) {
+                       if (mddev->pers->check_reshape(mddev) != 0)
+                               /* Cannot proceed */
+                               goto unlock;
+                       set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+               } else if ((spares = remove_and_add_spares(mddev))) {
                        clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                        clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                } else if (mddev->recovery_cp < MaxSector) {
@@ -5545,7 +5647,7 @@ static int __init md_init(void)
                            md_probe, NULL, NULL);
 
        register_reboot_notifier(&md_notifier);
-       raid_table_header = register_sysctl_table(raid_root_table, 1);
+       raid_table_header = register_sysctl_table(raid_root_table);
 
        md_geninit();
        return (0);
@@ -5593,7 +5695,7 @@ static void autostart_arrays(int part)
        autorun_devices(part);
 }
 
-#endif
+#endif /* !MODULE */
 
 static __exit void md_exit(void)
 {