geom_vinum_rm.c revision 168670
1/*-
2 *  Copyright (c) 2004 Lukas Ertl
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 AUTHOR 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 AUTHOR 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
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_rm.c 168670 2007-04-12 17:54:35Z le $");
30
31#include <sys/param.h>
32#include <sys/libkern.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
35
36#include <geom/geom.h>
37#include <geom/vinum/geom_vinum_var.h>
38#include <geom/vinum/geom_vinum.h>
39#include <geom/vinum/geom_vinum_share.h>
40
41static int	gv_rm_drive(struct gv_softc *, struct gctl_req *,
42		    struct gv_drive *, int);
43static int	gv_rm_plex(struct gv_softc *, struct gctl_req *,
44		    struct gv_plex *, int);
45static int	gv_rm_vol(struct gv_softc *, struct gctl_req *,
46		    struct gv_volume *, int);
47
48/* General 'remove' routine. */
49void
50gv_remove(struct g_geom *gp, struct gctl_req *req)
51{
52	struct gv_softc *sc;
53	struct gv_volume *v;
54	struct gv_plex *p;
55	struct gv_sd *s;
56	struct gv_drive *d;
57	int *argc, *flags;
58	char *argv, buf[20];
59	int i, type, err;
60
61	argc = gctl_get_paraml(req, "argc", sizeof(*argc));
62	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
63
64	if (argc == NULL || *argc == 0) {
65		gctl_error(req, "no arguments given");
66		return;
67	}
68
69	sc = gp->softc;
70
71	for (i = 0; i < *argc; i++) {
72		snprintf(buf, sizeof(buf), "argv%d", i);
73		argv = gctl_get_param(req, buf, NULL);
74		if (argv == NULL)
75			continue;
76		type = gv_object_type(sc, argv);
77		switch (type) {
78		case GV_TYPE_VOL:
79			v = gv_find_vol(sc, argv);
80			if (v == NULL) {
81				gctl_error(req, "unknown volume '%s'", argv);
82				return;
83			}
84			err = gv_rm_vol(sc, req, v, *flags);
85			if (err)
86				return;
87			break;
88		case GV_TYPE_PLEX:
89			p = gv_find_plex(sc, argv);
90			if (p == NULL) {
91				gctl_error(req, "unknown plex '%s'", argv);
92				return;
93			}
94			err = gv_rm_plex(sc, req, p, *flags);
95			if (err)
96				return;
97			break;
98		case GV_TYPE_SD:
99			s = gv_find_sd(sc, argv);
100			if (s == NULL) {
101				gctl_error(req, "unknown subdisk '%s'", argv);
102				return;
103			}
104			err = gv_rm_sd(sc, req, s, *flags);
105			if (err)
106				return;
107			break;
108		case GV_TYPE_DRIVE:
109			d = gv_find_drive(sc, argv);
110			if (d == NULL) {
111				gctl_error(req, "unknown drive '%s'", argv);
112				return;
113			}
114			err = gv_rm_drive(sc, req, d, *flags);
115			if (err)
116				return;
117			break;
118		default:
119			gctl_error(req, "unknown object '%s'", argv);
120			return;
121		}
122	}
123
124	gv_save_config_all(sc);
125}
126
127/* Resets configuration */
128int
129gv_resetconfig(struct g_geom *gp, struct gctl_req *req)
130{
131	struct gv_softc *sc;
132	struct gv_drive *d, *d2;
133	struct gv_volume *v, *v2;
134	struct gv_plex *p, *p2;
135	struct gv_sd *s, *s2;
136	int flags;
137
138	d = NULL;
139	d2 = NULL;
140	p = NULL;
141	p2 = NULL;
142	s = NULL;
143	s2 = NULL;
144	flags = GV_FLAG_R;
145	sc = gp->softc;
146	/* First loop through to make sure no volumes are up */
147        LIST_FOREACH_SAFE(v, &sc->volumes, volume, v2) {
148		if (gv_is_open(v->geom)) {
149			gctl_error(req, "volume '%s' is busy", v->name);
150			return (-1);
151		}
152	}
153	/* Then if not, we remove everything. */
154	LIST_FOREACH_SAFE(v, &sc->volumes, volume, v2)
155		gv_rm_vol(sc, req, v, flags);
156	LIST_FOREACH_SAFE(p, &sc->plexes, plex, p2)
157		gv_rm_plex(sc, req, p, flags);
158	LIST_FOREACH_SAFE(s, &sc->subdisks, sd, s2)
159		gv_rm_sd(sc, req, s, flags);
160	LIST_FOREACH_SAFE(d, &sc->drives, drive, d2)
161		gv_rm_drive(sc, req, d, flags);
162	gv_save_config_all(sc);
163	return (0);
164}
165
166/* Remove a volume. */
167static int
168gv_rm_vol(struct gv_softc *sc, struct gctl_req *req, struct gv_volume *v, int flags)
169{
170	struct g_geom *gp;
171	struct gv_plex *p, *p2;
172	int err;
173
174	g_topology_assert();
175	KASSERT(v != NULL, ("gv_rm_vol: NULL v"));
176
177	/* If this volume has plexes, we want a recursive removal. */
178	if (!LIST_EMPTY(&v->plexes) && !(flags & GV_FLAG_R)) {
179		gctl_error(req, "volume '%s' has attached plexes", v->name);
180		return (-1);
181	}
182
183	gp = v->geom;
184
185	/* Check if any of our consumers is open. */
186	if (gp != NULL && gv_is_open(gp)) {
187		gctl_error(req, "volume '%s' is busy", v->name);
188		return (-1);
189	}
190
191	/* Remove the plexes our volume has. */
192	LIST_FOREACH_SAFE(p, &v->plexes, in_volume, p2) {
193		v->plexcount--;
194		LIST_REMOVE(p, in_volume);
195		p->vol_sc = NULL;
196
197		err = gv_rm_plex(sc, req, p, flags);
198		if (err)
199			return (err);
200	}
201
202	/* Clean up and let our geom fade away. */
203	LIST_REMOVE(v, volume);
204	gv_kill_vol_thread(v);
205	g_free(v);
206	if (gp != NULL) {
207		gp->softc = NULL;
208		g_wither_geom(gp, ENXIO);
209	}
210
211	return (0);
212}
213
214/* Remove a plex. */
215static int
216gv_rm_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, int flags)
217{
218	struct g_geom *gp;
219	struct gv_volume *v;
220	struct gv_sd *s, *s2;
221	int err;
222
223	g_topology_assert();
224
225	KASSERT(p != NULL, ("gv_rm_plex: NULL p"));
226
227	/* If this plex has subdisks, we want a recursive removal. */
228	if (!LIST_EMPTY(&p->subdisks) && !(flags & GV_FLAG_R)) {
229		gctl_error(req, "plex '%s' has attached subdisks", p->name);
230		return (-1);
231	}
232
233	if (p->vol_sc != NULL && p->vol_sc->plexcount == 1) {
234		gctl_error(req, "plex '%s' is still attached to volume '%s'",
235		    p->name, p->volume);
236		return (-1);
237	}
238
239	gp = p->geom;
240
241	/* Check if any of our consumers is open. */
242	if (gp != NULL && gv_is_open(gp)) {
243		gctl_error(req, "plex '%s' is busy", p->name);
244		return (-1);
245	}
246
247	/* Remove the subdisks our plex has. */
248	LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) {
249#if 0
250		LIST_REMOVE(s, in_plex);
251		s->plex_sc = NULL;
252#endif
253
254		err = gv_rm_sd(sc, req, s, flags);
255		if (err)
256			return (err);
257	}
258
259	v = p->vol_sc;
260	/* Clean up and let our geom fade away. */
261	LIST_REMOVE(p, plex);
262	if (p->vol_sc != NULL) {
263		p->vol_sc->plexcount--;
264		LIST_REMOVE(p, in_volume);
265		p->vol_sc = NULL;
266		/* Correctly update the volume size. */
267		gv_update_vol_size(v, gv_vol_size(v));
268	}
269
270	gv_kill_plex_thread(p);
271	g_free(p);
272
273	if (gp != NULL) {
274		gp->softc = NULL;
275		g_wither_geom(gp, ENXIO);
276	}
277
278	return (0);
279}
280
281/* Remove a subdisk. */
282int
283gv_rm_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, int flags)
284{
285	struct g_provider *pp;
286	struct gv_plex *p;
287	struct gv_volume *v;
288
289	KASSERT(s != NULL, ("gv_rm_sd: NULL s"));
290
291	pp = s->provider;
292	p = s->plex_sc;
293	v = NULL;
294
295	/* Clean up. */
296	if (p != NULL) {
297		LIST_REMOVE(s, in_plex);
298
299		p->sdcount--;
300		/* Update the plexsize. */
301		p->size = gv_plex_size(p);
302		v = p->vol_sc;
303		if (v != NULL) {
304			/* Update the size of our plex' volume. */
305			gv_update_vol_size(v, gv_vol_size(v));
306		}
307	}
308	if (s->drive_sc)
309		LIST_REMOVE(s, from_drive);
310	LIST_REMOVE(s, sd);
311	gv_free_sd(s);
312	g_free(s);
313
314	/* If the subdisk has a provider we need to clean up this one too. */
315	if (pp != NULL) {
316		pp->flags |= G_PF_WITHER;
317		g_orphan_provider(pp, ENXIO);
318	}
319
320	return (0);
321}
322
323/* Remove a drive. */
324static int
325gv_rm_drive(struct gv_softc *sc, struct gctl_req *req, struct gv_drive *d, int flags)
326{
327	struct g_geom *gp;
328	struct g_consumer *cp;
329	struct gv_freelist *fl, *fl2;
330	struct gv_plex *p;
331	struct gv_sd *s, *s2;
332	struct gv_volume *v;
333	int err;
334
335	KASSERT(d != NULL, ("gv_rm_drive: NULL d"));
336	gp = d->geom;
337	KASSERT(gp != NULL, ("gv_rm_drive: NULL gp"));
338
339	/* We don't allow to remove open drives. */
340	if (gv_is_open(gp)) {
341		gctl_error(req, "drive '%s' is open", d->name);
342		return (-1);
343	}
344
345	/* A drive with subdisks needs a recursive removal. */
346	if (!LIST_EMPTY(&d->subdisks) && !(flags & GV_FLAG_R)) {
347		gctl_error(req, "drive '%s' still has subdisks", d->name);
348		return (-1);
349	}
350
351	cp = LIST_FIRST(&gp->consumer);
352	err = g_access(cp, 0, 1, 0);
353	if (err) {
354		printf("GEOM_VINUM: gv_rm_drive: couldn't access '%s', errno: "
355		    "%d\n", cp->provider->name, err);
356		return (err);
357	}
358
359	/* Clear the Vinum Magic. */
360	d->hdr->magic = GV_NOMAGIC;
361	g_topology_unlock();
362	err = g_write_data(cp, GV_HDR_OFFSET, d->hdr, GV_HDR_LEN);
363	if (err) {
364		printf("GEOM_VINUM: gv_rm_drive: couldn't write header to '%s'"
365		    ", errno: %d\n", cp->provider->name, err);
366		d->hdr->magic = GV_MAGIC;
367	}
368	g_topology_lock();
369	g_access(cp, 0, -1, 0);
370
371	/* Remove all associated subdisks, plexes, volumes. */
372	if (!LIST_EMPTY(&d->subdisks)) {
373		LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) {
374			p = s->plex_sc;
375			if (p != NULL) {
376				v = p->vol_sc;
377				if (v != NULL)
378					gv_rm_vol(sc, req, v, flags);
379			}
380		}
381	}
382
383	/* Clean up. */
384	LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) {
385		LIST_REMOVE(fl, freelist);
386		g_free(fl);
387	}
388	LIST_REMOVE(d, drive);
389
390	gv_kill_drive_thread(d);
391	gp = d->geom;
392	d->geom = NULL;
393	g_free(d->hdr);
394	g_free(d);
395	gv_save_config_all(sc);
396	g_wither_geom(gp, ENXIO);
397
398	return (err);
399}
400