Deleted Added
sdiff udiff text old ( 63309 ) new ( 64880 )
full compact
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/sys/dev/md/md.c 64880 2000-08-20 21:34:39Z phk $
10 *
11 */
12
13#include "opt_mfs.h" /* We have adopted some tasks from MFS */
14#include "opt_md.h"
15#include "opt_devfs.h"
16
17#include <sys/param.h>
18#include <sys/systm.h>
19#include <sys/bio.h>
20#include <sys/conf.h>
21#include <sys/devicestat.h>
22#include <sys/disk.h>
23#include <sys/kernel.h>
24#include <sys/malloc.h>
25#include <sys/sysctl.h>
26#include <sys/linker.h>
27#include <sys/queue.h>
28
29#ifdef DEVFS
30#include <sys/eventhandler.h>
31#include <fs/devfs/devfs.h>
32#endif
33
34#ifndef MD_NSECT
35#define MD_NSECT (10000 * 2)
36#endif
37
38MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk");
39MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors");
40
41static int md_debug;
42SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, "");
43
44#if defined(MFS_ROOT) && !defined(MD_ROOT)
45#define MD_ROOT MFS_ROOT
46#warning "option MFS_ROOT has been superceeded by MD_ROOT"
47#endif
48
49#if defined(MFS_ROOT_SIZE) && !defined(MD_ROOT_SIZE)
50#define MD_ROOT_SIZE MFS_ROOT_SIZE
51#warning "option MFS_ROOT_SIZE has been superceeded by MD_ROOT_SIZE"
52#endif
53
54#if defined(MD_ROOT) && defined(MD_ROOT_SIZE)
55/* Image gets put here: */
56static u_char mfs_root[MD_ROOT_SIZE*1024] = "MFS Filesystem goes here";
57static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
58#endif
59
60static int mdrootready;
61
62static void mdcreate_malloc(int unit);
63
64#define CDEV_MAJOR 95
65#define BDEV_MAJOR 22
66
67static d_strategy_t mdstrategy;
68static d_strategy_t mdstrategy_preload;
69static d_strategy_t mdstrategy_malloc;
70static d_open_t mdopen;
71static d_ioctl_t mdioctl;
72
73static struct cdevsw md_cdevsw = {
74 /* open */ mdopen,
75 /* close */ nullclose,
76 /* read */ physread,
77 /* write */ physwrite,
78 /* ioctl */ mdioctl,
79 /* poll */ nopoll,
80 /* mmap */ nommap,
81 /* strategy */ mdstrategy,
82 /* name */ "md",
83 /* maj */ CDEV_MAJOR,
84 /* dump */ nodump,
85 /* psize */ nopsize,
86 /* flags */ D_DISK | D_CANFREE | D_MEMDISK,
87 /* bmaj */ BDEV_MAJOR
88};
89
90static struct cdevsw mddisk_cdevsw;
91
92static LIST_HEAD(, md_s) md_softc_list = LIST_HEAD_INITIALIZER(&md_softc_list);
93
94struct md_s {
95 int unit;
96 LIST_ENTRY(md_s) list;
97 struct devstat stats;
98 struct bio_queue_head bio_queue;
99 struct disk disk;
100 dev_t dev;
101 int busy;
102 enum {MD_MALLOC, MD_PRELOAD} type;
103 unsigned nsect;
104
105 /* MD_MALLOC related fields */
106 unsigned nsecp;
107 u_char **secp;
108
109 /* MD_PRELOAD related fields */
110 u_char *pl_ptr;
111 unsigned pl_len;
112};
113
114static int mdunits;
115
116static int
117mdopen(dev_t dev, int flag, int fmt, struct proc *p)
118{
119 struct md_s *sc;
120 struct disklabel *dl;
121
122 if (md_debug)
123 printf("mdopen(%s %x %x %p)\n",
124 devtoname(dev), flag, fmt, p);
125
126 sc = dev->si_drv1;
127#ifndef DEVFS
128 if (sc->unit + 1 == mdunits)
129 mdcreate_malloc(-1);
130#endif
131
132 dl = &sc->disk.d_label;
133 bzero(dl, sizeof(*dl));
134 dl->d_secsize = DEV_BSIZE;
135 dl->d_nsectors = 1024;
136 dl->d_ntracks = 1;
137 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
138 dl->d_secperunit = sc->nsect;
139 dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl;
140 return (0);
141}
142
143static int
144mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
145{
146
147 if (md_debug)
148 printf("mdioctl(%s %lx %p %x %p)\n",
149 devtoname(dev), cmd, addr, flags, p);
150
151 return (ENOIOCTL);
152}
153
154static void
155mdstrategy(struct bio *bp)
156{
157 struct md_s *sc;
158
159 if (md_debug > 1)
160 printf("mdstrategy(%p) %s %x, %d, %ld, %p)\n",
161 bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
162 bp->bio_bcount / DEV_BSIZE, bp->bio_data);
163
164 sc = bp->bio_dev->si_drv1;
165 if (sc->type == MD_MALLOC) {
166 mdstrategy_malloc(bp);
167 } else {
168 mdstrategy_preload(bp);
169 }
170 return;
171}
172
173
174static void
175mdstrategy_malloc(struct bio *bp)
176{
177 int s, i;
178 struct md_s *sc;
179 devstat_trans_flags dop;
180 u_char *secp, **secpp, *dst;
181 unsigned secno, nsec, secval, uc;
182
183 if (md_debug > 1)
184 printf("mdstrategy_malloc(%p) %s %x, %d, %ld, %p)\n",
185 bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
186 bp->bio_bcount / DEV_BSIZE, bp->bio_data);
187
188 sc = bp->bio_dev->si_drv1;
189
190 s = splbio();
191
192 bioqdisksort(&sc->bio_queue, bp);
193
194 if (sc->busy) {
195 splx(s);
196 return;
197 }
198
199 sc->busy++;
200
201 while (1) {
202 bp = bioq_first(&sc->bio_queue);
203 if (bp)
204 bioq_remove(&sc->bio_queue, bp);
205 splx(s);
206 if (!bp)
207 break;
208
209 devstat_start_transaction(&sc->stats);
210
211 if (bp->bio_cmd == BIO_DELETE)
212 dop = DEVSTAT_NO_DATA;
213 else if (bp->bio_cmd == BIO_READ)
214 dop = DEVSTAT_READ;
215 else
216 dop = DEVSTAT_WRITE;
217
218 nsec = bp->bio_bcount / DEV_BSIZE;
219 secno = bp->bio_pblkno;
220 dst = bp->bio_data;
221 while (nsec--) {
222
223 if (secno < sc->nsecp) {
224 secpp = &sc->secp[secno];
225 if ((u_int)*secpp > 255) {
226 secp = *secpp;
227 secval = 0;
228 } else {
229 secp = 0;
230 secval = (u_int) *secpp;
231 }
232 } else {
233 secpp = 0;
234 secp = 0;
235 secval = 0;
236 }
237 if (md_debug > 2)
238 printf("%x %p %p %d\n",
239 bp->bio_flags, secpp, secp, secval);
240
241 if (bp->bio_cmd == BIO_DELETE) {
242 if (secpp) {
243 if (secp)
244 FREE(secp, M_MDSECT);
245 *secpp = 0;
246 }
247 } else if (bp->bio_cmd == BIO_READ) {
248 if (secp) {
249 bcopy(secp, dst, DEV_BSIZE);
250 } else if (secval) {
251 for (i = 0; i < DEV_BSIZE; i++)
252 dst[i] = secval;
253 } else {
254 bzero(dst, DEV_BSIZE);
255 }
256 } else {
257 uc = dst[0];
258 for (i = 1; i < DEV_BSIZE; i++)
259 if (dst[i] != uc)
260 break;
261 if (i == DEV_BSIZE && !uc) {
262 if (secp)
263 FREE(secp, M_MDSECT);
264 if (secpp)
265 *secpp = (u_char *)uc;
266 } else {
267 if (!secpp) {
268 MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK);
269 bzero(secpp, (secno + nsec + 1) * sizeof(u_char *));
270 bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *));
271 FREE(sc->secp, M_MD);
272 sc->secp = secpp;
273 sc->nsecp = secno + nsec + 1;
274 secpp = &sc->secp[secno];
275 }
276 if (i == DEV_BSIZE) {
277 if (secp)
278 FREE(secp, M_MDSECT);
279 *secpp = (u_char *)uc;
280 } else {
281 if (!secp)
282 MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
283 bcopy(dst, secp, DEV_BSIZE);
284
285 *secpp = secp;
286 }
287 }
288 }
289 secno++;
290 dst += DEV_BSIZE;
291 }
292 bp->bio_resid = 0;
293 devstat_end_transaction_bio(&sc->stats, bp);
294 biodone(bp);
295 s = splbio();
296 }
297 sc->busy = 0;
298 return;
299}
300
301
302static void
303mdstrategy_preload(struct bio *bp)
304{
305 int s;
306 struct md_s *sc;
307 devstat_trans_flags dop;
308
309 if (md_debug > 1)
310 printf("mdstrategy_preload(%p) %s %x, %d, %ld, %p)\n",
311 bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
312 bp->bio_bcount / DEV_BSIZE, bp->bio_data);
313
314 sc = bp->bio_dev->si_drv1;
315
316 s = splbio();
317
318 bioqdisksort(&sc->bio_queue, bp);
319
320 if (sc->busy) {
321 splx(s);
322 return;
323 }
324
325 sc->busy++;
326
327 while (1) {
328 bp = bioq_first(&sc->bio_queue);
329 if (bp)
330 bioq_remove(&sc->bio_queue, bp);
331 splx(s);
332 if (!bp)
333 break;
334
335 devstat_start_transaction(&sc->stats);
336
337 if (bp->bio_cmd == BIO_DELETE) {
338 dop = DEVSTAT_NO_DATA;
339 } else if (bp->bio_cmd == BIO_READ) {
340 dop = DEVSTAT_READ;
341 bcopy(sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_data, bp->bio_bcount);
342 } else {
343 dop = DEVSTAT_WRITE;
344 bcopy(bp->bio_data, sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_bcount);
345 }
346 bp->bio_resid = 0;
347 devstat_end_transaction_bio(&sc->stats, bp);
348 biodone(bp);
349 s = splbio();
350 }
351 sc->busy = 0;
352 return;
353}
354
355static struct md_s *
356mdcreate(int unit)
357{
358 struct md_s *sc;
359
360 if (unit == -1)
361 unit = mdunits++;
362 /* Make sure this unit isn't already in action */
363 LIST_FOREACH(sc, &md_softc_list, list) {
364 if (sc->unit == unit)
365 return (NULL);
366 }
367 MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
368 bzero(sc, sizeof(*sc));
369 LIST_INSERT_HEAD(&md_softc_list, sc, list);
370 sc->unit = unit;
371 bioq_init(&sc->bio_queue);
372 devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
373 DEVSTAT_NO_ORDERED_TAGS,
374 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
375 DEVSTAT_PRIORITY_OTHER);
376 sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_cdevsw, &mddisk_cdevsw);
377 sc->dev->si_drv1 = sc;
378 return (sc);
379}
380
381static void
382mdcreate_preload(u_char *image, unsigned length)
383{
384 struct md_s *sc;
385
386 sc = mdcreate(-1);
387 sc->type = MD_PRELOAD;
388 sc->nsect = length / DEV_BSIZE;
389 sc->pl_ptr = image;
390 sc->pl_len = length;
391
392 if (sc->unit == 0)
393 mdrootready = 1;
394}
395
396static void
397mdcreate_malloc(int unit)
398{
399 struct md_s *sc;
400
401 sc = mdcreate(unit);
402 if (sc == NULL)
403 return;
404
405 sc->type = MD_MALLOC;
406
407 sc->nsect = MD_NSECT; /* for now */
408 MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK);
409 bzero(sc->secp, sizeof(u_char *));
410 sc->nsecp = 1;
411 printf("md%d: Malloc disk\n", sc->unit);
412}
413
414#ifdef DEVFS
415static void
416md_clone (void *arg, char *name, int namelen, dev_t *dev)
417{
418 int i, u;
419
420 if (*dev != NODEV)
421 return;
422 i = devfs_stdclone(name, NULL, "md", &u);
423 if (i == 0)
424 return;
425 /* XXX: should check that next char is [\0sa-h] */
426 /*
427 * Now we cheat: We just create the disk, but don't match.
428 * Since we run before it, subr_disk.c::disk_clone() will
429 * find our disk and match the sought for device.
430 */
431 mdcreate_malloc(u);
432 return;
433}
434#endif
435
436static void
437md_drvinit(void *unused)
438{
439
440 caddr_t mod;
441 caddr_t c;
442 u_char *ptr, *name, *type;
443 unsigned len;
444
445#ifdef MD_ROOT_SIZE
446 mdcreate_preload(mfs_root, MD_ROOT_SIZE*1024);
447#endif
448 mod = NULL;
449 while ((mod = preload_search_next_name(mod)) != NULL) {
450 name = (char *)preload_search_info(mod, MODINFO_NAME);
451 type = (char *)preload_search_info(mod, MODINFO_TYPE);
452 if (name == NULL)
453 continue;
454 if (type == NULL)
455 continue;
456 if (strcmp(type, "md_image") && strcmp(type, "mfs_root"))
457 continue;
458 c = preload_search_info(mod, MODINFO_ADDR);
459 ptr = *(u_char **)c;
460 c = preload_search_info(mod, MODINFO_SIZE);
461 len = *(unsigned *)c;
462 printf("md%d: Preloaded image <%s> %d bytes at %p\n",
463 mdunits, name, len, ptr);
464 mdcreate_preload(ptr, len);
465 }
466#ifdef DEVFS
467 EVENTHANDLER_REGISTER(devfs_clone, md_clone, 0, 999);
468#else
469 mdcreate_malloc(-1);
470#endif
471}
472
473SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
474
475#ifdef MD_ROOT
476static void
477md_takeroot(void *junk)
478{
479 if (mdrootready)
480 rootdevnames[0] = "ufs:/dev/md0c";
481}
482
483SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL);
484#endif
485