📄 rf_kintf.c
字号:
/* make a copy of the recon request so that we don't rely on the user's buffer */ RF_Malloc(rrcopy, sizeof(*rrcopy), (struct rf_recon_req *)); bcopy(rr, rrcopy, sizeof(*rr)); rrcopy->raidPtr = (void *) raidPtrs[raidID]; LOCK_RECON_Q_MUTEX(); rrcopy->next = recon_queue; recon_queue = rrcopy; wakeup(&recon_queue); UNLOCK_RECON_Q_MUTEX(); return(0); /* invoke a copyback operation after recon on whatever disk needs it, if any */ case RAIDFRAME_COPYBACK: /* borrow the current thread to get this done */ rf_CopybackReconstructedData(raidPtrs[raidID]); return(0); /* return the percentage completion of reconstruction */ case RAIDFRAME_CHECKRECON: row = *(int *) data; if (row < 0 || row >= raidPtrs[raidID]->numRow) return(EINVAL); if (raidPtrs[raidID]->status[row] != rf_rs_reconstructing) *(int *) data = 100; else *(int *) data = raidPtrs[raidID]->reconControl[row]->percentComplete; return(0); /* the sparetable daemon calls this to wait for the kernel to need a spare table. * this ioctl does not return until a spare table is needed. * XXX -- calling mpsleep here in the ioctl code is almost certainly wrong and evil. -- XXX * XXX -- I should either compute the spare table in the kernel, or have a different -- XXX * XXX -- interface (a different character device) for delivering the table -- XXX */ case RAIDFRAME_SPARET_WAIT: RF_LOCK_MUTEX(rf_sparet_wait_mutex); while (!rf_sparet_wait_queue) mpsleep(&rf_sparet_wait_queue, (PZERO+1)|PCATCH, "sparet wait", 0, (void *) simple_lock_addr(rf_sparet_wait_mutex), MS_LOCK_SIMPLE); waitreq = rf_sparet_wait_queue; rf_sparet_wait_queue = rf_sparet_wait_queue->next; RF_UNLOCK_MUTEX(rf_sparet_wait_mutex); *((RF_SparetWait_t *) data) = *waitreq; /* structure assignment */ RF_Free(waitreq, sizeof(*waitreq)); return(0); /* wakes up a process waiting on SPARET_WAIT and puts an error code in it that will cause the dameon to exit */ case RAIDFRAME_ABORT_SPARET_WAIT: RF_Malloc(waitreq, sizeof(*waitreq), (RF_SparetWait_t *)); waitreq->fcol = -1; RF_LOCK_MUTEX(rf_sparet_wait_mutex); waitreq->next = rf_sparet_wait_queue; rf_sparet_wait_queue = waitreq; RF_UNLOCK_MUTEX(rf_sparet_wait_mutex); wakeup(&rf_sparet_wait_queue); return(0); /* used by the spare table daemon to deliver a spare table into the kernel */ case RAIDFRAME_SEND_SPARET: /* install the spare table */ retcode = rf_SetSpareTable(raidPtrs[raidID],*(void **) data); /* respond to the requestor. the return status of the spare table installation is passed in the "fcol" field */ RF_Malloc(waitreq, sizeof(*waitreq), (RF_SparetWait_t *)); waitreq->fcol = retcode; RF_LOCK_MUTEX(rf_sparet_wait_mutex); waitreq->next = rf_sparet_resp_queue; rf_sparet_resp_queue = waitreq; wakeup(&rf_sparet_resp_queue); RF_UNLOCK_MUTEX(rf_sparet_wait_mutex); return(retcode);#endif /* RAIDFRAME_RECON > 0 */ default: break; /* fall through to the os-specific code below */ } if (!raidPtrs[raidID]->valid) return(EINVAL); /* * Add support for "regular" device ioctls here. * Eventually, this may include disk label stuff. */ switch (cmd) { default: retcode = EINVAL; break; } return(retcode);}/********************************************************* * * support code * ********************************************************/static int rf_WrapUpTestAcc(ta, raidPtr) struct rf_test_acc *ta; RF_Raid_t *raidPtr;{ struct buf *bp = (struct buf *)ta->bp; int nbytes = ta->numSector << raidPtr->logBytesPerSector; /* unwire memory */ vm_map_pageable(proc_to_task(bp->b_proc)->map, trunc_page(ta->buf), round_page(ta->buf+nbytes), VM_PROT_NONE); /* release the buf structure */ ubc_buffree(bp); return(0);}/* allocate a new testacc descriptor & copy the input into it */static struct rf_test_acc *rf_DupTestAccDesc(ta) struct rf_test_acc *ta;{ struct rf_test_acc *new; RF_Malloc(new,sizeof(struct rf_test_acc),(struct rf_test_acc *)); if (new == NULL) return(NULL); bcopy(ta, new, sizeof(*ta)); return(new);}/* the callback that gets invoked when an async test acc completes */static void rf_AsyncTestAccCallbackFunc(ta) struct rf_test_acc *ta;{ if (rf_debugKernelAccess) { printf("completed async test acc %lx\n", ta); } /* place the testacc descriptor on the "done" list */ RF_LOCK_MUTEX(rf_async_done_q_mutex); ta->next = NULL; if (!rf_async_done_qt) rf_async_done_qt = rf_async_done_qh = ta; else {rf_async_done_qt->next = ta; rf_async_done_qt = ta;} RF_UNLOCK_MUTEX(rf_async_done_q_mutex);}/* the thread that does reconstruction in the kernel */void rf_ReconKernelThread(){ struct rf_recon_req *req; RF_Thread_t thread; thread = current_thread(); thread_swappable(thread, FALSE); /* this is one priority level _lower_ than regular system threads */ thread->priority = thread->sched_pri = BASEPRI_SYSTEM+1; spl0(); while (1) { /* grab the next reconstruction request from the queue */ LOCK_RECON_Q_MUTEX(); while (!recon_queue) { mpsleep(&recon_queue, PZERO, "recon q", 0, (void *)simple_lock_addr(recon_queue_mutex), MS_LOCK_SIMPLE); } req = recon_queue; recon_queue = recon_queue->next; UNLOCK_RECON_Q_MUTEX(); /* * If flags specifies that we should start recon, this call * will not return until reconstruction completes, fails, or is aborted. */ rf_FailDisk((RF_Raid_t *) req->raidPtr, req->row, req->col, ((req->flags&RF_FDFLAGS_RECON) ? 1 : 0)); RF_Free(req, sizeof(*req)); }}/* wake up the daemon & tell it to get us a spare table * XXX * the entries in the queues should be tagged with the raidPtr * so that in the extremely rare case that two recons happen at once, we know for * which device were requesting a spare table * XXX */int rf_GetSpareTableFromDaemon(req) RF_SparetWait_t *req;{ int retcode; RF_LOCK_MUTEX(rf_sparet_wait_mutex); req->next = rf_sparet_wait_queue; rf_sparet_wait_queue = req; wakeup(&rf_sparet_wait_queue); /* mpsleep unlocks the mutex */ while (!rf_sparet_resp_queue) mpsleep(&rf_sparet_resp_queue, PZERO, "sparet resp", 0, (void *) simple_lock_addr(rf_sparet_wait_mutex), MS_LOCK_SIMPLE); req = rf_sparet_resp_queue; rf_sparet_resp_queue = req->next; RF_UNLOCK_MUTEX(rf_sparet_wait_mutex); retcode = req->fcol; RF_Free(req, sizeof(*req)); /* this is not the same req as we alloc'd */ return(retcode);}/* map a page from user space to kernel space */caddr_t rf_MapToKernelSpace(bp, addr) struct buf *bp; caddr_t addr;{ vm_offset_t phys; phys = pmap_extract(proc_to_task(bp->b_proc)->map->vm_pmap, addr); if (!phys) return(NULL); return((caddr_t)PHYS_TO_KSEG(phys));}/* this does a bzero, remapping pages from user space to kernel space. * the caller must check to see if buf is already a kernel buffer, * and not invoke this if it is. See the RF_BZERO macro in rf_degdags.c. * * rather stupid to muck around casting to/from caddr_t here. * I should really unify all this. */int rf_BzeroWithRemap(bp, databuf, len) struct buf *bp; char *databuf; int len;{ caddr_t kptr; int len_this_time; while (len > 0) { len_this_time = RF_MIN(len, RF_BLIP(databuf)); kptr = (char *) rf_MapToKernelSpace(bp, (caddr_t) databuf); /* XXX -- this condition is currently ignored & will cause a panic -- XXX */ if (!kptr) return(EFAULT); bzero(kptr, len_this_time); len -= len_this_time; } return(0);}/* a wrapper around rf_DoAccess that extracts appropriate info from the bp & passes it down. * any calls originating in the kernel must use non-blocking I/O * do some extra sanity checking to return "appropriate" error values for * certain conditions (to make some standard utilities work) */int rf_DoAccessKernel(raidPtr, bp, flags, cbFunc, cbArg) RF_Raid_t *raidPtr; struct buf *bp; RF_RaidAccessFlags_t flags; void (*cbFunc)(); void *cbArg;{ RF_SectorCount_t num_blocks, pb, sum; RF_RaidAddr_t raid_addr; int retcode; raid_addr = bp->b_blkno; num_blocks = bp->b_bcount >> raidPtr->logBytesPerSector; pb = (bp->b_bcount&raidPtr->sectorMask) ? 1 : 0; sum = raid_addr + num_blocks + pb; if (rf_debugKernelAccess) { printf("raid_addr=%ld sum=%ld\n", (long)raid_addr, (long)sum); } if ((sum >= raidPtr->totalSectors) || (sum < raid_addr) || (sum < num_blocks) || (sum < pb)) { bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); return(bp->b_error); } /* * XXX rf_DoAccess() should do this, not just DoAccessKernel() */ if (bp->b_bcount & raidPtr->sectorMask) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); return(bp->b_error); } /* don't ever condition on bp->b_flags & B_WRITE. always condition on B_READ instead */ retcode = rf_DoAccess(raidPtr, (bp->b_flags & B_READ) ? RF_IO_TYPE_READ : RF_IO_TYPE_WRITE, 0, raid_addr, num_blocks, bp->b_un.b_addr, bp, NULL, NULL, RF_DAG_NONBLOCKING_IO|flags, NULL, cbFunc, cbArg); return(retcode);}/* invoke an I/O from kernel mode. Disk queue should be locked upon entry */int rf_DispatchKernelIO(queue, req) RF_DiskQueue_t *queue; RF_DiskQueueData_t *req;{ int retcode, op = (req->type == RF_IO_TYPE_READ) ? B_READ : B_WRITE; struct buf *bp; req->queue = queue; switch (req->type) { case RF_IO_TYPE_NOP: /* used primarily to unlock a locked queue */ Dprintf2("rf_DispatchKernelIO: NOP to r %d c %d\n",queue->row,queue->col); req->bp->b_driver_un_1.pointvalue = (void *) req; queue->numOutstanding++; KernelWakeupFunc(req->bp); break; case RF_IO_TYPE_READ: case RF_IO_TYPE_WRITE: if (req->tracerec) { RF_ETIMER_START(req->tracerec->timer); } bp = req->bp; InitBP(bp, op, queue->dev, req->sectorOffset, req->numSector, req->buf, KernelWakeupFunc, (void *) req, queue->raidPtr->logBytesPerSector, req->b_proc); if (rf_debugKernelAccess) { printf("dispatch: bp->b_blkno = %ld\n", bp->b_blkno); } queue->numOutstanding++; queue->last_deq_sector = req->sectorOffset; /* acc wouldn't have been let in if there were any pending reqs at any other priority */ queue->curPriority = req->priority; Dprintf3("rf_DispatchKernelIO: %c to row %d col %d\n", req->type, queue->row, queue->col); BDEVSW_STRATEGY(major(bp->b_dev), bp, retcode); /* no actual retcode here: cdisk_strategy has type void */ break; default: panic("bad req->type in rf_DispatchKernelIO"); } return(0);}/* this is the callback function associated with a I/O invoked from kernel code. */static void KernelWakeupFunc(bp) struct buf *bp;{ RF_DiskQueueData_t *req = (RF_DiskQueueData_t *) bp->b_driver_un_1.pointvalue; RF_DiskQueue_t *queue = (RF_DiskQueue_t *) req->queue; if (req->tracerec) { RF_ETIMER_STOP(req->tracerec->timer); RF_ETIMER_EVAL(req->tracerec->timer); RF_LOCK_MUTEX(rf_tracing_mutex); req->tracerec->diskwait_us += RF_ETIMER_VAL_US(req->tracerec->timer); req->tracerec->phys_io_us += RF_ETIMER_VAL_US(req->tracerec->timer); req->tracerec->num_phys_ios++; RF_UNLOCK_MUTEX(rf_tracing_mutex); } rf_DiskIOComplete(queue, req, (bp->b_flags & B_ERROR) ? 1 : 0); (req->CompleteFunc)(req->argument, (bp->b_flags & B_ERROR) ? 1 : 0);}/* * creates a buf structure for doing an I/O in the kernel. */static void InitBP( struct buf *bp, unsigned rw_flag, dev_t dev, RF_SectorNum_t startSect, RF_SectorCount_t numSect, caddr_t buf, void (*cbFunc)(), void *cbArg, int logBytesPerSector, struct proc *b_proc){ bp->b_flags = B_PHYS | rw_flag; bp->b_bcount = numSect << logBytesPerSector; bp->b_bufsize = bp->b_bcount; bp->b_error = 0; bp->b_dev = dev; bp->b_un.b_addr = buf; bp->b_blkno = startSect; bp->b_resid = 0; bp->b_proc = b_proc; bp->b_iodone = cbFunc; bp->b_driver_un_1.pointvalue = cbArg; /* used as the argument to the callback */ bp->b_vp = NULL;}#endif /* KERNEL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -