]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/nbd.c
coccinelle: use standard exit identifiers
[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 "memory_utils.h"
39 #include "nbd.h"
40 #include "storage.h"
41 #include "storage_utils.h"
42 #include "syscall_wrappers.h"
43 #include "utils.h"
44
45 #ifndef HAVE_STRLCPY
46 #include "include/strlcpy.h"
47 #endif
48
49 lxc_log_define(nbd, lxc);
50
51 struct nbd_attach_data {
52 const char *nbd;
53 const char *path;
54 };
55
56 static int do_attach_nbd(void *d);
57 static bool clone_attach_nbd(const char *nbd, const char *path);
58 static bool nbd_busy(int idx);
59 static void nbd_detach(const char *path);
60 static int nbd_get_partition(const char *src);
61 static bool wait_for_partition(const char *path);
62
63 bool attach_nbd(char *src, struct lxc_conf *conf)
64 {
65 __do_free char *orig;
66 char *p, path[50];
67 int i = 0;
68
69 orig = must_copy_string(src);
70 /* if path is followed by a partition, drop that for now */
71 p = strchr(orig, ':');
72 if (p)
73 *p = '\0';
74
75 for (;;) {
76 sprintf(path, "/dev/nbd%d", i);
77
78 if (!file_exists(path))
79 return false;
80
81 if (nbd_busy(i)) {
82 i++;
83 continue;
84 }
85
86 if (!clone_attach_nbd(path, orig))
87 return false;
88
89 conf->nbd_idx = i;
90 return true;
91 }
92 }
93
94 void detach_nbd_idx(int idx)
95 {
96 int ret;
97 char path[50];
98
99 ret = snprintf(path, 50, "/dev/nbd%d", idx);
100 if (ret < 0 || ret >= 50)
101 return;
102
103 nbd_detach(path);
104 }
105
106 int nbd_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
107 const char *oldname, const char *cname, const char *oldpath,
108 const char *lxcpath, int snap, uint64_t newsize,
109 struct lxc_conf *conf)
110 {
111 return -ENOSYS;
112 }
113
114 int nbd_create(struct lxc_storage *bdev, const char *dest, const char *n,
115 struct bdev_specs *specs)
116 {
117 return -ENOSYS;
118 }
119
120 int nbd_destroy(struct lxc_storage *orig)
121 {
122 return -ENOSYS;
123 }
124
125 bool nbd_detect(const char *path)
126 {
127 if (!strncmp(path, "nbd:", 4))
128 return true;
129
130 return false;
131 }
132
133 int nbd_mount(struct lxc_storage *bdev)
134 {
135 int ret = -1, partition;
136 const char *src;
137 char path[50];
138
139 if (strcmp(bdev->type, "nbd"))
140 return -22;
141
142 if (!bdev->src || !bdev->dest)
143 return -22;
144
145 /* nbd_idx should have been copied by bdev_init from the lxc_conf */
146 if (bdev->nbd_idx < 0)
147 return -22;
148
149 src = lxc_storage_get_path(bdev->src, bdev->type);
150 partition = nbd_get_partition(src);
151 if (partition)
152 ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx,
153 partition);
154 else
155 ret = snprintf(path, 50, "/dev/nbd%d", bdev->nbd_idx);
156 if (ret < 0 || ret >= 50) {
157 ERROR("Error setting up nbd device path");
158 return ret;
159 }
160
161 /* It might take awhile for the partition files to show up */
162 if (partition)
163 if (!wait_for_partition(path))
164 return -2;
165
166 ret = mount_unknown_fs(path, bdev->dest, bdev->mntopts);
167 if (ret < 0)
168 ERROR("Error mounting %s", bdev->src);
169
170 return ret;
171 }
172
173 int nbd_umount(struct lxc_storage *bdev)
174 {
175 if (strcmp(bdev->type, "nbd"))
176 return -22;
177
178 if (!bdev->src || !bdev->dest)
179 return -22;
180
181 return umount(bdev->dest);
182 }
183
184 bool requires_nbd(const char *path)
185 {
186 if (strncmp(path, "nbd:", 4) == 0)
187 return true;
188
189 return false;
190 }
191
192 static int do_attach_nbd(void *d)
193 {
194 struct nbd_attach_data *data = d;
195 const char *nbd, *path;
196 pid_t pid;
197 sigset_t mask;
198 int sfd;
199 ssize_t s;
200 struct signalfd_siginfo fdsi;
201
202 sigemptyset(&mask);
203 sigaddset(&mask, SIGHUP);
204 sigaddset(&mask, SIGCHLD);
205
206 nbd = data->nbd;
207 path = data->path;
208
209 if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
210 SYSERROR("Error blocking signals for nbd watcher");
211 exit(EXIT_FAILURE);
212 }
213
214 sfd = signalfd(-1, &mask, 0);
215 if (sfd == -1) {
216 SYSERROR("Error opening signalfd for nbd task");
217 exit(EXIT_FAILURE);
218 }
219
220 if (prctl(PR_SET_PDEATHSIG, prctl_arg(SIGHUP), prctl_arg(0),
221 prctl_arg(0), prctl_arg(0)) < 0)
222 SYSERROR("Error setting parent death signal for nbd watcher");
223
224 pid = fork();
225 if (pid) {
226 for (;;) {
227 s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
228 if (s != sizeof(struct signalfd_siginfo))
229 SYSERROR("Error reading from signalfd");
230
231 if (fdsi.ssi_signo == SIGHUP) {
232 /* container has exited */
233 nbd_detach(nbd);
234 exit(EXIT_SUCCESS);
235 } else if (fdsi.ssi_signo == SIGCHLD) {
236 int status;
237
238 /* If qemu-nbd fails, or is killed by a signal,
239 * then exit */
240 while (waitpid(-1, &status, WNOHANG) > 0) {
241 if ((WIFEXITED(status) && WEXITSTATUS(status) != 0) ||
242 WIFSIGNALED(status)) {
243 nbd_detach(nbd);
244 exit(EXIT_FAILURE);
245 }
246 }
247 }
248 }
249 }
250
251 close(sfd);
252
253 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
254 WARN("Warning: unblocking signals for nbd watcher");
255
256 execlp("qemu-nbd", "qemu-nbd", "-c", nbd, path, (char *)NULL);
257 SYSERROR("Error executing qemu-nbd");
258 _exit(EXIT_FAILURE);
259 }
260
261 static bool clone_attach_nbd(const char *nbd, const char *path)
262 {
263 pid_t pid;
264 struct nbd_attach_data data;
265
266 data.nbd = nbd;
267 data.path = path;
268
269 pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);
270 if (pid < 0)
271 return false;
272
273 return true;
274 }
275
276 static bool nbd_busy(int idx)
277 {
278 char path[100];
279 int ret;
280
281 ret = snprintf(path, 100, "/sys/block/nbd%d/pid", idx);
282 if (ret < 0 || ret >= 100)
283 return true;
284
285 return file_exists(path);
286 }
287
288 static void nbd_detach(const char *path)
289 {
290 int ret;
291 pid_t pid = fork();
292
293 if (pid < 0) {
294 SYSERROR("Error forking to detach nbd");
295 return;
296 }
297
298 if (pid) {
299 ret = wait_for_pid(pid);
300 if (ret < 0)
301 ERROR("nbd disconnect returned an error");
302 return;
303 }
304
305 execlp("qemu-nbd", "qemu-nbd", "-d", path, (char *)NULL);
306 SYSERROR("Error executing qemu-nbd");
307 _exit(EXIT_FAILURE);
308 }
309
310 /*
311 * Pick the partition # off the end of a nbd:file:p
312 * description. Return 1-9 for the partition id, or 0
313 * for no partition.
314 */
315 static int nbd_get_partition(const char *src)
316 {
317 char *p = strchr(src, ':');
318 if (!p)
319 return 0;
320
321 p = strchr(p+1, ':');
322 if (!p)
323 return 0;
324
325 p++;
326
327 if (*p < '1' || *p > '9')
328 return 0;
329
330 return *p - '0';
331 }
332
333 static bool wait_for_partition(const char *path)
334 {
335 int count = 0;
336
337 while (count < 5) {
338 if (file_exists(path))
339 return true;
340
341 sleep(1);
342 count++;
343 }
344
345 ERROR("Device %s did not show up after 5 seconds", path);
346 return false;
347 }