1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 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 THE AUTHORS 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 THE AUTHORS 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 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/module.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/bio.h> 39 #include <sys/sysctl.h> 40 #include <sys/malloc.h> 41 #include <sys/bitstring.h> 42 #include <vm/uma.h> 43 #include <machine/atomic.h> 44 #include <geom/geom.h> 45 #include <sys/proc.h> 46 #include <sys/kthread.h> 47 #include <geom/raid3/g_raid3.h> 48 49 50 static struct g_raid3_softc * 51 g_raid3_find_device(struct g_class *mp, const char *name) 52 { 53 struct g_raid3_softc *sc; 54 struct g_geom *gp; 55 56 g_topology_lock(); 57 LIST_FOREACH(gp, &mp->geom, geom) { 58 sc = gp->softc; 59 if (sc == NULL) 60 continue; 61 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) 62 continue; 63 if (strcmp(gp->name, name) == 0 || 64 strcmp(sc->sc_name, name) == 0) { 65 g_topology_unlock(); 66 sx_xlock(&sc->sc_lock); 67 return (sc); 68 } 69 } 70 g_topology_unlock(); 71 return (NULL); 72 } 73 74 static struct g_raid3_disk * 75 g_raid3_find_disk(struct g_raid3_softc *sc, const char *name) 76 { 77 struct g_raid3_disk *disk; 78 u_int n; 79 80 sx_assert(&sc->sc_lock, SX_XLOCKED); 81 if (strncmp(name, "/dev/", 5) == 0) 82 name += 5; 83 for (n = 0; n < sc->sc_ndisks; n++) { 84 disk = &sc->sc_disks[n]; 85 if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 86 continue; 87 if (disk->d_consumer == NULL) 88 continue; 89 if (disk->d_consumer->provider == NULL) 90 continue; 91 if (strcmp(disk->d_consumer->provider->name, name) == 0) 92 return (disk); 93 } 94 return (NULL); 95 } 96 97 static void 98 g_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp) 99 { 100 struct g_raid3_softc *sc; 101 struct g_raid3_disk *disk; 102 const char *name; 103 int *nargs, do_sync = 0, dirty = 1; 104 int *autosync, *noautosync; 105 int *failsync, *nofailsync; 106 int *round_robin, *noround_robin; 107 int *verify, *noverify; 108 u_int n; 109 110 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 111 if (nargs == NULL) { 112 gctl_error(req, "No '%s' argument.", "nargs"); 113 return; 114 } 115 if (*nargs != 1) { 116 gctl_error(req, "Invalid number of arguments."); 117 return; 118 } 119 autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 120 if (autosync == NULL) { 121 gctl_error(req, "No '%s' argument.", "autosync"); 122 return; 123 } 124 noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 125 if (noautosync == NULL) { 126 gctl_error(req, "No '%s' argument.", "noautosync"); 127 return; 128 } 129 if (*autosync && *noautosync) { 130 gctl_error(req, "'%s' and '%s' specified.", "autosync", 131 "noautosync"); 132 return; 133 } 134 failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync)); 135 if (failsync == NULL) { 136 gctl_error(req, "No '%s' argument.", "failsync"); 137 return; 138 } 139 nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync)); 140 if (nofailsync == NULL) { 141 gctl_error(req, "No '%s' argument.", "nofailsync"); 142 return; 143 } 144 if (*failsync && *nofailsync) { 145 gctl_error(req, "'%s' and '%s' specified.", "failsync", 146 "nofailsync"); 147 return; 148 } 149 round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 150 if (round_robin == NULL) { 151 gctl_error(req, "No '%s' argument.", "round_robin"); 152 return; 153 } 154 noround_robin = gctl_get_paraml(req, "noround_robin", 155 sizeof(*noround_robin)); 156 if (noround_robin == NULL) { 157 gctl_error(req, "No '%s' argument.", "noround_robin"); 158 return; 159 } 160 if (*round_robin && *noround_robin) { 161 gctl_error(req, "'%s' and '%s' specified.", "round_robin", 162 "noround_robin"); 163 return; 164 } 165 verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 166 if (verify == NULL) { 167 gctl_error(req, "No '%s' argument.", "verify"); 168 return; 169 } 170 noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 171 if (noverify == NULL) { 172 gctl_error(req, "No '%s' argument.", "noverify"); 173 return; 174 } 175 if (*verify && *noverify) { 176 gctl_error(req, "'%s' and '%s' specified.", "verify", 177 "noverify"); 178 return; 179 } 180 if (!*autosync && !*noautosync && !*failsync && !*nofailsync && 181 !*round_robin && !*noround_robin && !*verify && !*noverify) { 182 gctl_error(req, "Nothing has changed."); 183 return; 184 } 185 name = gctl_get_asciiparam(req, "arg0"); 186 if (name == NULL) { 187 gctl_error(req, "No 'arg%u' argument.", 0); 188 return; 189 } 190 sc = g_raid3_find_device(mp, name); 191 if (sc == NULL) { 192 gctl_error(req, "No such device: %s.", name); 193 return; 194 } 195 if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 196 gctl_error(req, "Not all disks connected."); 197 sx_xunlock(&sc->sc_lock); 198 return; 199 } 200 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 201 if (*autosync) { 202 sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 203 do_sync = 1; 204 } 205 } else { 206 if (*noautosync) 207 sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 208 } 209 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0) { 210 if (*failsync) 211 sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOFAILSYNC; 212 } else { 213 if (*nofailsync) { 214 sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC; 215 dirty = 0; 216 } 217 } 218 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 219 if (*noverify) 220 sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 221 } else { 222 if (*verify) 223 sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 224 } 225 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 226 if (*noround_robin) 227 sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 228 } else { 229 if (*round_robin) 230 sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 231 } 232 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 233 (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 234 /* 235 * VERIFY and ROUND-ROBIN options are mutally exclusive. 236 */ 237 sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 238 } 239 for (n = 0; n < sc->sc_ndisks; n++) { 240 disk = &sc->sc_disks[n]; 241 if (do_sync) { 242 if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 243 disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 244 } 245 if (!dirty) 246 disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 247 g_raid3_update_metadata(disk); 248 if (do_sync) { 249 if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 250 /* 251 * XXX: This is probably possible that this 252 * component will not be retasted. 253 */ 254 g_raid3_event_send(disk, 255 G_RAID3_DISK_STATE_DISCONNECTED, 256 G_RAID3_EVENT_DONTWAIT); 257 } 258 } 259 } 260 sx_xunlock(&sc->sc_lock); 261 } 262 263 static void 264 g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 265 { 266 struct g_raid3_metadata md; 267 struct g_raid3_softc *sc; 268 struct g_raid3_disk *disk; 269 struct g_provider *pp; 270 const char *name; 271 int error, *nargs; 272 273 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 274 if (nargs == NULL) { 275 gctl_error(req, "No '%s' argument.", "nargs"); 276 return; 277 } 278 if (*nargs != 2) { 279 gctl_error(req, "Invalid number of arguments."); 280 return; 281 } 282 name = gctl_get_asciiparam(req, "arg0"); 283 if (name == NULL) { 284 gctl_error(req, "No 'arg%u' argument.", 0); 285 return; 286 } 287 sc = g_raid3_find_device(mp, name); 288 if (sc == NULL) { 289 gctl_error(req, "No such device: %s.", name); 290 return; 291 } 292 name = gctl_get_asciiparam(req, "arg1"); 293 if (name == NULL) { 294 gctl_error(req, "No 'arg%u' argument.", 1); 295 sx_xunlock(&sc->sc_lock); 296 return; 297 } 298 disk = g_raid3_find_disk(sc, name); 299 if (disk == NULL) { 300 gctl_error(req, "No such provider: %s.", name); 301 sx_xunlock(&sc->sc_lock); 302 return; 303 } 304 if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 305 g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 306 gctl_error(req, "There is one stale disk already."); 307 sx_xunlock(&sc->sc_lock); 308 return; 309 } 310 /* 311 * Do rebuild by resetting syncid and disconnecting disk. 312 * It'll be retasted, connected to the device and synchronized. 313 */ 314 disk->d_sync.ds_syncid = 0; 315 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 316 disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 317 g_raid3_update_metadata(disk); 318 pp = disk->d_consumer->provider; 319 g_topology_lock(); 320 error = g_raid3_read_metadata(disk->d_consumer, &md); 321 g_topology_unlock(); 322 g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 323 G_RAID3_EVENT_WAIT); 324 if (error != 0) { 325 gctl_error(req, "Cannot read metadata from %s.", pp->name); 326 sx_xunlock(&sc->sc_lock); 327 return; 328 } 329 error = g_raid3_add_disk(sc, pp, &md); 330 if (error != 0) 331 gctl_error(req, "Cannot reconnect component %s.", pp->name); 332 sx_xunlock(&sc->sc_lock); 333 } 334 335 static void 336 g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 337 { 338 struct g_raid3_softc *sc; 339 int *force, *nargs, error; 340 const char *name; 341 char param[16]; 342 u_int i; 343 int how; 344 345 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 346 if (nargs == NULL) { 347 gctl_error(req, "No '%s' argument.", "nargs"); 348 return; 349 } 350 if (*nargs < 1) { 351 gctl_error(req, "Missing device(s)."); 352 return; 353 } 354 force = gctl_get_paraml(req, "force", sizeof(*force)); 355 if (force == NULL) { 356 gctl_error(req, "No '%s' argument.", "force"); 357 return; 358 } 359 if (*force) 360 how = G_RAID3_DESTROY_HARD; 361 else 362 how = G_RAID3_DESTROY_SOFT; 363 364 for (i = 0; i < (u_int)*nargs; i++) { 365 snprintf(param, sizeof(param), "arg%u", i); 366 name = gctl_get_asciiparam(req, param); 367 if (name == NULL) { 368 gctl_error(req, "No 'arg%u' argument.", i); 369 return; 370 } 371 sc = g_raid3_find_device(mp, name); 372 if (sc == NULL) { 373 gctl_error(req, "No such device: %s.", name); 374 return; 375 } 376 g_cancel_event(sc); 377 error = g_raid3_destroy(sc, how); 378 if (error != 0) { 379 gctl_error(req, "Cannot destroy device %s (error=%d).", 380 sc->sc_geom->name, error); 381 sx_xunlock(&sc->sc_lock); 382 return; 383 } 384 /* No need to unlock, because lock is already dead. */ 385 } 386 } 387 388 static void 389 g_raid3_ctl_insert_orphan(struct g_consumer *cp) 390 { 391 392 KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 393 cp->provider->name)); 394 } 395 396 static void 397 g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 398 { 399 struct g_raid3_metadata md; 400 struct g_raid3_softc *sc; 401 struct g_raid3_disk *disk; 402 struct g_geom *gp; 403 struct g_provider *pp; 404 struct g_consumer *cp; 405 const char *name; 406 u_char *sector; 407 off_t compsize; 408 intmax_t *no; 409 int *hardcode, *nargs, error, autono; 410 411 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 412 if (nargs == NULL) { 413 gctl_error(req, "No '%s' argument.", "nargs"); 414 return; 415 } 416 if (*nargs != 2) { 417 gctl_error(req, "Invalid number of arguments."); 418 return; 419 } 420 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 421 if (hardcode == NULL) { 422 gctl_error(req, "No '%s' argument.", "hardcode"); 423 return; 424 } 425 name = gctl_get_asciiparam(req, "arg1"); 426 if (name == NULL) { 427 gctl_error(req, "No 'arg%u' argument.", 1); 428 return; 429 } 430 if (gctl_get_param(req, "number", NULL) != NULL) 431 no = gctl_get_paraml(req, "number", sizeof(*no)); 432 else 433 no = NULL; 434 if (strncmp(name, "/dev/", 5) == 0) 435 name += 5; 436 g_topology_lock(); 437 pp = g_provider_by_name(name); 438 if (pp == NULL) { 439 g_topology_unlock(); 440 gctl_error(req, "Invalid provider."); 441 return; 442 } 443 gp = g_new_geomf(mp, "raid3:insert"); 444 gp->orphan = g_raid3_ctl_insert_orphan; 445 cp = g_new_consumer(gp); 446 error = g_attach(cp, pp); 447 if (error != 0) { 448 g_topology_unlock(); 449 gctl_error(req, "Cannot attach to %s.", pp->name); 450 goto end; 451 } 452 error = g_access(cp, 0, 1, 1); 453 if (error != 0) { 454 g_topology_unlock(); 455 gctl_error(req, "Cannot access %s.", pp->name); 456 goto end; 457 } 458 g_topology_unlock(); 459 name = gctl_get_asciiparam(req, "arg0"); 460 if (name == NULL) { 461 gctl_error(req, "No 'arg%u' argument.", 0); 462 goto end; 463 } 464 sc = g_raid3_find_device(mp, name); 465 if (sc == NULL) { 466 gctl_error(req, "No such device: %s.", name); 467 goto end; 468 } 469 if (no != NULL) { 470 if (*no < 0 || *no >= sc->sc_ndisks) { 471 sx_xunlock(&sc->sc_lock); 472 gctl_error(req, "Invalid component number."); 473 goto end; 474 } 475 disk = &sc->sc_disks[*no]; 476 if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 477 sx_xunlock(&sc->sc_lock); 478 gctl_error(req, "Component %jd is already connected.", 479 *no); 480 goto end; 481 } 482 } else { 483 disk = NULL; 484 for (autono = 0; autono < sc->sc_ndisks && disk == NULL; autono++) 485 if (sc->sc_disks[autono].d_state == 486 G_RAID3_DISK_STATE_NODISK) 487 disk = &sc->sc_disks[autono]; 488 if (disk == NULL) { 489 sx_xunlock(&sc->sc_lock); 490 gctl_error(req, "No disconnected components."); 491 goto end; 492 } 493 } 494 if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 495 sx_xunlock(&sc->sc_lock); 496 gctl_error(req, 497 "Cannot insert provider %s, because of its sector size.", 498 pp->name); 499 goto end; 500 } 501 compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 502 if (compsize > pp->mediasize - pp->sectorsize) { 503 sx_xunlock(&sc->sc_lock); 504 gctl_error(req, "Provider %s too small.", pp->name); 505 goto end; 506 } 507 if (compsize < pp->mediasize - pp->sectorsize) { 508 gctl_error(req, 509 "warning: %s: only %jd bytes from %jd bytes used.", 510 pp->name, (intmax_t)compsize, 511 (intmax_t)(pp->mediasize - pp->sectorsize)); 512 } 513 g_raid3_fill_metadata(disk, &md); 514 sx_xunlock(&sc->sc_lock); 515 md.md_syncid = 0; 516 md.md_dflags = 0; 517 if (*hardcode) 518 strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 519 else 520 bzero(md.md_provider, sizeof(md.md_provider)); 521 md.md_provsize = pp->mediasize; 522 sector = g_malloc(pp->sectorsize, M_WAITOK); 523 raid3_metadata_encode(&md, sector); 524 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 525 pp->sectorsize); 526 g_free(sector); 527 if (error != 0) 528 gctl_error(req, "Cannot store metadata on %s.", pp->name); 529 end: 530 g_topology_lock(); 531 if (cp->acw > 0) 532 g_access(cp, 0, -1, -1); 533 if (cp->provider != NULL) 534 g_detach(cp); 535 g_destroy_consumer(cp); 536 g_destroy_geom(gp); 537 g_topology_unlock(); 538 } 539 540 static void 541 g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 542 { 543 struct g_raid3_softc *sc; 544 struct g_raid3_disk *disk; 545 const char *name; 546 intmax_t *no; 547 int *nargs; 548 549 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 550 if (nargs == NULL) { 551 gctl_error(req, "No '%s' argument.", "nargs"); 552 return; 553 } 554 if (*nargs != 1) { 555 gctl_error(req, "Invalid number of arguments."); 556 return; 557 } 558 no = gctl_get_paraml(req, "number", sizeof(*no)); 559 if (no == NULL) { 560 gctl_error(req, "No '%s' argument.", "no"); 561 return; 562 } 563 name = gctl_get_asciiparam(req, "arg0"); 564 if (name == NULL) { 565 gctl_error(req, "No 'arg%u' argument.", 0); 566 return; 567 } 568 sc = g_raid3_find_device(mp, name); 569 if (sc == NULL) { 570 gctl_error(req, "No such device: %s.", name); 571 return; 572 } 573 if (*no >= sc->sc_ndisks) { 574 sx_xunlock(&sc->sc_lock); 575 gctl_error(req, "Invalid component number."); 576 return; 577 } 578 disk = &sc->sc_disks[*no]; 579 switch (disk->d_state) { 580 case G_RAID3_DISK_STATE_ACTIVE: 581 /* 582 * When replacing ACTIVE component, all the rest has to be also 583 * ACTIVE. 584 */ 585 if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 586 sc->sc_ndisks) { 587 gctl_error(req, "Cannot replace component number %jd.", 588 *no); 589 break; 590 } 591 /* FALLTHROUGH */ 592 case G_RAID3_DISK_STATE_STALE: 593 case G_RAID3_DISK_STATE_SYNCHRONIZING: 594 if (g_raid3_clear_metadata(disk) != 0) { 595 gctl_error(req, "Cannot clear metadata on %s.", 596 g_raid3_get_diskname(disk)); 597 } else { 598 g_raid3_event_send(disk, 599 G_RAID3_DISK_STATE_DISCONNECTED, 600 G_RAID3_EVENT_DONTWAIT); 601 } 602 break; 603 case G_RAID3_DISK_STATE_NODISK: 604 break; 605 default: 606 gctl_error(req, "Cannot replace component number %jd.", *no); 607 break; 608 } 609 sx_xunlock(&sc->sc_lock); 610 } 611 612 void 613 g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 614 { 615 uint32_t *version; 616 617 g_topology_assert(); 618 619 version = gctl_get_paraml(req, "version", sizeof(*version)); 620 if (version == NULL) { 621 gctl_error(req, "No '%s' argument.", "version"); 622 return; 623 } 624 if (*version != G_RAID3_VERSION) { 625 gctl_error(req, "Userland and kernel parts are out of sync."); 626 return; 627 } 628 629 g_topology_unlock(); 630 if (strcmp(verb, "configure") == 0) 631 g_raid3_ctl_configure(req, mp); 632 else if (strcmp(verb, "insert") == 0) 633 g_raid3_ctl_insert(req, mp); 634 else if (strcmp(verb, "rebuild") == 0) 635 g_raid3_ctl_rebuild(req, mp); 636 else if (strcmp(verb, "remove") == 0) 637 g_raid3_ctl_remove(req, mp); 638 else if (strcmp(verb, "stop") == 0) 639 g_raid3_ctl_stop(req, mp); 640 else 641 gctl_error(req, "Unknown verb."); 642 g_topology_lock(); 643 } 644