]> git.ipfire.org Git - thirdparty/mdadm.git/blob - sysfs.c
more ddf stuff
[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 mdinfo *sra)
46 {
47 while (sra) {
48 struct mdinfo *sra2 = sra->next;
49 while (sra->devs) {
50 struct mdinfo *d = sra->devs;
51 sra->devs = d->next;
52 free(d);
53 }
54 free(sra);
55 sra = sra2;
56 }
57 }
58
59 struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
60 {
61 /* Longest possible name in sysfs, mounted at /sys, is
62 * /sys/block/md_dXXX/md/dev-XXXXX/block/dev
63 * /sys/block/md_dXXX/md/metadata_version
64 * which is about 41 characters. 50 should do for now
65 */
66 char fname[50];
67 char buf[1024];
68 char *base;
69 char *dbase;
70 struct mdinfo *sra;
71 struct mdinfo *dev;
72 DIR *dir;
73 struct dirent *de;
74
75 sra = malloc(sizeof(*sra));
76 if (sra == NULL)
77 return sra;
78 sra->next = NULL;
79
80 if (fd >= 0) {
81 struct stat stb;
82 mdu_version_t vers;
83 if (fstat(fd, &stb)) return NULL;
84 if (ioctl(fd, RAID_VERSION, &vers) != 0)
85 return NULL;
86 if (major(stb.st_rdev)==9)
87 sprintf(sra->sys_name, "md%d", (int)minor(stb.st_rdev));
88 else
89 sprintf(sra->sys_name, "md_d%d",
90 (int)minor(stb.st_rdev)>>MdpMinorShift);
91 } else {
92 if (devnum >= 0)
93 sprintf(sra->sys_name, "md%d", devnum);
94 else
95 sprintf(sra->sys_name, "md_d%d",
96 -1-devnum);
97 }
98 sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
99 base = fname + strlen(fname);
100
101 sra->devs = NULL;
102 if (options & GET_VERSION) {
103 strcpy(base, "metadata_version");
104 if (load_sys(fname, buf))
105 goto abort;
106 if (strncmp(buf, "none", 4) == 0) {
107 sra->array.major_version =
108 sra->array.minor_version = -1;
109 strcpy(sra->text_version, "");
110 } else if (strncmp(buf, "external:", 9) == 0) {
111 sra->array.major_version = -1;
112 sra->array.minor_version = -2;
113 strcpy(sra->text_version, buf+9);
114 } else
115 sscanf(buf, "%d.%d",
116 &sra->array.major_version,
117 &sra->array.minor_version);
118 }
119 if (options & GET_LEVEL) {
120 strcpy(base, "level");
121 if (load_sys(fname, buf))
122 goto abort;
123 sra->array.level = map_name(pers, buf);
124 }
125 if (options & GET_LAYOUT) {
126 strcpy(base, "layout");
127 if (load_sys(fname, buf))
128 goto abort;
129 sra->array.layout = strtoul(buf, NULL, 0);
130 }
131 if (options & GET_COMPONENT) {
132 strcpy(base, "component_size");
133 if (load_sys(fname, buf))
134 goto abort;
135 sra->component_size = strtoull(buf, NULL, 0);
136 /* sysfs reports "K", but we want sectors */
137 sra->component_size *= 2;
138 }
139 if (options & GET_CHUNK) {
140 strcpy(base, "chunk_size");
141 if (load_sys(fname, buf))
142 goto abort;
143 sra->array.chunk_size = strtoul(buf, NULL, 0);
144 }
145 if (options & GET_CACHE) {
146 strcpy(base, "stripe_cache_size");
147 if (load_sys(fname, buf))
148 goto abort;
149 sra->cache_size = strtoul(buf, NULL, 0);
150 }
151 if (options & GET_MISMATCH) {
152 strcpy(base, "mismatch_cnt");
153 if (load_sys(fname, buf))
154 goto abort;
155 sra->mismatch_cnt = strtoul(buf, NULL, 0);
156 }
157
158 if (! (options & GET_DEVS))
159 return sra;
160
161 /* Get all the devices as well */
162 *base = 0;
163 dir = opendir(fname);
164 if (!dir)
165 goto abort;
166 sra->array.spare_disks = 0;
167
168 while ((de = readdir(dir)) != NULL) {
169 char *ep;
170 if (de->d_ino == 0 ||
171 strncmp(de->d_name, "dev-", 4) != 0)
172 continue;
173 strcpy(base, de->d_name);
174 dbase = base + strlen(base);
175 *dbase++ = '/';
176
177 dev = malloc(sizeof(*dev));
178 if (!dev)
179 goto abort;
180 dev->next = sra->devs;
181 sra->devs = dev;
182 strcpy(dev->sys_name, de->d_name);
183
184 /* Always get slot, major, minor */
185 strcpy(dbase, "slot");
186 if (load_sys(fname, buf))
187 goto abort;
188 dev->disk.raid_disk = strtoul(buf, &ep, 10);
189 if (*ep) dev->disk.raid_disk = -1;
190
191 strcpy(dbase, "block/dev");
192 if (load_sys(fname, buf))
193 goto abort;
194 sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
195
196 if (options & GET_OFFSET) {
197 strcpy(dbase, "offset");
198 if (load_sys(fname, buf))
199 goto abort;
200 dev->data_offset = strtoull(buf, NULL, 0);
201 }
202 if (options & GET_SIZE) {
203 strcpy(dbase, "size");
204 if (load_sys(fname, buf))
205 goto abort;
206 dev->component_size = strtoull(buf, NULL, 0);
207 }
208 if (options & GET_STATE) {
209 dev->disk.state = 0;
210 strcpy(dbase, "state");
211 if (load_sys(fname, buf))
212 goto abort;
213 if (strstr(buf, "in_sync"))
214 dev->disk.state |= (1<<MD_DISK_SYNC);
215 if (strstr(buf, "faulty"))
216 dev->disk.state |= (1<<MD_DISK_FAULTY);
217 if (dev->disk.state == 0)
218 sra->array.spare_disks++;
219 }
220 if (options & GET_ERROR) {
221 strcpy(buf, "errors");
222 if (load_sys(fname, buf))
223 goto abort;
224 dev->errors = strtoul(buf, NULL, 0);
225 }
226 }
227 return sra;
228
229 abort:
230 sysfs_free(sra);
231 return NULL;
232 }
233
234 unsigned long long get_component_size(int fd)
235 {
236 /* Find out the component size of the array.
237 * We cannot trust GET_ARRAY_INFO ioctl as it's
238 * size field is only 32bits.
239 * So look in /sys/block/mdXXX/md/component_size
240 *
241 * This returns in units of sectors.
242 */
243 struct stat stb;
244 char fname[50];
245 int n;
246 if (fstat(fd, &stb)) return 0;
247 if (major(stb.st_rdev) == 9)
248 sprintf(fname, "/sys/block/md%d/md/component_size",
249 (int)minor(stb.st_rdev));
250 else
251 sprintf(fname, "/sys/block/md_d%d/md/component_size",
252 (int)minor(stb.st_rdev)>>MdpMinorShift);
253 fd = open(fname, O_RDONLY);
254 if (fd < 0)
255 return 0;
256 n = read(fd, fname, sizeof(fname));
257 close(fd);
258 if (n == sizeof(fname))
259 return 0;
260 fname[n] = 0;
261 return strtoull(fname, NULL, 10) * 2;
262 }
263
264 int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
265 char *name, char *val)
266 {
267 char fname[50];
268 int n;
269 int fd;
270 sprintf(fname, "/sys/block/%s/md/%s/%s",
271 sra->sys_name, dev?dev->sys_name:"", name);
272 fd = open(fname, O_WRONLY);
273 if (fd < 0)
274 return -1;
275 n = write(fd, val, strlen(val));
276 close(fd);
277 if (n != strlen(val))
278 return -1;
279 return 0;
280 }
281
282 int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
283 char *name, unsigned long long val)
284 {
285 char valstr[50];
286 sprintf(valstr, "%llu", val);
287 return sysfs_set_str(sra, dev, name, valstr);
288 }
289
290 int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
291 char *name, unsigned long long *val)
292 {
293 char fname[50];
294 char buf[50];
295 int n;
296 int fd;
297 char *ep;
298 sprintf(fname, "/sys/block/%s/md/%s/%s",
299 sra->sys_name, dev?dev->sys_name:"", name);
300 fd = open(fname, O_RDONLY);
301 if (fd < 0)
302 return -1;
303 n = read(fd, buf, sizeof(buf));
304 close(fd);
305 if (n <= 0)
306 return -1;
307 buf[n] = 0;
308 *val = strtoull(buf, &ep, 0);
309 if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
310 return -1;
311 return 0;
312 }