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 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/sys/dev/md/md.c,v 1.8.2.2 2002/08/19 17:43:34 jdp Exp $
13 #include "opt_md.h" /* We have adopted some tasks from MFS */
15 #include <sys/param.h>
16 #include <sys/systm.h>
19 #include <sys/devicestat.h>
21 #include <sys/kernel.h>
22 #include <sys/malloc.h>
23 #include <sys/sysctl.h>
24 #include <sys/linker.h>
27 #include <sys/thread2.h>
28 #include <sys/queue.h>
32 #define MD_NSECT (10000 * 2)
35 MALLOC_DEFINE(M_MD
, "MD disk", "Memory Disk");
36 MALLOC_DEFINE(M_MDSECT
, "MD sectors", "Memory Disk Sectors");
39 SYSCTL_INT(_debug
, OID_AUTO
, mddebug
, CTLFLAG_RW
, &md_debug
, 0,
40 "Enable debug output for memory disk devices");
42 #if defined(MD_ROOT) && defined(MD_ROOT_SIZE)
43 /* Image gets put here: */
44 static u_char mfs_root
[MD_ROOT_SIZE
*1024] = "MFS Filesystem goes here";
45 static u_char end_mfs_root
[] __unused
= "MFS Filesystem had better STOP here";
48 static int mdrootready
;
50 static d_strategy_t mdstrategy
;
51 static d_strategy_t mdstrategy_preload
;
52 static d_strategy_t mdstrategy_malloc
;
53 static d_open_t mdopen
;
54 static d_close_t mdclose
;
55 static d_ioctl_t mdioctl
;
57 static struct dev_ops md_ops
= {
58 { "md", 0, D_DISK
| D_CANFREE
| D_MEMDISK
| D_TRACKCLOSE
| D_MPSAFE
},
64 .d_strategy
= mdstrategy
,
68 struct lwkt_token tok
;
71 struct bio_queue_head bio_queue
;
75 enum { /* Memory disk type */
81 /* MD_MALLOC related fields */
85 /* MD_PRELOAD related fields */
88 TAILQ_ENTRY(md_s
) link
;
90 TAILQ_HEAD(mdshead
, md_s
) mdlist
= TAILQ_HEAD_INITIALIZER(mdlist
);
95 static struct md_s
*mdcreate(unsigned);
96 static void mdcreate_malloc(void);
97 static int mdinit(module_t
, int, void *);
98 static void md_drvinit(void *);
99 static int md_drvcleanup(void);
102 mdinit(module_t mod
, int cmd
, void *arg
)
112 ret
= md_drvcleanup();
123 mdopen(struct dev_open_args
*ap
)
125 cdev_t dev
= ap
->a_head
.a_dev
;
129 kprintf("mdopen(%s %x %x)\n",
130 devtoname(dev
), ap
->a_oflags
, ap
->a_devtype
);
134 lwkt_gettoken(&sc
->tok
);
135 if (sc
->unit
+ 1 == mdunits
)
137 atomic_add_int(&refcnt
, 1);
138 lwkt_reltoken(&sc
->tok
);
144 mdclose(struct dev_close_args
*ap
)
146 cdev_t dev
= ap
->a_head
.a_dev
;
150 kprintf("mdclose(%s %x %x)\n",
151 devtoname(dev
), ap
->a_fflag
, ap
->a_devtype
);
154 lwkt_gettoken(&sc
->tok
);
155 atomic_add_int(&refcnt
, -1);
156 lwkt_reltoken(&sc
->tok
);
162 mdioctl(struct dev_ioctl_args
*ap
)
164 cdev_t dev
= ap
->a_head
.a_dev
;
167 kprintf("mdioctl(%s %lx %p %x)\n",
168 devtoname(dev
), ap
->a_cmd
, ap
->a_data
, ap
->a_fflag
);
175 mdstrategy(struct dev_strategy_args
*ap
)
177 cdev_t dev
= ap
->a_head
.a_dev
;
178 struct bio
*bio
= ap
->a_bio
;
179 struct buf
*bp
= bio
->bio_buf
;
183 kprintf("mdstrategy(%p) %s %08x, %lld, %d, %p)\n",
184 bp
, devtoname(dev
), bp
->b_flags
,
185 (long long)bio
->bio_offset
,
186 bp
->b_bcount
, bp
->b_data
);
188 bio
->bio_driver_info
= dev
;
190 lwkt_gettoken(&sc
->tok
);
191 if (sc
->type
== MD_MALLOC
) {
192 mdstrategy_malloc(ap
);
194 mdstrategy_preload(ap
);
196 lwkt_reltoken(&sc
->tok
);
202 mdstrategy_malloc(struct dev_strategy_args
*ap
)
204 cdev_t dev
= ap
->a_head
.a_dev
;
205 struct bio
*bio
= ap
->a_bio
;
206 struct buf
*bp
= bio
->bio_buf
;
207 unsigned secno
, nsec
, secval
, uc
;
208 u_char
*secp
, **secpp
, *dst
;
213 kprintf("mdstrategy_malloc(%p) %s %08xx, %lld, %d, %p)\n",
214 bp
, devtoname(dev
), bp
->b_flags
,
215 (long long)bio
->bio_offset
,
216 bp
->b_bcount
, bp
->b_data
);
222 bioqdisksort(&sc
->bio_queue
, bio
);
232 bio
= bioq_first(&sc
->bio_queue
);
238 bioq_remove(&sc
->bio_queue
, bio
);
241 devstat_start_transaction(&sc
->stats
);
244 case BUF_CMD_FREEBLKS
:
249 panic("md: bad b_cmd %d", bp
->b_cmd
);
252 nsec
= bp
->b_bcount
>> DEV_BSHIFT
;
253 secno
= (unsigned)(bio
->bio_offset
>> DEV_BSHIFT
);
256 if (secno
< sc
->nsecp
) {
257 secpp
= &sc
->secp
[secno
];
258 if ((u_int
)(uintptr_t)*secpp
> 255) {
263 secval
= (u_int
)(uintptr_t)*secpp
;
271 kprintf("%08x %p %p %d\n", bp
->b_flags
, secpp
, secp
, secval
);
274 case BUF_CMD_FREEBLKS
:
277 kfree(secp
, M_MDSECT
);
283 bcopy(secp
, dst
, DEV_BSIZE
);
285 for (i
= 0; i
< DEV_BSIZE
; i
++)
288 bzero(dst
, DEV_BSIZE
);
293 for (i
= 1; i
< DEV_BSIZE
; i
++)
296 if (i
== DEV_BSIZE
&& !uc
) {
298 kfree(secp
, M_MDSECT
);
300 *secpp
= (u_char
*)(uintptr_t)uc
;
303 secpp
= kmalloc((secno
+ nsec
+ 1) * sizeof(u_char
*),
306 bcopy(sc
->secp
, secpp
, sc
->nsecp
* sizeof(u_char
*));
307 kfree(sc
->secp
, M_MD
);
309 sc
->nsecp
= secno
+ nsec
+ 1;
310 secpp
= &sc
->secp
[secno
];
312 if (i
== DEV_BSIZE
) {
314 kfree(secp
, M_MDSECT
);
315 *secpp
= (u_char
*)(uintptr_t)uc
;
318 secp
= kmalloc(DEV_BSIZE
,
321 bcopy(dst
, secp
, DEV_BSIZE
);
328 panic("md: bad b_cmd %d", bp
->b_cmd
);
335 devstat_end_transaction_buf(&sc
->stats
, bp
);
345 mdstrategy_preload(struct dev_strategy_args
*ap
)
347 cdev_t dev
= ap
->a_head
.a_dev
;
348 struct bio
*bio
= ap
->a_bio
;
349 struct buf
*bp
= bio
->bio_buf
;
353 kprintf("mdstrategy_preload(%p) %s %08x, %lld, %d, %p)\n",
354 bp
, devtoname(dev
), bp
->b_flags
,
355 (long long)bio
->bio_offset
,
356 bp
->b_bcount
, bp
->b_data
);
362 bioqdisksort(&sc
->bio_queue
, bio
);
372 bio
= bioq_takefirst(&sc
->bio_queue
);
377 devstat_start_transaction(&sc
->stats
);
380 case BUF_CMD_FREEBLKS
:
383 bcopy(sc
->pl_ptr
+ bio
->bio_offset
,
384 bp
->b_data
, bp
->b_bcount
);
387 bcopy(bp
->b_data
, sc
->pl_ptr
+ bio
->bio_offset
,
391 panic("md: bad cmd %d", bp
->b_cmd
);
394 devstat_end_transaction_buf(&sc
->stats
, bp
);
403 mdcreate(unsigned length
)
406 struct disk_info info
;
408 sc
= kmalloc(sizeof(*sc
), M_MD
, M_WAITOK
| M_ZERO
);
409 lwkt_token_init(&sc
->tok
, "md");
410 sc
->unit
= mdunits
++;
411 bioq_init(&sc
->bio_queue
);
412 devstat_add_entry(&sc
->stats
, "md", sc
->unit
, DEV_BSIZE
,
413 DEVSTAT_NO_ORDERED_TAGS
,
414 DEVSTAT_TYPE_DIRECT
| DEVSTAT_TYPE_IF_OTHER
,
415 DEVSTAT_PRIORITY_OTHER
);
416 sc
->dev
= disk_create(sc
->unit
, &sc
->disk
, &md_ops
);
417 sc
->dev
->si_drv1
= sc
;
418 sc
->dev
->si_iosize_max
= MAXPHYS
;
419 disk_setdisktype(&sc
->disk
, "memory");
421 bzero(&info
, sizeof(info
));
422 info
.d_media_blksize
= DEV_BSIZE
; /* mandatory */
423 info
.d_media_blocks
= length
/ DEV_BSIZE
;
425 info
.d_secpertrack
= 1024; /* optional */
427 info
.d_secpercyl
= info
.d_secpertrack
* info
.d_nheads
;
428 info
.d_ncylinders
= (u_int
)(info
.d_media_blocks
/ info
.d_secpercyl
);
429 disk_setdiskinfo(&sc
->disk
, &info
);
430 TAILQ_INSERT_HEAD(&mdlist
, sc
, link
);
437 mdcreate_preload(u_char
*image
, unsigned length
)
441 sc
= mdcreate(length
);
442 sc
->type
= MD_PRELOAD
;
443 sc
->nsect
= length
/ DEV_BSIZE
;
452 mdcreate_malloc(void)
456 sc
= mdcreate(MD_NSECT
*DEV_BSIZE
);
457 sc
->type
= MD_MALLOC
;
459 sc
->nsect
= MD_NSECT
; /* for now */
460 sc
->secp
= kmalloc(sizeof(u_char
*), M_MD
, M_WAITOK
| M_ZERO
);
462 kprintf("md%d: Malloc disk\n", sc
->unit
);
470 struct md_s
*sc
, *sc_temp
;
472 if (atomic_fetchadd_int(&refcnt
, 0) != 0)
476 * Go through all the md devices, freeing up all the
477 * memory allocated for sectors, and the md_s struct
480 TAILQ_FOREACH_MUTABLE(sc
, &mdlist
, link
, sc_temp
) {
481 for (secno
= 0; secno
< sc
->nsecp
; secno
++) {
482 if ((u_int
)(uintptr_t)sc
->secp
[secno
] > 255)
483 kfree(sc
->secp
[secno
], M_MDSECT
);
487 disk_destroy(&sc
->disk
);
489 devstat_remove_entry(&sc
->stats
);
490 TAILQ_REMOVE(&mdlist
, sc
, link
);
492 kfree(sc
->secp
, M_MD
);
501 md_drvinit(void *unused
)
506 u_char
*ptr
, *name
, *type
;
510 mdcreate_preload(mfs_root
, MD_ROOT_SIZE
*1024);
513 while ((mod
= preload_search_next_name(mod
)) != NULL
) {
514 name
= (char *)preload_search_info(mod
, MODINFO_NAME
);
515 type
= (char *)preload_search_info(mod
, MODINFO_TYPE
);
520 if (strcmp(type
, "md_image") && strcmp(type
, "mfs_root"))
522 c
= preload_search_info(mod
, MODINFO_ADDR
);
524 c
= preload_search_info(mod
, MODINFO_SIZE
);
525 len
= *(unsigned *)c
;
526 kprintf("md%d: Preloaded image <%s> %d bytes at %p\n",
527 mdunits
, name
, len
, ptr
);
528 mdcreate_preload(ptr
, len
);
533 DEV_MODULE(md
, mdinit
, NULL
);
537 md_takeroot(void *junk
)
540 rootdevnames
[0] = "ufs:/dev/md0s0";
543 SYSINIT(md_root
, SI_SUB_MOUNT_ROOT
, SI_ORDER_FIRST
, md_takeroot
, NULL
);