]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/vn/vn.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / dev / vn / vn.c
CommitLineData
91447636 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
91447636 5 *
8ad349bb
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
91447636 29 */
9bccf70c
A
30
31/*
32 * Copyright (c) 1988 University of Utah.
33 * Copyright (c) 1990, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * the Systems Programming Group of the University of Utah Computer
38 * Science Department.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * from: Utah Hdr: vn.c 1.13 94/04/02
69 *
70 * from: @(#)vn.c 8.6 (Berkeley) 4/1/94
71 * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $
72 */
73
74/*
75 * Vnode disk driver.
76 *
77 * Block/character interface to a vnode. Allows one to treat a file
78 * as a disk (e.g. build a filesystem in it, mount it, etc.).
79 *
91447636 80 * NOTE 1: This uses the vnop_blockmap/vnop_strategy interface to the vnode
9bccf70c
A
81 * instead of a simple VOP_RDWR. We do this to avoid distorting the
82 * local buffer cache.
83 *
84 * NOTE 2: There is a security issue involved with this driver.
85 * Once mounted all access to the contents of the "mapped" file via
86 * the special file is controlled by the permissions on the special
87 * file, the protection of the mapped file is ignored (effectively,
88 * by using root credentials in all transactions).
89 *
90 * NOTE 3: Doesn't interact with leases, should it?
91 */
92
93#include "vndevice.h"
94
95#if NVNDEVICE > 0
96
97#include <sys/param.h>
98#include <sys/systm.h>
99#include <sys/kernel.h>
100#include <sys/mount.h>
101#include <sys/namei.h>
102#include <sys/proc.h>
91447636 103#include <sys/kauth.h>
9bccf70c
A
104#include <sys/buf.h>
105#include <sys/malloc.h>
91447636 106#include <sys/vnode_internal.h>
9bccf70c
A
107#include <sys/fcntl.h>
108#include <sys/conf.h>
55e303ae 109#include <sys/disk.h>
9bccf70c
A
110#include <sys/stat.h>
111#include <sys/conf.h>
91447636 112#include <sys/uio_internal.h>
9bccf70c
A
113
114#include <sys/vnioctl.h>
115
116#include <sys/vm.h>
117
118#include <vm/vm_pager.h>
9bccf70c
A
119#include <mach/memory_object_types.h>
120
121#include <miscfs/devfs/devfs.h>
122
55e303ae 123
9bccf70c
A
124#include "shadow.h"
125
126static ioctl_fcn_t vnioctl_chr;
127static ioctl_fcn_t vnioctl_blk;
128static open_close_fcn_t vnopen;
129static open_close_fcn_t vnclose;
130static psize_fcn_t vnsize;
131static strategy_fcn_t vnstrategy;
132static read_write_fcn_t vnread;
133static read_write_fcn_t vnwrite;
134
135static int vndevice_bdev_major;
136static int vndevice_cdev_major;
137
138/*
139 * cdevsw
140 * D_DISK we want to look like a disk
141 * D_CANFREE We support B_FREEBUF
142 */
143
144static struct bdevsw vn_bdevsw = {
145 /* open */ vnopen,
146 /* close */ vnclose,
147 /* strategy */ vnstrategy,
148 /* ioctl */ vnioctl_blk,
149 /* dump */ eno_dump,
150 /* psize */ vnsize,
151 /* flags */ D_DISK,
152};
153
154static struct cdevsw vn_cdevsw = {
155 /* open */ vnopen,
156 /* close */ vnclose,
157 /* read */ vnread,
158 /* write */ vnwrite,
159 /* ioctl */ vnioctl_chr,
160 /* stop */ eno_stop,
161 /* reset */ eno_reset,
162 /* ttys */ 0,
163 /* select */ eno_select,
164 /* mmap */ eno_mmap,
165 /* strategy */ eno_strat,
166 /* getc */ eno_getc,
167 /* putc */ eno_putc,
168 /* flags */ D_DISK,
169};
170
171struct vn_softc {
172 u_int64_t sc_fsize; /* file size in bytes */
173 u_int64_t sc_size; /* size of vn, sc_secsize scale */
174 int sc_flags; /* flags */
91447636 175 u_long sc_secsize; /* sector size */
9bccf70c 176 struct vnode *sc_vp; /* vnode if not NULL */
91447636 177 uint32_t sc_vid;
9bccf70c
A
178 int sc_open_flags;
179 struct vnode *sc_shadow_vp; /* shadow vnode if not NULL */
91447636 180 uint32_t sc_shadow_vid;
9bccf70c 181 shadow_map_t * sc_shadow_map; /* shadow map if not NULL */
91447636
A
182 kauth_cred_t sc_cred; /* credentials */
183 u_int32_t sc_options; /* options */
9bccf70c
A
184 void * sc_bdev;
185 void * sc_cdev;
186} vn_table[NVNDEVICE];
187
188#define ROOT_IMAGE_UNIT 0
189
190/* sc_flags */
191#define VNF_INITED 0x01
192#define VNF_READONLY 0x02
193
91447636 194static u_int32_t vn_options;
9bccf70c
A
195
196#define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt))
197#define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt))
198
91447636
A
199static int setcred(struct vnode * vp, struct proc * p,
200 kauth_cred_t cred);
201static void vnclear (struct vn_softc *vn, struct proc * p);
202static void vn_ioctl_to_64(struct vn_ioctl *from, struct user_vn_ioctl *to);
203void vndevice_init(void);
204int vndevice_root_image(char * path, char devname[], dev_t * dev_p);
9bccf70c
A
205
206static int
207vniocattach_file(struct vn_softc *vn,
91447636 208 struct user_vn_ioctl *vniop,
9bccf70c
A
209 dev_t dev,
210 int in_kernel,
211 struct proc *p);
212static int
213vniocattach_shadow(struct vn_softc * vn,
91447636 214 struct user_vn_ioctl *vniop,
9bccf70c
A
215 dev_t dev,
216 int in_kernel,
217 struct proc *p);
91447636 218static __inline__ int
9bccf70c
A
219vnunit(dev_t dev)
220{
221 return (minor(dev));
222}
223
224static int
91447636
A
225vnclose(__unused dev_t dev, __unused int flags,
226 __unused int devtype, __unused struct proc *p)
9bccf70c
A
227{
228 return (0);
229}
230
231static int
91447636 232vnopen(dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
9bccf70c
A
233{
234 struct vn_softc *vn;
235 int unit;
236
237 unit = vnunit(dev);
238 if (vnunit(dev) >= NVNDEVICE) {
239 return (ENXIO);
240 }
241 vn = vn_table + unit;
242 if ((flags & FWRITE) && (vn->sc_flags & VNF_READONLY))
243 return (EACCES);
244
245 return(0);
246}
247
91447636
A
248static int
249file_io(struct vnode * vp, struct vfs_context * context_p,
250 enum uio_rw op, char * base, off_t offset, user_ssize_t count,
251 user_ssize_t * resid)
252{
253 uio_t auio;
254 int error;
255 char uio_buf[UIO_SIZEOF(1)];
256
257 auio = uio_createwithbuffer(1, offset, UIO_SYSSPACE, op,
258 &uio_buf[0], sizeof(uio_buf));
259 uio_addiov(auio, CAST_USER_ADDR_T(base), count);
260 if (op == UIO_READ)
261 error = VNOP_READ(vp, auio, IO_SYNC, context_p);
262 else
263 error = VNOP_WRITE(vp, auio, IO_SYNC, context_p);
264
265 if (resid != NULL) {
266 *resid = uio_resid(auio);
267 }
268 return (error);
269}
270
271static __inline__ off_t
272block_round(off_t o, int blocksize)
273{
274 return ((o + blocksize - 1) / blocksize);
275}
276
277static __inline__ off_t
278block_truncate(off_t o, int blocksize)
279{
280 return (o / blocksize);
281}
282
283static __inline__ int
284block_remainder(off_t o, int blocksize)
285{
286 return (o % blocksize);
287}
288
289static int
290vnread_shadow(struct vn_softc * vn, struct uio *uio, int ioflag,
291 struct vfs_context * context_p)
292{
293 u_long blocksize = vn->sc_secsize;
294 int error = 0;
295 off_t offset;
296 user_ssize_t resid;
297 off_t orig_offset;
298 user_ssize_t orig_resid;
299
300 orig_resid = resid = uio_resid(uio);
301 orig_offset = offset = uio_offset(uio);
302
303 while (resid > 0) {
304 u_long remainder;
305 u_long this_block_number;
306 u_long this_block_count;
307 off_t this_offset;
308 user_ssize_t this_resid;
309 struct vnode * vp;
310
311 /* figure out which blocks to read */
312 remainder = block_remainder(offset, blocksize);
313 if (shadow_map_read(vn->sc_shadow_map,
314 block_truncate(offset, blocksize),
315 block_round(resid + remainder, blocksize),
316 &this_block_number, &this_block_count)) {
317 vp = vn->sc_shadow_vp;
318 }
319 else {
320 vp = vn->sc_vp;
321 }
322
323 /* read the blocks (or parts thereof) */
324 this_offset = (off_t)this_block_number * blocksize + remainder;
325 uio_setoffset(uio, this_offset);
326 this_resid = this_block_count * blocksize - remainder;
327 if (this_resid > resid) {
328 this_resid = resid;
329 }
330 uio_setresid(uio, this_resid);
331 error = VNOP_READ(vp, uio, ioflag, context_p);
332 if (error) {
333 break;
334 }
335
336 /* figure out how much we actually read */
337 this_resid -= uio_resid(uio);
338 if (this_resid == 0) {
339 printf("vn device: vnread_shadow zero length read\n");
340 break;
341 }
342 resid -= this_resid;
343 offset += this_resid;
344 }
345 uio_setresid(uio, resid);
346 uio_setoffset(uio, offset);
347 return (error);
348}
349
350static int
351vncopy_block_to_shadow(struct vn_softc * vn, struct vfs_context * context_p,
352 u_long file_block, u_long shadow_block)
353{
354 int error;
355 char * tmpbuf;
356
357 tmpbuf = _MALLOC(vn->sc_secsize, M_TEMP, M_WAITOK);
358 if (tmpbuf == NULL) {
359 return (ENOMEM);
360 }
361 /* read one block from file at file_block offset */
362 error = file_io(vn->sc_vp, context_p, UIO_READ,
363 tmpbuf, (off_t)file_block * vn->sc_secsize,
364 vn->sc_secsize, NULL);
365 if (error) {
366 goto done;
367 }
368 /* write one block to shadow file at shadow_block offset */
369 error = file_io(vn->sc_shadow_vp, context_p, UIO_WRITE,
370 tmpbuf, (off_t)shadow_block * vn->sc_secsize,
371 vn->sc_secsize, NULL);
372 done:
373 FREE(tmpbuf, M_TEMP);
374 return (error);
375}
376
377enum {
378 FLAGS_FIRST_BLOCK_PARTIAL = 0x1,
379 FLAGS_LAST_BLOCK_PARTIAL = 0x2
380};
381
382static int
383vnwrite_shadow(struct vn_softc * vn, struct uio *uio, int ioflag,
384 struct vfs_context * context_p)
385{
386 u_long blocksize = vn->sc_secsize;
387 int error = 0;
388 user_ssize_t resid;
389 off_t offset;
390
391 resid = uio_resid(uio);
392 offset = uio_offset(uio);
393
394 while (resid > 0) {
395 int flags = 0;
396 u_long offset_block_number;
397 u_long remainder;
398 u_long resid_block_count;
399 u_long shadow_block_count;
400 u_long shadow_block_number;
401 user_ssize_t this_resid;
402
403 /* figure out which blocks to write */
404 offset_block_number = block_truncate(offset, blocksize);
405 remainder = block_remainder(offset, blocksize);
406 resid_block_count = block_round(resid + remainder, blocksize);
407 /* figure out if the first or last blocks are partial writes */
408 if (remainder > 0
409 && !shadow_map_is_written(vn->sc_shadow_map,
410 offset_block_number)) {
411 /* the first block is a partial write */
412 flags |= FLAGS_FIRST_BLOCK_PARTIAL;
413 }
414 if (resid_block_count > 1
415 && !shadow_map_is_written(vn->sc_shadow_map,
416 offset_block_number
417 + resid_block_count - 1)
418 && block_remainder(offset + resid, blocksize) > 0) {
419 /* the last block is a partial write */
420 flags |= FLAGS_LAST_BLOCK_PARTIAL;
421 }
422 if (shadow_map_write(vn->sc_shadow_map,
423 offset_block_number, resid_block_count,
424 &shadow_block_number,
425 &shadow_block_count)) {
426 /* shadow file is growing */
427#if 0
428 /* truncate the file to its new length before write */
429 off_t size;
430 size = (off_t)shadow_map_shadow_size(vn->sc_shadow_map)
431 * vn->sc_secsize;
432 vnode_setsize(vn->sc_shadow_vp, size, IO_SYNC,
433 context_p);
434#endif 0
435 }
436 /* write the blocks (or parts thereof) */
437 uio_setoffset(uio, (off_t)
438 shadow_block_number * blocksize + remainder);
439 this_resid = (off_t)shadow_block_count * blocksize - remainder;
440 if (this_resid >= resid) {
441 this_resid = resid;
442 if ((flags & FLAGS_LAST_BLOCK_PARTIAL) != 0) {
443 /* copy the last block to the shadow */
444 u_long d;
445 u_long s;
446
447 s = offset_block_number
448 + resid_block_count - 1;
449 d = shadow_block_number
450 + shadow_block_count - 1;
451 error = vncopy_block_to_shadow(vn, context_p,
452 s, d);
453 if (error) {
454 printf("vnwrite_shadow: failed to copy"
455 " block %d to shadow block %d\n",
456 s, d);
457 break;
458 }
459 }
460 }
461 uio_setresid(uio, this_resid);
462 if ((flags & FLAGS_FIRST_BLOCK_PARTIAL) != 0) {
463 /* copy the first block to the shadow */
464 error = vncopy_block_to_shadow(vn, context_p,
465 offset_block_number,
466 shadow_block_number);
467 if (error) {
468 printf("vnwrite_shadow: failed to"
469 " copy block %d to shadow block %d\n",
470 offset_block_number,
471 shadow_block_number);
472 break;
473 }
474 }
475 error = VNOP_WRITE(vn->sc_shadow_vp, uio, ioflag, context_p);
476 if (error) {
477 break;
478 }
479 /* figure out how much we actually wrote */
480 this_resid -= uio_resid(uio);
481 if (this_resid == 0) {
482 printf("vn device: vnwrite_shadow zero length write\n");
483 break;
484 }
485 resid -= this_resid;
486 offset += this_resid;
487 }
488 uio_setresid(uio, resid);
489 uio_setoffset(uio, offset);
490 return (error);
491}
492
9bccf70c
A
493static int
494vnread(dev_t dev, struct uio *uio, int ioflag)
495{
91447636
A
496 struct vfs_context context;
497 int error = 0;
498 boolean_t funnel_state;
499 off_t offset;
500 struct proc * p;
501 user_ssize_t resid;
9bccf70c
A
502 struct vn_softc * vn;
503 int unit;
504
505 unit = vnunit(dev);
506 if (vnunit(dev) >= NVNDEVICE) {
507 return (ENXIO);
508 }
91447636
A
509 p = current_proc();
510 funnel_state = thread_funnel_set(kernel_flock, TRUE);
9bccf70c
A
511 vn = vn_table + unit;
512 if ((vn->sc_flags & VNF_INITED) == 0) {
91447636
A
513 error = ENXIO;
514 goto done;
9bccf70c 515 }
91447636
A
516 error = vnode_getwithvid(vn->sc_vp, vn->sc_vid);
517 if (error != 0) {
518 /* the vnode is no longer available, abort */
519 error = ENXIO;
520 vnclear(vn, p);
521 goto done;
522 }
523
524 resid = uio_resid(uio);
525 offset = uio_offset(uio);
526
527 /*
528 * If out of bounds return an error. If at the EOF point,
529 * simply read less.
530 */
531 if (offset >= (off_t)vn->sc_fsize) {
532 if (offset > (off_t)vn->sc_fsize) {
533 error = EINVAL;
534 }
535 goto done;
536 }
537 /*
538 * If the request crosses EOF, truncate the request.
539 */
540 if ((offset + resid) > (off_t)vn->sc_fsize) {
541 resid = vn->sc_fsize - offset;
542 uio_setresid(uio, resid);
9bccf70c 543 }
9bccf70c 544
91447636
A
545 context.vc_proc = p;
546 context.vc_ucred = vn->sc_cred;
547 if (vn->sc_shadow_vp != NULL) {
548 error = vnode_getwithvid(vn->sc_shadow_vp,
549 vn->sc_shadow_vid);
550 if (error != 0) {
551 /* the vnode is no longer available, abort */
552 error = ENXIO;
553 vnode_put(vn->sc_vp);
554 vnclear(vn, p);
555 goto done;
556 }
557 error = vnread_shadow(vn, uio, ioflag, &context);
558 vnode_put(vn->sc_shadow_vp);
559 } else {
560 error = VNOP_READ(vn->sc_vp, uio, ioflag, &context);
561 }
562 vnode_put(vn->sc_vp);
563 done:
564 (void) thread_funnel_set(kernel_flock, funnel_state);
565 return (error);
9bccf70c
A
566}
567
568static int
569vnwrite(dev_t dev, struct uio *uio, int ioflag)
570{
91447636
A
571 struct vfs_context context;
572 int error;
573 boolean_t funnel_state;
574 off_t offset;
575 struct proc * p;
576 user_ssize_t resid;
9bccf70c
A
577 struct vn_softc * vn;
578 int unit;
579
580 unit = vnunit(dev);
581 if (vnunit(dev) >= NVNDEVICE) {
582 return (ENXIO);
583 }
91447636
A
584 p = current_proc();
585 funnel_state = thread_funnel_set(kernel_flock, TRUE);
9bccf70c
A
586 vn = vn_table + unit;
587 if ((vn->sc_flags & VNF_INITED) == 0) {
91447636
A
588 error = ENXIO;
589 goto done;
9bccf70c
A
590 }
591 if (vn->sc_flags & VNF_READONLY) {
91447636
A
592 error = EROFS;
593 goto done;
9bccf70c 594 }
91447636
A
595 error = vnode_getwithvid(vn->sc_vp, vn->sc_vid);
596 if (error != 0) {
597 /* the vnode is no longer available, abort */
598 error = ENXIO;
599 vnclear(vn, p);
600 goto done;
601 }
602 resid = uio_resid(uio);
603 offset = uio_offset(uio);
9bccf70c 604
91447636
A
605 /*
606 * If out of bounds return an error. If at the EOF point,
607 * simply write less.
608 */
609 if (offset >= (off_t)vn->sc_fsize) {
610 if (offset > (off_t)vn->sc_fsize) {
611 error = EINVAL;
612 }
613 goto done;
614 }
615 /*
616 * If the request crosses EOF, truncate the request.
617 */
618 if ((offset + resid) > (off_t)vn->sc_fsize) {
619 resid = (off_t)vn->sc_fsize - offset;
620 uio_setresid(uio, resid);
621 }
9bccf70c 622
91447636
A
623 context.vc_proc = p;
624 context.vc_ucred = vn->sc_cred;
9bccf70c 625
91447636
A
626 if (vn->sc_shadow_vp != NULL) {
627 error = vnode_getwithvid(vn->sc_shadow_vp,
628 vn->sc_shadow_vid);
629 if (error != 0) {
630 /* the vnode is no longer available, abort */
631 error = ENXIO;
632 vnode_put(vn->sc_vp);
633 vnclear(vn, p);
634 goto done;
9bccf70c 635 }
91447636
A
636 error = vnwrite_shadow(vn, uio, ioflag, &context);
637 vnode_put(vn->sc_shadow_vp);
638 } else {
639 error = VNOP_WRITE(vn->sc_vp, uio, ioflag, &context);
9bccf70c 640 }
91447636
A
641 vnode_put(vn->sc_vp);
642 done:
643 (void) thread_funnel_set(kernel_flock, funnel_state);
9bccf70c
A
644 return (error);
645}
646
647static int
648shadow_read(struct vn_softc * vn, struct buf * bp, char * base, struct proc * p)
649{
91447636
A
650 u_long blocksize = vn->sc_secsize;
651 struct vfs_context context;
9bccf70c
A
652 int error = 0;
653 u_long offset;
654 boolean_t read_shadow;
655 u_long resid;
656 u_long start = 0;
657
91447636
A
658 context.vc_proc = p;
659 context.vc_ucred = vn->sc_cred;
660 offset = buf_blkno(bp);
661 resid = buf_resid(bp) / blocksize;
9bccf70c 662 while (resid > 0) {
91447636 663 user_ssize_t temp_resid;
9bccf70c
A
664 u_long this_offset;
665 u_long this_resid;
666 struct vnode * vp;
667
668 read_shadow = shadow_map_read(vn->sc_shadow_map,
669 offset, resid,
670 &this_offset, &this_resid);
671 if (read_shadow) {
672 vp = vn->sc_shadow_vp;
673 }
674 else {
675 vp = vn->sc_vp;
676 }
91447636
A
677 error = file_io(vp, &context, UIO_READ, base + start,
678 (off_t)this_offset * blocksize,
679 (user_ssize_t)this_resid * blocksize,
680 &temp_resid);
681 if (error) {
9bccf70c 682 break;
91447636
A
683 }
684 this_resid -= (temp_resid / blocksize);
685 if (this_resid == 0) {
686 printf("vn device: shadow_read zero length read\n");
9bccf70c
A
687 break;
688 }
91447636
A
689 resid -= this_resid;
690 offset += this_resid;
691 start += this_resid * blocksize;
9bccf70c 692 }
91447636 693 buf_setresid(bp, resid * blocksize);
9bccf70c
A
694 return (error);
695}
696
697static int
698shadow_write(struct vn_softc * vn, struct buf * bp, char * base,
699 struct proc * p)
700{
91447636
A
701 u_long blocksize = vn->sc_secsize;
702 struct vfs_context context;
9bccf70c
A
703 int error = 0;
704 u_long offset;
705 boolean_t shadow_grew;
706 u_long resid;
707 u_long start = 0;
708
91447636
A
709 context.vc_proc = p;
710 context.vc_ucred = vn->sc_cred;
711 offset = buf_blkno(bp);
712 resid = buf_resid(bp) / blocksize;
9bccf70c 713 while (resid > 0) {
91447636 714 user_ssize_t temp_resid;
9bccf70c
A
715 u_long this_offset;
716 u_long this_resid;
9bccf70c
A
717
718 shadow_grew = shadow_map_write(vn->sc_shadow_map,
719 offset, resid,
720 &this_offset, &this_resid);
721 if (shadow_grew) {
722#if 0
723 off_t size;
724 /* truncate the file to its new length before write */
725 size = (off_t)shadow_map_shadow_size(vn->sc_shadow_map)
91447636
A
726 * blocksize;
727 vnode_setsize(vn->sc_shadow_vp, size, IO_SYNC,
728 &context);
55e303ae 729#endif
9bccf70c 730 }
91447636 731 error = file_io(vn->sc_shadow_vp, &context, UIO_WRITE,
9bccf70c 732 base + start,
91447636
A
733 (off_t)this_offset * blocksize,
734 (user_ssize_t)this_resid * blocksize,
735 &temp_resid);
9bccf70c
A
736 if (error) {
737 break;
738 }
91447636
A
739 this_resid -= (temp_resid / blocksize);
740 if (this_resid == 0) {
741 printf("vn device: shadow_write zero length write\n");
9bccf70c
A
742 break;
743 }
91447636
A
744 resid -= this_resid;
745 offset += this_resid;
746 start += this_resid * blocksize;
9bccf70c 747 }
91447636 748 buf_setresid(bp, resid * blocksize);
9bccf70c
A
749 return (error);
750}
751
752static int
91447636 753vn_readwrite_io(struct vn_softc * vn, struct buf * bp, struct proc * p)
9bccf70c
A
754{
755 int error = 0;
756 char * iov_base;
91447636 757 caddr_t vaddr;
9bccf70c 758
9bccf70c 759
91447636
A
760 if (buf_map(bp, &vaddr))
761 panic("vn device: buf_map failed");
762 iov_base = (char *)vaddr;
763
9bccf70c 764 if (vn->sc_shadow_vp == NULL) {
91447636
A
765 struct vfs_context context;
766 user_ssize_t temp_resid;
767
768 context.vc_proc = p;
769 context.vc_ucred = vn->sc_cred;
770
771 error = file_io(vn->sc_vp, &context,
772 buf_flags(bp) & B_READ ? UIO_READ : UIO_WRITE,
773 iov_base,
774 (off_t)buf_blkno(bp) * vn->sc_secsize,
775 buf_resid(bp), &temp_resid);
776 buf_setresid(bp, temp_resid);
9bccf70c
A
777 }
778 else {
91447636 779 if (buf_flags(bp) & B_READ)
9bccf70c
A
780 error = shadow_read(vn, bp, iov_base, p);
781 else
782 error = shadow_write(vn, bp, iov_base, p);
9bccf70c 783 }
91447636
A
784 buf_unmap(bp);
785
9bccf70c
A
786 return (error);
787}
788
789static void
790vnstrategy(struct buf *bp)
791{
792 struct vn_softc *vn;
793 int error = 0;
794 long sz; /* in sc_secsize chunks */
91447636
A
795 daddr64_t blk_num;
796 boolean_t funnel_state;
797 struct proc * p = current_proc();
798 struct vnode * shadow_vp = NULL;
799 struct vnode * vp = NULL;
9bccf70c 800
91447636
A
801 funnel_state = thread_funnel_set(kernel_flock, TRUE);
802 vn = vn_table + vnunit(buf_device(bp));
9bccf70c 803 if ((vn->sc_flags & VNF_INITED) == 0) {
91447636
A
804 error = ENXIO;
805 goto done;
9bccf70c
A
806 }
807
91447636 808 buf_setresid(bp, buf_count(bp));
9bccf70c
A
809 /*
810 * Check for required alignment. Transfers must be a valid
811 * multiple of the sector size.
812 */
91447636
A
813 blk_num = buf_blkno(bp);
814 if (buf_count(bp) % vn->sc_secsize != 0) {
815 error = EINVAL;
816 goto done;
9bccf70c 817 }
91447636 818 sz = howmany(buf_count(bp), vn->sc_secsize);
9bccf70c
A
819
820 /*
821 * If out of bounds return an error. If at the EOF point,
822 * simply read or write less.
823 */
91447636
A
824 if (blk_num >= 0 && (u_int64_t)blk_num >= vn->sc_size) {
825 if (blk_num > 0 && (u_int64_t)blk_num > vn->sc_size) {
826 error = EINVAL;
55e303ae 827 }
91447636 828 goto done;
9bccf70c
A
829 }
830 /*
831 * If the request crosses EOF, truncate the request.
832 */
91447636
A
833 if ((blk_num + sz) > 0 && ((u_int64_t)(blk_num + sz)) > vn->sc_size) {
834 buf_setcount(bp, (vn->sc_size - blk_num) * vn->sc_secsize);
835 buf_setresid(bp, buf_count(bp));
9bccf70c 836 }
91447636
A
837 vp = vn->sc_vp;
838 if (vp == NULL) {
839 error = ENXIO;
840 goto done;
841 }
842 error = vnode_getwithvid(vp, vn->sc_vid);
843 if (error != 0) {
844 /* the vnode is no longer available, abort */
845 error = ENXIO;
846 vnclear(vn, p);
847 goto done;
848 }
849 shadow_vp = vn->sc_shadow_vp;
850 if (shadow_vp != NULL) {
851 error = vnode_getwithvid(shadow_vp,
852 vn->sc_shadow_vid);
853 if (error != 0) {
854 /* the vnode is no longer available, abort */
855 error = ENXIO;
856 vnode_put(vn->sc_vp);
857 vnclear(vn, p);
858 goto done;
9bccf70c 859 }
9bccf70c 860 }
91447636
A
861 error = vn_readwrite_io(vn, bp, p);
862 vnode_put(vp);
863 if (shadow_vp != NULL) {
864 vnode_put(shadow_vp);
9bccf70c 865 }
91447636
A
866
867 done:
868 (void) thread_funnel_set(kernel_flock, funnel_state);
869 if (error) {
870 buf_seterror(bp, error);
871 }
872 buf_biodone(bp);
873 return;
9bccf70c
A
874}
875
876/* ARGSUSED */
877static int
91447636
A
878vnioctl(dev_t dev, u_long cmd, caddr_t data,
879 __unused int flag, struct proc *p,
9bccf70c
A
880 int is_char)
881{
882 struct vn_softc *vn;
91447636 883 struct user_vn_ioctl *viop;
9bccf70c 884 int error;
91447636 885 u_int32_t *f;
9bccf70c
A
886 u_int64_t * o;
887 int unit;
91447636
A
888 struct vfsioattr ioattr;
889 struct user_vn_ioctl user_vnio;
890 boolean_t funnel_state;
9bccf70c
A
891
892 unit = vnunit(dev);
893 if (vnunit(dev) >= NVNDEVICE) {
894 return (ENXIO);
895 }
91447636
A
896
897 funnel_state = thread_funnel_set(kernel_flock, TRUE);
9bccf70c 898 vn = vn_table + unit;
91447636
A
899 error = proc_suser(p);
900 if (error) {
901 goto done;
902 }
9bccf70c 903
91447636
A
904 viop = (struct user_vn_ioctl *)data;
905 f = (u_int32_t *)data;
9bccf70c
A
906 o = (u_int64_t *)data;
907 switch (cmd) {
908 case VNIOCDETACH:
91447636 909 case VNIOCDETACH64:
55e303ae 910 case DKIOCGETBLOCKSIZE:
91447636 911 case DKIOCSETBLOCKSIZE:
9bccf70c
A
912 case DKIOCGETMAXBLOCKCOUNTREAD:
913 case DKIOCGETMAXBLOCKCOUNTWRITE:
914 case DKIOCGETMAXSEGMENTCOUNTREAD:
915 case DKIOCGETMAXSEGMENTCOUNTWRITE:
55e303ae
A
916 case DKIOCGETMAXSEGMENTBYTECOUNTREAD:
917 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE:
918 case DKIOCGETBLOCKCOUNT:
9bccf70c
A
919 case DKIOCGETBLOCKCOUNT32:
920 if ((vn->sc_flags & VNF_INITED) == 0) {
91447636
A
921 error = ENXIO;
922 goto done;
9bccf70c
A
923 }
924 break;
925 default:
926 break;
927 }
91447636
A
928
929 if (vn->sc_vp != NULL)
930 vfs_ioattr(vnode_mount(vn->sc_vp), &ioattr);
931 else
932 bzero(&ioattr, sizeof(ioattr));
933
9bccf70c 934 switch (cmd) {
91447636
A
935 case DKIOCISVIRTUAL:
936 *f = 1;
937 break;
9bccf70c 938 case DKIOCGETMAXBLOCKCOUNTREAD:
91447636 939 *o = ioattr.io_maxreadcnt / vn->sc_secsize;
9bccf70c
A
940 break;
941 case DKIOCGETMAXBLOCKCOUNTWRITE:
91447636 942 *o = ioattr.io_maxwritecnt / vn->sc_secsize;
55e303ae
A
943 break;
944 case DKIOCGETMAXBYTECOUNTREAD:
91447636 945 *o = ioattr.io_maxreadcnt;
55e303ae
A
946 break;
947 case DKIOCGETMAXBYTECOUNTWRITE:
91447636 948 *o = ioattr.io_maxwritecnt;
9bccf70c
A
949 break;
950 case DKIOCGETMAXSEGMENTCOUNTREAD:
91447636 951 *o = ioattr.io_segreadcnt;
9bccf70c
A
952 break;
953 case DKIOCGETMAXSEGMENTCOUNTWRITE:
91447636 954 *o = ioattr.io_segwritecnt;
55e303ae
A
955 break;
956 case DKIOCGETMAXSEGMENTBYTECOUNTREAD:
91447636 957 *o = ioattr.io_maxsegreadsize;
55e303ae
A
958 break;
959 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE:
91447636 960 *o = ioattr.io_maxsegwritesize;
9bccf70c 961 break;
91447636
A
962 case DKIOCGETBLOCKSIZE:
963 *f = vn->sc_secsize;
9bccf70c 964 break;
91447636 965 case DKIOCSETBLOCKSIZE:
9bccf70c
A
966 if (is_char) {
967 /* can only set block size on block device */
91447636
A
968 error = ENODEV;
969 break;
9bccf70c
A
970 }
971 if (*f < DEV_BSIZE) {
91447636
A
972 error = EINVAL;
973 break;
974 }
975 if (vn->sc_shadow_vp != NULL) {
976 if (*f == (unsigned)vn->sc_secsize) {
977 break;
978 }
979 /* can't change the block size if already shadowing */
980 error = EBUSY;
981 break;
9bccf70c
A
982 }
983 vn->sc_secsize = *f;
984 /* recompute the size in terms of the new blocksize */
985 vn->sc_size = vn->sc_fsize / vn->sc_secsize;
986 break;
987 case DKIOCISWRITABLE:
988 *f = 1;
989 break;
990 case DKIOCGETBLOCKCOUNT32:
991 *f = vn->sc_size;
992 break;
55e303ae 993 case DKIOCGETBLOCKCOUNT:
9bccf70c
A
994 *o = vn->sc_size;
995 break;
996 case VNIOCSHADOW:
91447636 997 case VNIOCSHADOW64:
9bccf70c 998 if (vn->sc_shadow_vp != NULL) {
91447636
A
999 error = EBUSY;
1000 break;
9bccf70c
A
1001 }
1002 if (vn->sc_vp == NULL) {
1003 /* much be attached before we can shadow */
91447636
A
1004 error = EINVAL;
1005 break;
1006 }
1007 if (!proc_is64bit(p)) {
1008 /* downstream code expects LP64 version of vn_ioctl structure */
1009 vn_ioctl_to_64((struct vn_ioctl *)viop, &user_vnio);
1010 viop = &user_vnio;
9bccf70c 1011 }
91447636
A
1012 if (viop->vn_file == USER_ADDR_NULL) {
1013 error = EINVAL;
1014 break;
9bccf70c 1015 }
91447636 1016 error = vniocattach_shadow(vn, viop, dev, 0, p);
9bccf70c
A
1017 break;
1018
1019 case VNIOCATTACH:
91447636 1020 case VNIOCATTACH64:
9bccf70c
A
1021 if (is_char) {
1022 /* attach only on block device */
91447636
A
1023 error = ENODEV;
1024 break;
9bccf70c
A
1025 }
1026 if (vn->sc_flags & VNF_INITED) {
91447636
A
1027 error = EBUSY;
1028 break;
1029 }
1030 if (!proc_is64bit(p)) {
1031 /* downstream code expects LP64 version of vn_ioctl structure */
1032 vn_ioctl_to_64((struct vn_ioctl *)viop, &user_vnio);
1033 viop = &user_vnio;
9bccf70c 1034 }
91447636
A
1035 if (viop->vn_file == USER_ADDR_NULL) {
1036 error = EINVAL;
1037 break;
9bccf70c 1038 }
91447636 1039 error = vniocattach_file(vn, viop, dev, 0, p);
9bccf70c
A
1040 break;
1041
1042 case VNIOCDETACH:
91447636 1043 case VNIOCDETACH64:
9bccf70c
A
1044 if (is_char) {
1045 /* detach only on block device */
91447636
A
1046 error = ENODEV;
1047 break;
9bccf70c
A
1048 }
1049 /* Note: spec_open won't open a mounted block device */
1050
1051 /*
1052 * XXX handle i/o in progress. Return EBUSY, or wait, or
1053 * flush the i/o.
1054 * XXX handle multiple opens of the device. Return EBUSY,
1055 * or revoke the fd's.
1056 * How are these problems handled for removable and failing
1057 * hardware devices? (Hint: They are not)
1058 */
91447636 1059 vnclear(vn, p);
9bccf70c
A
1060 break;
1061
1062 case VNIOCGSET:
1063 vn_options |= *f;
1064 *f = vn_options;
1065 break;
1066
1067 case VNIOCGCLEAR:
1068 vn_options &= ~(*f);
1069 *f = vn_options;
1070 break;
1071
1072 case VNIOCUSET:
1073 vn->sc_options |= *f;
1074 *f = vn->sc_options;
1075 break;
1076
1077 case VNIOCUCLEAR:
1078 vn->sc_options &= ~(*f);
1079 *f = vn->sc_options;
1080 break;
1081
1082 default:
1083 error = ENOTTY;
1084 break;
1085 }
91447636
A
1086 done:
1087 (void) thread_funnel_set(kernel_flock, funnel_state);
9bccf70c
A
1088 return(error);
1089}
1090
1091static int
1092vnioctl_chr(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1093{
1094 return (vnioctl(dev, cmd, data, flag, p, TRUE));
1095}
1096
1097static int
1098vnioctl_blk(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1099{
1100 return (vnioctl(dev, cmd, data, flag, p, FALSE));
1101}
1102
1103/*
1104 * vniocattach_file:
1105 *
1106 * Attach a file to a VN partition. Return the size in the vn_size
1107 * field.
1108 */
1109
1110static int
1111vniocattach_file(struct vn_softc *vn,
91447636 1112 struct user_vn_ioctl *vniop,
9bccf70c
A
1113 dev_t dev,
1114 int in_kernel,
1115 struct proc *p)
1116{
91447636
A
1117 dev_t cdev;
1118 struct vfs_context context;
1119 kauth_cred_t cred;
9bccf70c 1120 struct nameidata nd;
91447636 1121 off_t file_size;
9bccf70c 1122 int error, flags;
91447636
A
1123
1124 context.vc_proc = p;
1125 context.vc_ucred = proc_ucred(p);
9bccf70c
A
1126
1127 flags = FREAD|FWRITE;
1128 if (in_kernel) {
91447636 1129 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE32, vniop->vn_file, &context);
9bccf70c
A
1130 }
1131 else {
91447636
A
1132 NDINIT(&nd, LOOKUP, FOLLOW,
1133 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
1134 vniop->vn_file, &context);
9bccf70c 1135 }
91447636 1136 /* vn_open gives both long- and short-term references */
9bccf70c
A
1137 error = vn_open(&nd, flags, 0);
1138 if (error) {
1139 if (error != EACCES && error != EPERM && error != EROFS)
1140 return (error);
1141 flags &= ~FWRITE;
1142 if (in_kernel) {
91447636
A
1143 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE32,
1144 vniop->vn_file, &context);
9bccf70c
A
1145 }
1146 else {
91447636
A
1147 NDINIT(&nd, LOOKUP, FOLLOW,
1148 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
1149 vniop->vn_file, &context);
9bccf70c
A
1150 }
1151 error = vn_open(&nd, flags, 0);
1152 if (error)
1153 return (error);
1154 }
1155 if (nd.ni_vp->v_type != VREG) {
1156 error = EINVAL;
1157 }
9bccf70c 1158 else {
91447636 1159 error = vnode_size(nd.ni_vp, &file_size, &context);
9bccf70c
A
1160 }
1161 if (error != 0) {
91447636
A
1162 (void) vn_close(nd.ni_vp, flags, proc_ucred(p), p);
1163 vnode_put(nd.ni_vp);
9bccf70c
A
1164 return (error);
1165 }
91447636
A
1166 cred = kauth_cred_proc_ref(p);
1167 nd.ni_vp->v_flag |= VNOCACHE_DATA;
1168 error = setcred(nd.ni_vp, p, cred);
9bccf70c 1169 if (error) {
91447636
A
1170 (void)vn_close(nd.ni_vp, flags, proc_ucred(p), p);
1171 vnode_put(nd.ni_vp);
1172 kauth_cred_rele(cred);
9bccf70c
A
1173 return(error);
1174 }
91447636
A
1175 vn->sc_secsize = DEV_BSIZE;
1176 vn->sc_fsize = file_size;
1177 vn->sc_size = file_size / vn->sc_secsize;
1178 vn->sc_vp = nd.ni_vp;
1179 vn->sc_vid = vnode_vid(nd.ni_vp);
1180 vn->sc_open_flags = flags;
1181 vn->sc_cred = cred;
1182 cdev = makedev(vndevice_cdev_major, minor(dev));
1183 vn->sc_cdev = devfs_make_node(cdev, DEVFS_CHAR,
1184 UID_ROOT, GID_OPERATOR,
1185 0600, "rvn%d",
1186 minor(dev));
9bccf70c
A
1187 vn->sc_flags |= VNF_INITED;
1188 if (flags == FREAD)
1189 vn->sc_flags |= VNF_READONLY;
91447636
A
1190 /* lose the short-term reference */
1191 vnode_put(nd.ni_vp);
9bccf70c
A
1192 return(0);
1193}
1194
1195static int
91447636
A
1196vniocattach_shadow(struct vn_softc *vn, struct user_vn_ioctl *vniop,
1197 __unused int dev, int in_kernel, struct proc *p)
9bccf70c 1198{
91447636 1199 struct vfs_context context;
9bccf70c
A
1200 struct nameidata nd;
1201 int error, flags;
1202 shadow_map_t * map;
91447636
A
1203 off_t file_size;
1204
1205 context.vc_proc = p;
1206 context.vc_ucred = proc_ucred(p);
9bccf70c
A
1207
1208 flags = FREAD|FWRITE;
1209 if (in_kernel) {
91447636 1210 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE32, vniop->vn_file, &context);
9bccf70c
A
1211 }
1212 else {
91447636
A
1213 NDINIT(&nd, LOOKUP, FOLLOW,
1214 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
1215 vniop->vn_file, &context);
9bccf70c 1216 }
91447636 1217 /* vn_open gives both long- and short-term references */
9bccf70c
A
1218 error = vn_open(&nd, flags, 0);
1219 if (error) {
1220 /* shadow MUST be writable! */
1221 return (error);
1222 }
91447636
A
1223 if (nd.ni_vp->v_type != VREG
1224 || (error = vnode_size(nd.ni_vp, &file_size, &context))) {
1225 (void)vn_close(nd.ni_vp, flags, proc_ucred(p), p);
1226 vnode_put(nd.ni_vp);
9bccf70c
A
1227 return (error ? error : EINVAL);
1228 }
91447636 1229 map = shadow_map_create(vn->sc_fsize, file_size,
9bccf70c
A
1230 0, vn->sc_secsize);
1231 if (map == NULL) {
91447636
A
1232 (void)vn_close(nd.ni_vp, flags, proc_ucred(p), p);
1233 vnode_put(nd.ni_vp);
9bccf70c
A
1234 vn->sc_shadow_vp = NULL;
1235 return (ENOMEM);
1236 }
91447636
A
1237 vn->sc_shadow_vp = nd.ni_vp;
1238 vn->sc_shadow_vid = vnode_vid(nd.ni_vp);
1239 vn->sc_shadow_vp->v_flag |= VNOCACHE_DATA;
9bccf70c
A
1240 vn->sc_shadow_map = map;
1241 vn->sc_flags &= ~VNF_READONLY; /* we're now read/write */
91447636
A
1242
1243 /* lose the short-term reference */
1244 vnode_put(nd.ni_vp);
9bccf70c
A
1245 return(0);
1246}
1247
1248int
1249vndevice_root_image(char * path, char devname[], dev_t * dev_p)
1250{
1251 int error = 0;
91447636
A
1252 struct vn_softc * vn;
1253 struct user_vn_ioctl vnio;
9bccf70c 1254
91447636
A
1255 vnio.vn_file = CAST_USER_ADDR_T(path);
1256 vnio.vn_size = 0;
9bccf70c
A
1257
1258 vn = vn_table + ROOT_IMAGE_UNIT;
1259 *dev_p = makedev(vndevice_bdev_major,
1260 ROOT_IMAGE_UNIT);
1261 sprintf(devname, "vn%d", ROOT_IMAGE_UNIT);
91447636 1262 error = vniocattach_file(vn, &vnio, *dev_p, 1, current_proc());
9bccf70c
A
1263 return (error);
1264}
1265
1266/*
1267 * Duplicate the current processes' credentials. Since we are called only
1268 * as the result of a SET ioctl and only root can do that, any future access
1269 * to this "disk" is essentially as root. Note that credentials may change
1270 * if some other uid can write directly to the mapped file (NFS).
1271 */
91447636
A
1272static int
1273setcred(struct vnode * vp, struct proc * p, kauth_cred_t cred)
9bccf70c
A
1274{
1275 char *tmpbuf;
1276 int error = 0;
91447636 1277 struct vfs_context context;
9bccf70c
A
1278
1279 /*
1280 * Horrible kludge to establish credentials for NFS XXX.
1281 */
91447636
A
1282 context.vc_proc = p;
1283 context.vc_ucred = cred;
1284 tmpbuf = _MALLOC(DEV_BSIZE, M_TEMP, M_WAITOK);
1285 error = file_io(vp, &context, UIO_READ, tmpbuf, 0, DEV_BSIZE, NULL);
1286 FREE(tmpbuf, M_TEMP);
9bccf70c
A
1287 return (error);
1288}
1289
1290void
91447636 1291vnclear(struct vn_softc *vn, struct proc * p)
9bccf70c 1292{
9bccf70c 1293 if (vn->sc_vp != NULL) {
91447636 1294 /* release long-term reference */
9bccf70c
A
1295 (void)vn_close(vn->sc_vp, vn->sc_open_flags, vn->sc_cred, p);
1296 vn->sc_vp = NULL;
1297 }
1298 if (vn->sc_shadow_vp != NULL) {
91447636 1299 /* release long-term reference */
9bccf70c
A
1300 (void)vn_close(vn->sc_shadow_vp, FREAD | FWRITE,
1301 vn->sc_cred, p);
1302 vn->sc_shadow_vp = NULL;
1303 }
1304 if (vn->sc_shadow_map != NULL) {
1305 shadow_map_free(vn->sc_shadow_map);
1306 vn->sc_shadow_map = NULL;
1307 }
91447636 1308 vn->sc_flags &= ~(VNF_INITED | VNF_READONLY);
9bccf70c 1309 if (vn->sc_cred) {
91447636 1310 kauth_cred_rele(vn->sc_cred);
9bccf70c
A
1311 vn->sc_cred = NULL;
1312 }
1313 vn->sc_size = 0;
1314 vn->sc_fsize = 0;
1315 if (vn->sc_cdev) {
1316 devfs_remove(vn->sc_cdev);
1317 vn->sc_cdev = NULL;
1318 }
1319}
1320
1321static int
1322vnsize(dev_t dev)
1323{
91447636 1324 int secsize;
9bccf70c
A
1325 struct vn_softc *vn;
1326 int unit;
91447636 1327 boolean_t funnel_state;
9bccf70c
A
1328
1329 unit = vnunit(dev);
1330 if (vnunit(dev) >= NVNDEVICE) {
91447636 1331 return (-1);
9bccf70c 1332 }
9bccf70c 1333
91447636
A
1334 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1335 vn = vn_table + unit;
9bccf70c 1336 if ((vn->sc_flags & VNF_INITED) == 0)
91447636
A
1337 secsize = -1;
1338 else
1339 secsize = vn->sc_secsize;
1340 (void) thread_funnel_set(kernel_flock, funnel_state);
1341 return (secsize);
9bccf70c
A
1342}
1343
1344#define CDEV_MAJOR -1
1345#define BDEV_MAJOR -1
1346static int vndevice_inited = 0;
1347
1348void
91447636 1349vndevice_init(void)
9bccf70c
A
1350{
1351 int i;
1352
1353 if (vndevice_inited)
1354 return;
1355 vndevice_bdev_major = bdevsw_add(BDEV_MAJOR, &vn_bdevsw);
1356
1357 if (vndevice_bdev_major < 0) {
1358 printf("vndevice_init: bdevsw_add() returned %d\n",
1359 vndevice_bdev_major);
1360 return;
1361 }
1362 vndevice_cdev_major = cdevsw_add_with_bdev(CDEV_MAJOR, &vn_cdevsw,
1363 vndevice_bdev_major);
1364 if (vndevice_cdev_major < 0) {
1365 printf("vndevice_init: cdevsw_add() returned %d\n",
1366 vndevice_cdev_major);
1367 return;
1368 }
1369 for (i = 0; i < NVNDEVICE; i++) {
1370 dev_t dev = makedev(vndevice_bdev_major, i);
1371 vn_table[i].sc_bdev = devfs_make_node(dev, DEVFS_BLOCK,
1372 UID_ROOT, GID_OPERATOR,
1373 0600, "vn%d",
1374 i);
1375 if (vn_table[i].sc_bdev == NULL)
1376 printf("vninit: devfs_make_node failed!\n");
1377 }
1378}
91447636
A
1379
1380static void
1381vn_ioctl_to_64(struct vn_ioctl *from, struct user_vn_ioctl *to)
1382{
1383 to->vn_file = CAST_USER_ADDR_T(from->vn_file);
1384 to->vn_size = from->vn_size;
1385 to->vn_control = from->vn_control;
1386}
1387
55e303ae 1388#endif /* NVNDEVICE */