Thu Jan 21 02:14:42 2010 UTC ()
Take care not to dereference a NULL softc.


(dyoung)
diff -r1.61 -r1.62 src/sys/dev/md.c

cvs diff -r1.61 -r1.62 src/sys/dev/md.c (switch to unified diff)

--- src/sys/dev/md.c 2009/10/22 20:15:45 1.61
+++ src/sys/dev/md.c 2010/01/21 02:14:42 1.62
@@ -1,550 +1,551 @@ @@ -1,550 +1,551 @@
1/* $NetBSD: md.c,v 1.61 2009/10/22 20:15:45 snj Exp $ */ 1/* $NetBSD: md.c,v 1.62 2010/01/21 02:14:42 dyoung Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1995 Gordon W. Ross, Leo Weppelman. 4 * Copyright (c) 1995 Gordon W. Ross, Leo Weppelman.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28/* 28/*
29 * This implements a general-purpose memory-disk. 29 * This implements a general-purpose memory-disk.
30 * See md.h for notes on the config types. 30 * See md.h for notes on the config types.
31 * 31 *
32 * Note that this driver provides the same functionality 32 * Note that this driver provides the same functionality
33 * as the MFS filesystem hack, but this is better because 33 * as the MFS filesystem hack, but this is better because
34 * you can use this for any filesystem type you'd like! 34 * you can use this for any filesystem type you'd like!
35 * 35 *
36 * Credit for most of the kmem ramdisk code goes to: 36 * Credit for most of the kmem ramdisk code goes to:
37 * Leo Weppelman (atari) and Phil Nelson (pc532) 37 * Leo Weppelman (atari) and Phil Nelson (pc532)
38 * Credit for the ideas behind the "user space memory" code goes 38 * Credit for the ideas behind the "user space memory" code goes
39 * to the authors of the MFS implementation. 39 * to the authors of the MFS implementation.
40 */ 40 */
41 41
42#include <sys/cdefs.h> 42#include <sys/cdefs.h>
43__KERNEL_RCSID(0, "$NetBSD: md.c,v 1.61 2009/10/22 20:15:45 snj Exp $"); 43__KERNEL_RCSID(0, "$NetBSD: md.c,v 1.62 2010/01/21 02:14:42 dyoung Exp $");
44 44
45#include "opt_md.h" 45#include "opt_md.h"
46#include "opt_tftproot.h" 46#include "opt_tftproot.h"
47 47
48#include <sys/param.h> 48#include <sys/param.h>
49#include <sys/kernel.h> 49#include <sys/kernel.h>
50#include <sys/malloc.h> 50#include <sys/malloc.h>
51#include <sys/systm.h> 51#include <sys/systm.h>
52#include <sys/buf.h> 52#include <sys/buf.h>
53#include <sys/bufq.h> 53#include <sys/bufq.h>
54#include <sys/device.h> 54#include <sys/device.h>
55#include <sys/disk.h> 55#include <sys/disk.h>
56#include <sys/stat.h> 56#include <sys/stat.h>
57#include <sys/proc.h> 57#include <sys/proc.h>
58#include <sys/conf.h> 58#include <sys/conf.h>
59#include <sys/disklabel.h> 59#include <sys/disklabel.h>
60 60
61#include <uvm/uvm_extern.h> 61#include <uvm/uvm_extern.h>
62 62
63#include <dev/md.h> 63#include <dev/md.h>
64 64
65/* 65/*
66 * The user-space functionality is included by default. 66 * The user-space functionality is included by default.
67 * Use `options MEMORY_DISK_SERVER=0' to turn it off. 67 * Use `options MEMORY_DISK_SERVER=0' to turn it off.
68 */ 68 */
69#ifndef MEMORY_DISK_SERVER 69#ifndef MEMORY_DISK_SERVER
70#error MEMORY_DISK_SERVER should be defined by opt_md.h 70#error MEMORY_DISK_SERVER should be defined by opt_md.h
71#endif /* MEMORY_DISK_SERVER */ 71#endif /* MEMORY_DISK_SERVER */
72 72
73/* 73/*
74 * We should use the raw partition for ioctl. 74 * We should use the raw partition for ioctl.
75 */ 75 */
76#define MD_UNIT(unit) DISKUNIT(unit) 76#define MD_UNIT(unit) DISKUNIT(unit)
77 77
78/* autoconfig stuff... */ 78/* autoconfig stuff... */
79 79
80struct md_softc { 80struct md_softc {
81 struct disk sc_dkdev; /* hook for generic disk handling */ 81 struct disk sc_dkdev; /* hook for generic disk handling */
82 struct md_conf sc_md; 82 struct md_conf sc_md;
83 struct bufq_state *sc_buflist; 83 struct bufq_state *sc_buflist;
84}; 84};
85/* shorthand for fields in sc_md: */ 85/* shorthand for fields in sc_md: */
86#define sc_addr sc_md.md_addr 86#define sc_addr sc_md.md_addr
87#define sc_size sc_md.md_size 87#define sc_size sc_md.md_size
88#define sc_type sc_md.md_type 88#define sc_type sc_md.md_type
89 89
90void mdattach(int); 90void mdattach(int);
91 91
92static void md_attach(device_t, device_t, void *); 92static void md_attach(device_t, device_t, void *);
93static int md_detach(device_t, int); 93static int md_detach(device_t, int);
94 94
95static dev_type_open(mdopen); 95static dev_type_open(mdopen);
96static dev_type_close(mdclose); 96static dev_type_close(mdclose);
97static dev_type_read(mdread); 97static dev_type_read(mdread);
98static dev_type_write(mdwrite); 98static dev_type_write(mdwrite);
99static dev_type_ioctl(mdioctl); 99static dev_type_ioctl(mdioctl);
100static dev_type_strategy(mdstrategy); 100static dev_type_strategy(mdstrategy);
101static dev_type_size(mdsize); 101static dev_type_size(mdsize);
102 102
103const struct bdevsw md_bdevsw = { 103const struct bdevsw md_bdevsw = {
104 mdopen, mdclose, mdstrategy, mdioctl, nodump, mdsize, D_DISK 104 mdopen, mdclose, mdstrategy, mdioctl, nodump, mdsize, D_DISK
105}; 105};
106 106
107const struct cdevsw md_cdevsw = { 107const struct cdevsw md_cdevsw = {
108 mdopen, mdclose, mdread, mdwrite, mdioctl, 108 mdopen, mdclose, mdread, mdwrite, mdioctl,
109 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 109 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
110}; 110};
111 111
112static struct dkdriver mddkdriver = { mdstrategy, NULL }; 112static struct dkdriver mddkdriver = { mdstrategy, NULL };
113 113
114extern struct cfdriver md_cd; 114extern struct cfdriver md_cd;
115CFATTACH_DECL3_NEW(md, sizeof(struct md_softc), 115CFATTACH_DECL3_NEW(md, sizeof(struct md_softc),
116 0, md_attach, md_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); 116 0, md_attach, md_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
117 117
118extern size_t md_root_size; 118extern size_t md_root_size;
119 119
120/* 120/*
121 * This is called if we are configured as a pseudo-device 121 * This is called if we are configured as a pseudo-device
122 */ 122 */
123void 123void
124mdattach(int n) 124mdattach(int n)
125{ 125{
126 int i; 126 int i;
127 cfdata_t cf; 127 cfdata_t cf;
128 128
129#ifdef TFTPROOT 129#ifdef TFTPROOT
130 /*  130 /*
131 * Attachement of md0 must be done after md_root_setconf(),  131 * Attachement of md0 must be done after md_root_setconf(),
132 * because the RAMdisk is not loaded yet. 132 * because the RAMdisk is not loaded yet.
133 */ 133 */
134 if (md_root_size == 0) 134 if (md_root_size == 0)
135 return; 135 return;
136#endif 136#endif
137 if (config_cfattach_attach("md", &md_ca)) { 137 if (config_cfattach_attach("md", &md_ca)) {
138 printf("md: cfattach_attach failed\n"); 138 printf("md: cfattach_attach failed\n");
139 return; 139 return;
140 } 140 }
141 141
142 /* XXX: Are we supposed to provide a default? */ 142 /* XXX: Are we supposed to provide a default? */
143 if (n <= 1) 143 if (n <= 1)
144 n = 1; 144 n = 1;
145 145
146 /* Attach as if by autoconfig. */ 146 /* Attach as if by autoconfig. */
147 for (i = 0; i < n; i++) { 147 for (i = 0; i < n; i++) {
148 cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK); 148 cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
149 cf->cf_name = "md"; 149 cf->cf_name = "md";
150 cf->cf_atname = "md"; 150 cf->cf_atname = "md";
151 cf->cf_unit = i; 151 cf->cf_unit = i;
152 cf->cf_fstate = FSTATE_NOTFOUND; 152 cf->cf_fstate = FSTATE_NOTFOUND;
153 (void)config_attach_pseudo(cf); 153 (void)config_attach_pseudo(cf);
154 } 154 }
155} 155}
156 156
157static void 157static void
158md_attach(device_t parent, device_t self, void *aux) 158md_attach(device_t parent, device_t self, void *aux)
159{ 159{
160 struct md_softc *sc = device_private(self); 160 struct md_softc *sc = device_private(self);
161 161
162 bufq_alloc(&sc->sc_buflist, "fcfs", 0); 162 bufq_alloc(&sc->sc_buflist, "fcfs", 0);
163 163
164 /* XXX - Could accept aux info here to set the config. */ 164 /* XXX - Could accept aux info here to set the config. */
165#ifdef MEMORY_DISK_HOOKS 165#ifdef MEMORY_DISK_HOOKS
166 /* 166 /*
167 * This external function might setup a pre-loaded disk. 167 * This external function might setup a pre-loaded disk.
168 * All it would need to do is setup the md_conf struct. 168 * All it would need to do is setup the md_conf struct.
169 * See sys/dev/md_root.c for an example. 169 * See sys/dev/md_root.c for an example.
170 */ 170 */
171 md_attach_hook(device_unit(self), &sc->sc_md); 171 md_attach_hook(device_unit(self), &sc->sc_md);
172#endif 172#endif
173 173
174 /* 174 /*
175 * Initialize and attach the disk structure. 175 * Initialize and attach the disk structure.
176 */ 176 */
177 disk_init(&sc->sc_dkdev, device_xname(self), &mddkdriver); 177 disk_init(&sc->sc_dkdev, device_xname(self), &mddkdriver);
178 disk_attach(&sc->sc_dkdev); 178 disk_attach(&sc->sc_dkdev);
179 179
180 if (!pmf_device_register(self, NULL, NULL)) 180 if (!pmf_device_register(self, NULL, NULL))
181 aprint_error_dev(self, "couldn't establish power handler\n"); 181 aprint_error_dev(self, "couldn't establish power handler\n");
182} 182}
183 183
184static int 184static int
185md_detach(device_t self, int flags) 185md_detach(device_t self, int flags)
186{ 186{
187 struct md_softc *sc = device_private(self); 187 struct md_softc *sc = device_private(self);
188 int rc; 188 int rc;
189 189
190 rc = 0; 190 rc = 0;
191 mutex_enter(&sc->sc_dkdev.dk_openlock); 191 mutex_enter(&sc->sc_dkdev.dk_openlock);
192 if (sc->sc_dkdev.dk_openmask == 0) 192 if (sc->sc_dkdev.dk_openmask == 0)
193 ; /* nothing to do */ 193 ; /* nothing to do */
194 else if ((flags & DETACH_FORCE) == 0) 194 else if ((flags & DETACH_FORCE) == 0)
195 rc = EBUSY; 195 rc = EBUSY;
196 mutex_exit(&sc->sc_dkdev.dk_openlock); 196 mutex_exit(&sc->sc_dkdev.dk_openlock);
197 197
198 if (rc != 0) 198 if (rc != 0)
199 return rc; 199 return rc;
200 200
201 pmf_device_deregister(self); 201 pmf_device_deregister(self);
202 disk_detach(&sc->sc_dkdev); 202 disk_detach(&sc->sc_dkdev);
203 disk_destroy(&sc->sc_dkdev); 203 disk_destroy(&sc->sc_dkdev);
204 bufq_free(sc->sc_buflist); 204 bufq_free(sc->sc_buflist);
205 return 0; 205 return 0;
206} 206}
207 207
208/* 208/*
209 * operational routines: 209 * operational routines:
210 * open, close, read, write, strategy, 210 * open, close, read, write, strategy,
211 * ioctl, dump, size 211 * ioctl, dump, size
212 */ 212 */
213 213
214#if MEMORY_DISK_SERVER 214#if MEMORY_DISK_SERVER
215static int md_server_loop(struct md_softc *sc); 215static int md_server_loop(struct md_softc *sc);
216static int md_ioctl_server(struct md_softc *sc, struct md_conf *umd, 216static int md_ioctl_server(struct md_softc *sc, struct md_conf *umd,
217 struct lwp *l); 217 struct lwp *l);
218#endif /* MEMORY_DISK_SERVER */ 218#endif /* MEMORY_DISK_SERVER */
219static int md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd, 219static int md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd,
220 struct lwp *l); 220 struct lwp *l);
221 221
222static int 222static int
223mdsize(dev_t dev) 223mdsize(dev_t dev)
224{ 224{
225 struct md_softc *sc; 225 struct md_softc *sc;
226 226
227 sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 227 sc = device_lookup_private(&md_cd, MD_UNIT(dev));
228 if (sc == NULL) 228 if (sc == NULL)
229 return 0; 229 return 0;
230 230
231 if (sc->sc_type == MD_UNCONFIGURED) 231 if (sc->sc_type == MD_UNCONFIGURED)
232 return 0; 232 return 0;
233 233
234 return (sc->sc_size >> DEV_BSHIFT); 234 return (sc->sc_size >> DEV_BSHIFT);
235} 235}
236 236
237static int 237static int
238mdopen(dev_t dev, int flag, int fmt, struct lwp *l) 238mdopen(dev_t dev, int flag, int fmt, struct lwp *l)
239{ 239{
240 int unit; 240 int unit;
241 int part = DISKPART(dev); 241 int part = DISKPART(dev);
242 int pmask = 1 << part; 242 int pmask = 1 << part;
243 struct md_softc *sc; 243 struct md_softc *sc;
244 struct disk *dk; 244 struct disk *dk;
245 245
246 unit = MD_UNIT(dev); 246 unit = MD_UNIT(dev);
247 sc = device_lookup_private(&md_cd, unit); 247 sc = device_lookup_private(&md_cd, unit);
248 if (sc == NULL) 248 if (sc == NULL)
249 return ENXIO; 249 return ENXIO;
250 250
251 dk = &sc->sc_dkdev; 251 dk = &sc->sc_dkdev;
252 252
253 /* 253 /*
254 * The raw partition is used for ioctl to configure. 254 * The raw partition is used for ioctl to configure.
255 */ 255 */
256 if (part == RAW_PART) 256 if (part == RAW_PART)
257 goto ok; 257 goto ok;
258 258
259#ifdef MEMORY_DISK_HOOKS 259#ifdef MEMORY_DISK_HOOKS
260 /* Call the open hook to allow loading the device. */ 260 /* Call the open hook to allow loading the device. */
261 md_open_hook(unit, &sc->sc_md); 261 md_open_hook(unit, &sc->sc_md);
262#endif 262#endif
263 263
264 /* 264 /*
265 * This is a normal, "slave" device, so 265 * This is a normal, "slave" device, so
266 * enforce initialized. 266 * enforce initialized.
267 */ 267 */
268 if (sc->sc_type == MD_UNCONFIGURED) 268 if (sc->sc_type == MD_UNCONFIGURED)
269 return ENXIO; 269 return ENXIO;
270 270
271ok: 271ok:
272 /* XXX duplicates code in dk_open(). Call dk_open(), instead? */ 272 /* XXX duplicates code in dk_open(). Call dk_open(), instead? */
273 mutex_enter(&dk->dk_openlock); 273 mutex_enter(&dk->dk_openlock);
274 /* Mark our unit as open. */ 274 /* Mark our unit as open. */
275 switch (fmt) { 275 switch (fmt) {
276 case S_IFCHR: 276 case S_IFCHR:
277 dk->dk_copenmask |= pmask; 277 dk->dk_copenmask |= pmask;
278 break; 278 break;
279 case S_IFBLK: 279 case S_IFBLK:
280 dk->dk_bopenmask |= pmask; 280 dk->dk_bopenmask |= pmask;
281 break; 281 break;
282 } 282 }
283 283
284 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; 284 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
285 285
286 mutex_exit(&dk->dk_openlock); 286 mutex_exit(&dk->dk_openlock);
287 return 0; 287 return 0;
288} 288}
289 289
290static int 290static int
291mdclose(dev_t dev, int flag, int fmt, struct lwp *l) 291mdclose(dev_t dev, int flag, int fmt, struct lwp *l)
292{ 292{
293 int part = DISKPART(dev); 293 int part = DISKPART(dev);
294 int pmask = 1 << part; 294 int pmask = 1 << part;
295 struct md_softc *sc; 295 struct md_softc *sc;
296 struct disk *dk; 296 struct disk *dk;
297 297
298 sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 298 sc = device_lookup_private(&md_cd, MD_UNIT(dev));
299 if (sc == NULL) 299 if (sc == NULL)
300 return ENXIO; 300 return ENXIO;
301 301
302 dk = &sc->sc_dkdev; 302 dk = &sc->sc_dkdev;
303 303
304 mutex_enter(&dk->dk_openlock); 304 mutex_enter(&dk->dk_openlock);
305 305
306 switch (fmt) { 306 switch (fmt) {
307 case S_IFCHR: 307 case S_IFCHR:
308 dk->dk_copenmask &= ~pmask; 308 dk->dk_copenmask &= ~pmask;
309 break; 309 break;
310 case S_IFBLK: 310 case S_IFBLK:
311 dk->dk_bopenmask &= ~pmask; 311 dk->dk_bopenmask &= ~pmask;
312 break; 312 break;
313 } 313 }
314 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; 314 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
315 315
316 mutex_exit(&dk->dk_openlock); 316 mutex_exit(&dk->dk_openlock);
317 return 0; 317 return 0;
318} 318}
319 319
320static int 320static int
321mdread(dev_t dev, struct uio *uio, int flags) 321mdread(dev_t dev, struct uio *uio, int flags)
322{ 322{
323 struct md_softc *sc; 323 struct md_softc *sc;
324 324
325 sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 325 sc = device_lookup_private(&md_cd, MD_UNIT(dev));
326 326
327 if (sc->sc_type == MD_UNCONFIGURED) 327 if (sc == NULL || sc->sc_type == MD_UNCONFIGURED)
328 return ENXIO; 328 return ENXIO;
329 329
330 return (physio(mdstrategy, NULL, dev, B_READ, minphys, uio)); 330 return (physio(mdstrategy, NULL, dev, B_READ, minphys, uio));
331} 331}
332 332
333static int 333static int
334mdwrite(dev_t dev, struct uio *uio, int flags) 334mdwrite(dev_t dev, struct uio *uio, int flags)
335{ 335{
336 struct md_softc *sc; 336 struct md_softc *sc;
337 337
338 sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 338 sc = device_lookup_private(&md_cd, MD_UNIT(dev));
339 339
340 if (sc->sc_type == MD_UNCONFIGURED) 340 if (sc == NULL || sc->sc_type == MD_UNCONFIGURED)
341 return ENXIO; 341 return ENXIO;
342 342
343 return (physio(mdstrategy, NULL, dev, B_WRITE, minphys, uio)); 343 return (physio(mdstrategy, NULL, dev, B_WRITE, minphys, uio));
344} 344}
345 345
346/* 346/*
347 * Handle I/O requests, either directly, or 347 * Handle I/O requests, either directly, or
348 * by passing them to the server process. 348 * by passing them to the server process.
349 */ 349 */
350static void 350static void
351mdstrategy(struct buf *bp) 351mdstrategy(struct buf *bp)
352{ 352{
353 struct md_softc *sc; 353 struct md_softc *sc;
354 void * addr; 354 void * addr;
355 size_t off, xfer; 355 size_t off, xfer;
356 356
357 sc = device_lookup_private(&md_cd, MD_UNIT(bp->b_dev)); 357 sc = device_lookup_private(&md_cd, MD_UNIT(bp->b_dev));
358 358
359 if (sc->sc_type == MD_UNCONFIGURED) { 359 if (sc == NULL || sc->sc_type == MD_UNCONFIGURED) {
360 bp->b_error = ENXIO; 360 bp->b_error = ENXIO;
361 goto done; 361 goto done;
362 } 362 }
363 363
364 switch (sc->sc_type) { 364 switch (sc->sc_type) {
365#if MEMORY_DISK_SERVER 365#if MEMORY_DISK_SERVER
366 case MD_UMEM_SERVER: 366 case MD_UMEM_SERVER:
367 /* Just add this job to the server's queue. */ 367 /* Just add this job to the server's queue. */
368 bufq_put(sc->sc_buflist, bp); 368 bufq_put(sc->sc_buflist, bp);
369 wakeup((void *)sc); 369 wakeup((void *)sc);
370 /* see md_server_loop() */ 370 /* see md_server_loop() */
371 /* no biodone in this case */ 371 /* no biodone in this case */
372 return; 372 return;
373#endif /* MEMORY_DISK_SERVER */ 373#endif /* MEMORY_DISK_SERVER */
374 374
375 case MD_KMEM_FIXED: 375 case MD_KMEM_FIXED:
376 case MD_KMEM_ALLOCATED: 376 case MD_KMEM_ALLOCATED:
377 /* These are in kernel space. Access directly. */ 377 /* These are in kernel space. Access directly. */
378 bp->b_resid = bp->b_bcount; 378 bp->b_resid = bp->b_bcount;
379 off = (bp->b_blkno << DEV_BSHIFT); 379 off = (bp->b_blkno << DEV_BSHIFT);
380 if (off >= sc->sc_size) { 380 if (off >= sc->sc_size) {
381 if (bp->b_flags & B_READ) 381 if (bp->b_flags & B_READ)
382 break; /* EOF */ 382 break; /* EOF */
383 goto set_eio; 383 goto set_eio;
384 } 384 }
385 xfer = bp->b_resid; 385 xfer = bp->b_resid;
386 if (xfer > (sc->sc_size - off)) 386 if (xfer > (sc->sc_size - off))
387 xfer = (sc->sc_size - off); 387 xfer = (sc->sc_size - off);
388 addr = (char *)sc->sc_addr + off; 388 addr = (char *)sc->sc_addr + off;
389 if (bp->b_flags & B_READ) 389 if (bp->b_flags & B_READ)
390 memcpy(bp->b_data, addr, xfer); 390 memcpy(bp->b_data, addr, xfer);
391 else 391 else
392 memcpy(addr, bp->b_data, xfer); 392 memcpy(addr, bp->b_data, xfer);
393 bp->b_resid -= xfer; 393 bp->b_resid -= xfer;
394 break; 394 break;
395 395
396 default: 396 default:
397 bp->b_resid = bp->b_bcount; 397 bp->b_resid = bp->b_bcount;
398 set_eio: 398 set_eio:
399 bp->b_error = EIO; 399 bp->b_error = EIO;
400 break; 400 break;
401 } 401 }
402 done: 402 done:
403 biodone(bp); 403 biodone(bp);
404} 404}
405 405
406static int 406static int
407mdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 407mdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
408{ 408{
409 struct md_softc *sc; 409 struct md_softc *sc;
410 struct md_conf *umd; 410 struct md_conf *umd;
411 411
412 sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 412 if ((sc = device_lookup_private(&md_cd, MD_UNIT(dev))) == NULL)
 413 return ENXIO;
413 414
414 /* If this is not the raw partition, punt! */ 415 /* If this is not the raw partition, punt! */
415 if (DISKPART(dev) != RAW_PART) 416 if (DISKPART(dev) != RAW_PART)
416 return ENOTTY; 417 return ENOTTY;
417 418
418 umd = (struct md_conf *)data; 419 umd = (struct md_conf *)data;
419 switch (cmd) { 420 switch (cmd) {
420 case MD_GETCONF: 421 case MD_GETCONF:
421 *umd = sc->sc_md; 422 *umd = sc->sc_md;
422 return 0; 423 return 0;
423 424
424 case MD_SETCONF: 425 case MD_SETCONF:
425 /* Can only set it once. */ 426 /* Can only set it once. */
426 if (sc->sc_type != MD_UNCONFIGURED) 427 if (sc->sc_type != MD_UNCONFIGURED)
427 break; 428 break;
428 switch (umd->md_type) { 429 switch (umd->md_type) {
429 case MD_KMEM_ALLOCATED: 430 case MD_KMEM_ALLOCATED:
430 return md_ioctl_kalloc(sc, umd, l); 431 return md_ioctl_kalloc(sc, umd, l);
431#if MEMORY_DISK_SERVER 432#if MEMORY_DISK_SERVER
432 case MD_UMEM_SERVER: 433 case MD_UMEM_SERVER:
433 return md_ioctl_server(sc, umd, l); 434 return md_ioctl_server(sc, umd, l);
434#endif /* MEMORY_DISK_SERVER */ 435#endif /* MEMORY_DISK_SERVER */
435 default: 436 default:
436 break; 437 break;
437 } 438 }
438 break; 439 break;
439 } 440 }
440 return EINVAL; 441 return EINVAL;
441} 442}
442 443
443/* 444/*
444 * Handle ioctl MD_SETCONF for (sc_type == MD_KMEM_ALLOCATED) 445 * Handle ioctl MD_SETCONF for (sc_type == MD_KMEM_ALLOCATED)
445 * Just allocate some kernel memory and return. 446 * Just allocate some kernel memory and return.
446 */ 447 */
447static int 448static int
448md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd, 449md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd,
449 struct lwp *l) 450 struct lwp *l)
450{ 451{
451 vaddr_t addr; 452 vaddr_t addr;
452 vsize_t size; 453 vsize_t size;
453 454
454 /* Sanity check the size. */ 455 /* Sanity check the size. */
455 size = umd->md_size; 456 size = umd->md_size;
456 addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_WIRED|UVM_KMF_ZERO); 457 addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
457 if (!addr) 458 if (!addr)
458 return ENOMEM; 459 return ENOMEM;
459 460
460 /* This unit is now configured. */ 461 /* This unit is now configured. */
461 sc->sc_addr = (void *)addr; /* kernel space */ 462 sc->sc_addr = (void *)addr; /* kernel space */
462 sc->sc_size = (size_t)size; 463 sc->sc_size = (size_t)size;
463 sc->sc_type = MD_KMEM_ALLOCATED; 464 sc->sc_type = MD_KMEM_ALLOCATED;
464 return 0; 465 return 0;
465} 466}
466 467
467#if MEMORY_DISK_SERVER 468#if MEMORY_DISK_SERVER
468 469
469/* 470/*
470 * Handle ioctl MD_SETCONF for (sc_type == MD_UMEM_SERVER) 471 * Handle ioctl MD_SETCONF for (sc_type == MD_UMEM_SERVER)
471 * Set config, then become the I/O server for this unit. 472 * Set config, then become the I/O server for this unit.
472 */ 473 */
473static int 474static int
474md_ioctl_server(struct md_softc *sc, struct md_conf *umd, 475md_ioctl_server(struct md_softc *sc, struct md_conf *umd,
475 struct lwp *l) 476 struct lwp *l)
476{ 477{
477 vaddr_t end; 478 vaddr_t end;
478 int error; 479 int error;
479 480
480 /* Sanity check addr, size. */ 481 /* Sanity check addr, size. */
481 end = (vaddr_t) ((char *)umd->md_addr + umd->md_size); 482 end = (vaddr_t) ((char *)umd->md_addr + umd->md_size);
482 483
483 if ((end >= VM_MAXUSER_ADDRESS) || 484 if ((end >= VM_MAXUSER_ADDRESS) ||
484 (end < ((vaddr_t) umd->md_addr)) ) 485 (end < ((vaddr_t) umd->md_addr)) )
485 return EINVAL; 486 return EINVAL;
486 487
487 /* This unit is now configured. */ 488 /* This unit is now configured. */
488 sc->sc_addr = umd->md_addr; /* user space */ 489 sc->sc_addr = umd->md_addr; /* user space */
489 sc->sc_size = umd->md_size; 490 sc->sc_size = umd->md_size;
490 sc->sc_type = MD_UMEM_SERVER; 491 sc->sc_type = MD_UMEM_SERVER;
491 492
492 /* Become the server daemon */ 493 /* Become the server daemon */
493 error = md_server_loop(sc); 494 error = md_server_loop(sc);
494 495
495 /* This server is now going away! */ 496 /* This server is now going away! */
496 sc->sc_type = MD_UNCONFIGURED; 497 sc->sc_type = MD_UNCONFIGURED;
497 sc->sc_addr = 0; 498 sc->sc_addr = 0;
498 sc->sc_size = 0; 499 sc->sc_size = 0;
499 500
500 return (error); 501 return (error);
501} 502}
502 503
503static int md_sleep_pri = PWAIT | PCATCH; 504static int md_sleep_pri = PWAIT | PCATCH;
504 505
505static int 506static int
506md_server_loop(struct md_softc *sc) 507md_server_loop(struct md_softc *sc)
507{ 508{
508 struct buf *bp; 509 struct buf *bp;
509 void *addr; /* user space address */ 510 void *addr; /* user space address */
510 size_t off; /* offset into "device" */ 511 size_t off; /* offset into "device" */
511 size_t xfer; /* amount to transfer */ 512 size_t xfer; /* amount to transfer */
512 int error; 513 int error;
513 514
514 for (;;) { 515 for (;;) {
515 /* Wait for some work to arrive. */ 516 /* Wait for some work to arrive. */
516 while ((bp = bufq_get(sc->sc_buflist)) == NULL) { 517 while ((bp = bufq_get(sc->sc_buflist)) == NULL) {
517 error = tsleep((void *)sc, md_sleep_pri, "md_idle", 0); 518 error = tsleep((void *)sc, md_sleep_pri, "md_idle", 0);
518 if (error) 519 if (error)
519 return error; 520 return error;
520 } 521 }
521 522
522 /* Do the transfer to/from user space. */ 523 /* Do the transfer to/from user space. */
523 error = 0; 524 error = 0;
524 bp->b_resid = bp->b_bcount; 525 bp->b_resid = bp->b_bcount;
525 off = (bp->b_blkno << DEV_BSHIFT); 526 off = (bp->b_blkno << DEV_BSHIFT);
526 if (off >= sc->sc_size) { 527 if (off >= sc->sc_size) {
527 if (bp->b_flags & B_READ) 528 if (bp->b_flags & B_READ)
528 goto done; /* EOF (not an error) */ 529 goto done; /* EOF (not an error) */
529 error = EIO; 530 error = EIO;
530 goto done; 531 goto done;
531 } 532 }
532 xfer = bp->b_resid; 533 xfer = bp->b_resid;
533 if (xfer > (sc->sc_size - off)) 534 if (xfer > (sc->sc_size - off))
534 xfer = (sc->sc_size - off); 535 xfer = (sc->sc_size - off);
535 addr = (char *)sc->sc_addr + off; 536 addr = (char *)sc->sc_addr + off;
536 if (bp->b_flags & B_READ) 537 if (bp->b_flags & B_READ)
537 error = copyin(addr, bp->b_data, xfer); 538 error = copyin(addr, bp->b_data, xfer);
538 else 539 else
539 error = copyout(bp->b_data, addr, xfer); 540 error = copyout(bp->b_data, addr, xfer);
540 if (!error) 541 if (!error)
541 bp->b_resid -= xfer; 542 bp->b_resid -= xfer;
542 543
543 done: 544 done:
544 if (error) { 545 if (error) {
545 bp->b_error = error; 546 bp->b_error = error;
546 } 547 }
547 biodone(bp); 548 biodone(bp);
548 } 549 }
549} 550}
550#endif /* MEMORY_DISK_SERVER */ 551#endif /* MEMORY_DISK_SERVER */