dksubr.c revision 1.44 1 /* $NetBSD: dksubr.c,v 1.44 2012/05/25 14:25:39 elric 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.44 2012/05/25 14:25:39 elric 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
49 #include <dev/dkvar.h>
50
51 int dkdebug = 0;
52
53 #ifdef DEBUG
54 #define DKDB_FOLLOW 0x1
55 #define DKDB_INIT 0x2
56 #define DKDB_VNODE 0x4
57
58 #define IFDEBUG(x,y) if (dkdebug & (x)) y
59 #define DPRINTF(x,y) IFDEBUG(x, printf y)
60 #define DPRINTF_FOLLOW(y) DPRINTF(DKDB_FOLLOW, y)
61 #else
62 #define IFDEBUG(x,y)
63 #define DPRINTF(x,y)
64 #define DPRINTF_FOLLOW(y)
65 #endif
66
67 #define DKLABELDEV(dev) \
68 (MAKEDISKDEV(major((dev)), DISKUNIT((dev)), RAW_PART))
69
70 static void dk_makedisklabel(struct dk_intf *, struct dk_softc *);
71
72 void
73 dk_sc_init(struct dk_softc *dksc, const char *xname)
74 {
75
76 memset(dksc, 0x0, sizeof(*dksc));
77 strncpy(dksc->sc_xname, xname, DK_XNAME_SIZE);
78 dksc->sc_dkdev.dk_name = dksc->sc_xname;
79 }
80
81 /* ARGSUSED */
82 int
83 dk_open(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
84 int flags, int fmt, struct lwp *l)
85 {
86 struct disklabel *lp = dksc->sc_dkdev.dk_label;
87 int part = DISKPART(dev);
88 int pmask = 1 << part;
89 int ret = 0;
90 struct disk *dk = &dksc->sc_dkdev;
91
92 DPRINTF_FOLLOW(("dk_open(%s, %p, 0x%"PRIx64", 0x%x)\n",
93 di->di_dkname, dksc, dev, flags));
94
95 mutex_enter(&dk->dk_openlock);
96 part = DISKPART(dev);
97
98 /*
99 * If there are wedges, and this is not RAW_PART, then we
100 * need to fail.
101 */
102 if (dk->dk_nwedges != 0 && part != RAW_PART) {
103 ret = EBUSY;
104 goto done;
105 }
106
107 pmask = 1 << part;
108
109 /*
110 * If we're init'ed and there are no other open partitions then
111 * update the in-core disklabel.
112 */
113 if ((dksc->sc_flags & DKF_INITED)) {
114 if (dk->dk_openmask == 0) {
115 dk_getdisklabel(di, dksc, dev);
116 }
117 /* XXX re-discover wedges? */
118 }
119
120 /* Fail if we can't find the partition. */
121 if ((part != RAW_PART) &&
122 (((dksc->sc_flags & DKF_INITED) == 0) ||
123 ((part >= lp->d_npartitions) ||
124 (lp->d_partitions[part].p_fstype == FS_UNUSED)))) {
125 ret = ENXIO;
126 goto done;
127 }
128
129 /* Mark our unit as open. */
130 switch (fmt) {
131 case S_IFCHR:
132 dk->dk_copenmask |= pmask;
133 break;
134 case S_IFBLK:
135 dk->dk_bopenmask |= pmask;
136 break;
137 }
138
139 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
140
141 done:
142 mutex_exit(&dk->dk_openlock);
143 return ret;
144 }
145
146 /* ARGSUSED */
147 int
148 dk_close(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
149 int flags, int fmt, struct lwp *l)
150 {
151 int part = DISKPART(dev);
152 int pmask = 1 << part;
153 struct disk *dk = &dksc->sc_dkdev;
154
155 DPRINTF_FOLLOW(("dk_close(%s, %p, 0x%"PRIx64", 0x%x)\n",
156 di->di_dkname, dksc, dev, flags));
157
158 mutex_enter(&dk->dk_openlock);
159
160 switch (fmt) {
161 case S_IFCHR:
162 dk->dk_copenmask &= ~pmask;
163 break;
164 case S_IFBLK:
165 dk->dk_bopenmask &= ~pmask;
166 break;
167 }
168 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
169
170 mutex_exit(&dk->dk_openlock);
171 return 0;
172 }
173
174 void
175 dk_strategy(struct dk_intf *di, struct dk_softc *dksc, struct buf *bp)
176 {
177 int s;
178 int wlabel;
179 daddr_t blkno;
180
181 DPRINTF_FOLLOW(("dk_strategy(%s, %p, %p)\n",
182 di->di_dkname, dksc, bp));
183
184 if (!(dksc->sc_flags & DKF_INITED)) {
185 DPRINTF_FOLLOW(("dk_strategy: not inited\n"));
186 bp->b_error = ENXIO;
187 biodone(bp);
188 return;
189 }
190
191 /* XXX look for some more errors, c.f. ld.c */
192
193 bp->b_resid = bp->b_bcount;
194
195 /* If there is nothing to do, then we are done */
196 if (bp->b_bcount == 0) {
197 biodone(bp);
198 return;
199 }
200
201 wlabel = dksc->sc_flags & (DKF_WLABEL|DKF_LABELLING);
202 if (DISKPART(bp->b_dev) != RAW_PART &&
203 bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0) {
204 biodone(bp);
205 return;
206 }
207
208 blkno = bp->b_blkno;
209 if (DISKPART(bp->b_dev) != RAW_PART) {
210 struct partition *pp;
211
212 pp =
213 &dksc->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
214 blkno += pp->p_offset;
215 }
216 bp->b_rawblkno = blkno;
217
218 /*
219 * Start the unit by calling the start routine
220 * provided by the individual driver.
221 */
222 s = splbio();
223 bufq_put(dksc->sc_bufq, bp);
224 dk_start(di, dksc);
225 splx(s);
226 return;
227 }
228
229 void
230 dk_start(struct dk_intf *di, struct dk_softc *dksc)
231 {
232 struct buf *bp;
233
234 DPRINTF_FOLLOW(("dk_start(%s, %p)\n", di->di_dkname, dksc));
235
236 /* Process the work queue */
237 while ((bp = bufq_get(dksc->sc_bufq)) != NULL) {
238 if (di->di_diskstart(dksc, bp) != 0) {
239 bufq_put(dksc->sc_bufq, bp);
240 break;
241 }
242 }
243 }
244
245 void
246 dk_iodone(struct dk_intf *di, struct dk_softc *dksc)
247 {
248
249 DPRINTF_FOLLOW(("dk_iodone(%s, %p)\n", di->di_dkname, dksc));
250
251 /* We kick the queue in case we are able to get more work done */
252 dk_start(di, dksc);
253 }
254
255 int
256 dk_size(struct dk_intf *di, struct dk_softc *dksc, dev_t dev)
257 {
258 struct disklabel *lp;
259 int is_open;
260 int part;
261 int size;
262
263 if ((dksc->sc_flags & DKF_INITED) == 0)
264 return -1;
265
266 part = DISKPART(dev);
267 is_open = dksc->sc_dkdev.dk_openmask & (1 << part);
268
269 if (!is_open && di->di_open(dev, 0, S_IFBLK, curlwp))
270 return -1;
271
272 lp = dksc->sc_dkdev.dk_label;
273 if (lp->d_partitions[part].p_fstype != FS_SWAP)
274 size = -1;
275 else
276 size = lp->d_partitions[part].p_size *
277 (lp->d_secsize / DEV_BSIZE);
278
279 if (!is_open && di->di_close(dev, 0, S_IFBLK, curlwp))
280 return 1;
281
282 return size;
283 }
284
285 int
286 dk_ioctl(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
287 u_long cmd, void *data, int flag, struct lwp *l)
288 {
289 struct disklabel *lp;
290 struct disk *dk;
291 #ifdef __HAVE_OLD_DISKLABEL
292 struct disklabel newlabel;
293 #endif
294 int error = 0;
295
296 DPRINTF_FOLLOW(("dk_ioctl(%s, %p, 0x%"PRIx64", 0x%lx)\n",
297 di->di_dkname, dksc, dev, cmd));
298
299 /* ensure that the pseudo disk is open for writes for these commands */
300 switch (cmd) {
301 case DIOCSDINFO:
302 case DIOCWDINFO:
303 #ifdef __HAVE_OLD_DISKLABEL
304 case ODIOCSDINFO:
305 case ODIOCWDINFO:
306 #endif
307 case DIOCWLABEL:
308 case DIOCAWEDGE:
309 case DIOCDWEDGE:
310 if ((flag & FWRITE) == 0)
311 return EBADF;
312 }
313
314 /* ensure that the pseudo-disk is initialized for these */
315 switch (cmd) {
316 #ifdef DIOCGSECTORSIZE
317 case DIOCGSECTORSIZE:
318 case DIOCGMEDIASIZE:
319 #endif
320 case DIOCGDINFO:
321 case DIOCSDINFO:
322 case DIOCWDINFO:
323 case DIOCGPART:
324 case DIOCWLABEL:
325 case DIOCGDEFLABEL:
326 case DIOCAWEDGE:
327 case DIOCDWEDGE:
328 case DIOCLWEDGES:
329 case DIOCCACHESYNC:
330 #ifdef __HAVE_OLD_DISKLABEL
331 case ODIOCGDINFO:
332 case ODIOCSDINFO:
333 case ODIOCWDINFO:
334 case ODIOCGDEFLABEL:
335 #endif
336 if ((dksc->sc_flags & DKF_INITED) == 0)
337 return ENXIO;
338 }
339
340 switch (cmd) {
341 #ifdef DIOCGSECTORSIZE
342 case DIOCGSECTORSIZE:
343 *(u_int *)data = dksc->sc_geom.pdg_secsize;
344 return 0;
345 case DIOCGMEDIASIZE:
346 *(off_t *)data =
347 (off_t)dksc->sc_geom.pdg_secsize *
348 dksc->sc_geom.pdg_nsectors;
349 return 0;
350 #endif
351
352 case DIOCGDINFO:
353 *(struct disklabel *)data = *(dksc->sc_dkdev.dk_label);
354 break;
355
356 #ifdef __HAVE_OLD_DISKLABEL
357 case ODIOCGDINFO:
358 newlabel = *(dksc->sc_dkdev.dk_label);
359 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
360 return ENOTTY;
361 memcpy(data, &newlabel, sizeof (struct olddisklabel));
362 break;
363 #endif
364
365 case DIOCGPART:
366 ((struct partinfo *)data)->disklab = dksc->sc_dkdev.dk_label;
367 ((struct partinfo *)data)->part =
368 &dksc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
369 break;
370
371 case DIOCWDINFO:
372 case DIOCSDINFO:
373 #ifdef __HAVE_OLD_DISKLABEL
374 case ODIOCWDINFO:
375 case ODIOCSDINFO:
376 #endif
377 #ifdef __HAVE_OLD_DISKLABEL
378 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
379 memset(&newlabel, 0, sizeof newlabel);
380 memcpy(&newlabel, data, sizeof (struct olddisklabel));
381 lp = &newlabel;
382 } else
383 #endif
384 lp = (struct disklabel *)data;
385
386 dk = &dksc->sc_dkdev;
387 mutex_enter(&dk->dk_openlock);
388 dksc->sc_flags |= DKF_LABELLING;
389
390 error = setdisklabel(dksc->sc_dkdev.dk_label,
391 lp, 0, dksc->sc_dkdev.dk_cpulabel);
392 if (error == 0) {
393 if (cmd == DIOCWDINFO
394 #ifdef __HAVE_OLD_DISKLABEL
395 || cmd == ODIOCWDINFO
396 #endif
397 )
398 error = writedisklabel(DKLABELDEV(dev),
399 di->di_strategy, dksc->sc_dkdev.dk_label,
400 dksc->sc_dkdev.dk_cpulabel);
401 }
402
403 dksc->sc_flags &= ~DKF_LABELLING;
404 mutex_exit(&dk->dk_openlock);
405 break;
406
407 case DIOCWLABEL:
408 if (*(int *)data != 0)
409 dksc->sc_flags |= DKF_WLABEL;
410 else
411 dksc->sc_flags &= ~DKF_WLABEL;
412 break;
413
414 case DIOCGDEFLABEL:
415 dk_getdefaultlabel(di, dksc, (struct disklabel *)data);
416 break;
417
418 #ifdef __HAVE_OLD_DISKLABEL
419 case ODIOCGDEFLABEL:
420 dk_getdefaultlabel(di, dksc, &newlabel);
421 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
422 return ENOTTY;
423 memcpy(data, &newlabel, sizeof (struct olddisklabel));
424 break;
425 #endif
426
427 case DIOCAWEDGE:
428 {
429 struct dkwedge_info *dkw = (void *)data;
430
431 if ((flag & FWRITE) == 0)
432 return (EBADF);
433
434 /* If the ioctl happens here, the parent is us. */
435 strcpy(dkw->dkw_parent, dksc->sc_dkdev.dk_name);
436 return (dkwedge_add(dkw));
437 }
438
439 case DIOCDWEDGE:
440 {
441 struct dkwedge_info *dkw = (void *)data;
442
443 if ((flag & FWRITE) == 0)
444 return (EBADF);
445
446 /* If the ioctl happens here, the parent is us. */
447 strcpy(dkw->dkw_parent, dksc->sc_dkdev.dk_name);
448 return (dkwedge_del(dkw));
449 }
450
451 case DIOCLWEDGES:
452 {
453 struct dkwedge_list *dkwl = (void *)data;
454
455 return (dkwedge_list(&dksc->sc_dkdev, dkwl, l));
456 }
457
458 case DIOCGSTRATEGY:
459 {
460 struct disk_strategy *dks = (void *)data;
461 int s;
462
463 s = splbio();
464 strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq),
465 sizeof(dks->dks_name));
466 splx(s);
467 dks->dks_paramlen = 0;
468
469 return 0;
470 }
471
472 case DIOCSSTRATEGY:
473 {
474 struct disk_strategy *dks = (void *)data;
475 struct bufq_state *new;
476 struct bufq_state *old;
477 int s;
478
479 if ((flag & FWRITE) == 0) {
480 return EBADF;
481 }
482 if (dks->dks_param != NULL) {
483 return EINVAL;
484 }
485 dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
486 error = bufq_alloc(&new, dks->dks_name,
487 BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
488 if (error) {
489 return error;
490 }
491 s = splbio();
492 old = dksc->sc_bufq;
493 bufq_move(new, old);
494 dksc->sc_bufq = new;
495 splx(s);
496 bufq_free(old);
497
498 return 0;
499 }
500
501 default:
502 error = ENOTTY;
503 }
504
505 return error;
506 }
507
508 /*
509 * dk_dump dumps all of physical memory into the partition specified.
510 * This requires substantially more framework than {s,w}ddump, and hence
511 * is probably much more fragile.
512 *
513 * XXX: we currently do not implement this.
514 */
515
516 #define DKF_READYFORDUMP (DKF_INITED|DKF_TAKEDUMP)
517 #define DKFF_READYFORDUMP(x) (((x) & DKF_READYFORDUMP) == DKF_READYFORDUMP)
518 static volatile int dk_dumping = 0;
519
520 /* ARGSUSED */
521 int
522 dk_dump(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
523 daddr_t blkno, void *va, size_t size)
524 {
525
526 /*
527 * ensure that we consider this device to be safe for dumping,
528 * and that the device is configured.
529 */
530 if (!DKFF_READYFORDUMP(dksc->sc_flags))
531 return ENXIO;
532
533 /* ensure that we are not already dumping */
534 if (dk_dumping)
535 return EFAULT;
536 dk_dumping = 1;
537
538 /* XXX: unimplemented */
539
540 dk_dumping = 0;
541
542 /* XXX: actually for now, we are going to leave this alone */
543 return ENXIO;
544 }
545
546 /* ARGSUSED */
547 void
548 dk_getdefaultlabel(struct dk_intf *di, struct dk_softc *dksc,
549 struct disklabel *lp)
550 {
551 struct dk_geom *pdg = &dksc->sc_geom;
552
553 memset(lp, 0, sizeof(*lp));
554
555 lp->d_secperunit = dksc->sc_size;
556 lp->d_secsize = pdg->pdg_secsize;
557 lp->d_nsectors = pdg->pdg_nsectors;
558 lp->d_ntracks = pdg->pdg_ntracks;
559 lp->d_ncylinders = pdg->pdg_ncylinders;
560 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
561
562 strncpy(lp->d_typename, di->di_dkname, sizeof(lp->d_typename));
563 lp->d_type = di->di_dtype;
564 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
565 lp->d_rpm = 3600;
566 lp->d_interleave = 1;
567 lp->d_flags = 0;
568
569 lp->d_partitions[RAW_PART].p_offset = 0;
570 lp->d_partitions[RAW_PART].p_size = dksc->sc_size;
571 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
572 lp->d_npartitions = RAW_PART + 1;
573
574 lp->d_magic = DISKMAGIC;
575 lp->d_magic2 = DISKMAGIC;
576 lp->d_checksum = dkcksum(dksc->sc_dkdev.dk_label);
577 }
578
579 /* ARGSUSED */
580 void
581 dk_getdisklabel(struct dk_intf *di, struct dk_softc *dksc, dev_t dev)
582 {
583 struct disklabel *lp = dksc->sc_dkdev.dk_label;
584 struct cpu_disklabel *clp = dksc->sc_dkdev.dk_cpulabel;
585 struct partition *pp;
586 int i;
587 const char *errstring;
588
589 memset(clp, 0x0, sizeof(*clp));
590 dk_getdefaultlabel(di, dksc, lp);
591 errstring = readdisklabel(DKLABELDEV(dev), di->di_strategy,
592 dksc->sc_dkdev.dk_label, dksc->sc_dkdev.dk_cpulabel);
593 if (errstring) {
594 dk_makedisklabel(di, dksc);
595 if (dksc->sc_flags & DKF_WARNLABEL)
596 printf("%s: %s\n", dksc->sc_xname, errstring);
597 return;
598 }
599
600 if ((dksc->sc_flags & DKF_LABELSANITY) == 0)
601 return;
602
603 /* Sanity check */
604 if (lp->d_secperunit != dksc->sc_size)
605 printf("WARNING: %s: total sector size in disklabel (%d) "
606 "!= the size of %s (%lu)\n", dksc->sc_xname,
607 lp->d_secperunit, di->di_dkname, (u_long)dksc->sc_size);
608
609 for (i=0; i < lp->d_npartitions; i++) {
610 pp = &lp->d_partitions[i];
611 if (pp->p_offset + pp->p_size > dksc->sc_size)
612 printf("WARNING: %s: end of partition `%c' exceeds "
613 "the size of %s (%lu)\n", dksc->sc_xname,
614 'a' + i, di->di_dkname, (u_long)dksc->sc_size);
615 }
616 }
617
618 /* ARGSUSED */
619 static void
620 dk_makedisklabel(struct dk_intf *di, struct dk_softc *dksc)
621 {
622 struct disklabel *lp = dksc->sc_dkdev.dk_label;
623
624 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
625 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
626 lp->d_checksum = dkcksum(lp);
627 }
628
629 void
630 dk_set_properties(struct dk_intf *di, struct dk_softc *dksc)
631 {
632 prop_dictionary_t disk_info, odisk_info, geom;
633
634 disk_info = prop_dictionary_create();
635
636 geom = prop_dictionary_create();
637
638 prop_dictionary_set_uint64(geom, "sectors-per-unit",
639 dksc->sc_geom.pdg_nsectors * dksc->sc_geom.pdg_ntracks *
640 dksc->sc_geom.pdg_ncylinders);
641
642 prop_dictionary_set_uint32(geom, "sector-size",
643 dksc->sc_geom.pdg_secsize);
644
645 prop_dictionary_set_uint16(geom, "sectors-per-track",
646 dksc->sc_geom.pdg_nsectors);
647
648 prop_dictionary_set_uint16(geom, "tracks-per-cylinder",
649 dksc->sc_geom.pdg_ntracks);
650
651 prop_dictionary_set_uint64(geom, "cylinders-per-unit",
652 dksc->sc_geom.pdg_ncylinders);
653
654 prop_dictionary_set(disk_info, "geometry", geom);
655 prop_object_release(geom);
656
657 prop_dictionary_set(device_properties(dksc->sc_dev),
658 "disk-info", disk_info);
659
660 /*
661 * Don't release disk_info here; we keep a reference to it.
662 * disk_detach() will release it when we go away.
663 */
664
665 odisk_info = dksc->sc_dkdev.dk_info;
666 dksc->sc_dkdev.dk_info = disk_info;
667 if (odisk_info)
668 prop_object_release(odisk_info);
669 }
670
671 /* This function is taken from ccd.c:1.76 --rcd */
672
673 /*
674 * XXX this function looks too generic for dksubr.c, shouldn't we
675 * put it somewhere better?
676 */
677
678 /*
679 * Lookup the provided name in the filesystem. If the file exists,
680 * is a valid block device, and isn't being used by anyone else,
681 * set *vpp to the file's vnode.
682 */
683 int
684 dk_lookup(struct pathbuf *pb, struct lwp *l, struct vnode **vpp)
685 {
686 struct nameidata nd;
687 struct vnode *vp;
688 struct vattr va;
689 int error;
690
691 if (l == NULL)
692 return ESRCH; /* Is ESRCH the best choice? */
693
694 NDINIT(&nd, LOOKUP, FOLLOW, pb);
695 if ((error = vn_open(&nd, FREAD | FWRITE, 0)) != 0) {
696 DPRINTF((DKDB_FOLLOW|DKDB_INIT),
697 ("dk_lookup: vn_open error = %d\n", error));
698 return error;
699 }
700
701 vp = nd.ni_vp;
702 if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0) {
703 DPRINTF((DKDB_FOLLOW|DKDB_INIT),
704 ("dk_lookup: getattr error = %d\n", error));
705 goto out;
706 }
707
708 /* XXX: eventually we should handle VREG, too. */
709 if (va.va_type != VBLK) {
710 error = ENOTBLK;
711 goto out;
712 }
713
714 IFDEBUG(DKDB_VNODE, vprint("dk_lookup: vnode info", vp));
715
716 VOP_UNLOCK(vp);
717 *vpp = vp;
718 return 0;
719 out:
720 VOP_UNLOCK(vp);
721 (void) vn_close(vp, FREAD | FWRITE, l->l_cred);
722 return error;
723 }
724