1fa4a1febSPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
4b740e905SPawel Jakub Dawidek * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5fa4a1febSPawel Jakub Dawidek * All rights reserved.
6fa4a1febSPawel Jakub Dawidek *
7fa4a1febSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without
8fa4a1febSPawel Jakub Dawidek * modification, are permitted provided that the following conditions
9fa4a1febSPawel Jakub Dawidek * are met:
10fa4a1febSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright
11fa4a1febSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer.
12fa4a1febSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright
13fa4a1febSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the
14fa4a1febSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution.
15fa4a1febSPawel Jakub Dawidek *
16fa4a1febSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17fa4a1febSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18fa4a1febSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19fa4a1febSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20fa4a1febSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21fa4a1febSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22fa4a1febSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fa4a1febSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24fa4a1febSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fa4a1febSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fa4a1febSPawel Jakub Dawidek * SUCH DAMAGE.
27fa4a1febSPawel Jakub Dawidek */
28fa4a1febSPawel Jakub Dawidek
29fa4a1febSPawel Jakub Dawidek #include <sys/param.h>
30fa4a1febSPawel Jakub Dawidek #include <sys/systm.h>
318b0a00b7SMark Johnston #include <sys/bio.h>
32fa4a1febSPawel Jakub Dawidek #include <sys/kernel.h>
3332cea4caSAndrey V. Elsukov #include <sys/limits.h>
34fa4a1febSPawel Jakub Dawidek #include <sys/lock.h>
35fa4a1febSPawel Jakub Dawidek #include <sys/malloc.h>
368b0a00b7SMark Johnston #include <sys/sbuf.h>
378b0a00b7SMark Johnston #include <sys/sx.h>
388b0a00b7SMark Johnston
39fa4a1febSPawel Jakub Dawidek #include <geom/geom.h>
40ac03832eSConrad Meyer #include <geom/geom_dbg.h>
4132cea4caSAndrey V. Elsukov #include <geom/geom_int.h>
42fa4a1febSPawel Jakub Dawidek #include <geom/mirror/g_mirror.h>
43fa4a1febSPawel Jakub Dawidek
44844b743dSConrad Meyer /*
45844b743dSConrad Meyer * Configure, Rebuild, Remove, Deactivate, Forget, and Stop operations do not
46844b743dSConrad Meyer * seem to depend on any particular g_mirror initialization state.
47844b743dSConrad Meyer */
48fa4a1febSPawel Jakub Dawidek static struct g_mirror_softc *
g_mirror_find_device(struct g_class * mp,const char * name)49fa4a1febSPawel Jakub Dawidek g_mirror_find_device(struct g_class *mp, const char *name)
50fa4a1febSPawel Jakub Dawidek {
51fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
52fa4a1febSPawel Jakub Dawidek struct g_geom *gp;
53fa4a1febSPawel Jakub Dawidek
54855761d5SPawel Jakub Dawidek g_topology_lock();
55fa4a1febSPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) {
56fa4a1febSPawel Jakub Dawidek sc = gp->softc;
57fa4a1febSPawel Jakub Dawidek if (sc == NULL)
58fa4a1febSPawel Jakub Dawidek continue;
59fa4a1febSPawel Jakub Dawidek if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0)
60fa4a1febSPawel Jakub Dawidek continue;
61fa4a1febSPawel Jakub Dawidek if (strcmp(gp->name, name) == 0 ||
62fa4a1febSPawel Jakub Dawidek strcmp(sc->sc_name, name) == 0) {
63855761d5SPawel Jakub Dawidek g_topology_unlock();
64855761d5SPawel Jakub Dawidek sx_xlock(&sc->sc_lock);
65844b743dSConrad Meyer if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
66844b743dSConrad Meyer sx_xunlock(&sc->sc_lock);
67844b743dSConrad Meyer return (NULL);
68844b743dSConrad Meyer }
69fa4a1febSPawel Jakub Dawidek return (sc);
70fa4a1febSPawel Jakub Dawidek }
71fa4a1febSPawel Jakub Dawidek }
72855761d5SPawel Jakub Dawidek g_topology_unlock();
73fa4a1febSPawel Jakub Dawidek return (NULL);
74fa4a1febSPawel Jakub Dawidek }
75fa4a1febSPawel Jakub Dawidek
76844b743dSConrad Meyer /* Insert and Resize operations depend on a launched GEOM (sc_provider). */
77844b743dSConrad Meyer #define GMFL_VALID_FLAGS (M_WAITOK | M_NOWAIT)
78844b743dSConrad Meyer static struct g_mirror_softc *
g_mirror_find_launched_device(struct g_class * mp,const char * name,int flags)79844b743dSConrad Meyer g_mirror_find_launched_device(struct g_class *mp, const char *name, int flags)
80844b743dSConrad Meyer {
81844b743dSConrad Meyer struct g_mirror_softc *sc;
82844b743dSConrad Meyer int error;
83844b743dSConrad Meyer
84844b743dSConrad Meyer KASSERT((flags & ~GMFL_VALID_FLAGS) == 0 &&
85844b743dSConrad Meyer flags != GMFL_VALID_FLAGS && flags != 0,
86844b743dSConrad Meyer ("%s: Invalid flags %x\n", __func__, (unsigned)flags));
87844b743dSConrad Meyer #undef GMFL_VALID_FLAGS
88844b743dSConrad Meyer
89844b743dSConrad Meyer while (true) {
90844b743dSConrad Meyer sc = g_mirror_find_device(mp, name);
91844b743dSConrad Meyer if (sc == NULL)
92844b743dSConrad Meyer return (NULL);
93844b743dSConrad Meyer if (sc->sc_provider != NULL)
94844b743dSConrad Meyer return (sc);
95844b743dSConrad Meyer if (flags & M_NOWAIT) {
96844b743dSConrad Meyer sx_xunlock(&sc->sc_lock);
97844b743dSConrad Meyer return (NULL);
98844b743dSConrad Meyer }
99844b743dSConrad Meyer
100844b743dSConrad Meyer /*
101844b743dSConrad Meyer * This is a dumb hack. G_mirror does not expose any real
102844b743dSConrad Meyer * wakeup API for observing state changes, and even if it did,
103844b743dSConrad Meyer * its "RUNNING" state does not actually reflect all softc
104844b743dSConrad Meyer * elements being initialized.
105844b743dSConrad Meyer *
106844b743dSConrad Meyer * Revamping g_mirror to have a 3rd, ACTUALLY_RUNNING state and
107844b743dSConrad Meyer * updating all assertions and sc_state checks is a large work
108844b743dSConrad Meyer * and would be easy to introduce regressions.
109844b743dSConrad Meyer *
110844b743dSConrad Meyer * Revamping g_mirror to have a wakeup for state changes would
111844b743dSConrad Meyer * be difficult if one wanted to capture more than just
112844b743dSConrad Meyer * sc_state and sc_provider.
113844b743dSConrad Meyer *
114844b743dSConrad Meyer * For now, just dummy sleep-poll until sc_provider shows up,
115844b743dSConrad Meyer * the user cancels, or the g_mirror is destroyed.
116844b743dSConrad Meyer */
117844b743dSConrad Meyer error = sx_sleep(&sc, &sc->sc_lock, PRIBIO | PCATCH | PDROP,
118844b743dSConrad Meyer "GM:launched", 1);
119844b743dSConrad Meyer if (error != 0 && error != EWOULDBLOCK)
120844b743dSConrad Meyer return (NULL);
121844b743dSConrad Meyer }
122844b743dSConrad Meyer __unreachable();
123844b743dSConrad Meyer }
124844b743dSConrad Meyer
125fa4a1febSPawel Jakub Dawidek static struct g_mirror_disk *
g_mirror_find_disk(struct g_mirror_softc * sc,const char * name)126fa4a1febSPawel Jakub Dawidek g_mirror_find_disk(struct g_mirror_softc *sc, const char *name)
127fa4a1febSPawel Jakub Dawidek {
128fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
129fa4a1febSPawel Jakub Dawidek
130855761d5SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED);
1318510f61aSXin LI if (strncmp(name, _PATH_DEV, 5) == 0)
13286ed3c25SPawel Jakub Dawidek name += 5;
133fa4a1febSPawel Jakub Dawidek LIST_FOREACH(disk, &sc->sc_disks, d_next) {
134fa4a1febSPawel Jakub Dawidek if (disk->d_consumer == NULL)
135fa4a1febSPawel Jakub Dawidek continue;
136fa4a1febSPawel Jakub Dawidek if (disk->d_consumer->provider == NULL)
137fa4a1febSPawel Jakub Dawidek continue;
138fa4a1febSPawel Jakub Dawidek if (strcmp(disk->d_consumer->provider->name, name) == 0)
139fa4a1febSPawel Jakub Dawidek return (disk);
140fa4a1febSPawel Jakub Dawidek }
141fa4a1febSPawel Jakub Dawidek return (NULL);
142fa4a1febSPawel Jakub Dawidek }
143fa4a1febSPawel Jakub Dawidek
144fa4a1febSPawel Jakub Dawidek static void
g_mirror_ctl_configure(struct gctl_req * req,struct g_class * mp)145fa4a1febSPawel Jakub Dawidek g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp)
146fa4a1febSPawel Jakub Dawidek {
147fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
148fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
149b740e905SPawel Jakub Dawidek const char *name, *balancep, *prov;
150b740e905SPawel Jakub Dawidek intmax_t *slicep, *priority;
151fa4a1febSPawel Jakub Dawidek uint32_t slice;
152fa4a1febSPawel Jakub Dawidek uint8_t balance;
153501250baSPawel Jakub Dawidek int *autosync, *noautosync, *failsync, *nofailsync, *hardcode, *dynamic;
154b740e905SPawel Jakub Dawidek int *nargs, do_sync = 0, dirty = 1, do_priority = 0;
155fa4a1febSPawel Jakub Dawidek
156fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
157cc6aa917SPawel Jakub Dawidek if (nargs == NULL) {
158cc6aa917SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
159cc6aa917SPawel Jakub Dawidek return;
160cc6aa917SPawel Jakub Dawidek }
161b740e905SPawel Jakub Dawidek if (*nargs != 1 && *nargs != 2) {
162fa4a1febSPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments.");
163fa4a1febSPawel Jakub Dawidek return;
164fa4a1febSPawel Jakub Dawidek }
165fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0");
166cc6aa917SPawel Jakub Dawidek if (name == NULL) {
167cc6aa917SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0);
168cc6aa917SPawel Jakub Dawidek return;
169cc6aa917SPawel Jakub Dawidek }
170fa4a1febSPawel Jakub Dawidek balancep = gctl_get_asciiparam(req, "balance");
171cc6aa917SPawel Jakub Dawidek if (balancep == NULL) {
172cc6aa917SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "balance");
173cc6aa917SPawel Jakub Dawidek return;
174cc6aa917SPawel Jakub Dawidek }
175fa4a1febSPawel Jakub Dawidek autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
176fa4a1febSPawel Jakub Dawidek if (autosync == NULL) {
177fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "autosync");
178fa4a1febSPawel Jakub Dawidek return;
179fa4a1febSPawel Jakub Dawidek }
180fa4a1febSPawel Jakub Dawidek noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
181fa4a1febSPawel Jakub Dawidek if (noautosync == NULL) {
182fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "noautosync");
183fa4a1febSPawel Jakub Dawidek return;
184fa4a1febSPawel Jakub Dawidek }
185501250baSPawel Jakub Dawidek failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync));
186501250baSPawel Jakub Dawidek if (failsync == NULL) {
187501250baSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "failsync");
188501250baSPawel Jakub Dawidek return;
189501250baSPawel Jakub Dawidek }
190501250baSPawel Jakub Dawidek nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync));
191501250baSPawel Jakub Dawidek if (nofailsync == NULL) {
192501250baSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nofailsync");
193501250baSPawel Jakub Dawidek return;
194501250baSPawel Jakub Dawidek }
195c38d2f4eSPawel Jakub Dawidek hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
196c38d2f4eSPawel Jakub Dawidek if (hardcode == NULL) {
197c38d2f4eSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "hardcode");
198c38d2f4eSPawel Jakub Dawidek return;
199c38d2f4eSPawel Jakub Dawidek }
200c38d2f4eSPawel Jakub Dawidek dynamic = gctl_get_paraml(req, "dynamic", sizeof(*dynamic));
201c38d2f4eSPawel Jakub Dawidek if (dynamic == NULL) {
202c38d2f4eSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "dynamic");
203c38d2f4eSPawel Jakub Dawidek return;
204c38d2f4eSPawel Jakub Dawidek }
205b740e905SPawel Jakub Dawidek priority = gctl_get_paraml(req, "priority", sizeof(*priority));
206b740e905SPawel Jakub Dawidek if (priority == NULL) {
207b740e905SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "priority");
208b740e905SPawel Jakub Dawidek return;
209b740e905SPawel Jakub Dawidek }
210b740e905SPawel Jakub Dawidek if (*priority < -1 || *priority > 255) {
211b740e905SPawel Jakub Dawidek gctl_error(req, "Priority range is 0 to 255, %jd given",
212b740e905SPawel Jakub Dawidek *priority);
213b740e905SPawel Jakub Dawidek return;
214b740e905SPawel Jakub Dawidek }
215b740e905SPawel Jakub Dawidek /*
216b740e905SPawel Jakub Dawidek * Since we have a priority, we also need a provider now.
217b740e905SPawel Jakub Dawidek * Note: be WARNS safe, by always assigning prov and only throw an
218b740e905SPawel Jakub Dawidek * error if *priority != -1.
219b740e905SPawel Jakub Dawidek */
220b740e905SPawel Jakub Dawidek prov = gctl_get_asciiparam(req, "arg1");
221b740e905SPawel Jakub Dawidek if (*priority > -1) {
222b740e905SPawel Jakub Dawidek if (prov == NULL) {
223b740e905SPawel Jakub Dawidek gctl_error(req, "Priority needs a disk name");
224b740e905SPawel Jakub Dawidek return;
225b740e905SPawel Jakub Dawidek }
226b740e905SPawel Jakub Dawidek do_priority = 1;
227b740e905SPawel Jakub Dawidek }
228fa4a1febSPawel Jakub Dawidek if (*autosync && *noautosync) {
229fa4a1febSPawel Jakub Dawidek gctl_error(req, "'%s' and '%s' specified.", "autosync",
230fa4a1febSPawel Jakub Dawidek "noautosync");
231fa4a1febSPawel Jakub Dawidek return;
232fa4a1febSPawel Jakub Dawidek }
233501250baSPawel Jakub Dawidek if (*failsync && *nofailsync) {
234501250baSPawel Jakub Dawidek gctl_error(req, "'%s' and '%s' specified.", "failsync",
235501250baSPawel Jakub Dawidek "nofailsync");
236501250baSPawel Jakub Dawidek return;
237501250baSPawel Jakub Dawidek }
238c38d2f4eSPawel Jakub Dawidek if (*hardcode && *dynamic) {
239c38d2f4eSPawel Jakub Dawidek gctl_error(req, "'%s' and '%s' specified.", "hardcode",
240c38d2f4eSPawel Jakub Dawidek "dynamic");
241c38d2f4eSPawel Jakub Dawidek return;
242c38d2f4eSPawel Jakub Dawidek }
243855761d5SPawel Jakub Dawidek sc = g_mirror_find_device(mp, name);
244855761d5SPawel Jakub Dawidek if (sc == NULL) {
245855761d5SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
246855761d5SPawel Jakub Dawidek return;
247855761d5SPawel Jakub Dawidek }
248a478ea74SPawel Jakub Dawidek if (*balancep == '\0')
249855761d5SPawel Jakub Dawidek balance = sc->sc_balance;
250855761d5SPawel Jakub Dawidek else {
251855761d5SPawel Jakub Dawidek if (balance_id(balancep) == -1) {
252855761d5SPawel Jakub Dawidek gctl_error(req, "Invalid balance algorithm.");
253855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
254855761d5SPawel Jakub Dawidek return;
255855761d5SPawel Jakub Dawidek }
256855761d5SPawel Jakub Dawidek balance = balance_id(balancep);
257855761d5SPawel Jakub Dawidek }
258855761d5SPawel Jakub Dawidek slicep = gctl_get_paraml(req, "slice", sizeof(*slicep));
259855761d5SPawel Jakub Dawidek if (slicep == NULL) {
260855761d5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "slice");
261855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
262855761d5SPawel Jakub Dawidek return;
263855761d5SPawel Jakub Dawidek }
264855761d5SPawel Jakub Dawidek if (*slicep == -1)
265855761d5SPawel Jakub Dawidek slice = sc->sc_slice;
266855761d5SPawel Jakub Dawidek else
267855761d5SPawel Jakub Dawidek slice = *slicep;
268b740e905SPawel Jakub Dawidek /* Enforce usage() of -p not allowing any other options. */
269b740e905SPawel Jakub Dawidek if (do_priority && (*autosync || *noautosync || *failsync ||
270b740e905SPawel Jakub Dawidek *nofailsync || *hardcode || *dynamic || *slicep != -1 ||
271a478ea74SPawel Jakub Dawidek *balancep != '\0')) {
272855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
273b740e905SPawel Jakub Dawidek gctl_error(req, "only -p accepted when setting priority");
274855761d5SPawel Jakub Dawidek return;
275855761d5SPawel Jakub Dawidek }
276855761d5SPawel Jakub Dawidek if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync &&
277501250baSPawel Jakub Dawidek !*noautosync && !*failsync && !*nofailsync && !*hardcode &&
278b740e905SPawel Jakub Dawidek !*dynamic && !do_priority) {
279855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
280855761d5SPawel Jakub Dawidek gctl_error(req, "Nothing has changed.");
281855761d5SPawel Jakub Dawidek return;
282855761d5SPawel Jakub Dawidek }
283b740e905SPawel Jakub Dawidek if ((!do_priority && *nargs != 1) || (do_priority && *nargs != 2)) {
284b740e905SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
285b740e905SPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments.");
286b740e905SPawel Jakub Dawidek return;
287b740e905SPawel Jakub Dawidek }
288b740e905SPawel Jakub Dawidek if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
289b740e905SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
290b740e905SPawel Jakub Dawidek gctl_error(req, "Not all disks connected. Try 'forget' command "
291b740e905SPawel Jakub Dawidek "first.");
292b740e905SPawel Jakub Dawidek return;
293b740e905SPawel Jakub Dawidek }
294fa4a1febSPawel Jakub Dawidek sc->sc_balance = balance;
295fa4a1febSPawel Jakub Dawidek sc->sc_slice = slice;
296fa4a1febSPawel Jakub Dawidek if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) {
297fa4a1febSPawel Jakub Dawidek if (*autosync) {
298fa4a1febSPawel Jakub Dawidek sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
299fa4a1febSPawel Jakub Dawidek do_sync = 1;
300fa4a1febSPawel Jakub Dawidek }
301fa4a1febSPawel Jakub Dawidek } else {
302fa4a1febSPawel Jakub Dawidek if (*noautosync)
303fa4a1febSPawel Jakub Dawidek sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
304fa4a1febSPawel Jakub Dawidek }
305501250baSPawel Jakub Dawidek if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0) {
306501250baSPawel Jakub Dawidek if (*failsync)
307501250baSPawel Jakub Dawidek sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
308501250baSPawel Jakub Dawidek } else {
309501250baSPawel Jakub Dawidek if (*nofailsync) {
310501250baSPawel Jakub Dawidek sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
311501250baSPawel Jakub Dawidek dirty = 0;
312501250baSPawel Jakub Dawidek }
313501250baSPawel Jakub Dawidek }
314fa4a1febSPawel Jakub Dawidek LIST_FOREACH(disk, &sc->sc_disks, d_next) {
315b740e905SPawel Jakub Dawidek /*
316b740e905SPawel Jakub Dawidek * Handle priority first, since we only need one disk, do one
317b740e905SPawel Jakub Dawidek * operation on it and then we're done. No need to check other
318b740e905SPawel Jakub Dawidek * flags, as usage doesn't allow it.
319b740e905SPawel Jakub Dawidek */
320b740e905SPawel Jakub Dawidek if (do_priority) {
321b740e905SPawel Jakub Dawidek if (strcmp(disk->d_name, prov) == 0) {
322b740e905SPawel Jakub Dawidek if (disk->d_priority == *priority)
323b740e905SPawel Jakub Dawidek gctl_error(req, "Nothing has changed.");
324b740e905SPawel Jakub Dawidek else {
325b740e905SPawel Jakub Dawidek disk->d_priority = *priority;
326b740e905SPawel Jakub Dawidek g_mirror_update_metadata(disk);
327b740e905SPawel Jakub Dawidek }
328b740e905SPawel Jakub Dawidek break;
329b740e905SPawel Jakub Dawidek }
330b740e905SPawel Jakub Dawidek continue;
331b740e905SPawel Jakub Dawidek }
332fa4a1febSPawel Jakub Dawidek if (do_sync) {
333fa4a1febSPawel Jakub Dawidek if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING)
334fa4a1febSPawel Jakub Dawidek disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
335fa4a1febSPawel Jakub Dawidek }
336c38d2f4eSPawel Jakub Dawidek if (*hardcode)
337c38d2f4eSPawel Jakub Dawidek disk->d_flags |= G_MIRROR_DISK_FLAG_HARDCODED;
338c38d2f4eSPawel Jakub Dawidek else if (*dynamic)
339c38d2f4eSPawel Jakub Dawidek disk->d_flags &= ~G_MIRROR_DISK_FLAG_HARDCODED;
340501250baSPawel Jakub Dawidek if (!dirty)
341501250baSPawel Jakub Dawidek disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
342fa4a1febSPawel Jakub Dawidek g_mirror_update_metadata(disk);
343fa4a1febSPawel Jakub Dawidek if (do_sync) {
344fa4a1febSPawel Jakub Dawidek if (disk->d_state == G_MIRROR_DISK_STATE_STALE) {
345fa4a1febSPawel Jakub Dawidek g_mirror_event_send(disk,
346fa4a1febSPawel Jakub Dawidek G_MIRROR_DISK_STATE_DISCONNECTED,
347fa4a1febSPawel Jakub Dawidek G_MIRROR_EVENT_DONTWAIT);
348fa4a1febSPawel Jakub Dawidek }
349fa4a1febSPawel Jakub Dawidek }
350fa4a1febSPawel Jakub Dawidek }
351855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
352fa4a1febSPawel Jakub Dawidek }
353fa4a1febSPawel Jakub Dawidek
354fa4a1febSPawel Jakub Dawidek static void
g_mirror_create_orphan(struct g_consumer * cp)355b6fe583cSAlexander Motin g_mirror_create_orphan(struct g_consumer *cp)
356b6fe583cSAlexander Motin {
357b6fe583cSAlexander Motin
358b6fe583cSAlexander Motin KASSERT(1 == 0, ("%s called while creating %s.", __func__,
359b6fe583cSAlexander Motin cp->provider->name));
360b6fe583cSAlexander Motin }
361b6fe583cSAlexander Motin
362b6fe583cSAlexander Motin static void
g_mirror_ctl_create(struct gctl_req * req,struct g_class * mp)363b6fe583cSAlexander Motin g_mirror_ctl_create(struct gctl_req *req, struct g_class *mp)
364b6fe583cSAlexander Motin {
365b6fe583cSAlexander Motin struct g_mirror_metadata md;
366b6fe583cSAlexander Motin struct g_geom *gp;
367b6fe583cSAlexander Motin struct g_consumer *cp;
368b6fe583cSAlexander Motin struct g_provider *pp;
369b6fe583cSAlexander Motin struct g_mirror_softc *sc;
370b6fe583cSAlexander Motin struct sbuf *sb;
371b6fe583cSAlexander Motin const char *name;
372b6fe583cSAlexander Motin char param[16];
373b6fe583cSAlexander Motin int *nargs;
374b6fe583cSAlexander Motin intmax_t *val;
375b6fe583cSAlexander Motin int *ival;
376b6fe583cSAlexander Motin const char *sval;
377b6fe583cSAlexander Motin int bal;
378b6fe583cSAlexander Motin unsigned attached, no, sectorsize;
379b6fe583cSAlexander Motin off_t mediasize;
380b6fe583cSAlexander Motin
381b6fe583cSAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
382b6fe583cSAlexander Motin if (nargs == NULL) {
383b6fe583cSAlexander Motin gctl_error(req, "No '%s' argument.", "nargs");
384b6fe583cSAlexander Motin return;
385b6fe583cSAlexander Motin }
386b6fe583cSAlexander Motin if (*nargs <= 2) {
387b6fe583cSAlexander Motin gctl_error(req, "Too few arguments.");
388b6fe583cSAlexander Motin return;
389b6fe583cSAlexander Motin }
390b6fe583cSAlexander Motin
391b6fe583cSAlexander Motin strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic));
392b6fe583cSAlexander Motin md.md_version = G_MIRROR_VERSION;
393b6fe583cSAlexander Motin name = gctl_get_asciiparam(req, "arg0");
394b6fe583cSAlexander Motin if (name == NULL) {
395b6fe583cSAlexander Motin gctl_error(req, "No 'arg%u' argument.", 0);
396b6fe583cSAlexander Motin return;
397b6fe583cSAlexander Motin }
398b6fe583cSAlexander Motin strlcpy(md.md_name, name, sizeof(md.md_name));
399b6fe583cSAlexander Motin md.md_mid = arc4random();
400b6fe583cSAlexander Motin md.md_all = *nargs - 1;
401b6fe583cSAlexander Motin md.md_genid = 0;
402b6fe583cSAlexander Motin md.md_syncid = 1;
403b6fe583cSAlexander Motin md.md_sync_offset = 0;
404b6fe583cSAlexander Motin val = gctl_get_paraml(req, "slice", sizeof(*val));
405b6fe583cSAlexander Motin if (val == NULL) {
406b6fe583cSAlexander Motin gctl_error(req, "No slice argument.");
407b6fe583cSAlexander Motin return;
408b6fe583cSAlexander Motin }
409b6fe583cSAlexander Motin md.md_slice = *val;
410b6fe583cSAlexander Motin sval = gctl_get_asciiparam(req, "balance");
411b6fe583cSAlexander Motin if (sval == NULL) {
412b6fe583cSAlexander Motin gctl_error(req, "No balance argument.");
413b6fe583cSAlexander Motin return;
414b6fe583cSAlexander Motin }
415b6fe583cSAlexander Motin bal = balance_id(sval);
416b6fe583cSAlexander Motin if (bal < 0) {
417b6fe583cSAlexander Motin gctl_error(req, "Invalid balance algorithm.");
418b6fe583cSAlexander Motin return;
419b6fe583cSAlexander Motin }
420b6fe583cSAlexander Motin md.md_balance = bal;
421b6fe583cSAlexander Motin md.md_mflags = 0;
422b6fe583cSAlexander Motin md.md_dflags = 0;
423b6fe583cSAlexander Motin ival = gctl_get_paraml(req, "noautosync", sizeof(*ival));
424b6fe583cSAlexander Motin if (ival != NULL && *ival)
425b6fe583cSAlexander Motin md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
426b6fe583cSAlexander Motin ival = gctl_get_paraml(req, "nofailsync", sizeof(*ival));
427b6fe583cSAlexander Motin if (ival != NULL && *ival)
428b6fe583cSAlexander Motin md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
429b6fe583cSAlexander Motin /* These fields not used in manual mode. */
430b6fe583cSAlexander Motin bzero(md.md_provider, sizeof(md.md_provider));
431b6fe583cSAlexander Motin md.md_provsize = 0;
432b6fe583cSAlexander Motin
433b6fe583cSAlexander Motin g_topology_lock();
434b6fe583cSAlexander Motin mediasize = OFF_MAX;
435b6fe583cSAlexander Motin sectorsize = 0;
436b6fe583cSAlexander Motin gp = g_new_geomf(mp, "%s", md.md_name);
437b6fe583cSAlexander Motin gp->orphan = g_mirror_create_orphan;
438b6fe583cSAlexander Motin cp = g_new_consumer(gp);
439b6fe583cSAlexander Motin for (no = 1; no < *nargs; no++) {
440b6fe583cSAlexander Motin snprintf(param, sizeof(param), "arg%u", no);
441fcf69f3dSXin LI pp = gctl_get_provider(req, param);
442fcf69f3dSXin LI if (pp == NULL) {
443b6fe583cSAlexander Motin err:
444b6fe583cSAlexander Motin g_destroy_consumer(cp);
445b6fe583cSAlexander Motin g_destroy_geom(gp);
446b6fe583cSAlexander Motin g_topology_unlock();
447b6fe583cSAlexander Motin return;
448b6fe583cSAlexander Motin }
449d22ff249SEdward Tomasz Napierala if (g_attach(cp, pp) != 0) {
450d22ff249SEdward Tomasz Napierala G_MIRROR_DEBUG(1, "Can't attach disk %s.", pp->name);
451d22ff249SEdward Tomasz Napierala gctl_error(req, "Can't attach disk %s.", pp->name);
452d22ff249SEdward Tomasz Napierala goto err;
453d22ff249SEdward Tomasz Napierala }
454b6fe583cSAlexander Motin if (g_access(cp, 1, 0, 0) != 0) {
455fcf69f3dSXin LI G_MIRROR_DEBUG(1, "Can't open disk %s.", pp->name);
456fcf69f3dSXin LI gctl_error(req, "Can't open disk %s.", pp->name);
457b6fe583cSAlexander Motin err2:
458b6fe583cSAlexander Motin g_detach(cp);
459b6fe583cSAlexander Motin goto err;
460b6fe583cSAlexander Motin }
461b6fe583cSAlexander Motin if (pp->mediasize == 0 || pp->sectorsize == 0) {
462fcf69f3dSXin LI G_MIRROR_DEBUG(1, "Disk %s has no media.", pp->name);
463fcf69f3dSXin LI gctl_error(req, "Disk %s has no media.", pp->name);
464b6fe583cSAlexander Motin g_access(cp, -1, 0, 0);
465b6fe583cSAlexander Motin goto err2;
466b6fe583cSAlexander Motin }
467b6fe583cSAlexander Motin if (pp->mediasize < mediasize)
468b6fe583cSAlexander Motin mediasize = pp->mediasize;
469b6fe583cSAlexander Motin if (pp->sectorsize > sectorsize)
470b6fe583cSAlexander Motin sectorsize = pp->sectorsize;
471b6fe583cSAlexander Motin g_access(cp, -1, 0, 0);
472b6fe583cSAlexander Motin g_detach(cp);
473b6fe583cSAlexander Motin }
474b6fe583cSAlexander Motin g_destroy_consumer(cp);
475b6fe583cSAlexander Motin g_destroy_geom(gp);
476b6fe583cSAlexander Motin md.md_mediasize = mediasize;
477b6fe583cSAlexander Motin md.md_sectorsize = sectorsize;
478b6fe583cSAlexander Motin md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
479b6fe583cSAlexander Motin
480b6fe583cSAlexander Motin gp = g_mirror_create(mp, &md, G_MIRROR_TYPE_MANUAL);
481b6fe583cSAlexander Motin if (gp == NULL) {
482b6fe583cSAlexander Motin gctl_error(req, "Can't create %s.", md.md_name);
483b6fe583cSAlexander Motin g_topology_unlock();
484b6fe583cSAlexander Motin return;
485b6fe583cSAlexander Motin }
486b6fe583cSAlexander Motin
487b6fe583cSAlexander Motin sc = gp->softc;
488b6fe583cSAlexander Motin g_topology_unlock();
489b6fe583cSAlexander Motin sx_xlock(&sc->sc_lock);
490b6fe583cSAlexander Motin sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
491b6fe583cSAlexander Motin sb = sbuf_new_auto();
492b6fe583cSAlexander Motin sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name);
493b6fe583cSAlexander Motin for (attached = 0, no = 1; no < *nargs; no++) {
494b6fe583cSAlexander Motin snprintf(param, sizeof(param), "arg%u", no);
495fcf69f3dSXin LI pp = gctl_get_provider(req, param);
496b6fe583cSAlexander Motin if (pp == NULL) {
497fcf69f3dSXin LI name = gctl_get_asciiparam(req, param);
498fcf69f3dSXin LI MPASS(name != NULL);
499b6fe583cSAlexander Motin sbuf_printf(sb, " %s", name);
500b6fe583cSAlexander Motin continue;
501b6fe583cSAlexander Motin }
502b6fe583cSAlexander Motin md.md_did = arc4random();
503b6fe583cSAlexander Motin md.md_priority = no - 1;
504b6fe583cSAlexander Motin if (g_mirror_add_disk(sc, pp, &md) != 0) {
505b6fe583cSAlexander Motin G_MIRROR_DEBUG(1, "Disk %u (%s) not attached to %s.",
506b6fe583cSAlexander Motin no, pp->name, gp->name);
507b6fe583cSAlexander Motin sbuf_printf(sb, " %s", pp->name);
508b6fe583cSAlexander Motin continue;
509b6fe583cSAlexander Motin }
510b6fe583cSAlexander Motin attached++;
511b6fe583cSAlexander Motin }
512b6fe583cSAlexander Motin sbuf_finish(sb);
513b6fe583cSAlexander Motin sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
514b6fe583cSAlexander Motin if (md.md_all != attached ||
515b6fe583cSAlexander Motin (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
516b6fe583cSAlexander Motin g_mirror_destroy(gp->softc, G_MIRROR_DESTROY_HARD);
517b6fe583cSAlexander Motin gctl_error(req, "%s", sbuf_data(sb));
518b6fe583cSAlexander Motin } else
519b6fe583cSAlexander Motin sx_xunlock(&sc->sc_lock);
520b6fe583cSAlexander Motin sbuf_delete(sb);
521b6fe583cSAlexander Motin }
522b6fe583cSAlexander Motin
523b6fe583cSAlexander Motin static void
g_mirror_ctl_rebuild(struct gctl_req * req,struct g_class * mp)524fa4a1febSPawel Jakub Dawidek g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
525fa4a1febSPawel Jakub Dawidek {
526fd6d3120SPawel Jakub Dawidek struct g_mirror_metadata md;
527fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
528fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
529fd6d3120SPawel Jakub Dawidek struct g_provider *pp;
530fa4a1febSPawel Jakub Dawidek const char *name;
531fa4a1febSPawel Jakub Dawidek char param[16];
532fd6d3120SPawel Jakub Dawidek int error, *nargs;
533fa4a1febSPawel Jakub Dawidek u_int i;
534fa4a1febSPawel Jakub Dawidek
535fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
536fa4a1febSPawel Jakub Dawidek if (nargs == NULL) {
537fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
538fa4a1febSPawel Jakub Dawidek return;
539fa4a1febSPawel Jakub Dawidek }
540fa4a1febSPawel Jakub Dawidek if (*nargs < 2) {
541fa4a1febSPawel Jakub Dawidek gctl_error(req, "Too few arguments.");
542fa4a1febSPawel Jakub Dawidek return;
543fa4a1febSPawel Jakub Dawidek }
544fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0");
545fa4a1febSPawel Jakub Dawidek if (name == NULL) {
546fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0);
547fa4a1febSPawel Jakub Dawidek return;
548fa4a1febSPawel Jakub Dawidek }
549fa4a1febSPawel Jakub Dawidek sc = g_mirror_find_device(mp, name);
550fa4a1febSPawel Jakub Dawidek if (sc == NULL) {
551fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
552fa4a1febSPawel Jakub Dawidek return;
553fa4a1febSPawel Jakub Dawidek }
554fa4a1febSPawel Jakub Dawidek for (i = 1; i < (u_int)*nargs; i++) {
555fa4a1febSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i);
556fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, param);
557fa4a1febSPawel Jakub Dawidek if (name == NULL) {
558fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i);
559c37e2f9bSPawel Jakub Dawidek continue;
560fa4a1febSPawel Jakub Dawidek }
561fa4a1febSPawel Jakub Dawidek disk = g_mirror_find_disk(sc, name);
562fa4a1febSPawel Jakub Dawidek if (disk == NULL) {
563fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such provider: %s.", name);
564c37e2f9bSPawel Jakub Dawidek continue;
565fa4a1febSPawel Jakub Dawidek }
566fa4a1febSPawel Jakub Dawidek if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 &&
567fa4a1febSPawel Jakub Dawidek disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
568fa4a1febSPawel Jakub Dawidek /*
569fa4a1febSPawel Jakub Dawidek * This is the last active disk. There will be nothing
570fa4a1febSPawel Jakub Dawidek * to rebuild it from, so deny this request.
571fa4a1febSPawel Jakub Dawidek */
572fa4a1febSPawel Jakub Dawidek gctl_error(req,
573fa4a1febSPawel Jakub Dawidek "Provider %s is the last active provider in %s.",
574fa4a1febSPawel Jakub Dawidek name, sc->sc_geom->name);
575855761d5SPawel Jakub Dawidek break;
576fa4a1febSPawel Jakub Dawidek }
577fa4a1febSPawel Jakub Dawidek /*
578fd6d3120SPawel Jakub Dawidek * Do rebuild by resetting syncid, disconnecting the disk and
579fd6d3120SPawel Jakub Dawidek * connecting it again.
580fa4a1febSPawel Jakub Dawidek */
581fa4a1febSPawel Jakub Dawidek disk->d_sync.ds_syncid = 0;
582fa4a1febSPawel Jakub Dawidek if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0)
583fa4a1febSPawel Jakub Dawidek disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC;
584fa4a1febSPawel Jakub Dawidek g_mirror_update_metadata(disk);
585fd6d3120SPawel Jakub Dawidek pp = disk->d_consumer->provider;
586855761d5SPawel Jakub Dawidek g_topology_lock();
587fd6d3120SPawel Jakub Dawidek error = g_mirror_read_metadata(disk->d_consumer, &md);
588855761d5SPawel Jakub Dawidek g_topology_unlock();
589fa4a1febSPawel Jakub Dawidek g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
590fa4a1febSPawel Jakub Dawidek G_MIRROR_EVENT_WAIT);
591fd6d3120SPawel Jakub Dawidek if (error != 0) {
592fd6d3120SPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s.",
593fd6d3120SPawel Jakub Dawidek pp->name);
594fd6d3120SPawel Jakub Dawidek continue;
595fd6d3120SPawel Jakub Dawidek }
596fd6d3120SPawel Jakub Dawidek error = g_mirror_add_disk(sc, pp, &md);
597fd6d3120SPawel Jakub Dawidek if (error != 0) {
598fd6d3120SPawel Jakub Dawidek gctl_error(req, "Cannot reconnect component %s.",
599fd6d3120SPawel Jakub Dawidek pp->name);
600fd6d3120SPawel Jakub Dawidek continue;
601fd6d3120SPawel Jakub Dawidek }
602fa4a1febSPawel Jakub Dawidek }
603855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
604fa4a1febSPawel Jakub Dawidek }
605fa4a1febSPawel Jakub Dawidek
606fa4a1febSPawel Jakub Dawidek static void
g_mirror_ctl_insert(struct gctl_req * req,struct g_class * mp)607fa4a1febSPawel Jakub Dawidek g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp)
608fa4a1febSPawel Jakub Dawidek {
609fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
610fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
611fa4a1febSPawel Jakub Dawidek struct g_mirror_metadata md;
612fa4a1febSPawel Jakub Dawidek struct g_provider *pp;
613fa4a1febSPawel Jakub Dawidek struct g_consumer *cp;
61455d6eb9fSPawel Jakub Dawidek intmax_t *priority;
615fa4a1febSPawel Jakub Dawidek const char *name;
616fa4a1febSPawel Jakub Dawidek char param[16];
617fa4a1febSPawel Jakub Dawidek u_char *sector;
618fa4a1febSPawel Jakub Dawidek u_int i, n;
619c38d2f4eSPawel Jakub Dawidek int error, *nargs, *hardcode, *inactive;
620fa4a1febSPawel Jakub Dawidek struct {
621fa4a1febSPawel Jakub Dawidek struct g_provider *provider;
622fa4a1febSPawel Jakub Dawidek struct g_consumer *consumer;
623fa4a1febSPawel Jakub Dawidek } *disks;
624b6fe583cSAlexander Motin off_t mdsize;
625fa4a1febSPawel Jakub Dawidek
626fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
627fa4a1febSPawel Jakub Dawidek if (nargs == NULL) {
628fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
629fa4a1febSPawel Jakub Dawidek return;
630fa4a1febSPawel Jakub Dawidek }
631fa4a1febSPawel Jakub Dawidek if (*nargs < 2) {
632fa4a1febSPawel Jakub Dawidek gctl_error(req, "Too few arguments.");
633fa4a1febSPawel Jakub Dawidek return;
634fa4a1febSPawel Jakub Dawidek }
63555d6eb9fSPawel Jakub Dawidek priority = gctl_get_paraml(req, "priority", sizeof(*priority));
63655d6eb9fSPawel Jakub Dawidek if (priority == NULL) {
63755d6eb9fSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "priority");
63855d6eb9fSPawel Jakub Dawidek return;
63955d6eb9fSPawel Jakub Dawidek }
640fa4a1febSPawel Jakub Dawidek inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive));
641fa4a1febSPawel Jakub Dawidek if (inactive == NULL) {
642fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "inactive");
643fa4a1febSPawel Jakub Dawidek return;
644fa4a1febSPawel Jakub Dawidek }
645c38d2f4eSPawel Jakub Dawidek hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
646c38d2f4eSPawel Jakub Dawidek if (hardcode == NULL) {
647c38d2f4eSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "hardcode");
648c38d2f4eSPawel Jakub Dawidek return;
649c38d2f4eSPawel Jakub Dawidek }
650fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0");
651fa4a1febSPawel Jakub Dawidek if (name == NULL) {
652fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0);
653fa4a1febSPawel Jakub Dawidek return;
654fa4a1febSPawel Jakub Dawidek }
655844b743dSConrad Meyer sc = g_mirror_find_launched_device(mp, name, M_WAITOK);
656fa4a1febSPawel Jakub Dawidek if (sc == NULL) {
657fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
658fa4a1febSPawel Jakub Dawidek return;
659fa4a1febSPawel Jakub Dawidek }
660fa4a1febSPawel Jakub Dawidek if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
661fa4a1febSPawel Jakub Dawidek gctl_error(req, "Not all disks connected.");
662855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
663fa4a1febSPawel Jakub Dawidek return;
664fa4a1febSPawel Jakub Dawidek }
665fa4a1febSPawel Jakub Dawidek
666fa4a1febSPawel Jakub Dawidek disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO);
667855761d5SPawel Jakub Dawidek g_topology_lock();
668fa4a1febSPawel Jakub Dawidek for (i = 1, n = 0; i < (u_int)*nargs; i++) {
669fa4a1febSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i);
670fcf69f3dSXin LI pp = gctl_get_provider(req, param);
671fcf69f3dSXin LI if (pp == NULL)
672fa4a1febSPawel Jakub Dawidek continue;
673fcf69f3dSXin LI if (g_mirror_find_disk(sc, pp->name) != NULL) {
674fcf69f3dSXin LI gctl_error(req, "Provider %s already inserted.", pp->name);
675fa4a1febSPawel Jakub Dawidek continue;
676fa4a1febSPawel Jakub Dawidek }
677fa4a1febSPawel Jakub Dawidek cp = g_new_consumer(sc->sc_geom);
678fa4a1febSPawel Jakub Dawidek if (g_attach(cp, pp) != 0) {
679fa4a1febSPawel Jakub Dawidek g_destroy_consumer(cp);
680fcf69f3dSXin LI gctl_error(req, "Cannot attach to provider %s.", pp->name);
681fa4a1febSPawel Jakub Dawidek continue;
682fa4a1febSPawel Jakub Dawidek }
683fa4a1febSPawel Jakub Dawidek if (g_access(cp, 0, 1, 1) != 0) {
684fcf69f3dSXin LI gctl_error(req, "Cannot access provider %s.", pp->name);
685b6fe583cSAlexander Motin err:
686fa4a1febSPawel Jakub Dawidek g_detach(cp);
687fa4a1febSPawel Jakub Dawidek g_destroy_consumer(cp);
688b6fe583cSAlexander Motin continue;
689b6fe583cSAlexander Motin }
690b6fe583cSAlexander Motin mdsize = (sc->sc_type == G_MIRROR_TYPE_AUTOMATIC) ?
691b6fe583cSAlexander Motin pp->sectorsize : 0;
692b6fe583cSAlexander Motin if (sc->sc_provider->mediasize > pp->mediasize - mdsize) {
693fcf69f3dSXin LI gctl_error(req, "Provider %s too small.", pp->name);
694b6fe583cSAlexander Motin err2:
695b6fe583cSAlexander Motin g_access(cp, 0, -1, -1);
696b6fe583cSAlexander Motin goto err;
697b6fe583cSAlexander Motin }
698b6fe583cSAlexander Motin if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) {
699b6fe583cSAlexander Motin gctl_error(req, "Invalid sectorsize of provider %s.",
700fcf69f3dSXin LI pp->name);
701b6fe583cSAlexander Motin goto err2;
702b6fe583cSAlexander Motin }
703b6fe583cSAlexander Motin if (sc->sc_type != G_MIRROR_TYPE_AUTOMATIC) {
704b6fe583cSAlexander Motin g_access(cp, 0, -1, -1);
705b6fe583cSAlexander Motin g_detach(cp);
706b6fe583cSAlexander Motin g_destroy_consumer(cp);
707b6fe583cSAlexander Motin g_topology_unlock();
708b6fe583cSAlexander Motin sc->sc_ndisks++;
709b6fe583cSAlexander Motin g_mirror_fill_metadata(sc, NULL, &md);
710b6fe583cSAlexander Motin md.md_priority = *priority;
711b6fe583cSAlexander Motin if (*inactive)
712b6fe583cSAlexander Motin md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE;
713b6fe583cSAlexander Motin if (g_mirror_add_disk(sc, pp, &md) != 0) {
714b6fe583cSAlexander Motin sc->sc_ndisks--;
715fcf69f3dSXin LI gctl_error(req, "Disk %s not inserted.", pp->name);
716b6fe583cSAlexander Motin }
717b6fe583cSAlexander Motin g_topology_lock();
718fa4a1febSPawel Jakub Dawidek continue;
719fa4a1febSPawel Jakub Dawidek }
720fa4a1febSPawel Jakub Dawidek disks[n].provider = pp;
721fa4a1febSPawel Jakub Dawidek disks[n].consumer = cp;
722fa4a1febSPawel Jakub Dawidek n++;
723fa4a1febSPawel Jakub Dawidek }
724fa4a1febSPawel Jakub Dawidek if (n == 0) {
725855761d5SPawel Jakub Dawidek g_topology_unlock();
726855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
727fa4a1febSPawel Jakub Dawidek g_free(disks);
728fa4a1febSPawel Jakub Dawidek return;
729fa4a1febSPawel Jakub Dawidek }
730fa4a1febSPawel Jakub Dawidek sc->sc_ndisks += n;
731fa4a1febSPawel Jakub Dawidek again:
732fa4a1febSPawel Jakub Dawidek for (i = 0; i < n; i++) {
733fa4a1febSPawel Jakub Dawidek if (disks[i].consumer == NULL)
734fa4a1febSPawel Jakub Dawidek continue;
735fa4a1febSPawel Jakub Dawidek g_mirror_fill_metadata(sc, NULL, &md);
73655d6eb9fSPawel Jakub Dawidek md.md_priority = *priority;
737fa4a1febSPawel Jakub Dawidek if (*inactive)
738fa4a1febSPawel Jakub Dawidek md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE;
739fa4a1febSPawel Jakub Dawidek pp = disks[i].provider;
740c38d2f4eSPawel Jakub Dawidek if (*hardcode) {
741c38d2f4eSPawel Jakub Dawidek strlcpy(md.md_provider, pp->name,
742c38d2f4eSPawel Jakub Dawidek sizeof(md.md_provider));
743c38d2f4eSPawel Jakub Dawidek } else {
744c38d2f4eSPawel Jakub Dawidek bzero(md.md_provider, sizeof(md.md_provider));
745c38d2f4eSPawel Jakub Dawidek }
7469d793bddSPawel Jakub Dawidek md.md_provsize = pp->mediasize;
7477f053a44SMark Johnston sector = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
748fa4a1febSPawel Jakub Dawidek mirror_metadata_encode(&md, sector);
749fa4a1febSPawel Jakub Dawidek error = g_write_data(disks[i].consumer,
750fa4a1febSPawel Jakub Dawidek pp->mediasize - pp->sectorsize, sector, pp->sectorsize);
751fa4a1febSPawel Jakub Dawidek g_free(sector);
752fa4a1febSPawel Jakub Dawidek if (error != 0) {
753fa4a1febSPawel Jakub Dawidek gctl_error(req, "Cannot store metadata on %s.",
754fa4a1febSPawel Jakub Dawidek pp->name);
755fa4a1febSPawel Jakub Dawidek g_access(disks[i].consumer, 0, -1, -1);
756fa4a1febSPawel Jakub Dawidek g_detach(disks[i].consumer);
757fa4a1febSPawel Jakub Dawidek g_destroy_consumer(disks[i].consumer);
758fa4a1febSPawel Jakub Dawidek disks[i].consumer = NULL;
759fa4a1febSPawel Jakub Dawidek disks[i].provider = NULL;
760fa4a1febSPawel Jakub Dawidek sc->sc_ndisks--;
761fa4a1febSPawel Jakub Dawidek goto again;
762fa4a1febSPawel Jakub Dawidek }
763fa4a1febSPawel Jakub Dawidek }
764855761d5SPawel Jakub Dawidek g_topology_unlock();
765fa4a1febSPawel Jakub Dawidek if (i == 0) {
766fa4a1febSPawel Jakub Dawidek /* All writes failed. */
767855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
768fa4a1febSPawel Jakub Dawidek g_free(disks);
769fa4a1febSPawel Jakub Dawidek return;
770fa4a1febSPawel Jakub Dawidek }
771fa4a1febSPawel Jakub Dawidek LIST_FOREACH(disk, &sc->sc_disks, d_next) {
772fa4a1febSPawel Jakub Dawidek g_mirror_update_metadata(disk);
773fa4a1febSPawel Jakub Dawidek }
774fa4a1febSPawel Jakub Dawidek /*
775fa4a1febSPawel Jakub Dawidek * Release provider and wait for retaste.
776fa4a1febSPawel Jakub Dawidek */
777855761d5SPawel Jakub Dawidek g_topology_lock();
778fa4a1febSPawel Jakub Dawidek for (i = 0; i < n; i++) {
779fa4a1febSPawel Jakub Dawidek if (disks[i].consumer == NULL)
780fa4a1febSPawel Jakub Dawidek continue;
781fa4a1febSPawel Jakub Dawidek g_access(disks[i].consumer, 0, -1, -1);
782fa4a1febSPawel Jakub Dawidek g_detach(disks[i].consumer);
783fa4a1febSPawel Jakub Dawidek g_destroy_consumer(disks[i].consumer);
784fa4a1febSPawel Jakub Dawidek }
785855761d5SPawel Jakub Dawidek g_topology_unlock();
786855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
787fa4a1febSPawel Jakub Dawidek g_free(disks);
788fa4a1febSPawel Jakub Dawidek }
789fa4a1febSPawel Jakub Dawidek
790fa4a1febSPawel Jakub Dawidek static void
g_mirror_ctl_remove(struct gctl_req * req,struct g_class * mp)791fa4a1febSPawel Jakub Dawidek g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp)
792fa4a1febSPawel Jakub Dawidek {
793fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
794fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
795fa4a1febSPawel Jakub Dawidek const char *name;
796fa4a1febSPawel Jakub Dawidek char param[16];
797fa4a1febSPawel Jakub Dawidek int *nargs;
798f931cd70SAndrey V. Elsukov u_int i, active;
799fa4a1febSPawel Jakub Dawidek
800fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
801fa4a1febSPawel Jakub Dawidek if (nargs == NULL) {
802fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
803fa4a1febSPawel Jakub Dawidek return;
804fa4a1febSPawel Jakub Dawidek }
805fa4a1febSPawel Jakub Dawidek if (*nargs < 2) {
806fa4a1febSPawel Jakub Dawidek gctl_error(req, "Too few arguments.");
807fa4a1febSPawel Jakub Dawidek return;
808fa4a1febSPawel Jakub Dawidek }
809fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0");
810fa4a1febSPawel Jakub Dawidek if (name == NULL) {
811fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0);
812fa4a1febSPawel Jakub Dawidek return;
813fa4a1febSPawel Jakub Dawidek }
814fa4a1febSPawel Jakub Dawidek sc = g_mirror_find_device(mp, name);
815fa4a1febSPawel Jakub Dawidek if (sc == NULL) {
816fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
817fa4a1febSPawel Jakub Dawidek return;
818fa4a1febSPawel Jakub Dawidek }
819fa4a1febSPawel Jakub Dawidek if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
820855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
821855761d5SPawel Jakub Dawidek gctl_error(req, "Not all disks connected. Try 'forget' command "
822855761d5SPawel Jakub Dawidek "first.");
823fa4a1febSPawel Jakub Dawidek return;
824fa4a1febSPawel Jakub Dawidek }
825f931cd70SAndrey V. Elsukov active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
826fa4a1febSPawel Jakub Dawidek for (i = 1; i < (u_int)*nargs; i++) {
827fa4a1febSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i);
828fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, param);
829fa4a1febSPawel Jakub Dawidek if (name == NULL) {
830fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i);
831c37e2f9bSPawel Jakub Dawidek continue;
832fa4a1febSPawel Jakub Dawidek }
833fa4a1febSPawel Jakub Dawidek disk = g_mirror_find_disk(sc, name);
834fa4a1febSPawel Jakub Dawidek if (disk == NULL) {
835fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such provider: %s.", name);
836c37e2f9bSPawel Jakub Dawidek continue;
837fa4a1febSPawel Jakub Dawidek }
838f931cd70SAndrey V. Elsukov if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
839f931cd70SAndrey V. Elsukov if (active > 1)
840f931cd70SAndrey V. Elsukov active--;
841f931cd70SAndrey V. Elsukov else {
842f931cd70SAndrey V. Elsukov gctl_error(req, "%s: Can't remove the last "
843f931cd70SAndrey V. Elsukov "ACTIVE component %s.", sc->sc_geom->name,
844f931cd70SAndrey V. Elsukov name);
845f931cd70SAndrey V. Elsukov continue;
846f931cd70SAndrey V. Elsukov }
847f931cd70SAndrey V. Elsukov }
848fa4a1febSPawel Jakub Dawidek g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
849855761d5SPawel Jakub Dawidek G_MIRROR_EVENT_DONTWAIT);
850fa4a1febSPawel Jakub Dawidek }
851855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
852fa4a1febSPawel Jakub Dawidek }
853fa4a1febSPawel Jakub Dawidek
854fa4a1febSPawel Jakub Dawidek static void
g_mirror_ctl_resize(struct gctl_req * req,struct g_class * mp)85532cea4caSAndrey V. Elsukov g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp)
85632cea4caSAndrey V. Elsukov {
85732cea4caSAndrey V. Elsukov struct g_mirror_softc *sc;
85832cea4caSAndrey V. Elsukov struct g_mirror_disk *disk;
85932cea4caSAndrey V. Elsukov uint64_t mediasize;
86032cea4caSAndrey V. Elsukov const char *name, *s;
86132cea4caSAndrey V. Elsukov char *x;
86232cea4caSAndrey V. Elsukov int *nargs;
86332cea4caSAndrey V. Elsukov
86432cea4caSAndrey V. Elsukov nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
86532cea4caSAndrey V. Elsukov if (nargs == NULL) {
86632cea4caSAndrey V. Elsukov gctl_error(req, "No '%s' argument.", "nargs");
86732cea4caSAndrey V. Elsukov return;
86832cea4caSAndrey V. Elsukov }
86932cea4caSAndrey V. Elsukov if (*nargs != 1) {
87032cea4caSAndrey V. Elsukov gctl_error(req, "Missing device.");
87132cea4caSAndrey V. Elsukov return;
87232cea4caSAndrey V. Elsukov }
87332cea4caSAndrey V. Elsukov name = gctl_get_asciiparam(req, "arg0");
87432cea4caSAndrey V. Elsukov if (name == NULL) {
87532cea4caSAndrey V. Elsukov gctl_error(req, "No 'arg%u' argument.", 0);
87632cea4caSAndrey V. Elsukov return;
87732cea4caSAndrey V. Elsukov }
87832cea4caSAndrey V. Elsukov s = gctl_get_asciiparam(req, "size");
87932cea4caSAndrey V. Elsukov if (s == NULL) {
88032cea4caSAndrey V. Elsukov gctl_error(req, "No '%s' argument.", "size");
88132cea4caSAndrey V. Elsukov return;
88232cea4caSAndrey V. Elsukov }
88332cea4caSAndrey V. Elsukov mediasize = strtouq(s, &x, 0);
88432cea4caSAndrey V. Elsukov if (*x != '\0' || mediasize == 0) {
88532cea4caSAndrey V. Elsukov gctl_error(req, "Invalid '%s' argument.", "size");
88632cea4caSAndrey V. Elsukov return;
88732cea4caSAndrey V. Elsukov }
888844b743dSConrad Meyer sc = g_mirror_find_launched_device(mp, name, M_WAITOK);
88932cea4caSAndrey V. Elsukov if (sc == NULL) {
89032cea4caSAndrey V. Elsukov gctl_error(req, "No such device: %s.", name);
89132cea4caSAndrey V. Elsukov return;
89232cea4caSAndrey V. Elsukov }
89332cea4caSAndrey V. Elsukov /* Deny shrinking of an opened provider */
894c4c88d47SAlexander Motin if ((g_debugflags & G_F_FOOTSHOOTING) == 0 && sc->sc_provider_open > 0) {
89532cea4caSAndrey V. Elsukov if (sc->sc_mediasize > mediasize) {
89632cea4caSAndrey V. Elsukov gctl_error(req, "Device %s is busy.",
89732cea4caSAndrey V. Elsukov sc->sc_provider->name);
89832cea4caSAndrey V. Elsukov sx_xunlock(&sc->sc_lock);
89932cea4caSAndrey V. Elsukov return;
90032cea4caSAndrey V. Elsukov }
90132cea4caSAndrey V. Elsukov }
90232cea4caSAndrey V. Elsukov LIST_FOREACH(disk, &sc->sc_disks, d_next) {
90332cea4caSAndrey V. Elsukov if (mediasize > disk->d_consumer->provider->mediasize -
90432cea4caSAndrey V. Elsukov disk->d_consumer->provider->sectorsize) {
90532cea4caSAndrey V. Elsukov gctl_error(req, "Provider %s is too small.",
90632cea4caSAndrey V. Elsukov disk->d_name);
90732cea4caSAndrey V. Elsukov sx_xunlock(&sc->sc_lock);
90832cea4caSAndrey V. Elsukov return;
90932cea4caSAndrey V. Elsukov }
91032cea4caSAndrey V. Elsukov }
91132cea4caSAndrey V. Elsukov /* Update the size. */
91232cea4caSAndrey V. Elsukov sc->sc_mediasize = mediasize;
91332cea4caSAndrey V. Elsukov LIST_FOREACH(disk, &sc->sc_disks, d_next) {
91432cea4caSAndrey V. Elsukov g_mirror_update_metadata(disk);
91532cea4caSAndrey V. Elsukov }
91632cea4caSAndrey V. Elsukov g_topology_lock();
91732cea4caSAndrey V. Elsukov g_resize_provider(sc->sc_provider, mediasize);
91832cea4caSAndrey V. Elsukov g_topology_unlock();
91932cea4caSAndrey V. Elsukov sx_xunlock(&sc->sc_lock);
92032cea4caSAndrey V. Elsukov }
92132cea4caSAndrey V. Elsukov
92232cea4caSAndrey V. Elsukov static void
g_mirror_ctl_deactivate(struct gctl_req * req,struct g_class * mp)923fa4a1febSPawel Jakub Dawidek g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
924fa4a1febSPawel Jakub Dawidek {
925fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
926fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
927fa4a1febSPawel Jakub Dawidek const char *name;
928fa4a1febSPawel Jakub Dawidek char param[16];
929fa4a1febSPawel Jakub Dawidek int *nargs;
9307c5710dbSAndrey V. Elsukov u_int i, active;
931fa4a1febSPawel Jakub Dawidek
932fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
933fa4a1febSPawel Jakub Dawidek if (nargs == NULL) {
934fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
935fa4a1febSPawel Jakub Dawidek return;
936fa4a1febSPawel Jakub Dawidek }
937fa4a1febSPawel Jakub Dawidek if (*nargs < 2) {
938fa4a1febSPawel Jakub Dawidek gctl_error(req, "Too few arguments.");
939fa4a1febSPawel Jakub Dawidek return;
940fa4a1febSPawel Jakub Dawidek }
941fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0");
942fa4a1febSPawel Jakub Dawidek if (name == NULL) {
943fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0);
944fa4a1febSPawel Jakub Dawidek return;
945fa4a1febSPawel Jakub Dawidek }
946fa4a1febSPawel Jakub Dawidek sc = g_mirror_find_device(mp, name);
947fa4a1febSPawel Jakub Dawidek if (sc == NULL) {
948fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
949fa4a1febSPawel Jakub Dawidek return;
950fa4a1febSPawel Jakub Dawidek }
9517c5710dbSAndrey V. Elsukov active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
952fa4a1febSPawel Jakub Dawidek for (i = 1; i < (u_int)*nargs; i++) {
953fa4a1febSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i);
954fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, param);
955fa4a1febSPawel Jakub Dawidek if (name == NULL) {
956fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i);
957c37e2f9bSPawel Jakub Dawidek continue;
958fa4a1febSPawel Jakub Dawidek }
959fa4a1febSPawel Jakub Dawidek disk = g_mirror_find_disk(sc, name);
960fa4a1febSPawel Jakub Dawidek if (disk == NULL) {
961fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such provider: %s.", name);
962c37e2f9bSPawel Jakub Dawidek continue;
963fa4a1febSPawel Jakub Dawidek }
9647c5710dbSAndrey V. Elsukov if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
9657c5710dbSAndrey V. Elsukov if (active > 1)
9667c5710dbSAndrey V. Elsukov active--;
9677c5710dbSAndrey V. Elsukov else {
9687c5710dbSAndrey V. Elsukov gctl_error(req, "%s: Can't deactivate the "
9697c5710dbSAndrey V. Elsukov "last ACTIVE component %s.",
9707c5710dbSAndrey V. Elsukov sc->sc_geom->name, name);
9717c5710dbSAndrey V. Elsukov continue;
9727c5710dbSAndrey V. Elsukov }
9737c5710dbSAndrey V. Elsukov }
974fa4a1febSPawel Jakub Dawidek disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE;
975fa4a1febSPawel Jakub Dawidek disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
976fa4a1febSPawel Jakub Dawidek g_mirror_update_metadata(disk);
977da844167SPawel Jakub Dawidek sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID;
978fa4a1febSPawel Jakub Dawidek g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
979855761d5SPawel Jakub Dawidek G_MIRROR_EVENT_DONTWAIT);
980fa4a1febSPawel Jakub Dawidek }
981855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
982fa4a1febSPawel Jakub Dawidek }
983fa4a1febSPawel Jakub Dawidek
984fa4a1febSPawel Jakub Dawidek static void
g_mirror_ctl_forget(struct gctl_req * req,struct g_class * mp)985fa4a1febSPawel Jakub Dawidek g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp)
986fa4a1febSPawel Jakub Dawidek {
987fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
988fa4a1febSPawel Jakub Dawidek struct g_mirror_disk *disk;
989fa4a1febSPawel Jakub Dawidek const char *name;
990fa4a1febSPawel Jakub Dawidek char param[16];
991fa4a1febSPawel Jakub Dawidek int *nargs;
992fa4a1febSPawel Jakub Dawidek u_int i;
993fa4a1febSPawel Jakub Dawidek
994fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
995fa4a1febSPawel Jakub Dawidek if (nargs == NULL) {
996fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
997fa4a1febSPawel Jakub Dawidek return;
998fa4a1febSPawel Jakub Dawidek }
999fa4a1febSPawel Jakub Dawidek if (*nargs < 1) {
1000fa4a1febSPawel Jakub Dawidek gctl_error(req, "Missing device(s).");
1001fa4a1febSPawel Jakub Dawidek return;
1002fa4a1febSPawel Jakub Dawidek }
1003fa4a1febSPawel Jakub Dawidek
1004fa4a1febSPawel Jakub Dawidek for (i = 0; i < (u_int)*nargs; i++) {
1005fa4a1febSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i);
1006fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, param);
1007fa4a1febSPawel Jakub Dawidek if (name == NULL) {
1008fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i);
1009fa4a1febSPawel Jakub Dawidek return;
1010fa4a1febSPawel Jakub Dawidek }
1011fa4a1febSPawel Jakub Dawidek sc = g_mirror_find_device(mp, name);
1012fa4a1febSPawel Jakub Dawidek if (sc == NULL) {
1013fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
1014fa4a1febSPawel Jakub Dawidek return;
1015fa4a1febSPawel Jakub Dawidek }
1016fa4a1febSPawel Jakub Dawidek if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) {
1017855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
1018fa4a1febSPawel Jakub Dawidek G_MIRROR_DEBUG(1,
1019fa4a1febSPawel Jakub Dawidek "All disks connected in %s, skipping.",
1020fa4a1febSPawel Jakub Dawidek sc->sc_name);
1021fa4a1febSPawel Jakub Dawidek continue;
1022fa4a1febSPawel Jakub Dawidek }
1023fa4a1febSPawel Jakub Dawidek sc->sc_ndisks = g_mirror_ndisks(sc, -1);
1024fa4a1febSPawel Jakub Dawidek LIST_FOREACH(disk, &sc->sc_disks, d_next) {
1025fa4a1febSPawel Jakub Dawidek g_mirror_update_metadata(disk);
1026fa4a1febSPawel Jakub Dawidek }
1027855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
1028fa4a1febSPawel Jakub Dawidek }
1029fa4a1febSPawel Jakub Dawidek }
1030fa4a1febSPawel Jakub Dawidek
1031fa4a1febSPawel Jakub Dawidek static void
g_mirror_ctl_stop(struct gctl_req * req,struct g_class * mp,int wipe)1032ae3bc0acSAndrey V. Elsukov g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe)
1033fa4a1febSPawel Jakub Dawidek {
1034fa4a1febSPawel Jakub Dawidek struct g_mirror_softc *sc;
1035fa4a1febSPawel Jakub Dawidek int *force, *nargs, error;
1036fa4a1febSPawel Jakub Dawidek const char *name;
1037fa4a1febSPawel Jakub Dawidek char param[16];
1038fa4a1febSPawel Jakub Dawidek u_int i;
1039712fe9bdSPawel Jakub Dawidek int how;
1040fa4a1febSPawel Jakub Dawidek
1041fa4a1febSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1042fa4a1febSPawel Jakub Dawidek if (nargs == NULL) {
1043fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs");
1044fa4a1febSPawel Jakub Dawidek return;
1045fa4a1febSPawel Jakub Dawidek }
1046fa4a1febSPawel Jakub Dawidek if (*nargs < 1) {
1047fa4a1febSPawel Jakub Dawidek gctl_error(req, "Missing device(s).");
1048fa4a1febSPawel Jakub Dawidek return;
1049fa4a1febSPawel Jakub Dawidek }
1050fa4a1febSPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force));
1051fa4a1febSPawel Jakub Dawidek if (force == NULL) {
1052fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force");
1053fa4a1febSPawel Jakub Dawidek return;
1054fa4a1febSPawel Jakub Dawidek }
1055712fe9bdSPawel Jakub Dawidek if (*force)
1056712fe9bdSPawel Jakub Dawidek how = G_MIRROR_DESTROY_HARD;
1057712fe9bdSPawel Jakub Dawidek else
1058712fe9bdSPawel Jakub Dawidek how = G_MIRROR_DESTROY_SOFT;
1059fa4a1febSPawel Jakub Dawidek
1060fa4a1febSPawel Jakub Dawidek for (i = 0; i < (u_int)*nargs; i++) {
1061fa4a1febSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i);
1062fa4a1febSPawel Jakub Dawidek name = gctl_get_asciiparam(req, param);
1063fa4a1febSPawel Jakub Dawidek if (name == NULL) {
1064fa4a1febSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i);
1065fa4a1febSPawel Jakub Dawidek return;
1066fa4a1febSPawel Jakub Dawidek }
1067fa4a1febSPawel Jakub Dawidek sc = g_mirror_find_device(mp, name);
1068fa4a1febSPawel Jakub Dawidek if (sc == NULL) {
1069fa4a1febSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name);
1070fa4a1febSPawel Jakub Dawidek return;
1071fa4a1febSPawel Jakub Dawidek }
1072712fe9bdSPawel Jakub Dawidek g_cancel_event(sc);
1073ae3bc0acSAndrey V. Elsukov if (wipe)
1074ae3bc0acSAndrey V. Elsukov sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE;
1075712fe9bdSPawel Jakub Dawidek error = g_mirror_destroy(sc, how);
1076fa4a1febSPawel Jakub Dawidek if (error != 0) {
1077fa4a1febSPawel Jakub Dawidek gctl_error(req, "Cannot destroy device %s (error=%d).",
1078fa4a1febSPawel Jakub Dawidek sc->sc_geom->name, error);
1079ae3bc0acSAndrey V. Elsukov if (wipe)
1080ae3bc0acSAndrey V. Elsukov sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE;
1081855761d5SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock);
1082fa4a1febSPawel Jakub Dawidek return;
1083fa4a1febSPawel Jakub Dawidek }
1084855761d5SPawel Jakub Dawidek /* No need to unlock, because lock is already dead. */
1085fa4a1febSPawel Jakub Dawidek }
1086fa4a1febSPawel Jakub Dawidek }
1087fa4a1febSPawel Jakub Dawidek
1088fa4a1febSPawel Jakub Dawidek void
g_mirror_config(struct gctl_req * req,struct g_class * mp,const char * verb)1089fa4a1febSPawel Jakub Dawidek g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1090fa4a1febSPawel Jakub Dawidek {
1091fa4a1febSPawel Jakub Dawidek uint32_t *version;
1092fa4a1febSPawel Jakub Dawidek
1093fa4a1febSPawel Jakub Dawidek g_topology_assert();
1094fa4a1febSPawel Jakub Dawidek
1095fa4a1febSPawel Jakub Dawidek version = gctl_get_paraml(req, "version", sizeof(*version));
1096fa4a1febSPawel Jakub Dawidek if (version == NULL) {
1097fa4a1febSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "version");
1098fa4a1febSPawel Jakub Dawidek return;
1099fa4a1febSPawel Jakub Dawidek }
1100fa4a1febSPawel Jakub Dawidek if (*version != G_MIRROR_VERSION) {
1101fa4a1febSPawel Jakub Dawidek gctl_error(req, "Userland and kernel parts are out of sync.");
1102fa4a1febSPawel Jakub Dawidek return;
1103fa4a1febSPawel Jakub Dawidek }
1104fa4a1febSPawel Jakub Dawidek
1105855761d5SPawel Jakub Dawidek g_topology_unlock();
1106fa4a1febSPawel Jakub Dawidek if (strcmp(verb, "configure") == 0)
1107fa4a1febSPawel Jakub Dawidek g_mirror_ctl_configure(req, mp);
1108b6fe583cSAlexander Motin else if (strcmp(verb, "create") == 0)
1109b6fe583cSAlexander Motin g_mirror_ctl_create(req, mp);
1110fa4a1febSPawel Jakub Dawidek else if (strcmp(verb, "rebuild") == 0)
1111fa4a1febSPawel Jakub Dawidek g_mirror_ctl_rebuild(req, mp);
1112fa4a1febSPawel Jakub Dawidek else if (strcmp(verb, "insert") == 0)
1113fa4a1febSPawel Jakub Dawidek g_mirror_ctl_insert(req, mp);
1114fa4a1febSPawel Jakub Dawidek else if (strcmp(verb, "remove") == 0)
1115fa4a1febSPawel Jakub Dawidek g_mirror_ctl_remove(req, mp);
111632cea4caSAndrey V. Elsukov else if (strcmp(verb, "resize") == 0)
111732cea4caSAndrey V. Elsukov g_mirror_ctl_resize(req, mp);
1118fa4a1febSPawel Jakub Dawidek else if (strcmp(verb, "deactivate") == 0)
1119fa4a1febSPawel Jakub Dawidek g_mirror_ctl_deactivate(req, mp);
1120fa4a1febSPawel Jakub Dawidek else if (strcmp(verb, "forget") == 0)
1121fa4a1febSPawel Jakub Dawidek g_mirror_ctl_forget(req, mp);
1122fa4a1febSPawel Jakub Dawidek else if (strcmp(verb, "stop") == 0)
1123ae3bc0acSAndrey V. Elsukov g_mirror_ctl_stop(req, mp, 0);
1124ae3bc0acSAndrey V. Elsukov else if (strcmp(verb, "destroy") == 0)
1125ae3bc0acSAndrey V. Elsukov g_mirror_ctl_stop(req, mp, 1);
1126fa4a1febSPawel Jakub Dawidek else
1127fa4a1febSPawel Jakub Dawidek gctl_error(req, "Unknown verb.");
1128855761d5SPawel Jakub Dawidek g_topology_lock();
1129fa4a1febSPawel Jakub Dawidek }
1130