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 + -
显示快捷键?