static void viva_power_init(struct power_module *module) { struct viva_power_module *viva = (struct viva_power_module *) module; int tmp; char freq_buf[MAX_FREQ_NUMBER*10]; tmp = sysfs_read(CPUFREQ_CPU0 "scaling_available_frequencies", freq_buf, sizeof(freq_buf)); if (tmp <= 0) { return; } freq_num = str_to_tokens(freq_buf, freq_list, MAX_FREQ_NUMBER); if (!freq_num) { return; } max_freq = freq_list[freq_num - 1]; tmp = (NOM_FREQ_INDEX > freq_num) ? freq_num : NOM_FREQ_INDEX; nom_freq = freq_list[tmp - 1]; sysfs_write(CPUFREQ_INTERACTIVE "timer_rate", "20000"); sysfs_write(CPUFREQ_INTERACTIVE "min_sample_time","60000"); sysfs_write(CPUFREQ_INTERACTIVE "hispeed_freq", nom_freq); sysfs_write(CPUFREQ_INTERACTIVE "go_hispeed_load", "60"); sysfs_write(CPUFREQ_INTERACTIVE "above_hispeed_delay", "100000"); ALOGI("Initialized successfully"); viva->inited = 1; }
int sysfs_gpio_getvalue(uint8_t pin) { char buf[MAX_BUF], value[4]; snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/", pin); sysfs_read(buf, "value", value); return atoi(value); }
/** * Read the value from an ADC. * * It is recommended to use adc_sample() in preference to this as the ADC values can sometimes be erroneous. * * @see adc_sample() * * @param int adc the ADC channel to read * * @return int */ int adc_get_value(int adc) { char ctrlFile[1024]; char adcVal[16]; int bytesRead; switch (adc) { case 0: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_0_DIR); break; case 1: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_1_DIR); break; case 2: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_2_DIR); break; case 3: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_3_DIR); break; case 4: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_4_DIR); break; case 5: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_5_DIR); break; case 6: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_6_DIR); break; case 7: snprintf(ctrlFile, sizeof(ctrlFile), "%s%s", ADC_DIR_PREFIX, ADC_7_DIR); break; default: Logger::getInstance()->error("adc::adc_get_value: unknown ADC"); return -1; } memset(adcVal, 0, sizeof(adcVal)); bytesRead = sysfs_read(ctrlFile, adcVal, sizeof(adcVal)); if (bytesRead < 0) { Logger::getInstance()->error("adc::adc_get_value: failed to read ADC sysfs file"); return -1; } if (bytesRead >= sizeof(adcVal)) { Logger::getInstance()->error("adc::adc_get_value: overflow"); return -1; } else { adcVal[bytesRead+1] = '\0'; } return atoi(adcVal); }
static ssize_t dven_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { char src[] = "0x15b3"; return sysfs_read(buf, count, pos, src); }
static ssize_t vsd_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { char *src = "puma20_A1-10.2.3.0"; return sysfs_read(buf, count, pos, src); }
void unblock_monitor(char *container, const int unfreeze) { struct mdstat_ent *ent, *e; struct mdinfo *sra = NULL; int to_ping = 0; ent = mdstat_read(0, 0); if (!ent) { fprintf(stderr, Name ": failed to read /proc/mdstat while unblocking container\n"); return; } /* unfreeze 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|GET_LEVEL); if (sra->array.level > 0) to_ping++; if (unblock_subarray(sra, unfreeze)) fprintf(stderr, Name ": Failed to unfreeze %s\n", e->dev); } if (to_ping) ping_monitor(container); sysfs_free(sra); free_mdstat(ent); }
static ssize_t dname_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_device *uvp; uvp = (struct ib_uverbs_device *)get_fs_info(filp); return sysfs_read(buf, count, pos, uvp->ib_dev->name); }
static ssize_t ib_api_ver_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { char src[4] = { 0, 0, 0, 0}; src[0] = '0' + IB_USER_VERBS_ABI_VERSION; return sysfs_read(buf, count, pos, src); }
static ssize_t mlx4_mgm_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { #if CONFIG_MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE == -1 char src[4] = { '-', '1', 0, 0 }; #else char src[4] = { '1', '0', 0, 0 }; #endif return sysfs_read(buf, count, pos, src); }
static ssize_t dver_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_device *uvp; char src[4] = { 0, 0, 0, 0}; uvp = (struct ib_uverbs_device *)get_fs_info(filp); src[0] = '0' + uvp->ib_dev->uverbs_abi_ver; return sysfs_read(buf, count, pos, src); }
void power_set_interactive(struct power_module *, int on) { if (on) { if (hispeed_freq[0]) { sysfs_write(HISPEED_FREQ_PATH, hispeed_freq); } } else { if (sysfs_read(HISPEED_FREQ_PATH, hispeed_freq) < 0) { hispeed_freq[0] = '\0'; } sysfs_write(HISPEED_FREQ_PATH, HISPEED_FREQ_OFF); } }
int get_scaling_governor_check_cores(char governor[], int size,int core_num) { if (sysfs_read(scaling_gov_path[core_num], governor, size) == -1) { // Can't obtain the scaling governor. Return. return -1; } // Strip newline at the end. int len = strlen(governor); len--; while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r')) governor[len--] = '\0'; return 0; }
static int get_scaling_governor() { if (sysfs_read(SCALING_GOVERNOR_PATH, governor, sizeof(governor)) == -1) { return -1; } else { // Strip newline at the end. int len = strlen(governor); len--; while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r')) governor[len--] = '\0'; } return 0; }
static int get_scaling_governor(char governor[], int size) { if (sysfs_read(SCALING_GOVERNOR_PATH, governor, size) == -1) { // Can't obtain the scaling governor. Return. return -1; } else { // Strip newline at the end. int len = strlen(governor); len--; while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r')) governor[len--] = '\0'; } return 0; }
static ssize_t cpu_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { char cpu_info_str[128]; long freq = __proc_global_info.tsc_freq, idx; strncpy(cpu_info_str, "cpu MHz\t\t: ", 16); idx = strlen(cpu_info_str); stradd(cpu_info_str + idx, freq / 1000000, 4); idx += 4; strncpy(cpu_info_str + idx, ".", 1); idx++; stradd(cpu_info_str + idx, freq % 1000000, 3); idx += 3; cpu_info_str[idx] = 0; return sysfs_read(buf, count, pos, cpu_info_str); }
void RebuildMap(void) { struct mdstat_ent *mdstat = mdstat_read(0, 0); struct mdstat_ent *md; struct map_ent *map = NULL; int require_homehost; char sys_hostname[256]; char *homehost = conf_get_homehost(&require_homehost); if (homehost == NULL || strcmp(homehost, "<system>")==0) { if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { sys_hostname[sizeof(sys_hostname)-1] = 0; homehost = sys_hostname; } } for (md = mdstat ; md ; md = md->next) { struct mdinfo *sra = sysfs_read(-1, md->devnm, GET_DEVS); struct mdinfo *sd; if (!sra) continue; for (sd = sra->devs ; sd ; sd = sd->next) { char namebuf[100]; char dn[30]; int dfd; int ok; int devid; struct supertype *st; char *subarray = NULL; char *path; struct mdinfo *info; sprintf(dn, "%d:%d", sd->disk.major, sd->disk.minor); dfd = dev_open(dn, O_RDONLY); if (dfd < 0) continue; st = guess_super(dfd); if ( st == NULL) ok = -1; else { subarray = get_member_info(md); ok = st->ss->load_super(st, dfd, NULL); } close(dfd); if (ok != 0) continue; if (subarray) info = st->ss->container_content(st, subarray); else { info = xmalloc(sizeof(*info)); st->ss->getinfo_super(st, info, NULL); } if (!info) continue; devid = devnm2devid(md->devnm); path = map_dev(major(devid), minor(devid), 0); if (path == NULL || strncmp(path, "/dev/md/", 8) != 0) { /* We would really like a name that provides * an MD_DEVNAME for udev. * The name needs to be unique both in /dev/md/ * and in this mapfile. * It needs to match what -I or -As would come * up with. * That means: * Check if array is in mdadm.conf * - if so use that. * determine trustworthy from homehost etc * find a unique name based on metadata name. * */ struct mddev_ident *match = conf_match(st, info, NULL, 0, NULL); struct stat stb; if (match && match->devname && match->devname[0] == '/') { path = match->devname; if (path[0] != '/') { strcpy(namebuf, "/dev/md/"); strcat(namebuf, path); path = namebuf; } } else { int unum = 0; char *sep = "_"; const char *name; int conflict = 1; if ((homehost == NULL || st->ss->match_home(st, homehost) != 1) && st->ss->match_home(st, "any") != 1 && (require_homehost || ! conf_name_is_free(info->name))) /* require a numeric suffix */ unum = 0; else /* allow name to be used as-is if no conflict */ unum = -1; name = info->name; if (!*name) { name = st->ss->name; if (!isdigit(name[strlen(name)-1]) && unum == -1) { unum = 0; sep = ""; } } if (strchr(name, ':')) { /* Probably a uniquifying * hostname prefix. Allow * without a suffix, and strip * hostname if it is us. */ if (homehost && unum == -1 && strncmp(name, homehost, strlen(homehost)) == 0 && name[strlen(homehost)] == ':') name += strlen(homehost)+1; unum = -1; } while (conflict) { if (unum >= 0) sprintf(namebuf, "/dev/md/%s%s%d", name, sep, unum); else sprintf(namebuf, "/dev/md/%s", name); unum++; if (lstat(namebuf, &stb) != 0 && (map == NULL || !map_by_name(&map, namebuf+8))) conflict = 0; } path = namebuf; } } map_add(&map, md->devnm, info->text_version, info->uuid, path); st->ss->free_super(st); free(info); break; } sysfs_free(sra); } /* Only trigger a change if we wrote a new map file */ if (map_write(map)) for (md = mdstat ; md ; md = md->next) { struct mdinfo *sra = sysfs_read(-1, md->devnm, GET_VERSION); if (sra) sysfs_uevent(sra, "change"); sysfs_free(sra); } map_free(map); free_mdstat(mdstat); }
int Manage_subdevs(char *devname, int fd, struct mddev_dev *devlist, int verbose, int test, char *update) { /* do something to each dev. * devmode can be * 'a' - add the device * try HOT_ADD_DISK * If that fails EINVAL, try ADD_NEW_DISK * 'r' - remove the device HOT_REMOVE_DISK * device can be 'faulty' or 'detached' in which case all * matching devices are removed. * 'f' - set the device faulty SET_DISK_FAULTY * device can be 'detached' in which case any device that * is inaccessible will be marked faulty. * For 'f' and 'r', the device can also be a kernel-internal * name such as 'sdb'. */ struct mddev_dev *add_devlist = NULL; mdu_array_info_t array; mdu_disk_info_t disc; unsigned long long array_size; struct mddev_dev *dv, *next = NULL; struct stat stb; int j, jnext = 0; int tfd = -1; struct supertype *st, *tst; char *subarray = NULL; int duuid[4]; int ouuid[4]; int lfd = -1; int sysfd = -1; int count = 0; /* number of actions taken */ if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": cannot get array info for %s\n", devname); return 1; } /* array.size is only 32 bit and may be truncated. * So read from sysfs if possible, and record number of sectors */ array_size = get_component_size(fd); if (array_size <= 0) array_size = array.size * 2; tst = super_by_fd(fd, &subarray); if (!tst) { fprintf(stderr, Name ": unsupport array - version %d.%d\n", array.major_version, array.minor_version); return 1; } stb.st_rdev = 0; for (dv = devlist, j=0 ; dv; dv = next, j = jnext) { unsigned long long ldsize; char dvname[20]; char *dnprintable = dv->devname; char *add_dev = dv->devname; int err; int re_add_failed = 0; next = dv->next; jnext = 0; if (strcmp(dv->devname, "failed")==0 || strcmp(dv->devname, "faulty")==0) { int remaining_disks = array.nr_disks; if (dv->disposition != 'r') { fprintf(stderr, Name ": %s only meaningful " "with -r, not -%c\n", dv->devname, dv->disposition); return 1; } for (; j < 1024 && remaining_disks > 0; j++) { unsigned dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major == 0 && disc.minor == 0) continue; remaining_disks --; if ((disc.state & 1) == 0) /* faulty */ continue; dev = makedev(disc.major, disc.minor); if (stb.st_rdev == dev) /* already did that one */ continue; stb.st_rdev = dev; next = dv; /* same slot again next time - things might * have reshuffled */ jnext = j; sprintf(dvname,"%d:%d", disc.major, disc.minor); dnprintable = dvname; break; } if (next != dv) continue; } else if (strcmp(dv->devname, "detached") == 0) { int remaining_disks = array.nr_disks; if (dv->disposition != 'r' && dv->disposition != 'f') { fprintf(stderr, Name ": %s only meaningful " "with -r of -f, not -%c\n", dv->devname, dv->disposition); return 1; } for (; j < 1024 && remaining_disks > 0; j++) { int sfd; unsigned dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major == 0 && disc.minor == 0) continue; remaining_disks --; sprintf(dvname,"%d:%d", disc.major, disc.minor); sfd = dev_open(dvname, O_RDONLY); if (sfd >= 0) { close(sfd); continue; } if (dv->disposition == 'f' && (disc.state & 1) == 1) /* already faulty */ continue; if (errno != ENXIO) continue; dev = makedev(disc.major, disc.minor); if (stb.st_rdev == dev) /* already did that one */ continue; stb.st_rdev = dev; next = dv; /* same slot again next time - things might * have reshuffled */ jnext = j; dnprintable = dvname; break; } if (next != dv) continue; } else if (strcmp(dv->devname, "missing") == 0) { if (dv->disposition != 'a' || dv->re_add == 0) { fprintf(stderr, Name ": 'missing' only meaningful " "with --re-add\n"); return 1; } if (add_devlist == NULL) add_devlist = conf_get_devs(); if (add_devlist == NULL) { fprintf(stderr, Name ": no devices to scan for missing members."); continue; } add_dev = add_devlist->devname; add_devlist = add_devlist->next; if (add_devlist != NULL) next = dv; if (stat(add_dev, &stb) < 0) continue; } else if (strchr(dv->devname, '/') == NULL && strchr(dv->devname, ':') == NULL && strlen(dv->devname) < 50) { /* Assume this is a kernel-internal name like 'sda1' */ int found = 0; char dname[55]; if (dv->disposition != 'r' && dv->disposition != 'f') { fprintf(stderr, Name ": %s only meaningful " "with -r or -f, not -%c\n", dv->devname, dv->disposition); return 1; } sprintf(dname, "dev-%s", dv->devname); sysfd = sysfs_open(fd2devnum(fd), dname, "block/dev"); if (sysfd >= 0) { char dn[20]; int mj,mn; if (sysfs_fd_get_str(sysfd, dn, 20) > 0 && sscanf(dn, "%d:%d", &mj,&mn) == 2) { stb.st_rdev = makedev(mj,mn); found = 1; } close(sysfd); sysfd = -1; } if (!found) { sysfd = sysfs_open(fd2devnum(fd), dname, "state"); if (sysfd < 0) { fprintf(stderr, Name ": %s does not appear " "to be a component of %s\n", dv->devname, devname); return 1; } } } else { j = 0; tfd = dev_open(dv->devname, O_RDONLY); if (tfd < 0 && dv->disposition == 'r' && lstat(dv->devname, &stb) == 0) /* Be happy, the lstat worked, that is * enough for --remove */ ; else { if (tfd < 0 || fstat(tfd, &stb) != 0) { fprintf(stderr, Name ": cannot find %s: %s\n", dv->devname, strerror(errno)); if (tfd >= 0) close(tfd); return 1; } close(tfd); tfd = -1; } if ((stb.st_mode & S_IFMT) != S_IFBLK) { fprintf(stderr, Name ": %s is not a " "block device.\n", dv->devname); return 1; } } switch(dv->disposition){ default: fprintf(stderr, Name ": internal error - devmode[%s]=%d\n", dv->devname, dv->disposition); return 1; case 'a': /* add the device */ if (subarray) { fprintf(stderr, Name ": Cannot add disks to a" " \'member\' array, perform this" " operation on the parent container\n"); return 1; } /* Make sure it isn't in use (in 2.6 or later) */ tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT); if (tfd < 0 && add_dev != dv->devname) continue; if (tfd < 0) { fprintf(stderr, Name ": Cannot open %s: %s\n", dv->devname, strerror(errno)); return 1; } st = dup_super(tst); if (array.not_persistent==0) st->ss->load_super(st, tfd, NULL); if (add_dev == dv->devname) { if (!get_dev_size(tfd, dv->devname, &ldsize)) { close(tfd); return 1; } } else if (!get_dev_size(tfd, NULL, &ldsize)) { close(tfd); tfd = -1; continue; } if (!tst->ss->external && array.major_version == 0 && md_get_version(fd)%100 < 2) { close(tfd); tfd = -1; if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) { if (verbose >= 0) fprintf(stderr, Name ": hot added %s\n", add_dev); continue; } fprintf(stderr, Name ": hot add failed for %s: %s\n", add_dev, strerror(errno)); return 1; } if (array.not_persistent == 0 || tst->ss->external) { /* need to find a sample superblock to copy, and * a spare slot to use. * For 'external' array (well, container based), * We can just load the metadata for the array. */ if (tst->sb) /* already loaded */; else if (tst->ss->external) { tst->ss->load_container(tst, fd, NULL); } else for (j = 0; j < tst->max_devs; j++) { char *dev; int dfd; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major==0 && disc.minor==0) continue; if ((disc.state & 4)==0) continue; /* sync */ /* Looks like a good device to try */ dev = map_dev(disc.major, disc.minor, 1); if (!dev) continue; dfd = dev_open(dev, O_RDONLY); if (dfd < 0) continue; if (tst->ss->load_super(tst, dfd, NULL)) { close(dfd); continue; } close(dfd); break; } /* FIXME this is a bad test to be using */ if (!tst->sb) { close(tfd); fprintf(stderr, Name ": cannot load array metadata from %s\n", devname); return 1; } /* Make sure device is large enough */ if (tst->ss->avail_size(tst, ldsize/512) < array_size) { close(tfd); tfd = -1; if (add_dev != dv->devname) continue; fprintf(stderr, Name ": %s not large enough to join array\n", dv->devname); return 1; } /* Possibly this device was recently part of the array * and was temporarily removed, and is now being re-added. * If so, we can simply re-add it. */ tst->ss->uuid_from_super(tst, duuid); if (st->sb) { struct mdinfo mdi; st->ss->getinfo_super(st, &mdi, NULL); st->ss->uuid_from_super(st, ouuid); if ((mdi.disk.state & (1<<MD_DISK_ACTIVE)) && !(mdi.disk.state & (1<<MD_DISK_FAULTY)) && memcmp(duuid, ouuid, sizeof(ouuid))==0) { /* look like it is worth a try. Need to * make sure kernel will accept it though. */ /* re-add doesn't work for version-1 superblocks * before 2.6.18 :-( */ if (array.major_version == 1 && get_linux_version() <= 2006018) goto skip_re_add; disc.number = mdi.disk.number; if (ioctl(fd, GET_DISK_INFO, &disc) != 0 || disc.major != 0 || disc.minor != 0 || !enough_fd(fd)) goto skip_re_add; disc.major = major(stb.st_rdev); disc.minor = minor(stb.st_rdev); disc.number = mdi.disk.number; disc.raid_disk = mdi.disk.raid_disk; disc.state = mdi.disk.state; if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; if (dv->writemostly == 2) disc.state &= ~(1 << MD_DISK_WRITEMOSTLY); remove_partitions(tfd); close(tfd); tfd = -1; if (update) { int rv = -1; tfd = dev_open(dv->devname, O_RDWR); if (tfd >= 0) rv = st->ss->update_super( st, NULL, update, devname, verbose, 0, NULL); if (rv == 0) rv = st->ss->store_super(st, tfd); close(tfd); tfd = -1; if (rv != 0) { fprintf(stderr, Name ": failed to update" " superblock during re-add\n"); return 1; } } /* don't even try if disk is marked as faulty */ errno = 0; if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) { if (verbose >= 0) fprintf(stderr, Name ": re-added %s\n", add_dev); count++; continue; } if (errno == ENOMEM || errno == EROFS) { fprintf(stderr, Name ": add new device failed for %s: %s\n", add_dev, strerror(errno)); if (add_dev != dv->devname) continue; return 1; } skip_re_add: re_add_failed = 1; } st->ss->free_super(st); } if (add_dev != dv->devname) { if (verbose > 0) fprintf(stderr, Name ": --re-add for %s to %s is not possible\n", add_dev, devname); if (tfd >= 0) { close(tfd); tfd = -1; } continue; } if (dv->re_add) { if (tfd >= 0) close(tfd); fprintf(stderr, Name ": --re-add for %s to %s is not possible\n", dv->devname, devname); return 1; } if (re_add_failed) { fprintf(stderr, Name ": %s reports being an active member for %s, but a --re-add fails.\n", dv->devname, devname); fprintf(stderr, Name ": not performing --add as that would convert %s in to a spare.\n", dv->devname); fprintf(stderr, Name ": To make this a spare, use \"mdadm --zero-superblock %s\" first.\n", dv->devname); if (tfd >= 0) close(tfd); return 1; } } else { /* non-persistent. Must ensure that new drive * is at least array.size big. */ if (ldsize/512 < array_size) { fprintf(stderr, Name ": %s not large enough to join array\n", dv->devname); if (tfd >= 0) close(tfd); return 1; } } /* committed to really trying this device now*/ if (tfd >= 0) { remove_partitions(tfd); close(tfd); tfd = -1; } /* in 2.6.17 and earlier, version-1 superblocks won't * use the number we write, but will choose a free number. * we must choose the same free number, which requires * starting at 'raid_disks' and counting up */ for (j = array.raid_disks; j< tst->max_devs; j++) { disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) break; if (disc.major==0 && disc.minor==0) break; if (disc.state & 8) /* removed */ break; } disc.major = major(stb.st_rdev); disc.minor = minor(stb.st_rdev); disc.number =j; disc.state = 0; if (array.not_persistent==0) { int dfd; if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); if (tst->ss->add_to_super(tst, &disc, dfd, dv->devname)) { close(dfd); return 1; } if (tst->ss->write_init_super(tst)) { close(dfd); return 1; } } else if (dv->re_add) { /* this had better be raid1. * As we are "--re-add"ing we must find a spare slot * to fill. */ char *used = malloc(array.raid_disks); memset(used, 0, array.raid_disks); for (j=0; j< tst->max_devs; j++) { mdu_disk_info_t disc2; disc2.number = j; if (ioctl(fd, GET_DISK_INFO, &disc2)) continue; if (disc2.major==0 && disc2.minor==0) continue; if (disc2.state & 8) /* removed */ continue; if (disc2.raid_disk < 0) continue; if (disc2.raid_disk > array.raid_disks) continue; used[disc2.raid_disk] = 1; } for (j=0 ; j<array.raid_disks; j++) if (!used[j]) { disc.raid_disk = j; disc.state |= (1<<MD_DISK_SYNC); break; } free(used); } if (dv->writemostly == 1) disc.state |= (1 << MD_DISK_WRITEMOSTLY); if (tst->ss->external) { /* add a disk * to an external metadata container */ struct mdinfo new_mdi; struct mdinfo *sra; int container_fd; int devnum = fd2devnum(fd); int dfd; container_fd = open_dev_excl(devnum); if (container_fd < 0) { fprintf(stderr, Name ": add failed for %s:" " could not get exclusive access to container\n", dv->devname); tst->ss->free_super(tst); return 1; } dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); if (mdmon_running(tst->container_dev)) tst->update_tail = &tst->updates; if (tst->ss->add_to_super(tst, &disc, dfd, dv->devname)) { close(dfd); close(container_fd); return 1; } if (tst->update_tail) flush_metadata_updates(tst); else tst->ss->sync_metadata(tst); sra = sysfs_read(container_fd, -1, 0); if (!sra) { fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n", dv->devname); close(container_fd); tst->ss->free_super(tst); return 1; } sra->array.level = LEVEL_CONTAINER; /* Need to set data_offset and component_size */ tst->ss->getinfo_super(tst, &new_mdi, NULL); new_mdi.disk.major = disc.major; new_mdi.disk.minor = disc.minor; new_mdi.recovery_start = 0; /* Make sure fds are closed as they are O_EXCL which * would block add_disk */ tst->ss->free_super(tst); if (sysfs_add_disk(sra, &new_mdi, 0) != 0) { fprintf(stderr, Name ": add new device to external metadata" " failed for %s\n", dv->devname); close(container_fd); sysfs_free(sra); return 1; } ping_monitor_by_id(devnum); sysfs_free(sra); close(container_fd); } else { tst->ss->free_super(tst); if (ioctl(fd, ADD_NEW_DISK, &disc)) { fprintf(stderr, Name ": add new device failed for %s as %d: %s\n", dv->devname, j, strerror(errno)); return 1; } } if (verbose >= 0) fprintf(stderr, Name ": added %s\n", dv->devname); break; case 'r': /* hot remove */ if (subarray) { fprintf(stderr, Name ": Cannot remove disks from a" " \'member\' array, perform this" " operation on the parent container\n"); if (sysfd >= 0) close(sysfd); return 1; } if (tst->ss->external) { /* To remove a device from a container, we must * check that it isn't in use in an array. * This involves looking in the 'holders' * directory - there must be just one entry, * the container. * To ensure that it doesn't get used as a * hold spare while we are checking, we * get an O_EXCL open on the container */ int dnum = fd2devnum(fd); lfd = open_dev_excl(dnum); if (lfd < 0) { fprintf(stderr, Name ": Cannot get exclusive access " " to container - odd\n"); if (sysfd >= 0) close(sysfd); return 1; } /* in the detached case it is not possible to * check if we are the unique holder, so just * rely on the 'detached' checks */ if (strcmp(dv->devname, "detached") == 0 || sysfd >= 0 || sysfs_unique_holder(dnum, stb.st_rdev)) /* pass */; else { fprintf(stderr, Name ": %s is %s, cannot remove.\n", dnprintable, errno == EEXIST ? "still in use": "not a member"); close(lfd); return 1; } } /* FIXME check that it is a current member */ if (sysfd >= 0) { /* device has been removed and we don't know * the major:minor number */ int n = write(sysfd, "remove", 6); if (n != 6) err = -1; else err = 0; close(sysfd); sysfd = -1; } else { err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev); if (err && errno == ENODEV) { /* Old kernels rejected this if no personality * registered */ struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS); struct mdinfo *dv = NULL; if (sra) dv = sra->devs; for ( ; dv ; dv=dv->next) if (dv->disk.major == (int)major(stb.st_rdev) && dv->disk.minor == (int)minor(stb.st_rdev)) break; if (dv) err = sysfs_set_str(sra, dv, "state", "remove"); else err = -1; if (sra) sysfs_free(sra); } } if (err) { fprintf(stderr, Name ": hot remove failed " "for %s: %s\n", dnprintable, strerror(errno)); if (lfd >= 0) close(lfd); return 1; } if (tst->ss->external) { /* * Before dropping our exclusive open we make an * attempt at preventing mdmon from seeing an * 'add' event before reconciling this 'remove' * event. */ char *name = devnum2devname(fd2devnum(fd)); if (!name) { fprintf(stderr, Name ": unable to get container name\n"); return 1; } ping_manager(name); free(name); } if (lfd >= 0) close(lfd); count++; if (verbose >= 0) fprintf(stderr, Name ": hot removed %s from %s\n", dnprintable, devname); break; case 'f': /* set faulty */ /* FIXME check current member */ if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev))) { fprintf(stderr, Name ": set device faulty failed for %s: %s\n", dnprintable, strerror(errno)); if (sysfd >= 0) close(sysfd); return 1; } if (sysfd >= 0) close(sysfd); sysfd = -1; count++; if (verbose >= 0) fprintf(stderr, Name ": set %s faulty in %s\n", dnprintable, devname); break; } } if (test && count == 0) return 2; return 0; }
/* Turn file (or device node) into class name */ static int affinity_file(struct bitmask *mask, char *cls, const char *file) { struct stat st; DIR *dir; int n; unsigned maj = 0, min = 0; dev_t d; struct dirent de, *dep; cls = "block"; char fn[sizeof("/sys/class/") + strlen(cls)]; if (stat(file, &st) < 0) { numa_warn(W_blockdev1, "Cannot stat file %s", file); return -1; } d = st.st_dev; if (S_ISCHR(st.st_mode)) { /* Better choice than misc? Most likely misc will not work anyways unless the kernel is fixed. */ cls = "misc"; d = st.st_rdev; } else if (S_ISBLK(st.st_mode)) d = st.st_rdev; sprintf(fn, "/sys/class/%s", cls); dir = opendir(fn); if (!dir) { numa_warn(W_blockdev2, "Cannot enumerate %s devices in sysfs", cls); return -1; } while (readdir_r(dir, &de, &dep) == 0 && dep) { char *name = dep->d_name; if (*name == '.') continue; char *dev; char fn2[sizeof("/sys/class/block//dev") + strlen(name)]; n = -1; if (sprintf(fn2, "/sys/class/block/%s/dev", name) < 0) break; dev = sysfs_read(fn2); if (dev) { n = sscanf(dev, "%u:%u", &maj, &min); free(dev); } if (n != 2) { numa_warn(W_blockdev3, "Cannot parse sysfs device %s", name); continue; } if (major(d) != maj || minor(d) != min) continue; closedir(dir); return affinity_class(mask, "block", name); } closedir(dir); numa_warn(W_blockdev5, "Cannot find block device %x:%x in sysfs for `%s'", maj, min, file); return -1; }
int main(int argc, char *argv[]) { /* md_device start length */ int *fds = NULL; char *buf = NULL; char **disk_name = NULL; unsigned long long *offsets = NULL; int raid_disks = 0; int active_disks; int chunk_size = 0; int layout = -1; int level = 6; int repair = 0; int failed_disk1, failed_disk2; unsigned long long start, length; int i; int mdfd; struct mdinfo *info = NULL, *comp = NULL; char *err = NULL; int exit_err = 0; int close_flag = 0; char *prg = strrchr(argv[0], '/'); if (prg == NULL) prg = argv[0]; else prg++; if (argc < 4) { fprintf(stderr, "Usage: %s md_device start_stripe length_stripes [autorepair]\n", prg); fprintf(stderr, " or: %s md_device repair stripe failed_slot_1 failed_slot_2\n", prg); exit_err = 1; goto exitHere; } mdfd = open(argv[1], O_RDONLY); if(mdfd < 0) { perror(argv[1]); fprintf(stderr, "%s: cannot open %s\n", prg, argv[1]); exit_err = 2; goto exitHere; } info = sysfs_read(mdfd, -1, GET_LEVEL| GET_LAYOUT| GET_DISKS| GET_DEGRADED | GET_COMPONENT| GET_CHUNK| GET_DEVS| GET_OFFSET| GET_SIZE); if(info == NULL) { fprintf(stderr, "%s: Error reading sysfs information of %s\n", prg, argv[1]); exit_err = 9; goto exitHere; } if(info->array.level != level) { fprintf(stderr, "%s: %s not a RAID-6\n", prg, argv[1]); exit_err = 3; goto exitHere; } if(info->array.failed_disks > 0) { fprintf(stderr, "%s: %s degraded array\n", prg, argv[1]); exit_err = 8; goto exitHere; } printf("layout: %d\n", info->array.layout); printf("disks: %d\n", info->array.raid_disks); printf("component size: %llu\n", info->component_size * 512); printf("total stripes: %llu\n", (info->component_size * 512) / info->array.chunk_size); printf("chunk size: %d\n", info->array.chunk_size); printf("\n"); comp = info->devs; for(i = 0, active_disks = 0; active_disks < info->array.raid_disks; i++) { printf("disk: %d - offset: %llu - size: %llu - name: %s - slot: %d\n", i, comp->data_offset * 512, comp->component_size * 512, map_dev(comp->disk.major, comp->disk.minor, 0), comp->disk.raid_disk); if(comp->disk.raid_disk >= 0) active_disks++; comp = comp->next; } printf("\n"); close(mdfd); raid_disks = info->array.raid_disks; chunk_size = info->array.chunk_size; layout = info->array.layout; if (strcmp(argv[2], "repair")==0) { if (argc < 6) { fprintf(stderr, "For repair mode, call %s md_device repair stripe failed_slot_1 failed_slot_2\n", prg); exit_err = 1; goto exitHere; } repair = 1; start = getnum(argv[3], &err); length = 1; failed_disk1 = getnum(argv[4], &err); failed_disk2 = getnum(argv[5], &err); if(failed_disk1 >= info->array.raid_disks) { fprintf(stderr, "%s: failed_slot_1 index is higher than number of devices in raid\n", prg); exit_err = 4; goto exitHere; } if(failed_disk2 >= info->array.raid_disks) { fprintf(stderr, "%s: failed_slot_2 index is higher than number of devices in raid\n", prg); exit_err = 4; goto exitHere; } if(failed_disk1 == failed_disk2) { fprintf(stderr, "%s: failed_slot_1 and failed_slot_2 are the same\n", prg); exit_err = 4; goto exitHere; } } else { start = getnum(argv[2], &err); length = getnum(argv[3], &err); if (argc >= 5 && strcmp(argv[4], "autorepair")==0) repair = 2; } if (err) { fprintf(stderr, "%s: Bad number: %s\n", prg, err); exit_err = 4; goto exitHere; } if(start > ((info->component_size * 512) / chunk_size)) { start = (info->component_size * 512) / chunk_size; fprintf(stderr, "%s: start beyond disks size\n", prg); } if((length == 0) || ((length + start) > ((info->component_size * 512) / chunk_size))) { length = (info->component_size * 512) / chunk_size - start; } disk_name = xmalloc(raid_disks * sizeof(*disk_name)); fds = xmalloc(raid_disks * sizeof(*fds)); offsets = xcalloc(raid_disks, sizeof(*offsets)); buf = xmalloc(raid_disks * chunk_size); for(i=0; i<raid_disks; i++) { fds[i] = -1; } close_flag = 1; comp = info->devs; for (i=0, active_disks=0; active_disks<raid_disks; i++) { int disk_slot = comp->disk.raid_disk; if(disk_slot >= 0) { disk_name[disk_slot] = map_dev(comp->disk.major, comp->disk.minor, 0); offsets[disk_slot] = comp->data_offset * 512; fds[disk_slot] = open(disk_name[disk_slot], O_RDWR); if (fds[disk_slot] < 0) { perror(disk_name[disk_slot]); fprintf(stderr,"%s: cannot open %s\n", prg, disk_name[disk_slot]); exit_err = 6; goto exitHere; } active_disks++; } comp = comp->next; } int rv = check_stripes(info, fds, offsets, raid_disks, chunk_size, level, layout, start, length, disk_name, repair, failed_disk1, failed_disk2); if (rv != 0) { fprintf(stderr, "%s: check_stripes returned %d\n", prg, rv); exit_err = 7; goto exitHere; } exitHere: if (close_flag) for(i = 0; i < raid_disks; i++) close(fds[i]); free(disk_name); free(fds); free(offsets); free(buf); exit(exit_err); }
int Monitor(mddev_dev_t devlist, char *mailaddr, char *alert_cmd, int period, int daemonise, int scan, int oneshot, int dosyslog, int test, char* pidfile, int increments) { /* * Every few seconds, scan every md device looking for changes * When a change is found, log it, possibly run the alert command, * and possibly send Email * * For each array, we record: * Update time * active/working/failed/spare drives * State of each device. * %rebuilt if rebuilding * * If the update time changes, check out all the data again * It is possible that we cannot get the state of each device * due to bugs in the md kernel module. * We also read /proc/mdstat to get rebuild percent, * and to get state on all active devices incase of kernel bug. * * Events are: * Fail * An active device had Faulty set or Active/Sync removed * FailSpare * A spare device had Faulty set * SpareActive * An active device had a reverse transition * RebuildStarted * percent went from -1 to +ve * RebuildNN * percent went from below to not-below NN% * DeviceDisappeared * Couldn't access a device which was previously visible * * if we detect an array with active<raid and spare==0 * we look at other arrays that have same spare-group * If we find one with active==raid and spare>0, * and if we can get_disk_info and find a name * Then we hot-remove and hot-add to the other array * * If devlist is NULL, then we can monitor everything because --scan * was given. We get an initial list from config file and add anything * that appears in /proc/mdstat */ struct state { char *devname; int devnum; /* to sync with mdstat info */ long utime; int err; char *spare_group; int active, working, failed, spare, raid; int expected_spares; int devstate[MaxDisks]; unsigned devid[MaxDisks]; int percent; struct state *next; } *statelist = NULL; int finished = 0; struct mdstat_ent *mdstat = NULL; char *mailfrom = NULL; if (!mailaddr) { mailaddr = conf_get_mailaddr(); if (mailaddr && ! scan) fprintf(stderr, Name ": Monitor using email address \"%s\" from config file\n", mailaddr); } mailfrom = conf_get_mailfrom(); if (!alert_cmd) { alert_cmd = conf_get_program(); if (alert_cmd && ! scan) fprintf(stderr, Name ": Monitor using program \"%s\" from config file\n", alert_cmd); } if (scan && !mailaddr && !alert_cmd) { fprintf(stderr, Name ": No mail address or alert command - not monitoring.\n"); return 1; } if (daemonise) { int pid = fork(); if (pid > 0) { if (!pidfile) printf("%d\n", pid); else { FILE *pid_file; pid_file=fopen(pidfile, "w"); if (!pid_file) perror("cannot create pid file"); else { fprintf(pid_file,"%d\n", pid); fclose(pid_file); } } return 0; } if (pid < 0) { perror("daemonise"); return 1; } close(0); open("/dev/null", O_RDWR); dup2(0,1); dup2(0,2); setsid(); } if (devlist == NULL) { mddev_ident_t mdlist = conf_get_ident(NULL); for (; mdlist; mdlist=mdlist->next) { struct state *st; if (mdlist->devname == NULL) continue; if (strcasecmp(mdlist->devname, "<ignore>") == 0) continue; st = malloc(sizeof *st); if (st == NULL) continue; if (mdlist->devname[0] == '/') st->devname = strdup(mdlist->devname); else { st->devname = malloc(8+strlen(mdlist->devname)+1); strcpy(strcpy(st->devname, "/dev/md/"), mdlist->devname); } st->utime = 0; st->next = statelist; st->err = 0; st->devnum = INT_MAX; st->percent = -2; st->expected_spares = mdlist->spare_disks; if (mdlist->spare_group) st->spare_group = strdup(mdlist->spare_group); else st->spare_group = NULL; statelist = st; } } else { mddev_dev_t dv; for (dv=devlist ; dv; dv=dv->next) { mddev_ident_t mdlist = conf_get_ident(dv->devname); struct state *st = malloc(sizeof *st); if (st == NULL) continue; st->devname = strdup(dv->devname); st->utime = 0; st->next = statelist; st->err = 0; st->devnum = INT_MAX; st->percent = -2; st->expected_spares = -1; st->spare_group = NULL; if (mdlist) { st->expected_spares = mdlist->spare_disks; if (mdlist->spare_group) st->spare_group = strdup(mdlist->spare_group); } statelist = st; } } while (! finished) { int new_found = 0; struct state *st; if (mdstat) free_mdstat(mdstat); mdstat = mdstat_read(oneshot?0:1, 0); for (st=statelist; st; st=st->next) { struct { int state, major, minor; } info[MaxDisks]; mdu_array_info_t array; struct mdstat_ent *mse = NULL, *mse2; char *dev = st->devname; int fd; int i; if (test) alert("TestMessage", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); fd = open(dev, O_RDONLY); if (fd < 0) { if (!st->err) alert("DeviceDisappeared", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); /* fprintf(stderr, Name ": cannot open %s: %s\n", dev, strerror(errno)); */ st->err=1; continue; } fcntl(fd, F_SETFD, FD_CLOEXEC); if (ioctl(fd, GET_ARRAY_INFO, &array)<0) { if (!st->err) alert("DeviceDisappeared", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); /* fprintf(stderr, Name ": cannot get array info for %s: %s\n", dev, strerror(errno)); */ st->err=1; close(fd); continue; } /* It's much easier to list what array levels can't * have a device disappear than all of them that can */ if (array.level == 0 || array.level == -1) { if (!st->err) alert("DeviceDisappeared", dev, "Wrong-Level", mailaddr, mailfrom, alert_cmd, dosyslog); st->err = 1; close(fd); continue; } if (st->devnum == INT_MAX) { struct stat stb; if (fstat(fd, &stb) == 0 && (S_IFMT&stb.st_mode)==S_IFBLK) { if (major(stb.st_rdev) == MD_MAJOR) st->devnum = minor(stb.st_rdev); else st->devnum = -1- (minor(stb.st_rdev)>>6); } } for (mse2 = mdstat ; mse2 ; mse2=mse2->next) if (mse2->devnum == st->devnum) { mse2->devnum = INT_MAX; /* flag it as "used" */ mse = mse2; } if (array.utime == 0) /* external arrays don't update utime */ array.utime = time(0); if (st->utime == array.utime && st->failed == array.failed_disks && st->working == array.working_disks && st->spare == array.spare_disks && (mse == NULL || ( mse->percent == st->percent ))) { close(fd); st->err = 0; continue; } if (st->utime == 0 && /* new array */ mse && /* is in /proc/mdstat */ mse->pattern && strchr(mse->pattern, '_') /* degraded */ ) alert("DegradedArray", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); if (st->utime == 0 && /* new array */ st->expected_spares > 0 && array.spare_disks < st->expected_spares) alert("SparesMissing", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); if (mse && st->percent == -1 && mse->percent >= 0) alert("RebuildStarted", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); if (mse && st->percent >= 0 && mse->percent >= 0 && (mse->percent / increments) > (st->percent / increments)) { char percentalert[15]; // "RebuildNN" (10 chars) or "RebuildStarted" (15 chars) if((mse->percent / increments) == 0) snprintf(percentalert, sizeof(percentalert), "RebuildStarted"); else snprintf(percentalert, sizeof(percentalert), "Rebuild%02d", mse->percent); alert(percentalert, dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); } if (mse && mse->percent == -1 && st->percent >= 0) { /* Rebuild/sync/whatever just finished. * If there is a number in /mismatch_cnt, * we should report that. */ struct mdinfo *sra = sysfs_read(-1, st->devnum, GET_MISMATCH); if (sra && sra->mismatch_cnt > 0) { char cnt[40]; sprintf(cnt, " mismatches found: %d", sra->mismatch_cnt); alert("RebuildFinished", dev, cnt, mailaddr, mailfrom, alert_cmd, dosyslog); } else alert("RebuildFinished", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); if (sra) free(sra); } if (mse) st->percent = mse->percent; for (i=0; i<MaxDisks && i <= array.raid_disks + array.nr_disks; i++) { mdu_disk_info_t disc; disc.number = i; if (ioctl(fd, GET_DISK_INFO, &disc) >= 0) { info[i].state = disc.state; info[i].major = disc.major; info[i].minor = disc.minor; } else info[i].major = info[i].minor = 0; } close(fd); for (i=0; i<MaxDisks; i++) { mdu_disk_info_t disc = {0,0,0,0,0}; int newstate=0; int change; char *dv = NULL; disc.number = i; if (i > array.raid_disks + array.nr_disks) { newstate = 0; disc.major = disc.minor = 0; } else if (info[i].major || info[i].minor) { newstate = info[i].state; dv = map_dev(info[i].major, info[i].minor, 1); disc.state = newstate; disc.major = info[i].major; disc.minor = info[i].minor; } else if (mse && mse->pattern && i < (int)strlen(mse->pattern)) { switch(mse->pattern[i]) { case 'U': newstate = 6 /* ACTIVE/SYNC */; break; case '_': newstate = 0; break; } disc.major = disc.minor = 0; } if (dv == NULL && st->devid[i]) dv = map_dev(major(st->devid[i]), minor(st->devid[i]), 1); change = newstate ^ st->devstate[i]; if (st->utime && change && !st->err) { if (i < array.raid_disks && (((newstate&change)&(1<<MD_DISK_FAULTY)) || ((st->devstate[i]&change)&(1<<MD_DISK_ACTIVE)) || ((st->devstate[i]&change)&(1<<MD_DISK_SYNC))) ) alert("Fail", dev, dv, mailaddr, mailfrom, alert_cmd, dosyslog); else if (i >= array.raid_disks && (disc.major || disc.minor) && st->devid[i] == makedev(disc.major, disc.minor) && ((newstate&change)&(1<<MD_DISK_FAULTY)) ) alert("FailSpare", dev, dv, mailaddr, mailfrom, alert_cmd, dosyslog); else if (i < array.raid_disks && ! (newstate & (1<<MD_DISK_REMOVED)) && (((st->devstate[i]&change)&(1<<MD_DISK_FAULTY)) || ((newstate&change)&(1<<MD_DISK_ACTIVE)) || ((newstate&change)&(1<<MD_DISK_SYNC))) ) alert("SpareActive", dev, dv, mailaddr, mailfrom, alert_cmd, dosyslog); } st->devstate[i] = newstate; st->devid[i] = makedev(disc.major, disc.minor); } st->active = array.active_disks; st->working = array.working_disks; st->spare = array.spare_disks; st->failed = array.failed_disks; st->utime = array.utime; st->raid = array.raid_disks; st->err = 0; } /* now check if there are any new devices found in mdstat */ if (scan) { struct mdstat_ent *mse; for (mse=mdstat; mse; mse=mse->next) if (mse->devnum != INT_MAX && mse->level && (strcmp(mse->level, "raid0")!=0 && strcmp(mse->level, "linear")!=0) ) { struct state *st = malloc(sizeof *st); mdu_array_info_t array; int fd; if (st == NULL) continue; st->devname = strdup(get_md_name(mse->devnum)); if ((fd = open(st->devname, O_RDONLY)) < 0 || ioctl(fd, GET_ARRAY_INFO, &array)< 0) { /* no such array */ if (fd >=0) close(fd); put_md_name(st->devname); free(st->devname); free(st); continue; } close(fd); st->utime = 0; st->next = statelist; st->err = 1; st->devnum = mse->devnum; st->percent = -2; st->spare_group = NULL; st->expected_spares = -1; statelist = st; if (test) alert("TestMessage", st->devname, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); alert("NewArray", st->devname, NULL, mailaddr, mailfrom, alert_cmd, dosyslog); new_found = 1; } } /* If an array has active < raid && spare == 0 && spare_group != NULL * Look for another array with spare > 0 and active == raid and same spare_group * if found, choose a device and hotremove/hotadd */ for (st = statelist; st; st=st->next) if (st->active < st->raid && st->spare == 0 && st->spare_group != NULL) { struct state *st2; for (st2=statelist ; st2 ; st2=st2->next) if (st2 != st && st2->spare > 0 && st2->active == st2->raid && st2->spare_group != NULL && strcmp(st->spare_group, st2->spare_group) == 0) { /* try to remove and add */ int fd1 = open(st->devname, O_RDONLY); int fd2 = open(st2->devname, O_RDONLY); int dev = -1; int d; if (fd1 < 0 || fd2 < 0) { if (fd1>=0) close(fd1); if (fd2>=0) close(fd2); continue; } for (d=st2->raid; d < MaxDisks; d++) { if (st2->devid[d] > 0 && st2->devstate[d] == 0) { dev = st2->devid[d]; break; } } if (dev > 0) { struct mddev_dev_s devlist; char devname[20]; devlist.next = NULL; devlist.used = 0; devlist.re_add = 0; devlist.writemostly = 0; devlist.devname = devname; sprintf(devname, "%d:%d", major(dev), minor(dev)); devlist.disposition = 'r'; if (Manage_subdevs(st2->devname, fd2, &devlist, -1, 0) == 0) { devlist.disposition = 'a'; if (Manage_subdevs(st->devname, fd1, &devlist, -1, 0) == 0) { alert("MoveSpare", st->devname, st2->devname, mailaddr, mailfrom, alert_cmd, dosyslog); close(fd1); close(fd2); break; } else Manage_subdevs(st2->devname, fd2, &devlist, -1, 0); } } close(fd1); close(fd2); } } if (!new_found) { if (oneshot) break; else mdstat_wait(period); } test = 0; } if (pidfile) unlink(pidfile); return 0; }
uint64_t ad_read(int idx) { char tmp[256]; snprintf(tmp, 256, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw",idx); return (uint64_t) sysfs_read(tmp); }
int WaitClean(char *dev, int sock, int verbose) { int fd; struct mdinfo *mdi; int rv = 1; char devnm[32]; fd = open(dev, O_RDONLY); if (fd < 0) { if (verbose) pr_err("Couldn't open %s: %s\n", dev, strerror(errno)); return 1; } strcpy(devnm, fd2devnm(fd)); mdi = sysfs_read(fd, devnm, GET_VERSION|GET_LEVEL|GET_SAFEMODE); if (!mdi) { if (verbose) pr_err("Failed to read sysfs attributes for %s\n", dev); close(fd); return 0; } switch(mdi->array.level) { case LEVEL_LINEAR: case LEVEL_MULTIPATH: case 0: /* safemode delay is irrelevant for these levels */ rv = 0; } /* for internal metadata the kernel handles the final clean * transition, containers can never be dirty */ if (!is_subarray(mdi->text_version)) rv = 0; /* safemode disabled ? */ if (mdi->safe_mode_delay == 0) rv = 0; if (rv) { int state_fd = sysfs_open(fd2devnm(fd), NULL, "array_state"); char buf[20]; int delay = 5000; /* minimize the safe_mode_delay and prepare to wait up to 5s * for writes to quiesce */ sysfs_set_safemode(mdi, 1); /* wait for array_state to be clean */ while (1) { rv = read(state_fd, buf, sizeof(buf)); if (rv < 0) break; if (sysfs_match_word(buf, clean_states) <= 4) break; rv = sysfs_wait(state_fd, &delay); if (rv < 0 && errno != EINTR) break; lseek(state_fd, 0, SEEK_SET); } if (rv < 0) rv = 1; else if (fping_monitor(sock) == 0 || ping_monitor(mdi->text_version) == 0) { /* we need to ping to close the window between array * state transitioning to clean and the metadata being * marked clean */ rv = 0; } else rv = 1; if (rv && verbose) pr_err("Error waiting for %s to be clean\n", dev); /* restore the original safe_mode_delay */ sysfs_set_safemode(mdi, mdi->safe_mode_delay); close(state_fd); } sysfs_free(mdi); close(fd); return rv; }
static int check_array(struct state *st, struct mdstat_ent *mdstat, int test, struct alert_info *ainfo, int increments, char *prefer) { /* Update the state 'st' to reflect any changes shown in mdstat, * or found by directly examining the array, and return * '1' if the array is degraded, or '0' if it is optimal (or dead). */ struct { int state, major, minor; } info[MAX_DISKS]; mdu_array_info_t array; struct mdstat_ent *mse = NULL, *mse2; char *dev = st->devname; int fd = -1; int i; int remaining_disks; int last_disk; int new_array = 0; if (test) alert("TestMessage", dev, NULL, ainfo); if (st->devnm[0]) fd = open("/sys/block", O_RDONLY|O_DIRECTORY); if (fd >= 0) { /* Don't open the device unless it is present and * active in sysfs. */ char buf[10]; close(fd); fd = sysfs_open(st->devnm, NULL, "array_state"); if (fd < 0 || read(fd, buf, 10) < 5 || strncmp(buf,"clear",5) == 0 || strncmp(buf,"inact",5) == 0) { if (fd >= 0) close(fd); fd = sysfs_open(st->devnm, NULL, "level"); if (fd < 0 || read(fd, buf, 10) != 0) { if (fd >= 0) close(fd); if (!st->err) alert("DeviceDisappeared", dev, NULL, ainfo); st->err++; return 0; } } close(fd); } fd = open(dev, O_RDONLY); if (fd < 0) { if (!st->err) alert("DeviceDisappeared", dev, NULL, ainfo); st->err++; return 0; } fcntl(fd, F_SETFD, FD_CLOEXEC); if (ioctl(fd, GET_ARRAY_INFO, &array)<0) { if (!st->err) alert("DeviceDisappeared", dev, NULL, ainfo); st->err++; close(fd); return 0; } /* It's much easier to list what array levels can't * have a device disappear than all of them that can */ if (array.level == 0 || array.level == -1) { if (!st->err && !st->from_config) alert("DeviceDisappeared", dev, " Wrong-Level", ainfo); st->err++; close(fd); return 0; } if (st->devnm[0] == 0) strcpy(st->devnm, fd2devnm(fd)); for (mse2 = mdstat ; mse2 ; mse2=mse2->next) if (strcmp(mse2->devnm, st->devnm) == 0) { mse2->devnm[0] = 0; /* flag it as "used" */ mse = mse2; } if (!mse) { /* duplicated array in statelist * or re-created after reading mdstat*/ st->err++; close(fd); return 0; } /* this array is in /proc/mdstat */ if (array.utime == 0) /* external arrays don't update utime, so * just make sure it is always different. */ array.utime = st->utime + 1;; if (st->err) { /* New array appeared where previously had an error */ st->err = 0; st->percent = RESYNC_NONE; new_array = 1; alert("NewArray", st->devname, NULL, ainfo); } if (st->utime == array.utime && st->failed == array.failed_disks && st->working == array.working_disks && st->spare == array.spare_disks && (mse == NULL || ( mse->percent == st->percent ))) { close(fd); if ((st->active < st->raid) && st->spare == 0) return 1; else return 0; } if (st->utime == 0 && /* new array */ mse->pattern && strchr(mse->pattern, '_') /* degraded */ ) alert("DegradedArray", dev, NULL, ainfo); if (st->utime == 0 && /* new array */ st->expected_spares > 0 && array.spare_disks < st->expected_spares) alert("SparesMissing", dev, NULL, ainfo); if (st->percent < 0 && st->percent != RESYNC_UNKNOWN && mse->percent >= 0) alert("RebuildStarted", dev, NULL, ainfo); if (st->percent >= 0 && mse->percent >= 0 && (mse->percent / increments) > (st->percent / increments)) { char percentalert[15]; // "RebuildNN" (10 chars) or "RebuildStarted" (15 chars) if((mse->percent / increments) == 0) snprintf(percentalert, sizeof(percentalert), "RebuildStarted"); else snprintf(percentalert, sizeof(percentalert), "Rebuild%02d", mse->percent); alert(percentalert, dev, NULL, ainfo); } if (mse->percent == RESYNC_NONE && st->percent >= 0) { /* Rebuild/sync/whatever just finished. * If there is a number in /mismatch_cnt, * we should report that. */ struct mdinfo *sra = sysfs_read(-1, st->devnm, GET_MISMATCH); if (sra && sra->mismatch_cnt > 0) { char cnt[80]; snprintf(cnt, sizeof(cnt), " mismatches found: %d (on raid level %d)", sra->mismatch_cnt, array.level); alert("RebuildFinished", dev, cnt, ainfo); } else alert("RebuildFinished", dev, NULL, ainfo); if (sra) free(sra); } st->percent = mse->percent; remaining_disks = array.nr_disks; for (i=0; i<MAX_DISKS && remaining_disks > 0; i++) { mdu_disk_info_t disc; disc.number = i; if (ioctl(fd, GET_DISK_INFO, &disc) >= 0) { info[i].state = disc.state; info[i].major = disc.major; info[i].minor = disc.minor; if (disc.major || disc.minor) remaining_disks --; } else info[i].major = info[i].minor = 0; } last_disk = i; if (mse->metadata_version && strncmp(mse->metadata_version, "external:", 9) == 0 && is_subarray(mse->metadata_version+9)) { char *sl; strcpy(st->parent_devnm, mse->metadata_version+10); sl = strchr(st->parent_devnm, '/'); if (sl) *sl = 0; } else st->parent_devnm[0] = 0; if (st->metadata == NULL && st->parent_devnm[0] == 0) st->metadata = super_by_fd(fd, NULL); close(fd); for (i=0; i<MAX_DISKS; i++) { mdu_disk_info_t disc = {0,0,0,0,0}; int newstate=0; int change; char *dv = NULL; disc.number = i; if (i < last_disk && (info[i].major || info[i].minor)) { newstate = info[i].state; dv = map_dev_preferred( info[i].major, info[i].minor, 1, prefer); disc.state = newstate; disc.major = info[i].major; disc.minor = info[i].minor; } else newstate = (1 << MD_DISK_REMOVED); if (dv == NULL && st->devid[i]) dv = map_dev_preferred( major(st->devid[i]), minor(st->devid[i]), 1, prefer); change = newstate ^ st->devstate[i]; if (st->utime && change && !st->err && !new_array) { if ((st->devstate[i]&change)&(1<<MD_DISK_SYNC)) alert("Fail", dev, dv, ainfo); else if ((newstate & (1<<MD_DISK_FAULTY)) && (disc.major || disc.minor) && st->devid[i] == makedev(disc.major, disc.minor)) alert("FailSpare", dev, dv, ainfo); else if ((newstate&change)&(1<<MD_DISK_SYNC)) alert("SpareActive", dev, dv, ainfo); } st->devstate[i] = newstate; st->devid[i] = makedev(disc.major, disc.minor); } st->active = array.active_disks; st->working = array.working_disks; st->spare = array.spare_disks; st->failed = array.failed_disks; st->utime = array.utime; st->raid = array.raid_disks; st->err = 0; if ((st->active < st->raid) && st->spare == 0) return 1; return 0; }
JsVarInt sysfs_read_int(const char *path) { char buf[20]; sysfs_read(path, buf, sizeof(buf)); return stringToIntWithRadix(buf, 10, 0); }
static int mdmon(char *devnm, int must_fork, int takeover) { int mdfd; struct mdinfo *mdi, *di; struct supertype *container; sigset_t set; struct sigaction act; int pfd[2]; int status; int ignore; pid_t victim = -1; int victim_sock = -1; dprintf("starting mdmon for %s\n", devnm); mdfd = open_dev(devnm); if (mdfd < 0) { pr_err("%s: %s\n", devnm, strerror(errno)); return 1; } if (md_get_version(mdfd) < 0) { pr_err("%s: Not an md device\n", devnm); return 1; } /* Fork, and have the child tell us when they are ready */ if (must_fork) { if (pipe(pfd) != 0) { pr_err("failed to create pipe\n"); return 1; } switch(fork()) { case -1: pr_err("failed to fork: %s\n", strerror(errno)); return 1; case 0: /* child */ close(pfd[0]); break; default: /* parent */ close(pfd[1]); if (read(pfd[0], &status, sizeof(status)) != sizeof(status)) { wait(&status); status = WEXITSTATUS(status); } close(pfd[0]); return status; } } else pfd[0] = pfd[1] = -1; container = xcalloc(1, sizeof(*container)); strcpy(container->devnm, devnm); container->arrays = NULL; container->sock = -1; mdi = sysfs_read(mdfd, container->devnm, GET_VERSION|GET_LEVEL|GET_DEVS); if (!mdi) { pr_err("failed to load sysfs info for %s\n", container->devnm); exit(3); } if (mdi->array.level != UnSet) { pr_err("%s is not a container - cannot monitor\n", devnm); exit(3); } if (mdi->array.major_version != -1 || mdi->array.minor_version != -2) { pr_err("%s does not use external metadata - cannot monitor\n", devnm); exit(3); } container->ss = version_to_superswitch(mdi->text_version); if (container->ss == NULL) { pr_err("%s uses unsupported metadata: %s\n", devnm, mdi->text_version); exit(3); } container->devs = NULL; for (di = mdi->devs; di; di = di->next) { struct mdinfo *cd = xmalloc(sizeof(*cd)); *cd = *di; cd->next = container->devs; container->devs = cd; } sysfs_free(mdi); /* SIGUSR is sent between parent and child. So both block it * and enable it only with pselect. */ sigemptyset(&set); sigaddset(&set, SIGUSR1); sigaddset(&set, SIGTERM); sigprocmask(SIG_BLOCK, &set, NULL); act.sa_handler = wake_me; act.sa_flags = 0; sigaction(SIGUSR1, &act, NULL); act.sa_handler = term; sigaction(SIGTERM, &act, NULL); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); victim = mdmon_pid(container->devnm); if (victim >= 0) victim_sock = connect_monitor(container->devnm); ignore = chdir("/"); if (!takeover && victim > 0 && victim_sock >= 0) { if (fping_monitor(victim_sock) == 0) { pr_err("%s already managed\n", container->devnm); exit(3); } close(victim_sock); victim_sock = -1; } if (container->ss->load_container(container, mdfd, devnm)) { pr_err("Cannot load metadata for %s\n", devnm); exit(3); } close(mdfd); /* Ok, this is close enough. We can say goodbye to our parent now. */ if (victim > 0) remove_pidfile(devnm); if (make_pidfile(devnm) < 0) { exit(3); } container->sock = make_control_sock(devnm); status = 0; if (pfd[1] >= 0) { if (write(pfd[1], &status, sizeof(status)) < 0) pr_err("failed to notify our parent: %d\n", getppid()); close(pfd[1]); } mlockall(MCL_CURRENT | MCL_FUTURE); if (clone_monitor(container) < 0) { pr_err("failed to start monitor process: %s\n", strerror(errno)); exit(2); } if (victim > 0) { try_kill_monitor(victim, container->devnm, victim_sock); if (victim_sock >= 0) close(victim_sock); } setsid(); close(0); open("/dev/null", O_RDWR); close(1); ignore = dup(0); #ifndef DEBUG close(2); ignore = dup(0); #endif /* This silliness is to stop the compiler complaining * that we ignore 'ignore' */ if (ignore) ignore++; do_manager(container); exit(0); }
int Manage_ro(char *devname, int fd, int readonly) { /* switch to readonly or rw * * requires >= 0.90.0 * first check that array is runing * use RESTART_ARRAY_RW or STOP_ARRAY_RO * */ mdu_array_info_t array; #ifndef MDASSEMBLE struct mdinfo *mdi; #endif if (md_get_version(fd) < 9000) { fprintf(stderr, Name ": need md driver version 0.90.0 or later\n"); return 1; } #ifndef MDASSEMBLE /* If this is an externally-manage array, we need to modify the * metadata_version so that mdmon doesn't undo our change. */ mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION); if (mdi && mdi->array.major_version == -1 && is_subarray(mdi->text_version)) { char vers[64]; strcpy(vers, "external:"); strcat(vers, mdi->text_version); if (readonly > 0) { int rv; /* We set readonly ourselves. */ vers[9] = '-'; sysfs_set_str(mdi, NULL, "metadata_version", vers); close(fd); rv = sysfs_set_str(mdi, NULL, "array_state", "readonly"); if (rv < 0) { fprintf(stderr, Name ": failed to set readonly for %s: %s\n", devname, strerror(errno)); vers[9] = mdi->text_version[0]; sysfs_set_str(mdi, NULL, "metadata_version", vers); return 1; } } else { char *cp; /* We cannot set read/write - must signal mdmon */ vers[9] = '/'; sysfs_set_str(mdi, NULL, "metadata_version", vers); cp = strchr(vers+10, '/'); if (*cp) *cp = 0; ping_monitor(vers+10); if (mdi->array.level <= 0) sysfs_set_str(mdi, NULL, "array_state", "active"); } return 0; } #endif if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": %s does not appear to be active.\n", devname); return 1; } if (readonly>0) { if (ioctl(fd, STOP_ARRAY_RO, NULL)) { fprintf(stderr, Name ": failed to set readonly for %s: %s\n", devname, strerror(errno)); return 1; } } else if (readonly < 0) { if (ioctl(fd, RESTART_ARRAY_RW, NULL)) { fprintf(stderr, Name ": failed to set writable for %s: %s\n", devname, strerror(errno)); return 1; } } 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; }
void set_interactive(struct power_module *module, int on) { char governor[80]; char tmp_str[NODE_MAX]; struct video_encode_metadata_t video_encode_metadata; int rc; if (set_interactive_override(module, on) == HINT_HANDLED) { return; } ALOGI("Got set_interactive hint"); if (get_scaling_governor(governor, sizeof(governor)) == -1) { ALOGE("Can't obtain scaling governor."); return; } if (!on) { /* Display off. */ if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) && (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) { int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF}; if (!display_hint_sent) { perform_hint_action(DISPLAY_STATE_HINT_ID, resource_values, sizeof(resource_values)/sizeof(resource_values[0])); display_hint_sent = 1; } } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { int resource_values[] = {TR_MS_500, THREAD_MIGRATION_SYNC_OFF}; if (!display_hint_sent) { perform_hint_action(DISPLAY_STATE_HINT_ID, resource_values, sizeof(resource_values)/sizeof(resource_values[0])); display_hint_sent = 1; } } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) && (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) { if (saved_interactive_mode == 1){ /* Display turned off. */ if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) { if (!slack_node_rw_failed) { ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE); } rc = 1; } else { saved_dcvs_cpu0_slack_max = atoi(tmp_str); } if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) { if (!slack_node_rw_failed) { ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE); } rc = 1; } else { saved_dcvs_cpu0_slack_min = atoi(tmp_str); } if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) { if (!slack_node_rw_failed) { ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE); } rc = 1; } else { saved_mpdecision_slack_max = atoi(tmp_str); } if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) { if(!slack_node_rw_failed) { ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE); } rc = 1; } else { saved_mpdecision_slack_min = atoi(tmp_str); } /* Write new values. */ if (saved_dcvs_cpu0_slack_max != -1) { snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max); if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) { if (!slack_node_rw_failed) { ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE); } rc = 1; } } if (saved_dcvs_cpu0_slack_min != -1) { snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min); if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) { if(!slack_node_rw_failed) { ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE); } rc = 1; } } if (saved_mpdecision_slack_max != -1) { snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max); if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) { if(!slack_node_rw_failed) { ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE); } rc = 1; } } if (saved_mpdecision_slack_min != -1) { snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min); if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) { if(!slack_node_rw_failed) { ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE); } rc = 1; } } } slack_node_rw_failed = rc; } } else { /* Display on. */ if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) && (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) { undo_hint_action(DISPLAY_STATE_HINT_ID); display_hint_sent = 0; } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { undo_hint_action(DISPLAY_STATE_HINT_ID); display_hint_sent = 0; } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) && (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) { if (saved_interactive_mode == -1 || saved_interactive_mode == 0) { /* Display turned on. Restore if possible. */ if (saved_dcvs_cpu0_slack_max != -1) { snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max); if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) { if (!slack_node_rw_failed) { ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE); } rc = 1; } } if (saved_dcvs_cpu0_slack_min != -1) { snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min); if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) { if (!slack_node_rw_failed) { ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE); } rc = 1; } } if (saved_mpdecision_slack_max != -1) { snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max); if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) { if (!slack_node_rw_failed) { ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE); } rc = 1; } } if (saved_mpdecision_slack_min != -1) { snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min); if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) { if (!slack_node_rw_failed) { ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE); } rc = 1; } } } slack_node_rw_failed = rc; } } saved_interactive_mode = !!on; }
int Manage_runstop(char *devname, int fd, int runstop, int quiet) { /* Run or stop the array. array must already be configured * required >= 0.90.0 * Only print failure messages if quiet == 0; * quiet > 0 means really be quiet * quiet < 0 means we will try again if it fails. */ mdu_param_t param; /* unused */ if (runstop == -1 && md_get_version(fd) < 9000) { if (ioctl(fd, STOP_MD, 0)) { if (quiet == 0) fprintf(stderr, Name ": stopping device %s " "failed: %s\n", devname, strerror(errno)); return 1; } } if (md_get_version(fd) < 9000) { fprintf(stderr, Name ": need md driver version 0.90.0 or later\n"); return 1; } /* if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": %s does not appear to be active.\n", devname); return 1; } */ if (runstop>0) { if (ioctl(fd, RUN_ARRAY, ¶m)) { fprintf(stderr, Name ": failed to run array %s: %s\n", devname, strerror(errno)); return 1; } if (quiet <= 0) fprintf(stderr, Name ": started %s\n", devname); } else if (runstop < 0){ struct map_ent *map = NULL; struct stat stb; struct mdinfo *mdi; int devnum; int err; int count; /* If this is an mdmon managed array, just write 'inactive' * to the array state and let mdmon clear up. */ devnum = fd2devnum(fd); /* Get EXCL access first. If this fails, then attempting * to stop is probably a bad idea. */ close(fd); fd = open(devname, O_RDONLY|O_EXCL); if (fd < 0 || fd2devnum(fd) != devnum) { if (fd >= 0) close(fd); fprintf(stderr, Name ": Cannot get exclusive access to %s:" "Perhaps a running " "process, mounted filesystem " "or active volume group?\n", devname); return 1; } mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION); if (mdi && mdi->array.level > 0 && is_subarray(mdi->text_version)) { int err; /* This is mdmon managed. */ close(fd); count = 25; while (count && (err = sysfs_set_str(mdi, NULL, "array_state", "inactive")) < 0 && errno == EBUSY) { usleep(200000); count--; } if (err && !quiet) { fprintf(stderr, Name ": failed to stop array %s: %s\n", devname, strerror(errno)); return 1; } /* Give monitor a chance to act */ ping_monitor(mdi->text_version); fd = open_dev_excl(devnum); if (fd < 0) { fprintf(stderr, Name ": failed to completely stop %s" ": Device is busy\n", devname); return 1; } } else if (mdi && mdi->array.major_version == -1 && mdi->array.minor_version == -2 && !is_subarray(mdi->text_version)) { struct mdstat_ent *mds, *m; /* container, possibly mdmon-managed. * Make sure mdmon isn't opening it, which * would interfere with the 'stop' */ ping_monitor(mdi->sys_name); /* now check that there are no existing arrays * which are members of this array */ mds = mdstat_read(0, 0); for (m=mds; m; m=m->next) if (m->metadata_version && strncmp(m->metadata_version, "external:", 9)==0 && is_subarray(m->metadata_version+9) && devname2devnum(m->metadata_version+10) == devnum) { if (!quiet) fprintf(stderr, Name ": Cannot stop container %s: " "member %s still active\n", devname, m->dev); free_mdstat(mds); if (mdi) sysfs_free(mdi); return 1; } } /* As we have an O_EXCL open, any use of the device * which blocks STOP_ARRAY is probably a transient use, * so it is reasonable to retry for a while - 5 seconds. */ count = 25; err = 0; while (count && fd >= 0 && (err = ioctl(fd, STOP_ARRAY, NULL)) < 0 && errno == EBUSY) { usleep(200000); count --; } if (fd >= 0 && err) { if (quiet == 0) { fprintf(stderr, Name ": failed to stop array %s: %s\n", devname, strerror(errno)); if (errno == EBUSY) fprintf(stderr, "Perhaps a running " "process, mounted filesystem " "or active volume group?\n"); } if (mdi) sysfs_free(mdi); return 1; } /* prior to 2.6.28, KOBJ_CHANGE was not sent when an md array * was stopped, so We'll do it here just to be sure. Drop any * partitions as well... */ if (fd >= 0) ioctl(fd, BLKRRPART, 0); if (mdi) sysfs_uevent(mdi, "change"); if (devnum != NoMdDev && (stat("/dev/.udev", &stb) != 0 || check_env("MDADM_NO_UDEV"))) { struct map_ent *mp = map_by_devnum(&map, devnum); remove_devices(devnum, mp ? mp->path : NULL); } if (quiet <= 0) fprintf(stderr, Name ": stopped %s\n", devname); map_lock(&map); map_remove(&map, devnum); map_unlock(&map); } return 0; }