]> git.ipfire.org Git - thirdparty/mdadm.git/blame - mdstat.c
add infrastructure to receive higher order commands, like remove_device
[thirdparty/mdadm.git] / mdstat.c
CommitLineData
e0d19036
NB
1/*
2 * mdstat - parse /proc/mdstat file. Part of:
3 * mdadm - manage Linux "md" devices aka RAID arrays.
4 *
4f589ad0 5 * Copyright (C) 2002-2006 Neil Brown <neilb@suse.de>
e0d19036
NB
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@cse.unsw.edu.au>
24 * Paper: Neil Brown
25 * School of Computer Science and Engineering
26 * The University of New South Wales
27 * Sydney, 2052
28 * Australia
29 */
30
31/*
32 * The /proc/mdstat file comes in at least 3 flavours:
33 * In an unpatched 2.2 kernel (md 0.36.6):
34 * Personalities : [n raidx] ...
35 * read_ahead {not set|%d sectors}
36 * md0 : {in}active{ raidX /dev/hda... %d blocks{ maxfault=%d}}
37 * md1 : .....
38 *
39 * Normally only 4 md lines, but all are listed.
40 *
41 * In a patched 2.2 kernel (md 0.90.0)
42 * Personalities : [raidx] ...
43 * read_ahead {not set|%d sectors}
44 * mdN : {in}active {(readonly)} raidX dev[%d]{(F)} ... %d blocks STATUS RESYNC
45 * ... Only initialised arrays listed
8f21823f 46 * unused devices: {dev dev ... | <none>}
e0d19036
NB
47 *
48 * STATUS is personality dependant:
49 * linear: %dk rounding
50 * raid0: %dk chunks
51 * raid1: [%d/%d] [U_U] ( raid/working. operational or not)
52 * raid5: level 4/5, %dk chunk, algorithm %d [%d/%d] [U_U]
53 *
54 * RESYNC is empty or:
55 * {resync|recovery}=%u%% finish=%u.%umin
56 * or
57 * resync=DELAYED
58 *
59 * In a 2.4 kernel (md 0.90.0/2.4)
60 * Personalities : [raidX] ...
61 * read_ahead {not set|%d sectors}
62 * mdN : {in}active {(read-only)} raidX dev[%d]{(F)} ...
63 * %d blocks STATUS
64 * RESYNC
8f21823f 65 * unused devices: {dev dev .. | <none>}
e0d19036
NB
66 *
67 * STATUS matches 0.90.0/2.2
68 * RESYNC includes [===>....],
69 * adds a space after {resync|recovery} and before and after '='
70 * adds a decimal to the recovery percent.
71 * adds (%d/%d) resync amount and max_blocks, before finish.
72 * adds speed=%dK/sec after finish
73 *
74 *
75 *
76 * Out of this we want to extract:
77 * list of devices, active or not
78 * pattern of failed drives (so need number of drives)
79 * percent resync complete
80 *
81 * As continuation is indicated by leading space, we use
82 * conf_line from config.c to read logical lines
83 *
84 */
85
86#include "mdadm.h"
87#include "dlink.h"
dd0781e5 88#include <sys/select.h>
549e9569 89#include <ctype.h>
e0d19036
NB
90
91void free_mdstat(struct mdstat_ent *ms)
92{
93 while (ms) {
94 struct mdstat_ent *t;
95 if (ms->dev) free(ms->dev);
96 if (ms->level) free(ms->level);
97 if (ms->pattern) free(ms->pattern);
98 t = ms;
99 ms = ms->next;
100 free(t);
101 }
102}
103
dd0781e5 104static int mdstat_fd = -1;
22a88995 105struct mdstat_ent *mdstat_read(int hold, int start)
e0d19036
NB
106{
107 FILE *f;
22a88995 108 struct mdstat_ent *all, *rv, **end, **insert_here;
e0d19036
NB
109 char *line;
110
dd0781e5
NB
111 if (hold && mdstat_fd != -1) {
112 lseek(mdstat_fd, 0L, 0);
113 f = fdopen(dup(mdstat_fd), "r");
114 } else
115 f = fopen("/proc/mdstat", "r");
e0d19036
NB
116 if (f == NULL)
117 return NULL;
e4dc5106
DL
118 else
119 fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
e0d19036
NB
120
121 all = NULL;
122 end = &all;
123 for (; (line = conf_line(f)) ; free_line(line)) {
124 struct mdstat_ent *ent;
125 char *w;
98c6faba 126 int devnum;
22a88995 127 int in_devs = 0;
98c6faba 128 char *ep;
e0d19036
NB
129
130 if (strcmp(line, "Personalities")==0)
131 continue;
132 if (strcmp(line, "read_ahead")==0)
133 continue;
134 if (strcmp(line, "unused")==0)
135 continue;
22a88995 136 insert_here = NULL;
e0d19036 137 /* Better be an md line.. */
98c6faba
NB
138 if (strncmp(line, "md", 2)!= 0)
139 continue;
140 if (strncmp(line, "md_d", 4) == 0)
141 devnum = -1-strtoul(line+4, &ep, 10);
142 else if (strncmp(line, "md", 2) == 0)
143 devnum = strtoul(line+2, &ep, 10);
144 else
145 continue;
146 if (ep == NULL || *ep ) {
147 /* fprintf(stderr, Name ": bad /proc/mdstat line starts: %s\n", line); */
e0d19036
NB
148 continue;
149 }
150
151 ent = malloc(sizeof(*ent));
152 if (!ent) {
153 fprintf(stderr, Name ": malloc failed reading /proc/mdstat.\n");
154 free_line(line);
dd0781e5 155 break;
e0d19036
NB
156 }
157 ent->dev = ent->level = ent->pattern= NULL;
158 ent->next = NULL;
159 ent->percent = -1;
160 ent->active = -1;
e5329c37 161 ent->resync = 0;
549e9569
NB
162 ent->metadata_version = NULL;
163 ent->raid_disks = 0;
164 ent->chunk_size = 0;
165 ent->devcnt = 0;
e0d19036
NB
166
167 ent->dev = strdup(line);
98c6faba 168 ent->devnum = devnum;
aba69144 169
e0d19036
NB
170 for (w=dl_next(line); w!= line ; w=dl_next(w)) {
171 int l = strlen(w);
172 char *eq;
173 if (strcmp(w, "active")==0)
174 ent->active = 1;
175 else if (strcmp(w, "inactive")==0)
176 ent->active = 0;
177 else if (ent->active >=0 &&
178 ent->level == NULL &&
22a88995 179 w[0] != '(' /*readonly*/) {
e0d19036 180 ent->level = strdup(w);
22a88995
NB
181 in_devs = 1;
182 } else if (in_devs && strcmp(w, "blocks")==0)
183 in_devs = 0;
549e9569
NB
184 else if (in_devs) {
185 ent->devcnt++;
186 if (strncmp(w, "md", 2)==0) {
187 /* This has an md device as a component.
188 * If that device is already in the
189 * list, make sure we insert before
190 * there.
191 */
192 struct mdstat_ent **ih;
193 int dn2;
194 if (strncmp(w, "md_d", 4)==0)
195 dn2 = -1-strtoul(w+4, &ep, 10);
196 else
197 dn2 = strtoul(w+2, &ep, 10);
198 ih = &all;
199 while (ih != insert_here && *ih &&
200 (*ih)->devnum != dn2)
201 ih = & (*ih)->next;
202 insert_here = ih;
203 }
204 } else if (strcmp(w, "super") == 0 &&
205 dl_next(w) != line) {
206 w = dl_next(w);
207 ent->metadata_version = strdup(w);
208 } else if (w[0] == '[' && isdigit(w[1])) {
209 ent->raid_disks = atoi(w+1);
22a88995 210 } else if (!ent->pattern &&
e0d19036
NB
211 w[0] == '[' &&
212 (w[1] == 'U' || w[1] == '_')) {
213 ent->pattern = strdup(w+1);
214 if (ent->pattern[l-2]==']')
215 ent->pattern[l-2] = '\0';
216 } else if (ent->percent == -1 &&
217 strncmp(w, "re", 2)== 0 &&
218 w[l-1] == '%' &&
219 (eq=strchr(w, '=')) != NULL ) {
220 ent->percent = atoi(eq+1);
e5329c37
NB
221 if (strncmp(w,"resync", 4)==0)
222 ent->resync = 1;
223 } else if (ent->percent == -1 &&
224 strncmp(w, "resync", 4)==0) {
225 ent->resync = 1;
e0d19036 226 } else if (ent->percent == -1 &&
aba69144 227 w[0] >= '0' &&
e0d19036
NB
228 w[0] <= '9' &&
229 w[l-1] == '%') {
230 ent->percent = atoi(w);
231 }
232 }
22a88995
NB
233 if (insert_here && (*insert_here)) {
234 ent->next = *insert_here;
235 *insert_here = ent;
236 } else {
237 *end = ent;
238 end = &ent->next;
239 }
e0d19036 240 }
e4dc5106 241 if (hold && mdstat_fd == -1) {
dd0781e5 242 mdstat_fd = dup(fileno(f));
e4dc5106
DL
243 fcntl(mdstat_fd, F_SETFD, FD_CLOEXEC);
244 }
e0d19036 245 fclose(f);
22a88995
NB
246
247 /* If we might want to start array,
248 * reverse the order, so that components comes before composites
249 */
250 if (start) {
251 rv = NULL;
252 while (all) {
253 struct mdstat_ent *e = all;
254 all = all->next;
255 e->next = rv;
256 rv = e;
257 }
258 } else rv = all;
259 return rv;
e0d19036 260}
dd0781e5
NB
261
262void mdstat_wait(int seconds)
263{
264 fd_set fds;
265 struct timeval tm;
266 FD_ZERO(&fds);
267 if (mdstat_fd >= 0)
268 FD_SET(mdstat_fd, &fds);
269 tm.tv_sec = seconds;
270 tm.tv_usec = 0;
271 select(mdstat_fd >2 ? mdstat_fd+1:3, NULL, NULL, &fds, &tm);
272}
8382f19b 273
549e9569
NB
274void mdstat_wait_fd(int fd)
275{
276 fd_set fds, rfds;
277
278 FD_ZERO(&fds);
279 FD_ZERO(&rfds);
280 if (mdstat_fd >= 0)
281 FD_SET(mdstat_fd, &fds);
282 FD_SET(fd, &rfds);
283
284 select(mdstat_fd >2 ? mdstat_fd+1:3, &rfds, NULL, &fds, NULL);
285}
286
8382f19b
NB
287int mddev_busy(int devnum)
288{
289 struct mdstat_ent *mdstat = mdstat_read(0, 0);
290 struct mdstat_ent *me;
291
292 for (me = mdstat ; me ; me = me->next)
293 if (me->devnum == devnum)
294 break;
295 free_mdstat(mdstat);
296 return me != NULL;
297}