]>
Commit | Line | Data |
---|---|---|
cc73685d | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
3ceb2820 | 2 | |
d38dd64a CB |
3 | #ifndef _GNU_SOURCE |
4 | #define _GNU_SOURCE 1 | |
5 | #endif | |
3ceb2820 | 6 | #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ |
7b22b3e9 | 7 | #include <inttypes.h> /* Required for PRIu64 to work. */ |
3ceb2820 CB |
8 | #include <stdint.h> |
9 | #include <stdio.h> | |
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
12 | ||
d38dd64a | 13 | #include "config.h" |
3ceb2820 | 14 | #include "log.h" |
32068050 | 15 | #include "memory_utils.h" |
28d832c4 | 16 | #include "storage.h" |
f2d5a09d | 17 | #include "storage_utils.h" |
3ceb2820 CB |
18 | #include "utils.h" |
19 | ||
43f984ea | 20 | #ifndef HAVE_STRLCPY |
58db1a61 | 21 | #include "strlcpy.h" |
43f984ea DJ |
22 | #endif |
23 | ||
10bc1861 | 24 | lxc_log_define(rbd, lxc); |
3ceb2820 | 25 | |
3b0e906f CB |
26 | struct rbd_args { |
27 | const char *osd_pool_name; | |
28 | const char *rbd_name; | |
29 | const char *size; | |
30 | }; | |
31 | ||
59eac805 | 32 | static int rbd_create_wrapper(void *data) |
3b0e906f CB |
33 | { |
34 | struct rbd_args *args = data; | |
35 | ||
36 | execlp("rbd", "rbd", "create", "--pool", args->osd_pool_name, | |
37 | args->rbd_name, "--size", args->size, (char *)NULL); | |
38 | ||
39 | return -1; | |
40 | } | |
41 | ||
59eac805 | 42 | static int rbd_map_wrapper(void *data) |
3b0e906f CB |
43 | { |
44 | struct rbd_args *args = data; | |
45 | ||
46 | execlp("rbd", "rbd", "map", "--pool", args->osd_pool_name, | |
47 | args->rbd_name, (char *)NULL); | |
48 | ||
49 | return -1; | |
50 | } | |
51 | ||
59eac805 | 52 | static int rbd_unmap_wrapper(void *data) |
3b0e906f CB |
53 | { |
54 | struct rbd_args *args = data; | |
55 | ||
56 | execlp("rbd", "rbd", "unmap", args->rbd_name, (char *)NULL); | |
57 | ||
58 | return -1; | |
59 | } | |
60 | ||
59eac805 | 61 | static int rbd_delete_wrapper(void *data) |
3b0e906f CB |
62 | { |
63 | struct rbd_args *args = data; | |
64 | ||
65 | execlp("rbd", "rbd", "rm", args->rbd_name, (char *)NULL); | |
66 | ||
67 | return -1; | |
68 | } | |
69 | ||
10bc1861 CB |
70 | int rbd_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, |
71 | const char *oldname, const char *cname, const char *oldpath, | |
72 | const char *lxcpath, int snap, uint64_t newsize, | |
73 | struct lxc_conf *conf) | |
3ceb2820 CB |
74 | { |
75 | ERROR("rbd clonepaths not implemented"); | |
76 | return -1; | |
77 | } | |
78 | ||
10bc1861 | 79 | int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n, |
facdf925 | 80 | struct bdev_specs *specs, const struct lxc_conf *conf) |
3ceb2820 | 81 | { |
3b0e906f | 82 | const char *rbdpool, *fstype; |
3ceb2820 CB |
83 | uint64_t size; |
84 | int ret, len; | |
85 | char sz[24]; | |
a5b18cb1 | 86 | const char *cmd_args[2]; |
339de297 | 87 | char cmd_output[PATH_MAX]; |
3b0e906f CB |
88 | const char *rbdname = n; |
89 | struct rbd_args args = {0}; | |
3ceb2820 CB |
90 | |
91 | if (!specs) | |
92 | return -1; | |
93 | ||
94 | rbdpool = specs->rbd.rbdpool; | |
95 | if (!rbdpool) | |
96 | rbdpool = lxc_global_config_value("lxc.bdev.rbd.rbdpool"); | |
97 | ||
98 | if (specs->rbd.rbdname) | |
99 | rbdname = specs->rbd.rbdname; | |
100 | ||
101 | /* source device /dev/rbd/lxc/ctn */ | |
43bd0ebf | 102 | len = strlen(rbdpool) + strlen(rbdname) + 4 + 11; |
3ceb2820 | 103 | bdev->src = malloc(len); |
3b0e906f CB |
104 | if (!bdev->src) { |
105 | ERROR("Failed to allocate memory"); | |
3ceb2820 | 106 | return -1; |
3b0e906f | 107 | } |
3ceb2820 | 108 | |
43bd0ebf | 109 | ret = snprintf(bdev->src, len, "rbd:/dev/rbd/%s/%s", rbdpool, rbdname); |
3b0e906f CB |
110 | if (ret < 0 || ret >= len) { |
111 | ERROR("Failed to create string"); | |
3ceb2820 | 112 | return -1; |
3b0e906f | 113 | } |
3ceb2820 | 114 | |
7b22b3e9 | 115 | /* fssize is in bytes */ |
3ceb2820 CB |
116 | size = specs->fssize; |
117 | if (!size) | |
118 | size = DEFAULT_FS_SIZE; | |
119 | ||
7b22b3e9 CB |
120 | /* in megabytes for rbd tool */ |
121 | ret = snprintf(sz, 24, "%" PRIu64, size / 1024 / 1024); | |
3b0e906f CB |
122 | if (ret < 0 || ret >= 24) { |
123 | ERROR("Failed to create string"); | |
3ceb2820 | 124 | return -1; |
3ceb2820 | 125 | } |
3ceb2820 | 126 | |
3b0e906f CB |
127 | args.osd_pool_name = rbdpool; |
128 | args.rbd_name = rbdname; | |
129 | args.size = sz; | |
130 | ret = run_command(cmd_output, sizeof(cmd_output), rbd_create_wrapper, | |
131 | (void *)&args); | |
132 | if (ret < 0) { | |
133 | ERROR("Failed to create rbd storage volume \"%s\": %s", rbdname, | |
134 | cmd_output); | |
3ceb2820 | 135 | return -1; |
3ceb2820 | 136 | } |
3b0e906f CB |
137 | |
138 | ret = run_command(cmd_output, sizeof(cmd_output), rbd_map_wrapper, | |
139 | (void *)&args); | |
140 | if (ret < 0) { | |
141 | ERROR("Failed to map rbd storage volume \"%s\": %s", rbdname, | |
142 | cmd_output); | |
3ceb2820 | 143 | return -1; |
3b0e906f | 144 | } |
3ceb2820 CB |
145 | |
146 | fstype = specs->fstype; | |
147 | if (!fstype) | |
148 | fstype = DEFAULT_FSTYPE; | |
149 | ||
a5b18cb1 | 150 | cmd_args[0] = fstype; |
3b0e906f | 151 | cmd_args[1] = lxc_storage_get_path(bdev->src, bdev->type); |
a5b18cb1 CB |
152 | ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper, |
153 | (void *)cmd_args); | |
3b0e906f CB |
154 | if (ret < 0) { |
155 | ERROR("Failed to map rbd storage volume \"%s\": %s", rbdname, | |
156 | cmd_output); | |
3ceb2820 | 157 | return -1; |
3b0e906f | 158 | } |
a5b18cb1 | 159 | |
3b0e906f CB |
160 | bdev->dest = strdup(dest); |
161 | if (!bdev->dest) { | |
162 | ERROR("Failed to duplicate string \"%s\"", dest); | |
3ceb2820 | 163 | return -1; |
3b0e906f | 164 | } |
3ceb2820 | 165 | |
3b0e906f CB |
166 | ret = mkdir_p(bdev->dest, 0755); |
167 | if (ret < 0 && errno != EEXIST) { | |
168 | ERROR("Failed to create directory \"%s\"", bdev->dest); | |
3ceb2820 CB |
169 | return -1; |
170 | } | |
171 | ||
3b0e906f | 172 | TRACE("Created rbd storage volume \"%s\"", bdev->dest); |
3ceb2820 CB |
173 | return 0; |
174 | } | |
175 | ||
10bc1861 | 176 | int rbd_destroy(struct lxc_storage *orig) |
3ceb2820 | 177 | { |
32068050 | 178 | __do_free char *rbdfullname = NULL; |
3b0e906f | 179 | int ret; |
41dc7155 | 180 | const char *src; |
339de297 | 181 | char cmd_output[PATH_MAX]; |
3b0e906f | 182 | struct rbd_args args = {0}; |
43f984ea | 183 | size_t len; |
3ceb2820 | 184 | |
43bd0ebf CB |
185 | src = lxc_storage_get_path(orig->src, orig->type); |
186 | if (file_exists(src)) { | |
3b0e906f CB |
187 | args.rbd_name = src; |
188 | ret = run_command(cmd_output, sizeof(cmd_output), | |
189 | rbd_unmap_wrapper, (void *)&args); | |
190 | if (ret < 0) { | |
191 | ERROR("Failed to map rbd storage volume \"%s\": %s", | |
192 | src, cmd_output); | |
3ceb2820 | 193 | return -1; |
3ceb2820 | 194 | } |
3ceb2820 CB |
195 | } |
196 | ||
43f984ea | 197 | len = strlen(src); |
32068050 | 198 | rbdfullname = must_realloc(NULL, len - 8); |
43f984ea | 199 | (void)strlcpy(rbdfullname, &src[9], len - 8); |
3b0e906f | 200 | args.rbd_name = rbdfullname; |
43f984ea | 201 | |
3b0e906f CB |
202 | ret = run_command(cmd_output, sizeof(cmd_output), |
203 | rbd_delete_wrapper, (void *)&args); | |
204 | if (ret < 0) { | |
205 | ERROR("Failed to delete rbd storage volume \"%s\": %s", | |
206 | rbdfullname, cmd_output); | |
3ceb2820 | 207 | return -1; |
3ceb2820 | 208 | } |
3b0e906f CB |
209 | |
210 | return 0; | |
3ceb2820 CB |
211 | } |
212 | ||
3d2ae1e2 | 213 | bool rbd_detect(const char *path) |
3ceb2820 | 214 | { |
f7ac4459 | 215 | if (!strncmp(path, "rbd:", 4)) |
3d2ae1e2 | 216 | return true; |
f7ac4459 CB |
217 | |
218 | if (!strncmp(path, "/dev/rbd/", 9)) | |
3d2ae1e2 | 219 | return true; |
f7ac4459 | 220 | |
3d2ae1e2 | 221 | return false; |
3ceb2820 CB |
222 | } |
223 | ||
10bc1861 | 224 | int rbd_mount(struct lxc_storage *bdev) |
3ceb2820 | 225 | { |
41dc7155 | 226 | const char *src; |
3b0e906f | 227 | |
3ceb2820 CB |
228 | if (strcmp(bdev->type, "rbd")) |
229 | return -22; | |
43bd0ebf | 230 | |
3ceb2820 CB |
231 | if (!bdev->src || !bdev->dest) |
232 | return -22; | |
233 | ||
43bd0ebf CB |
234 | src = lxc_storage_get_path(bdev->src, bdev->type); |
235 | if (!file_exists(src)) { | |
7b22b3e9 CB |
236 | /* If blkdev does not exist it should be mapped, because it is |
237 | * not persistent on reboot. | |
238 | */ | |
3ceb2820 CB |
239 | ERROR("Block device %s is not mapped.", bdev->src); |
240 | return -1; | |
241 | } | |
242 | ||
3b0e906f | 243 | return mount_unknown_fs(src, bdev->dest, bdev->mntopts); |
3ceb2820 CB |
244 | } |
245 | ||
10bc1861 | 246 | int rbd_umount(struct lxc_storage *bdev) |
3ceb2820 CB |
247 | { |
248 | if (strcmp(bdev->type, "rbd")) | |
249 | return -22; | |
43bd0ebf | 250 | |
3ceb2820 CB |
251 | if (!bdev->src || !bdev->dest) |
252 | return -22; | |
43bd0ebf | 253 | |
3ceb2820 CB |
254 | return umount(bdev->dest); |
255 | } |