2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1988 University of Utah.
25 * Copyright (c) 1990, 1993
26 * The Regents of the University of California. All rights reserved.
28 * This code is derived from software contributed to Berkeley by
29 * the Systems Programming Group of the University of Utah Computer
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * from: Utah Hdr: vn.c 1.13 94/04/02
62 * from: @(#)vn.c 8.6 (Berkeley) 4/1/94
63 * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $
69 * Block/character interface to a vnode. Allows one to treat a file
70 * as a disk (e.g. build a filesystem in it, mount it, etc.).
72 * NOTE 1: This uses the vnop_blockmap/vnop_strategy interface to the vnode
73 * instead of a simple VOP_RDWR. We do this to avoid distorting the
76 * NOTE 2: There is a security issue involved with this driver.
77 * Once mounted all access to the contents of the "mapped" file via
78 * the special file is controlled by the permissions on the special
79 * file, the protection of the mapped file is ignored (effectively,
80 * by using root credentials in all transactions).
82 * NOTE 3: Doesn't interact with leases, should it?
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/kernel.h>
92 #include <sys/mount.h>
93 #include <sys/namei.h>
95 #include <sys/kauth.h>
97 #include <sys/malloc.h>
98 #include <sys/vnode_internal.h>
99 #include <sys/fcntl.h>
100 #include <sys/conf.h>
101 #include <sys/disk.h>
102 #include <sys/stat.h>
103 #include <sys/conf.h>
104 #include <sys/uio_internal.h>
106 #include <sys/vnioctl.h>
110 #include <vm/vm_pager.h>
111 #include <mach/memory_object_types.h>
113 #include <miscfs/devfs/devfs.h>
118 static ioctl_fcn_t vnioctl_chr
;
119 static ioctl_fcn_t vnioctl_blk
;
120 static open_close_fcn_t vnopen
;
121 static open_close_fcn_t vnclose
;
122 static psize_fcn_t vnsize
;
123 static strategy_fcn_t vnstrategy
;
124 static read_write_fcn_t vnread
;
125 static read_write_fcn_t vnwrite
;
127 static int vndevice_bdev_major
;
128 static int vndevice_cdev_major
;
132 * D_DISK we want to look like a disk
133 * D_CANFREE We support B_FREEBUF
136 static struct bdevsw vn_bdevsw
= {
139 /* strategy */ vnstrategy
,
140 /* ioctl */ vnioctl_blk
,
146 static struct cdevsw vn_cdevsw
= {
151 /* ioctl */ vnioctl_chr
,
153 /* reset */ eno_reset
,
155 /* select */ eno_select
,
157 /* strategy */ eno_strat
,
164 u_int64_t sc_fsize
; /* file size in bytes */
165 u_int64_t sc_size
; /* size of vn, sc_secsize scale */
166 int sc_flags
; /* flags */
167 u_long sc_secsize
; /* sector size */
168 struct vnode
*sc_vp
; /* vnode if not NULL */
171 struct vnode
*sc_shadow_vp
; /* shadow vnode if not NULL */
172 uint32_t sc_shadow_vid
;
173 shadow_map_t
* sc_shadow_map
; /* shadow map if not NULL */
174 kauth_cred_t sc_cred
; /* credentials */
175 u_int32_t sc_options
; /* options */
178 } vn_table
[NVNDEVICE
];
180 #define ROOT_IMAGE_UNIT 0
183 #define VNF_INITED 0x01
184 #define VNF_READONLY 0x02
186 static u_int32_t vn_options
;
188 #define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt))
189 #define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt))
191 static int setcred(struct vnode
* vp
, struct proc
* p
,
193 static void vnclear (struct vn_softc
*vn
, struct proc
* p
);
194 static void vn_ioctl_to_64(struct vn_ioctl
*from
, struct user_vn_ioctl
*to
);
195 void vndevice_init(void);
196 int vndevice_root_image(char * path
, char devname
[], dev_t
* dev_p
);
199 vniocattach_file(struct vn_softc
*vn
,
200 struct user_vn_ioctl
*vniop
,
205 vniocattach_shadow(struct vn_softc
* vn
,
206 struct user_vn_ioctl
*vniop
,
210 static __inline__
int
217 vnclose(__unused dev_t dev
, __unused
int flags
,
218 __unused
int devtype
, __unused
struct proc
*p
)
224 vnopen(dev_t dev
, int flags
, __unused
int devtype
, __unused
struct proc
*p
)
230 if (vnunit(dev
) >= NVNDEVICE
) {
233 vn
= vn_table
+ unit
;
234 if ((flags
& FWRITE
) && (vn
->sc_flags
& VNF_READONLY
))
241 file_io(struct vnode
* vp
, struct vfs_context
* context_p
,
242 enum uio_rw op
, char * base
, off_t offset
, user_ssize_t count
,
243 user_ssize_t
* resid
)
247 char uio_buf
[UIO_SIZEOF(1)];
249 auio
= uio_createwithbuffer(1, offset
, UIO_SYSSPACE
, op
,
250 &uio_buf
[0], sizeof(uio_buf
));
251 uio_addiov(auio
, CAST_USER_ADDR_T(base
), count
);
253 error
= VNOP_READ(vp
, auio
, IO_SYNC
, context_p
);
255 error
= VNOP_WRITE(vp
, auio
, IO_SYNC
, context_p
);
258 *resid
= uio_resid(auio
);
263 static __inline__ off_t
264 block_round(off_t o
, int blocksize
)
266 return ((o
+ blocksize
- 1) / blocksize
);
269 static __inline__ off_t
270 block_truncate(off_t o
, int blocksize
)
272 return (o
/ blocksize
);
275 static __inline__
int
276 block_remainder(off_t o
, int blocksize
)
278 return (o
% blocksize
);
282 vnread_shadow(struct vn_softc
* vn
, struct uio
*uio
, int ioflag
,
283 struct vfs_context
* context_p
)
285 u_long blocksize
= vn
->sc_secsize
;
290 user_ssize_t orig_resid
;
292 orig_resid
= resid
= uio_resid(uio
);
293 orig_offset
= offset
= uio_offset(uio
);
297 u_long this_block_number
;
298 u_long this_block_count
;
300 user_ssize_t this_resid
;
303 /* figure out which blocks to read */
304 remainder
= block_remainder(offset
, blocksize
);
305 if (shadow_map_read(vn
->sc_shadow_map
,
306 block_truncate(offset
, blocksize
),
307 block_round(resid
+ remainder
, blocksize
),
308 &this_block_number
, &this_block_count
)) {
309 vp
= vn
->sc_shadow_vp
;
315 /* read the blocks (or parts thereof) */
316 this_offset
= (off_t
)this_block_number
* blocksize
+ remainder
;
317 uio_setoffset(uio
, this_offset
);
318 this_resid
= this_block_count
* blocksize
- remainder
;
319 if (this_resid
> resid
) {
322 uio_setresid(uio
, this_resid
);
323 error
= VNOP_READ(vp
, uio
, ioflag
, context_p
);
328 /* figure out how much we actually read */
329 this_resid
-= uio_resid(uio
);
330 if (this_resid
== 0) {
331 printf("vn device: vnread_shadow zero length read\n");
335 offset
+= this_resid
;
337 uio_setresid(uio
, resid
);
338 uio_setoffset(uio
, offset
);
343 vncopy_block_to_shadow(struct vn_softc
* vn
, struct vfs_context
* context_p
,
344 u_long file_block
, u_long shadow_block
)
349 tmpbuf
= _MALLOC(vn
->sc_secsize
, M_TEMP
, M_WAITOK
);
350 if (tmpbuf
== NULL
) {
353 /* read one block from file at file_block offset */
354 error
= file_io(vn
->sc_vp
, context_p
, UIO_READ
,
355 tmpbuf
, (off_t
)file_block
* vn
->sc_secsize
,
356 vn
->sc_secsize
, NULL
);
360 /* write one block to shadow file at shadow_block offset */
361 error
= file_io(vn
->sc_shadow_vp
, context_p
, UIO_WRITE
,
362 tmpbuf
, (off_t
)shadow_block
* vn
->sc_secsize
,
363 vn
->sc_secsize
, NULL
);
365 FREE(tmpbuf
, M_TEMP
);
370 FLAGS_FIRST_BLOCK_PARTIAL
= 0x1,
371 FLAGS_LAST_BLOCK_PARTIAL
= 0x2
375 vnwrite_shadow(struct vn_softc
* vn
, struct uio
*uio
, int ioflag
,
376 struct vfs_context
* context_p
)
378 u_long blocksize
= vn
->sc_secsize
;
383 resid
= uio_resid(uio
);
384 offset
= uio_offset(uio
);
388 u_long offset_block_number
;
390 u_long resid_block_count
;
391 u_long shadow_block_count
;
392 u_long shadow_block_number
;
393 user_ssize_t this_resid
;
395 /* figure out which blocks to write */
396 offset_block_number
= block_truncate(offset
, blocksize
);
397 remainder
= block_remainder(offset
, blocksize
);
398 resid_block_count
= block_round(resid
+ remainder
, blocksize
);
399 /* figure out if the first or last blocks are partial writes */
401 && !shadow_map_is_written(vn
->sc_shadow_map
,
402 offset_block_number
)) {
403 /* the first block is a partial write */
404 flags
|= FLAGS_FIRST_BLOCK_PARTIAL
;
406 if (resid_block_count
> 1
407 && !shadow_map_is_written(vn
->sc_shadow_map
,
409 + resid_block_count
- 1)
410 && block_remainder(offset
+ resid
, blocksize
) > 0) {
411 /* the last block is a partial write */
412 flags
|= FLAGS_LAST_BLOCK_PARTIAL
;
414 if (shadow_map_write(vn
->sc_shadow_map
,
415 offset_block_number
, resid_block_count
,
416 &shadow_block_number
,
417 &shadow_block_count
)) {
418 /* shadow file is growing */
420 /* truncate the file to its new length before write */
422 size
= (off_t
)shadow_map_shadow_size(vn
->sc_shadow_map
)
424 vnode_setsize(vn
->sc_shadow_vp
, size
, IO_SYNC
,
428 /* write the blocks (or parts thereof) */
429 uio_setoffset(uio
, (off_t
)
430 shadow_block_number
* blocksize
+ remainder
);
431 this_resid
= (off_t
)shadow_block_count
* blocksize
- remainder
;
432 if (this_resid
>= resid
) {
434 if ((flags
& FLAGS_LAST_BLOCK_PARTIAL
) != 0) {
435 /* copy the last block to the shadow */
439 s
= offset_block_number
440 + resid_block_count
- 1;
441 d
= shadow_block_number
442 + shadow_block_count
- 1;
443 error
= vncopy_block_to_shadow(vn
, context_p
,
446 printf("vnwrite_shadow: failed to copy"
447 " block %d to shadow block %d\n",
453 uio_setresid(uio
, this_resid
);
454 if ((flags
& FLAGS_FIRST_BLOCK_PARTIAL
) != 0) {
455 /* copy the first block to the shadow */
456 error
= vncopy_block_to_shadow(vn
, context_p
,
458 shadow_block_number
);
460 printf("vnwrite_shadow: failed to"
461 " copy block %d to shadow block %d\n",
463 shadow_block_number
);
467 error
= VNOP_WRITE(vn
->sc_shadow_vp
, uio
, ioflag
, context_p
);
471 /* figure out how much we actually wrote */
472 this_resid
-= uio_resid(uio
);
473 if (this_resid
== 0) {
474 printf("vn device: vnwrite_shadow zero length write\n");
478 offset
+= this_resid
;
480 uio_setresid(uio
, resid
);
481 uio_setoffset(uio
, offset
);
486 vnread(dev_t dev
, struct uio
*uio
, int ioflag
)
488 struct vfs_context context
;
490 boolean_t funnel_state
;
494 struct vn_softc
* vn
;
498 if (vnunit(dev
) >= NVNDEVICE
) {
502 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
503 vn
= vn_table
+ unit
;
504 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
508 error
= vnode_getwithvid(vn
->sc_vp
, vn
->sc_vid
);
510 /* the vnode is no longer available, abort */
516 resid
= uio_resid(uio
);
517 offset
= uio_offset(uio
);
520 * If out of bounds return an error. If at the EOF point,
523 if (offset
>= (off_t
)vn
->sc_fsize
) {
524 if (offset
> (off_t
)vn
->sc_fsize
) {
530 * If the request crosses EOF, truncate the request.
532 if ((offset
+ resid
) > (off_t
)vn
->sc_fsize
) {
533 resid
= vn
->sc_fsize
- offset
;
534 uio_setresid(uio
, resid
);
538 context
.vc_ucred
= vn
->sc_cred
;
539 if (vn
->sc_shadow_vp
!= NULL
) {
540 error
= vnode_getwithvid(vn
->sc_shadow_vp
,
543 /* the vnode is no longer available, abort */
545 vnode_put(vn
->sc_vp
);
549 error
= vnread_shadow(vn
, uio
, ioflag
, &context
);
550 vnode_put(vn
->sc_shadow_vp
);
552 error
= VNOP_READ(vn
->sc_vp
, uio
, ioflag
, &context
);
554 vnode_put(vn
->sc_vp
);
556 (void) thread_funnel_set(kernel_flock
, funnel_state
);
561 vnwrite(dev_t dev
, struct uio
*uio
, int ioflag
)
563 struct vfs_context context
;
565 boolean_t funnel_state
;
569 struct vn_softc
* vn
;
573 if (vnunit(dev
) >= NVNDEVICE
) {
577 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
578 vn
= vn_table
+ unit
;
579 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
583 if (vn
->sc_flags
& VNF_READONLY
) {
587 error
= vnode_getwithvid(vn
->sc_vp
, vn
->sc_vid
);
589 /* the vnode is no longer available, abort */
594 resid
= uio_resid(uio
);
595 offset
= uio_offset(uio
);
598 * If out of bounds return an error. If at the EOF point,
601 if (offset
>= (off_t
)vn
->sc_fsize
) {
602 if (offset
> (off_t
)vn
->sc_fsize
) {
608 * If the request crosses EOF, truncate the request.
610 if ((offset
+ resid
) > (off_t
)vn
->sc_fsize
) {
611 resid
= (off_t
)vn
->sc_fsize
- offset
;
612 uio_setresid(uio
, resid
);
616 context
.vc_ucred
= vn
->sc_cred
;
618 if (vn
->sc_shadow_vp
!= NULL
) {
619 error
= vnode_getwithvid(vn
->sc_shadow_vp
,
622 /* the vnode is no longer available, abort */
624 vnode_put(vn
->sc_vp
);
628 error
= vnwrite_shadow(vn
, uio
, ioflag
, &context
);
629 vnode_put(vn
->sc_shadow_vp
);
631 error
= VNOP_WRITE(vn
->sc_vp
, uio
, ioflag
, &context
);
633 vnode_put(vn
->sc_vp
);
635 (void) thread_funnel_set(kernel_flock
, funnel_state
);
640 shadow_read(struct vn_softc
* vn
, struct buf
* bp
, char * base
, struct proc
* p
)
642 u_long blocksize
= vn
->sc_secsize
;
643 struct vfs_context context
;
646 boolean_t read_shadow
;
651 context
.vc_ucred
= vn
->sc_cred
;
652 offset
= buf_blkno(bp
);
653 resid
= buf_resid(bp
) / blocksize
;
655 user_ssize_t temp_resid
;
660 read_shadow
= shadow_map_read(vn
->sc_shadow_map
,
662 &this_offset
, &this_resid
);
664 vp
= vn
->sc_shadow_vp
;
669 error
= file_io(vp
, &context
, UIO_READ
, base
+ start
,
670 (off_t
)this_offset
* blocksize
,
671 (user_ssize_t
)this_resid
* blocksize
,
676 this_resid
-= (temp_resid
/ blocksize
);
677 if (this_resid
== 0) {
678 printf("vn device: shadow_read zero length read\n");
682 offset
+= this_resid
;
683 start
+= this_resid
* blocksize
;
685 buf_setresid(bp
, resid
* blocksize
);
690 shadow_write(struct vn_softc
* vn
, struct buf
* bp
, char * base
,
693 u_long blocksize
= vn
->sc_secsize
;
694 struct vfs_context context
;
697 boolean_t shadow_grew
;
702 context
.vc_ucred
= vn
->sc_cred
;
703 offset
= buf_blkno(bp
);
704 resid
= buf_resid(bp
) / blocksize
;
706 user_ssize_t temp_resid
;
710 shadow_grew
= shadow_map_write(vn
->sc_shadow_map
,
712 &this_offset
, &this_resid
);
716 /* truncate the file to its new length before write */
717 size
= (off_t
)shadow_map_shadow_size(vn
->sc_shadow_map
)
719 vnode_setsize(vn
->sc_shadow_vp
, size
, IO_SYNC
,
723 error
= file_io(vn
->sc_shadow_vp
, &context
, UIO_WRITE
,
725 (off_t
)this_offset
* blocksize
,
726 (user_ssize_t
)this_resid
* blocksize
,
731 this_resid
-= (temp_resid
/ blocksize
);
732 if (this_resid
== 0) {
733 printf("vn device: shadow_write zero length write\n");
737 offset
+= this_resid
;
738 start
+= this_resid
* blocksize
;
740 buf_setresid(bp
, resid
* blocksize
);
745 vn_readwrite_io(struct vn_softc
* vn
, struct buf
* bp
, struct proc
* p
)
752 if (buf_map(bp
, &vaddr
))
753 panic("vn device: buf_map failed");
754 iov_base
= (char *)vaddr
;
756 if (vn
->sc_shadow_vp
== NULL
) {
757 struct vfs_context context
;
758 user_ssize_t temp_resid
;
761 context
.vc_ucred
= vn
->sc_cred
;
763 error
= file_io(vn
->sc_vp
, &context
,
764 buf_flags(bp
) & B_READ
? UIO_READ
: UIO_WRITE
,
766 (off_t
)buf_blkno(bp
) * vn
->sc_secsize
,
767 buf_resid(bp
), &temp_resid
);
768 buf_setresid(bp
, temp_resid
);
771 if (buf_flags(bp
) & B_READ
)
772 error
= shadow_read(vn
, bp
, iov_base
, p
);
774 error
= shadow_write(vn
, bp
, iov_base
, p
);
782 vnstrategy(struct buf
*bp
)
786 long sz
; /* in sc_secsize chunks */
788 boolean_t funnel_state
;
789 struct proc
* p
= current_proc();
790 struct vnode
* shadow_vp
= NULL
;
791 struct vnode
* vp
= NULL
;
793 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
794 vn
= vn_table
+ vnunit(buf_device(bp
));
795 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
800 buf_setresid(bp
, buf_count(bp
));
802 * Check for required alignment. Transfers must be a valid
803 * multiple of the sector size.
805 blk_num
= buf_blkno(bp
);
806 if (buf_count(bp
) % vn
->sc_secsize
!= 0) {
810 sz
= howmany(buf_count(bp
), vn
->sc_secsize
);
813 * If out of bounds return an error. If at the EOF point,
814 * simply read or write less.
816 if (blk_num
>= 0 && (u_int64_t
)blk_num
>= vn
->sc_size
) {
817 if (blk_num
> 0 && (u_int64_t
)blk_num
> vn
->sc_size
) {
823 * If the request crosses EOF, truncate the request.
825 if ((blk_num
+ sz
) > 0 && ((u_int64_t
)(blk_num
+ sz
)) > vn
->sc_size
) {
826 buf_setcount(bp
, (vn
->sc_size
- blk_num
) * vn
->sc_secsize
);
827 buf_setresid(bp
, buf_count(bp
));
834 error
= vnode_getwithvid(vp
, vn
->sc_vid
);
836 /* the vnode is no longer available, abort */
841 shadow_vp
= vn
->sc_shadow_vp
;
842 if (shadow_vp
!= NULL
) {
843 error
= vnode_getwithvid(shadow_vp
,
846 /* the vnode is no longer available, abort */
848 vnode_put(vn
->sc_vp
);
853 error
= vn_readwrite_io(vn
, bp
, p
);
855 if (shadow_vp
!= NULL
) {
856 vnode_put(shadow_vp
);
860 (void) thread_funnel_set(kernel_flock
, funnel_state
);
862 buf_seterror(bp
, error
);
870 vnioctl(dev_t dev
, u_long cmd
, caddr_t data
,
871 __unused
int flag
, struct proc
*p
,
875 struct user_vn_ioctl
*viop
;
880 struct vfsioattr ioattr
;
881 struct user_vn_ioctl user_vnio
;
882 boolean_t funnel_state
;
885 if (vnunit(dev
) >= NVNDEVICE
) {
889 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
890 vn
= vn_table
+ unit
;
891 error
= proc_suser(p
);
896 viop
= (struct user_vn_ioctl
*)data
;
897 f
= (u_int32_t
*)data
;
898 o
= (u_int64_t
*)data
;
902 case DKIOCGETBLOCKSIZE
:
903 case DKIOCSETBLOCKSIZE
:
904 case DKIOCGETMAXBLOCKCOUNTREAD
:
905 case DKIOCGETMAXBLOCKCOUNTWRITE
:
906 case DKIOCGETMAXSEGMENTCOUNTREAD
:
907 case DKIOCGETMAXSEGMENTCOUNTWRITE
:
908 case DKIOCGETMAXSEGMENTBYTECOUNTREAD
:
909 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE
:
910 case DKIOCGETBLOCKCOUNT
:
911 case DKIOCGETBLOCKCOUNT32
:
912 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
921 if (vn
->sc_vp
!= NULL
)
922 vfs_ioattr(vnode_mount(vn
->sc_vp
), &ioattr
);
924 bzero(&ioattr
, sizeof(ioattr
));
930 case DKIOCGETMAXBLOCKCOUNTREAD
:
931 *o
= ioattr
.io_maxreadcnt
/ vn
->sc_secsize
;
933 case DKIOCGETMAXBLOCKCOUNTWRITE
:
934 *o
= ioattr
.io_maxwritecnt
/ vn
->sc_secsize
;
936 case DKIOCGETMAXBYTECOUNTREAD
:
937 *o
= ioattr
.io_maxreadcnt
;
939 case DKIOCGETMAXBYTECOUNTWRITE
:
940 *o
= ioattr
.io_maxwritecnt
;
942 case DKIOCGETMAXSEGMENTCOUNTREAD
:
943 *o
= ioattr
.io_segreadcnt
;
945 case DKIOCGETMAXSEGMENTCOUNTWRITE
:
946 *o
= ioattr
.io_segwritecnt
;
948 case DKIOCGETMAXSEGMENTBYTECOUNTREAD
:
949 *o
= ioattr
.io_maxsegreadsize
;
951 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE
:
952 *o
= ioattr
.io_maxsegwritesize
;
954 case DKIOCGETBLOCKSIZE
:
957 case DKIOCSETBLOCKSIZE
:
959 /* can only set block size on block device */
963 if (*f
< DEV_BSIZE
) {
967 if (vn
->sc_shadow_vp
!= NULL
) {
968 if (*f
== (unsigned)vn
->sc_secsize
) {
971 /* can't change the block size if already shadowing */
976 /* recompute the size in terms of the new blocksize */
977 vn
->sc_size
= vn
->sc_fsize
/ vn
->sc_secsize
;
979 case DKIOCISWRITABLE
:
982 case DKIOCGETBLOCKCOUNT32
:
985 case DKIOCGETBLOCKCOUNT
:
990 if (vn
->sc_shadow_vp
!= NULL
) {
994 if (vn
->sc_vp
== NULL
) {
995 /* much be attached before we can shadow */
999 if (!proc_is64bit(p
)) {
1000 /* downstream code expects LP64 version of vn_ioctl structure */
1001 vn_ioctl_to_64((struct vn_ioctl
*)viop
, &user_vnio
);
1004 if (viop
->vn_file
== USER_ADDR_NULL
) {
1008 error
= vniocattach_shadow(vn
, viop
, dev
, 0, p
);
1014 /* attach only on block device */
1018 if (vn
->sc_flags
& VNF_INITED
) {
1022 if (!proc_is64bit(p
)) {
1023 /* downstream code expects LP64 version of vn_ioctl structure */
1024 vn_ioctl_to_64((struct vn_ioctl
*)viop
, &user_vnio
);
1027 if (viop
->vn_file
== USER_ADDR_NULL
) {
1031 error
= vniocattach_file(vn
, viop
, dev
, 0, p
);
1037 /* detach only on block device */
1041 /* Note: spec_open won't open a mounted block device */
1044 * XXX handle i/o in progress. Return EBUSY, or wait, or
1046 * XXX handle multiple opens of the device. Return EBUSY,
1047 * or revoke the fd's.
1048 * How are these problems handled for removable and failing
1049 * hardware devices? (Hint: They are not)
1060 vn_options
&= ~(*f
);
1065 vn
->sc_options
|= *f
;
1066 *f
= vn
->sc_options
;
1070 vn
->sc_options
&= ~(*f
);
1071 *f
= vn
->sc_options
;
1079 (void) thread_funnel_set(kernel_flock
, funnel_state
);
1084 vnioctl_chr(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc
*p
)
1086 return (vnioctl(dev
, cmd
, data
, flag
, p
, TRUE
));
1090 vnioctl_blk(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc
*p
)
1092 return (vnioctl(dev
, cmd
, data
, flag
, p
, FALSE
));
1098 * Attach a file to a VN partition. Return the size in the vn_size
1103 vniocattach_file(struct vn_softc
*vn
,
1104 struct user_vn_ioctl
*vniop
,
1110 struct vfs_context context
;
1112 struct nameidata nd
;
1116 context
.vc_proc
= p
;
1117 context
.vc_ucred
= proc_ucred(p
);
1119 flags
= FREAD
|FWRITE
;
1121 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, vniop
->vn_file
, &context
);
1124 NDINIT(&nd
, LOOKUP
, FOLLOW
,
1125 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
1126 vniop
->vn_file
, &context
);
1128 /* vn_open gives both long- and short-term references */
1129 error
= vn_open(&nd
, flags
, 0);
1131 if (error
!= EACCES
&& error
!= EPERM
&& error
!= EROFS
)
1135 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
,
1136 vniop
->vn_file
, &context
);
1139 NDINIT(&nd
, LOOKUP
, FOLLOW
,
1140 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
1141 vniop
->vn_file
, &context
);
1143 error
= vn_open(&nd
, flags
, 0);
1147 if (nd
.ni_vp
->v_type
!= VREG
) {
1151 error
= vnode_size(nd
.ni_vp
, &file_size
, &context
);
1154 (void) vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1155 vnode_put(nd
.ni_vp
);
1158 cred
= kauth_cred_proc_ref(p
);
1159 nd
.ni_vp
->v_flag
|= VNOCACHE_DATA
;
1160 error
= setcred(nd
.ni_vp
, p
, cred
);
1162 (void)vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1163 vnode_put(nd
.ni_vp
);
1164 kauth_cred_rele(cred
);
1167 vn
->sc_secsize
= DEV_BSIZE
;
1168 vn
->sc_fsize
= file_size
;
1169 vn
->sc_size
= file_size
/ vn
->sc_secsize
;
1170 vn
->sc_vp
= nd
.ni_vp
;
1171 vn
->sc_vid
= vnode_vid(nd
.ni_vp
);
1172 vn
->sc_open_flags
= flags
;
1174 cdev
= makedev(vndevice_cdev_major
, minor(dev
));
1175 vn
->sc_cdev
= devfs_make_node(cdev
, DEVFS_CHAR
,
1176 UID_ROOT
, GID_OPERATOR
,
1179 vn
->sc_flags
|= VNF_INITED
;
1181 vn
->sc_flags
|= VNF_READONLY
;
1182 /* lose the short-term reference */
1183 vnode_put(nd
.ni_vp
);
1188 vniocattach_shadow(struct vn_softc
*vn
, struct user_vn_ioctl
*vniop
,
1189 __unused
int dev
, int in_kernel
, struct proc
*p
)
1191 struct vfs_context context
;
1192 struct nameidata nd
;
1197 context
.vc_proc
= p
;
1198 context
.vc_ucred
= proc_ucred(p
);
1200 flags
= FREAD
|FWRITE
;
1202 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, vniop
->vn_file
, &context
);
1205 NDINIT(&nd
, LOOKUP
, FOLLOW
,
1206 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
1207 vniop
->vn_file
, &context
);
1209 /* vn_open gives both long- and short-term references */
1210 error
= vn_open(&nd
, flags
, 0);
1212 /* shadow MUST be writable! */
1215 if (nd
.ni_vp
->v_type
!= VREG
1216 || (error
= vnode_size(nd
.ni_vp
, &file_size
, &context
))) {
1217 (void)vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1218 vnode_put(nd
.ni_vp
);
1219 return (error
? error
: EINVAL
);
1221 map
= shadow_map_create(vn
->sc_fsize
, file_size
,
1224 (void)vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1225 vnode_put(nd
.ni_vp
);
1226 vn
->sc_shadow_vp
= NULL
;
1229 vn
->sc_shadow_vp
= nd
.ni_vp
;
1230 vn
->sc_shadow_vid
= vnode_vid(nd
.ni_vp
);
1231 vn
->sc_shadow_vp
->v_flag
|= VNOCACHE_DATA
;
1232 vn
->sc_shadow_map
= map
;
1233 vn
->sc_flags
&= ~VNF_READONLY
; /* we're now read/write */
1235 /* lose the short-term reference */
1236 vnode_put(nd
.ni_vp
);
1241 vndevice_root_image(char * path
, char devname
[], dev_t
* dev_p
)
1244 struct vn_softc
* vn
;
1245 struct user_vn_ioctl vnio
;
1247 vnio
.vn_file
= CAST_USER_ADDR_T(path
);
1250 vn
= vn_table
+ ROOT_IMAGE_UNIT
;
1251 *dev_p
= makedev(vndevice_bdev_major
,
1253 sprintf(devname
, "vn%d", ROOT_IMAGE_UNIT
);
1254 error
= vniocattach_file(vn
, &vnio
, *dev_p
, 1, current_proc());
1259 * Duplicate the current processes' credentials. Since we are called only
1260 * as the result of a SET ioctl and only root can do that, any future access
1261 * to this "disk" is essentially as root. Note that credentials may change
1262 * if some other uid can write directly to the mapped file (NFS).
1265 setcred(struct vnode
* vp
, struct proc
* p
, kauth_cred_t cred
)
1269 struct vfs_context context
;
1272 * Horrible kludge to establish credentials for NFS XXX.
1274 context
.vc_proc
= p
;
1275 context
.vc_ucred
= cred
;
1276 tmpbuf
= _MALLOC(DEV_BSIZE
, M_TEMP
, M_WAITOK
);
1277 error
= file_io(vp
, &context
, UIO_READ
, tmpbuf
, 0, DEV_BSIZE
, NULL
);
1278 FREE(tmpbuf
, M_TEMP
);
1283 vnclear(struct vn_softc
*vn
, struct proc
* p
)
1285 if (vn
->sc_vp
!= NULL
) {
1286 /* release long-term reference */
1287 (void)vn_close(vn
->sc_vp
, vn
->sc_open_flags
, vn
->sc_cred
, p
);
1290 if (vn
->sc_shadow_vp
!= NULL
) {
1291 /* release long-term reference */
1292 (void)vn_close(vn
->sc_shadow_vp
, FREAD
| FWRITE
,
1294 vn
->sc_shadow_vp
= NULL
;
1296 if (vn
->sc_shadow_map
!= NULL
) {
1297 shadow_map_free(vn
->sc_shadow_map
);
1298 vn
->sc_shadow_map
= NULL
;
1300 vn
->sc_flags
&= ~(VNF_INITED
| VNF_READONLY
);
1302 kauth_cred_rele(vn
->sc_cred
);
1308 devfs_remove(vn
->sc_cdev
);
1317 struct vn_softc
*vn
;
1319 boolean_t funnel_state
;
1322 if (vnunit(dev
) >= NVNDEVICE
) {
1326 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
1327 vn
= vn_table
+ unit
;
1328 if ((vn
->sc_flags
& VNF_INITED
) == 0)
1331 secsize
= vn
->sc_secsize
;
1332 (void) thread_funnel_set(kernel_flock
, funnel_state
);
1336 #define CDEV_MAJOR -1
1337 #define BDEV_MAJOR -1
1338 static int vndevice_inited
= 0;
1345 if (vndevice_inited
)
1347 vndevice_bdev_major
= bdevsw_add(BDEV_MAJOR
, &vn_bdevsw
);
1349 if (vndevice_bdev_major
< 0) {
1350 printf("vndevice_init: bdevsw_add() returned %d\n",
1351 vndevice_bdev_major
);
1354 vndevice_cdev_major
= cdevsw_add_with_bdev(CDEV_MAJOR
, &vn_cdevsw
,
1355 vndevice_bdev_major
);
1356 if (vndevice_cdev_major
< 0) {
1357 printf("vndevice_init: cdevsw_add() returned %d\n",
1358 vndevice_cdev_major
);
1361 for (i
= 0; i
< NVNDEVICE
; i
++) {
1362 dev_t dev
= makedev(vndevice_bdev_major
, i
);
1363 vn_table
[i
].sc_bdev
= devfs_make_node(dev
, DEVFS_BLOCK
,
1364 UID_ROOT
, GID_OPERATOR
,
1367 if (vn_table
[i
].sc_bdev
== NULL
)
1368 printf("vninit: devfs_make_node failed!\n");
1373 vn_ioctl_to_64(struct vn_ioctl
*from
, struct user_vn_ioctl
*to
)
1375 to
->vn_file
= CAST_USER_ADDR_T(from
->vn_file
);
1376 to
->vn_size
= from
->vn_size
;
1377 to
->vn_control
= from
->vn_control
;
1380 #endif /* NVNDEVICE */