]>
Commit | Line | Data |
---|---|---|
f7dd881f DW |
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" | |
bfa44e2e | 32 | #include "mdmon.h" |
f7dd881f | 33 | |
bfa44e2e NB |
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) | |
f7dd881f | 38 | { |
bfa44e2e NB |
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 | } | |
f7dd881f | 58 | |
bfa44e2e NB |
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; | |
f7dd881f DW |
79 | } |
80 | ||
81 | ||
bfa44e2e | 82 | int send_message(int fd, struct metadata_update *msg, int tmo) |
f7dd881f | 83 | { |
313a4a82 | 84 | __s32 len = msg->len; |
bfa44e2e NB |
85 | int rv; |
86 | ||
87 | rv = send_buf(fd, &start_magic, 4, tmo); | |
88 | rv = rv ?: send_buf(fd, &len, 4, tmo); | |
313a4a82 | 89 | if (len > 0) |
bfa44e2e NB |
90 | rv = rv ?: send_buf(fd, msg->buf, msg->len, tmo); |
91 | rv = send_buf(fd, &end_magic, 4, tmo); | |
92 | ||
93 | return rv; | |
f7dd881f DW |
94 | } |
95 | ||
bfa44e2e | 96 | int receive_message(int fd, struct metadata_update *msg, int tmo) |
f7dd881f | 97 | { |
bfa44e2e | 98 | __u32 magic; |
313a4a82 | 99 | __s32 len; |
bfa44e2e NB |
100 | int rv; |
101 | ||
102 | rv = recv_buf(fd, &magic, 4, tmo); | |
103 | if (rv < 0 || magic != start_magic) | |
104 | return -1; | |
105 | rv = recv_buf(fd, &len, 4, tmo); | |
106 | if (rv < 0 || len > MSG_MAX_LEN) | |
f7dd881f | 107 | return -1; |
313a4a82 | 108 | if (len > 0) { |
bfa44e2e NB |
109 | msg->buf = malloc(len); |
110 | if (msg->buf == NULL) | |
111 | return -1; | |
112 | rv = recv_buf(fd, msg->buf, len, tmo); | |
113 | if (rv < 0) { | |
114 | free(msg->buf); | |
115 | return -1; | |
116 | } | |
117 | } else | |
118 | msg->buf = NULL; | |
119 | rv = recv_buf(fd, &magic, 4, tmo); | |
120 | if (rv < 0 || magic != end_magic) { | |
121 | free(msg->buf); | |
122 | return -1; | |
123 | } | |
124 | msg->len = len; | |
125 | return 0; | |
f7dd881f DW |
126 | } |
127 | ||
bfa44e2e | 128 | int ack(int fd, int tmo) |
f7dd881f | 129 | { |
bfa44e2e | 130 | struct metadata_update msg = { .len = 0 }; |
f7dd881f DW |
131 | |
132 | return send_message(fd, &msg, tmo); | |
133 | } | |
134 | ||
bfa44e2e | 135 | int wait_reply(int fd, int tmo) |
f7dd881f | 136 | { |
bfa44e2e NB |
137 | struct metadata_update msg; |
138 | return receive_message(fd, &msg, tmo); | |
f7dd881f DW |
139 | } |
140 | ||
f7dd881f DW |
141 | int connect_monitor(char *devname) |
142 | { | |
143 | char path[100]; | |
144 | int sfd; | |
145 | long fl; | |
146 | struct sockaddr_un addr; | |
c94709e8 DW |
147 | int pos; |
148 | char *c; | |
149 | ||
150 | pos = sprintf(path, "/var/run/mdadm/"); | |
151 | if (is_subarray(devname)) { | |
152 | devname++; | |
153 | c = strchr(devname, '/'); | |
154 | if (!c) | |
155 | return -1; | |
156 | snprintf(&path[pos], c - devname + 1, "%s", devname); | |
157 | pos += c - devname; | |
158 | } else | |
159 | pos += sprintf(&path[pos], "%s", devname); | |
160 | sprintf(&path[pos], ".sock"); | |
f7dd881f | 161 | |
f7dd881f DW |
162 | sfd = socket(PF_LOCAL, SOCK_STREAM, 0); |
163 | if (sfd < 0) | |
164 | return -1; | |
165 | ||
166 | addr.sun_family = PF_LOCAL; | |
167 | strcpy(addr.sun_path, path); | |
168 | if (connect(sfd, &addr, sizeof(addr)) < 0) { | |
169 | close(sfd); | |
170 | return -1; | |
171 | } | |
172 | ||
173 | fl = fcntl(sfd, F_GETFL, 0); | |
174 | fl |= O_NONBLOCK; | |
175 | fcntl(sfd, F_SETFL, fl); | |
176 | ||
177 | return sfd; | |
178 | } | |
179 | ||
9f1da824 | 180 | int fping_monitor(int sfd) |
f7dd881f | 181 | { |
f7dd881f DW |
182 | int err = 0; |
183 | ||
184 | if (sfd < 0) | |
185 | return sfd; | |
186 | ||
187 | /* try to ping existing socket */ | |
eb2c876f | 188 | if (ack(sfd, 20) != 0) |
f7dd881f DW |
189 | err = -1; |
190 | ||
191 | /* check the reply */ | |
eb2c876f | 192 | if (!err && wait_reply(sfd, 20) != 0) |
f7dd881f DW |
193 | err = -1; |
194 | ||
9f1da824 DW |
195 | return err; |
196 | } | |
197 | ||
198 | ||
199 | /* give the monitor a chance to update the metadata */ | |
200 | int ping_monitor(char *devname) | |
201 | { | |
202 | int sfd = connect_monitor(devname); | |
203 | int err = fping_monitor(sfd); | |
204 | ||
f7dd881f DW |
205 | close(sfd); |
206 | return err; | |
207 | } | |
313a4a82 DW |
208 | |
209 | /* give the manager a chance to view the updated container state. This | |
210 | * would naturally happen due to the manager noticing a change in | |
211 | * /proc/mdstat; however, pinging encourages this detection to happen | |
212 | * while an exclusive open() on the container is active | |
213 | */ | |
214 | int ping_manager(char *devname) | |
215 | { | |
216 | int sfd = connect_monitor(devname); | |
217 | struct metadata_update msg = { .len = -1 }; | |
218 | int err = 0; | |
219 | ||
220 | if (sfd < 0) | |
221 | return sfd; | |
222 | ||
223 | err = send_message(sfd, &msg, 20); | |
224 | ||
225 | /* check the reply */ | |
226 | if (!err && wait_reply(sfd, 20) != 0) | |
227 | err = -1; | |
228 | ||
229 | close(sfd); | |
230 | return err; | |
231 | } |