media: v4l2-compat-ioctl32: fix missing reserved field copy in put_v4l2_create32
[pandora-kernel.git] / drivers / md / dm-raid.c
index 37a3726..8158f63 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "md.h"
 #include "raid1.h"
@@ -590,8 +591,7 @@ struct dm_raid_superblock {
        __le32 layout;
        __le32 stripe_sectors;
 
-       __u8 pad[452];          /* Round struct to 512 bytes. */
-                               /* Always set to 0 when writing. */
+       /* Remainder of a logical block is zero-filled when writing (see super_sync()). */
 } __packed;
 
 static int read_disk_sb(struct md_rdev *rdev, int size)
@@ -624,7 +624,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
                if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
                        failed_devices |= (1ULL << r->raid_disk);
 
-       memset(sb, 0, sizeof(*sb));
+       memset(sb + 1, 0, rdev->sb_size - sizeof(*sb));
 
        sb->magic = cpu_to_le32(DM_RAID_MAGIC);
        sb->features = cpu_to_le32(0);  /* No features yet */
@@ -659,14 +659,25 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
        uint64_t events_sb, events_refsb;
 
        rdev->sb_start = 0;
-       rdev->sb_size = sizeof(*sb);
+       rdev->sb_size = bdev_logical_block_size(rdev->meta_bdev);
+       if (rdev->sb_size < sizeof(*sb) || rdev->sb_size > PAGE_SIZE) {
+               DMERR("superblock size of a logical block is no longer valid");
+               return -EINVAL;
+       }
 
        ret = read_disk_sb(rdev, rdev->sb_size);
        if (ret)
                return ret;
 
        sb = page_address(rdev->sb_page);
-       if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) {
+
+       /*
+        * Two cases that we want to write new superblocks and rebuild:
+        * 1) New device (no matching magic number)
+        * 2) Device specified for rebuild (!In_sync w/ offset == 0)
+        */
+       if ((sb->magic != cpu_to_le32(DM_RAID_MAGIC)) ||
+           (!test_bit(In_sync, &rdev->flags) && !rdev->recovery_offset)) {
                super_sync(rdev->mddev, rdev);
 
                set_bit(FirstUse, &rdev->flags);
@@ -743,11 +754,8 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
         */
        rdev_for_each(r, t, mddev) {
                if (!test_bit(In_sync, &r->flags)) {
-                       if (!test_bit(FirstUse, &r->flags))
-                               DMERR("Superblock area of "
-                                     "rebuild device %d should have been "
-                                     "cleared.", r->raid_disk);
-                       set_bit(FirstUse, &r->flags);
+                       DMINFO("Device %d specified for rebuild: "
+                              "Clearing superblock", r->raid_disk);
                        rebuilds++;
                } else if (test_bit(FirstUse, &r->flags))
                        new_devs++;
@@ -969,6 +977,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        INIT_WORK(&rs->md.event_work, do_table_event);
        ti->private = rs;
+       ti->num_flush_requests = 1;
 
        mutex_lock(&rs->md.reconfig_mutex);
        ret = md_run(&rs->md);
@@ -1011,36 +1020,62 @@ static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_c
        return DM_MAPIO_SUBMITTED;
 }
 
-static int raid_status(struct dm_target *ti, status_type_t type,
-                      char *result, unsigned maxlen)
+static void raid_status(struct dm_target *ti, status_type_t type,
+                       char *result, unsigned maxlen)
 {
        struct raid_set *rs = ti->private;
        unsigned raid_param_cnt = 1; /* at least 1 for chunksize */
        unsigned sz = 0;
-       int i;
+       int i, array_in_sync = 0;
        sector_t sync;
 
        switch (type) {
        case STATUSTYPE_INFO:
                DMEMIT("%s %d ", rs->raid_type->name, rs->md.raid_disks);
 
-               for (i = 0; i < rs->md.raid_disks; i++) {
-                       if (test_bit(Faulty, &rs->dev[i].rdev.flags))
-                               DMEMIT("D");
-                       else if (test_bit(In_sync, &rs->dev[i].rdev.flags))
-                               DMEMIT("A");
-                       else
-                               DMEMIT("a");
-               }
-
                if (test_bit(MD_RECOVERY_RUNNING, &rs->md.recovery))
                        sync = rs->md.curr_resync_completed;
                else
                        sync = rs->md.recovery_cp;
 
-               if (sync > rs->md.resync_max_sectors)
+               if (sync >= rs->md.resync_max_sectors) {
+                       array_in_sync = 1;
                        sync = rs->md.resync_max_sectors;
+               } else {
+                       /*
+                        * The array may be doing an initial sync, or it may
+                        * be rebuilding individual components.  If all the
+                        * devices are In_sync, then it is the array that is
+                        * being initialized.
+                        */
+                       for (i = 0; i < rs->md.raid_disks; i++)
+                               if (!test_bit(In_sync, &rs->dev[i].rdev.flags))
+                                       array_in_sync = 1;
+               }
+               /*
+                * Status characters:
+                *  'D' = Dead/Failed device
+                *  'a' = Alive but not in-sync
+                *  'A' = Alive and in-sync
+                */
+               for (i = 0; i < rs->md.raid_disks; i++) {
+                       if (test_bit(Faulty, &rs->dev[i].rdev.flags))
+                               DMEMIT("D");
+                       else if (!array_in_sync ||
+                                !test_bit(In_sync, &rs->dev[i].rdev.flags))
+                               DMEMIT("a");
+                       else
+                               DMEMIT("A");
+               }
 
+               /*
+                * In-sync ratio:
+                *  The in-sync ratio shows the progress of:
+                *   - Initializing the array
+                *   - Rebuilding a subset of devices of the array
+                *  The user can distinguish between the two by referring
+                *  to the status characters.
+                */
                DMEMIT(" %llu/%llu",
                       (unsigned long long) sync,
                       (unsigned long long) rs->md.resync_max_sectors);
@@ -1121,8 +1156,6 @@ static int raid_status(struct dm_target *ti, status_type_t type,
                                DMEMIT(" -");
                }
        }
-
-       return 0;
 }
 
 static int raid_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
@@ -1176,7 +1209,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 1, 0},
+       .version = {1, 1, 1},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,