1 /* $NetBSD: ccd.c,v 1.168 2016/11/20 02:35:19 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe, and by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1988 University of Utah. 34 * Copyright (c) 1990, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * the Systems Programming Group of the University of Utah Computer 39 * Science Department. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * from: Utah $Hdr: cd.c 1.6 90/11/28$ 66 * 67 * @(#)cd.c 8.2 (Berkeley) 11/16/93 68 */ 69 70 /* 71 * "Concatenated" disk driver. 72 * 73 * Notes on concurrency: 74 * 75 * => sc_dvlock serializes access to the device nodes, excluding block I/O. 76 * 77 * => sc_iolock serializes access to (sc_flags & CCDF_INITED), disk stats, 78 * sc_stop, sc_bufq and b_resid from master buffers. 79 * 80 * => a combination of CCDF_INITED, sc_inflight, and sc_iolock is used to 81 * serialize I/O and configuration changes. 82 * 83 * => the in-core disk label does not change while the device is open. 84 * 85 * On memory consumption: ccd fans out I/O requests and so needs to 86 * allocate memory. If the system is desperately low on memory, we 87 * single thread I/O. 88 */ 89 90 #include <sys/cdefs.h> 91 __KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.168 2016/11/20 02:35:19 pgoyette Exp $"); 92 93 #if defined(_KERNEL_OPT) 94 #include "opt_compat_netbsd.h" 95 #endif 96 97 #include <sys/param.h> 98 #include <sys/systm.h> 99 #include <sys/kernel.h> 100 #include <sys/proc.h> 101 #include <sys/errno.h> 102 #include <sys/buf.h> 103 #include <sys/kmem.h> 104 #include <sys/pool.h> 105 #include <sys/module.h> 106 #include <sys/namei.h> 107 #include <sys/stat.h> 108 #include <sys/ioctl.h> 109 #include <sys/disklabel.h> 110 #include <sys/device.h> 111 #include <sys/disk.h> 112 #include <sys/syslog.h> 113 #include <sys/fcntl.h> 114 #include <sys/vnode.h> 115 #include <sys/conf.h> 116 #include <sys/mutex.h> 117 #include <sys/queue.h> 118 #include <sys/kauth.h> 119 #include <sys/kthread.h> 120 #include <sys/bufq.h> 121 #include <sys/sysctl.h> 122 123 #include <uvm/uvm_extern.h> 124 125 #include <dev/ccdvar.h> 126 #include <dev/dkvar.h> 127 128 #include <miscfs/specfs/specdev.h> /* for v_rdev */ 129 130 #include "ioconf.h" 131 132 #if defined(CCDDEBUG) && !defined(DEBUG) 133 #define DEBUG 134 #endif 135 136 #ifdef DEBUG 137 #define CCDB_FOLLOW 0x01 138 #define CCDB_INIT 0x02 139 #define CCDB_IO 0x04 140 #define CCDB_LABEL 0x08 141 #define CCDB_VNODE 0x10 142 int ccddebug = 0x00; 143 #endif 144 145 #define ccdunit(x) DISKUNIT(x) 146 147 struct ccdbuf { 148 struct buf cb_buf; /* new I/O buf */ 149 struct buf *cb_obp; /* ptr. to original I/O buf */ 150 struct ccd_softc *cb_sc; /* pointer to ccd softc */ 151 int cb_comp; /* target component */ 152 SIMPLEQ_ENTRY(ccdbuf) cb_q; /* fifo of component buffers */ 153 }; 154 155 /* component buffer pool */ 156 static pool_cache_t ccd_cache; 157 158 #define CCD_GETBUF() pool_cache_get(ccd_cache, PR_WAITOK) 159 #define CCD_PUTBUF(cbp) pool_cache_put(ccd_cache, cbp) 160 161 #define CCDLABELDEV(dev) \ 162 (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART)) 163 164 /* called by main() at boot time */ 165 void ccddetach(void); 166 167 /* called by biodone() at interrupt time */ 168 static void ccdiodone(struct buf *); 169 170 static void ccdinterleave(struct ccd_softc *); 171 static int ccdinit(struct ccd_softc *, char **, struct vnode **, 172 struct lwp *); 173 static struct ccdbuf *ccdbuffer(struct ccd_softc *, struct buf *, 174 daddr_t, void *, long); 175 static void ccdgetdefaultlabel(struct ccd_softc *, struct disklabel *); 176 static void ccdgetdisklabel(dev_t); 177 static void ccdmakedisklabel(struct ccd_softc *); 178 static void ccdstart(struct ccd_softc *); 179 static void ccdthread(void *); 180 181 static dev_type_open(ccdopen); 182 static dev_type_close(ccdclose); 183 static dev_type_read(ccdread); 184 static dev_type_write(ccdwrite); 185 static dev_type_ioctl(ccdioctl); 186 static dev_type_strategy(ccdstrategy); 187 static dev_type_size(ccdsize); 188 189 const struct bdevsw ccd_bdevsw = { 190 .d_open = ccdopen, 191 .d_close = ccdclose, 192 .d_strategy = ccdstrategy, 193 .d_ioctl = ccdioctl, 194 .d_dump = nodump, 195 .d_psize = ccdsize, 196 .d_discard = nodiscard, 197 .d_flag = D_DISK | D_MPSAFE 198 }; 199 200 const struct cdevsw ccd_cdevsw = { 201 .d_open = ccdopen, 202 .d_close = ccdclose, 203 .d_read = ccdread, 204 .d_write = ccdwrite, 205 .d_ioctl = ccdioctl, 206 .d_stop = nostop, 207 .d_tty = notty, 208 .d_poll = nopoll, 209 .d_mmap = nommap, 210 .d_kqfilter = nokqfilter, 211 .d_discard = nodiscard, 212 .d_flag = D_DISK | D_MPSAFE 213 }; 214 215 #ifdef DEBUG 216 static void printiinfo(struct ccdiinfo *); 217 #endif 218 219 static LIST_HEAD(, ccd_softc) ccds = LIST_HEAD_INITIALIZER(ccds); 220 static kmutex_t ccd_lock; 221 static size_t ccd_nactive = 0; 222 223 #ifdef _MODULE 224 static struct sysctllog *ccd_clog; 225 #endif 226 227 SYSCTL_SETUP_PROTO(sysctl_kern_ccd_setup); 228 229 static struct ccd_softc * 230 ccdcreate(int unit) { 231 struct ccd_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); 232 if (sc == NULL) { 233 #ifdef DIAGNOSTIC 234 printf("%s: out of memory\n", __func__); 235 #endif 236 return NULL; 237 } 238 /* Initialize per-softc structures. */ 239 snprintf(sc->sc_xname, sizeof(sc->sc_xname), "ccd%d", unit); 240 sc->sc_unit = unit; 241 mutex_init(&sc->sc_dvlock, MUTEX_DEFAULT, IPL_NONE); 242 sc->sc_iolock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); 243 cv_init(&sc->sc_stop, "ccdstop"); 244 cv_init(&sc->sc_push, "ccdthr"); 245 disk_init(&sc->sc_dkdev, sc->sc_xname, NULL); /* XXX */ 246 return sc; 247 } 248 249 static void 250 ccddestroy(struct ccd_softc *sc) { 251 mutex_obj_free(sc->sc_iolock); 252 mutex_exit(&sc->sc_dvlock); 253 mutex_destroy(&sc->sc_dvlock); 254 cv_destroy(&sc->sc_stop); 255 cv_destroy(&sc->sc_push); 256 disk_destroy(&sc->sc_dkdev); 257 kmem_free(sc, sizeof(*sc)); 258 } 259 260 static struct ccd_softc * 261 ccdget(int unit, int make) { 262 struct ccd_softc *sc; 263 if (unit < 0) { 264 #ifdef DIAGNOSTIC 265 panic("%s: unit %d!", __func__, unit); 266 #endif 267 return NULL; 268 } 269 mutex_enter(&ccd_lock); 270 LIST_FOREACH(sc, &ccds, sc_link) { 271 if (sc->sc_unit == unit) { 272 mutex_exit(&ccd_lock); 273 return sc; 274 } 275 } 276 mutex_exit(&ccd_lock); 277 if (!make) 278 return NULL; 279 if ((sc = ccdcreate(unit)) == NULL) 280 return NULL; 281 mutex_enter(&ccd_lock); 282 LIST_INSERT_HEAD(&ccds, sc, sc_link); 283 ccd_nactive++; 284 mutex_exit(&ccd_lock); 285 return sc; 286 } 287 288 static void 289 ccdput(struct ccd_softc *sc) { 290 mutex_enter(&ccd_lock); 291 LIST_REMOVE(sc, sc_link); 292 ccd_nactive--; 293 mutex_exit(&ccd_lock); 294 ccddestroy(sc); 295 } 296 297 /* 298 * Called by main() during pseudo-device attachment. All we need 299 * to do is allocate enough space for devices to be configured later. 300 */ 301 void 302 ccdattach(int num) 303 { 304 mutex_init(&ccd_lock, MUTEX_DEFAULT, IPL_NONE); 305 306 /* Initialize the component buffer pool. */ 307 ccd_cache = pool_cache_init(sizeof(struct ccdbuf), 0, 308 0, 0, "ccdbuf", NULL, IPL_BIO, NULL, NULL, NULL); 309 } 310 311 void 312 ccddetach(void) 313 { 314 pool_cache_destroy(ccd_cache); 315 mutex_destroy(&ccd_lock); 316 } 317 318 static int 319 ccdinit(struct ccd_softc *cs, char **cpaths, struct vnode **vpp, 320 struct lwp *l) 321 { 322 struct ccdcinfo *ci = NULL; 323 int ix; 324 struct ccdgeom *ccg = &cs->sc_geom; 325 char *tmppath; 326 int error, path_alloced; 327 uint64_t psize, minsize; 328 unsigned secsize, maxsecsize; 329 struct disk_geom *dg; 330 331 #ifdef DEBUG 332 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 333 printf("%s: ccdinit\n", cs->sc_xname); 334 #endif 335 336 /* Allocate space for the component info. */ 337 cs->sc_cinfo = kmem_alloc(cs->sc_nccdisks * sizeof(*cs->sc_cinfo), 338 KM_SLEEP); 339 tmppath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 340 341 cs->sc_size = 0; 342 343 /* 344 * Verify that each component piece exists and record 345 * relevant information about it. 346 */ 347 maxsecsize = 0; 348 minsize = 0; 349 for (ix = 0, path_alloced = 0; ix < cs->sc_nccdisks; ix++) { 350 ci = &cs->sc_cinfo[ix]; 351 ci->ci_vp = vpp[ix]; 352 353 /* 354 * Copy in the pathname of the component. 355 */ 356 memset(tmppath, 0, MAXPATHLEN); /* sanity */ 357 error = copyinstr(cpaths[ix], tmppath, 358 MAXPATHLEN, &ci->ci_pathlen); 359 if (ci->ci_pathlen == 0) 360 error = EINVAL; 361 if (error) { 362 #ifdef DEBUG 363 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 364 printf("%s: can't copy path, error = %d\n", 365 cs->sc_xname, error); 366 #endif 367 goto out; 368 } 369 ci->ci_path = kmem_alloc(ci->ci_pathlen, KM_SLEEP); 370 memcpy(ci->ci_path, tmppath, ci->ci_pathlen); 371 path_alloced++; 372 373 /* 374 * XXX: Cache the component's dev_t. 375 */ 376 ci->ci_dev = vpp[ix]->v_rdev; 377 378 /* 379 * Get partition information for the component. 380 */ 381 error = getdisksize(vpp[ix], &psize, &secsize); 382 if (error) { 383 #ifdef DEBUG 384 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 385 printf("%s: %s: disksize failed, error = %d\n", 386 cs->sc_xname, ci->ci_path, error); 387 #endif 388 goto out; 389 } 390 391 /* 392 * Calculate the size, truncating to an interleave 393 * boundary if necessary. 394 */ 395 maxsecsize = secsize > maxsecsize ? secsize : maxsecsize; 396 if (cs->sc_ileave > 1) 397 psize -= psize % cs->sc_ileave; 398 399 if (psize == 0) { 400 #ifdef DEBUG 401 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 402 printf("%s: %s: size == 0\n", 403 cs->sc_xname, ci->ci_path); 404 #endif 405 error = ENODEV; 406 goto out; 407 } 408 409 if (minsize == 0 || psize < minsize) 410 minsize = psize; 411 ci->ci_size = psize; 412 cs->sc_size += psize; 413 } 414 415 /* 416 * Don't allow the interleave to be smaller than 417 * the biggest component sector. 418 */ 419 if ((cs->sc_ileave > 0) && 420 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 421 #ifdef DEBUG 422 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 423 printf("%s: interleave must be at least %d\n", 424 cs->sc_xname, (maxsecsize / DEV_BSIZE)); 425 #endif 426 error = EINVAL; 427 goto out; 428 } 429 430 /* 431 * If uniform interleave is desired set all sizes to that of 432 * the smallest component. 433 */ 434 if (cs->sc_flags & CCDF_UNIFORM) { 435 for (ci = cs->sc_cinfo; 436 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 437 ci->ci_size = minsize; 438 439 cs->sc_size = cs->sc_nccdisks * minsize; 440 } 441 442 /* 443 * Construct the interleave table. 444 */ 445 ccdinterleave(cs); 446 447 /* 448 * Create pseudo-geometry based on 1MB cylinders. It's 449 * pretty close. 450 */ 451 ccg->ccg_secsize = DEV_BSIZE; 452 ccg->ccg_ntracks = 1; 453 ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); 454 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 455 456 dg = &cs->sc_dkdev.dk_geom; 457 memset(dg, 0, sizeof(*dg)); 458 dg->dg_secperunit = cs->sc_size; 459 dg->dg_secsize = ccg->ccg_secsize; 460 dg->dg_nsectors = ccg->ccg_nsectors; 461 dg->dg_ntracks = ccg->ccg_ntracks; 462 dg->dg_ncylinders = ccg->ccg_ncylinders; 463 464 if (cs->sc_ileave > 0) 465 aprint_normal("%s: Interleaving %d component%s " 466 "(%d block interleave)\n", cs->sc_xname, 467 cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : ""), 468 cs->sc_ileave); 469 else 470 aprint_normal("%s: Concatenating %d component%s\n", 471 cs->sc_xname, 472 cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : "")); 473 for (ix = 0; ix < cs->sc_nccdisks; ix++) { 474 ci = &cs->sc_cinfo[ix]; 475 aprint_normal("%s: %s (%ju blocks)\n", cs->sc_xname, 476 ci->ci_path, (uintmax_t)ci->ci_size); 477 } 478 aprint_normal("%s: total %ju blocks\n", cs->sc_xname, cs->sc_size); 479 480 /* 481 * Create thread to handle deferred I/O. 482 */ 483 cs->sc_zap = false; 484 error = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, ccdthread, 485 cs, &cs->sc_thread, "%s", cs->sc_xname); 486 if (error) { 487 printf("ccdinit: can't create thread: %d\n", error); 488 goto out; 489 } 490 491 /* 492 * Only now that everything is set up can we enable the device. 493 */ 494 mutex_enter(cs->sc_iolock); 495 cs->sc_flags |= CCDF_INITED; 496 mutex_exit(cs->sc_iolock); 497 kmem_free(tmppath, MAXPATHLEN); 498 return (0); 499 500 out: 501 for (ix = 0; ix < path_alloced; ix++) { 502 kmem_free(cs->sc_cinfo[ix].ci_path, 503 cs->sc_cinfo[ix].ci_pathlen); 504 } 505 kmem_free(cs->sc_cinfo, cs->sc_nccdisks * sizeof(struct ccdcinfo)); 506 kmem_free(tmppath, MAXPATHLEN); 507 return (error); 508 } 509 510 static void 511 ccdinterleave(struct ccd_softc *cs) 512 { 513 struct ccdcinfo *ci, *smallci; 514 struct ccdiinfo *ii; 515 daddr_t bn, lbn; 516 int ix; 517 u_long size; 518 519 #ifdef DEBUG 520 if (ccddebug & CCDB_INIT) 521 printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave); 522 #endif 523 /* 524 * Allocate an interleave table. 525 * Chances are this is too big, but we don't care. 526 */ 527 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 528 cs->sc_itable = kmem_zalloc(size, KM_SLEEP); 529 530 /* 531 * Trivial case: no interleave (actually interleave of disk size). 532 * Each table entry represents a single component in its entirety. 533 */ 534 if (cs->sc_ileave == 0) { 535 bn = 0; 536 ii = cs->sc_itable; 537 538 for (ix = 0; ix < cs->sc_nccdisks; ix++) { 539 /* Allocate space for ii_index. */ 540 ii->ii_indexsz = sizeof(int); 541 ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP); 542 ii->ii_ndisk = 1; 543 ii->ii_startblk = bn; 544 ii->ii_startoff = 0; 545 ii->ii_index[0] = ix; 546 bn += cs->sc_cinfo[ix].ci_size; 547 ii++; 548 } 549 ii->ii_ndisk = 0; 550 #ifdef DEBUG 551 if (ccddebug & CCDB_INIT) 552 printiinfo(cs->sc_itable); 553 #endif 554 return; 555 } 556 557 /* 558 * The following isn't fast or pretty; it doesn't have to be. 559 */ 560 size = 0; 561 bn = lbn = 0; 562 for (ii = cs->sc_itable; ; ii++) { 563 /* Allocate space for ii_index. */ 564 ii->ii_indexsz = sizeof(int) * cs->sc_nccdisks; 565 ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP); 566 567 /* 568 * Locate the smallest of the remaining components 569 */ 570 smallci = NULL; 571 for (ci = cs->sc_cinfo; 572 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 573 if (ci->ci_size > size && 574 (smallci == NULL || 575 ci->ci_size < smallci->ci_size)) 576 smallci = ci; 577 578 /* 579 * Nobody left, all done 580 */ 581 if (smallci == NULL) { 582 ii->ii_ndisk = 0; 583 break; 584 } 585 586 /* 587 * Record starting logical block and component offset 588 */ 589 ii->ii_startblk = bn / cs->sc_ileave; 590 ii->ii_startoff = lbn; 591 592 /* 593 * Determine how many disks take part in this interleave 594 * and record their indices. 595 */ 596 ix = 0; 597 for (ci = cs->sc_cinfo; 598 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 599 if (ci->ci_size >= smallci->ci_size) 600 ii->ii_index[ix++] = ci - cs->sc_cinfo; 601 ii->ii_ndisk = ix; 602 bn += ix * (smallci->ci_size - size); 603 lbn = smallci->ci_size / cs->sc_ileave; 604 size = smallci->ci_size; 605 } 606 #ifdef DEBUG 607 if (ccddebug & CCDB_INIT) 608 printiinfo(cs->sc_itable); 609 #endif 610 } 611 612 /* ARGSUSED */ 613 static int 614 ccdopen(dev_t dev, int flags, int fmt, struct lwp *l) 615 { 616 int unit = ccdunit(dev); 617 struct ccd_softc *cs; 618 struct disklabel *lp; 619 int error = 0, part, pmask; 620 621 #ifdef DEBUG 622 if (ccddebug & CCDB_FOLLOW) 623 printf("ccdopen(0x%"PRIx64", 0x%x)\n", dev, flags); 624 #endif 625 if ((cs = ccdget(unit, 1)) == NULL) 626 return ENXIO; 627 628 mutex_enter(&cs->sc_dvlock); 629 630 lp = cs->sc_dkdev.dk_label; 631 632 part = DISKPART(dev); 633 pmask = (1 << part); 634 635 /* 636 * If we're initialized, check to see if there are any other 637 * open partitions. If not, then it's safe to update 638 * the in-core disklabel. Only read the disklabel if it is 639 * not already valid. 640 */ 641 if ((cs->sc_flags & (CCDF_INITED|CCDF_VLABEL)) == CCDF_INITED && 642 cs->sc_dkdev.dk_openmask == 0) 643 ccdgetdisklabel(dev); 644 645 /* Check that the partition exists. */ 646 if (part != RAW_PART) { 647 if (((cs->sc_flags & CCDF_INITED) == 0) || 648 ((part >= lp->d_npartitions) || 649 (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 650 error = ENXIO; 651 goto done; 652 } 653 } 654 655 /* Prevent our unit from being unconfigured while open. */ 656 switch (fmt) { 657 case S_IFCHR: 658 cs->sc_dkdev.dk_copenmask |= pmask; 659 break; 660 661 case S_IFBLK: 662 cs->sc_dkdev.dk_bopenmask |= pmask; 663 break; 664 } 665 cs->sc_dkdev.dk_openmask = 666 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 667 668 done: 669 mutex_exit(&cs->sc_dvlock); 670 return (error); 671 } 672 673 /* ARGSUSED */ 674 static int 675 ccdclose(dev_t dev, int flags, int fmt, struct lwp *l) 676 { 677 int unit = ccdunit(dev); 678 struct ccd_softc *cs; 679 int part; 680 681 #ifdef DEBUG 682 if (ccddebug & CCDB_FOLLOW) 683 printf("ccdclose(0x%"PRIx64", 0x%x)\n", dev, flags); 684 #endif 685 686 if ((cs = ccdget(unit, 0)) == NULL) 687 return ENXIO; 688 689 mutex_enter(&cs->sc_dvlock); 690 691 part = DISKPART(dev); 692 693 /* ...that much closer to allowing unconfiguration... */ 694 switch (fmt) { 695 case S_IFCHR: 696 cs->sc_dkdev.dk_copenmask &= ~(1 << part); 697 break; 698 699 case S_IFBLK: 700 cs->sc_dkdev.dk_bopenmask &= ~(1 << part); 701 break; 702 } 703 cs->sc_dkdev.dk_openmask = 704 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 705 706 if (cs->sc_dkdev.dk_openmask == 0) { 707 if ((cs->sc_flags & CCDF_KLABEL) == 0) 708 cs->sc_flags &= ~CCDF_VLABEL; 709 } 710 711 mutex_exit(&cs->sc_dvlock); 712 return (0); 713 } 714 715 static bool 716 ccdbackoff(struct ccd_softc *cs) 717 { 718 719 /* XXX Arbitrary, should be a uvm call. */ 720 return uvmexp.free < (uvmexp.freemin >> 1) && 721 disk_isbusy(&cs->sc_dkdev); 722 } 723 724 static void 725 ccdthread(void *cookie) 726 { 727 struct ccd_softc *cs; 728 729 cs = cookie; 730 731 #ifdef DEBUG 732 if (ccddebug & CCDB_FOLLOW) 733 printf("ccdthread: hello\n"); 734 #endif 735 736 mutex_enter(cs->sc_iolock); 737 while (__predict_true(!cs->sc_zap)) { 738 if (bufq_peek(cs->sc_bufq) == NULL) { 739 /* Nothing to do. */ 740 cv_wait(&cs->sc_push, cs->sc_iolock); 741 continue; 742 } 743 if (ccdbackoff(cs)) { 744 /* Wait for memory to become available. */ 745 (void)cv_timedwait(&cs->sc_push, cs->sc_iolock, 1); 746 continue; 747 } 748 #ifdef DEBUG 749 if (ccddebug & CCDB_FOLLOW) 750 printf("ccdthread: dispatching I/O\n"); 751 #endif 752 ccdstart(cs); 753 mutex_enter(cs->sc_iolock); 754 } 755 cs->sc_thread = NULL; 756 mutex_exit(cs->sc_iolock); 757 #ifdef DEBUG 758 if (ccddebug & CCDB_FOLLOW) 759 printf("ccdthread: goodbye\n"); 760 #endif 761 kthread_exit(0); 762 } 763 764 static void 765 ccdstrategy(struct buf *bp) 766 { 767 int unit = ccdunit(bp->b_dev); 768 struct ccd_softc *cs; 769 if ((cs = ccdget(unit, 0)) == NULL) 770 return; 771 772 /* Must be open or reading label. */ 773 KASSERT(cs->sc_dkdev.dk_openmask != 0 || 774 (cs->sc_flags & CCDF_RLABEL) != 0); 775 776 mutex_enter(cs->sc_iolock); 777 /* Synchronize with device init/uninit. */ 778 if (__predict_false((cs->sc_flags & CCDF_INITED) == 0)) { 779 mutex_exit(cs->sc_iolock); 780 #ifdef DEBUG 781 if (ccddebug & CCDB_FOLLOW) 782 printf("ccdstrategy: unit %d: not inited\n", unit); 783 #endif 784 bp->b_error = ENXIO; 785 bp->b_resid = bp->b_bcount; 786 biodone(bp); 787 return; 788 } 789 790 /* Defer to thread if system is low on memory. */ 791 bufq_put(cs->sc_bufq, bp); 792 if (__predict_false(ccdbackoff(cs))) { 793 mutex_exit(cs->sc_iolock); 794 #ifdef DEBUG 795 if (ccddebug & CCDB_FOLLOW) 796 printf("ccdstrategy: holding off on I/O\n"); 797 #endif 798 return; 799 } 800 ccdstart(cs); 801 } 802 803 static void 804 ccdstart(struct ccd_softc *cs) 805 { 806 daddr_t blkno; 807 int wlabel; 808 struct disklabel *lp; 809 long bcount, rcount; 810 struct ccdbuf *cbp; 811 char *addr; 812 daddr_t bn; 813 vnode_t *vp; 814 buf_t *bp; 815 816 KASSERT(mutex_owned(cs->sc_iolock)); 817 818 disk_busy(&cs->sc_dkdev); 819 bp = bufq_get(cs->sc_bufq); 820 KASSERT(bp != NULL); 821 822 #ifdef DEBUG 823 if (ccddebug & CCDB_FOLLOW) 824 printf("ccdstart(%s, %p)\n", cs->sc_xname, bp); 825 #endif 826 827 /* If it's a nil transfer, wake up the top half now. */ 828 if (bp->b_bcount == 0) 829 goto done; 830 831 lp = cs->sc_dkdev.dk_label; 832 833 /* 834 * Do bounds checking and adjust transfer. If there's an 835 * error, the bounds check will flag that for us. Convert 836 * the partition relative block number to an absolute. 837 */ 838 blkno = bp->b_blkno; 839 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 840 if (DISKPART(bp->b_dev) != RAW_PART) { 841 if (bounds_check_with_label(&cs->sc_dkdev, bp, wlabel) <= 0) 842 goto done; 843 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 844 } 845 mutex_exit(cs->sc_iolock); 846 bp->b_rawblkno = blkno; 847 848 /* Allocate the component buffers and start I/O! */ 849 bp->b_resid = bp->b_bcount; 850 bn = bp->b_rawblkno; 851 addr = bp->b_data; 852 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 853 cbp = ccdbuffer(cs, bp, bn, addr, bcount); 854 rcount = cbp->cb_buf.b_bcount; 855 bn += btodb(rcount); 856 addr += rcount; 857 vp = cbp->cb_buf.b_vp; 858 if ((cbp->cb_buf.b_flags & B_READ) == 0) { 859 mutex_enter(vp->v_interlock); 860 vp->v_numoutput++; 861 mutex_exit(vp->v_interlock); 862 } 863 (void)VOP_STRATEGY(vp, &cbp->cb_buf); 864 } 865 return; 866 867 done: 868 disk_unbusy(&cs->sc_dkdev, 0, 0); 869 cv_broadcast(&cs->sc_stop); 870 cv_broadcast(&cs->sc_push); 871 mutex_exit(cs->sc_iolock); 872 bp->b_resid = bp->b_bcount; 873 biodone(bp); 874 } 875 876 /* 877 * Build a component buffer header. 878 */ 879 static struct ccdbuf * 880 ccdbuffer(struct ccd_softc *cs, struct buf *bp, daddr_t bn, void *addr, 881 long bcount) 882 { 883 struct ccdcinfo *ci; 884 struct ccdbuf *cbp; 885 daddr_t cbn, cboff; 886 u_int64_t cbc; 887 int ccdisk; 888 889 #ifdef DEBUG 890 if (ccddebug & CCDB_IO) 891 printf("ccdbuffer(%p, %p, %" PRId64 ", %p, %ld)\n", 892 cs, bp, bn, addr, bcount); 893 #endif 894 /* 895 * Determine which component bn falls in. 896 */ 897 cbn = bn; 898 cboff = 0; 899 900 /* 901 * Serially concatenated 902 */ 903 if (cs->sc_ileave == 0) { 904 daddr_t sblk; 905 906 sblk = 0; 907 for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk]; 908 cbn >= sblk + ci->ci_size; 909 ccdisk++, ci = &cs->sc_cinfo[ccdisk]) 910 sblk += ci->ci_size; 911 cbn -= sblk; 912 } 913 /* 914 * Interleaved 915 */ 916 else { 917 struct ccdiinfo *ii; 918 int off; 919 920 cboff = cbn % cs->sc_ileave; 921 cbn /= cs->sc_ileave; 922 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 923 if (ii->ii_startblk > cbn) 924 break; 925 ii--; 926 off = cbn - ii->ii_startblk; 927 if (ii->ii_ndisk == 1) { 928 ccdisk = ii->ii_index[0]; 929 cbn = ii->ii_startoff + off; 930 } else { 931 ccdisk = ii->ii_index[off % ii->ii_ndisk]; 932 cbn = ii->ii_startoff + off / ii->ii_ndisk; 933 } 934 cbn *= cs->sc_ileave; 935 ci = &cs->sc_cinfo[ccdisk]; 936 } 937 938 /* 939 * Fill in the component buf structure. 940 */ 941 cbp = CCD_GETBUF(); 942 KASSERT(cbp != NULL); 943 buf_init(&cbp->cb_buf); 944 cbp->cb_buf.b_flags = bp->b_flags; 945 cbp->cb_buf.b_oflags = bp->b_oflags; 946 cbp->cb_buf.b_cflags = bp->b_cflags; 947 cbp->cb_buf.b_iodone = ccdiodone; 948 cbp->cb_buf.b_proc = bp->b_proc; 949 cbp->cb_buf.b_dev = ci->ci_dev; 950 cbp->cb_buf.b_blkno = cbn + cboff; 951 cbp->cb_buf.b_data = addr; 952 cbp->cb_buf.b_vp = ci->ci_vp; 953 cbp->cb_buf.b_objlock = ci->ci_vp->v_interlock; 954 if (cs->sc_ileave == 0) 955 cbc = dbtob((u_int64_t)(ci->ci_size - cbn)); 956 else 957 cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff)); 958 cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount; 959 960 /* 961 * context for ccdiodone 962 */ 963 cbp->cb_obp = bp; 964 cbp->cb_sc = cs; 965 cbp->cb_comp = ccdisk; 966 967 BIO_COPYPRIO(&cbp->cb_buf, bp); 968 969 #ifdef DEBUG 970 if (ccddebug & CCDB_IO) 971 printf(" dev 0x%"PRIx64"(u%lu): cbp %p bn %" PRId64 " addr %p" 972 " bcnt %d\n", 973 ci->ci_dev, (unsigned long) (ci-cs->sc_cinfo), cbp, 974 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 975 cbp->cb_buf.b_bcount); 976 #endif 977 978 return (cbp); 979 } 980 981 /* 982 * Called at interrupt time. 983 * Mark the component as done and if all components are done, 984 * take a ccd interrupt. 985 */ 986 static void 987 ccdiodone(struct buf *vbp) 988 { 989 struct ccdbuf *cbp = (struct ccdbuf *) vbp; 990 struct buf *bp = cbp->cb_obp; 991 struct ccd_softc *cs = cbp->cb_sc; 992 int count; 993 994 #ifdef DEBUG 995 if (ccddebug & CCDB_FOLLOW) 996 printf("ccdiodone(%p)\n", cbp); 997 if (ccddebug & CCDB_IO) { 998 printf("ccdiodone: bp %p bcount %d resid %d\n", 999 bp, bp->b_bcount, bp->b_resid); 1000 printf(" dev 0x%"PRIx64"(u%d), cbp %p bn %" PRId64 " addr %p" 1001 " bcnt %d\n", 1002 cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 1003 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 1004 cbp->cb_buf.b_bcount); 1005 } 1006 #endif 1007 1008 if (cbp->cb_buf.b_error != 0) { 1009 bp->b_error = cbp->cb_buf.b_error; 1010 printf("%s: error %d on component %d\n", 1011 cs->sc_xname, bp->b_error, cbp->cb_comp); 1012 } 1013 count = cbp->cb_buf.b_bcount; 1014 buf_destroy(&cbp->cb_buf); 1015 CCD_PUTBUF(cbp); 1016 1017 /* 1018 * If all done, "interrupt". 1019 */ 1020 mutex_enter(cs->sc_iolock); 1021 bp->b_resid -= count; 1022 if (bp->b_resid < 0) 1023 panic("ccdiodone: count"); 1024 if (bp->b_resid == 0) { 1025 /* 1026 * Request is done for better or worse, wakeup the top half. 1027 */ 1028 if (bp->b_error != 0) 1029 bp->b_resid = bp->b_bcount; 1030 disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid), 1031 (bp->b_flags & B_READ)); 1032 if (!disk_isbusy(&cs->sc_dkdev)) { 1033 if (bufq_peek(cs->sc_bufq) != NULL) { 1034 cv_broadcast(&cs->sc_push); 1035 } 1036 cv_broadcast(&cs->sc_stop); 1037 } 1038 mutex_exit(cs->sc_iolock); 1039 biodone(bp); 1040 } else 1041 mutex_exit(cs->sc_iolock); 1042 } 1043 1044 /* ARGSUSED */ 1045 static int 1046 ccdread(dev_t dev, struct uio *uio, int flags) 1047 { 1048 int unit = ccdunit(dev); 1049 struct ccd_softc *cs; 1050 1051 #ifdef DEBUG 1052 if (ccddebug & CCDB_FOLLOW) 1053 printf("ccdread(0x%"PRIx64", %p)\n", dev, uio); 1054 #endif 1055 if ((cs = ccdget(unit, 0)) == NULL) 1056 return 0; 1057 1058 /* Unlocked advisory check, ccdstrategy check is synchronous. */ 1059 if ((cs->sc_flags & CCDF_INITED) == 0) 1060 return (ENXIO); 1061 1062 return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio)); 1063 } 1064 1065 /* ARGSUSED */ 1066 static int 1067 ccdwrite(dev_t dev, struct uio *uio, int flags) 1068 { 1069 int unit = ccdunit(dev); 1070 struct ccd_softc *cs; 1071 1072 #ifdef DEBUG 1073 if (ccddebug & CCDB_FOLLOW) 1074 printf("ccdwrite(0x%"PRIx64", %p)\n", dev, uio); 1075 #endif 1076 if ((cs = ccdget(unit, 0)) == NULL) 1077 return ENOENT; 1078 1079 /* Unlocked advisory check, ccdstrategy check is synchronous. */ 1080 if ((cs->sc_flags & CCDF_INITED) == 0) 1081 return (ENXIO); 1082 1083 return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio)); 1084 } 1085 1086 static int 1087 ccdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1088 { 1089 int unit = ccdunit(dev); 1090 int i, j, lookedup = 0, error = 0; 1091 int part, pmask, make; 1092 struct ccd_softc *cs; 1093 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1094 kauth_cred_t uc; 1095 char **cpp; 1096 struct pathbuf *pb; 1097 struct vnode **vpp; 1098 #ifdef __HAVE_OLD_DISKLABEL 1099 struct disklabel newlabel; 1100 #endif 1101 1102 switch (cmd) { 1103 #if defined(COMPAT_60) && !defined(_LP64) 1104 case CCDIOCSET_60: 1105 #endif 1106 case CCDIOCSET: 1107 make = 1; 1108 break; 1109 default: 1110 make = 0; 1111 break; 1112 } 1113 1114 if ((cs = ccdget(unit, make)) == NULL) 1115 return ENOENT; 1116 uc = kauth_cred_get(); 1117 1118 /* 1119 * Compat code must not be called if on a platform where 1120 * sizeof (size_t) == sizeof (uint64_t) as CCDIOCSET will 1121 * be the same as CCDIOCSET_60 1122 */ 1123 #if defined(COMPAT_60) && !defined(_LP64) 1124 switch (cmd) { 1125 case CCDIOCSET_60: { 1126 struct ccd_ioctl ccionew; 1127 struct ccd_ioctl_60 *ccio60 = 1128 (struct ccd_ioctl_60 *)data; 1129 ccionew.ccio_disks = ccio->ccio_disks; 1130 ccionew.ccio_ndisks = ccio->ccio_ndisks; 1131 ccionew.ccio_ileave = ccio->ccio_ileave; 1132 ccionew.ccio_flags = ccio->ccio_flags; 1133 ccionew.ccio_unit = ccio->ccio_unit; 1134 error = ccdioctl(dev, CCDIOCSET, &ccionew, flag, l); 1135 if (!error) { 1136 /* Copy data back, adjust types if necessary */ 1137 ccio60->ccio_disks = ccionew.ccio_disks; 1138 ccio60->ccio_ndisks = ccionew.ccio_ndisks; 1139 ccio60->ccio_ileave = ccionew.ccio_ileave; 1140 ccio60->ccio_flags = ccionew.ccio_flags; 1141 ccio60->ccio_unit = ccionew.ccio_unit; 1142 ccio60->ccio_size = (size_t)ccionew.ccio_size; 1143 } 1144 return error; 1145 } 1146 break; 1147 1148 case CCDIOCCLR_60: 1149 /* 1150 * ccio_size member not used, so existing struct OK 1151 * drop through to existing non-compat version 1152 */ 1153 cmd = CCDIOCCLR; 1154 break; 1155 } 1156 #endif /* COMPAT_60 && !_LP64*/ 1157 1158 /* Must be open for writes for these commands... */ 1159 switch (cmd) { 1160 case CCDIOCSET: 1161 case CCDIOCCLR: 1162 case DIOCSDINFO: 1163 case DIOCWDINFO: 1164 case DIOCCACHESYNC: 1165 case DIOCAWEDGE: 1166 case DIOCDWEDGE: 1167 case DIOCMWEDGES: 1168 #ifdef __HAVE_OLD_DISKLABEL 1169 case ODIOCSDINFO: 1170 case ODIOCWDINFO: 1171 #endif 1172 case DIOCKLABEL: 1173 case DIOCWLABEL: 1174 if ((flag & FWRITE) == 0) 1175 return (EBADF); 1176 } 1177 1178 mutex_enter(&cs->sc_dvlock); 1179 1180 /* Must be initialized for these... */ 1181 switch (cmd) { 1182 case CCDIOCCLR: 1183 case DIOCGDINFO: 1184 case DIOCCACHESYNC: 1185 case DIOCAWEDGE: 1186 case DIOCDWEDGE: 1187 case DIOCLWEDGES: 1188 case DIOCMWEDGES: 1189 case DIOCSDINFO: 1190 case DIOCWDINFO: 1191 case DIOCGPARTINFO: 1192 case DIOCWLABEL: 1193 case DIOCKLABEL: 1194 case DIOCGDEFLABEL: 1195 #ifdef __HAVE_OLD_DISKLABEL 1196 case ODIOCGDINFO: 1197 case ODIOCSDINFO: 1198 case ODIOCWDINFO: 1199 case ODIOCGDEFLABEL: 1200 #endif 1201 if ((cs->sc_flags & CCDF_INITED) == 0) { 1202 error = ENXIO; 1203 goto out; 1204 } 1205 } 1206 1207 error = disk_ioctl(&cs->sc_dkdev, dev, cmd, data, flag, l); 1208 if (error != EPASSTHROUGH) 1209 goto out; 1210 1211 error = 0; 1212 switch (cmd) { 1213 case CCDIOCSET: 1214 if (cs->sc_flags & CCDF_INITED) { 1215 error = EBUSY; 1216 goto out; 1217 } 1218 1219 /* Validate the flags. */ 1220 if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) { 1221 error = EINVAL; 1222 goto out; 1223 } 1224 1225 if (ccio->ccio_ndisks > CCD_MAXNDISKS || 1226 ccio->ccio_ndisks == 0) { 1227 error = EINVAL; 1228 goto out; 1229 } 1230 1231 /* Fill in some important bits. */ 1232 cs->sc_ileave = ccio->ccio_ileave; 1233 cs->sc_nccdisks = ccio->ccio_ndisks; 1234 cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK; 1235 1236 /* 1237 * Allocate space for and copy in the array of 1238 * component pathnames and device numbers. 1239 */ 1240 cpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*cpp), KM_SLEEP); 1241 vpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*vpp), KM_SLEEP); 1242 error = copyin(ccio->ccio_disks, cpp, 1243 ccio->ccio_ndisks * sizeof(*cpp)); 1244 if (error) { 1245 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp)); 1246 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp)); 1247 goto out; 1248 } 1249 1250 #ifdef DEBUG 1251 if (ccddebug & CCDB_INIT) 1252 for (i = 0; i < ccio->ccio_ndisks; ++i) 1253 printf("ccdioctl: component %d: %p\n", 1254 i, cpp[i]); 1255 #endif 1256 1257 for (i = 0; i < ccio->ccio_ndisks; ++i) { 1258 #ifdef DEBUG 1259 if (ccddebug & CCDB_INIT) 1260 printf("ccdioctl: lookedup = %d\n", lookedup); 1261 #endif 1262 error = pathbuf_copyin(cpp[i], &pb); 1263 if (error == 0) { 1264 error = dk_lookup(pb, l, &vpp[i]); 1265 } 1266 pathbuf_destroy(pb); 1267 if (error != 0) { 1268 for (j = 0; j < lookedup; ++j) 1269 (void)vn_close(vpp[j], FREAD|FWRITE, 1270 uc); 1271 kmem_free(vpp, ccio->ccio_ndisks * 1272 sizeof(*vpp)); 1273 kmem_free(cpp, ccio->ccio_ndisks * 1274 sizeof(*cpp)); 1275 goto out; 1276 } 1277 ++lookedup; 1278 } 1279 1280 /* Attach the disk. */ 1281 disk_attach(&cs->sc_dkdev); 1282 bufq_alloc(&cs->sc_bufq, "fcfs", 0); 1283 1284 /* 1285 * Initialize the ccd. Fills in the softc for us. 1286 */ 1287 if ((error = ccdinit(cs, cpp, vpp, l)) != 0) { 1288 for (j = 0; j < lookedup; ++j) 1289 (void)vn_close(vpp[j], FREAD|FWRITE, 1290 uc); 1291 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp)); 1292 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp)); 1293 disk_detach(&cs->sc_dkdev); 1294 mutex_exit(&cs->sc_dvlock); 1295 bufq_free(cs->sc_bufq); 1296 return error; 1297 } 1298 1299 /* We can free the temporary variables now. */ 1300 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp)); 1301 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp)); 1302 1303 /* 1304 * The ccd has been successfully initialized, so 1305 * we can place it into the array. Don't try to 1306 * read the disklabel until the disk has been attached, 1307 * because space for the disklabel is allocated 1308 * in disk_attach(); 1309 */ 1310 ccio->ccio_unit = unit; 1311 ccio->ccio_size = cs->sc_size; 1312 1313 /* Try and read the disklabel. */ 1314 ccdgetdisklabel(dev); 1315 disk_set_info(NULL, &cs->sc_dkdev, NULL); 1316 1317 /* discover wedges */ 1318 mutex_exit(&cs->sc_dvlock); 1319 dkwedge_discover(&cs->sc_dkdev); 1320 return 0; 1321 1322 case CCDIOCCLR: 1323 /* 1324 * Don't unconfigure if any other partitions are open 1325 * or if both the character and block flavors of this 1326 * partition are open. 1327 */ 1328 part = DISKPART(dev); 1329 pmask = (1 << part); 1330 if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1331 ((cs->sc_dkdev.dk_bopenmask & pmask) && 1332 (cs->sc_dkdev.dk_copenmask & pmask))) { 1333 error = EBUSY; 1334 goto out; 1335 } 1336 1337 /* Delete all of our wedges. */ 1338 dkwedge_delall(&cs->sc_dkdev); 1339 1340 /* Stop new I/O, wait for in-flight I/O to complete. */ 1341 mutex_enter(cs->sc_iolock); 1342 cs->sc_flags &= ~(CCDF_INITED|CCDF_VLABEL); 1343 cs->sc_zap = true; 1344 while (disk_isbusy(&cs->sc_dkdev) || 1345 bufq_peek(cs->sc_bufq) != NULL || 1346 cs->sc_thread != NULL) { 1347 cv_broadcast(&cs->sc_push); 1348 (void)cv_timedwait(&cs->sc_stop, cs->sc_iolock, hz); 1349 } 1350 mutex_exit(cs->sc_iolock); 1351 1352 /* 1353 * Free ccd_softc information and clear entry. 1354 */ 1355 1356 /* Close the components and free their pathnames. */ 1357 for (i = 0; i < cs->sc_nccdisks; ++i) { 1358 /* 1359 * XXX: this close could potentially fail and 1360 * cause Bad Things. Maybe we need to force 1361 * the close to happen? 1362 */ 1363 #ifdef DEBUG 1364 if (ccddebug & CCDB_VNODE) 1365 vprint("CCDIOCCLR: vnode info", 1366 cs->sc_cinfo[i].ci_vp); 1367 #endif 1368 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1369 uc); 1370 kmem_free(cs->sc_cinfo[i].ci_path, 1371 cs->sc_cinfo[i].ci_pathlen); 1372 } 1373 1374 /* Free interleave index. */ 1375 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) { 1376 kmem_free(cs->sc_itable[i].ii_index, 1377 cs->sc_itable[i].ii_indexsz); 1378 } 1379 1380 /* Free component info and interleave table. */ 1381 kmem_free(cs->sc_cinfo, cs->sc_nccdisks * 1382 sizeof(struct ccdcinfo)); 1383 kmem_free(cs->sc_itable, (cs->sc_nccdisks + 1) * 1384 sizeof(struct ccdiinfo)); 1385 1386 aprint_normal("%s: detached\n", cs->sc_xname); 1387 1388 /* Detach the disk. */ 1389 disk_detach(&cs->sc_dkdev); 1390 bufq_free(cs->sc_bufq); 1391 ccdput(cs); 1392 /* Don't break, otherwise cs is read again. */ 1393 return 0; 1394 1395 case DIOCCACHESYNC: 1396 /* 1397 * We pass this call down to all components and report 1398 * the first error we encounter. 1399 */ 1400 for (error = 0, i = 0; i < cs->sc_nccdisks; i++) { 1401 j = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, data, 1402 flag, uc); 1403 if (j != 0 && error == 0) 1404 error = j; 1405 } 1406 break; 1407 1408 case DIOCWDINFO: 1409 case DIOCSDINFO: 1410 #ifdef __HAVE_OLD_DISKLABEL 1411 case ODIOCWDINFO: 1412 case ODIOCSDINFO: 1413 #endif 1414 { 1415 struct disklabel *lp; 1416 #ifdef __HAVE_OLD_DISKLABEL 1417 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1418 memset(&newlabel, 0, sizeof newlabel); 1419 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1420 lp = &newlabel; 1421 } else 1422 #endif 1423 lp = (struct disklabel *)data; 1424 1425 cs->sc_flags |= CCDF_LABELLING; 1426 1427 error = setdisklabel(cs->sc_dkdev.dk_label, 1428 lp, 0, cs->sc_dkdev.dk_cpulabel); 1429 if (error == 0) { 1430 if (cmd == DIOCWDINFO 1431 #ifdef __HAVE_OLD_DISKLABEL 1432 || cmd == ODIOCWDINFO 1433 #endif 1434 ) 1435 error = writedisklabel(CCDLABELDEV(dev), 1436 ccdstrategy, cs->sc_dkdev.dk_label, 1437 cs->sc_dkdev.dk_cpulabel); 1438 } 1439 1440 cs->sc_flags &= ~CCDF_LABELLING; 1441 break; 1442 } 1443 1444 case DIOCKLABEL: 1445 if (*(int *)data != 0) 1446 cs->sc_flags |= CCDF_KLABEL; 1447 else 1448 cs->sc_flags &= ~CCDF_KLABEL; 1449 break; 1450 1451 case DIOCWLABEL: 1452 if (*(int *)data != 0) 1453 cs->sc_flags |= CCDF_WLABEL; 1454 else 1455 cs->sc_flags &= ~CCDF_WLABEL; 1456 break; 1457 1458 case DIOCGDEFLABEL: 1459 ccdgetdefaultlabel(cs, (struct disklabel *)data); 1460 break; 1461 1462 #ifdef __HAVE_OLD_DISKLABEL 1463 case ODIOCGDEFLABEL: 1464 ccdgetdefaultlabel(cs, &newlabel); 1465 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1466 return ENOTTY; 1467 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1468 break; 1469 #endif 1470 1471 default: 1472 error = ENOTTY; 1473 } 1474 1475 out: 1476 mutex_exit(&cs->sc_dvlock); 1477 return (error); 1478 } 1479 1480 static int 1481 ccdsize(dev_t dev) 1482 { 1483 struct ccd_softc *cs; 1484 struct disklabel *lp; 1485 int part, unit, omask, size; 1486 1487 unit = ccdunit(dev); 1488 if ((cs = ccdget(unit, 0)) == NULL) 1489 return -1; 1490 1491 if ((cs->sc_flags & CCDF_INITED) == 0) 1492 return (-1); 1493 1494 part = DISKPART(dev); 1495 omask = cs->sc_dkdev.dk_openmask & (1 << part); 1496 lp = cs->sc_dkdev.dk_label; 1497 1498 if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curlwp)) 1499 return (-1); 1500 1501 if (lp->d_partitions[part].p_fstype != FS_SWAP) 1502 size = -1; 1503 else 1504 size = lp->d_partitions[part].p_size * 1505 (lp->d_secsize / DEV_BSIZE); 1506 1507 if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curlwp)) 1508 return (-1); 1509 1510 return (size); 1511 } 1512 1513 static void 1514 ccdgetdefaultlabel(struct ccd_softc *cs, struct disklabel *lp) 1515 { 1516 struct ccdgeom *ccg = &cs->sc_geom; 1517 1518 memset(lp, 0, sizeof(*lp)); 1519 1520 if (cs->sc_size > UINT32_MAX) 1521 lp->d_secperunit = UINT32_MAX; 1522 else 1523 lp->d_secperunit = cs->sc_size; 1524 lp->d_secsize = ccg->ccg_secsize; 1525 lp->d_nsectors = ccg->ccg_nsectors; 1526 lp->d_ntracks = ccg->ccg_ntracks; 1527 lp->d_ncylinders = ccg->ccg_ncylinders; 1528 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1529 1530 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1531 lp->d_type = DKTYPE_CCD; 1532 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1533 lp->d_rpm = 3600; 1534 lp->d_interleave = 1; 1535 lp->d_flags = 0; 1536 1537 lp->d_partitions[RAW_PART].p_offset = 0; 1538 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; 1539 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1540 lp->d_npartitions = RAW_PART + 1; 1541 1542 lp->d_magic = DISKMAGIC; 1543 lp->d_magic2 = DISKMAGIC; 1544 lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label); 1545 } 1546 1547 /* 1548 * Read the disklabel from the ccd. If one is not present, fake one 1549 * up. 1550 */ 1551 static void 1552 ccdgetdisklabel(dev_t dev) 1553 { 1554 int unit = ccdunit(dev); 1555 struct ccd_softc *cs; 1556 const char *errstring; 1557 struct disklabel *lp; 1558 struct cpu_disklabel *clp; 1559 1560 if ((cs = ccdget(unit, 0)) == NULL) 1561 return; 1562 lp = cs->sc_dkdev.dk_label; 1563 clp = cs->sc_dkdev.dk_cpulabel; 1564 KASSERT(mutex_owned(&cs->sc_dvlock)); 1565 1566 memset(clp, 0, sizeof(*clp)); 1567 1568 ccdgetdefaultlabel(cs, lp); 1569 1570 /* 1571 * Call the generic disklabel extraction routine. 1572 */ 1573 cs->sc_flags |= CCDF_RLABEL; 1574 if ((cs->sc_flags & CCDF_NOLABEL) != 0) 1575 errstring = "CCDF_NOLABEL set; ignoring on-disk label"; 1576 else 1577 errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1578 cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel); 1579 if (errstring) 1580 ccdmakedisklabel(cs); 1581 else { 1582 int i; 1583 struct partition *pp; 1584 1585 /* 1586 * Sanity check whether the found disklabel is valid. 1587 * 1588 * This is necessary since total size of ccd may vary 1589 * when an interleave is changed even though exactly 1590 * same componets are used, and old disklabel may used 1591 * if that is found. 1592 */ 1593 if (lp->d_secperunit < UINT32_MAX ? 1594 lp->d_secperunit != cs->sc_size : 1595 lp->d_secperunit > cs->sc_size) 1596 printf("WARNING: %s: " 1597 "total sector size in disklabel (%ju) != " 1598 "the size of ccd (%ju)\n", cs->sc_xname, 1599 (uintmax_t)lp->d_secperunit, 1600 (uintmax_t)cs->sc_size); 1601 for (i = 0; i < lp->d_npartitions; i++) { 1602 pp = &lp->d_partitions[i]; 1603 if (pp->p_offset + pp->p_size > cs->sc_size) 1604 printf("WARNING: %s: end of partition `%c' " 1605 "exceeds the size of ccd (%ju)\n", 1606 cs->sc_xname, 'a' + i, (uintmax_t)cs->sc_size); 1607 } 1608 } 1609 1610 #ifdef DEBUG 1611 /* It's actually extremely common to have unlabeled ccds. */ 1612 if (ccddebug & CCDB_LABEL) 1613 if (errstring != NULL) 1614 printf("%s: %s\n", cs->sc_xname, errstring); 1615 #endif 1616 1617 /* In-core label now valid. */ 1618 cs->sc_flags = (cs->sc_flags | CCDF_VLABEL) & ~CCDF_RLABEL; 1619 } 1620 1621 /* 1622 * Take care of things one might want to take care of in the event 1623 * that a disklabel isn't present. 1624 */ 1625 static void 1626 ccdmakedisklabel(struct ccd_softc *cs) 1627 { 1628 struct disklabel *lp = cs->sc_dkdev.dk_label; 1629 1630 /* 1631 * For historical reasons, if there's no disklabel present 1632 * the raw partition must be marked FS_BSDFFS. 1633 */ 1634 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1635 1636 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1637 1638 lp->d_checksum = dkcksum(lp); 1639 } 1640 1641 #ifdef DEBUG 1642 static void 1643 printiinfo(struct ccdiinfo *ii) 1644 { 1645 int ix, i; 1646 1647 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1648 printf(" itab[%d]: #dk %d sblk %" PRId64 " soff %" PRId64, 1649 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1650 for (i = 0; i < ii->ii_ndisk; i++) 1651 printf(" %d", ii->ii_index[i]); 1652 printf("\n"); 1653 } 1654 } 1655 #endif 1656 1657 MODULE(MODULE_CLASS_DRIVER, ccd, "dk_subr"); 1658 1659 static int 1660 ccd_modcmd(modcmd_t cmd, void *arg) 1661 { 1662 int error = 0; 1663 #ifdef _MODULE 1664 int bmajor = -1, cmajor = -1; 1665 #endif 1666 1667 1668 switch (cmd) { 1669 case MODULE_CMD_INIT: 1670 #ifdef _MODULE 1671 ccdattach(0); 1672 1673 error = devsw_attach("ccd", &ccd_bdevsw, &bmajor, 1674 &ccd_cdevsw, &cmajor); 1675 sysctl_kern_ccd_setup(&ccd_clog); 1676 #endif 1677 break; 1678 1679 case MODULE_CMD_FINI: 1680 #ifdef _MODULE 1681 mutex_enter(&ccd_lock); 1682 if (ccd_nactive) { 1683 mutex_exit(&ccd_lock); 1684 error = EBUSY; 1685 } else { 1686 mutex_exit(&ccd_lock); 1687 error = devsw_detach(&ccd_bdevsw, &ccd_cdevsw); 1688 ccddetach(); 1689 } 1690 sysctl_teardown(&ccd_clog); 1691 #endif 1692 break; 1693 1694 case MODULE_CMD_STAT: 1695 return ENOTTY; 1696 1697 default: 1698 return ENOTTY; 1699 } 1700 1701 return error; 1702 } 1703 1704 static int 1705 ccd_units_sysctl(SYSCTLFN_ARGS) 1706 { 1707 struct sysctlnode node; 1708 struct ccd_softc *sc; 1709 int error, i, nccd, *units; 1710 size_t size; 1711 1712 nccd = 0; 1713 mutex_enter(&ccd_lock); 1714 LIST_FOREACH(sc, &ccds, sc_link) 1715 nccd++; 1716 mutex_exit(&ccd_lock); 1717 1718 if (nccd != 0) { 1719 size = nccd * sizeof(*units); 1720 units = kmem_zalloc(size, KM_SLEEP); 1721 if (units == NULL) 1722 return ENOMEM; 1723 1724 i = 0; 1725 mutex_enter(&ccd_lock); 1726 LIST_FOREACH(sc, &ccds, sc_link) { 1727 if (i >= nccd) 1728 break; 1729 units[i] = sc->sc_unit; 1730 } 1731 mutex_exit(&ccd_lock); 1732 } else { 1733 units = NULL; 1734 size = 0; 1735 } 1736 1737 node = *rnode; 1738 node.sysctl_data = units; 1739 node.sysctl_size = size; 1740 1741 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1742 if (units) 1743 kmem_free(units, size); 1744 return error; 1745 } 1746 1747 static int 1748 ccd_info_sysctl(SYSCTLFN_ARGS) 1749 { 1750 struct sysctlnode node; 1751 struct ccddiskinfo ccd; 1752 struct ccd_softc *sc; 1753 int unit; 1754 1755 if (newp == NULL || newlen != sizeof(int)) 1756 return EINVAL; 1757 1758 unit = *(const int *)newp; 1759 newp = NULL; 1760 newlen = 0; 1761 ccd.ccd_ndisks = ~0; 1762 mutex_enter(&ccd_lock); 1763 LIST_FOREACH(sc, &ccds, sc_link) { 1764 if (sc->sc_unit == unit) { 1765 ccd.ccd_ileave = sc->sc_ileave; 1766 ccd.ccd_size = sc->sc_size; 1767 ccd.ccd_ndisks = sc->sc_nccdisks; 1768 ccd.ccd_flags = sc->sc_flags; 1769 break; 1770 } 1771 } 1772 mutex_exit(&ccd_lock); 1773 1774 if (ccd.ccd_ndisks == ~0) 1775 return ENOENT; 1776 1777 node = *rnode; 1778 node.sysctl_data = &ccd; 1779 node.sysctl_size = sizeof(ccd); 1780 1781 return sysctl_lookup(SYSCTLFN_CALL(&node)); 1782 } 1783 1784 static int 1785 ccd_components_sysctl(SYSCTLFN_ARGS) 1786 { 1787 struct sysctlnode node; 1788 int error, unit; 1789 size_t size; 1790 char *names, *p, *ep; 1791 struct ccd_softc *sc; 1792 1793 if (newp == NULL || newlen != sizeof(int)) 1794 return EINVAL; 1795 1796 size = 0; 1797 unit = *(const int *)newp; 1798 newp = NULL; 1799 newlen = 0; 1800 mutex_enter(&ccd_lock); 1801 LIST_FOREACH(sc, &ccds, sc_link) 1802 if (sc->sc_unit == unit) { 1803 for (size_t i = 0; i < sc->sc_nccdisks; i++) 1804 size += strlen(sc->sc_cinfo[i].ci_path) + 1; 1805 break; 1806 } 1807 mutex_exit(&ccd_lock); 1808 1809 if (size == 0) 1810 return ENOENT; 1811 names = kmem_zalloc(size, KM_SLEEP); 1812 if (names == NULL) 1813 return ENOMEM; 1814 1815 p = names; 1816 ep = names + size; 1817 mutex_enter(&ccd_lock); 1818 LIST_FOREACH(sc, &ccds, sc_link) 1819 if (sc->sc_unit == unit) { 1820 for (size_t i = 0; i < sc->sc_nccdisks; i++) { 1821 char *d = sc->sc_cinfo[i].ci_path; 1822 while (p < ep && (*p++ = *d++) != '\0') 1823 continue; 1824 } 1825 break; 1826 } 1827 mutex_exit(&ccd_lock); 1828 1829 node = *rnode; 1830 node.sysctl_data = names; 1831 node.sysctl_size = ep - names; 1832 1833 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1834 kmem_free(names, size); 1835 return error; 1836 } 1837 1838 SYSCTL_SETUP(sysctl_kern_ccd_setup, "sysctl kern.ccd subtree setup") 1839 { 1840 const struct sysctlnode *node = NULL; 1841 1842 sysctl_createv(clog, 0, NULL, &node, 1843 CTLFLAG_PERMANENT, 1844 CTLTYPE_NODE, "ccd", 1845 SYSCTL_DESCR("ConCatenated Disk state"), 1846 NULL, 0, NULL, 0, 1847 CTL_KERN, CTL_CREATE, CTL_EOL); 1848 1849 if (node == NULL) 1850 return; 1851 1852 sysctl_createv(clog, 0, &node, NULL, 1853 CTLFLAG_PERMANENT | CTLFLAG_READONLY, 1854 CTLTYPE_STRUCT, "units", 1855 SYSCTL_DESCR("List of ccd unit numbers"), 1856 ccd_units_sysctl, 0, NULL, 0, 1857 CTL_CREATE, CTL_EOL); 1858 sysctl_createv(clog, 0, &node, NULL, 1859 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1860 CTLTYPE_STRUCT, "info", 1861 SYSCTL_DESCR("Information about a CCD unit"), 1862 ccd_info_sysctl, 0, NULL, 0, 1863 CTL_CREATE, CTL_EOL); 1864 sysctl_createv(clog, 0, &node, NULL, 1865 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1866 CTLTYPE_STRUCT, "components", 1867 SYSCTL_DESCR("Information about CCD components"), 1868 ccd_components_sysctl, 0, NULL, 0, 1869 CTL_CREATE, CTL_EOL); 1870 } 1871