]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/nbd.c
Merge pull request #2652 from brauner/lxc/master
[mirror_lxc.git] / src / lxc / storage / nbd.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE 1
26 #endif
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/prctl.h>
34 #include <sys/wait.h>
35
36 #include "config.h"
37 #include "log.h"
38 #include "nbd.h"
39 #include "storage.h"
40 #include "storage_utils.h"
41 #include "utils.h"
42
43 #ifndef HAVE_STRLCPY
44 #include "include/strlcpy.h"
45 #endif
46
47 lxc_log_define(nbd, lxc);
48
49 struct nbd_attach_data {
50 const char *nbd;
51 const char *path;
52 };
53
54 static int do_attach_nbd(void *d);
55 static bool clone_attach_nbd(const char *nbd, const char *path);
56 static bool nbd_busy(int idx);
57 static void nbd_detach(const char *path);
58 static int nbd_get_partition(const char *src);
59 static bool wait_for_partition(const char *path);
60
61 bool attach_nbd(char *src, struct lxc_conf *conf)
62 {
63 char *orig, *p, path[50];
64 int i = 0;
65 size_t len;
66
67 len = strlen(src);
68 orig = alloca(len + 1);
69 (void)strlcpy(orig, src, len + 1);
70
71 /* if path is followed by a partition, drop that for now */
72 p = strchr(orig, ':');
73 if (p)
74 *p = '\0';
75
76 while (1) {
77 sprintf(path, "/dev/nbd%d", i);
78
79 if (!file_exists(path))
80 return false;
81
82 if (nbd_busy(i)) {
83 i++;
84 continue;
85 }
86
87 if (!clone_attach_nbd(path, orig))
88 return false;
89
90 conf->nbd_idx = i;
91 return true;
92 }
93 }
94
95 void detach_nbd_idx(int idx)
96 {
97 int ret;
98 char path[50];
99
100 ret = snprintf(path, 50, "/dev/nbd%d", idx);
101 if (ret < 0 || ret >= 50)
102 return;
103
104 nbd_detach(path);
105 }
106
107 int nbd_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
108 const char *oldname, const char *cname, const char *oldpath,
109 const char *lxcpath, int snap, uint64_t newsize,
110 struct lxc_conf *conf)
111 {
112 return -ENOSYS;
113 }
114
115 int nbd_create(struct lxc_storage *bdev, const char *dest, const char *n,
116 struct bdev_specs *specs)
117 {
118 return -ENOSYS;
119 }
120
121 int nbd_destroy(struct lxc_storage *orig)
122 {
123 return -ENOSYS;
124 }
125
126 bool nbd_detect(const char *path)
127 {
128 if (!strncmp(path, "nbd:", 4))
129 return true;
130
131 return false;
132 }
133
134 int nbd_mount(struct lxc_storage *bdev)
135 {
136 int ret = -1, partition;
137 const char *src;
138 char path[50];
139
140 if (strcmp(bdev->type, "nbd"))
141 return -22;
142
143 if (!bdev->src || !bdev->dest)
144 return -22;
145
146 /* nbd_idx should have been copied by bdev_init from the lxc_conf */
147 if (bdev->nbd_idx < 0)
148 return -22;
149
150 src = lxc_storage_get_path(bdev->src, bdev->type);
151 partition = nbd_get_partition(src);
152 if (partition)
153 ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx,
154 partition);
155 else
156 ret = snprintf(path, 50, "/dev/nbd%d", bdev->nbd_idx);
157 if (ret < 0 || ret >= 50) {
158 ERROR("Error setting up nbd device path");
159 return ret;
160 }
161
162 /* It might take awhile for the partition files to show up */
163 if (partition)
164 if (!wait_for_partition(path))
165 return -2;
166
167 ret = mount_unknown_fs(path, bdev->dest, bdev->mntopts);
168 if (ret < 0)
169 ERROR("Error mounting %s", bdev->src);
170
171 return ret;
172 }
173
174 int nbd_umount(struct lxc_storage *bdev)
175 {
176 if (strcmp(bdev->type, "nbd"))
177 return -22;
178
179 if (!bdev->src || !bdev->dest)
180 return -22;
181
182 return umount(bdev->dest);
183 }
184
185 bool requires_nbd(const char *path)
186 {
187 if (strncmp(path, "nbd:", 4) == 0)
188 return true;
189
190 return false;
191 }
192
193 static int do_attach_nbd(void *d)
194 {
195 struct nbd_attach_data *data = d;
196 const char *nbd, *path;
197 pid_t pid;
198 sigset_t mask;
199 int sfd;
200 ssize_t s;
201 struct signalfd_siginfo fdsi;
202
203 sigemptyset(&mask);
204 sigaddset(&mask, SIGHUP);
205 sigaddset(&mask, SIGCHLD);
206
207 nbd = data->nbd;
208 path = data->path;
209
210 if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
211 SYSERROR("Error blocking signals for nbd watcher");
212 exit(1);
213 }
214
215 sfd = signalfd(-1, &mask, 0);
216 if (sfd == -1) {
217 SYSERROR("Error opening signalfd for nbd task");
218 exit(1);
219 }
220
221 if (prctl(PR_SET_PDEATHSIG, prctl_arg(SIGHUP), prctl_arg(0),
222 prctl_arg(0), prctl_arg(0)) < 0)
223 SYSERROR("Error setting parent death signal for nbd watcher");
224
225 pid = fork();
226 if (pid) {
227 for (;;) {
228 s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
229 if (s != sizeof(struct signalfd_siginfo))
230 SYSERROR("Error reading from signalfd");
231
232 if (fdsi.ssi_signo == SIGHUP) {
233 /* container has exited */
234 nbd_detach(nbd);
235 exit(0);
236 } else if (fdsi.ssi_signo == SIGCHLD) {
237 int status;
238
239 /* If qemu-nbd fails, or is killed by a signal,
240 * then exit */
241 while (waitpid(-1, &status, WNOHANG) > 0) {
242 if ((WIFEXITED(status) && WEXITSTATUS(status) != 0) ||
243 WIFSIGNALED(status)) {
244 nbd_detach(nbd);
245 exit(1);
246 }
247 }
248 }
249 }
250 }
251
252 close(sfd);
253
254 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
255 WARN("Warning: unblocking signals for nbd watcher");
256
257 execlp("qemu-nbd", "qemu-nbd", "-c", nbd, path, (char *)NULL);
258 SYSERROR("Error executing qemu-nbd");
259 _exit(1);
260 }
261
262 static bool clone_attach_nbd(const char *nbd, const char *path)
263 {
264 pid_t pid;
265 struct nbd_attach_data data;
266
267 data.nbd = nbd;
268 data.path = path;
269
270 pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);
271 if (pid < 0)
272 return false;
273
274 return true;
275 }
276
277 static bool nbd_busy(int idx)
278 {
279 char path[100];
280 int ret;
281
282 ret = snprintf(path, 100, "/sys/block/nbd%d/pid", idx);
283 if (ret < 0 || ret >= 100)
284 return true;
285
286 return file_exists(path);
287 }
288
289 static void nbd_detach(const char *path)
290 {
291 int ret;
292 pid_t pid = fork();
293
294 if (pid < 0) {
295 SYSERROR("Error forking to detach nbd");
296 return;
297 }
298
299 if (pid) {
300 ret = wait_for_pid(pid);
301 if (ret < 0)
302 ERROR("nbd disconnect returned an error");
303 return;
304 }
305
306 execlp("qemu-nbd", "qemu-nbd", "-d", path, (char *)NULL);
307 SYSERROR("Error executing qemu-nbd");
308 _exit(1);
309 }
310
311 /*
312 * Pick the partition # off the end of a nbd:file:p
313 * description. Return 1-9 for the partition id, or 0
314 * for no partition.
315 */
316 static int nbd_get_partition(const char *src)
317 {
318 char *p = strchr(src, ':');
319 if (!p)
320 return 0;
321
322 p = strchr(p+1, ':');
323 if (!p)
324 return 0;
325
326 p++;
327
328 if (*p < '1' || *p > '9')
329 return 0;
330
331 return *p - '0';
332 }
333
334 static bool wait_for_partition(const char *path)
335 {
336 int count = 0;
337
338 while (count < 5) {
339 if (file_exists(path))
340 return true;
341
342 sleep(1);
343 count++;
344 }
345
346 ERROR("Device %s did not show up after 5 seconds", path);
347 return false;
348 }