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