vinumrequest.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 998 行 · 第 1/3 页
C
998 行
/*- * 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: vinumrequest.c,v 1.7.2.4 1999/04/06 09:05:58 grog Exp $ */#define REALLYKERNEL#include "opt_vinum.h"#include <dev/vinum/vinumhdr.h>#include <dev/vinum/request.h>#include <miscfs/specfs/specdev.h>#include <sys/resourcevar.h>enum requeststatus bre(struct request *rq, int plexno, daddr_t * diskstart, daddr_t diskend);enum requeststatus bre5(struct request *rq, int plexno, daddr_t * diskstart, daddr_t diskend);enum requeststatus build_read_request(struct request *rq, int volplexno);enum requeststatus build_write_request(struct request *rq);enum requeststatus build_rq_buffer(struct rqelement *rqe, struct plex *plex);void freerq(struct request *rq);int find_alternate_sd(struct request *rq);int check_range_covered(struct request *);void complete_rqe(struct buf *bp);void complete_raid5_write(struct rqelement *);int abortrequest(struct request *rq, int error);void sdio_done(struct buf *bp);int vinum_bounds_check(struct buf *bp, struct volume *vol);caddr_t allocdatabuf(struct rqelement *rqe);void freedatabuf(struct rqelement *rqe);#ifdef VINUMDEBUGstruct rqinfo rqinfo[RQINFO_SIZE];struct rqinfo *rqip = rqinfo;void logrq(enum rqinfo_type type, union rqinfou info, struct buf *ubp){ int s = splhigh(); microtime(&rqip->timestamp); /* when did this happen? */ rqip->type = type; rqip->bp = ubp; /* user buffer */ switch (type) { case loginfo_user_bp: case loginfo_user_bpl: bcopy(info.bp, &rqip->info.b, sizeof(struct buf)); break; case loginfo_iodone: case loginfo_rqe: case loginfo_raid5_data: case loginfo_raid5_parity: bcopy(info.rqe, &rqip->info.rqe, sizeof(struct rqelement)); break; case loginfo_unused: break; } rqip++; if (rqip >= &rqinfo[RQINFO_SIZE]) /* wrap around */ rqip = rqinfo; splx(s);}#endifvoid vinumstrategy(struct buf *bp){ int volno; struct volume *vol = NULL; struct devcode *device = (struct devcode *) &bp->b_dev; /* decode device number */ switch (device->type) { case VINUM_SD_TYPE: case VINUM_RAWSD_TYPE: sdio(bp); return; /* * In fact, vinum doesn't handle drives: they're * handled directly by the disk drivers */ case VINUM_DRIVE_TYPE: default: bp->b_error = EIO; /* I/O error */ bp->b_flags |= B_ERROR; biodone(bp); return; case VINUM_VOLUME_TYPE: /* volume I/O */ volno = Volno(bp->b_dev); vol = &VOL[volno]; if (vol->state != volume_up) { /* can't access this volume */ bp->b_error = EIO; /* I/O error */ bp->b_flags |= B_ERROR; biodone(bp); return; } if (vinum_bounds_check(bp, vol) <= 0) { /* don't like them bounds */ biodone(bp); /* have nothing to do with this */ return; } /* FALLTHROUGH */ /* * Plex I/O is pretty much the same as volume I/O * for a single plex. Indicate this by passing a NULL * pointer (set above) for the volume */ case VINUM_PLEX_TYPE: case VINUM_RAWPLEX_TYPE: bp->b_resid = bp->b_bcount; /* transfer everything */ vinumstart(bp, 0); return; }}/* * Start a transfer. Return -1 on error, * 0 if OK, 1 if we need to retry. * Parameter reviveok is set when doing * transfers for revives: it allows transfers to * be started immediately when a revive is in * progress. During revive, normal transfers * are queued if they share address space with * a currently active revive operation. */int vinumstart(struct buf *bp, int reviveok){ int plexno; int maxplex; /* maximum number of plexes to handle */ struct volume *vol; struct request *rq; /* build up our request here */ enum requeststatus status;#if VINUMDEBUG if (debug & DEBUG_LASTREQS) logrq(loginfo_user_bp, (union rqinfou) bp, bp);#endif /* * XXX In these routines, we're assuming that * we will always be called with bp->b_bcount * which is a multiple of the sector size. This * is a reasonable assumption, since we are only * called from system routines. Should we check * anyway? */ if ((bp->b_bcount % DEV_BSIZE) != 0) { /* bad length */ bp->b_error = EINVAL; /* invalid size */ bp->b_flags |= B_ERROR; biodone(bp); return -1; } rq = (struct request *) Malloc(sizeof(struct request)); /* allocate a request struct */ if (rq == NULL) { /* can't do it */ bp->b_error = ENOMEM; /* can't get memory */ bp->b_flags |= B_ERROR; biodone(bp); return -1; } bzero(rq, sizeof(struct request)); /* * Note the volume ID. This can be NULL, which * the request building functions use as an * indication for single plex I/O */ rq->bp = bp; /* and the user buffer struct */ if (DEVTYPE(bp->b_dev) == VINUM_VOLUME_TYPE) { /* it's a volume, */ rq->volplex.volno = Volno(bp->b_dev); /* get the volume number */ vol = &VOL[rq->volplex.volno]; /* and point to it */ vol->active++; /* one more active request */ maxplex = vol->plexes; /* consider all its plexes */ } else { vol = NULL; /* no volume */ rq->volplex.plexno = Plexno(bp->b_dev); /* point to the plex */ rq->isplex = 1; /* note that it's a plex */ maxplex = 1; /* just the one plex */ } if (bp->b_flags & B_READ) { /* * This is a read request. Decide * which plex to read from. * * There's a potential race condition here, * since we're not locked, and we could end * up multiply incrementing the round-robin * counter. This doesn't have any serious * effects, however. */ if (vol != NULL) { vol->reads++; vol->bytes_read += bp->b_bcount; plexno = vol->preferred_plex; /* get the plex to use */ if (plexno < 0) { /* round robin */ plexno = vol->last_plex_read; vol->last_plex_read++; if (vol->last_plex_read == vol->plexes) /* got the the end? */ vol->last_plex_read = 0; /* wrap around */ } status = build_read_request(rq, plexno); /* build a request */ } else { daddr_t diskaddr = bp->b_blkno; /* start offset of transfer */ status = bre(rq, /* build a request list */ rq->volplex.plexno, &diskaddr, diskaddr + (bp->b_bcount / DEV_BSIZE)); } if ((status > REQUEST_RECOVERED) /* can't satisfy it */ ||(bp->b_flags & B_DONE)) { /* XXX shouldn't get this without bad status */ if (status == REQUEST_DOWN) { /* not enough subdisks */ bp->b_error = EIO; /* I/O error */ bp->b_flags |= B_ERROR; } biodone(bp); freerq(rq); return -1; } return launch_requests(rq, reviveok); /* now start the requests if we can */ } else /* * This is a write operation. We write to all * plexes. If this is a RAID 5 plex, we must also * update the parity stripe. */ { if (vol != NULL) { vol->writes++; vol->bytes_written += bp->b_bcount; status = build_write_request(rq); /* Not all the subdisks are up */ } else { /* plex I/O */ daddr_t diskstart; diskstart = bp->b_blkno; /* start offset of transfer */ status = bre(rq, Plexno(bp->b_dev), &diskstart, bp->b_blkno + (bp->b_bcount / DEV_BSIZE)); /* build requests for the plex */ } if ((status > REQUEST_RECOVERED) /* can't satisfy it */ ||(bp->b_flags & B_DONE)) { /* XXX shouldn't get this without bad status */ if (status == REQUEST_DOWN) { /* not enough subdisks */ bp->b_error = EIO; /* I/O error */ bp->b_flags |= B_ERROR; } if ((bp->b_flags & B_DONE) == 0) biodone(bp); freerq(rq); return -1; } return launch_requests(rq, reviveok); /* now start the requests if we can */ }}/* * Call the low-level strategy routines to * perform the requests in a struct request */int launch_requests(struct request *rq, int reviveok){ struct rqgroup *rqg; int rqno; /* loop index */ struct rqelement *rqe; /* current element */ int s; /* * First find out whether we're reviving, and the * request contains a conflict. If so, we hang * the request off plex->waitlist of the first * plex we find which is reviving */ if ((rq->flags & XFR_REVIVECONFLICT) /* possible revive conflict */ &&(!reviveok)) { /* and we don't want to do it now, */ struct sd *sd; struct request *waitlist; /* point to the waitlist */ sd = &SD[rq->sdno]; if (sd->waitlist != NULL) { /* something there already, */ waitlist = sd->waitlist; while (waitlist->next != NULL) /* find the end */ waitlist = waitlist->next; waitlist->next = rq; /* hook our request there */ } else sd->waitlist = rq; /* hook our request at the front */#if VINUMDEBUG if (debug & DEBUG_REVIVECONFLICT) log(LOG_DEBUG, "Revive conflict sd %d: %x\n%s dev 0x%x, offset 0x%x, length %ld\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?