g_raid3_ctl.c revision 134420
1314097Smarius/*- 2314097Smarius * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3314097Smarius * All rights reserved. 4314097Smarius * 5314097Smarius * Redistribution and use in source and binary forms, with or without 6314097Smarius * modification, are permitted provided that the following conditions 7314097Smarius * are met: 8314097Smarius * 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 134420 2004-08-28 02:34:10Z 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 off_t compsize; 342 intmax_t *no; 343 int *hardcode, *nargs, error; 344 345 g_topology_assert(); 346 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 347 if (nargs == NULL) { 348 gctl_error(req, "No '%s' argument.", "nargs"); 349 return; 350 } 351 if (*nargs != 2) { 352 gctl_error(req, "Invalid number of arguments."); 353 return; 354 } 355 name = gctl_get_asciiparam(req, "arg0"); 356 if (name == NULL) { 357 gctl_error(req, "No 'arg%u' argument.", 0); 358 return; 359 } 360 sc = g_raid3_find_device(mp, name); 361 if (sc == NULL) { 362 gctl_error(req, "No such device: %s.", name); 363 return; 364 } 365 no = gctl_get_paraml(req, "number", sizeof(*no)); 366 if (no == NULL) { 367 gctl_error(req, "No '%s' argument.", "no"); 368 return; 369 } 370 if (*no >= sc->sc_ndisks) { 371 gctl_error(req, "Invalid component number."); 372 return; 373 } 374 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 375 if (hardcode == NULL) { 376 gctl_error(req, "No '%s' argument.", "hardcode"); 377 return; 378 } 379 disk = &sc->sc_disks[*no]; 380 if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 381 gctl_error(req, "Component %u is already connected.", *no); 382 return; 383 } 384 name = gctl_get_asciiparam(req, "arg1"); 385 if (name == NULL) { 386 gctl_error(req, "No 'arg%u' argument.", 1); 387 return; 388 } 389 pp = g_provider_by_name(name); 390 if (pp == NULL) { 391 gctl_error(req, "Invalid provider."); 392 return; 393 } 394 if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 395 gctl_error(req, 396 "Cannot insert provider %s, because of its sector size.", 397 pp->name); 398 return; 399 } 400 compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 401 if (compsize > pp->mediasize - pp->sectorsize) { 402 gctl_error(req, "Provider %s too small.", pp->name); 403 return; 404 } 405 if (compsize < pp->mediasize - pp->sectorsize) { 406 gctl_error(req, 407 "warning: %s: only %jd bytes from %jd bytes used.", 408 pp->name, (intmax_t)compsize, 409 (intmax_t)(pp->mediasize - pp->sectorsize)); 410 } 411 gp = g_new_geomf(mp, "raid3:insert"); 412 gp->orphan = g_raid3_ctl_insert_orphan; 413 cp = g_new_consumer(gp); 414 error = g_attach(cp, pp); 415 if (error != 0) { 416 gctl_error(req, "Cannot attach to %s.", pp->name); 417 goto end; 418 } 419 error = g_access(cp, 0, 1, 1); 420 if (error != 0) { 421 gctl_error(req, "Cannot access %s.", pp->name); 422 goto end; 423 } 424 g_raid3_fill_metadata(disk, &md); 425 md.md_syncid = 0; 426 md.md_dflags = 0; 427 if (*hardcode) 428 strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 429 else 430 bzero(md.md_provider, sizeof(md.md_provider)); 431 sector = g_malloc(pp->sectorsize, M_WAITOK); 432 raid3_metadata_encode(&md, sector); 433 g_topology_unlock(); 434 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 435 pp->sectorsize); 436 g_topology_lock(); 437 g_free(sector); 438 if (error != 0) 439 gctl_error(req, "Cannot store metadata on %s.", pp->name); 440end: 441 if (gp != NULL) { 442 if (cp != NULL) { 443 if (cp->acw > 0) 444 g_access(cp, 0, -1, -1); 445 if (cp->provider != NULL) 446 g_detach(cp); 447 g_destroy_consumer(cp); 448 } 449 g_destroy_geom(gp); 450 } 451} 452 453static void 454g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 455{ 456 struct g_raid3_softc *sc; 457 struct g_raid3_disk *disk; 458 const char *name; 459 intmax_t *no; 460 int *nargs; 461 462 g_topology_assert(); 463 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 464 if (nargs == NULL) { 465 gctl_error(req, "No '%s' argument.", "nargs"); 466 return; 467 } 468 if (*nargs != 1) { 469 gctl_error(req, "Invalid number of arguments."); 470 return; 471 } 472 name = gctl_get_asciiparam(req, "arg0"); 473 if (name == NULL) { 474 gctl_error(req, "No 'arg%u' argument.", 0); 475 return; 476 } 477 sc = g_raid3_find_device(mp, name); 478 if (sc == NULL) { 479 gctl_error(req, "No such device: %s.", name); 480 return; 481 } 482 no = gctl_get_paraml(req, "number", sizeof(*no)); 483 if (no == NULL) { 484 gctl_error(req, "No '%s' argument.", "no"); 485 return; 486 } 487 if (*no >= sc->sc_ndisks) { 488 gctl_error(req, "Invalid component number."); 489 return; 490 } 491 disk = &sc->sc_disks[*no]; 492 switch (disk->d_state) { 493 case G_RAID3_DISK_STATE_ACTIVE: 494 /* 495 * When replacing ACTIVE component, all the rest has to be also 496 * ACTIVE. 497 */ 498 if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 499 sc->sc_ndisks) { 500 gctl_error(req, "Cannot replace component number %u.", 501 *no); 502 return; 503 } 504 /* FALLTHROUGH */ 505 case G_RAID3_DISK_STATE_STALE: 506 case G_RAID3_DISK_STATE_SYNCHRONIZING: 507 if (g_raid3_clear_metadata(disk) != 0) { 508 gctl_error(req, "Cannot clear metadata on %s.", 509 g_raid3_get_diskname(disk)); 510 sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 511 } 512 g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 513 G_RAID3_EVENT_WAIT); 514 break; 515 case G_RAID3_DISK_STATE_NODISK: 516 break; 517 default: 518 gctl_error(req, "Cannot replace component number %u.", *no); 519 return; 520 } 521} 522 523void 524g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 525{ 526 uint32_t *version; 527 528 g_topology_assert(); 529 530 version = gctl_get_paraml(req, "version", sizeof(*version)); 531 if (version == NULL) { 532 gctl_error(req, "No '%s' argument.", "version"); 533 return; 534 } 535 if (*version != G_RAID3_VERSION) { 536 gctl_error(req, "Userland and kernel parts are out of sync."); 537 return; 538 } 539 540 if (strcmp(verb, "configure") == 0) 541 g_raid3_ctl_configure(req, mp); 542 else if (strcmp(verb, "insert") == 0) 543 g_raid3_ctl_insert(req, mp); 544 else if (strcmp(verb, "rebuild") == 0) 545 g_raid3_ctl_rebuild(req, mp); 546 else if (strcmp(verb, "remove") == 0) 547 g_raid3_ctl_remove(req, mp); 548 else if (strcmp(verb, "stop") == 0) 549 g_raid3_ctl_stop(req, mp); 550 else 551 gctl_error(req, "Unknown verb."); 552} 553