149589Sbostic /*- 2*63174Sbostic * Copyright (c) 1982, 1986, 1990, 1993 3*63174Sbostic * The Regents of the University of California. All rights reserved. 423461Smckusick * 549589Sbostic * %sccs.include.proprietary.c% 649589Sbostic * 7*63174Sbostic * @(#)kern_physio.c 8.1 (Berkeley) 06/10/93 823461Smckusick */ 98Sbill 1051454Sbostic #include <sys/param.h> 1151454Sbostic #include <sys/systm.h> 1251454Sbostic #include <sys/buf.h> 1351454Sbostic #include <sys/conf.h> 1451454Sbostic #include <sys/proc.h> 1551454Sbostic #include <sys/vnode.h> 168Sbill 1751454Sbostic static void freeswbuf __P((struct buf *)); 1851454Sbostic static struct buf *getswbuf __P((int)); 1948414Skarels 2091Sbill /* 2149672Smckusick * This routine does device I/O for a user process. 2249672Smckusick * 2351759Storek * If the user has the proper access privileges, the process is 248Sbill * marked 'delayed unlock' and the pages involved in the I/O are 2549672Smckusick * faulted and locked. After the completion of the I/O, the pages 268Sbill * are unlocked. 278Sbill */ 287724Swnj physio(strat, bp, dev, rw, mincnt, uio) 297724Swnj int (*strat)(); 307724Swnj register struct buf *bp; 317724Swnj dev_t dev; 327724Swnj int rw; 3334215Sbostic u_int (*mincnt)(); 347724Swnj struct uio *uio; 358Sbill { 3617313Skarels register struct iovec *iov; 3752424Storek register int requested = 0, done = 0; 3847540Skarels register struct proc *p = curproc; 398Sbill char *a; 4034215Sbostic int s, allocbuf = 0, error = 0; 418Sbill 4234215Sbostic if (bp == NULL) { 4334215Sbostic allocbuf = 1; 4434215Sbostic bp = getswbuf(PRIBIO+1); 4534215Sbostic } 4634215Sbostic for (; uio->uio_iovcnt; uio->uio_iov++, uio->uio_iovcnt--) { 4730750Skarels iov = uio->uio_iov; 4852424Storek if (iov->iov_len == 0) 4952424Storek continue; 5034215Sbostic if (!useracc(iov->iov_base, (u_int)iov->iov_len, 5134215Sbostic rw == B_READ ? B_WRITE : B_READ)) { 5234215Sbostic error = EFAULT; 5334215Sbostic break; 5430750Skarels } 5534215Sbostic if (!allocbuf) { /* only if sharing caller's buffer */ 5634215Sbostic s = splbio(); 5734215Sbostic while (bp->b_flags&B_BUSY) { 5834215Sbostic bp->b_flags |= B_WANTED; 5934215Sbostic sleep((caddr_t)bp, PRIBIO+1); 6034215Sbostic } 6134215Sbostic splx(s); 6234215Sbostic } 6330750Skarels bp->b_error = 0; 6447540Skarels bp->b_proc = p; 6542001Smckusick #ifdef HPUXCOMPAT 6642001Smckusick if (ISHPMMADDR(iov->iov_base)) 6742001Smckusick bp->b_un.b_addr = (caddr_t)HPMMBASEADDR(iov->iov_base); 6842001Smckusick else 6942001Smckusick #endif 7030750Skarels bp->b_un.b_addr = iov->iov_base; 7130750Skarels while (iov->iov_len > 0) { 7234215Sbostic bp->b_flags = B_BUSY | B_PHYS | B_RAW | rw; 7330750Skarels bp->b_dev = dev; 7430750Skarels bp->b_blkno = btodb(uio->uio_offset); 7530750Skarels bp->b_bcount = iov->iov_len; 7630750Skarels (*mincnt)(bp); 7738794Skarels requested = bp->b_bcount; 7847540Skarels p->p_flag |= SPHYSIO; 7938794Skarels vslock(a = bp->b_un.b_addr, requested); 8042001Smckusick vmapbuf(bp); 8134215Sbostic (*strat)(bp); 8234215Sbostic s = splbio(); 8334215Sbostic while ((bp->b_flags & B_DONE) == 0) 8434215Sbostic sleep((caddr_t)bp, PRIBIO); 8542001Smckusick vunmapbuf(bp); 8638794Skarels vsunlock(a, requested, rw); 8747540Skarels p->p_flag &= ~SPHYSIO; 8834215Sbostic if (bp->b_flags&B_WANTED) /* rare */ 8930750Skarels wakeup((caddr_t)bp); 9030750Skarels splx(s); 9138794Skarels done = bp->b_bcount - bp->b_resid; 9238794Skarels bp->b_un.b_addr += done; 9338794Skarels iov->iov_len -= done; 9438794Skarels uio->uio_resid -= done; 9538794Skarels uio->uio_offset += done; 9638794Skarels /* temp kludge for disk drives */ 9738794Skarels if (done < requested || bp->b_flags & B_ERROR) 9830750Skarels break; 9930750Skarels } 10034215Sbostic bp->b_flags &= ~(B_BUSY | B_WANTED | B_PHYS | B_RAW); 10137729Smckusick error = biowait(bp); 10238794Skarels /* temp kludge for disk drives */ 10338794Skarels if (done < requested || bp->b_flags & B_ERROR) 10434215Sbostic break; 1058Sbill } 10634215Sbostic if (allocbuf) 10734215Sbostic freeswbuf(bp); 10834215Sbostic return (error); 1098Sbill } 1108Sbill 11149672Smckusick /* 11249672Smckusick * Calculate the maximum size of I/O request that can be requested 11349672Smckusick * in a single operation. This limit is necessary to prevent a single 11449672Smckusick * process from being able to lock more than a fixed amount of memory 11549672Smckusick * in the kernel. 11649672Smckusick */ 11734215Sbostic u_int 1188Sbill minphys(bp) 1197724Swnj struct buf *bp; 1208Sbill { 12110400Ssam if (bp->b_bcount > MAXPHYS) 12210400Ssam bp->b_bcount = MAXPHYS; 1238Sbill } 12434215Sbostic 12551454Sbostic static struct buf * 12634215Sbostic getswbuf(prio) 12734215Sbostic int prio; 12834215Sbostic { 12934215Sbostic int s; 13034215Sbostic struct buf *bp; 13134215Sbostic 13234215Sbostic s = splbio(); 13356387Smckusick while (bswlist.b_actf == NULL) { 13434215Sbostic bswlist.b_flags |= B_WANTED; 13534215Sbostic sleep((caddr_t)&bswlist, prio); 13634215Sbostic } 13756387Smckusick bp = bswlist.b_actf; 13856387Smckusick bswlist.b_actf = bp->b_actf; 13934215Sbostic splx(s); 14034215Sbostic return (bp); 14134215Sbostic } 14234215Sbostic 14351454Sbostic static void 14434215Sbostic freeswbuf(bp) 14534215Sbostic struct buf *bp; 14634215Sbostic { 14734215Sbostic int s; 14834215Sbostic 14934215Sbostic s = splbio(); 15056387Smckusick bp->b_actf = bswlist.b_actf; 15156387Smckusick bswlist.b_actf = bp; 15239148Smckusick if (bp->b_vp) 15339148Smckusick brelvp(bp); 15434215Sbostic if (bswlist.b_flags & B_WANTED) { 15534215Sbostic bswlist.b_flags &= ~B_WANTED; 15634215Sbostic wakeup((caddr_t)&bswlist); 15747540Skarels wakeup((caddr_t)pageproc); 15834215Sbostic } 15934215Sbostic splx(s); 16034215Sbostic } 16134215Sbostic 16249672Smckusick /* 16349672Smckusick * Do a read on a device for a user process. 16449672Smckusick */ 16534215Sbostic rawread(dev, uio) 16634215Sbostic dev_t dev; 16734215Sbostic struct uio *uio; 16834215Sbostic { 16934215Sbostic return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 17034215Sbostic dev, B_READ, minphys, uio)); 17134215Sbostic } 17234215Sbostic 17349672Smckusick /* 17449672Smckusick * Do a write on a device for a user process. 17549672Smckusick */ 17634215Sbostic rawwrite(dev, uio) 17734215Sbostic dev_t dev; 17834215Sbostic struct uio *uio; 17934215Sbostic { 18034215Sbostic return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 18134215Sbostic dev, B_WRITE, minphys, uio)); 18234215Sbostic } 183