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