kern_physio.c revision 248515
1169695Skan/*- 2169695Skan * Copyright (c) 1994 John S. Dyson 3258826Spfg * All rights reserved. 4258826Spfg * 5169695Skan * Redistribution and use in source and binary forms, with or without 6169695Skan * modification, are permitted provided that the following conditions 7169695Skan * are met: 8169695Skan * 1. Redistributions of source code must retain the above copyright 9169695Skan * notice immediately at the beginning of the file, without modification, 10169695Skan * this list of conditions, and the following disclaimer. 11169695Skan * 2. Redistributions in binary form must reproduce the above copyright 12169695Skan * notice, this list of conditions and the following disclaimer in the 13169695Skan * documentation and/or other materials provided with the distribution. 14169695Skan * 3. Absolutely no warranty of function or purpose is made by the author 15169695Skan * John S. Dyson. 16169695Skan * 4. Modifications may be freely made to this file if the above conditions 17169695Skan * are met. 18169695Skan */ 19169695Skan 20169695Skan#include <sys/cdefs.h> 21169695Skan__FBSDID("$FreeBSD: head/sys/kern/kern_physio.c 248515 2013-03-19 14:43:57Z kib $"); 22169695Skan 23169695Skan#include <sys/param.h> 24169695Skan#include <sys/systm.h> 25169695Skan#include <sys/bio.h> 26169695Skan#include <sys/buf.h> 27169695Skan#include <sys/conf.h> 28169695Skan#include <sys/proc.h> 29169695Skan#include <sys/uio.h> 30169695Skan 31169695Skan#include <vm/vm.h> 32169695Skan#include <vm/vm_extern.h> 33169695Skan 34169695Skanint 35169695Skanphysio(struct cdev *dev, struct uio *uio, int ioflag) 36169695Skan{ 37169695Skan int i; 38169695Skan int error; 39169695Skan caddr_t sa; 40169695Skan u_int iolen; 41169695Skan struct buf *bp; 42169695Skan 43169695Skan /* Keep the process UPAGES from being swapped. XXX: why ? */ 44169695Skan PHOLD(curproc); 45169695Skan 46169695Skan bp = getpbuf(NULL); 47169695Skan sa = bp->b_data; 48169695Skan error = 0; 49169695Skan 50169695Skan /* XXX: sanity check */ 51169695Skan if(dev->si_iosize_max < PAGE_SIZE) { 52169695Skan printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 53169695Skan devtoname(dev), dev->si_iosize_max); 54169695Skan dev->si_iosize_max = DFLTPHYS; 55169695Skan } 56169695Skan 57169695Skan for (i = 0; i < uio->uio_iovcnt; i++) { 58169695Skan while (uio->uio_iov[i].iov_len) { 59169695Skan bp->b_flags = 0; 60169695Skan if (uio->uio_rw == UIO_READ) { 61169695Skan bp->b_iocmd = BIO_READ; 62169695Skan curthread->td_ru.ru_inblock++; 63169695Skan } else { 64169695Skan bp->b_iocmd = BIO_WRITE; 65169695Skan curthread->td_ru.ru_oublock++; 66169695Skan } 67169695Skan bp->b_iodone = bdone; 68169695Skan bp->b_data = uio->uio_iov[i].iov_base; 69169695Skan bp->b_bcount = uio->uio_iov[i].iov_len; 70169695Skan bp->b_offset = uio->uio_offset; 71169695Skan bp->b_iooffset = uio->uio_offset; 72169695Skan bp->b_saveaddr = sa; 73169695Skan 74169695Skan /* Don't exceed drivers iosize limit */ 75169695Skan if (bp->b_bcount > dev->si_iosize_max) 76169695Skan bp->b_bcount = dev->si_iosize_max; 77169695Skan 78169695Skan /* 79169695Skan * Make sure the pbuf can map the request 80169695Skan * XXX: The pbuf has kvasize = MAXPHYS so a request 81169695Skan * XXX: larger than MAXPHYS - PAGE_SIZE must be 82169695Skan * XXX: page aligned or it will be fragmented. 83169695Skan */ 84169695Skan iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK; 85169695Skan if ((bp->b_bcount + iolen) > bp->b_kvasize) { 86169695Skan bp->b_bcount = bp->b_kvasize; 87169695Skan if (iolen != 0) 88169695Skan bp->b_bcount -= PAGE_SIZE; 89169695Skan } 90169695Skan bp->b_bufsize = bp->b_bcount; 91169695Skan 92169695Skan bp->b_blkno = btodb(bp->b_offset); 93169695Skan 94169695Skan if (uio->uio_segflg == UIO_USERSPACE) 95169695Skan if (vmapbuf(bp, 0) < 0) { 96169695Skan error = EFAULT; 97169695Skan goto doerror; 98169695Skan } 99169695Skan 100169695Skan dev_strategy(dev, bp); 101169695Skan if (uio->uio_rw == UIO_READ) 102169695Skan bwait(bp, PRIBIO, "physrd"); 103169695Skan else 104169695Skan bwait(bp, PRIBIO, "physwr"); 105169695Skan 106169695Skan if (uio->uio_segflg == UIO_USERSPACE) 107169695Skan vunmapbuf(bp); 108169695Skan iolen = bp->b_bcount - bp->b_resid; 109169695Skan if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR)) 110169695Skan goto doerror; /* EOF */ 111169695Skan uio->uio_iov[i].iov_len -= iolen; 112169695Skan uio->uio_iov[i].iov_base = 113169695Skan (char *)uio->uio_iov[i].iov_base + iolen; 114169695Skan uio->uio_resid -= iolen; 115169695Skan uio->uio_offset += iolen; 116169695Skan if( bp->b_ioflags & BIO_ERROR) { 117169695Skan error = bp->b_error; 118169695Skan goto doerror; 119169695Skan } 120169695Skan } 121169695Skan } 122169695Skandoerror: 123169695Skan relpbuf(bp, NULL); 124169695Skan PRELE(curproc); 125169695Skan return (error); 126169695Skan} 127169695Skan