dksubr.c revision 1.54.2.3 1 /* $NetBSD: dksubr.c,v 1.54.2.3 2015/09/22 12:05:56 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe and Roland C. Dowdeswell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.54.2.3 2015/09/22 12:05:56 skrll Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/stat.h>
38 #include <sys/proc.h>
39 #include <sys/ioctl.h>
40 #include <sys/device.h>
41 #include <sys/disk.h>
42 #include <sys/disklabel.h>
43 #include <sys/buf.h>
44 #include <sys/bufq.h>
45 #include <sys/vnode.h>
46 #include <sys/fcntl.h>
47 #include <sys/namei.h>
48 #include <sys/module.h>
49 #include <sys/syslog.h>
50
51 #include <dev/dkvar.h>
52 #include <miscfs/specfs/specdev.h> /* for v_rdev */
53
54 int dkdebug = 0;
55
56 #ifdef DEBUG
57 #define DKDB_FOLLOW 0x1
58 #define DKDB_INIT 0x2
59 #define DKDB_VNODE 0x4
60
61 #define IFDEBUG(x,y) if (dkdebug & (x)) y
62 #define DPRINTF(x,y) IFDEBUG(x, printf y)
63 #define DPRINTF_FOLLOW(y) DPRINTF(DKDB_FOLLOW, y)
64 #else
65 #define IFDEBUG(x,y)
66 #define DPRINTF(x,y)
67 #define DPRINTF_FOLLOW(y)
68 #endif
69
70 static int dk_subr_modcmd(modcmd_t, void *);
71
72 #define DKLABELDEV(dev) \
73 (MAKEDISKDEV(major((dev)), DISKUNIT((dev)), RAW_PART))
74
75 static void dk_makedisklabel(struct dk_softc *);
76 static int dk_translate(struct dk_softc *, struct buf *);
77 static void dk_done1(struct dk_softc *, struct buf *, bool);
78
79 void
80 dk_init(struct dk_softc *dksc, device_t dev, int dtype)
81 {
82
83 memset(dksc, 0x0, sizeof(*dksc));
84 dksc->sc_dtype = dtype;
85 dksc->sc_dev = dev;
86
87 strlcpy(dksc->sc_xname, device_xname(dev), DK_XNAME_SIZE);
88 dksc->sc_dkdev.dk_name = dksc->sc_xname;
89 }
90
91 void
92 dk_attach(struct dk_softc *dksc)
93 {
94 mutex_init(&dksc->sc_iolock, MUTEX_DEFAULT, IPL_VM);
95 dksc->sc_flags |= DKF_INITED;
96 #ifdef DIAGNOSTIC
97 dksc->sc_flags |= DKF_WARNLABEL | DKF_LABELSANITY;
98 #endif
99
100 /* Attach the device into the rnd source list. */
101 rnd_attach_source(&dksc->sc_rnd_source, dksc->sc_xname,
102 RND_TYPE_DISK, RND_FLAG_DEFAULT);
103 }
104
105 void
106 dk_detach(struct dk_softc *dksc)
107 {
108 /* Unhook the entropy source. */
109 rnd_detach_source(&dksc->sc_rnd_source);
110
111 dksc->sc_flags &= ~DKF_INITED;
112 mutex_destroy(&dksc->sc_iolock);
113 }
114
115 /* ARGSUSED */
116 int
117 dk_open(struct dk_softc *dksc, dev_t dev,
118 int flags, int fmt, struct lwp *l)
119 {
120 struct disklabel *lp = dksc->sc_dkdev.dk_label;
121 int part = DISKPART(dev);
122 int pmask = 1 << part;
123 int ret = 0;
124 struct disk *dk = &dksc->sc_dkdev;
125
126 DPRINTF_FOLLOW(("dk_open(%s, %p, 0x%"PRIx64", 0x%x)\n",
127 dksc->sc_xname, dksc, dev, flags));
128
129 mutex_enter(&dk->dk_openlock);
130
131 /*
132 * If there are wedges, and this is not RAW_PART, then we
133 * need to fail.
134 */
135 if (dk->dk_nwedges != 0 && part != RAW_PART) {
136 ret = EBUSY;
137 goto done;
138 }
139
140 /*
141 * If we're init'ed and there are no other open partitions then
142 * update the in-core disklabel.
143 */
144 if ((dksc->sc_flags & DKF_INITED)) {
145 if ((dksc->sc_flags & DKF_VLABEL) == 0) {
146 dksc->sc_flags |= DKF_VLABEL;
147 dk_getdisklabel(dksc, dev);
148 }
149 }
150
151 /* Fail if we can't find the partition. */
152 if (part != RAW_PART &&
153 ((dksc->sc_flags & DKF_VLABEL) == 0 ||
154 part >= lp->d_npartitions ||
155 lp->d_partitions[part].p_fstype == FS_UNUSED)) {
156 ret = ENXIO;
157 goto done;
158 }
159
160 /* Mark our unit as open. */
161 switch (fmt) {
162 case S_IFCHR:
163 dk->dk_copenmask |= pmask;
164 break;
165 case S_IFBLK:
166 dk->dk_bopenmask |= pmask;
167 break;
168 }
169
170 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
171
172 done:
173 mutex_exit(&dk->dk_openlock);
174 return ret;
175 }
176
177 /* ARGSUSED */
178 int
179 dk_close(struct dk_softc *dksc, dev_t dev,
180 int flags, int fmt, struct lwp *l)
181 {
182 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
183 int part = DISKPART(dev);
184 int pmask = 1 << part;
185 struct disk *dk = &dksc->sc_dkdev;
186
187 DPRINTF_FOLLOW(("dk_close(%s, %p, 0x%"PRIx64", 0x%x)\n",
188 dksc->sc_xname, dksc, dev, flags));
189
190 mutex_enter(&dk->dk_openlock);
191
192 switch (fmt) {
193 case S_IFCHR:
194 dk->dk_copenmask &= ~pmask;
195 break;
196 case S_IFBLK:
197 dk->dk_bopenmask &= ~pmask;
198 break;
199 }
200 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
201
202 if (dk->dk_openmask == 0) {
203 if (dkd->d_lastclose != NULL)
204 (*dkd->d_lastclose)(dksc->sc_dev);
205 if ((dksc->sc_flags & DKF_KLABEL) == 0)
206 dksc->sc_flags &= ~DKF_VLABEL;
207 }
208
209 mutex_exit(&dk->dk_openlock);
210 return 0;
211 }
212
213 static int
214 dk_translate(struct dk_softc *dksc, struct buf *bp)
215 {
216 int part;
217 int wlabel;
218 daddr_t blkno;
219 struct disklabel *lp;
220 struct disk *dk;
221 uint64_t numsecs;
222 unsigned secsize;
223
224 lp = dksc->sc_dkdev.dk_label;
225 dk = &dksc->sc_dkdev;
226
227 part = DISKPART(bp->b_dev);
228 numsecs = dk->dk_geom.dg_secperunit;
229 secsize = dk->dk_geom.dg_secsize;
230
231 /*
232 * The transfer must be a whole number of blocks and the offset must
233 * not be negative.
234 */
235 if ((bp->b_bcount % secsize) != 0 || bp->b_blkno < 0) {
236 bp->b_error = EINVAL;
237 goto done;
238 }
239
240 /* If there is nothing to do, then we are done */
241 if (bp->b_bcount == 0)
242 goto done;
243
244 wlabel = dksc->sc_flags & (DKF_WLABEL|DKF_LABELLING);
245 if (part == RAW_PART) {
246 if (bounds_check_with_mediasize(bp, DEV_BSIZE, numsecs) <= 0)
247 goto done;
248 } else {
249 if (bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0)
250 goto done;
251 }
252
253 /*
254 * Convert the block number to absolute and put it in terms
255 * of the device's logical block size.
256 */
257 if (secsize >= DEV_BSIZE)
258 blkno = bp->b_blkno / (secsize / DEV_BSIZE);
259 else
260 blkno = bp->b_blkno * (DEV_BSIZE / secsize);
261
262 if (part != RAW_PART)
263 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
264 bp->b_rawblkno = blkno;
265
266 return -1;
267
268 done:
269 bp->b_resid = bp->b_bcount;
270 return bp->b_error;
271 }
272
273 void
274 dk_strategy(struct dk_softc *dksc, struct buf *bp)
275 {
276 int error;
277
278 DPRINTF_FOLLOW(("dk_strategy(%s, %p, %p)\n",
279 dksc->sc_xname, dksc, bp));
280
281 if (!(dksc->sc_flags & DKF_INITED)) {
282 DPRINTF_FOLLOW(("dk_strategy: not inited\n"));
283 bp->b_error = ENXIO;
284 biodone(bp);
285 return;
286 }
287
288 error = dk_translate(dksc, bp);
289 if (error >= 0) {
290 biodone(bp);
291 return;
292 }
293
294 /*
295 * Queue buffer and start unit
296 */
297 dk_start(dksc, bp);
298 }
299
300 void
301 dk_start(struct dk_softc *dksc, struct buf *bp)
302 {
303 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
304 int error;
305
306 mutex_enter(&dksc->sc_iolock);
307
308 if (bp != NULL)
309 bufq_put(dksc->sc_bufq, bp);
310
311 if (dksc->sc_busy)
312 goto done;
313 dksc->sc_busy = true;
314
315 /*
316 * Peeking at the buffer queue and committing the operation
317 * only after success isn't atomic.
318 *
319 * So when a diskstart fails, the buffer is saved
320 * and tried again before the next buffer is fetched.
321 * dk_drain() handles flushing of a saved buffer.
322 *
323 * This keeps order of I/O operations, unlike bufq_put.
324 */
325
326 bp = dksc->sc_deferred;
327 dksc->sc_deferred = NULL;
328
329 if (bp == NULL)
330 bp = bufq_get(dksc->sc_bufq);
331
332 while (bp != NULL) {
333
334 disk_busy(&dksc->sc_dkdev);
335 mutex_exit(&dksc->sc_iolock);
336 error = dkd->d_diskstart(dksc->sc_dev, bp);
337 mutex_enter(&dksc->sc_iolock);
338 if (error == EAGAIN) {
339 dksc->sc_deferred = bp;
340 disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
341 break;
342 }
343
344 if (error != 0) {
345 bp->b_error = error;
346 bp->b_resid = bp->b_bcount;
347 dk_done1(dksc, bp, false);
348 }
349
350 bp = bufq_get(dksc->sc_bufq);
351 }
352
353 dksc->sc_busy = false;
354 done:
355 mutex_exit(&dksc->sc_iolock);
356 }
357
358 static void
359 dk_done1(struct dk_softc *dksc, struct buf *bp, bool lock)
360 {
361 struct disk *dk = &dksc->sc_dkdev;
362
363 if (bp->b_error != 0) {
364 struct cfdriver *cd = device_cfdriver(dksc->sc_dev);
365
366 diskerr(bp, cd->cd_name, "error", LOG_PRINTF, 0,
367 dk->dk_label);
368 printf("\n");
369 }
370
371 if (lock)
372 mutex_enter(&dksc->sc_iolock);
373 disk_unbusy(dk, bp->b_bcount - bp->b_resid, (bp->b_flags & B_READ));
374 if (lock)
375 mutex_exit(&dksc->sc_iolock);
376
377 rnd_add_uint32(&dksc->sc_rnd_source, bp->b_rawblkno);
378
379 biodone(bp);
380 }
381
382 void
383 dk_done(struct dk_softc *dksc, struct buf *bp)
384 {
385 dk_done1(dksc, bp, true);
386 }
387
388 void
389 dk_drain(struct dk_softc *dksc)
390 {
391 struct buf *bp;
392
393 mutex_enter(&dksc->sc_iolock);
394 bp = dksc->sc_deferred;
395 if (bp != NULL) {
396 bp->b_error = EIO;
397 bp->b_resid = bp->b_bcount;
398 biodone(bp);
399 }
400 bufq_drain(dksc->sc_bufq);
401 mutex_exit(&dksc->sc_iolock);
402 }
403
404 int
405 dk_discard(struct dk_softc *dksc, dev_t dev, off_t pos, off_t len)
406 {
407 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
408 unsigned secsize = dksc->sc_dkdev.dk_geom.dg_secsize;
409 struct buf tmp, *bp = &tmp;
410 int error;
411
412 DPRINTF_FOLLOW(("dk_discard(%s, %p, 0x"PRIx64", %jd, %jd)\n",
413 dksc->sc_xname, dksc, (intmax_t)pos, (intmax_t)len));
414
415 if (!(dksc->sc_flags & DKF_INITED)) {
416 DPRINTF_FOLLOW(("dk_discard: not inited\n"));
417 return ENXIO;
418 }
419
420 if (secsize == 0 || (pos % secsize) != 0)
421 return EINVAL;
422
423 /* enough data to please the bounds checking code */
424 bp->b_dev = dev;
425 bp->b_blkno = (daddr_t)(pos / secsize);
426 bp->b_bcount = len;
427 bp->b_flags = B_WRITE;
428
429 error = dk_translate(dksc, bp);
430 if (error >= 0)
431 return error;
432
433 error = dkd->d_discard(dksc->sc_dev,
434 (off_t)bp->b_rawblkno * secsize,
435 (off_t)bp->b_bcount);
436
437 return error;
438 }
439
440 int
441 dk_size(struct dk_softc *dksc, dev_t dev)
442 {
443 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
444 struct disklabel *lp;
445 int is_open;
446 int part;
447 int size;
448
449 if ((dksc->sc_flags & DKF_INITED) == 0)
450 return -1;
451
452 part = DISKPART(dev);
453 is_open = dksc->sc_dkdev.dk_openmask & (1 << part);
454
455 if (!is_open && dkd->d_open(dev, 0, S_IFBLK, curlwp))
456 return -1;
457
458 lp = dksc->sc_dkdev.dk_label;
459 if (lp->d_partitions[part].p_fstype != FS_SWAP)
460 size = -1;
461 else
462 size = lp->d_partitions[part].p_size *
463 (lp->d_secsize / DEV_BSIZE);
464
465 if (!is_open && dkd->d_close(dev, 0, S_IFBLK, curlwp))
466 return -1;
467
468 return size;
469 }
470
471 int
472 dk_ioctl(struct dk_softc *dksc, dev_t dev,
473 u_long cmd, void *data, int flag, struct lwp *l)
474 {
475 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
476 struct disklabel *lp;
477 struct disk *dk = &dksc->sc_dkdev;
478 #ifdef __HAVE_OLD_DISKLABEL
479 struct disklabel newlabel;
480 #endif
481 int error;
482
483 DPRINTF_FOLLOW(("dk_ioctl(%s, %p, 0x%"PRIx64", 0x%lx)\n",
484 dksc->sc_xname, dksc, dev, cmd));
485
486 /* ensure that the pseudo disk is open for writes for these commands */
487 switch (cmd) {
488 case DIOCSDINFO:
489 case DIOCWDINFO:
490 #ifdef __HAVE_OLD_DISKLABEL
491 case ODIOCSDINFO:
492 case ODIOCWDINFO:
493 #endif
494 case DIOCKLABEL:
495 case DIOCWLABEL:
496 case DIOCAWEDGE:
497 case DIOCDWEDGE:
498 case DIOCSSTRATEGY:
499 if ((flag & FWRITE) == 0)
500 return EBADF;
501 }
502
503 /* ensure that the pseudo-disk is initialized for these */
504 switch (cmd) {
505 case DIOCGDINFO:
506 case DIOCSDINFO:
507 case DIOCWDINFO:
508 case DIOCGPART:
509 case DIOCKLABEL:
510 case DIOCWLABEL:
511 case DIOCGDEFLABEL:
512 case DIOCAWEDGE:
513 case DIOCDWEDGE:
514 case DIOCLWEDGES:
515 case DIOCMWEDGES:
516 case DIOCCACHESYNC:
517 #ifdef __HAVE_OLD_DISKLABEL
518 case ODIOCGDINFO:
519 case ODIOCSDINFO:
520 case ODIOCWDINFO:
521 case ODIOCGDEFLABEL:
522 #endif
523 if ((dksc->sc_flags & DKF_INITED) == 0)
524 return ENXIO;
525 }
526
527 error = disk_ioctl(dk, dev, cmd, data, flag, l);
528 if (error != EPASSTHROUGH)
529 return error;
530 else
531 error = 0;
532
533 switch (cmd) {
534 case DIOCWDINFO:
535 case DIOCSDINFO:
536 #ifdef __HAVE_OLD_DISKLABEL
537 case ODIOCWDINFO:
538 case ODIOCSDINFO:
539 #endif
540 #ifdef __HAVE_OLD_DISKLABEL
541 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
542 memset(&newlabel, 0, sizeof newlabel);
543 memcpy(&newlabel, data, sizeof (struct olddisklabel));
544 lp = &newlabel;
545 } else
546 #endif
547 lp = (struct disklabel *)data;
548
549 mutex_enter(&dk->dk_openlock);
550 dksc->sc_flags |= DKF_LABELLING;
551
552 error = setdisklabel(dksc->sc_dkdev.dk_label,
553 lp, 0, dksc->sc_dkdev.dk_cpulabel);
554 if (error == 0) {
555 if (cmd == DIOCWDINFO
556 #ifdef __HAVE_OLD_DISKLABEL
557 || cmd == ODIOCWDINFO
558 #endif
559 )
560 error = writedisklabel(DKLABELDEV(dev),
561 dkd->d_strategy, dksc->sc_dkdev.dk_label,
562 dksc->sc_dkdev.dk_cpulabel);
563 }
564
565 dksc->sc_flags &= ~DKF_LABELLING;
566 mutex_exit(&dk->dk_openlock);
567 break;
568
569 case DIOCKLABEL:
570 if (*(int *)data != 0)
571 dksc->sc_flags |= DKF_KLABEL;
572 else
573 dksc->sc_flags &= ~DKF_KLABEL;
574 break;
575
576 case DIOCWLABEL:
577 if (*(int *)data != 0)
578 dksc->sc_flags |= DKF_WLABEL;
579 else
580 dksc->sc_flags &= ~DKF_WLABEL;
581 break;
582
583 case DIOCGDEFLABEL:
584 dk_getdefaultlabel(dksc, (struct disklabel *)data);
585 break;
586
587 #ifdef __HAVE_OLD_DISKLABEL
588 case ODIOCGDEFLABEL:
589 dk_getdefaultlabel(dksc, &newlabel);
590 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
591 return ENOTTY;
592 memcpy(data, &newlabel, sizeof (struct olddisklabel));
593 break;
594 #endif
595
596 case DIOCGSTRATEGY:
597 {
598 struct disk_strategy *dks = (void *)data;
599
600 mutex_enter(&dksc->sc_iolock);
601 strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq),
602 sizeof(dks->dks_name));
603 mutex_exit(&dksc->sc_iolock);
604 dks->dks_paramlen = 0;
605
606 return 0;
607 }
608
609 case DIOCSSTRATEGY:
610 {
611 struct disk_strategy *dks = (void *)data;
612 struct bufq_state *new;
613 struct bufq_state *old;
614
615 if (dks->dks_param != NULL) {
616 return EINVAL;
617 }
618 dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
619 error = bufq_alloc(&new, dks->dks_name,
620 BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
621 if (error) {
622 return error;
623 }
624 mutex_enter(&dksc->sc_iolock);
625 old = dksc->sc_bufq;
626 bufq_move(new, old);
627 dksc->sc_bufq = new;
628 mutex_exit(&dksc->sc_iolock);
629 bufq_free(old);
630
631 return 0;
632 }
633
634 default:
635 error = ENOTTY;
636 }
637
638 return error;
639 }
640
641 /*
642 * dk_dump dumps all of physical memory into the partition specified.
643 * This requires substantially more framework than {s,w}ddump, and hence
644 * is probably much more fragile.
645 *
646 */
647
648 #define DKF_READYFORDUMP (DKF_INITED|DKF_TAKEDUMP)
649 #define DKFF_READYFORDUMP(x) (((x) & DKF_READYFORDUMP) == DKF_READYFORDUMP)
650 static volatile int dk_dumping = 0;
651
652 /* ARGSUSED */
653 int
654 dk_dump(struct dk_softc *dksc, dev_t dev,
655 daddr_t blkno, void *vav, size_t size)
656 {
657 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
658 char *va = vav;
659 struct disklabel *lp;
660 int part, towrt, nsects, sectoff, maxblkcnt, nblk;
661 int maxxfer, rv = 0;
662
663 /*
664 * ensure that we consider this device to be safe for dumping,
665 * and that the device is configured.
666 */
667 if (!DKFF_READYFORDUMP(dksc->sc_flags))
668 return ENXIO;
669
670 /* ensure that we are not already dumping */
671 if (dk_dumping)
672 return EFAULT;
673 dk_dumping = 1;
674
675 if (dkd->d_dumpblocks == NULL)
676 return ENXIO;
677
678 /* device specific max transfer size */
679 maxxfer = MAXPHYS;
680 if (dkd->d_iosize != NULL)
681 (*dkd->d_iosize)(dksc->sc_dev, &maxxfer);
682
683 /* Convert to disk sectors. Request must be a multiple of size. */
684 part = DISKPART(dev);
685 lp = dksc->sc_dkdev.dk_label;
686 if ((size % lp->d_secsize) != 0)
687 return (EFAULT);
688 towrt = size / lp->d_secsize;
689 blkno = dbtob(blkno) / lp->d_secsize; /* blkno in secsize units */
690
691 nsects = lp->d_partitions[part].p_size;
692 sectoff = lp->d_partitions[part].p_offset;
693
694 /* Check transfer bounds against partition size. */
695 if ((blkno < 0) || ((blkno + towrt) > nsects))
696 return (EINVAL);
697
698 /* Offset block number to start of partition. */
699 blkno += sectoff;
700
701 /* Start dumping and return when done. */
702 maxblkcnt = howmany(maxxfer, lp->d_secsize);
703 while (towrt > 0) {
704 nblk = min(maxblkcnt, towrt);
705
706 if ((rv = (*dkd->d_dumpblocks)(dksc->sc_dev, va, blkno, nblk)) != 0)
707 return (rv);
708
709 towrt -= nblk;
710 blkno += nblk;
711 va += nblk * lp->d_secsize;
712 }
713
714 dk_dumping = 0;
715
716 return 0;
717 }
718
719 /* ARGSUSED */
720 void
721 dk_getdefaultlabel(struct dk_softc *dksc, struct disklabel *lp)
722 {
723 struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
724
725 memset(lp, 0, sizeof(*lp));
726
727 if (dg->dg_secperunit > UINT32_MAX)
728 lp->d_secperunit = UINT32_MAX;
729 else
730 lp->d_secperunit = dg->dg_secperunit;
731 lp->d_secsize = dg->dg_secsize;
732 lp->d_nsectors = dg->dg_nsectors;
733 lp->d_ntracks = dg->dg_ntracks;
734 lp->d_ncylinders = dg->dg_ncylinders;
735 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
736
737 strlcpy(lp->d_typename, dksc->sc_xname, sizeof(lp->d_typename));
738 lp->d_type = dksc->sc_dtype;
739 strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
740 lp->d_rpm = 3600;
741 lp->d_interleave = 1;
742 lp->d_flags = 0;
743
744 lp->d_partitions[RAW_PART].p_offset = 0;
745 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
746 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
747 lp->d_npartitions = RAW_PART + 1;
748
749 lp->d_magic = DISKMAGIC;
750 lp->d_magic2 = DISKMAGIC;
751 lp->d_checksum = dkcksum(dksc->sc_dkdev.dk_label);
752 }
753
754 /* ARGSUSED */
755 void
756 dk_getdisklabel(struct dk_softc *dksc, dev_t dev)
757 {
758 const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
759 struct disklabel *lp = dksc->sc_dkdev.dk_label;
760 struct cpu_disklabel *clp = dksc->sc_dkdev.dk_cpulabel;
761 struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
762 struct partition *pp;
763 int i;
764 const char *errstring;
765
766 memset(clp, 0x0, sizeof(*clp));
767 dk_getdefaultlabel(dksc, lp);
768 errstring = readdisklabel(DKLABELDEV(dev), dkd->d_strategy,
769 dksc->sc_dkdev.dk_label, dksc->sc_dkdev.dk_cpulabel);
770 if (errstring) {
771 dk_makedisklabel(dksc);
772 if (dksc->sc_flags & DKF_WARNLABEL)
773 printf("%s: %s\n", dksc->sc_xname, errstring);
774 return;
775 }
776
777 if ((dksc->sc_flags & DKF_LABELSANITY) == 0)
778 return;
779
780 /* Sanity check */
781 if (lp->d_secperunit < UINT32_MAX ?
782 lp->d_secperunit != dg->dg_secperunit :
783 lp->d_secperunit > dg->dg_secperunit)
784 printf("WARNING: %s: total sector size in disklabel (%ju) "
785 "!= the size of %s (%ju)\n", dksc->sc_xname,
786 (uintmax_t)lp->d_secperunit, dksc->sc_xname,
787 (uintmax_t)dg->dg_secperunit);
788
789 for (i=0; i < lp->d_npartitions; i++) {
790 pp = &lp->d_partitions[i];
791 if (pp->p_offset + pp->p_size > dg->dg_secperunit)
792 printf("WARNING: %s: end of partition `%c' exceeds "
793 "the size of %s (%ju)\n", dksc->sc_xname,
794 'a' + i, dksc->sc_xname,
795 (uintmax_t)dg->dg_secperunit);
796 }
797 }
798
799 /* ARGSUSED */
800 static void
801 dk_makedisklabel(struct dk_softc *dksc)
802 {
803 struct disklabel *lp = dksc->sc_dkdev.dk_label;
804
805 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
806 strlcpy(lp->d_packname, "default label", sizeof(lp->d_packname));
807 lp->d_checksum = dkcksum(lp);
808 }
809
810 /* This function is taken from ccd.c:1.76 --rcd */
811
812 /*
813 * XXX this function looks too generic for dksubr.c, shouldn't we
814 * put it somewhere better?
815 */
816
817 /*
818 * Lookup the provided name in the filesystem. If the file exists,
819 * is a valid block device, and isn't being used by anyone else,
820 * set *vpp to the file's vnode.
821 */
822 int
823 dk_lookup(struct pathbuf *pb, struct lwp *l, struct vnode **vpp)
824 {
825 struct nameidata nd;
826 struct vnode *vp;
827 int error;
828
829 if (l == NULL)
830 return ESRCH; /* Is ESRCH the best choice? */
831
832 NDINIT(&nd, LOOKUP, FOLLOW, pb);
833 if ((error = vn_open(&nd, FREAD | FWRITE, 0)) != 0) {
834 DPRINTF((DKDB_FOLLOW|DKDB_INIT),
835 ("dk_lookup: vn_open error = %d\n", error));
836 return error;
837 }
838
839 vp = nd.ni_vp;
840 if (vp->v_type != VBLK) {
841 error = ENOTBLK;
842 goto out;
843 }
844
845 /* Reopen as anonymous vnode to protect against forced unmount. */
846 if ((error = bdevvp(vp->v_rdev, vpp)) != 0)
847 goto out;
848 VOP_UNLOCK(vp);
849 if ((error = vn_close(vp, FREAD | FWRITE, l->l_cred)) != 0) {
850 vrele(*vpp);
851 return error;
852 }
853 if ((error = VOP_OPEN(*vpp, FREAD | FWRITE, l->l_cred)) != 0) {
854 vrele(*vpp);
855 return error;
856 }
857 mutex_enter((*vpp)->v_interlock);
858 (*vpp)->v_writecount++;
859 mutex_exit((*vpp)->v_interlock);
860
861 IFDEBUG(DKDB_VNODE, vprint("dk_lookup: vnode info", *vpp));
862
863 return 0;
864 out:
865 VOP_UNLOCK(vp);
866 (void) vn_close(vp, FREAD | FWRITE, l->l_cred);
867 return error;
868 }
869
870 MODULE(MODULE_CLASS_MISC, dk_subr, NULL);
871
872 static int
873 dk_subr_modcmd(modcmd_t cmd, void *arg)
874 {
875 switch (cmd) {
876 case MODULE_CMD_INIT:
877 case MODULE_CMD_FINI:
878 return 0;
879 case MODULE_CMD_STAT:
880 case MODULE_CMD_AUTOUNLOAD:
881 default:
882 return ENOTTY;
883 }
884 }
885