]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Fix parsing of inactive arrays in /proc/mdstat
[thirdparty/mdadm.git] / super-intel.c
index fbebfcfe87e1405ac17143bdd8894fac340c1a0c..d6d8b090b1aa4244b986534d4db0c3834bc52834 100644 (file)
@@ -243,7 +243,6 @@ struct intel_super {
        void *next_buf; /* for realloc'ing buf from the manager */
        size_t next_len;
        int updates_pending; /* count of pending updates for mdmon */
-       int creating_imsm; /* flag to indicate container creation */
        int current_vol; /* index of raid device undergoing creation */
        __u32 create_offset; /* common start for 'current_vol' */
        __u32 random; /* random data for seeding new family numbers */
@@ -345,7 +344,6 @@ static struct imsm_disk *__get_imsm_disk(struct imsm_super *mpb, __u8 index)
        return &mpb->disk[index];
 }
 
-#ifndef MDASSEMBLE
 /* retrieve a disk from the parsed metadata */
 static struct imsm_disk *get_imsm_disk(struct intel_super *super, __u8 index)
 {
@@ -357,7 +355,6 @@ static struct imsm_disk *get_imsm_disk(struct intel_super *super, __u8 index)
        
        return NULL;
 }
-#endif
 
 /* generate a checksum directly from the anchor when the anchor is known to be
  * up-to-date, currently only at load or write_super after coalescing
@@ -698,7 +695,7 @@ static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx)
                printf(" <-- %s", map_state_str[map->map_state]);
                printf("\n     Checkpoint : %u (%llu)",
                       __le32_to_cpu(dev->vol.curr_migr_unit),
-                      blocks_per_migr_unit(dev));
+                      (unsigned long long)blocks_per_migr_unit(dev));
        }
        printf("\n");
        printf("    Dirty State : %s\n", dev->vol.dirty ? "dirty" : "clean");
@@ -1453,6 +1450,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info)
        info->component_size      = __le32_to_cpu(map->blocks_per_member);
        memset(info->uuid, 0, sizeof(info->uuid));
        info->recovery_start = MaxSector;
+       info->reshape_active = 0;
 
        if (map->map_state == IMSM_T_STATE_UNINITIALIZED || dev->vol.dirty) {
                info->resync_start = 0;
@@ -1528,6 +1526,20 @@ static void fixup_container_spare_uuid(struct mdinfo *inf)
        }
 }
 
+
+static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed);
+static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev);
+
+static struct imsm_disk *get_imsm_missing(struct intel_super *super, __u8 index)
+{
+       struct dl *d;
+
+       for (d = super->missing; d; d = d->next)
+               if (d->index == index)
+                       return &d->disk;
+       return NULL;
+}
+
 static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info)
 {
        struct intel_super *super = st->sb;
@@ -1562,6 +1574,53 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info)
        info->name[0] = 0;
        info->recovery_start = MaxSector;
 
+       /* do we have the all the insync disks that we expect? */
+       if (st->loaded_container) {
+               struct imsm_super *mpb = super->anchor;
+               int max_enough = -1, i;
+
+               for (i = 0; i < mpb->num_raid_devs; i++) {
+                       struct imsm_dev *dev = get_imsm_dev(super, i);
+                       int failed, enough, j, missing = 0;
+                       struct imsm_map *map;
+                       __u8 state;
+
+                       failed = imsm_count_failed(super, dev);
+                       state = imsm_check_degraded(super, dev, failed);
+                       map = get_imsm_map(dev, dev->vol.migr_state);
+
+                       /* any newly missing disks?
+                        * (catches single-degraded vs double-degraded)
+                        */
+                       for (j = 0; j < map->num_members; j++) {
+                               __u32 ord = get_imsm_ord_tbl_ent(dev, i);
+                               __u32 idx = ord_to_idx(ord);
+
+                               if (!(ord & IMSM_ORD_REBUILD) &&
+                                   get_imsm_missing(super, idx)) {
+                                       missing = 1;
+                                       break;
+                               }
+                       }
+
+                       if (state == IMSM_T_STATE_FAILED)
+                               enough = -1;
+                       else if (state == IMSM_T_STATE_DEGRADED &&
+                                (state != map->map_state || missing))
+                               enough = 0;
+                       else /* we're normal, or already degraded */
+                               enough = 1;
+
+                       /* in the missing/failed disk case check to see
+                        * if at least one array is runnable
+                        */
+                       max_enough = max(max_enough, enough);
+               }
+               dprintf("%s: enough: %d\n", __func__, max_enough);
+               info->container_enough = max_enough;
+       } else
+               info->container_enough = -1;
+
        if (super->disks) {
                __u32 reserved = imsm_reserved_sectors(super, super->disks);
 
@@ -2296,13 +2355,12 @@ static void free_super_imsm(struct supertype *st)
        st->sb = NULL;
 }
 
-static struct intel_super *alloc_super(int creating_imsm)
+static struct intel_super *alloc_super(void)
 {
        struct intel_super *super = malloc(sizeof(*super));
 
        if (super) {
                memset(super, 0, sizeof(*super));
-               super->creating_imsm = creating_imsm;
                super->current_vol = -1;
                super->create_offset = ~((__u32 ) 0);
                if (!check_env("IMSM_NO_PLATFORM"))
@@ -2708,7 +2766,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        }
        /* load all mpbs */
        for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
-               struct intel_super *s = alloc_super(0);
+               struct intel_super *s = alloc_super();
                char nm[32];
                int dfd;
 
@@ -2799,9 +2857,13 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
                return 0;
 #endif
 
+       if (test_partition(fd))
+               /* IMSM not allowed on partitions */
+               return 1;
+
        free_super_imsm(st);
 
-       super = alloc_super(0);
+       super = alloc_super();
        if (!super) {
                fprintf(stderr,
                        Name ": malloc of %zu failed.\n",
@@ -3036,7 +3098,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        map->num_members = info->raid_disks;
        for (i = 0; i < map->num_members; i++) {
                /* initialized in add_to_super */
-               set_imsm_ord_tbl_ent(map, i, 0);
+               set_imsm_ord_tbl_ent(map, i, IMSM_ORD_REBUILD);
        }
        mpb->num_raid_devs++;
 
@@ -3075,7 +3137,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        else
                mpb_size = 512;
 
-       super = alloc_super(1);
+       super = alloc_super();
        if (super && posix_memalign(&super->buf, 512, mpb_size) != 0) {
                free(super);
                super = NULL;
@@ -3114,6 +3176,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        struct dl *dl;
        struct imsm_dev *dev;
        struct imsm_map *map;
+       int slot;
 
        dev = get_imsm_dev(super, super->current_vol);
        map = get_imsm_map(dev, 0);
@@ -3148,6 +3211,14 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                dl->index = super->anchor->num_disks;
                super->anchor->num_disks++;
        }
+       /* Check the device has not already been added */
+       slot = get_imsm_disk_slot(map, dl->index);
+       if (slot >= 0 &&
+           (get_imsm_ord_tbl_ent(dev, slot) & IMSM_ORD_REBUILD) == 0) {
+               fprintf(stderr, Name ": %s has been included in this array twice\n",
+                       devname);
+               return 1;
+       }
        set_imsm_ord_tbl_ent(map, dk->number, dl->index);
        dl->disk.status = CONFIGURED_DISK;
 
@@ -3442,8 +3513,12 @@ static int write_init_super_imsm(struct supertype *st)
                }
 
                return rv;
-       } else
+       } else {
+               struct dl *d;
+               for (d = super->disks; d; d = d->next)
+                       Kill(d->devname, NULL, 0, 1, 1);
                return write_super_imsm(st->sb, 1);
+       }
 }
 #endif
 
@@ -4028,6 +4103,15 @@ static void update_recovery_start(struct imsm_dev *dev, struct mdinfo *array)
                        rebuild = d;
                }
 
+       if (!rebuild) {
+               /* (?) none of the disks are marked with
+                * IMSM_ORD_REBUILD, so assume they are missing and the
+                * disk_ord_tbl was not correctly updated
+                */
+               dprintf("%s: failed to locate out-of-sync disk\n", __func__);
+               return;
+       }
+
        units = __le32_to_cpu(dev->vol.curr_migr_unit);
        rebuild->recovery_start = units * blocks_per_migr_unit(dev);
 }
@@ -4159,24 +4243,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st)
 }
 
 
-#ifndef MDASSEMBLE
-static int imsm_open_new(struct supertype *c, struct active_array *a,
-                        char *inst)
-{
-       struct intel_super *super = c->sb;
-       struct imsm_super *mpb = super->anchor;
-       
-       if (atoi(inst) >= mpb->num_raid_devs) {
-               fprintf(stderr, "%s: subarry index %d, out of range\n",
-                       __func__, atoi(inst));
-               return -ENODEV;
-       }
-
-       dprintf("imsm: open_new %s\n", inst);
-       a->info.container_member = atoi(inst);
-       return 0;
-}
-
 static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed)
 {
        struct imsm_map *map = get_imsm_map(dev, 0);
@@ -4275,6 +4341,24 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev)
        return failed;
 }
 
+#ifndef MDASSEMBLE
+static int imsm_open_new(struct supertype *c, struct active_array *a,
+                        char *inst)
+{
+       struct intel_super *super = c->sb;
+       struct imsm_super *mpb = super->anchor;
+       
+       if (atoi(inst) >= mpb->num_raid_devs) {
+               fprintf(stderr, "%s: subarry index %d, out of range\n",
+                       __func__, atoi(inst));
+               return -ENODEV;
+       }
+
+       dprintf("imsm: open_new %s\n", inst);
+       a->info.container_member = atoi(inst);
+       return 0;
+}
+
 static int is_resyncing(struct imsm_dev *dev)
 {
        struct imsm_map *migr_map;