vinumio.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,103 行 · 第 1/3 页

C
1,103
字号
/*- * Copyright (c) 1997, 1998 *	Nan Yang Computer Services Limited.  All rights reserved. * *  This software is distributed under the so-called ``Berkeley *  License'': * * 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 Nan Yang Computer *      Services Limited. * 4. Neither the name of the Company 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 ``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 company 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. * * $Id: vinumio.c,v 1.7.2.6 1999/05/05 05:18:16 grog Exp $ */#define STATIC						    /* nothing while we're testing XXX */#include "opt_vinum.h"#define REALLYKERNEL#include <dev/vinum/vinumhdr.h>#include <dev/vinum/request.h>#include <miscfs/specfs/specdev.h>static char *sappend(char *txt, char *s);static int drivecmp(const void *va, const void *vb);/* * Open the device associated with the drive, and set drive's vp. * Return an error number  */intopen_drive(struct drive *drive, struct proc *p, int verbose){    struct nameidata nd;    struct vattr va;    int error;    if (drive->devicename[0] != '/')			    /* no device name */	sprintf(drive->devicename, "/dev/%s", drive->label.name); /* get it from the drive name */    NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, drive->devicename, p);    error = vn_open(&nd, FREAD | FWRITE, 0);		    /* open the device */    if (error != 0) {					    /* can't open? */	set_drive_state(drive->driveno, drive_down, setstate_force);	drive->lasterror = error;	if (verbose)	    log(LOG_WARNING,		"vinum open_drive %s: failed with error %d\n",		drive->devicename, error);		    /* XXX */	return error;    }    drive->vp = nd.ni_vp;    drive->p = p;    if (drive->vp->v_usecount > 1) {			    /* already in use? */	if (verbose)	    log(LOG_WARNING,		"open_drive %s: use count %d, ignoring\n",  /* XXX where does this come from? */		drive->devicename,		drive->vp->v_usecount);    }    error = VOP_GETATTR(drive->vp, &va, NOCRED, drive->p);    if (error) {	VOP_UNLOCK(drive->vp, 0, drive->p);	close_drive(drive);	set_drive_state(drive->driveno, drive_down, setstate_force);	drive->lasterror = error;	if (verbose)	    log(LOG_WARNING,		"vinum open_drive %s: GETAATTR returns error %d\n",		drive->devicename, error);		    /* XXX */	return error;    }    drive->dev = va.va_rdev;				    /* device */    if (va.va_type != VBLK) {				    /* only consider block devices */	VOP_UNLOCK(drive->vp, 0, drive->p);	close_drive(drive);	set_drive_state(drive->driveno, drive_down, setstate_force); /* this also closes the drive */	drive->lasterror = ENOTBLK;	if (verbose)	    log(LOG_WARNING,		"vinum open_drive %s: Not a block device\n",		drive->devicename);			    /* XXX */	return ENOTBLK;    }    drive->vp->v_numoutput = 0;    VOP_UNLOCK(drive->vp, 0, drive->p);    return 0;}/* * Set some variables in the drive struct * in more convenient form.  Return error indication  */int set_drive_parms(struct drive *drive){    drive->blocksize = BLKDEV_IOSIZE;			    /* XXX do we need this? */    drive->secsperblock = drive->blocksize		    /* number of sectors per block */	/ drive->partinfo.disklab->d_secsize;    /* Now update the label part */    bcopy(hostname, drive->label.sysname, VINUMHOSTNAMELEN); /* put in host name */    getmicrotime(&drive->label.date_of_birth);		    /* and current time */    drive->label.drive_size = ((u_int64_t) drive->partinfo.part->p_size) /* size of the drive in bytes */    *((u_int64_t) drive->partinfo.disklab->d_secsize);#if VINUMDEBUG    if (debug & DEBUG_BIGDRIVE)				    /* pretend we're 100 times as big */	drive->label.drive_size *= 100;#endif    /* number of sectors available for subdisks */    drive->sectors_available = drive->label.drive_size / DEV_BSIZE - DATASTART;    /*     * XXX Bug in 3.0 as of January 1998: you can open     * non-existent slices.  They have a length of 0      */    if (drive->label.drive_size < MINVINUMSLICE) {	    /* too small to worry about */	set_drive_state(drive->driveno, drive_down, setstate_force);	drive->lasterror = ENOSPC;	return ENOSPC;    }    drive->freelist_size = INITIAL_DRIVE_FREELIST;	    /* initial number of entries */    drive->freelist = (struct drive_freelist *)	Malloc(INITIAL_DRIVE_FREELIST * sizeof(struct drive_freelist));    if (drive->freelist == NULL)			    /* can't malloc, dammit */	return ENOSPC;    drive->freelist_entries = 1;			    /* just (almost) the complete drive */    drive->freelist[0].offset = DATASTART;		    /* starts here */    drive->freelist[0].sectors = (drive->label.drive_size >> DEV_BSHIFT) - DATASTART; /* and it's this long */    if (drive->label.name[0] != '\0')			    /* got a name */	set_drive_state(drive->driveno, drive_up, setstate_force); /* our drive is accessible */    else						    /* we know about it, but that's all */	drive->state = drive_referenced;    return 0;}/* * Initialize a drive: open the device and add device * information  */int init_drive(struct drive *drive, int verbose){    int error;    if (drive->devicename[0] != '/') {	drive->lasterror = EINVAL;	log(LOG_ERR, "vinum: Can't open drive without drive name\n");	return EINVAL;    }    error = open_drive(drive, curproc, verbose);	    /* open the drive */    if (error)	return error;    error = VOP_IOCTL(drive->vp,			    /* get the partition information */	DIOCGPART,	(caddr_t) & drive->partinfo,	FREAD,	NOCRED,	curproc);    if (error) {	if (verbose)	    log(LOG_WARNING,		"vinum open_drive %s: Can't get partition information, error %d\n",		drive->devicename,		error);					    /* XXX */	close_drive(drive);	drive->lasterror = error;	drive->state = drive_down;			    /* don't tell the system about this one at all */	return error;    }    if ((drive->partinfo.part->p_fstype != FS_UNUSED)	    /* not plain */    &&(drive->partinfo.part->p_fstype != FS_VINUM)) {	    /* and not Vinum */	drive->lasterror = EFTYPE;	if (verbose)	    log(LOG_WARNING,		"vinum open_drive %s: Wrong partition type for vinum\n",		drive->devicename);			    /* XXX */	close_drive(drive);	drive->state = drive_down;			    /* don't tell the system about this one at all */	return EFTYPE;    }    return set_drive_parms(drive);			    /* set various odds and ends */}/* Close a drive if it's open.  No errors */void close_drive(struct drive *drive){    if (drive->vp) {	LOCKDRIVE(drive);				    /* keep the daemon out */	/*	 * If we can't access the drive, we can't flush 	 * the queues, which spec_close() will try to	 * do.  Get rid of them here first	 */	if (drive->state < drive_up) {			    /* we can't access the drive, */	    vn_lock(drive->vp, LK_EXCLUSIVE | LK_RETRY, drive->p);	    vinvalbuf(drive->vp, 0, NOCRED, drive->p, 0, 0);	    VOP_UNLOCK(drive->vp, 0, drive->p);	}	vn_close(drive->vp, FREAD | FWRITE, NOCRED, drive->p);#ifdef VINUMDEBUG	if ((debug & DEBUG_WARNINGS)			    /* want to hear about them */	&&(drive->vp->v_usecount))			    /* XXX shouldn't happen */	    log(LOG_WARNING,		"close_drive %s: use count still %d\n",		drive->devicename,		drive->vp->v_usecount);#endif	drive->vp = NULL;	unlockdrive(drive);    }}/* * Remove drive from the configuration. * Caller must ensure that it isn't active */void remove_drive(int driveno){    struct drive *drive = &vinum_conf.drive[driveno];    long long int nomagic = VINUM_NOMAGIC;		    /* no magic number */    if (drive->state > drive_referenced) {		    /* real drive */	if (drive->state == drive_up)	    write_drive(drive,				    /* obliterate the magic, but leave a hint */		(char *) &nomagic,		8,		VINUM_LABEL_OFFSET);	free_drive(drive);				    /* close it and free resources */	save_config();					    /* and save the updated configuration */    }}/* * Transfer drive data.  Usually called from one of these defines; * #define read_drive(a, b, c, d) driveio (a, b, c, d, B_READ) * #define write_drive(a, b, c, d) driveio (a, b, c, d, B_WRITE) * * length and offset are in bytes, but must be multiples of sector * size.  The function *does not check* for this condition, and * truncates ruthlessly. * Return error number */intdriveio(struct drive *drive, char *buf, size_t length, off_t offset, int flag){    int error;    struct buf *bp;    char foo[40];    error = 0;						    /* to keep the compiler happy */    while (length) {					    /* divide into small enough blocks */	int len = min(length, MAXBSIZE);		    /* maximum block device transfer is MAXBSIZE */	bp = geteblk(len);				    /* get a buffer header */	bp->b_flags = B_BUSY | flag;			    /* get busy */	bp->b_proc = curproc;				    /* process */	bp->b_dev = drive->vp->v_un.vu_specinfo->si_rdev;   /* device */	bp->b_blkno = offset / drive->partinfo.disklab->d_secsize; /* block number */	bp->b_data = buf;	bp->b_bcount = len;	bp->b_bufsize = len;	(*bdevsw[major(bp->b_dev)]->d_strategy) (bp);	    /* initiate the transfer */	error = biowait(bp);	printf("driveio: %s dev 0x%x, block 0x%x, len 0x%lx, error %d\n", /* XXX */	    flag ? "read" : "write",	    bp->b_dev,	    bp->b_blkno,	    bp->b_bcount,	    error);	bcopy(buf, foo, 40);	foo[39] = '\0';	printf("---> %s\n", foo);			    /* XXXXXX */	bp->b_flags |= B_INVAL | B_AGE;	brelse(bp);	if (error)	    break;	length -= len;					    /* update pointers */	buf += len;	offset += len;    }    return error;}/* * Read data from a drive * * Return error number */intread_drive(struct drive *drive, void *buf, size_t length, off_t offset){    int error;    struct buf *bp;    daddr_t nextbn;    long bscale;    struct uio uio;    struct iovec iov;    daddr_t blocknum;					    /* block number */    int blockoff;					    /* offset in block */    int count;						    /* amount to transfer */    iov.iov_base = buf;    iov.iov_len = length;    uio.uio_iov = &iov;    uio.uio_iovcnt = length;    uio.uio_offset = offset;    uio.uio_resid = length;    uio.uio_segflg = UIO_SYSSPACE;    uio.uio_rw = UIO_READ;    uio.uio_procp = curproc;    bscale = btodb(drive->blocksize);			    /* mask off offset from block number */    do {	blocknum = btodb(uio.uio_offset) & ~(bscale - 1);   /* get the block number */	blockoff = uio.uio_offset % drive->blocksize;	    /* offset in block */	count = min((unsigned) (drive->blocksize - blockoff), /* amount to transfer in this block */	    uio.uio_resid);	/* XXX Check this.  I think the test is wrong */	if (drive->vp->v_lastr + bscale == blocknum) {	    /* did our last read finish in this block? */	    nextbn = blocknum + bscale;			    /* note the end of the transfer */	    error = breadn(drive->vp,			    /* and read with read-ahead */		blocknum,		(int) drive->blocksize,		&nextbn,		(int *) &drive->blocksize,		1,		NOCRED,		&bp);	} else						    /* random read: just read this block */	    error = bread(drive->vp, blocknum, (int) drive->blocksize, NOCRED, &bp);	drive->vp->v_lastr = blocknum;			    /* note the last block we read */	count = min(count, drive->blocksize - bp->b_resid);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?