static void fill_initiator_context(char *subsys, struct boot_context *context) { sysfs_get_str("initiator", subsys, "initiator-name", context->initiatorname, sizeof(context->initiatorname)); sysfs_get_str("initiator", subsys, "isid", context->isid, sizeof(context->isid)); strlcpy(context->boot_root, subsys, sizeof(context->boot_root)); }
/* Not really Monitor but ... */ int Wait(char *dev) { struct stat stb; char devnm[32]; int rv = 1; int frozen_remaining = 3; if (stat(dev, &stb) != 0) { pr_err("Cannot find %s: %s\n", dev, strerror(errno)); return 2; } strcpy(devnm, stat2devnm(&stb)); while(1) { struct mdstat_ent *ms = mdstat_read(1, 0); struct mdstat_ent *e; for (e=ms ; e; e=e->next) if (strcmp(e->devnm, devnm) == 0) break; if (e && e->percent == RESYNC_NONE) { /* We could be in the brief pause before something * starts. /proc/mdstat doesn't show that, but * sync_action does. */ struct mdinfo mdi; char buf[21]; sysfs_init(&mdi, -1, devnm); if (sysfs_get_str(&mdi, NULL, "sync_action", buf, 20) > 0 && strcmp(buf,"idle\n") != 0) { e->percent = RESYNC_UNKNOWN; if (strcmp(buf, "frozen\n") == 0) { if (frozen_remaining == 0) e->percent = RESYNC_NONE; else frozen_remaining -= 1; } } } if (!e || e->percent == RESYNC_NONE) { if (e && e->metadata_version && strncmp(e->metadata_version, "external:", 9) == 0) { if (is_subarray(&e->metadata_version[9])) ping_monitor(&e->metadata_version[9]); else ping_monitor(devnm); } free_mdstat(ms); return rv; } free_mdstat(ms); rv = 0; mdstat_wait(5); } }
static int fill_tgt_context(char *subsys, char *id, struct boot_context *context) { int rc; rc = sysfs_get_int(id, subsys, "flags", &context->target_flags); /* * Per spec we would need to check against Bit 0 * (Block Valid Flag), but some firmware only * sets Bit 1 (Firmware Booting Selected). * So any setting is deemed okay. */ if (!rc && (context->nic_flags == 0)) rc = ENODEV; if (rc) return rc; rc = sysfs_get_str(id, subsys, "target-name", context->targetname, sizeof(context->targetname)); if (rc) return rc; rc = sysfs_get_str(id, subsys, "ip-addr", context->target_ipaddr, sizeof(context->target_ipaddr)); if (rc) return rc; memset(&context->boot_target, 0, sizeof(context->boot_target)); snprintf(context->boot_target, sizeof(context->boot_target), "%s", id); /* * We can live without the rest of they do not exist. If we * failed to get them we will figure it out when we login. */ if (sysfs_get_int(id, subsys, "port", &context->target_port)) context->target_port = ISCSI_LISTEN_PORT; sysfs_get_str(id, subsys, "lun", context->lun, sizeof(context->lun)); sysfs_get_str(id, subsys, "chap-name", context->chap_name, sizeof(context->chap_name)); sysfs_get_str(id, subsys, "chap-secret", context->chap_password, sizeof(context->chap_password)); sysfs_get_str(id, subsys, "rev-chap-name", context->chap_name_in, sizeof(context->chap_name_in)); sysfs_get_str(id, subsys, "rev-chap-name-secret", context->chap_password_in, sizeof(context->chap_password_in)); return 0; }
int sysfs_freeze_array(struct mdinfo *sra) { /* Try to freeze resync/rebuild on this array/container. * Return -1 if the array is busy, * return 0 if this kernel doesn't support 'frozen' * return 1 if it worked. */ char buf[20]; if (!sysfs_attribute_available(sra, NULL, "sync_action")) return 1; /* no sync_action == frozen */ if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0) return 0; if (strcmp(buf, "frozen\n") == 0) /* Already frozen */ return 0; if (strcmp(buf, "idle\n") != 0 && strcmp(buf, "recover\n") != 0) return -1; if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0) return 0; return 1; }
/* * Routines to fill in the context values. */ static int fill_nic_context(char *subsys, char *id, struct boot_context *context) { int rc; rc = sysfs_get_int(id, subsys, "flags", &context->nic_flags); /* * Per spec we would need to check against Bit 0 * (Block Valid Flag), but some firmware only * sets Bit 1 (Firmware Booting Selected). * So any setting is deemed okay. */ if (!rc && (context->nic_flags == 0)) rc = ENODEV; if (rc) return rc; rc = sysfs_get_str(id, subsys, "mac", context->mac, sizeof(context->mac)); if (rc) return rc; /* * Some offload cards like bnx2i use different MACs for the net and * iscsi functions, so we have to follow the sysfs links. * * Other ibft implementations may not be tied to a pci function, * so there will not be any device/net link, so we drop down to * the MAC matching. * * And finally, some cards like be2iscsi and qla4xxx do not have * any linux network subsys representation. These hosts will * not have the ibft subsys. Instead the subsys is the scsi host * number. */ if (!strcmp(IBFT_SUBSYS, subsys)) { rc = get_iface_from_device(id, context); if (rc) { rc = net_get_netdev_from_hwaddress(context->mac, context->iface); if (rc) return rc; } } else strlcpy(context->scsi_host_name, subsys, sizeof(context->scsi_host_name)); memset(&context->boot_nic, 0, sizeof(context->boot_nic)); snprintf(context->boot_nic, sizeof(context->boot_nic), "%s", id); sysfs_get_str(id, subsys, "ip-addr", context->ipaddr, sizeof(context->ipaddr)); sysfs_get_str(id, subsys, "vlan", context->vlan, sizeof(context->vlan)); sysfs_get_str(id, subsys, "subnet-mask", context->mask, sizeof(context->mask)); sysfs_get_str(id, subsys, "gateway", context->gateway, sizeof(context->gateway)); sysfs_get_str(id, subsys, "primary-dns", context->primary_dns, sizeof(context->primary_dns)); sysfs_get_str(id, subsys, "secondary-dns", context->secondary_dns, sizeof(context->secondary_dns)); sysfs_get_str(id, subsys, "dhcp", context->dhcp, sizeof(context->dhcp)); sysfs_get_int(id, subsys, "origin", (int *)&context->origin); return 0; }
/** * block_monitor - prevent mdmon spare assignment * @container - container to block * @freeze - flag to additionally freeze sync_action * * This is used by the reshape code to freeze the container, and the * auto-rebuild implementation to atomically move spares. * In both cases we need to stop mdmon from assigning spares to replace * failed devices as we might have other plans for the spare. * For the reshape case we also need to 'freeze' sync_action so that * no recovery happens until we have fully prepared for the reshape. * * We tell mdmon that the array is frozen by marking the 'metadata' name * with a leading '-'. The previously told mdmon "Don't make this array * read/write, leave it readonly". Now it means a more general "Don't * reconfigure this array at all". * As older versions of mdmon (which might run from initrd) don't understand * this, we first check that the running mdmon is new enough. */ int block_monitor(char *container, const int freeze) { int devnum = devname2devnum(container); struct mdstat_ent *ent, *e, *e2; struct mdinfo *sra = NULL; char *version = NULL; char buf[64]; int rv = 0; if (!mdmon_running(devnum)) { /* if mdmon is not active we assume that any instance that is * later started will match the current mdadm version, if this * assumption is violated we may inadvertantly rebuild an array * that was meant for reshape, or start rebuild on a spare that * was to be moved to another container */ /* pass */; } else { int ver; version = ping_monitor_version(container); ver = version ? mdadm_version(version) : -1; free(version); if (ver < 3002000) { fprintf(stderr, Name ": mdmon instance for %s cannot be disabled\n", container); return -1; } } ent = mdstat_read(0, 0); if (!ent) { fprintf(stderr, Name ": failed to read /proc/mdstat while disabling mdmon\n"); return -1; } /* freeze container contents */ for (e = ent; e; e = e->next) { if (!is_container_member(e, container)) continue; sysfs_free(sra); sra = sysfs_read(-1, e->devnum, GET_VERSION); if (!sra) { fprintf(stderr, Name ": failed to read sysfs for subarray%s\n", to_subarray(e, container)); break; } /* can't reshape an array that we can't monitor */ if (sra->text_version[0] == '-') break; if (freeze && sysfs_freeze_array(sra) < 1) break; /* flag this array to not be modified by mdmon (close race with * takeover in reshape case and spare reassignment in the * auto-rebuild case) */ if (block_subarray(sra)) break; ping_monitor(container); /* check that we did not race with recovery */ if ((freeze && !sysfs_attribute_available(sra, NULL, "sync_action")) || (freeze && sysfs_attribute_available(sra, NULL, "sync_action") && sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0 && strcmp(buf, "frozen\n") == 0)) /* pass */; else { unblock_subarray(sra, 0); break; } /* Double check against races - there should be no spares * or part-spares */ sysfs_free(sra); sra = sysfs_read(-1, e->devnum, GET_DEVS | GET_STATE); if (sra && sra->array.spare_disks > 0) { unblock_subarray(sra, freeze); break; } } if (e) { fprintf(stderr, Name ": failed to freeze subarray%s\n", to_subarray(e, container)); /* thaw the partially frozen container */ for (e2 = ent; e2 && e2 != e; e2 = e2->next) { if (!is_container_member(e2, container)) continue; sysfs_free(sra); sra = sysfs_read(-1, e2->devnum, GET_VERSION); if (unblock_subarray(sra, freeze)) fprintf(stderr, Name ": Failed to unfreeze %s\n", e2->dev); } ping_monitor(container); /* cleared frozen */ rv = -1; } sysfs_free(sra); free_mdstat(ent); return rv; }
int sysfs_set_array(struct mdinfo *info, int vers) { int rv = 0; char ver[100]; int raid_disks = info->array.raid_disks; ver[0] = 0; if (info->array.major_version == -1 && info->array.minor_version == -2) { char buf[1024]; strcat(strcpy(ver, "external:"), info->text_version); /* meta version might already be set if we are setting * new geometry for a reshape. In that case we don't * want to over-write the 'readonly' flag that is * stored in the metadata version. So read the current * version first, and preserve the flag */ if (sysfs_get_str(info, NULL, "metadata_version", buf, 1024) > 0) if (strlen(buf) >= 9 && buf[9] == '-') ver[9] = '-'; if ((vers % 100) < 2 || sysfs_set_str(info, NULL, "metadata_version", ver) < 0) { pr_err("This kernel does not support external metadata.\n"); return 1; } } if (info->array.level < 0) return 0; /* FIXME */ rv |= sysfs_set_str(info, NULL, "level", map_num(pers, info->array.level)); if (info->reshape_active && info->delta_disks != UnSet) raid_disks -= info->delta_disks; rv |= sysfs_set_num(info, NULL, "raid_disks", raid_disks); rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size); rv |= sysfs_set_num(info, NULL, "layout", info->array.layout); rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2); if (info->custom_array_size) { int rc; rc = sysfs_set_num(info, NULL, "array_size", info->custom_array_size/2); if (rc && errno == ENOENT) { pr_err("This kernel does not have the md/array_size attribute, the array may be larger than expected\n"); rc = 0; } rv |= rc; } if (info->array.level > 0) rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start); if (info->reshape_active) { rv |= sysfs_set_num(info, NULL, "reshape_position", info->reshape_progress); rv |= sysfs_set_num(info, NULL, "chunk_size", info->new_chunk); rv |= sysfs_set_num(info, NULL, "layout", info->new_layout); rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks); /* We don't set 'new_level' here. That can only happen * once the reshape completes. */ } return rv; }