RDMA/mlx5: Verify that DM operation is reasonable
[linux-2.6-microblaze.git] / drivers / md / md.c
index 21da0c4..49f897f 100644 (file)
@@ -734,78 +734,94 @@ void mddev_init(struct mddev *mddev)
 }
 EXPORT_SYMBOL_GPL(mddev_init);
 
+static struct mddev *mddev_find_locked(dev_t unit)
+{
+       struct mddev *mddev;
+
+       list_for_each_entry(mddev, &all_mddevs, all_mddevs)
+               if (mddev->unit == unit)
+                       return mddev;
+
+       return NULL;
+}
+
+/* find an unused unit number */
+static dev_t mddev_alloc_unit(void)
+{
+       static int next_minor = 512;
+       int start = next_minor;
+       bool is_free = 0;
+       dev_t dev = 0;
+
+       while (!is_free) {
+               dev = MKDEV(MD_MAJOR, next_minor);
+               next_minor++;
+               if (next_minor > MINORMASK)
+                       next_minor = 0;
+               if (next_minor == start)
+                       return 0;               /* Oh dear, all in use. */
+               is_free = !mddev_find_locked(dev);
+       }
+
+       return dev;
+}
+
 static struct mddev *mddev_find(dev_t unit)
 {
-       struct mddev *mddev, *new = NULL;
+       struct mddev *mddev;
 
-       if (unit && MAJOR(unit) != MD_MAJOR)
-               unit &= ~((1<<MdpMinorShift)-1);
+       if (MAJOR(unit) != MD_MAJOR)
+               unit &= ~((1 << MdpMinorShift) - 1);
 
- retry:
        spin_lock(&all_mddevs_lock);
+       mddev = mddev_find_locked(unit);
+       if (mddev)
+               mddev_get(mddev);
+       spin_unlock(&all_mddevs_lock);
 
-       if (unit) {
-               list_for_each_entry(mddev, &all_mddevs, all_mddevs)
-                       if (mddev->unit == unit) {
-                               mddev_get(mddev);
-                               spin_unlock(&all_mddevs_lock);
-                               kfree(new);
-                               return mddev;
-                       }
+       return mddev;
+}
 
-               if (new) {
-                       list_add(&new->all_mddevs, &all_mddevs);
-                       spin_unlock(&all_mddevs_lock);
-                       new->hold_active = UNTIL_IOCTL;
-                       return new;
-               }
-       } else if (new) {
-               /* find an unused unit number */
-               static int next_minor = 512;
-               int start = next_minor;
-               int is_free = 0;
-               int dev = 0;
-               while (!is_free) {
-                       dev = MKDEV(MD_MAJOR, next_minor);
-                       next_minor++;
-                       if (next_minor > MINORMASK)
-                               next_minor = 0;
-                       if (next_minor == start) {
-                               /* Oh dear, all in use. */
-                               spin_unlock(&all_mddevs_lock);
-                               kfree(new);
-                               return NULL;
-                       }
+static struct mddev *mddev_alloc(dev_t unit)
+{
+       struct mddev *new;
+       int error;
 
-                       is_free = 1;
-                       list_for_each_entry(mddev, &all_mddevs, all_mddevs)
-                               if (mddev->unit == dev) {
-                                       is_free = 0;
-                                       break;
-                               }
-               }
-               new->unit = dev;
-               new->md_minor = MINOR(dev);
-               new->hold_active = UNTIL_STOP;
-               list_add(&new->all_mddevs, &all_mddevs);
-               spin_unlock(&all_mddevs_lock);
-               return new;
-       }
-       spin_unlock(&all_mddevs_lock);
+       if (unit && MAJOR(unit) != MD_MAJOR)
+               unit &= ~((1 << MdpMinorShift) - 1);
 
        new = kzalloc(sizeof(*new), GFP_KERNEL);
        if (!new)
-               return NULL;
-
-       new->unit = unit;
-       if (MAJOR(unit) == MD_MAJOR)
-               new->md_minor = MINOR(unit);
-       else
-               new->md_minor = MINOR(unit) >> MdpMinorShift;
-
+               return ERR_PTR(-ENOMEM);
        mddev_init(new);
 
-       goto retry;
+       spin_lock(&all_mddevs_lock);
+       if (unit) {
+               error = -EEXIST;
+               if (mddev_find_locked(unit))
+                       goto out_free_new;
+               new->unit = unit;
+               if (MAJOR(unit) == MD_MAJOR)
+                       new->md_minor = MINOR(unit);
+               else
+                       new->md_minor = MINOR(unit) >> MdpMinorShift;
+               new->hold_active = UNTIL_IOCTL;
+       } else {
+               error = -ENODEV;
+               new->unit = mddev_alloc_unit();
+               if (!new->unit)
+                       goto out_free_new;
+               new->md_minor = MINOR(new->unit);
+               new->hold_active = UNTIL_STOP;
+       }
+
+       list_add(&new->all_mddevs, &all_mddevs);
+       spin_unlock(&all_mddevs_lock);
+       return new;
+out_free_new:
+       spin_unlock(&all_mddevs_lock);
+       kfree(new);
+       return ERR_PTR(error);
 }
 
 static struct attribute_group md_redundancy_group;
@@ -5644,29 +5660,29 @@ static int md_alloc(dev_t dev, char *name)
         * writing to /sys/module/md_mod/parameters/new_array.
         */
        static DEFINE_MUTEX(disks_mutex);
-       struct mddev *mddev = mddev_find(dev);
+       struct mddev *mddev;
        struct gendisk *disk;
        int partitioned;
        int shift;
        int unit;
-       int error;
+       int error ;
 
-       if (!mddev)
-               return -ENODEV;
-
-       partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
-       shift = partitioned ? MdpMinorShift : 0;
-       unit = MINOR(mddev->unit) >> shift;
-
-       /* wait for any previous instance of this device to be
-        * completely removed (mddev_delayed_delete).
+       /*
+        * Wait for any previous instance of this device to be completely
+        * removed (mddev_delayed_delete).
         */
        flush_workqueue(md_misc_wq);
 
        mutex_lock(&disks_mutex);
-       error = -EEXIST;
-       if (mddev->gendisk)
-               goto abort;
+       mddev = mddev_alloc(dev);
+       if (IS_ERR(mddev)) {
+               mutex_unlock(&disks_mutex);
+               return PTR_ERR(mddev);
+       }
+
+       partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
+       shift = partitioned ? MdpMinorShift : 0;
+       unit = MINOR(mddev->unit) >> shift;
 
        if (name && !dev) {
                /* Need to ensure that 'name' is not a duplicate.
@@ -5678,6 +5694,7 @@ static int md_alloc(dev_t dev, char *name)
                        if (mddev2->gendisk &&
                            strcmp(mddev2->gendisk->disk_name, name) == 0) {
                                spin_unlock(&all_mddevs_lock);
+                               error = -EEXIST;
                                goto abort;
                        }
                spin_unlock(&all_mddevs_lock);
@@ -6524,11 +6541,9 @@ static void autorun_devices(int part)
 
                md_probe(dev);
                mddev = mddev_find(dev);
-               if (!mddev || !mddev->gendisk) {
-                       if (mddev)
-                               mddev_put(mddev);
+               if (!mddev)
                        break;
-               }
+
                if (mddev_lock(mddev))
                        pr_warn("md: %s locked, cannot run\n", mdname(mddev));
                else if (mddev->raid_disks || mddev->major_version
@@ -7821,8 +7836,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
                /* Wait until bdev->bd_disk is definitely gone */
                if (work_pending(&mddev->del_work))
                        flush_workqueue(md_misc_wq);
-               /* Then retry the open from the top */
-               return -ERESTARTSYS;
+               return -EBUSY;
        }
        BUG_ON(mddev != bdev->bd_disk->private_data);
 
@@ -8153,7 +8167,11 @@ static void *md_seq_start(struct seq_file *seq, loff_t *pos)
        loff_t l = *pos;
        struct mddev *mddev;
 
-       if (l >= 0x10000)
+       if (l == 0x10000) {
+               ++*pos;
+               return (void *)2;
+       }
+       if (l > 0x10000)
                return NULL;
        if (!l--)
                /* header */
@@ -8575,6 +8593,26 @@ void md_write_end(struct mddev *mddev)
 
 EXPORT_SYMBOL(md_write_end);
 
+/* This is used by raid0 and raid10 */
+void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
+                       struct bio *bio, sector_t start, sector_t size)
+{
+       struct bio *discard_bio = NULL;
+
+       if (__blkdev_issue_discard(rdev->bdev, start, size, GFP_NOIO, 0,
+                       &discard_bio) || !discard_bio)
+               return;
+
+       bio_chain(discard_bio, bio);
+       bio_clone_blkg_association(discard_bio, bio);
+       if (mddev->gendisk)
+               trace_block_bio_remap(discard_bio,
+                               disk_devt(mddev->gendisk),
+                               bio->bi_iter.bi_sector);
+       submit_bio_noacct(discard_bio);
+}
+EXPORT_SYMBOL_GPL(md_submit_discard_bio);
+
 /* 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
@@ -9251,11 +9289,11 @@ void md_check_recovery(struct mddev *mddev)
                }
 
                if (mddev_is_clustered(mddev)) {
-                       struct md_rdev *rdev;
+                       struct md_rdev *rdev, *tmp;
                        /* kick the device if another node issued a
                         * remove disk.
                         */
-                       rdev_for_each(rdev, mddev) {
+                       rdev_for_each_safe(rdev, tmp, mddev) {
                                if (test_and_clear_bit(ClusterRemove, &rdev->flags) &&
                                                rdev->raid_disk < 0)
                                        md_kick_rdev_from_array(rdev);
@@ -9569,7 +9607,7 @@ err_wq:
 static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
 {
        struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
-       struct md_rdev *rdev2;
+       struct md_rdev *rdev2, *tmp;
        int role, ret;
        char b[BDEVNAME_SIZE];
 
@@ -9586,7 +9624,7 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
        }
 
        /* Check for change of roles in the active devices */
-       rdev_for_each(rdev2, mddev) {
+       rdev_for_each_safe(rdev2, tmp, mddev) {
                if (test_bit(Faulty, &rdev2->flags))
                        continue;