Merge branch 'for-linus' of git://neil.brown.name/md
[sfrench/cifs-2.6.git] / drivers / md / md.c
index 9d4e44e460e9c15197a95c65a4ce61f07867978e..11567c7999a243d3d95ebecdb623c26de49705ce 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/blkdev.h>
 #include <linux/sysctl.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/poll.h>
 #include <linux/ctype.h>
@@ -355,7 +356,7 @@ static void md_submit_barrier(struct work_struct *ws)
                /* an empty barrier - all done */
                bio_endio(bio, 0);
        else {
-               bio->bi_rw &= ~(1<<BIO_RW_BARRIER);
+               bio->bi_rw &= ~REQ_HARDBARRIER;
                if (mddev->pers->make_request(mddev, bio))
                        generic_make_request(bio);
                mddev->barrier = POST_REQUEST_BARRIER;
@@ -580,13 +581,17 @@ static void mddev_unlock(mddev_t * mddev)
                 * an access to the files will try to take reconfig_mutex
                 * while holding the file unremovable, which leads to
                 * a deadlock.
-                * So hold open_mutex instead - we are allowed to take
-                * it while holding reconfig_mutex, and md_run can
-                * use it to wait for the remove to complete.
+                * So hold set sysfs_active while the remove in happeing,
+                * and anything else which might set ->to_remove or my
+                * otherwise change the sysfs namespace will fail with
+                * -EBUSY if sysfs_active is still set.
+                * We set sysfs_active under reconfig_mutex and elsewhere
+                * test it under the same mutex to ensure its correct value
+                * is seen.
                 */
                struct attribute_group *to_remove = mddev->to_remove;
                mddev->to_remove = NULL;
-               mutex_lock(&mddev->open_mutex);
+               mddev->sysfs_active = 1;
                mutex_unlock(&mddev->reconfig_mutex);
 
                if (mddev->kobj.sd) {
@@ -600,7 +605,7 @@ static void mddev_unlock(mddev_t * mddev)
                                mddev->sysfs_action = NULL;
                        }
                }
-               mutex_unlock(&mddev->open_mutex);
+               mddev->sysfs_active = 0;
        } else
                mutex_unlock(&mddev->reconfig_mutex);
 
@@ -725,11 +730,11 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
         * if zero is reached.
         * If an error occurred, call md_error
         *
-        * As we might need to resubmit the request if BIO_RW_BARRIER
+        * As we might need to resubmit the request if REQ_HARDBARRIER
         * causes ENOTSUPP, we allocate a spare bio...
         */
        struct bio *bio = bio_alloc(GFP_NOIO, 1);
-       int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNCIO) | (1<<BIO_RW_UNPLUG);
+       int rw = REQ_WRITE | REQ_SYNC | REQ_UNPLUG;
 
        bio->bi_bdev = rdev->bdev;
        bio->bi_sector = sector;
@@ -741,7 +746,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
        atomic_inc(&mddev->pending_writes);
        if (!test_bit(BarriersNotsupp, &rdev->flags)) {
                struct bio *rbio;
-               rw |= (1<<BIO_RW_BARRIER);
+               rw |= REQ_HARDBARRIER;
                rbio = bio_clone(bio, GFP_NOIO);
                rbio->bi_private = bio;
                rbio->bi_end_io = super_written_barrier;
@@ -786,7 +791,7 @@ int sync_page_io(struct block_device *bdev, sector_t sector, int size,
        struct completion event;
        int ret;
 
-       rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
+       rw |= REQ_SYNC | REQ_UNPLUG;
 
        bio->bi_bdev = bdev;
        bio->bi_sector = sector;
@@ -3008,7 +3013,9 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
         *  - new personality will access other array.
         */
 
-       if (mddev->sync_thread || mddev->reshape_position != MaxSector)
+       if (mddev->sync_thread ||
+           mddev->reshape_position != MaxSector ||
+           mddev->sysfs_active)
                return -EBUSY;
 
        if (!mddev->pers->quiesce) {
@@ -4393,13 +4400,9 @@ int md_run(mddev_t *mddev)
 
        if (mddev->pers)
                return -EBUSY;
-
-       /* These two calls synchronise us with the
-        * sysfs_remove_group calls in mddev_unlock,
-        * so they must have completed.
-        */
-       mutex_lock(&mddev->open_mutex);
-       mutex_unlock(&mddev->open_mutex);
+       /* Cannot run until previous stop completes properly */
+       if (mddev->sysfs_active)
+               return -EBUSY;
 
        /*
         * Analyze all RAID superblock(s)
@@ -4594,7 +4597,11 @@ static int do_md_run(mddev_t *mddev)
        err = md_run(mddev);
        if (err)
                goto out;
-
+       err = bitmap_load(mddev);
+       if (err) {
+               bitmap_destroy(mddev);
+               goto out;
+       }
        set_capacity(mddev->gendisk, mddev->array_sectors);
        revalidate_disk(mddev->gendisk);
        kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
@@ -4761,16 +4768,18 @@ out:
  */
 static int do_md_stop(mddev_t * mddev, int mode, int is_open)
 {
-       int err = 0;
        struct gendisk *disk = mddev->gendisk;
        mdk_rdev_t *rdev;
 
        mutex_lock(&mddev->open_mutex);
-       if (atomic_read(&mddev->openers) > is_open) {
+       if (atomic_read(&mddev->openers) > is_open ||
+           mddev->sysfs_active) {
                printk("md: %s still in use.\n",mdname(mddev));
-               err = -EBUSY;
-       } else if (mddev->pers) {
+               mutex_unlock(&mddev->open_mutex);
+               return -EBUSY;
+       }
 
+       if (mddev->pers) {
                if (mddev->ro)
                        set_disk_ro(disk, 0);
 
@@ -4791,21 +4800,17 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                        }
 
                set_capacity(disk, 0);
+               mutex_unlock(&mddev->open_mutex);
                revalidate_disk(disk);
 
                if (mddev->ro)
                        mddev->ro = 0;
-               
-               err = 0;
-       }
-       mutex_unlock(&mddev->open_mutex);
-       if (err)
-               return err;
+       } else
+               mutex_unlock(&mddev->open_mutex);
        /*
         * Free resources if final stop
         */
        if (mode == 0) {
-
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
                bitmap_destroy(mddev);
@@ -4822,13 +4827,11 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
                if (mddev->hold_active == UNTIL_STOP)
                        mddev->hold_active = 0;
-
        }
-       err = 0;
        blk_integrity_unregister(disk);
        md_new_event(mddev);
        sysfs_notify_dirent_safe(mddev->sysfs_state);
-       return err;
+       return 0;
 }
 
 #ifndef MODULE
@@ -5382,8 +5385,11 @@ static int set_bitmap_file(mddev_t *mddev, int fd)
        err = 0;
        if (mddev->pers) {
                mddev->pers->quiesce(mddev, 1);
-               if (fd >= 0)
+               if (fd >= 0) {
                        err = bitmap_create(mddev);
+                       if (!err)
+                               err = bitmap_load(mddev);
+               }
                if (fd < 0 || err) {
                        bitmap_destroy(mddev);
                        fd = -1; /* make sure to put the file */
@@ -5632,6 +5638,8 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                                mddev->bitmap_info.default_offset;
                        mddev->pers->quiesce(mddev, 1);
                        rv = bitmap_create(mddev);
+                       if (!rv)
+                               rv = bitmap_load(mddev);
                        if (rv)
                                bitmap_destroy(mddev);
                        mddev->pers->quiesce(mddev, 0);
@@ -5953,6 +5961,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
        mddev_t *mddev = mddev_find(bdev->bd_dev);
        int err;
 
+       lock_kernel();
        if (mddev->gendisk != bdev->bd_disk) {
                /* we are racing with mddev_put which is discarding this
                 * bd_disk.
@@ -5961,6 +5970,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
                /* Wait until bdev->bd_disk is definitely gone */
                flush_scheduled_work();
                /* Then retry the open from the top */
+               unlock_kernel();
                return -ERESTARTSYS;
        }
        BUG_ON(mddev != bdev->bd_disk->private_data);
@@ -5974,6 +5984,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
 
        check_disk_size_change(mddev->gendisk, bdev);
  out:
+       unlock_kernel();
        return err;
 }
 
@@ -5982,8 +5993,10 @@ static int md_release(struct gendisk *disk, fmode_t mode)
        mddev_t *mddev = disk->private_data;
 
        BUG_ON(!mddev);
+       lock_kernel();
        atomic_dec(&mddev->openers);
        mddev_put(mddev);
+       unlock_kernel();
 
        return 0;
 }