Merge mdmon
[thirdparty/mdadm.git] / mdmon.c
CommitLineData
549e9569
NB
1
2/*
3 * md array manager.
4 * When md arrays have user-space managed metadata, this is the program
5 * that does the managing.
6 *
7 * Given one argument: the name of the array (e.g. /dev/md0) that is
8 * the container.
9 * We fork off a helper that runs high priority and mlocked. It responds to
10 * device failures and other events that might stop writeout, or that are
11 * trivial to deal with.
12 * The main thread then watches for new arrays being created in the container
13 * and starts monitoring them too ... along with a few other tasks.
14 *
15 * The main thread communicates with the priority thread by writing over
16 * a pipe.
17 * Separate programs can communicate with the main thread via Unix-domain
18 * socket.
19 * The two threads share address space and open file table.
20 *
21 */
22
23#ifndef _GNU_SOURCE
24#define _GNU_SOURCE
25#endif
26
27#include <unistd.h>
28#include <stdlib.h>
29#include <sys/stat.h>
30#include <sys/socket.h>
31#include <sys/un.h>
32#include <sys/mman.h>
33#include <stdio.h>
34#include <errno.h>
35#include <string.h>
36#include <fcntl.h>
37
38#include <sched.h>
39
40#include "mdadm.h"
41#include "mdmon.h"
42
43struct active_array *array_list;
44struct active_array *discard_this;
45struct active_array *pending_discard;
46
47int run_child(void *v)
48{
49 struct supertype *c = v;
50 do_monitor(c);
51 return 0;
52}
53
54int clone_monitor(struct supertype *container)
55{
56 int pfd[2];
57 static char stack[4096];
58 int rv;
59
60 pipe(container->pipe);
61
62 rv = clone(run_child, stack+4096-64,
63 CLONE_FS|CLONE_FILES|CLONE_VM|CLONE_SIGHAND|CLONE_THREAD,
64 container);
65
66 if (rv < 0)
67 return rv;
68 return pfd[1];
69}
70
71static struct superswitch *find_metadata_methods(char *vers)
72{
73 if (strcmp(vers, "ddf") == 0)
74 return &super_ddf;
75 return NULL;
76}
77
78
79static int make_pidfile(char *devname)
80{
81 char path[100];
82 char pid[10];
83 int fd;
84 sprintf(path, "/var/run/mdadm/%s.pid", devname);
85
86 fd = open(path, O_RDWR|O_CREAT|O_EXCL, 0600);
87 if (fd < 0)
88 return -1;
89 sprintf(pid, "%d\n", getpid());
90 write(fd, pid, strlen(pid));
91 close(fd);
92 return 0;
93}
94
95static int make_control_sock(char *devname)
96{
97 char path[100];
98 int sfd;
99 long fl;
100 struct sockaddr_un addr;
101
102 sprintf(path, "/var/run/mdadm/%s.sock", devname);
103 unlink(path);
104 sfd = socket(PF_LOCAL, SOCK_STREAM, 0);
105 if (sfd < 0)
106 return -1;
107
108 addr.sun_family = PF_LOCAL;
109 strcpy(addr.sun_path, path);
110 if (bind(sfd, &addr, sizeof(addr)) < 0) {
111 close(sfd);
112 return -1;
113 }
114 listen(sfd, 10);
115 fl = fcntl(sfd, F_GETFL, 0);
116 fl |= O_NONBLOCK;
117 fcntl(sfd, F_SETFL, fl);
118 return sfd;
119}
120
121int main(int argc, char *argv[])
122{
123 int mdfd;
124 int pipefd;
125 struct mdinfo *mdi, *di;
126 struct supertype *container;
127 if (argc != 2) {
128 fprintf(stderr, "Usage: md-manage /device/name/for/container\n");
129 exit(2);
130 }
131 mdfd = open(argv[1], O_RDWR);
132 if (mdfd < 0) {
133 fprintf(stderr, "md-manage: %s: %s\n", argv[1],
134 strerror(errno));
135 exit(1);
136 }
137 if (md_get_version(mdfd) < 0) {
138 fprintf(stderr, "md-manage: %s: Not an md device\n",
139 argv[1]);
140 exit(1);
141 }
142
143 /* hopefully it is a container - we'll check later */
144
145 container = malloc(sizeof(*container));
146 container->devfd = mdfd;
147 container->devnum = fd2devnum(mdfd);
148 container->devname = devnum2devname(container->devnum);
149
150 /* If this fails, we hope it already exists */
151 mkdir("/var/run/mdadm", 0600);
152 /* pid file lives in /var/run/mdadm/mdXX.pid */
153 if (make_pidfile(container->devname) < 0) {
154 fprintf(stderr, "md-manage: %s already managed\n",
155 container->devname);
156 exit(3);
157 }
158
159 container->sock = make_control_sock(container->devname);
160 if (container->sock < 0) {
161 fprintf(stderr, "mdmon: Cannot create socket in /var/run/mdadm\n");
162 exit(3);
163 }
164 container->arrays = NULL;
165
166 mdi = sysfs_read(mdfd, container->devnum,
167 GET_VERSION|GET_LEVEL|GET_DEVS);
168
169 if (!mdi) {
170 fprintf(stderr, "mdmon: failed to load sysfs info for %s\n",
171 container->devname);
172 exit(3);
173 }
174 if (mdi->array.level != UnSet) {
175 fprintf(stderr, "mdmon: %s is not a container - cannot monitor\n",
176 argv[1]);
177 exit(3);
178 }
179 if (mdi->array.major_version != -1 ||
180 mdi->array.minor_version != -2) {
181 fprintf(stderr, "mdmon: %s does not use external metadata - cannot monitor\n",
182 argv[1]);
183 exit(3);
184 }
185
186 container->ss = find_metadata_methods(mdi->text_version);
187 if (container->ss == NULL) {
188 fprintf(stderr, "mdmon: %s uses unknown metadata: %s\n",
189 argv[1], mdi->text_version);
190 exit(3);
191 }
192
193 container->devs = NULL;
194 for (di = mdi->devs; di; di = di->next) {
195 struct mdinfo *cd = malloc(sizeof(*cd));
196 cd = di;
197 cd->next = container->devs;
198 container->devs = cd;
199 }
200 sysfs_free(mdi);
201
202
203 if (container->ss->load_super(container, mdfd, argv[1])) {
204 fprintf(stderr, "mdmon: Cannot load metadata for %s\n",
205 argv[1]);
206 exit(3);
207 }
208
209
210 mlockall(MCL_FUTURE);
211
212 pipefd = clone_monitor(container);
213 if (pipefd < 0) {
214 fprintf(stderr, "md-manage: failed to start monitor process: %s\n",
215 strerror(errno));
216 exit(2);
217 }
218
219 do_manager(container);
220
221 exit(0);
222}