Commit | Line | Data |
---|---|---|
5dc2581e | 1 | /*- |
436acd38 KB |
2 | * Copyright (c) 1982, 1986, 1990, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
adb35f79 KB |
4 | * (c) UNIX System Laboratories, Inc. |
5 | * All or some portions of this file are derived from material licensed | |
6 | * to the University of California by American Telephone and Telegraph | |
7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
8 | * the permission of UNIX System Laboratories, Inc. | |
5dc2581e KB |
9 | * |
10 | * %sccs.include.proprietary.c% | |
da7c5cc6 | 11 | * |
adb35f79 | 12 | * @(#)kern_physio.c 8.4 (Berkeley) %G% |
da7c5cc6 | 13 | */ |
961945a8 | 14 | |
251f56ba KB |
15 | #include <sys/param.h> |
16 | #include <sys/systm.h> | |
17 | #include <sys/buf.h> | |
18 | #include <sys/conf.h> | |
19 | #include <sys/proc.h> | |
251f56ba | 20 | #include <sys/vnode.h> |
d301d150 | 21 | |
251f56ba KB |
22 | static void freeswbuf __P((struct buf *)); |
23 | static struct buf *getswbuf __P((int)); | |
edc76308 | 24 | |
663dbc72 | 25 | /* |
d99a6abd KM |
26 | * This routine does device I/O for a user process. |
27 | * | |
4fa687fa | 28 | * If the user has the proper access privileges, the process is |
663dbc72 | 29 | * marked 'delayed unlock' and the pages involved in the I/O are |
d99a6abd | 30 | * faulted and locked. After the completion of the I/O, the pages |
663dbc72 BJ |
31 | * are unlocked. |
32 | */ | |
d6d7360b BJ |
33 | physio(strat, bp, dev, rw, mincnt, uio) |
34 | int (*strat)(); | |
35 | register struct buf *bp; | |
36 | dev_t dev; | |
37 | int rw; | |
c5648f55 | 38 | u_int (*mincnt)(); |
d6d7360b | 39 | struct uio *uio; |
663dbc72 | 40 | { |
a196746e | 41 | register struct iovec *iov; |
a9fcede9 | 42 | register int requested = 0, done = 0; |
8429d022 | 43 | register struct proc *p = curproc; |
663dbc72 | 44 | char *a; |
c5648f55 | 45 | int s, allocbuf = 0, error = 0; |
ec67a3ce MK |
46 | #ifdef SECSIZE |
47 | int bsize; | |
48 | struct partinfo dpart; | |
49 | #endif SECSIZE | |
663dbc72 | 50 | |
ec67a3ce MK |
51 | #ifdef SECSIZE |
52 | if ((unsigned)major(dev) < nchrdev && | |
53 | (*cdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, (caddr_t)&dpart, | |
54 | FREAD) == 0) | |
55 | bsize = dpart.disklab->d_secsize; | |
56 | else | |
57 | bsize = DEV_BSIZE; | |
58 | #endif SECSIZE | |
59 | for (;;) { | |
60 | if (uio->uio_iovcnt == 0) | |
61 | return (0); | |
62 | iov = uio->uio_iov; | |
63 | if (useracc(iov->iov_base, (u_int)iov->iov_len, | |
64 | rw==B_READ? B_WRITE : B_READ) == NULL) | |
65 | return (EFAULT); | |
66 | s = splbio(); | |
67 | while (bp->b_flags&B_BUSY) { | |
68 | bp->b_flags |= B_WANTED; | |
69 | sleep((caddr_t)bp, PRIBIO+1); | |
70 | } | |
c5648f55 KB |
71 | if (!allocbuf) { /* only if sharing caller's buffer */ |
72 | s = splbio(); | |
73 | while (bp->b_flags&B_BUSY) { | |
74 | bp->b_flags |= B_WANTED; | |
75 | sleep((caddr_t)bp, PRIBIO+1); | |
76 | } | |
77 | splx(s); | |
78 | } | |
ec67a3ce MK |
79 | bp->b_error = 0; |
80 | bp->b_proc = u.u_procp; | |
81 | #ifdef SECSIZE | |
82 | bp->b_blksize = bsize; | |
83 | #endif SECSIZE | |
84 | bp->b_un.b_addr = iov->iov_base; | |
85 | while (iov->iov_len > 0) { | |
86 | bp->b_flags = B_BUSY | B_PHYS | rw; | |
87 | bp->b_dev = dev; | |
88 | #ifdef SECSIZE | |
89 | bp->b_blkno = uio->uio_offset / bsize; | |
90 | #else SECSIZE | |
91 | bp->b_blkno = btodb(uio->uio_offset); | |
92 | #endif SECSIZE | |
93 | bp->b_bcount = iov->iov_len; | |
94 | (*mincnt)(bp); | |
95 | c = bp->b_bcount; | |
96 | u.u_procp->p_flag |= SPHYSIO; | |
97 | vslock(a = bp->b_un.b_addr, c); | |
98 | physstrat(bp, strat, PRIBIO); | |
99 | (void) splbio(); | |
100 | vsunlock(a, c, rw); | |
101 | u.u_procp->p_flag &= ~SPHYSIO; | |
102 | if (bp->b_flags&B_WANTED) | |
103 | wakeup((caddr_t)bp); | |
104 | splx(s); | |
105 | c -= bp->b_resid; | |
106 | bp->b_un.b_addr += c; | |
107 | iov->iov_len -= c; | |
108 | uio->uio_resid -= c; | |
109 | uio->uio_offset += c; | |
110 | /* temp kludge for tape drives */ | |
111 | if (bp->b_resid || (bp->b_flags&B_ERROR)) | |
112 | break; | |
113 | } | |
114 | bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS); | |
115 | error = geterror(bp); | |
ec67a3ce MK |
116 | if (bp->b_resid || error) |
117 | return (error); | |
118 | uio->uio_iov++; | |
119 | uio->uio_iovcnt--; | |
663dbc72 | 120 | } |
c5648f55 KB |
121 | if (allocbuf) |
122 | freeswbuf(bp); | |
123 | return (error); | |
663dbc72 BJ |
124 | } |
125 | ||
d99a6abd KM |
126 | /* |
127 | * Calculate the maximum size of I/O request that can be requested | |
128 | * in a single operation. This limit is necessary to prevent a single | |
129 | * process from being able to lock more than a fixed amount of memory | |
130 | * in the kernel. | |
131 | */ | |
c5648f55 | 132 | u_int |
663dbc72 | 133 | minphys(bp) |
d6d7360b | 134 | struct buf *bp; |
663dbc72 | 135 | { |
35a494b8 SL |
136 | if (bp->b_bcount > MAXPHYS) |
137 | bp->b_bcount = MAXPHYS; | |
663dbc72 | 138 | } |
c5648f55 | 139 | |
251f56ba | 140 | static struct buf * |
c5648f55 KB |
141 | getswbuf(prio) |
142 | int prio; | |
143 | { | |
144 | int s; | |
145 | struct buf *bp; | |
146 | ||
147 | s = splbio(); | |
360d7067 | 148 | while (bswlist.b_actf == NULL) { |
c5648f55 KB |
149 | bswlist.b_flags |= B_WANTED; |
150 | sleep((caddr_t)&bswlist, prio); | |
151 | } | |
360d7067 KM |
152 | bp = bswlist.b_actf; |
153 | bswlist.b_actf = bp->b_actf; | |
c5648f55 KB |
154 | splx(s); |
155 | return (bp); | |
156 | } | |
157 | ||
251f56ba | 158 | static void |
c5648f55 KB |
159 | freeswbuf(bp) |
160 | struct buf *bp; | |
161 | { | |
162 | int s; | |
163 | ||
164 | s = splbio(); | |
360d7067 KM |
165 | bp->b_actf = bswlist.b_actf; |
166 | bswlist.b_actf = bp; | |
343a57bd KM |
167 | if (bp->b_vp) |
168 | brelvp(bp); | |
c5648f55 KB |
169 | if (bswlist.b_flags & B_WANTED) { |
170 | bswlist.b_flags &= ~B_WANTED; | |
171 | wakeup((caddr_t)&bswlist); | |
8429d022 | 172 | wakeup((caddr_t)pageproc); |
c5648f55 KB |
173 | } |
174 | splx(s); | |
175 | } | |
176 | ||
d99a6abd KM |
177 | /* |
178 | * Do a read on a device for a user process. | |
179 | */ | |
c5648f55 KB |
180 | rawread(dev, uio) |
181 | dev_t dev; | |
182 | struct uio *uio; | |
183 | { | |
184 | return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, | |
185 | dev, B_READ, minphys, uio)); | |
186 | } | |
187 | ||
d99a6abd KM |
188 | /* |
189 | * Do a write on a device for a user process. | |
190 | */ | |
c5648f55 KB |
191 | rawwrite(dev, uio) |
192 | dev_t dev; | |
193 | struct uio *uio; | |
194 | { | |
195 | return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, | |
196 | dev, B_WRITE, minphys, uio)); | |
197 | } |