Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/geom/multipath/geom_multipath.c
34862 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2006 Mathew Jacob <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <errno.h>
31
#include <paths.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <stdint.h>
35
#include <string.h>
36
#include <strings.h>
37
#include <assert.h>
38
#include <libgeom.h>
39
#include <unistd.h>
40
#include <uuid.h>
41
#include <geom/multipath/g_multipath.h>
42
43
#include "core/geom.h"
44
#include "misc/subr.h"
45
46
uint32_t lib_version = G_LIB_VERSION;
47
uint32_t version = G_MULTIPATH_VERSION;
48
49
static void mp_main(struct gctl_req *, unsigned int);
50
static void mp_label(struct gctl_req *);
51
static void mp_clear(struct gctl_req *);
52
static void mp_prefer(struct gctl_req *);
53
54
struct g_command class_commands[] = {
55
{
56
"create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
57
{
58
{ 'A', "active_active", NULL, G_TYPE_BOOL },
59
{ 'R', "active_read", NULL, G_TYPE_BOOL },
60
G_OPT_SENTINEL
61
},
62
"[-vAR] name prov ..."
63
},
64
{
65
"label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, mp_main,
66
{
67
{ 'A', "active_active", NULL, G_TYPE_BOOL },
68
{ 'R', "active_read", NULL, G_TYPE_BOOL },
69
G_OPT_SENTINEL
70
},
71
"[-vAR] name prov ..."
72
},
73
{ "configure", G_FLAG_VERBOSE, NULL,
74
{
75
{ 'A', "active_active", NULL, G_TYPE_BOOL },
76
{ 'P', "active_passive", NULL, G_TYPE_BOOL },
77
{ 'R', "active_read", NULL, G_TYPE_BOOL },
78
G_OPT_SENTINEL
79
},
80
"[-vAPR] name"
81
},
82
{
83
"add", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
84
"[-v] name prov"
85
},
86
{
87
"remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
88
"[-v] name prov"
89
},
90
{
91
"prefer", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,
92
"[-v] prov ..."
93
},
94
{
95
"fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
96
"[-v] name prov"
97
},
98
{
99
"restore", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
100
"[-v] name prov"
101
},
102
{
103
"rotate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
104
"[-v] name"
105
},
106
{
107
"getactive", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
108
"[-v] name"
109
},
110
{
111
"destroy", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
112
"[-v] name"
113
},
114
{
115
"stop", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
116
"[-v] name"
117
},
118
{
119
"clear", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,
120
"[-v] prov ..."
121
},
122
G_CMD_SENTINEL
123
};
124
125
static void
126
mp_main(struct gctl_req *req, unsigned int flags __unused)
127
{
128
const char *name;
129
130
name = gctl_get_ascii(req, "verb");
131
if (name == NULL) {
132
gctl_error(req, "No '%s' argument.", "verb");
133
return;
134
}
135
if (strcmp(name, "label") == 0) {
136
mp_label(req);
137
} else if (strcmp(name, "clear") == 0) {
138
mp_clear(req);
139
} else if (strcmp(name, "prefer") == 0) {
140
mp_prefer(req);
141
} else {
142
gctl_error(req, "Unknown command: %s.", name);
143
}
144
}
145
146
static void
147
mp_label(struct gctl_req *req)
148
{
149
struct g_multipath_metadata md;
150
off_t disksize = 0, msize;
151
uint8_t *sector, *rsector;
152
char *ptr;
153
uuid_t uuid;
154
ssize_t secsize = 0, ssize;
155
uint32_t status;
156
const char *name, *name2, *mpname;
157
int error, i, nargs, fd;
158
159
nargs = gctl_get_int(req, "nargs");
160
if (nargs < 2) {
161
gctl_error(req, "wrong number of arguments.");
162
return;
163
}
164
165
/*
166
* First, check each provider to make sure it's the same size.
167
* This also gets us our size and sectorsize for the metadata.
168
*/
169
for (i = 1; i < nargs; i++) {
170
name = gctl_get_ascii(req, "arg%d", i);
171
msize = g_get_mediasize(name);
172
ssize = g_get_sectorsize(name);
173
if (msize == 0 || ssize == 0) {
174
gctl_error(req, "cannot get information about %s: %s.",
175
name, strerror(errno));
176
return;
177
}
178
if (i == 1) {
179
secsize = ssize;
180
disksize = msize;
181
} else {
182
if (secsize != ssize) {
183
gctl_error(req, "%s sector size %ju different.",
184
name, (intmax_t)ssize);
185
return;
186
}
187
if (disksize != msize) {
188
gctl_error(req, "%s media size %ju different.",
189
name, (intmax_t)msize);
190
return;
191
}
192
}
193
194
}
195
196
/*
197
* Generate metadata.
198
*/
199
strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
200
md.md_version = G_MULTIPATH_VERSION;
201
mpname = gctl_get_ascii(req, "arg0");
202
strlcpy(md.md_name, mpname, sizeof(md.md_name));
203
md.md_size = disksize;
204
md.md_sectorsize = secsize;
205
uuid_create(&uuid, &status);
206
if (status != uuid_s_ok) {
207
gctl_error(req, "cannot create a UUID.");
208
return;
209
}
210
uuid_to_string(&uuid, &ptr, &status);
211
if (status != uuid_s_ok) {
212
gctl_error(req, "cannot stringify a UUID.");
213
return;
214
}
215
strlcpy(md.md_uuid, ptr, sizeof (md.md_uuid));
216
md.md_active_active = gctl_get_int(req, "active_active");
217
if (gctl_get_int(req, "active_read"))
218
md.md_active_active = 2;
219
free(ptr);
220
221
/*
222
* Allocate a sector to write as metadata.
223
*/
224
sector = calloc(1, secsize);
225
if (sector == NULL) {
226
gctl_error(req, "unable to allocate metadata buffer");
227
return;
228
}
229
rsector = malloc(secsize);
230
if (rsector == NULL) {
231
gctl_error(req, "unable to allocate metadata buffer");
232
goto done;
233
}
234
235
/*
236
* encode the metadata
237
*/
238
multipath_metadata_encode(&md, sector);
239
240
/*
241
* Store metadata on the initial provider.
242
*/
243
name = gctl_get_ascii(req, "arg1");
244
error = g_metadata_store(name, sector, secsize);
245
if (error != 0) {
246
gctl_error(req, "cannot store metadata on %s: %s.", name, strerror(error));
247
goto done;
248
}
249
250
/*
251
* Now touch the rest of the providers to hint retaste.
252
*/
253
for (i = 2; i < nargs; i++) {
254
name2 = gctl_get_ascii(req, "arg%d", i);
255
fd = g_open(name2, 1);
256
if (fd < 0) {
257
fprintf(stderr, "Unable to open %s: %s.\n",
258
name2, strerror(errno));
259
continue;
260
}
261
if (pread(fd, rsector, secsize, disksize - secsize) !=
262
(ssize_t)secsize) {
263
fprintf(stderr, "Unable to read metadata from %s: %s.\n",
264
name2, strerror(errno));
265
g_close(fd);
266
continue;
267
}
268
g_close(fd);
269
if (memcmp(sector, rsector, secsize)) {
270
fprintf(stderr, "No metadata found on %s."
271
" It is not a path of %s.\n",
272
name2, name);
273
}
274
}
275
done:
276
free(rsector);
277
free(sector);
278
}
279
280
281
static void
282
mp_clear(struct gctl_req *req)
283
{
284
const char *name;
285
int error, i, nargs;
286
287
nargs = gctl_get_int(req, "nargs");
288
if (nargs < 1) {
289
gctl_error(req, "Too few arguments.");
290
return;
291
}
292
293
for (i = 0; i < nargs; i++) {
294
name = gctl_get_ascii(req, "arg%d", i);
295
error = g_metadata_clear(name, G_MULTIPATH_MAGIC);
296
if (error != 0) {
297
fprintf(stderr, "Can't clear metadata on %s: %s.\n",
298
name, strerror(error));
299
gctl_error(req, "Not fully done.");
300
continue;
301
}
302
}
303
}
304
305
static void
306
mp_prefer(struct gctl_req *req)
307
{
308
const char *name, *comp, *errstr;
309
int nargs;
310
311
nargs = gctl_get_int(req, "nargs");
312
if (nargs != 2) {
313
gctl_error(req, "Usage: prefer GEOM PROVIDER");
314
return;
315
}
316
name = gctl_get_ascii(req, "arg0");
317
comp = gctl_get_ascii(req, "arg1");
318
errstr = gctl_issue (req);
319
if (errstr != NULL) {
320
fprintf(stderr, "Can't set %s preferred provider to %s: %s.\n",
321
name, comp, errstr);
322
}
323
}
324
325