2
* mdstat - parse /proc/mdstat file. Part of:
3
* mdadm - manage Linux "md" devices aka RAID arrays.
5
* Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
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.
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.
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
23
* Email: <neilb@cse.unsw.edu.au>
25
* School of Computer Science and Engineering
26
* The University of New South Wales
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}}
39
* Normally only 4 md lines, but all are listed.
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
46
* unused: dev dev dev | <none>
48
* STATUS is personality dependant:
49
* linear: %dk rounding
51
* raid1: [%d/%d] [U_U] ( raid/working. operational or not)
52
* raid5: level 4/5, %dk chunk, algorithm %d [%d/%d] [U_U]
55
* {resync|recovery}=%u%% finish=%u.%umin
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)} ...
65
* unused: dev dev .. | <none>
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
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
81
* As continuation is indicated by leading space, we use
82
* conf_line from config.c to read logical lines
88
#include <sys/select.h>
90
void free_mdstat(struct mdstat_ent *ms)
94
if (ms->dev) free(ms->dev);
95
if (ms->level) free(ms->level);
96
if (ms->pattern) free(ms->pattern);
103
static int mdstat_fd = -1;
104
struct mdstat_ent *mdstat_read(int hold)
107
struct mdstat_ent *all, **end;
110
if (hold && mdstat_fd != -1) {
111
lseek(mdstat_fd, 0L, 0);
112
f = fdopen(dup(mdstat_fd), "r");
114
f = fopen("/proc/mdstat", "r");
120
for (; (line = conf_line(f)) ; free_line(line)) {
121
struct mdstat_ent *ent;
126
if (strcmp(line, "Personalities")==0)
128
if (strcmp(line, "read_ahead")==0)
130
if (strcmp(line, "unused")==0)
132
/* Better be an md line.. */
133
if (strncmp(line, "md", 2)!= 0)
135
if (strncmp(line, "md_d", 4) == 0)
136
devnum = -1-strtoul(line+4, &ep, 10);
137
else if (strncmp(line, "md", 2) == 0)
138
devnum = strtoul(line+2, &ep, 10);
141
if (ep == NULL || *ep ) {
142
/* fprintf(stderr, Name ": bad /proc/mdstat line starts: %s\n", line); */
146
ent = malloc(sizeof(*ent));
148
fprintf(stderr, Name ": malloc failed reading /proc/mdstat.\n");
152
ent->dev = ent->level = ent->pattern= NULL;
158
ent->dev = strdup(line);
159
ent->devnum = devnum;
161
for (w=dl_next(line); w!= line ; w=dl_next(w)) {
164
if (strcmp(w, "active")==0)
166
else if (strcmp(w, "inactive")==0)
168
else if (ent->active >=0 &&
169
ent->level == NULL &&
170
w[0] != '(' /*readonly*/)
171
ent->level = strdup(w);
172
else if (!ent->pattern &&
174
(w[1] == 'U' || w[1] == '_')) {
175
ent->pattern = strdup(w+1);
176
if (ent->pattern[l-2]==']')
177
ent->pattern[l-2] = '\0';
178
} else if (ent->percent == -1 &&
179
strncmp(w, "re", 2)== 0 &&
181
(eq=strchr(w, '=')) != NULL ) {
182
ent->percent = atoi(eq+1);
183
if (strncmp(w,"resync", 4)==0)
185
} else if (ent->percent == -1 &&
186
strncmp(w, "resync", 4)==0) {
188
} else if (ent->percent == -1 &&
192
ent->percent = atoi(w);
198
if (hold && mdstat_fd == -1)
199
mdstat_fd = dup(fileno(f));
204
void mdstat_wait(int seconds)
210
FD_SET(mdstat_fd, &fds);
213
select(mdstat_fd >2 ? mdstat_fd+1:3, NULL, NULL, &fds, &tm);