📄 ccd.c
字号:
/* $Id: ccd.c,v 1.37.2.2 1999/03/11 19:21:31 dg Exp $ *//* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ *//* * Copyright (c) 1995 Jason R. Thorpe. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project * by Jason R. Thorpe. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * Copyright (c) 1988 University of Utah. * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: cd.c 1.6 90/11/28$ * * @(#)cd.c 8.2 (Berkeley) 11/16/93 *//* * "Concatenated" disk driver. * * Dynamic configuration and disklabel support by: * Jason R. Thorpe <thorpej@nas.nasa.gov> * Numerical Aerodynamic Simulation Facility * Mail Stop 258-6 * NASA Ames Research Center * Moffett Field, CA 94035 */#include "ccd.h"#if NCCD > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/proc.h>#include <sys/buf.h>#include <sys/malloc.h>#include <sys/namei.h>#include <sys/conf.h>#include <sys/stat.h>#include <sys/sysctl.h>#include <sys/disklabel.h>#include <ufs/ffs/fs.h> #include <sys/device.h>#include <sys/devicestat.h>#undef KERNEL /* XXX */#include <sys/disk.h>#define KERNEL#include <sys/fcntl.h>#include <sys/vnode.h>#include <sys/ccdvar.h>#if defined(CCDDEBUG) && !defined(DEBUG)#define DEBUG#endif#ifdef DEBUG#define CCDB_FOLLOW 0x01#define CCDB_INIT 0x02#define CCDB_IO 0x04#define CCDB_LABEL 0x08#define CCDB_VNODE 0x10static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | CCDB_VNODE;SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");#undef DEBUG#endif#define ccdunit(x) dkunit(x)#define ccdpart(x) dkpart(x)/* This is how mirroring works (only writes are special): When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s linked together by the cb_mirror field. "cb_pflags & CCDPF_MIRROR_DONE" is set to 0 on both of them. When a component returns to ccdiodone(), it checks if "cb_pflags & CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's flag and returns. If it is, it means its partner has already returned, so it will go to the regular cleanup. */struct ccdbuf { struct buf cb_buf; /* new I/O buf */ struct buf *cb_obp; /* ptr. to original I/O buf */ int cb_unit; /* target unit */ int cb_comp; /* target component */ int cb_pflags; /* mirror/parity status flag */ struct ccdbuf *cb_mirror; /* mirror counterpart */};/* bits in cb_pflags */#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */#define getccdbuf() \ ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK))#define putccdbuf(cbp) \ free((caddr_t)(cbp), M_DEVBUF)#define CCDLABELDEV(dev) \ (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))static d_open_t ccdopen;static d_read_t ccdread;static d_write_t ccdwrite;static d_close_t ccdclose;static d_strategy_t ccdstrategy;static d_ioctl_t ccdioctl;static d_dump_t ccddump;static d_psize_t ccdsize;#define CDEV_MAJOR 74#define BDEV_MAJOR 21static struct cdevsw ccd_cdevsw = { ccdopen, ccdclose, ccdread, ccdwrite, ccdioctl, nostop, nullreset, nodevtotty, seltrue, nommap, ccdstrategy, "ccd", NULL, -1, ccddump, ccdsize, D_DISK, 0, -1 };/* Called by main() during pseudo-device attachment */static void ccdattach __P((void *));PSEUDO_SET(ccdattach, ccd);/* called by biodone() at interrupt time */static void ccdiodone __P((struct ccdbuf *cbp));static void ccdstart __P((struct ccd_softc *, struct buf *));static void ccdinterleave __P((struct ccd_softc *, int));static void ccdintr __P((struct ccd_softc *, struct buf *));static int ccdinit __P((struct ccddevice *, char **, struct proc *));static int ccdlookup __P((char *, struct proc *p, struct vnode **));static void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *, struct buf *, daddr_t, caddr_t, long));static void ccdgetdisklabel __P((dev_t));static void ccdmakedisklabel __P((struct ccd_softc *));static int ccdlock __P((struct ccd_softc *));static void ccdunlock __P((struct ccd_softc *));#ifdef DEBUGstatic void printiinfo __P((struct ccdiinfo *));#endif/* Non-private for the benefit of libkvm. */struct ccd_softc *ccd_softc;struct ccddevice *ccddevs;static int numccd = 0;static int ccd_devsw_installed = 0;/* * Number of blocks to untouched in front of a component partition. * This is to avoid violating its disklabel area when it starts at the * beginning of the slice. */#if !defined(CCD_OFFSET)#define CCD_OFFSET 16#endif/* * Called by main() during pseudo-device attachment. All we need * to do is allocate enough space for devices to be configured later, and * add devsw entries. */static voidccdattach(dummy) void *dummy;{ int i; int num = NCCD; if (num > 1) printf("ccd0-%d: Concatenated disk drivers\n", num-1); else printf("ccd0: Concatenated disk driver\n"); ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), M_DEVBUF, M_NOWAIT); ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice), M_DEVBUF, M_NOWAIT); if ((ccd_softc == NULL) || (ccddevs == NULL)) { printf("WARNING: no memory for concatenated disks\n"); if (ccd_softc != NULL) free(ccd_softc, M_DEVBUF); if (ccddevs != NULL) free(ccddevs, M_DEVBUF); return; } numccd = num; bzero(ccd_softc, num * sizeof(struct ccd_softc)); bzero(ccddevs, num * sizeof(struct ccddevice)); /* XXX: is this necessary? */ for (i = 0; i < numccd; ++i) ccddevs[i].ccd_dk = -1; if( ! ccd_devsw_installed ) { cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &ccd_cdevsw); ccd_devsw_installed = 1; } else { printf("huh?\n"); }}static intccdinit(ccd, cpaths, p) struct ccddevice *ccd; char **cpaths; struct proc *p;{ register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; register struct ccdcinfo *ci = NULL; /* XXX */ register size_t size; register int ix; struct vnode *vp; struct vattr va; size_t minsize; int maxsecsize; struct partinfo dpart; struct ccdgeom *ccg = &cs->sc_geom; char tmppath[MAXPATHLEN]; int error;#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccdinit: unit %d\n", ccd->ccd_unit);#endif cs->sc_size = 0; cs->sc_ileave = ccd->ccd_interleave; cs->sc_nccdisks = ccd->ccd_ndev; /* Allocate space for the component info. */ cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), M_DEVBUF, M_WAITOK); /* * Verify that each component piece exists and record * relevant information about it. */ maxsecsize = 0; minsize = 0; for (ix = 0; ix < cs->sc_nccdisks; ix++) { vp = ccd->ccd_vpp[ix]; ci = &cs->sc_cinfo[ix]; ci->ci_vp = vp; /* * Copy in the pathname of the component. */ bzero(tmppath, sizeof(tmppath)); /* sanity */ if (error = copyinstr(cpaths[ix], tmppath, MAXPATHLEN, &ci->ci_pathlen)) {#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccd%d: can't copy path, error = %d\n", ccd->ccd_unit, error);#endif while (ci > cs->sc_cinfo) { ci--; free(ci->ci_path, M_DEVBUF); } free(cs->sc_cinfo, M_DEVBUF); return (error); } ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); bcopy(tmppath, ci->ci_path, ci->ci_pathlen); /* * XXX: Cache the component's dev_t. */ if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) {#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccd%d: %s: getattr failed %s = %d\n", ccd->ccd_unit, ci->ci_path, "error", error);#endif while (ci >= cs->sc_cinfo) { free(ci->ci_path, M_DEVBUF); ci--; } free(cs->sc_cinfo, M_DEVBUF); return (error); } ci->ci_dev = va.va_rdev; /* * Get partition information for the component. */ if (error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, FREAD, p->p_ucred, p)) {#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccd%d: %s: ioctl failed, error = %d\n", ccd->ccd_unit, ci->ci_path, error);#endif while (ci >= cs->sc_cinfo) { free(ci->ci_path, M_DEVBUF); ci--; } free(cs->sc_cinfo, M_DEVBUF); return (error); } if (dpart.part->p_fstype == FS_BSDFFS) { maxsecsize = ((dpart.disklab->d_secsize > maxsecsize) ? dpart.disklab->d_secsize : maxsecsize); size = dpart.part->p_size - CCD_OFFSET; } else {#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccd%d: %s: incorrect partition type\n", ccd->ccd_unit, ci->ci_path);#endif while (ci >= cs->sc_cinfo) { free(ci->ci_path, M_DEVBUF); ci--; } free(cs->sc_cinfo, M_DEVBUF); return (EFTYPE); } /* * Calculate the size, truncating to an interleave * boundary if necessary. */ if (cs->sc_ileave > 1) size -= size % cs->sc_ileave; if (size == 0) {#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccd%d: %s: size == 0\n", ccd->ccd_unit, ci->ci_path);#endif while (ci >= cs->sc_cinfo) { free(ci->ci_path, M_DEVBUF); ci--; } free(cs->sc_cinfo, M_DEVBUF); return (ENODEV); } if (minsize == 0 || size < minsize) minsize = size; ci->ci_size = size; cs->sc_size += size; } /* * Don't allow the interleave to be smaller than * the biggest component sector. */ if ((cs->sc_ileave > 0) && (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {#ifdef DEBUG if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) printf("ccd%d: interleave must be at least %d\n", ccd->ccd_unit, (maxsecsize / DEV_BSIZE));#endif while (ci >= cs->sc_cinfo) { free(ci->ci_path, M_DEVBUF); ci--; } free(cs->sc_cinfo, M_DEVBUF); return (EINVAL); } /* * If uniform interleave is desired set all sizes to that of * the smallest component. */ if (ccd->ccd_flags & CCDF_UNIFORM) { for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) ci->ci_size = minsize; if (ccd->ccd_flags & CCDF_MIRROR) { /* * Check to see if an even number of components * have been specified. */ if (cs->sc_nccdisks % 2) { printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit ); while (ci > cs->sc_cinfo) { ci--; free(ci->ci_path, M_DEVBUF); } free(cs->sc_cinfo, M_DEVBUF); return (EINVAL); } cs->sc_size = (cs->sc_nccdisks/2) * minsize; } else if (ccd->ccd_flags & CCDF_PARITY) cs->sc_size = (cs->sc_nccdisks-1) * minsize; else cs->sc_size = cs->sc_nccdisks * minsize; } /* * Construct the interleave table. */ ccdinterleave(cs, ccd->ccd_unit); /* * Create pseudo-geometry based on 1MB cylinders. It's * pretty close. */ ccg->ccg_secsize = maxsecsize; ccg->ccg_ntracks = 1; ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; /* * Add an devstat entry for this device. */ devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit, ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_ASC0 |DEVSTAT_TYPE_IF_OTHER, DEVSTAT_PRIORITY_CCD); cs->sc_flags |= CCDF_INITED; cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */ cs->sc_unit = ccd->ccd_unit; return (0);}static voidccdinterleave(cs, unit) register struct ccd_softc *cs; int unit;{ register struct ccdcinfo *ci, *smallci; register struct ccdiinfo *ii; register daddr_t bn, lbn; register int ix; u_long size;#ifdef DEBUG if (ccddebug & CCDB_INIT) printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -