g_raid3_ctl.c revision 155174
117680Spst/*- 217680Spst * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 317680Spst * All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that the following conditions 717680Spst * are met: 817680Spst * 1. Redistributions of source code must retain the above copyright 917680Spst * notice, this list of conditions and the following disclaimer. 1017680Spst * 2. Redistributions in binary form must reproduce the above copyright 1117680Spst * notice, this list of conditions and the following disclaimer in the 1217680Spst * documentation and/or other materials provided with the distribution. 1317680Spst * 1417680Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1517680Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1617680Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1717680Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1817680Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1917680Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026183Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2117680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2217680Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2356896Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2456896Sfenner * SUCH DAMAGE. 2517680Spst */ 2626183Sfenner 2717680Spst#include <sys/cdefs.h> 28127675Sbms__FBSDID("$FreeBSD: head/sys/geom/raid3/g_raid3_ctl.c 155174 2006-02-01 12:06:01Z pjd $"); 29146778Ssam 3017680Spst#include <sys/param.h> 3117680Spst#include <sys/systm.h> 3256896Sfenner#include <sys/kernel.h> 3356896Sfenner#include <sys/module.h> 3456896Sfenner#include <sys/lock.h> 3556896Sfenner#include <sys/mutex.h> 36127675Sbms#include <sys/bio.h> 3717680Spst#include <sys/sysctl.h> 3817680Spst#include <sys/malloc.h> 3917680Spst#include <sys/bitstring.h> 4017680Spst#include <vm/uma.h> 4117680Spst#include <machine/atomic.h> 4217680Spst#include <geom/geom.h> 4317680Spst#include <sys/proc.h> 4417680Spst#include <sys/kthread.h> 4517680Spst#include <geom/raid3/g_raid3.h> 4617680Spst 4717680Spst 4817680Spststatic struct g_raid3_softc * 4917680Spstg_raid3_find_device(struct g_class *mp, const char *name) 5017680Spst{ 5117680Spst struct g_raid3_softc *sc; 5217680Spst struct g_geom *gp; 5317680Spst 5417680Spst g_topology_assert(); 5517680Spst LIST_FOREACH(gp, &mp->geom, geom) { 5617680Spst sc = gp->softc; 5717680Spst if (sc == NULL) 5817680Spst continue; 5917680Spst if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) 6017680Spst continue; 61146778Ssam if (strcmp(gp->name, name) == 0 || 62146778Ssam strcmp(sc->sc_name, name) == 0) { 63146778Ssam return (sc); 6417680Spst } 65127675Sbms } 6617680Spst return (NULL); 6717680Spst} 6817680Spst 69146778Ssamstatic struct g_raid3_disk * 7017680Spstg_raid3_find_disk(struct g_raid3_softc *sc, const char *name) 7117680Spst{ 7217680Spst struct g_raid3_disk *disk; 7317680Spst u_int n; 7417680Spst 7517680Spst g_topology_assert(); 7617680Spst for (n = 0; n < sc->sc_ndisks; n++) { 7717680Spst disk = &sc->sc_disks[n]; 7817680Spst if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 7917680Spst continue; 8017680Spst if (disk->d_consumer == NULL) 8117680Spst continue; 8217680Spst if (disk->d_consumer->provider == NULL) 8317680Spst continue; 8417680Spst if (strcmp(disk->d_consumer->provider->name, name) == 0) 8517680Spst return (disk); 8617680Spst } 8717680Spst return (NULL); 88127675Sbms} 8917680Spst 9017680Spststatic void 9117680Spstg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp) 9217680Spst{ 9317680Spst struct g_raid3_softc *sc; 9417680Spst struct g_raid3_disk *disk; 9517680Spst const char *name; 9617680Spst int *nargs, do_sync = 0; 9717680Spst int *autosync, *noautosync; 9817680Spst int *round_robin, *noround_robin; 9917680Spst int *verify, *noverify; 10017680Spst u_int n; 10117680Spst 102146778Ssam g_topology_assert(); 10317680Spst nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 10417680Spst if (nargs == NULL) { 10517680Spst gctl_error(req, "No '%s' argument.", "nargs"); 10617680Spst return; 10717680Spst } 10817680Spst if (*nargs != 1) { 10917680Spst gctl_error(req, "Invalid number of arguments."); 11017680Spst return; 111146778Ssam } 11298527Sfenner name = gctl_get_asciiparam(req, "arg0"); 11398527Sfenner if (name == NULL) { 11498527Sfenner gctl_error(req, "No 'arg%u' argument.", 0); 11517680Spst return; 11617680Spst } 117146778Ssam sc = g_raid3_find_device(mp, name); 11817680Spst if (sc == NULL) { 11998527Sfenner gctl_error(req, "No such device: %s.", name); 120146778Ssam return; 12198527Sfenner } 12298527Sfenner if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 12398527Sfenner gctl_error(req, "Not all disks connected."); 12498527Sfenner return; 12598527Sfenner } 126146778Ssam autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 12798527Sfenner if (autosync == NULL) { 12817680Spst gctl_error(req, "No '%s' argument.", "autosync"); 129146778Ssam return; 13017680Spst } 13117680Spst noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 13217680Spst if (noautosync == NULL) { 13317680Spst gctl_error(req, "No '%s' argument.", "noautosync"); 13417680Spst return; 13517680Spst } 13617680Spst if (*autosync && *noautosync) { 13717680Spst gctl_error(req, "'%s' and '%s' specified.", "autosync", 13817680Spst "noautosync"); 13917680Spst return; 14017680Spst } 14117680Spst round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 14217680Spst if (round_robin == NULL) { 14317680Spst gctl_error(req, "No '%s' argument.", "round_robin"); 14417680Spst return; 14517680Spst } 14617680Spst noround_robin = gctl_get_paraml(req, "noround_robin", 14717680Spst sizeof(*noround_robin)); 14817680Spst if (noround_robin == NULL) { 14917680Spst gctl_error(req, "No '%s' argument.", "noround_robin"); 15017680Spst return; 15117680Spst } 15298527Sfenner if (*round_robin && *noround_robin) { 153127675Sbms gctl_error(req, "'%s' and '%s' specified.", "round_robin", 15417680Spst "noround_robin"); 15517680Spst return; 15617680Spst } 15717680Spst verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 15817680Spst if (verify == NULL) { 15917680Spst gctl_error(req, "No '%s' argument.", "verify"); 16017680Spst return; 16117680Spst } 16217680Spst noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 16317680Spst if (noverify == NULL) { 16498527Sfenner gctl_error(req, "No '%s' argument.", "noverify"); 165127675Sbms return; 16626183Sfenner } 16717680Spst if (*verify && *noverify) { 16817680Spst gctl_error(req, "'%s' and '%s' specified.", "verify", 16917680Spst "noverify"); 17017680Spst return; 17117680Spst } 17217680Spst if (!*autosync && !*noautosync && !*round_robin && !*noround_robin && 17317680Spst !*verify && !*noverify) { 17498527Sfenner gctl_error(req, "Nothing has changed."); 17517680Spst return; 17617680Spst } 17798527Sfenner if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 17817680Spst if (*autosync) { 17998527Sfenner sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 18017680Spst do_sync = 1; 18117680Spst } 18217680Spst } else { 18317680Spst if (*noautosync) 18417680Spst sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 18517680Spst } 18617680Spst if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 18717680Spst if (*noverify) 18817680Spst sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 18917680Spst } else { 19017680Spst if (*verify) 19117680Spst sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 19217680Spst } 19317680Spst if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 19417680Spst if (*noround_robin) 19517680Spst sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 19617680Spst } else { 19717692Spst if (*round_robin) 19817680Spst sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 19917680Spst } 20017680Spst if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 20117680Spst (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 20217680Spst /* 20317680Spst * VERIFY and ROUND-ROBIN options are mutally exclusive. 20417680Spst */ 20517692Spst sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 20617680Spst } 20717680Spst for (n = 0; n < sc->sc_ndisks; n++) { 20817680Spst disk = &sc->sc_disks[n]; 20917680Spst if (do_sync) { 21017680Spst if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 21117680Spst disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 21217680Spst } 21398527Sfenner g_raid3_update_metadata(disk); 21498527Sfenner if (do_sync) { 21517680Spst if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 21698527Sfenner /* 21717680Spst * XXX: This is probably possible that this 21898527Sfenner * component will not be retasted. 21917680Spst */ 220 g_raid3_event_send(disk, 221 G_RAID3_DISK_STATE_DISCONNECTED, 222 G_RAID3_EVENT_DONTWAIT); 223 } 224 } 225 } 226} 227 228static void 229g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 230{ 231 struct g_raid3_metadata md; 232 struct g_raid3_softc *sc; 233 struct g_raid3_disk *disk; 234 struct g_provider *pp; 235 const char *name; 236 int error, *nargs; 237 238 g_topology_assert(); 239 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 240 if (nargs == NULL) { 241 gctl_error(req, "No '%s' argument.", "nargs"); 242 return; 243 } 244 if (*nargs != 2) { 245 gctl_error(req, "Invalid number of arguments."); 246 return; 247 } 248 name = gctl_get_asciiparam(req, "arg0"); 249 if (name == NULL) { 250 gctl_error(req, "No 'arg%u' argument.", 0); 251 return; 252 } 253 sc = g_raid3_find_device(mp, name); 254 if (sc == NULL) { 255 gctl_error(req, "No such device: %s.", name); 256 return; 257 } 258 name = gctl_get_asciiparam(req, "arg1"); 259 if (name == NULL) { 260 gctl_error(req, "No 'arg%u' argument.", 1); 261 return; 262 } 263 disk = g_raid3_find_disk(sc, name); 264 if (disk == NULL) { 265 gctl_error(req, "No such provider: %s.", name); 266 return; 267 } 268 if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 269 g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 270 gctl_error(req, "There is one stale disk already.", name); 271 return; 272 } 273 /* 274 * Do rebuild by resetting syncid and disconnecting disk. 275 * It'll be retasted, connected to the device and synchronized. 276 */ 277 disk->d_sync.ds_syncid = 0; 278 if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 279 disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 280 g_raid3_update_metadata(disk); 281 pp = disk->d_consumer->provider; 282 error = g_raid3_read_metadata(disk->d_consumer, &md); 283 g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 284 G_RAID3_EVENT_WAIT); 285 if (error != 0) { 286 gctl_error(req, "Cannot read metadata from %s.", pp->name); 287 return; 288 } 289 error = g_raid3_add_disk(sc, pp, &md); 290 if (error != 0) { 291 gctl_error(req, "Cannot reconnect component %s.", pp->name); 292 return; 293 } 294} 295 296static void 297g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 298{ 299 struct g_raid3_softc *sc; 300 int *force, *nargs, error; 301 const char *name; 302 char param[16]; 303 u_int i; 304 305 g_topology_assert(); 306 307 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 308 if (nargs == NULL) { 309 gctl_error(req, "No '%s' argument.", "nargs"); 310 return; 311 } 312 if (*nargs < 1) { 313 gctl_error(req, "Missing device(s)."); 314 return; 315 } 316 force = gctl_get_paraml(req, "force", sizeof(*force)); 317 if (force == NULL) { 318 gctl_error(req, "No '%s' argument.", "force"); 319 return; 320 } 321 322 for (i = 0; i < (u_int)*nargs; i++) { 323 snprintf(param, sizeof(param), "arg%u", i); 324 name = gctl_get_asciiparam(req, param); 325 if (name == NULL) { 326 gctl_error(req, "No 'arg%u' argument.", i); 327 return; 328 } 329 sc = g_raid3_find_device(mp, name); 330 if (sc == NULL) { 331 gctl_error(req, "No such device: %s.", name); 332 return; 333 } 334 error = g_raid3_destroy(sc, *force); 335 if (error != 0) { 336 gctl_error(req, "Cannot destroy device %s (error=%d).", 337 sc->sc_geom->name, error); 338 return; 339 } 340 } 341} 342 343static void 344g_raid3_ctl_insert_orphan(struct g_consumer *cp) 345{ 346 347 KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 348 cp->provider->name)); 349} 350 351static void 352g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 353{ 354 struct g_raid3_metadata md; 355 struct g_raid3_softc *sc; 356 struct g_raid3_disk *disk; 357 struct g_geom *gp; 358 struct g_provider *pp; 359 struct g_consumer *cp; 360 const char *name; 361 u_char *sector; 362 off_t compsize; 363 intmax_t *no; 364 int *hardcode, *nargs, error; 365 366 g_topology_assert(); 367 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 368 if (nargs == NULL) { 369 gctl_error(req, "No '%s' argument.", "nargs"); 370 return; 371 } 372 if (*nargs != 2) { 373 gctl_error(req, "Invalid number of arguments."); 374 return; 375 } 376 name = gctl_get_asciiparam(req, "arg0"); 377 if (name == NULL) { 378 gctl_error(req, "No 'arg%u' argument.", 0); 379 return; 380 } 381 sc = g_raid3_find_device(mp, name); 382 if (sc == NULL) { 383 gctl_error(req, "No such device: %s.", name); 384 return; 385 } 386 no = gctl_get_paraml(req, "number", sizeof(*no)); 387 if (no == NULL) { 388 gctl_error(req, "No '%s' argument.", "no"); 389 return; 390 } 391 if (*no >= sc->sc_ndisks) { 392 gctl_error(req, "Invalid component number."); 393 return; 394 } 395 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 396 if (hardcode == NULL) { 397 gctl_error(req, "No '%s' argument.", "hardcode"); 398 return; 399 } 400 disk = &sc->sc_disks[*no]; 401 if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 402 gctl_error(req, "Component %u is already connected.", *no); 403 return; 404 } 405 name = gctl_get_asciiparam(req, "arg1"); 406 if (name == NULL) { 407 gctl_error(req, "No 'arg%u' argument.", 1); 408 return; 409 } 410 pp = g_provider_by_name(name); 411 if (pp == NULL) { 412 gctl_error(req, "Invalid provider."); 413 return; 414 } 415 if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 416 gctl_error(req, 417 "Cannot insert provider %s, because of its sector size.", 418 pp->name); 419 return; 420 } 421 compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 422 if (compsize > pp->mediasize - pp->sectorsize) { 423 gctl_error(req, "Provider %s too small.", pp->name); 424 return; 425 } 426 if (compsize < pp->mediasize - pp->sectorsize) { 427 gctl_error(req, 428 "warning: %s: only %jd bytes from %jd bytes used.", 429 pp->name, (intmax_t)compsize, 430 (intmax_t)(pp->mediasize - pp->sectorsize)); 431 } 432 gp = g_new_geomf(mp, "raid3:insert"); 433 gp->orphan = g_raid3_ctl_insert_orphan; 434 cp = g_new_consumer(gp); 435 error = g_attach(cp, pp); 436 if (error != 0) { 437 gctl_error(req, "Cannot attach to %s.", pp->name); 438 goto end; 439 } 440 error = g_access(cp, 0, 1, 1); 441 if (error != 0) { 442 gctl_error(req, "Cannot access %s.", pp->name); 443 goto end; 444 } 445 g_raid3_fill_metadata(disk, &md); 446 md.md_syncid = 0; 447 md.md_dflags = 0; 448 if (*hardcode) 449 strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 450 else 451 bzero(md.md_provider, sizeof(md.md_provider)); 452 sector = g_malloc(pp->sectorsize, M_WAITOK); 453 raid3_metadata_encode(&md, sector); 454 g_topology_unlock(); 455 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 456 pp->sectorsize); 457 g_topology_lock(); 458 g_free(sector); 459 if (error != 0) 460 gctl_error(req, "Cannot store metadata on %s.", pp->name); 461end: 462 if (cp->acw > 0) 463 g_access(cp, 0, -1, -1); 464 if (cp->provider != NULL) 465 g_detach(cp); 466 g_destroy_consumer(cp); 467 g_destroy_geom(gp); 468} 469 470static void 471g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 472{ 473 struct g_raid3_softc *sc; 474 struct g_raid3_disk *disk; 475 const char *name; 476 intmax_t *no; 477 int *nargs; 478 479 g_topology_assert(); 480 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 481 if (nargs == NULL) { 482 gctl_error(req, "No '%s' argument.", "nargs"); 483 return; 484 } 485 if (*nargs != 1) { 486 gctl_error(req, "Invalid number of arguments."); 487 return; 488 } 489 name = gctl_get_asciiparam(req, "arg0"); 490 if (name == NULL) { 491 gctl_error(req, "No 'arg%u' argument.", 0); 492 return; 493 } 494 sc = g_raid3_find_device(mp, name); 495 if (sc == NULL) { 496 gctl_error(req, "No such device: %s.", name); 497 return; 498 } 499 no = gctl_get_paraml(req, "number", sizeof(*no)); 500 if (no == NULL) { 501 gctl_error(req, "No '%s' argument.", "no"); 502 return; 503 } 504 if (*no >= sc->sc_ndisks) { 505 gctl_error(req, "Invalid component number."); 506 return; 507 } 508 disk = &sc->sc_disks[*no]; 509 switch (disk->d_state) { 510 case G_RAID3_DISK_STATE_ACTIVE: 511 /* 512 * When replacing ACTIVE component, all the rest has to be also 513 * ACTIVE. 514 */ 515 if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 516 sc->sc_ndisks) { 517 gctl_error(req, "Cannot replace component number %u.", 518 *no); 519 return; 520 } 521 /* FALLTHROUGH */ 522 case G_RAID3_DISK_STATE_STALE: 523 case G_RAID3_DISK_STATE_SYNCHRONIZING: 524 if (g_raid3_clear_metadata(disk) != 0) { 525 gctl_error(req, "Cannot clear metadata on %s.", 526 g_raid3_get_diskname(disk)); 527 } else { 528 g_raid3_event_send(disk, 529 G_RAID3_DISK_STATE_DISCONNECTED, 530 G_RAID3_EVENT_WAIT); 531 } 532 break; 533 case G_RAID3_DISK_STATE_NODISK: 534 break; 535 default: 536 gctl_error(req, "Cannot replace component number %u.", *no); 537 return; 538 } 539} 540 541void 542g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 543{ 544 uint32_t *version; 545 546 g_topology_assert(); 547 548 version = gctl_get_paraml(req, "version", sizeof(*version)); 549 if (version == NULL) { 550 gctl_error(req, "No '%s' argument.", "version"); 551 return; 552 } 553 if (*version != G_RAID3_VERSION) { 554 gctl_error(req, "Userland and kernel parts are out of sync."); 555 return; 556 } 557 558 if (strcmp(verb, "configure") == 0) 559 g_raid3_ctl_configure(req, mp); 560 else if (strcmp(verb, "insert") == 0) 561 g_raid3_ctl_insert(req, mp); 562 else if (strcmp(verb, "rebuild") == 0) 563 g_raid3_ctl_rebuild(req, mp); 564 else if (strcmp(verb, "remove") == 0) 565 g_raid3_ctl_remove(req, mp); 566 else if (strcmp(verb, "stop") == 0) 567 g_raid3_ctl_stop(req, mp); 568 else 569 gctl_error(req, "Unknown verb."); 570} 571