(Online Capacity Expansion for IMSM) When mdmon calls grow_array() on disks increase detection, grow_array() has to add new disks to active_array structure. According to this memory for internal imsm data has to be reallocated reallocate_imsm_dev() takes current memory contents of internal imsm data and copies it to new (larger) memory location. Manages memory relink then. Signed-off-by: Adam Kwolek <adam.kwolek@xxxxxxxxx> --- mdadm.h | 2 + monitor.c | 50 ----------------------- super-intel.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.c | 51 +++++++++++++++++++++++ 4 files changed, 179 insertions(+), 50 deletions(-) diff --git a/mdadm.h b/mdadm.h index a846098..ecef25c 100644 --- a/mdadm.h +++ b/mdadm.h @@ -861,6 +861,8 @@ extern int conf_name_is_free(char *name); extern int devname_matches(char *name, char *match); extern struct mddev_ident_s *conf_match(struct mdinfo *info, struct supertype *st); extern void sleep2(unsigned int sec, unsigned int usec); +extern int read_attr(char *buf, int len, int fd); extern int +read_dev_state(int fd); extern void free_line(char *line); extern int match_oneof(char *devices, char *devname); diff --git a/monitor.c b/monitor.c index 4578718..3c99dff 100644 --- a/monitor.c +++ b/monitor.c @@ -45,27 +45,6 @@ static void add_fd(fd_set *fds, int *maxfd, int fd) FD_SET(fd, fds); } -static int read_attr(char *buf, int len, int fd) -{ - int n; - - if (fd < 0) { - buf[0] = 0; - return 0; - } - lseek(fd, 0, 0); - n = read(fd, buf, len - 1); - - if (n <= 0) { - buf[0] = 0; - return 0; - } - buf[n] = 0; - if (buf[n-1] == '\n') - buf[n-1] = 0; - return n; -} - static unsigned long long read_resync_start(int fd) { char buf[30]; @@ -100,35 +79,6 @@ static enum sync_action read_action( int fd) return (enum sync_action) sysfs_match_word(buf, sync_actions); } -int read_dev_state(int fd) -{ - char buf[60]; - int n = read_attr(buf, 60, fd); - char *cp; - int rv = 0; - - if (n <= 0) - return 0; - - cp = buf; - while (cp) { - if (sysfs_attr_match(cp, "faulty")) - rv |= DS_FAULTY; - if (sysfs_attr_match(cp, "in_sync")) - rv |= DS_INSYNC; - if (sysfs_attr_match(cp, "write_mostly")) - rv |= DS_WRITE_MOSTLY; - if (sysfs_attr_match(cp, "spare")) - rv |= DS_SPARE; - if (sysfs_attr_match(cp, "blocked")) - rv |= DS_BLOCKED; - cp = strchr(cp, ','); - if (cp) - cp++; - } - return rv; -} - static void signal_manager(void) { /* tgkill(getpid(), mon_tid, SIGUSR1); */ diff --git a/super-intel.c b/super-intel.c index a4ffb3f..115a5f0 100644 --- a/super-intel.c +++ b/super-intel.c @@ -5098,6 +5098,131 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, return rv; } +int imsm_grow_array(struct active_array *a, int new_raid_disks) { + int ret_val = 0; + struct intel_super *super = a->container->sb; + int inst = a->info.container_member; + struct imsm_dev *dev = get_imsm_dev(super, inst); + struct imsm_map *map = get_imsm_map(dev, 0); + struct mdinfo *d; + struct mdinfo *di; + struct dl *dl; + int i; + int rv; + char dv[1024]; + char nm[1024]; + char *dname; + + dprintf("imsm: grow array: inst=%d raid disks=%d level=%d\n", + inst, a->info.array.raid_disks, a->info.array.level); + + /* grow support only */ + if ((a->info.array.raid_disks >= new_raid_disks) && + (new_raid_disks > 0)) + return ret_val; + + /* Look for all disks beyond current configuration + * To handle degradation after takeover + * look also on last disk in configuration. + */ + for (i = a->info.array.raid_disks-1; i < new_raid_disks; i++) { + for (d = a->info.devs ; d ; d = d->next) + if (d->disk.raid_disk == i) + break; + dprintf("found %d: %p %x\n", i, d, d ? d->curr_state : 0); + if (d && (d->state_fd >= 0)) + continue; + + /* OK, this device can be added. Try to add. + */ + dl = imsm_add_spare(super, i, a, 0); + if (!dl) + dl = imsm_add_spare(super, i, a, 1); + if (!dl) + continue; + + if (dl->index < 0) + dl->index = i; + /* found a usable disk with enough space */ + di = malloc(sizeof(*di)); + if (!di) + continue; + memset(di, 0, sizeof(*di)); + + /* dl->index will be -1 in the case we are activating a + * pristine spare. imsm_process_update() will create a + * new index in this case. Once a disk is found to be + * failed in all member arrays it is kicked from the + * metadata + */ + di->disk.number = dl->index; + + dl->disk.status |= CONFIGURED_DISK; + dl->disk.status &= ~SPARE_DISK; + + /* (ab)use di->devs to store a pointer to the device + * we chose + */ + di->devs = (struct mdinfo *) dl; + + di->disk.raid_disk = i; + di->disk.major = dl->major; + di->disk.minor = dl->minor; + di->disk.state = (1<<MD_DISK_SYNC) | + (1<<MD_DISK_ACTIVE); + + /* set handle to state in sysfs + */ + sprintf(dv, "/sys/dev/block/%d:%d", di->disk.major, di->disk.minor); + memset(nm, 0, sizeof(nm)); + rv = readlink(dv, nm, sizeof(nm)); + if (rv > 0) { + nm[rv] = '\0'; + dname = strrchr(nm, '/'); + if (dname) { + dname++; + sprintf(di->sys_name, "dev-%s", dname); + } + } + + di->state_fd = sysfs_open(a->devnum, + di->sys_name, + "state"); + di->recovery_fd = sysfs_open(a->devnum, + di->sys_name, + "recovery_start"); + + di->prev_state = read_dev_state(di->state_fd); + di->curr_state = di->prev_state; + di->next_state = 0; + + di->recovery_start = 0; + di->data_offset = __le32_to_cpu(map->pba_of_lba0); + di->component_size = a->info.component_size; + di->container_member = inst; + super->random = random32(); + + di->next = a->info.devs; + a->info.devs = di; + + ret_val++; + dprintf("%x:%x to be %d at %llu\n", dl->major, dl->minor, + i, di->data_offset); + } + + if ((new_raid_disks - a->info.array.raid_disks) != ret_val) { + dprintf("imsm: ERROR: imsm_grow_array() configures %i raid disks\n", + ret_val); + } + + /* prepare device to receive new disk(s) + */ + reallocate_imsm_dev(super, inst, new_raid_disks); + + return ret_val; +} + static int disks_overlap(struct intel_super *super, int idx, struct imsm_update_create_array *u) { struct imsm_dev *dev = get_imsm_dev(super, idx); @@ -5697,6 +5822,7 @@ struct superswitch super_imsm = { .match_metadata_desc = match_metadata_desc_imsm, .container_content = container_content_imsm, .default_layout = imsm_level_to_layout, + .grow_array = imsm_grow_array, .external = 1, .name = "imsm", diff --git a/util.c b/util.c index 5779d52..7f5e20a 100644 --- a/util.c +++ b/util.c @@ -1656,3 +1656,54 @@ void sleep2(unsigned int sec, unsigned int usec) tv.tv_usec = usec; select(0, NULL, NULL, NULL, &tv); } + +int read_attr(char *buf, int len, int fd) { + int n; + + if (fd < 0) { + buf[0] = 0; + return 0; + } + lseek(fd, 0, 0); + n = read(fd, buf, len - 1); + + if (n <= 0) { + buf[0] = 0; + return 0; + } + buf[n] = 0; + if (buf[n-1] == '\n') + buf[n-1] = 0; + + return n; +} + +int read_dev_state(int fd) +{ + char buf[60]; + int n = read_attr(buf, 60, fd); + char *cp; + int rv = 0; + + if (n <= 0) + return 0; + + cp = buf; + while (cp) { + if (sysfs_attr_match(cp, "faulty")) + rv |= DS_FAULTY; + if (sysfs_attr_match(cp, "in_sync")) + rv |= DS_INSYNC; + if (sysfs_attr_match(cp, "write_mostly")) + rv |= DS_WRITE_MOSTLY; + if (sysfs_attr_match(cp, "spare")) + rv |= DS_SPARE; + if (sysfs_attr_match(cp, "blocked")) + rv |= DS_BLOCKED; + cp = strchr(cp, ','); + if (cp) + cp++; + } + return rv; +} ��.n��������+%������w��{.n�����{����w��ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f