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