geom_vinum_init.c revision 145619
1251881Speter/*- 2251881Speter * Copyright (c) 2004 Lukas Ertl 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * Redistribution and use in source and binary forms, with or without 6251881Speter * modification, are permitted provided that the following conditions 7251881Speter * are met: 8251881Speter * 1. Redistributions of source code must retain the above copyright 9251881Speter * notice, this list of conditions and the following disclaimer. 10251881Speter * 2. Redistributions in binary form must reproduce the above copyright 11251881Speter * notice, this list of conditions and the following disclaimer in the 12251881Speter * documentation and/or other materials provided with the distribution. 13251881Speter * 14251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24251881Speter * SUCH DAMAGE. 25251881Speter */ 26251881Speter 27251881Speter#include <sys/cdefs.h> 28251881Speter__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_init.c 145619 2005-04-28 13:09:00Z le $"); 29251881Speter 30251881Speter#include <sys/param.h> 31251881Speter#include <sys/bio.h> 32251881Speter#include <sys/kernel.h> 33251881Speter#include <sys/kthread.h> 34251881Speter#include <sys/libkern.h> 35251881Speter#include <sys/malloc.h> 36251881Speter#include <sys/queue.h> 37251881Speter 38251881Speter#include <geom/geom.h> 39251881Speter#include <geom/vinum/geom_vinum_var.h> 40251881Speter#include <geom/vinum/geom_vinum.h> 41251881Speter#include <geom/vinum/geom_vinum_share.h> 42251881Speter 43251881Speterint gv_init_plex(struct gv_plex *); 44251881Speterint gv_init_sd(struct gv_sd *); 45251881Spetervoid gv_init_td(void *); 46251881Spetervoid gv_rebuild_plex(struct gv_plex *); 47251881Spetervoid gv_rebuild_td(void *); 48251881Spetervoid gv_start_plex(struct gv_plex *); 49251881Spetervoid gv_start_vol(struct gv_volume *); 50251881Spetervoid gv_sync(struct gv_volume *); 51299742Sdimvoid gv_sync_td(void *); 52251881Speter 53251881Speterstruct gv_sync_args { 54251881Speter struct gv_volume *v; 55251881Speter struct gv_plex *from; 56251881Speter struct gv_plex *to; 57251881Speter off_t syncsize; 58299742Sdim}; 59262253Speter 60251881Spetervoid 61299742Sdimgv_parityop(struct g_geom *gp, struct gctl_req *req) 62299742Sdim{ 63299742Sdim struct gv_softc *sc; 64299742Sdim struct gv_plex *p; 65251881Speter struct bio *bp; 66251881Speter struct g_consumer *cp; 67251881Speter int error, *flags, type, *rebuild, rv; 68251881Speter char *plex; 69251881Speter 70251881Speter rv = -1; 71251881Speter 72299742Sdim plex = gctl_get_param(req, "plex", NULL); 73251881Speter if (plex == NULL) { 74251881Speter gctl_error(req, "no plex given"); 75251881Speter goto out; 76251881Speter } 77251881Speter 78251881Speter flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 79251881Speter if (flags == NULL) { 80251881Speter gctl_error(req, "no flags given"); 81251881Speter goto out; 82251881Speter } 83251881Speter 84251881Speter rebuild = gctl_get_paraml(req, "rebuild", sizeof(*rebuild)); 85251881Speter if (rebuild == NULL) { 86251881Speter gctl_error(req, "no rebuild op given"); 87251881Speter goto out; 88251881Speter } 89251881Speter 90251881Speter sc = gp->softc; 91251881Speter type = gv_object_type(sc, plex); 92251881Speter switch (type) { 93251881Speter case GV_TYPE_PLEX: 94251881Speter break; 95251881Speter case GV_TYPE_VOL: 96251881Speter case GV_TYPE_SD: 97251881Speter case GV_TYPE_DRIVE: 98251881Speter default: 99251881Speter gctl_error(req, "'%s' is not a plex", plex); 100251881Speter goto out; 101251881Speter } 102251881Speter 103251881Speter p = gv_find_plex(sc, plex); 104251881Speter if (p->state != GV_PLEX_UP) { 105251881Speter gctl_error(req, "plex %s is not completely accessible", 106251881Speter p->name); 107251881Speter goto out; 108251881Speter } 109251881Speter if (p->org != GV_PLEX_RAID5) { 110251881Speter gctl_error(req, "plex %s is not a RAID5 plex", p->name); 111251881Speter goto out; 112251881Speter } 113299742Sdim 114251881Speter cp = p->consumer; 115299742Sdim error = g_access(cp, 1, 1, 0); 116299742Sdim if (error) { 117299742Sdim gctl_error(req, "cannot access consumer"); 118299742Sdim goto out; 119299742Sdim } 120299742Sdim g_topology_unlock(); 121299742Sdim 122299742Sdim /* Reset the check pointer when using -f. */ 123299742Sdim if (*flags & GV_FLAG_F) 124299742Sdim p->synced = 0; 125299742Sdim 126299742Sdim bp = g_new_bio(); 127299742Sdim if (bp == NULL) { 128299742Sdim gctl_error(req, "cannot create BIO - out of memory"); 129299742Sdim g_topology_lock(); 130299742Sdim error = g_access(cp, -1, -1, 0); 131299742Sdim goto out; 132299742Sdim } 133299742Sdim bp->bio_cmd = BIO_WRITE; 134299742Sdim bp->bio_done = NULL; 135299742Sdim bp->bio_data = g_malloc(p->stripesize, M_WAITOK | M_ZERO); 136299742Sdim bp->bio_cflags |= GV_BIO_CHECK; 137299742Sdim if (*rebuild) 138299742Sdim bp->bio_cflags |= GV_BIO_PARITY; 139299742Sdim bp->bio_offset = p->synced; 140299742Sdim bp->bio_length = p->stripesize; 141299742Sdim 142299742Sdim /* Schedule it down ... */ 143299742Sdim g_io_request(bp, cp); 144299742Sdim 145299742Sdim /* ... and wait for the result. */ 146299742Sdim error = biowait(bp, "gwrite"); 147299742Sdim g_free(bp->bio_data); 148299742Sdim g_destroy_bio(bp); 149299742Sdim 150299742Sdim if (error) { 151299742Sdim /* Incorrect parity. */ 152299742Sdim if (error == EAGAIN) 153299742Sdim rv = 1; 154299742Sdim 155299742Sdim /* Some other error happened. */ 156299742Sdim else 157299742Sdim gctl_error(req, "Parity check failed at offset 0x%jx, " 158251881Speter "errno %d", (intmax_t)p->synced, error); 159251881Speter 160251881Speter /* Correct parity. */ 161251881Speter } else 162251881Speter rv = 0; 163251881Speter 164251881Speter gctl_set_param(req, "offset", &p->synced, sizeof(p->synced)); 165251881Speter 166251881Speter /* Advance the checkpointer if there was no error. */ 167251881Speter if (rv == 0) 168251881Speter p->synced += p->stripesize; 169251881Speter 170251881Speter /* End of plex; reset the check pointer and signal it to the caller. */ 171251881Speter if (p->synced >= p->size) { 172251881Speter p->synced = 0; 173251881Speter rv = -2; 174251881Speter } 175251881Speter 176251881Speter g_topology_lock(); 177251881Speter error = g_access(cp, -1, -1, 0); 178251881Speter 179251881Speterout: 180251881Speter gctl_set_param(req, "rv", &rv, sizeof(rv)); 181251881Speter} 182251881Speter 183251881Spetervoid 184251881Spetergv_start_obj(struct g_geom *gp, struct gctl_req *req) 185251881Speter{ 186251881Speter struct gv_softc *sc; 187251881Speter struct gv_volume *v; 188251881Speter struct gv_plex *p; 189251881Speter int *argc, *initsize; 190251881Speter char *argv, buf[20]; 191251881Speter int i, type; 192251881Speter 193251881Speter argc = gctl_get_paraml(req, "argc", sizeof(*argc)); 194251881Speter initsize = gctl_get_paraml(req, "initsize", sizeof(*initsize)); 195251881Speter 196251881Speter if (argc == NULL || *argc == 0) { 197251881Speter gctl_error(req, "no arguments given"); 198251881Speter return; 199251881Speter } 200251881Speter 201251881Speter sc = gp->softc; 202251881Speter 203251881Speter for (i = 0; i < *argc; i++) { 204251881Speter snprintf(buf, sizeof(buf), "argv%d", i); 205251881Speter argv = gctl_get_param(req, buf, NULL); 206251881Speter if (argv == NULL) 207251881Speter continue; 208251881Speter type = gv_object_type(sc, argv); 209251881Speter switch (type) { 210299742Sdim case GV_TYPE_VOL: 211299742Sdim v = gv_find_vol(sc, argv); 212299742Sdim gv_start_vol(v); 213251881Speter break; 214251881Speter 215251881Speter case GV_TYPE_PLEX: 216251881Speter p = gv_find_plex(sc, argv); 217251881Speter gv_start_plex(p); 218251881Speter break; 219251881Speter 220251881Speter case GV_TYPE_SD: 221251881Speter case GV_TYPE_DRIVE: 222251881Speter /* XXX not yet */ 223251881Speter gctl_error(req, "cannot start '%s'", argv); 224251881Speter return; 225251881Speter default: 226251881Speter gctl_error(req, "unknown object '%s'", argv); 227251881Speter return; 228251881Speter } 229251881Speter } 230251881Speter} 231251881Speter 232251881Spetervoid 233251881Spetergv_start_plex(struct gv_plex *p) 234251881Speter{ 235251881Speter struct gv_volume *v; 236251881Speter 237251881Speter KASSERT(p != NULL, ("gv_start_plex: NULL p")); 238251881Speter 239251881Speter if (p->state == GV_PLEX_UP) 240251881Speter return; 241251881Speter 242251881Speter v = p->vol_sc; 243251881Speter if ((v != NULL) && (v->plexcount > 1)) 244251881Speter gv_sync(v); 245251881Speter else if (p->org == GV_PLEX_RAID5) { 246251881Speter if (p->state == GV_PLEX_DEGRADED) 247251881Speter gv_rebuild_plex(p); 248251881Speter else 249251881Speter gv_init_plex(p); 250251881Speter } 251251881Speter 252251881Speter return; 253251881Speter} 254251881Speter 255251881Spetervoid 256251881Spetergv_start_vol(struct gv_volume *v) 257251881Speter{ 258251881Speter struct gv_plex *p; 259251881Speter struct gv_sd *s; 260251881Speter 261251881Speter KASSERT(v != NULL, ("gv_start_vol: NULL v")); 262251881Speter 263251881Speter if (v->plexcount == 0) 264251881Speter return; 265251881Speter 266251881Speter else if (v->plexcount == 1) { 267251881Speter p = LIST_FIRST(&v->plexes); 268251881Speter KASSERT(p != NULL, ("gv_start_vol: NULL p on %s", v->name)); 269251881Speter if (p->org == GV_PLEX_RAID5) { 270251881Speter switch (p->state) { 271251881Speter case GV_PLEX_DOWN: 272262253Speter gv_init_plex(p); 273251881Speter break; 274299742Sdim case GV_PLEX_DEGRADED: 275299742Sdim gv_rebuild_plex(p); 276299742Sdim break; 277251881Speter default: 278251881Speter return; 279251881Speter } 280251881Speter } else { 281251881Speter LIST_FOREACH(s, &p->subdisks, in_plex) { 282299742Sdim gv_set_sd_state(s, GV_SD_UP, 283251881Speter GV_SETSTATE_CONFIG); 284299742Sdim } 285251881Speter } 286251881Speter } else 287251881Speter gv_sync(v); 288251881Speter} 289251881Speter 290299742Sdimvoid 291251881Spetergv_sync(struct gv_volume *v) 292251881Speter{ 293251881Speter struct gv_softc *sc; 294251881Speter struct gv_plex *p, *up; 295251881Speter struct gv_sync_args *sync; 296251881Speter 297251881Speter KASSERT(v != NULL, ("gv_sync: NULL v")); 298299742Sdim sc = v->vinumconf; 299251881Speter KASSERT(sc != NULL, ("gv_sync: NULL sc on %s", v->name)); 300251881Speter 301251881Speter /* Find the plex that's up. */ 302251881Speter up = NULL; 303251881Speter LIST_FOREACH(up, &v->plexes, in_volume) { 304251881Speter if (up->state == GV_PLEX_UP) 305251881Speter break; 306251881Speter } 307299742Sdim 308299742Sdim /* Didn't find a good plex. */ 309299742Sdim if (up == NULL) 310299742Sdim return; 311299742Sdim 312299742Sdim LIST_FOREACH(p, &v->plexes, in_volume) { 313299742Sdim if ((p == up) || (p->state == GV_PLEX_UP)) 314299742Sdim continue; 315251881Speter sync = g_malloc(sizeof(*sync), M_WAITOK | M_ZERO); 316251881Speter sync->v = v; 317251881Speter sync->from = up; 318251881Speter sync->to = p; 319251881Speter sync->syncsize = GV_DFLT_SYNCSIZE; 320299742Sdim kthread_create(gv_sync_td, sync, NULL, 0, 0, "gv_sync '%s'", 321299742Sdim p->name); 322299742Sdim } 323299742Sdim} 324299742Sdim 325299742Sdimvoid 326299742Sdimgv_rebuild_plex(struct gv_plex *p) 327299742Sdim{ 328299742Sdim struct gv_sync_args *sync; 329299742Sdim 330299742Sdim if ((p->flags & GV_PLEX_SYNCING) || gv_is_open(p->geom)) 331299742Sdim return; 332299742Sdim 333299742Sdim sync = g_malloc(sizeof(*sync), M_WAITOK | M_ZERO); 334299742Sdim sync->to = p; 335299742Sdim sync->syncsize = GV_DFLT_SYNCSIZE; 336299742Sdim 337299742Sdim kthread_create(gv_rebuild_td, sync, NULL, 0, 0, "gv_rebuild %s", 338299742Sdim p->name); 339299742Sdim} 340299742Sdim 341299742Sdimint 342299742Sdimgv_init_plex(struct gv_plex *p) 343299742Sdim{ 344299742Sdim struct gv_sd *s; 345299742Sdim int err; 346251881Speter 347299742Sdim KASSERT(p != NULL, ("gv_init_plex: NULL p")); 348251881Speter 349251881Speter LIST_FOREACH(s, &p->subdisks, in_plex) { 350251881Speter err = gv_init_sd(s); 351251881Speter if (err) 352251881Speter return (err); 353299742Sdim } 354251881Speter 355299742Sdim return (0); 356251881Speter} 357251881Speter 358251881Speterint 359251881Spetergv_init_sd(struct gv_sd *s) 360251881Speter{ 361251881Speter KASSERT(s != NULL, ("gv_init_sd: NULL s")); 362251881Speter 363251881Speter if (gv_set_sd_state(s, GV_SD_INITIALIZING, GV_SETSTATE_FORCE)) 364251881Speter return (-1); 365251881Speter 366251881Speter s->init_size = GV_DFLT_SYNCSIZE; 367251881Speter s->flags &= ~GV_SD_INITCANCEL; 368251881Speter 369251881Speter /* Spawn the thread that does the work for us. */ 370251881Speter kthread_create(gv_init_td, s, NULL, 0, 0, "gv_init %s", s->name); 371251881Speter 372251881Speter return (0); 373251881Speter} 374251881Speter 375251881Speter/* This thread is responsible for rebuilding a degraded RAID5 plex. */ 376251881Spetervoid 377251881Spetergv_rebuild_td(void *arg) 378251881Speter{ 379251881Speter struct bio *bp; 380251881Speter struct gv_plex *p; 381251881Speter struct g_consumer *cp; 382251881Speter struct gv_sync_args *sync; 383251881Speter u_char *buf; 384251881Speter off_t i; 385251881Speter int error; 386251881Speter 387251881Speter buf = NULL; 388251881Speter bp = NULL; 389251881Speter 390251881Speter sync = arg; 391251881Speter p = sync->to; 392251881Speter p->synced = 0; 393251881Speter p->flags |= GV_PLEX_SYNCING; 394251881Speter cp = p->consumer; 395251881Speter 396251881Speter g_topology_lock(); 397251881Speter error = g_access(cp, 1, 1, 0); 398251881Speter if (error) { 399251881Speter g_topology_unlock(); 400251881Speter printf("GEOM_VINUM: rebuild of %s failed to access consumer: " 401299742Sdim "%d\n", p->name, error); 402299742Sdim kthread_exit(error); 403299742Sdim } 404251881Speter g_topology_unlock(); 405251881Speter 406299742Sdim buf = g_malloc(sync->syncsize, M_WAITOK); 407251881Speter 408251881Speter printf("GEOM_VINUM: rebuild of %s started\n", p->name); 409251881Speter i = 0; 410299742Sdim for (i = 0; i < p->size; i += (p->stripesize * (p->sdcount - 1))) { 411299742Sdim/* 412299742Sdim if (i + sync->syncsize > p->size) 413251881Speter sync->syncsize = p->size - i; 414251881Speter*/ 415299742Sdim bp = g_new_bio(); 416251881Speter if (bp == NULL) { 417251881Speter printf("GEOM_VINUM: rebuild of %s failed creating bio: " 418251881Speter "out of memory\n", p->name); 419251881Speter break; 420251881Speter } 421251881Speter bp->bio_cmd = BIO_WRITE; 422251881Speter bp->bio_done = NULL; 423251881Speter bp->bio_data = buf; 424251881Speter bp->bio_cflags |= GV_BIO_REBUILD; 425251881Speter bp->bio_offset = i; 426251881Speter bp->bio_length = p->stripesize; 427251881Speter 428251881Speter /* Schedule it down ... */ 429251881Speter g_io_request(bp, cp); 430251881Speter 431251881Speter /* ... and wait for the result. */ 432251881Speter error = biowait(bp, "gwrite"); 433251881Speter if (error) { 434251881Speter printf("GEOM_VINUM: rebuild of %s failed at offset %jd " 435251881Speter "errno: %d\n", p->name, i, error); 436251881Speter break; 437251881Speter } 438251881Speter g_destroy_bio(bp); 439251881Speter bp = NULL; 440251881Speter } 441251881Speter 442251881Speter if (bp != NULL) 443251881Speter g_destroy_bio(bp); 444251881Speter if (buf != NULL) 445251881Speter g_free(buf); 446251881Speter 447251881Speter g_topology_lock(); 448251881Speter g_access(cp, -1, -1, 0); 449251881Speter gv_save_config_all(p->vinumconf); 450251881Speter g_topology_unlock(); 451251881Speter 452251881Speter p->flags &= ~GV_PLEX_SYNCING; 453251881Speter p->synced = 0; 454251881Speter 455251881Speter /* Successful initialization. */ 456251881Speter if (!error) 457251881Speter printf("GEOM_VINUM: rebuild of %s finished\n", p->name); 458251881Speter 459251881Speter g_free(sync); 460251881Speter kthread_exit(error); 461251881Speter} 462251881Speter 463251881Spetervoid 464251881Spetergv_sync_td(void *arg) 465251881Speter{ 466251881Speter struct bio *bp; 467251881Speter struct gv_plex *p; 468251881Speter struct g_consumer *from, *to; 469251881Speter struct gv_sync_args *sync; 470251881Speter u_char *buf; 471251881Speter off_t i; 472251881Speter int error; 473251881Speter 474251881Speter sync = arg; 475299742Sdim 476299742Sdim from = sync->from->consumer; 477299742Sdim to = sync->to->consumer; 478299742Sdim 479299742Sdim p = sync->to; 480299742Sdim 481299742Sdim if (p->flags & GV_PLEX_SYNCING) { 482299742Sdim printf("GEOM_VINUM: plex '%s' is already syncing.\n", p->name); 483299742Sdim g_free(sync); 484299742Sdim kthread_exit(0); 485299742Sdim } 486299742Sdim 487299742Sdim p->synced = 0; 488299742Sdim p->flags |= GV_PLEX_SYNCING; 489251881Speter 490299742Sdim error = 0; 491299742Sdim 492299742Sdim g_topology_lock(); 493251881Speter error = g_access(from, 1, 0, 0); 494299742Sdim if (error) { 495299742Sdim g_topology_unlock(); 496299742Sdim printf("GEOM_VINUM: sync from '%s' failed to access " 497299742Sdim "consumer: %d\n", sync->from->name, error); 498299742Sdim g_free(sync); 499251881Speter kthread_exit(error); 500299742Sdim } 501299742Sdim error = g_access(to, 0, 1, 0); 502299742Sdim if (error) { 503299742Sdim g_access(from, -1, 0, 0); 504299742Sdim g_topology_unlock(); 505299742Sdim printf("GEOM_VINUM: sync to '%s' failed to access " 506251881Speter "consumer: %d\n", p->name, error); 507299742Sdim g_free(sync); 508299742Sdim kthread_exit(error); 509299742Sdim } 510299742Sdim g_topology_unlock(); 511299742Sdim 512251881Speter printf("GEOM_VINUM: plex sync %s -> %s started\n", sync->from->name, 513299742Sdim sync->to->name); 514299742Sdim for (i = 0; i < p->size; i+= sync->syncsize) { 515299742Sdim /* Read some bits from the good plex. */ 516299742Sdim buf = g_read_data(from, i, sync->syncsize, &error); 517299742Sdim if (buf == NULL) { 518299742Sdim printf("GEOM_VINUM: sync read from '%s' failed at " 519299742Sdim "offset %jd; errno: %d\n", sync->from->name, i, 520299742Sdim error); 521299742Sdim break; 522299742Sdim } 523299742Sdim 524299742Sdim /* 525299742Sdim * Create a bio and schedule it down on the 'bad' plex. We 526251881Speter * cannot simply use g_write_data() because we have to let the 527251881Speter * lower parts know that we are an initialization process and 528299742Sdim * not a 'normal' request. 529299742Sdim */ 530299742Sdim bp = g_new_bio(); 531251881Speter if (bp == NULL) { 532299742Sdim printf("GEOM_VINUM: sync write to '%s' failed at " 533251881Speter "offset %jd; out of memory\n", p->name, i); 534299742Sdim g_free(buf); 535251881Speter break; 536251881Speter } 537299742Sdim bp->bio_cmd = BIO_WRITE; 538299742Sdim bp->bio_offset = i; 539299742Sdim bp->bio_length = sync->syncsize; 540299742Sdim bp->bio_data = buf; 541299742Sdim bp->bio_done = NULL; 542299742Sdim 543299742Sdim /* 544299742Sdim * This hack declare this bio as part of an initialization 545299742Sdim * process, so that the lower levels allow it to get through. 546299742Sdim */ 547251881Speter bp->bio_cflags |= GV_BIO_SYNCREQ; 548299742Sdim 549299742Sdim /* Schedule it down ... */ 550299742Sdim g_io_request(bp, to); 551299742Sdim 552299742Sdim /* ... and wait for the result. */ 553299742Sdim error = biowait(bp, "gwrite"); 554299742Sdim g_destroy_bio(bp); 555299742Sdim g_free(buf); 556299742Sdim if (error) { 557299742Sdim printf("GEOM_VINUM: sync write to '%s' failed at " 558299742Sdim "offset %jd; errno: %d\n", p->name, i, error); 559299742Sdim break; 560299742Sdim } 561299742Sdim 562299742Sdim /* Note that we have synced a little bit more. */ 563299742Sdim p->synced += sync->syncsize; 564299742Sdim } 565299742Sdim 566299742Sdim g_topology_lock(); 567251881Speter g_access(from, -1, 0, 0); 568299742Sdim g_access(to, 0, -1, 0); 569299742Sdim gv_save_config_all(p->vinumconf); 570299742Sdim g_topology_unlock(); 571299742Sdim 572299742Sdim /* Successful initialization. */ 573299742Sdim if (!error) 574299742Sdim printf("GEOM_VINUM: plex sync %s -> %s finished\n", 575299742Sdim sync->from->name, sync->to->name); 576299742Sdim 577299742Sdim p->flags &= ~GV_PLEX_SYNCING; 578299742Sdim p->synced = 0; 579299742Sdim 580299742Sdim g_free(sync); 581299742Sdim kthread_exit(error); 582299742Sdim} 583299742Sdim 584299742Sdimvoid 585299742Sdimgv_init_td(void *arg) 586299742Sdim{ 587299742Sdim struct gv_sd *s; 588299742Sdim struct gv_drive *d; 589251881Speter struct g_geom *gp; 590251881Speter struct g_consumer *cp; 591299742Sdim int error; 592299742Sdim off_t i, init_size, start, offset, length; 593299742Sdim u_char *buf; 594251881Speter 595299742Sdim s = arg; 596251881Speter KASSERT(s != NULL, ("gv_init_td: NULL s")); 597299742Sdim d = s->drive_sc; 598299742Sdim KASSERT(d != NULL, ("gv_init_td: NULL d")); 599299742Sdim gp = d->geom; 600299742Sdim KASSERT(gp != NULL, ("gv_init_td: NULL gp")); 601299742Sdim 602299742Sdim cp = LIST_FIRST(&gp->consumer); 603299742Sdim KASSERT(cp != NULL, ("gv_init_td: NULL cp")); 604299742Sdim 605299742Sdim s->init_error = 0; 606299742Sdim init_size = s->init_size; 607299742Sdim start = s->drive_offset + s->initialized; 608299742Sdim offset = s->drive_offset; 609299742Sdim length = s->size; 610299742Sdim 611299742Sdim buf = g_malloc(s->init_size, M_WAITOK | M_ZERO); 612299742Sdim 613299742Sdim g_topology_lock(); 614299742Sdim error = g_access(cp, 0, 1, 0); 615251881Speter if (error) { 616251881Speter s->init_error = error; 617299742Sdim g_topology_unlock(); 618251881Speter printf("geom_vinum: init '%s' failed to access consumer: %d\n", 619251881Speter s->name, error); 620251881Speter kthread_exit(error); 621251881Speter } 622251881Speter g_topology_unlock(); 623251881Speter 624251881Speter for (i = start; i < offset + length; i += init_size) { 625251881Speter if (s->flags & GV_SD_INITCANCEL) { 626251881Speter printf("geom_vinum: subdisk '%s' init: cancelled at" 627251881Speter " offset %jd (drive offset %jd)\n", s->name, 628262253Speter (intmax_t)s->initialized, (intmax_t)i); 629251881Speter error = EAGAIN; 630262253Speter break; 631251881Speter } 632251881Speter error = g_write_data(cp, i, buf, init_size); 633251881Speter if (error) { 634251881Speter printf("geom_vinum: subdisk '%s' init: write failed" 635251881Speter " at offset %jd (drive offset %jd)\n", s->name, 636251881Speter (intmax_t)s->initialized, (intmax_t)i); 637251881Speter break; 638251881Speter } 639251881Speter s->initialized += init_size; 640251881Speter } 641251881Speter 642251881Speter g_free(buf); 643251881Speter 644251881Speter g_topology_lock(); 645251881Speter g_access(cp, 0, -1, 0); 646251881Speter g_topology_unlock(); 647251881Speter if (error) { 648251881Speter s->init_error = error; 649251881Speter g_topology_lock(); 650251881Speter gv_set_sd_state(s, GV_SD_STALE, 651251881Speter GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); 652251881Speter g_topology_unlock(); 653251881Speter } else { 654251881Speter g_topology_lock(); 655262253Speter gv_set_sd_state(s, GV_SD_UP, GV_SETSTATE_CONFIG); 656251881Speter g_topology_unlock(); 657251881Speter s->initialized = 0; 658251881Speter printf("geom_vinum: init '%s' finished\n", s->name); 659299742Sdim } 660299742Sdim kthread_exit(error); 661299742Sdim} 662299742Sdim