md.c revision 53722
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 53722 1999-11-26 20:08:44Z phk $
10 *
11 */
12
13#include "opt_mfs.h"		/* We have adopted some tasks from MFS */
14#include "opt_md.h"		/* We have adopted some tasks from MFS */
15
16#include <sys/param.h>
17#include <sys/systm.h>
18#include <sys/buf.h>
19#include <sys/conf.h>
20#include <sys/devicestat.h>
21#include <sys/disk.h>
22#include <sys/kernel.h>
23#include <sys/malloc.h>
24#include <sys/sysctl.h>
25#include <sys/linker.h>
26
27#ifndef MDNSECT
28#define MDNSECT (10000 * 2)
29#endif
30
31MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk");
32MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors");
33
34static int md_debug;
35SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, "");
36
37#if defined(MFS_ROOT) && !defined(MD_ROOT)
38#define MD_ROOT MFS_ROOT
39#warning "option MFS_ROOT has been superceeded by MD_ROOT"
40#endif
41
42#if defined(MFS_ROOT_SIZE) && !defined(MD_ROOT_SIZE)
43#define MD_ROOT_SIZE MFS_ROOT_SIZE
44#warning "option MFS_ROOT_SIZE has been superceeded by MD_ROOT_SIZE"
45#endif
46
47#if defined(MD_ROOT) && defined(MD_ROOT_SIZE)
48/* Image gets put here: */
49static u_char mfs_root[MD_ROOT_SIZE*1024] = "MFS Filesystem goes here";
50static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
51#endif
52
53static int mdrootready;
54
55#define CDEV_MAJOR	95
56#define BDEV_MAJOR	22
57
58static d_strategy_t mdstrategy;
59static d_strategy_t mdstrategy_preload;
60static d_strategy_t mdstrategy_malloc;
61static d_open_t mdopen;
62static d_ioctl_t mdioctl;
63
64static struct cdevsw md_cdevsw = {
65        /* open */      mdopen,
66        /* close */     nullclose,
67        /* read */      physread,
68        /* write */     physwrite,
69        /* ioctl */     mdioctl,
70        /* poll */      nopoll,
71        /* mmap */      nommap,
72        /* strategy */  mdstrategy,
73        /* name */      "md",
74        /* maj */       CDEV_MAJOR,
75        /* dump */      nodump,
76        /* psize */     nopsize,
77        /* flags */     D_DISK | D_CANFREE | D_MEMDISK,
78        /* bmaj */      BDEV_MAJOR
79};
80
81struct md_s {
82	int unit;
83	struct devstat stats;
84	struct buf_queue_head buf_queue;
85	struct disk disk;
86	dev_t dev;
87	int busy;
88	enum {MD_MALLOC, MD_PRELOAD} type;
89	unsigned nsect;
90	struct cdevsw devsw;
91
92	/* MD_MALLOC related fields */
93	unsigned nsecp;
94	u_char **secp;
95
96	/* MD_PRELOAD related fields */
97	u_char *pl_ptr;
98	unsigned pl_len;
99};
100
101static int mdunits;
102
103static int
104mdopen(dev_t dev, int flag, int fmt, struct proc *p)
105{
106	struct md_s *sc;
107	struct disklabel *dl;
108
109	if (md_debug)
110		printf("mdopen(%s %x %x %p)\n",
111			devtoname(dev), flag, fmt, p);
112
113	sc = dev->si_drv1;
114
115	dl = &sc->disk.d_label;
116	bzero(dl, sizeof(*dl));
117	dl->d_secsize = DEV_BSIZE;
118	dl->d_nsectors = 1024;
119	dl->d_ntracks = 1;
120	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
121	dl->d_secperunit = sc->nsect;
122	dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl;
123	return (0);
124}
125
126static int
127mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
128{
129
130	if (md_debug)
131		printf("mdioctl(%s %lx %p %x %p)\n",
132			devtoname(dev), cmd, addr, flags, p);
133
134	return (ENOIOCTL);
135}
136
137static void
138mdstrategy(struct buf *bp)
139{
140	struct md_s *sc;
141
142	if (md_debug > 1)
143		printf("mdstrategy(%p) %s %lx, %d, %ld, %p)\n",
144		    bp, devtoname(bp->b_dev), bp->b_flags, bp->b_blkno,
145		    bp->b_bcount / DEV_BSIZE, bp->b_data);
146
147	sc = bp->b_dev->si_drv1;
148	if (sc->type == MD_MALLOC) {
149		mdstrategy_malloc(bp);
150	} else {
151		mdstrategy_preload(bp);
152	}
153	return;
154}
155
156
157static void
158mdstrategy_malloc(struct buf *bp)
159{
160	int s, i;
161	struct md_s *sc;
162	devstat_trans_flags dop;
163	u_char *secp, **secpp, *dst;
164	unsigned secno, nsec, secval, uc;
165
166	if (md_debug > 1)
167		printf("mdstrategy_malloc(%p) %s %lx, %d, %ld, %p)\n",
168		    bp, devtoname(bp->b_dev), bp->b_flags, bp->b_blkno,
169		    bp->b_bcount / DEV_BSIZE, bp->b_data);
170
171	sc = bp->b_dev->si_drv1;
172
173	s = splbio();
174
175	bufqdisksort(&sc->buf_queue, bp);
176
177	if (sc->busy) {
178		splx(s);
179		return;
180	}
181
182	sc->busy++;
183
184	while (1) {
185		bp = bufq_first(&sc->buf_queue);
186		if (bp)
187			bufq_remove(&sc->buf_queue, bp);
188		splx(s);
189		if (!bp)
190			break;
191
192		devstat_start_transaction(&sc->stats);
193
194		if (bp->b_flags & B_FREEBUF)
195			dop = DEVSTAT_NO_DATA;
196		else if (bp->b_flags & B_READ)
197			dop = DEVSTAT_READ;
198		else
199			dop = DEVSTAT_WRITE;
200
201		nsec = bp->b_bcount / DEV_BSIZE;
202		secno = bp->b_pblkno;
203		dst = bp->b_data;
204		while (nsec--) {
205
206			if (secno < sc->nsecp) {
207				secpp = &sc->secp[secno];
208				if ((u_int)*secpp > 255) {
209					secp = *secpp;
210					secval = 0;
211				} else {
212					secp = 0;
213					secval = (u_int) *secpp;
214				}
215			} else {
216				secpp = 0;
217				secp = 0;
218				secval = 0;
219			}
220			if (md_debug > 2)
221				printf("%lx %p %p %d\n", bp->b_flags, secpp, secp, secval);
222
223			if (bp->b_flags & B_FREEBUF) {
224				if (secpp) {
225					if (secp)
226						FREE(secp, M_MDSECT);
227					*secpp = 0;
228				}
229			} else if (bp->b_flags & B_READ) {
230				if (secp) {
231					bcopy(secp, dst, DEV_BSIZE);
232				} else if (secval) {
233					for (i = 0; i < DEV_BSIZE; i++)
234						dst[i] = secval;
235				} else {
236					bzero(dst, DEV_BSIZE);
237				}
238			} else {
239				uc = dst[0];
240				for (i = 1; i < DEV_BSIZE; i++)
241					if (dst[i] != uc)
242						break;
243				if (i == DEV_BSIZE && !uc) {
244					if (secp)
245						FREE(secp, M_MDSECT);
246					if (secpp)
247						*secpp = (u_char *)uc;
248				} else {
249					if (!secpp) {
250						MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK);
251						bzero(secpp, (secno + nsec + 1) * sizeof(u_char *));
252						bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *));
253						FREE(sc->secp, M_MD);
254						sc->secp = secpp;
255						sc->nsecp = secno + nsec + 1;
256						secpp = &sc->secp[secno];
257					}
258					if (i == DEV_BSIZE) {
259						if (secp)
260							FREE(secp, M_MDSECT);
261						*secpp = (u_char *)uc;
262					} else {
263						if (!secp)
264							MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
265						bcopy(dst, secp, DEV_BSIZE);
266
267						*secpp = secp;
268					}
269				}
270			}
271			secno++;
272			dst += DEV_BSIZE;
273		}
274		bp->b_resid = 0;
275		devstat_end_transaction_buf(&sc->stats, bp);
276		biodone(bp);
277		s = splbio();
278	}
279	sc->busy = 0;
280	return;
281}
282
283
284static void
285mdstrategy_preload(struct buf *bp)
286{
287	int s;
288	struct md_s *sc;
289	devstat_trans_flags dop;
290
291	if (md_debug > 1)
292		printf("mdstrategy_preload(%p) %s %lx, %d, %ld, %p)\n",
293		    bp, devtoname(bp->b_dev), bp->b_flags, bp->b_blkno,
294		    bp->b_bcount / DEV_BSIZE, bp->b_data);
295
296	sc = bp->b_dev->si_drv1;
297
298	s = splbio();
299
300	bufqdisksort(&sc->buf_queue, bp);
301
302	if (sc->busy) {
303		splx(s);
304		return;
305	}
306
307	sc->busy++;
308
309	while (1) {
310		bp = bufq_first(&sc->buf_queue);
311		if (bp)
312			bufq_remove(&sc->buf_queue, bp);
313		splx(s);
314		if (!bp)
315			break;
316
317		devstat_start_transaction(&sc->stats);
318
319		if (bp->b_flags & B_FREEBUF) {
320			dop = DEVSTAT_NO_DATA;
321		} else if (bp->b_flags & B_READ) {
322			dop = DEVSTAT_READ;
323			bcopy(sc->pl_ptr + (bp->b_pblkno << DEV_BSHIFT), bp->b_data, bp->b_bcount);
324		} else {
325			dop = DEVSTAT_WRITE;
326			bcopy(bp->b_data, sc->pl_ptr + (bp->b_pblkno << DEV_BSHIFT), bp->b_bcount);
327		}
328		bp->b_resid = 0;
329		devstat_end_transaction_buf(&sc->stats, bp);
330		biodone(bp);
331		s = splbio();
332	}
333	sc->busy = 0;
334	return;
335}
336
337static struct md_s *
338mdcreate(struct cdevsw *devsw)
339{
340	struct md_s *sc;
341
342	MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
343	bzero(sc, sizeof(*sc));
344	sc->unit = mdunits++;
345	sc->type = MD_PRELOAD;
346	bufq_init(&sc->buf_queue);
347	devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
348		DEVSTAT_NO_ORDERED_TAGS,
349		DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
350		DEVSTAT_PRIORITY_OTHER);
351	sc->dev = disk_create(sc->unit, &sc->disk, 0, devsw, &sc->devsw);
352	sc->dev->si_drv1 = sc;
353	return (sc);
354}
355
356static void
357mdcreate_preload(u_char *image, unsigned length)
358{
359	struct md_s *sc;
360
361	sc = mdcreate(&md_cdevsw);
362	sc->nsect = length / DEV_BSIZE;
363	sc->pl_ptr = image;
364	sc->pl_len = length;
365
366	if (sc->unit == 0)
367		mdrootready = 1;
368}
369
370static void
371mdcreate_malloc(void)
372{
373	struct md_s *sc;
374
375	sc = mdcreate(&md_cdevsw);
376
377	sc->nsect = MDNSECT;	/* for now */
378	MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK);
379	bzero(sc->secp, sizeof(u_char *));
380	sc->nsecp = 1;
381}
382
383static void
384md_drvinit(void *unused)
385{
386
387	caddr_t mod;
388	caddr_t c;
389	u_char *ptr, *name, *type;
390	unsigned len;
391
392#ifdef MD_ROOT_SIZE
393	mdcreate_preload(mfs_root, MD_ROOT_SIZE*1024);
394#endif
395	mod = NULL;
396	while ((mod = preload_search_next_name(mod)) != NULL) {
397		name = (char *)preload_search_info(mod, MODINFO_NAME);
398		type = (char *)preload_search_info(mod, MODINFO_TYPE);
399		if (name == NULL)
400			continue;
401		if (type == NULL)
402			continue;
403		if (strcmp(type, "md_image") && strcmp(type, "mfs_root"))
404			continue;
405		c = preload_search_info(mod, MODINFO_ADDR);
406		ptr = *(u_char **)c;
407		c = preload_search_info(mod, MODINFO_SIZE);
408		len = *(unsigned *)c;
409		printf("md%d: Preloaded image <%s> %d bytes at %p\n",
410		   mdunits, name, len, ptr);
411		mdcreate_preload(ptr, len);
412	}
413	mdcreate_malloc();
414}
415
416SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
417
418#ifdef MD_ROOT
419static void
420md_takeroot(void *junk)
421{
422	if (mdrootready)
423		rootdevnames[0] = "ufs:/dev/md0c";
424}
425
426SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL);
427#endif
428