diff options
author | Neil Brown <neilb@suse.de> | 2006-03-13 05:51:32 +0000 |
---|---|---|
committer | Neil Brown <neilb@suse.de> | 2006-03-13 05:51:32 +0000 |
commit | e86c9dd6d847ec57ec400b118efaf2c1808f10bc (patch) | |
tree | 6cb0e2d0c2e48d102b08b99d41941ae7f215a90c /sysfs.c | |
parent | 8a4440794afbebe6bdc710eefd21c221c9046644 (diff) | |
download | mdadm-e86c9dd6d847ec57ec400b118efaf2c1808f10bc.tar.gz |
Initial reshape support
Needs work for other levels etc.
Signed-off-by: Neil Brown <neilb@suse.de>
Diffstat (limited to 'sysfs.c')
-rw-r--r-- | sysfs.c | 265 |
1 files changed, 265 insertions, 0 deletions
@@ -0,0 +1,265 @@ +/* + * sysfs - extract md related information from sysfs. Part of: + * mdadm - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2006 Neil Brown <neilb@suse.de> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Neil Brown + * Email: <neilb@suse.de> + */ + +#include "mdadm.h" +#include <dirent.h> + +int load_sys(char *path, char *buf) +{ + int fd = open(path, O_RDONLY); + int n; + if (fd < 0) + return -1; + n = read(fd, buf, 1024); + close(fd); + if (n <=0 || n >= 1024) + return -1; + buf[n] = 0; + if (buf[n-1] == '\n') + buf[n-1] = 0; + return 0; +} + +struct sysarray *sysfs_read(int fd, int devnum, unsigned long options) +{ + /* Longest possible name in sysfs, mounted at /sys, is + * /sys/block/md_dXXX/md/dev-XXXXX/block/dev + * /sys/block/md_dXXX/md/metadata_version + * which is about 41 characters. 50 should do for now + */ + char fname[50]; + char buf[1024]; + char *base; + char *dbase; + struct sysarray *sra; + struct sysdev *dev; + DIR *dir; + struct dirent *de; + + sra = malloc(sizeof(*sra)); + if (sra == NULL) + return sra; + + if (fd >= 0) { + struct stat stb; + if (fstat(fd, &stb)) return NULL; + if (major(stb.st_rdev)==9) + sprintf(sra->name, "md%d", minor(stb.st_rdev)); + else + sprintf(sra->name, "md_d%d", + minor(stb.st_rdev)/16); + } else { + if (devnum >= 0) + sprintf(sra->name, "md%d", devnum); + else + sprintf(sra->name, "md_d%d", + -1-devnum); + } + sprintf(fname, "/sys/block/%s/md/", sra->name); + base = fname + strlen(fname); + + sra->devs = NULL; + if (options & GET_LEVEL) { + strcpy(base, "level"); + if (load_sys(fname, buf)) + goto abort; + sra->level = map_name(pers, buf); + } + if (options & GET_LAYOUT) { + strcpy(base, "layout"); + if (load_sys(fname, buf)) + goto abort; + sra->layout = strtoul(buf, NULL, 0); + } + if (options & GET_COMPONENT) { + strcpy(base, "component_size"); + if (load_sys(fname, buf)) + goto abort; + sra->component_size = strtoull(buf, NULL, 0); + } + if (options & GET_CHUNK) { + strcpy(base, "chunk_size"); + if (load_sys(fname, buf)) + goto abort; + sra->chunk = strtoul(buf, NULL, 0); + } + + if (! (options & GET_DEVS)) + return sra; + + /* Get all the devices as well */ + *base = 0; + dir = opendir(fname); + if (!dir) + goto abort; + sra->spares = 0; + + while ((de = readdir(dir)) != NULL) { + char *ep; + if (de->d_ino == 0 || + strncmp(de->d_name, "dev-", 4) != 0) + continue; + strcpy(base, de->d_name); + dbase = base + strlen(base); + *dbase++ = '/'; + + dev = malloc(sizeof(*dev)); + if (!dev) + goto abort; + dev->next = sra->devs; + sra->devs = dev; + + /* Always get slot, major, minor */ + strcpy(dbase, "slot"); + if (load_sys(fname, buf)) + goto abort; + dev->role = strtoul(buf, &ep, 10); + if (*ep) dev->role = -1; + + strcpy(dbase, "block/dev"); + if (load_sys(fname, buf)) + goto abort; + sscanf(buf, "%d:%d", &dev->major, &dev->minor); + + if (options & GET_OFFSET) { + strcpy(dbase, "offset"); + if (load_sys(fname, buf)) + goto abort; + dev->offset = strtoull(buf, NULL, 0); + } + if (options & GET_SIZE) { + strcpy(dbase, "size"); + if (load_sys(fname, buf)) + goto abort; + dev->size = strtoull(buf, NULL, 0); + } + if (options & GET_STATE) { + dev->state = 0; + strcpy(dbase, "state"); + if (load_sys(fname, buf)) + goto abort; + if (strstr(buf, "in_sync")) + dev->state |= (1<<MD_DISK_SYNC); + if (strstr(buf, "faulty")) + dev->state |= (1<<MD_DISK_FAULTY); + if (dev->state == 0) + sra->spares++; + } + if (options & GET_ERROR) { + strcpy(buf, "errors"); + if (load_sys(fname, buf)) + goto abort; + dev->errors = strtoul(buf, NULL, 0); + } + } + return sra; + + abort: + while (sra && sra->devs) { + dev = sra->devs; + sra->devs = dev->next; + free(dev); + } + if(sra) free(sra); + return NULL; +} + +unsigned long long get_component_size(int fd) +{ + /* Find out the component size of the array. + * We cannot trust GET_ARRAY_INFO ioctl as it's + * size field is only 32bits. + * So look in /sys/block/mdXXX/md/component_size + */ + struct stat stb; + char fname[50]; + int n; + if (fstat(fd, &stb)) return 0; + if (major(stb.st_rdev) == 9) + sprintf(fname, "/sys/block/md%d/md/component_size", + minor(stb.st_rdev)); + else + sprintf(fname, "/sys/block/md_d%d/md/component_size", + minor(stb.st_rdev)/16); + fd = open(fname, O_RDONLY); + if (fd < 0) + return 0; + n = read(fd, fname, sizeof(fname)); + close(fd); + if (n == sizeof(fname)) + return 0; + fname[n] = 0; + return strtoull(fname, NULL, 10); +} + +int sysfs_set_str(struct sysarray *sra, struct sysdev *dev, + char *name, char *val) +{ + char fname[50]; + int n; + int fd; + sprintf(fname, "/sys/block/%s/md/%s/%s", + sra->name, dev?dev->name:"", name); + fd = open(fname, O_WRONLY); + if (fd < 0) + return -1; + n = write(fd, val, strlen(val)); + close(fd); + if (n != strlen(val)) + return -1; + return 0; +} + +int sysfs_set_num(struct sysarray *sra, struct sysdev *dev, + char *name, unsigned long long val) +{ + char valstr[50]; + sprintf(valstr, "%llu", val); + return sysfs_set_str(sra, dev, name, valstr); +} + +int sysfs_get_ll(struct sysarray *sra, struct sysdev *dev, + char *name, unsigned long long *val) +{ + char fname[50]; + char buf[50]; + int n; + int fd; + char *ep; + sprintf(fname, "/sys/block/%s/md/%s/%s", + sra->name, dev?dev->name:"", name); + fd = open(fname, O_RDONLY); + if (fd < 0) + return -1; + n = read(fd, buf, sizeof(buf)); + close(fd); + if (n <= 0) + return -1; + buf[n] = 0; + *val = strtoull(buf, &ep, 0); + if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' ')) + return -1; + return 0; +} |