]> git.ipfire.org Git - thirdparty/mdadm.git/blob - sysfs.c
1dbc680f8bf0a4b51b9c4e0f6aec8ffd0fc5561c
[thirdparty/mdadm.git] / sysfs.c
1 /*
2 * sysfs - extract md related information from sysfs. Part of:
3 * mdadm - manage Linux "md" devices aka RAID arrays.
4 *
5 * Copyright (C) 2006 Neil Brown <neilb@suse.de>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Author: Neil Brown
23 * Email: <neilb@suse.de>
24 */
25
26 #include "mdadm.h"
27 #include <dirent.h>
28
29 int load_sys(char *path, char *buf)
30 {
31 int fd = open(path, O_RDONLY);
32 int n;
33 if (fd < 0)
34 return -1;
35 n = read(fd, buf, 1024);
36 close(fd);
37 if (n <=0 || n >= 1024)
38 return -1;
39 buf[n] = 0;
40 if (buf[n-1] == '\n')
41 buf[n-1] = 0;
42 return 0;
43 }
44
45 void sysfs_free(struct sysarray *sra)
46 {
47 if (!sra)
48 return;
49 while (sra->devs) {
50 struct sysdev *d = sra->devs;
51 sra->devs = d->next;
52 free(d);
53 }
54 free(sra);
55 }
56
57 struct sysarray *sysfs_read(int fd, int devnum, unsigned long options)
58 {
59 /* Longest possible name in sysfs, mounted at /sys, is
60 * /sys/block/md_dXXX/md/dev-XXXXX/block/dev
61 * /sys/block/md_dXXX/md/metadata_version
62 * which is about 41 characters. 50 should do for now
63 */
64 char fname[50];
65 char buf[1024];
66 char *base;
67 char *dbase;
68 struct sysarray *sra;
69 struct sysdev *dev;
70 DIR *dir;
71 struct dirent *de;
72
73 sra = malloc(sizeof(*sra));
74 if (sra == NULL)
75 return sra;
76
77 if (fd >= 0) {
78 struct stat stb;
79 mdu_version_t vers;
80 if (fstat(fd, &stb)) return NULL;
81 if (ioctl(fd, RAID_VERSION, &vers) != 0)
82 return NULL;
83 if (major(stb.st_rdev)==9)
84 sprintf(sra->name, "md%d", minor(stb.st_rdev));
85 else
86 sprintf(sra->name, "md_d%d",
87 minor(stb.st_rdev)>>MdpMinorShift);
88 } else {
89 if (devnum >= 0)
90 sprintf(sra->name, "md%d", devnum);
91 else
92 sprintf(sra->name, "md_d%d",
93 -1-devnum);
94 }
95 sprintf(fname, "/sys/block/%s/md/", sra->name);
96 base = fname + strlen(fname);
97
98 sra->devs = NULL;
99 if (options & GET_VERSION) {
100 strcpy(base, "metadata_version");
101 if (load_sys(fname, buf))
102 goto abort;
103 if (strncmp(buf, "none", 4) == 0)
104 sra->major_version = sra->minor_version = -1;
105 else
106 sscanf(buf, "%d.%d",
107 &sra->major_version, &sra->minor_version);
108 }
109 if (options & GET_LEVEL) {
110 strcpy(base, "level");
111 if (load_sys(fname, buf))
112 goto abort;
113 sra->level = map_name(pers, buf);
114 }
115 if (options & GET_LAYOUT) {
116 strcpy(base, "layout");
117 if (load_sys(fname, buf))
118 goto abort;
119 sra->layout = strtoul(buf, NULL, 0);
120 }
121 if (options & GET_COMPONENT) {
122 strcpy(base, "component_size");
123 if (load_sys(fname, buf))
124 goto abort;
125 sra->component_size = strtoull(buf, NULL, 0);
126 /* sysfs reports "K", but we want sectors */
127 sra->component_size *= 2;
128 }
129 if (options & GET_CHUNK) {
130 strcpy(base, "chunk_size");
131 if (load_sys(fname, buf))
132 goto abort;
133 sra->chunk = strtoul(buf, NULL, 0);
134 }
135 if (options & GET_CACHE) {
136 strcpy(base, "stripe_cache_size");
137 if (load_sys(fname, buf))
138 goto abort;
139 sra->cache_size = strtoul(buf, NULL, 0);
140 }
141 if (options & GET_MISMATCH) {
142 strcpy(base, "mismatch_cnt");
143 if (load_sys(fname, buf))
144 goto abort;
145 sra->mismatch_cnt = strtoul(buf, NULL, 0);
146 }
147
148 if (! (options & GET_DEVS))
149 return sra;
150
151 /* Get all the devices as well */
152 *base = 0;
153 dir = opendir(fname);
154 if (!dir)
155 goto abort;
156 sra->spares = 0;
157
158 while ((de = readdir(dir)) != NULL) {
159 char *ep;
160 if (de->d_ino == 0 ||
161 strncmp(de->d_name, "dev-", 4) != 0)
162 continue;
163 strcpy(base, de->d_name);
164 dbase = base + strlen(base);
165 *dbase++ = '/';
166
167 dev = malloc(sizeof(*dev));
168 if (!dev)
169 goto abort;
170 dev->next = sra->devs;
171 sra->devs = dev;
172 strcpy(dev->name, de->d_name);
173
174 /* Always get slot, major, minor */
175 strcpy(dbase, "slot");
176 if (load_sys(fname, buf))
177 goto abort;
178 dev->role = strtoul(buf, &ep, 10);
179 if (*ep) dev->role = -1;
180
181 strcpy(dbase, "block/dev");
182 if (load_sys(fname, buf))
183 goto abort;
184 sscanf(buf, "%d:%d", &dev->major, &dev->minor);
185
186 if (options & GET_OFFSET) {
187 strcpy(dbase, "offset");
188 if (load_sys(fname, buf))
189 goto abort;
190 dev->offset = strtoull(buf, NULL, 0);
191 }
192 if (options & GET_SIZE) {
193 strcpy(dbase, "size");
194 if (load_sys(fname, buf))
195 goto abort;
196 dev->size = strtoull(buf, NULL, 0);
197 }
198 if (options & GET_STATE) {
199 dev->state = 0;
200 strcpy(dbase, "state");
201 if (load_sys(fname, buf))
202 goto abort;
203 if (strstr(buf, "in_sync"))
204 dev->state |= (1<<MD_DISK_SYNC);
205 if (strstr(buf, "faulty"))
206 dev->state |= (1<<MD_DISK_FAULTY);
207 if (dev->state == 0)
208 sra->spares++;
209 }
210 if (options & GET_ERROR) {
211 strcpy(buf, "errors");
212 if (load_sys(fname, buf))
213 goto abort;
214 dev->errors = strtoul(buf, NULL, 0);
215 }
216 }
217 return sra;
218
219 abort:
220 sysfs_free(sra);
221 return NULL;
222 }
223
224 unsigned long long get_component_size(int fd)
225 {
226 /* Find out the component size of the array.
227 * We cannot trust GET_ARRAY_INFO ioctl as it's
228 * size field is only 32bits.
229 * So look in /sys/block/mdXXX/md/component_size
230 *
231 * This returns in units of sectors.
232 */
233 struct stat stb;
234 char fname[50];
235 int n;
236 if (fstat(fd, &stb)) return 0;
237 if (major(stb.st_rdev) == 9)
238 sprintf(fname, "/sys/block/md%d/md/component_size",
239 minor(stb.st_rdev));
240 else
241 sprintf(fname, "/sys/block/md_d%d/md/component_size",
242 minor(stb.st_rdev)>>MdpMinorShift);
243 fd = open(fname, O_RDONLY);
244 if (fd < 0)
245 return 0;
246 n = read(fd, fname, sizeof(fname));
247 close(fd);
248 if (n == sizeof(fname))
249 return 0;
250 fname[n] = 0;
251 return strtoull(fname, NULL, 10) * 2;
252 }
253
254 int sysfs_set_str(struct sysarray *sra, struct sysdev *dev,
255 char *name, char *val)
256 {
257 char fname[50];
258 int n;
259 int fd;
260 sprintf(fname, "/sys/block/%s/md/%s/%s",
261 sra->name, dev?dev->name:"", name);
262 fd = open(fname, O_WRONLY);
263 if (fd < 0)
264 return -1;
265 n = write(fd, val, strlen(val));
266 close(fd);
267 if (n != strlen(val))
268 return -1;
269 return 0;
270 }
271
272 int sysfs_set_num(struct sysarray *sra, struct sysdev *dev,
273 char *name, unsigned long long val)
274 {
275 char valstr[50];
276 sprintf(valstr, "%llu", val);
277 return sysfs_set_str(sra, dev, name, valstr);
278 }
279
280 int sysfs_get_ll(struct sysarray *sra, struct sysdev *dev,
281 char *name, unsigned long long *val)
282 {
283 char fname[50];
284 char buf[50];
285 int n;
286 int fd;
287 char *ep;
288 sprintf(fname, "/sys/block/%s/md/%s/%s",
289 sra->name, dev?dev->name:"", name);
290 fd = open(fname, O_RDONLY);
291 if (fd < 0)
292 return -1;
293 n = read(fd, buf, sizeof(buf));
294 close(fd);
295 if (n <= 0)
296 return -1;
297 buf[n] = 0;
298 *val = strtoull(buf, &ep, 0);
299 if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
300 return -1;
301 return 0;
302 }