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