X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=sysfs.c;h=9a1d856960e82ba78d16b12b6da5cf4bf0efe455;hb=6b781d331bf52b01b9bafa6409ffb400f8c62895;hp=cddabaee8b6d17dbfab3deb92fe2687edb4cb4b8;hpb=fd324b08dbfa8404558534dd0a2321213ffb7257;p=thirdparty%2Fmdadm.git diff --git a/sysfs.c b/sysfs.c index cddabaee..9a1d8569 100644 --- a/sysfs.c +++ b/sysfs.c @@ -57,16 +57,12 @@ void sysfs_free(struct mdinfo *sra) } } -int sysfs_open(int devnum, char *devname, char *attr) +int sysfs_open(char *devnm, char *devname, char *attr) { char fname[50]; int fd; - char *mdname = devnum2devname(devnum); - if (!mdname) - return -1; - - sprintf(fname, "/sys/block/%s/md/", mdname); + sprintf(fname, "/sys/block/%s/md/", devnm); if (devname) { strcat(fname, devname); strcat(fname, "/"); @@ -75,41 +71,36 @@ int sysfs_open(int devnum, char *devname, char *attr) fd = open(fname, O_RDWR); if (fd < 0 && errno == EACCES) fd = open(fname, O_RDONLY); - free(mdname); return fd; } -void sysfs_init(struct mdinfo *mdi, int fd, int devnum) +void sysfs_init(struct mdinfo *mdi, int fd, char *devnm) { mdi->sys_name[0] = 0; if (fd >= 0) { mdu_version_t vers; if (ioctl(fd, RAID_VERSION, &vers) != 0) return; - devnum = fd2devnum(fd); + devnm = fd2devnm(fd); } - if (devnum == NoMdDev) + if (devnm == NULL) return; - fmt_devname(mdi->sys_name, devnum); + strcpy(mdi->sys_name, devnm); } - -struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) +struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options) { char fname[PATH_MAX]; char buf[PATH_MAX]; char *base; char *dbase; struct mdinfo *sra; - struct mdinfo *dev; + struct mdinfo *dev, **devp; DIR *dir = NULL; struct dirent *de; - sra = malloc(sizeof(*sra)); - if (sra == NULL) - return sra; - memset(sra, 0, sizeof(*sra)); - sysfs_init(sra, fd, devnum); + sra = xcalloc(1, sizeof(*sra)); + sysfs_init(sra, fd, devnm); if (sra->sys_name[0] == 0) { free(sra); return NULL; @@ -179,8 +170,10 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) if (options & GET_CACHE) { strcpy(base, "stripe_cache_size"); if (load_sys(fname, buf)) - goto abort; - sra->cache_size = strtoul(buf, NULL, 0); + /* Probably level doesn't support it */ + sra->cache_size = 0; + else + sra->cache_size = strtoul(buf, NULL, 0); } if (options & GET_MISMATCH) { strcpy(base, "mismatch_cnt"); @@ -226,7 +219,7 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) else if (strncmp(buf, "none", 4) == 0) sra->bitmap_offset = 0; else if (buf[0] == '+') - sra->bitmap_offset = strtoul(buf+1, NULL, 10); + sra->bitmap_offset = strtol(buf+1, NULL, 10); else goto abort; } @@ -241,6 +234,8 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) goto abort; sra->array.spare_disks = 0; + devp = &sra->devs; + sra->devs = NULL; while ((de = readdir(dir)) != NULL) { char *ep; if (de->d_ino == 0 || @@ -250,9 +245,7 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) dbase = base + strlen(base); *dbase++ = '/'; - dev = malloc(sizeof(*dev)); - if (!dev) - goto abort; + dev = xmalloc(sizeof(*dev)); /* Always get slot, major, minor */ strcpy(dbase, "slot"); @@ -274,7 +267,7 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) free(dev); goto abort; } - + } strcpy(dev->sys_name, de->d_name); dev->disk.raid_disk = strtoul(buf, &ep, 10); @@ -288,6 +281,7 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) free(dev); continue; } + sra->array.nr_disks++; sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor); /* special case check for block devices that can go 'offline' */ @@ -299,14 +293,20 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) } /* finally add this disk to the array */ - dev->next = sra->devs; - sra->devs = dev; + *devp = dev; + devp = & dev->next; + dev->next = NULL; if (options & GET_OFFSET) { strcpy(dbase, "offset"); if (load_sys(fname, buf)) goto abort; dev->data_offset = strtoull(buf, NULL, 0); + strcpy(dbase, "new_offset"); + if (load_sys(fname, buf) == 0) + dev->new_data_offset = strtoull(buf, NULL, 0); + else + dev->new_data_offset = dev->data_offset; } if (options & GET_SIZE) { strcpy(dbase, "size"); @@ -428,6 +428,14 @@ int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev, return sysfs_set_str(sra, dev, name, valstr); } +int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev, + char *name, long long val) +{ + char valstr[50]; + sprintf(valstr, "%lli", val); + return sysfs_set_str(sra, dev, name, valstr); +} + int sysfs_uevent(struct mdinfo *sra, char *event) { char fname[50]; @@ -447,7 +455,7 @@ int sysfs_uevent(struct mdinfo *sra, char *event) return -1; } return 0; -} +} int sysfs_attribute_available(struct mdinfo *sra, struct mdinfo *dev, char *name) { @@ -505,6 +513,49 @@ int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev, return n; } +int sysfs_fd_get_two(int fd, unsigned long long *v1, unsigned long long *v2) +{ + /* two numbers in this sysfs file, either + * NNN (NNN) + * or + * NNN / NNN + */ + char buf[80]; + int n; + char *ep, *ep2; + + lseek(fd, 0, 0); + n = read(fd, buf, sizeof(buf)); + if (n <= 0) + return -2; + buf[n] = 0; + *v1 = strtoull(buf, &ep, 0); + if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' ')) + return -1; + while (*ep == ' ' || *ep == '/' || *ep == '(') + ep++; + *v2 = strtoull(ep, &ep2, 0); + if (ep2 == ep || (*ep2 != 0 && *ep2 != '\n' && *ep2 != ' ' && *ep2 != ')')) { + *v2 = *v1; + return 1; + } + return 2; +} + +int sysfs_get_two(struct mdinfo *sra, struct mdinfo *dev, + char *name, unsigned long long *v1, unsigned long long *v2) +{ + int n; + int fd; + + fd = sysfs_get_fd(sra, dev, name); + if (fd < 0) + return -1; + n = sysfs_fd_get_two(fd, v1, v2); + close(fd); + return n; +} + int sysfs_fd_get_str(int fd, char *val, int size) { int n; @@ -572,7 +623,7 @@ int sysfs_set_array(struct mdinfo *info, int vers) if ((vers % 100) < 2 || sysfs_set_str(info, NULL, "metadata_version", ver) < 0) { - fprintf(stderr, Name ": This kernel does not " + pr_err("This kernel does not " "support external metadata.\n"); return 1; } @@ -593,7 +644,7 @@ int sysfs_set_array(struct mdinfo *info, int vers) rc = sysfs_set_num(info, NULL, "array_size", info->custom_array_size/2); if (rc && errno == ENOENT) { - fprintf(stderr, Name ": This kernel does not " + pr_err("This kernel does not " "have the md/array_size attribute, " "the array may be larger than expected\n"); rc = 0; @@ -631,13 +682,7 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume) return rv; memset(nm, 0, sizeof(nm)); - sprintf(dv, "/sys/dev/block/%d:%d", sd->disk.major, sd->disk.minor); - rv = readlink(dv, nm, sizeof(nm)-1); - if (rv <= 0) - return -1; - nm[rv] = '\0'; - dname = strrchr(nm, '/'); - if (dname) dname++; + dname = devid2kname(makedev(sd->disk.major, sd->disk.minor)); strcpy(sd->sys_name, "dev-"); strcpy(sd->sys_name+4, dname); @@ -768,32 +813,33 @@ int sysfs_disk_to_scsi_id(int fd, __u32 *id) return 0; } - -int sysfs_unique_holder(int devnum, long rdev) +int sysfs_unique_holder(char *devnm, long rdev) { - /* Check that devnum is a holder of rdev, + /* Check that devnm is a holder of rdev, * and is the only holder. * we should be locked against races by - * an O_EXCL on devnum + * an O_EXCL on devnm + * Return values: + * 0 - not unique, not even a holder + * 1 - unique, this is the only holder. + * 2/3 - not unique, there is another holder + * -1 - error, cannot find the holders */ DIR *dir; struct dirent *de; char dirname[100]; char l; - int found = 0; + int ret = 0; sprintf(dirname, "/sys/dev/block/%d:%d/holders", major(rdev), minor(rdev)); dir = opendir(dirname); - errno = ENOENT; if (!dir) - return 0; + return -1; l = strlen(dirname); while ((de = readdir(dir)) != NULL) { - char buf[10]; + char buf[100]; + char *sl; int n; - int mj, mn; - char c; - int fd; if (de->d_ino == 0) continue; @@ -801,36 +847,22 @@ int sysfs_unique_holder(int devnum, long rdev) continue; strcpy(dirname+l, "/"); strcat(dirname+l, de->d_name); - strcat(dirname+l, "/dev"); - fd = open(dirname, O_RDONLY); - if (fd < 0) { - errno = ENOENT; - break; - } - n = read(fd, buf, sizeof(buf)-1); - close(fd); - if (n < 0) + n = readlink(dirname, buf, sizeof(buf)-1); + if (n <= 0) continue; buf[n] = 0; - if (sscanf(buf, "%d:%d%c", &mj, &mn, &c) != 3 || - c != '\n') { - errno = ENOENT; - break; - } - if (mj != MD_MAJOR) - mn = -1-(mn>>6); + sl = strrchr(buf, '/'); + if (!sl) + continue; + sl++; - if (devnum != mn) { - errno = EEXIST; - break; - } - found = 1; + if (strcmp(devnm, sl) == 0) + ret |= 1; + else + ret |= 2; } closedir(dir); - if (de) - return 0; - else - return found; + return ret; } int sysfs_freeze_array(struct mdinfo *sra) @@ -849,9 +881,41 @@ int sysfs_freeze_array(struct mdinfo *sra) if (strcmp(buf, "frozen\n") == 0) /* Already frozen */ return 0; - if (strcmp(buf, "idle\n") != 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; } + +int sysfs_wait(int fd, int *msec) +{ + /* Wait up to '*msec' for fd to have an exception condition. + * if msec == NULL, wait indefinitely. + */ + fd_set fds; + int n; + FD_ZERO(&fds); + FD_SET(fd, &fds); + if (msec == NULL) + n = select(fd+1, NULL, NULL, &fds, NULL); + else if (*msec < 0) + n = 0; + else { + struct timeval start, end, tv; + gettimeofday(&start, NULL); + if (*msec < 1000) { + tv.tv_sec = 0; + tv.tv_usec = (*msec)*1000; + } else { + tv.tv_sec = (*msec)/1000; + tv.tv_usec = 0; + } + n = select(fd+1, NULL, NULL, &fds, &tv); + gettimeofday(&end, NULL); + end.tv_sec -= start.tv_sec; + *msec -= (end.tv_sec * 1000 + end.tv_usec/1000 + - start.tv_usec/1000) + 1; + } + return n; +}