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