*/
#include "mdadm.h"
+#include "mdmon.h"
#include <values.h>
#include <scsi/sg.h>
#include <ctype.h>
struct imsm_super *mpb;
void *buf;
};
+ int updates_pending;
struct dl {
struct dl *next;
int index;
int rv;
#ifndef MDASSEMBLE
- if (load_super_imsm_all(st, fd, &st->sb, devname, 0) == 0)
+ if (load_super_imsm_all(st, fd, &st->sb, devname, 1) == 0)
return 0;
#endif
this->array.chunk_size = __le16_to_cpu(map->blocks_per_strip) << 9;
this->array.state = !vol->dirty;
this->container_member = i;
+ if (map->map_state == IMSM_T_STATE_UNINITIALIZED || dev->vol.dirty)
+ this->resync_start = 0;
+ else
+ this->resync_start = ~0ULL;
+
strncpy(this->name, (char *) dev->volume, MAX_RAID_SERIAL_LEN);
this->name[MAX_RAID_SERIAL_LEN] = 0;
return rest;
}
+
+static int imsm_open_new(struct supertype *c, struct active_array *a, int inst)
+{
+ fprintf(stderr, "imsm: open_new %d\n", inst);
+ return 0;
+}
+
+static void imsm_mark_clean(struct active_array *a, unsigned long long sync_pos)
+{
+ int inst = a->info.container_member;
+ struct intel_super *super = a->container->sb;
+ struct imsm_dev *dev = get_imsm_dev(super->mpb, inst);
+
+ if (dev->vol.dirty) {
+ fprintf(stderr, "imsm: mark clean %llu\n", sync_pos);
+ dev->vol.dirty = 0;
+ super->updates_pending++;
+ }
+}
+
+static void imsm_mark_dirty(struct active_array *a)
+{
+ int inst = a->info.container_member;
+ struct intel_super *super = a->container->sb;
+ struct imsm_dev *dev = get_imsm_dev(super->mpb, inst);
+
+ if (!dev->vol.dirty) {
+ fprintf(stderr, "imsm: mark dirty\n");
+ dev->vol.dirty = 1;
+ super->updates_pending++;
+ }
+}
+
+static __u8 imsm_check_degraded(struct imsm_super *mpb, int n, int failed)
+{
+ struct imsm_dev *dev = get_imsm_dev(mpb, n);
+ struct imsm_map *map = dev->vol.map;
+
+ if (!failed)
+ return map->map_state;
+
+ switch (get_imsm_raid_level(map)) {
+ case 0:
+ return IMSM_T_STATE_FAILED;
+ break;
+ case 1:
+ if (failed < map->num_members)
+ return IMSM_T_STATE_DEGRADED;
+ else
+ return IMSM_T_STATE_FAILED;
+ break;
+ case 10:
+ {
+ /**
+ * check to see if any mirrors have failed,
+ * otherwise we are degraded
+ */
+ int device_per_mirror = 2; /* FIXME is this always the case?
+ * and are they always adjacent?
+ */
+ int failed = 0;
+ int i;
+
+ for (i = 0; i < map->num_members; i++) {
+ int idx = get_imsm_disk_idx(map, i);
+ struct imsm_disk *disk = get_imsm_disk(mpb, idx);
+
+ if (__le32_to_cpu(disk->status) & FAILED_DISK)
+ failed++;
+
+ if (failed >= device_per_mirror)
+ return IMSM_T_STATE_FAILED;
+
+ /* reset 'failed' for next mirror set */
+ if (!((i + 1) % device_per_mirror))
+ failed = 0;
+ }
+
+ return IMSM_T_STATE_DEGRADED;
+ }
+ case 5:
+ if (failed < 2)
+ return IMSM_T_STATE_DEGRADED;
+ else
+ return IMSM_T_STATE_FAILED;
+ break;
+ default:
+ break;
+ }
+
+ return map->map_state;
+}
+
+static int imsm_count_failed(struct imsm_super *mpb, struct imsm_map *map)
+{
+ int i;
+ int failed = 0;
+ struct imsm_disk *disk;
+
+ for (i = 0; i < map->num_members; i++) {
+ int idx = get_imsm_disk_idx(map, i);
+
+ disk = get_imsm_disk(mpb, idx);
+ if (__le32_to_cpu(disk->status) & FAILED_DISK)
+ failed++;
+ }
+
+ return failed;
+}
+
+static void imsm_mark_sync(struct active_array *a, unsigned long long resync)
+{
+ int inst = a->info.container_member;
+ struct intel_super *super = a->container->sb;
+ struct imsm_dev *dev = get_imsm_dev(super->mpb, inst);
+ struct imsm_map *map = dev->vol.map;
+ int failed;
+ __u8 map_state;
+
+ if (resync != ~0ULL)
+ return;
+
+ fprintf(stderr, "imsm: mark sync\n");
+
+ failed = imsm_count_failed(super->mpb, map);
+ map_state = imsm_check_degraded(super->mpb, inst, failed);
+ if (!failed)
+ map_state = IMSM_T_STATE_NORMAL;
+ if (map->map_state != map_state) {
+ map->map_state = map_state;
+ super->updates_pending++;
+ }
+}
+
+static void imsm_set_disk(struct active_array *a, int n, int state)
+{
+ int inst = a->info.container_member;
+ struct intel_super *super = a->container->sb;
+ struct imsm_dev *dev = get_imsm_dev(super->mpb, inst);
+ struct imsm_map *map = dev->vol.map;
+ struct imsm_disk *disk;
+ __u32 status;
+ int failed = 0;
+ int new_failure = 0;
+
+ if (n > map->num_members)
+ fprintf(stderr, "imsm: set_disk %d out of range 0..%d\n",
+ n, map->num_members - 1);
+
+ if (n < 0)
+ return;
+
+ fprintf(stderr, "imsm: set_disk %d:%x\n", n, state);
+
+ disk = get_imsm_disk(super->mpb, get_imsm_disk_idx(map, n));
+
+ /* check if we have seen this failure before */
+ status = __le32_to_cpu(disk->status);
+ if ((state & DS_FAULTY) && !(status & FAILED_DISK)) {
+ status |= FAILED_DISK;
+ disk->status = __cpu_to_le32(status);
+ new_failure = 1;
+ }
+
+ /**
+ * the number of failures have changed, count up 'failed' to determine
+ * degraded / failed status
+ */
+ if (new_failure && map->map_state != IMSM_T_STATE_FAILED)
+ failed = imsm_count_failed(super->mpb, map);
+
+ if (failed)
+ map->map_state = imsm_check_degraded(super->mpb, inst, failed);
+
+ if (new_failure)
+ super->updates_pending++;
+}
+
+static int store_imsm_mpb(int fd, struct intel_super *super)
+{
+ struct imsm_super *mpb = super->mpb;
+ __u32 mpb_size = __le32_to_cpu(mpb->mpb_size);
+ unsigned long long dsize;
+ unsigned long long sectors;
+
+ get_dev_size(fd, NULL, &dsize);
+
+ /* first block is stored on second to last sector of the disk */
+ if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0)
+ return 1;
+
+ if (write(fd, super->buf, 512) != 512)
+ return 1;
+
+ if (mpb_size <= 512)
+ return 0;
+
+ /* -1 because we already wrote a sector */
+ sectors = mpb_sectors(mpb) - 1;
+
+ /* write the extended mpb to the sectors preceeding the anchor */
+ if (lseek64(fd, dsize - (512 * (2 + sectors)), SEEK_SET) < 0)
+ return 1;
+
+ if (write(fd, super->buf + 512, mpb_size - 512) != mpb_size - 512)
+ return 1;
+
+ fsync(fd);
+
+ return 0;
+}
+
+static void imsm_sync_metadata(struct active_array *a)
+{
+ struct intel_super *super = a->container->sb;
+ struct imsm_super *mpb = super->mpb;
+ struct dl *d;
+ __u32 generation;
+ __u32 sum;
+
+ if (!super->updates_pending)
+ return;
+
+ fprintf(stderr, "imsm: sync_metadata\n");
+
+ /* 'generation' is incremented everytime the metadata is written */
+ generation = __le32_to_cpu(mpb->generation_num);
+ generation++;
+ mpb->generation_num = __cpu_to_le32(generation);
+
+ /* recalculate checksum */
+ sum = gen_imsm_checksum(mpb);
+ mpb->check_sum = __cpu_to_le32(sum);
+
+ for (d = super->disks; d ; d = d->next)
+ if (store_imsm_mpb(d->fd, super))
+ fprintf(stderr, "%s: failed for device %d:%d %s\n",
+ __func__, d->major, d->minor, strerror(errno));
+
+ super->updates_pending = 0;
+}
+
struct superswitch super_imsm = {
#ifndef MDASSEMBLE
.examine_super = examine_super_imsm,
.swapuuid = 0,
.external = 1,
.text_version = "imsm",
+
+/* for mdmon */
+ .open_new = imsm_open_new,
+ .load_super = load_super_imsm,
+ .mark_clean = imsm_mark_clean,
+ .mark_dirty = imsm_mark_dirty,
+ .mark_sync = imsm_mark_sync,
+ .set_disk = imsm_set_disk,
+ .sync_metadata = imsm_sync_metadata,
};
/* super_imsm_container is set by validate_geometry_imsm when given a