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