]> git.neil.brown.name Git - mdadm.git/blob - msg.c
Release mdadm-4.0
[mdadm.git] / msg.c
1 /*
2  * Copyright (C) 2008 Intel Corporation
3  *
4  *      mdmon socket / message handling
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include "mdadm.h"
32 #include "mdmon.h"
33
34 static const __u32 start_magic = 0x5a5aa5a5;
35 static const __u32 end_magic = 0xa5a55a5a;
36
37 static int send_buf(int fd, const void* buf, int len, int tmo)
38 {
39         fd_set set;
40         int rv;
41         struct timeval timeout = {tmo, 0};
42         struct timeval *ptmo = tmo ? &timeout : NULL;
43
44         while (len) {
45                 FD_ZERO(&set);
46                 FD_SET(fd, &set);
47                 rv = select(fd+1, NULL, &set, NULL, ptmo);
48                 if (rv <= 0)
49                         return -1;
50                 rv = write(fd, buf, len);
51                 if (rv <= 0)
52                         return -1;
53                 len -= rv;
54                 buf += rv;
55         }
56         return 0;
57 }
58
59 static int recv_buf(int fd, void* buf, int len, int tmo)
60 {
61         fd_set set;
62         int rv;
63         struct timeval timeout = {tmo, 0};
64         struct timeval *ptmo = tmo ? &timeout : NULL;
65
66         while (len) {
67                 FD_ZERO(&set);
68                 FD_SET(fd, &set);
69                 rv = select(fd+1, &set, NULL, NULL, ptmo);
70                 if (rv <= 0)
71                         return -1;
72                 rv = read(fd, buf, len);
73                 if (rv <= 0)
74                         return -1;
75                 len -= rv;
76                 buf += rv;
77         }
78         return 0;
79 }
80
81 int send_message(int fd, struct metadata_update *msg, int tmo)
82 {
83         __s32 len = msg->len;
84         int rv;
85
86         rv = send_buf(fd, &start_magic, 4, tmo);
87         rv = rv ?: send_buf(fd, &len, 4, tmo);
88         if (len > 0)
89                 rv = rv ?: send_buf(fd, msg->buf, msg->len, tmo);
90         rv = send_buf(fd, &end_magic, 4, tmo);
91
92         return rv;
93 }
94
95 int receive_message(int fd, struct metadata_update *msg, int tmo)
96 {
97         __u32 magic;
98         __s32 len;
99         int rv;
100
101         rv = recv_buf(fd, &magic, 4, tmo);
102         if (rv < 0 || magic != start_magic)
103                 return -1;
104         rv = recv_buf(fd, &len, 4, tmo);
105         if (rv < 0 || len > MSG_MAX_LEN)
106                 return -1;
107         if (len > 0) {
108                 msg->buf = xmalloc(len);
109                 rv = recv_buf(fd, msg->buf, len, tmo);
110                 if (rv < 0) {
111                         free(msg->buf);
112                         return -1;
113                 }
114         } else
115                 msg->buf = NULL;
116         rv = recv_buf(fd, &magic, 4, tmo);
117         if (rv < 0 || magic != end_magic) {
118                 free(msg->buf);
119                 return -1;
120         }
121         msg->len = len;
122         return 0;
123 }
124
125 int ack(int fd, int tmo)
126 {
127         struct metadata_update msg = { .len = 0 };
128
129         return send_message(fd, &msg, tmo);
130 }
131
132 int wait_reply(int fd, int tmo)
133 {
134         struct metadata_update msg;
135         int err = receive_message(fd, &msg, tmo);
136
137         /* mdmon sent extra data, but caller only cares that we got a
138          * successful reply
139          */
140         if (err == 0 && msg.len > 0)
141                 free(msg.buf);
142
143         return err;
144 }
145
146 int connect_monitor(char *devname)
147 {
148         char path[100];
149         int sfd;
150         long fl;
151         struct sockaddr_un addr;
152         int pos;
153         char *c;
154
155         pos = sprintf(path, "%s/", MDMON_DIR);
156         if (is_subarray(devname)) {
157                 devname++;
158                 c = strchr(devname, '/');
159                 if (!c)
160                         return -1;
161                 snprintf(&path[pos], c - devname + 1, "%s", devname);
162                 pos += c - devname;
163         } else
164                 pos += sprintf(&path[pos], "%s", devname);
165         sprintf(&path[pos], ".sock");
166
167         sfd = socket(PF_LOCAL, SOCK_STREAM, 0);
168         if (sfd < 0)
169                 return -1;
170
171         addr.sun_family = PF_LOCAL;
172         strcpy(addr.sun_path, path);
173         if (connect(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
174                 pr_err("Error connecting monitor with %s: %s\n",
175                         addr.sun_path, strerror(errno));
176                 close(sfd);
177                 return -1;
178         }
179
180         fl = fcntl(sfd, F_GETFL, 0);
181         fl |= O_NONBLOCK;
182         fcntl(sfd, F_SETFL, fl);
183
184         return sfd;
185 }
186
187 int fping_monitor(int sfd)
188 {
189         int err = 0;
190
191         if (sfd < 0)
192                 return sfd;
193
194         /* try to ping existing socket */
195         if (ack(sfd, 20) != 0)
196                 err = -1;
197
198         /* check the reply */
199         if (!err && wait_reply(sfd, 20) != 0)
200                 err = -1;
201
202         return err;
203 }
204
205 /* give the monitor a chance to update the metadata */
206 int ping_monitor(char *devname)
207 {
208         int sfd = connect_monitor(devname);
209         int err;
210
211         if (sfd >= 0) {
212                 err = fping_monitor(sfd);
213                 close(sfd);
214         } else
215                 err = -1;
216
217         return err;
218 }
219
220 static char *ping_monitor_version(char *devname)
221 {
222         int sfd = connect_monitor(devname);
223         struct metadata_update msg;
224         int err = 0;
225
226         if (sfd < 0)
227                 return NULL;
228
229         if (ack(sfd, 20) != 0)
230                 err = -1;
231
232         if (!err && receive_message(sfd, &msg, 20) != 0)
233                 err = -1;
234
235         close(sfd);
236
237         if (err || !msg.len || !msg.buf)
238                 return NULL;
239         return msg.buf;
240 }
241
242 int unblock_subarray(struct mdinfo *sra, const int unfreeze)
243 {
244         char buf[64];
245         int rc = 0;
246
247         if (sra) {
248                 sprintf(buf, "external:%s\n", sra->text_version);
249                 buf[9] = '/';
250         } else
251                 buf[9] = '-';
252
253         if (buf[9] == '-' ||
254             sysfs_set_str(sra, NULL, "metadata_version", buf) ||
255             (unfreeze &&
256              sysfs_attribute_available(sra, NULL, "sync_action") &&
257              sysfs_set_str(sra, NULL, "sync_action", "idle")))
258                 rc = -1;
259         return rc;
260 }
261
262 int block_subarray(struct mdinfo *sra)
263 {
264         char buf[64];
265         int rc = 0;
266
267         sprintf(buf, "external:%s\n", sra->text_version);
268         buf[9] = '-';
269         if (sysfs_set_str(sra, NULL, "metadata_version", buf))
270                 rc = -1;
271
272         return rc;
273 }
274
275 /* check mdmon version if it supports
276  * array blocking mechanism
277  */
278 int check_mdmon_version(char *container)
279 {
280         char *version = NULL;
281
282         if (!mdmon_running(container)) {
283                 /* if mdmon is not active we assume that any instance that is
284                  * later started will match the current mdadm version, if this
285                  * assumption is violated we may inadvertantly rebuild an array
286                  * that was meant for reshape, or start rebuild on a spare that
287                  * was to be moved to another container
288                  */
289                 /* pass */;
290         } else {
291                 int ver;
292
293                 version = ping_monitor_version(container);
294                 ver = version ? mdadm_version(version) : -1;
295                 free(version);
296                 if (ver < 3002000) {
297                         pr_err("mdmon instance for %s cannot be disabled\n",
298                                container);
299                         return -1;
300                 }
301         }
302
303         return 0;
304 }
305
306 /**
307  * block_monitor - prevent mdmon spare assignment
308  * @container - container to block
309  * @freeze - flag to additionally freeze sync_action
310  *
311  * This is used by the reshape code to freeze the container, and the
312  * auto-rebuild implementation to atomically move spares.
313  * In both cases we need to stop mdmon from assigning spares to replace
314  * failed devices as we might have other plans for the spare.
315  * For the reshape case we also need to 'freeze' sync_action so that
316  * no recovery happens until we have fully prepared for the reshape.
317  *
318  * We tell mdmon that the array is frozen by marking the 'metadata' name
319  * with a leading '-'.  The previously told mdmon "Don't make this array
320  * read/write, leave it readonly".  Now it means a more general "Don't
321  * reconfigure this array at all".
322  * As older versions of mdmon (which might run from initrd) don't understand
323  * this, we first check that the running mdmon is new enough.
324  */
325 int block_monitor(char *container, const int freeze)
326 {
327         struct mdstat_ent *ent, *e, *e2;
328         struct mdinfo *sra = NULL;
329         char buf[64];
330         int rv = 0;
331
332         if (check_mdmon_version(container))
333                 return -1;
334
335         ent = mdstat_read(0, 0);
336         if (!ent) {
337                 pr_err("failed to read /proc/mdstat while disabling mdmon\n");
338                 return -1;
339         }
340
341         /* freeze container contents */
342         for (e = ent; e; e = e->next) {
343                 if (!is_container_member(e, container))
344                         continue;
345                 sysfs_free(sra);
346                 sra = sysfs_read(-1, e->devnm, GET_VERSION);
347                 if (!sra) {
348                         pr_err("failed to read sysfs for subarray%s\n",
349                                to_subarray(e, container));
350                         break;
351                 }
352                 /* can't reshape an array that we can't monitor */
353                 if (sra->text_version[0] == '-')
354                         break;
355
356                 if (freeze && sysfs_freeze_array(sra) < 1)
357                         break;
358                 /* flag this array to not be modified by mdmon (close race with
359                  * takeover in reshape case and spare reassignment in the
360                  * auto-rebuild case)
361                  */
362                 if (block_subarray(sra))
363                         break;
364                 ping_monitor(container);
365
366                 /* check that we did not race with recovery */
367                 if ((freeze &&
368                      !sysfs_attribute_available(sra, NULL, "sync_action")) ||
369                     (freeze &&
370                      sysfs_attribute_available(sra, NULL, "sync_action") &&
371                      sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0 &&
372                      strcmp(buf, "frozen\n") == 0))
373                         /* pass */;
374                 else {
375                         unblock_subarray(sra, 0);
376                         break;
377                 }
378                 /* Double check against races - there should be no spares
379                  * or part-spares
380                  */
381                 sysfs_free(sra);
382                 sra = sysfs_read(-1, e->devnm, GET_DEVS | GET_STATE);
383                 if (sra && sra->array.spare_disks > 0) {
384                         unblock_subarray(sra, freeze);
385                         break;
386                 }
387         }
388
389         if (e) {
390                 pr_err("failed to freeze subarray%s\n",
391                         to_subarray(e, container));
392
393                 /* thaw the partially frozen container */
394                 for (e2 = ent; e2 && e2 != e; e2 = e2->next) {
395                         if (!is_container_member(e2, container))
396                                 continue;
397                         sysfs_free(sra);
398                         sra = sysfs_read(-1, e2->devnm, GET_VERSION);
399                         if (unblock_subarray(sra, freeze))
400                                 pr_err("Failed to unfreeze %s\n", e2->devnm);
401                 }
402
403                 ping_monitor(container); /* cleared frozen */
404                 rv = -1;
405         }
406
407         sysfs_free(sra);
408         free_mdstat(ent);
409
410         return rv;
411 }
412
413 void unblock_monitor(char *container, const int unfreeze)
414 {
415         struct mdstat_ent *ent, *e;
416         struct mdinfo *sra = NULL;
417         int to_ping = 0;
418
419         ent = mdstat_read(0, 0);
420         if (!ent) {
421                 pr_err("failed to read /proc/mdstat while unblocking container\n");
422                 return;
423         }
424
425         /* unfreeze container contents */
426         for (e = ent; e; e = e->next) {
427                 if (!is_container_member(e, container))
428                         continue;
429                 sysfs_free(sra);
430                 sra = sysfs_read(-1, e->devnm, GET_VERSION|GET_LEVEL);
431                 if (!sra)
432                         continue;
433                 if (sra->array.level > 0)
434                         to_ping++;
435                 if (unblock_subarray(sra, unfreeze))
436                         pr_err("Failed to unfreeze %s\n", e->devnm);
437         }
438         if (to_ping)
439                 ping_monitor(container);
440
441         sysfs_free(sra);
442         free_mdstat(ent);
443 }
444
445 /* give the manager a chance to view the updated container state.  This
446  * would naturally happen due to the manager noticing a change in
447  * /proc/mdstat; however, pinging encourages this detection to happen
448  * while an exclusive open() on the container is active
449  */
450 int ping_manager(char *devname)
451 {
452         int sfd = connect_monitor(devname);
453         struct metadata_update msg = { .len = -1 };
454         int err = 0;
455
456         if (sfd < 0)
457                 return sfd;
458
459         err = send_message(sfd, &msg, 20);
460
461         /* check the reply */
462         if (!err && wait_reply(sfd, 20) != 0)
463                 err = -1;
464
465         close(sfd);
466         return err;
467 }
468
469 /* using takeover operation for grow purposes, mdadm has to be sure
470  * that mdmon processes all updates, and if necessary it will be closed
471  * at takeover to raid0 operation
472   */
473 void flush_mdmon(char *container)
474 {
475         ping_manager(container);
476         ping_monitor(container);
477 }