2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1988 University of Utah.
26 * Copyright (c) 1990, 1993
27 * The Regents of the University of California. All rights reserved.
29 * This code is derived from software contributed to Berkeley by
30 * the Systems Programming Group of the University of Utah Computer
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * from: Utah Hdr: vn.c 1.13 94/04/02
63 * from: @(#)vn.c 8.6 (Berkeley) 4/1/94
64 * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $
70 * Block/character interface to a vnode. Allows one to treat a file
71 * as a disk (e.g. build a filesystem in it, mount it, etc.).
73 * NOTE 1: This uses the vnop_blockmap/vnop_strategy interface to the vnode
74 * instead of a simple VOP_RDWR. We do this to avoid distorting the
77 * NOTE 2: There is a security issue involved with this driver.
78 * Once mounted all access to the contents of the "mapped" file via
79 * the special file is controlled by the permissions on the special
80 * file, the protection of the mapped file is ignored (effectively,
81 * by using root credentials in all transactions).
83 * NOTE 3: Doesn't interact with leases, should it?
90 #include <sys/param.h>
91 #include <sys/systm.h>
92 #include <sys/kernel.h>
93 #include <sys/mount.h>
94 #include <sys/namei.h>
96 #include <sys/kauth.h>
98 #include <sys/malloc.h>
99 #include <sys/vnode_internal.h>
100 #include <sys/fcntl.h>
101 #include <sys/conf.h>
102 #include <sys/disk.h>
103 #include <sys/stat.h>
104 #include <sys/conf.h>
105 #include <sys/uio_internal.h>
107 #include <sys/vnioctl.h>
111 #include <vm/vm_pager.h>
112 #include <mach/memory_object_types.h>
114 #include <miscfs/devfs/devfs.h>
119 static ioctl_fcn_t vnioctl_chr
;
120 static ioctl_fcn_t vnioctl_blk
;
121 static open_close_fcn_t vnopen
;
122 static open_close_fcn_t vnclose
;
123 static psize_fcn_t vnsize
;
124 static strategy_fcn_t vnstrategy
;
125 static read_write_fcn_t vnread
;
126 static read_write_fcn_t vnwrite
;
128 static int vndevice_bdev_major
;
129 static int vndevice_cdev_major
;
133 * D_DISK we want to look like a disk
134 * D_CANFREE We support B_FREEBUF
137 static struct bdevsw vn_bdevsw
= {
140 /* strategy */ vnstrategy
,
141 /* ioctl */ vnioctl_blk
,
147 static struct cdevsw vn_cdevsw
= {
152 /* ioctl */ vnioctl_chr
,
154 /* reset */ eno_reset
,
156 /* select */ eno_select
,
158 /* strategy */ eno_strat
,
165 u_int64_t sc_fsize
; /* file size in bytes */
166 u_int64_t sc_size
; /* size of vn, sc_secsize scale */
167 int sc_flags
; /* flags */
168 u_long sc_secsize
; /* sector size */
169 struct vnode
*sc_vp
; /* vnode if not NULL */
172 struct vnode
*sc_shadow_vp
; /* shadow vnode if not NULL */
173 uint32_t sc_shadow_vid
;
174 shadow_map_t
* sc_shadow_map
; /* shadow map if not NULL */
175 kauth_cred_t sc_cred
; /* credentials */
176 u_int32_t sc_options
; /* options */
179 } vn_table
[NVNDEVICE
];
181 #define ROOT_IMAGE_UNIT 0
184 #define VNF_INITED 0x01
185 #define VNF_READONLY 0x02
187 static u_int32_t vn_options
;
189 #define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt))
190 #define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt))
192 static int setcred(struct vnode
* vp
, struct proc
* p
,
194 static void vnclear (struct vn_softc
*vn
, struct proc
* p
);
195 static void vn_ioctl_to_64(struct vn_ioctl
*from
, struct user_vn_ioctl
*to
);
196 void vndevice_init(void);
197 int vndevice_root_image(char * path
, char devname
[], dev_t
* dev_p
);
200 vniocattach_file(struct vn_softc
*vn
,
201 struct user_vn_ioctl
*vniop
,
206 vniocattach_shadow(struct vn_softc
* vn
,
207 struct user_vn_ioctl
*vniop
,
211 static __inline__
int
218 vnclose(__unused dev_t dev
, __unused
int flags
,
219 __unused
int devtype
, __unused
struct proc
*p
)
225 vnopen(dev_t dev
, int flags
, __unused
int devtype
, __unused
struct proc
*p
)
231 if (vnunit(dev
) >= NVNDEVICE
) {
234 vn
= vn_table
+ unit
;
235 if ((flags
& FWRITE
) && (vn
->sc_flags
& VNF_READONLY
))
242 file_io(struct vnode
* vp
, struct vfs_context
* context_p
,
243 enum uio_rw op
, char * base
, off_t offset
, user_ssize_t count
,
244 user_ssize_t
* resid
)
248 char uio_buf
[UIO_SIZEOF(1)];
250 auio
= uio_createwithbuffer(1, offset
, UIO_SYSSPACE
, op
,
251 &uio_buf
[0], sizeof(uio_buf
));
252 uio_addiov(auio
, CAST_USER_ADDR_T(base
), count
);
254 error
= VNOP_READ(vp
, auio
, IO_SYNC
, context_p
);
256 error
= VNOP_WRITE(vp
, auio
, IO_SYNC
, context_p
);
259 *resid
= uio_resid(auio
);
264 static __inline__ off_t
265 block_round(off_t o
, int blocksize
)
267 return ((o
+ blocksize
- 1) / blocksize
);
270 static __inline__ off_t
271 block_truncate(off_t o
, int blocksize
)
273 return (o
/ blocksize
);
276 static __inline__
int
277 block_remainder(off_t o
, int blocksize
)
279 return (o
% blocksize
);
283 vnread_shadow(struct vn_softc
* vn
, struct uio
*uio
, int ioflag
,
284 struct vfs_context
* context_p
)
286 u_long blocksize
= vn
->sc_secsize
;
291 user_ssize_t orig_resid
;
293 orig_resid
= resid
= uio_resid(uio
);
294 orig_offset
= offset
= uio_offset(uio
);
298 u_long this_block_number
;
299 u_long this_block_count
;
301 user_ssize_t this_resid
;
304 /* figure out which blocks to read */
305 remainder
= block_remainder(offset
, blocksize
);
306 if (shadow_map_read(vn
->sc_shadow_map
,
307 block_truncate(offset
, blocksize
),
308 block_round(resid
+ remainder
, blocksize
),
309 &this_block_number
, &this_block_count
)) {
310 vp
= vn
->sc_shadow_vp
;
316 /* read the blocks (or parts thereof) */
317 this_offset
= (off_t
)this_block_number
* blocksize
+ remainder
;
318 uio_setoffset(uio
, this_offset
);
319 this_resid
= this_block_count
* blocksize
- remainder
;
320 if (this_resid
> resid
) {
323 uio_setresid(uio
, this_resid
);
324 error
= VNOP_READ(vp
, uio
, ioflag
, context_p
);
329 /* figure out how much we actually read */
330 this_resid
-= uio_resid(uio
);
331 if (this_resid
== 0) {
332 printf("vn device: vnread_shadow zero length read\n");
336 offset
+= this_resid
;
338 uio_setresid(uio
, resid
);
339 uio_setoffset(uio
, offset
);
344 vncopy_block_to_shadow(struct vn_softc
* vn
, struct vfs_context
* context_p
,
345 u_long file_block
, u_long shadow_block
)
350 tmpbuf
= _MALLOC(vn
->sc_secsize
, M_TEMP
, M_WAITOK
);
351 if (tmpbuf
== NULL
) {
354 /* read one block from file at file_block offset */
355 error
= file_io(vn
->sc_vp
, context_p
, UIO_READ
,
356 tmpbuf
, (off_t
)file_block
* vn
->sc_secsize
,
357 vn
->sc_secsize
, NULL
);
361 /* write one block to shadow file at shadow_block offset */
362 error
= file_io(vn
->sc_shadow_vp
, context_p
, UIO_WRITE
,
363 tmpbuf
, (off_t
)shadow_block
* vn
->sc_secsize
,
364 vn
->sc_secsize
, NULL
);
366 FREE(tmpbuf
, M_TEMP
);
371 FLAGS_FIRST_BLOCK_PARTIAL
= 0x1,
372 FLAGS_LAST_BLOCK_PARTIAL
= 0x2
376 vnwrite_shadow(struct vn_softc
* vn
, struct uio
*uio
, int ioflag
,
377 struct vfs_context
* context_p
)
379 u_long blocksize
= vn
->sc_secsize
;
384 resid
= uio_resid(uio
);
385 offset
= uio_offset(uio
);
389 u_long offset_block_number
;
391 u_long resid_block_count
;
392 u_long shadow_block_count
;
393 u_long shadow_block_number
;
394 user_ssize_t this_resid
;
396 /* figure out which blocks to write */
397 offset_block_number
= block_truncate(offset
, blocksize
);
398 remainder
= block_remainder(offset
, blocksize
);
399 resid_block_count
= block_round(resid
+ remainder
, blocksize
);
400 /* figure out if the first or last blocks are partial writes */
402 && !shadow_map_is_written(vn
->sc_shadow_map
,
403 offset_block_number
)) {
404 /* the first block is a partial write */
405 flags
|= FLAGS_FIRST_BLOCK_PARTIAL
;
407 if (resid_block_count
> 1
408 && !shadow_map_is_written(vn
->sc_shadow_map
,
410 + resid_block_count
- 1)
411 && block_remainder(offset
+ resid
, blocksize
) > 0) {
412 /* the last block is a partial write */
413 flags
|= FLAGS_LAST_BLOCK_PARTIAL
;
415 if (shadow_map_write(vn
->sc_shadow_map
,
416 offset_block_number
, resid_block_count
,
417 &shadow_block_number
,
418 &shadow_block_count
)) {
419 /* shadow file is growing */
421 /* truncate the file to its new length before write */
423 size
= (off_t
)shadow_map_shadow_size(vn
->sc_shadow_map
)
425 vnode_setsize(vn
->sc_shadow_vp
, size
, IO_SYNC
,
429 /* write the blocks (or parts thereof) */
430 uio_setoffset(uio
, (off_t
)
431 shadow_block_number
* blocksize
+ remainder
);
432 this_resid
= (off_t
)shadow_block_count
* blocksize
- remainder
;
433 if (this_resid
>= resid
) {
435 if ((flags
& FLAGS_LAST_BLOCK_PARTIAL
) != 0) {
436 /* copy the last block to the shadow */
440 s
= offset_block_number
441 + resid_block_count
- 1;
442 d
= shadow_block_number
443 + shadow_block_count
- 1;
444 error
= vncopy_block_to_shadow(vn
, context_p
,
447 printf("vnwrite_shadow: failed to copy"
448 " block %d to shadow block %d\n",
454 uio_setresid(uio
, this_resid
);
455 if ((flags
& FLAGS_FIRST_BLOCK_PARTIAL
) != 0) {
456 /* copy the first block to the shadow */
457 error
= vncopy_block_to_shadow(vn
, context_p
,
459 shadow_block_number
);
461 printf("vnwrite_shadow: failed to"
462 " copy block %d to shadow block %d\n",
464 shadow_block_number
);
468 error
= VNOP_WRITE(vn
->sc_shadow_vp
, uio
, ioflag
, context_p
);
472 /* figure out how much we actually wrote */
473 this_resid
-= uio_resid(uio
);
474 if (this_resid
== 0) {
475 printf("vn device: vnwrite_shadow zero length write\n");
479 offset
+= this_resid
;
481 uio_setresid(uio
, resid
);
482 uio_setoffset(uio
, offset
);
487 vnread(dev_t dev
, struct uio
*uio
, int ioflag
)
489 struct vfs_context context
;
491 boolean_t funnel_state
;
495 struct vn_softc
* vn
;
499 if (vnunit(dev
) >= NVNDEVICE
) {
503 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
504 vn
= vn_table
+ unit
;
505 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
509 error
= vnode_getwithvid(vn
->sc_vp
, vn
->sc_vid
);
511 /* the vnode is no longer available, abort */
517 resid
= uio_resid(uio
);
518 offset
= uio_offset(uio
);
521 * If out of bounds return an error. If at the EOF point,
524 if (offset
>= (off_t
)vn
->sc_fsize
) {
525 if (offset
> (off_t
)vn
->sc_fsize
) {
531 * If the request crosses EOF, truncate the request.
533 if ((offset
+ resid
) > (off_t
)vn
->sc_fsize
) {
534 resid
= vn
->sc_fsize
- offset
;
535 uio_setresid(uio
, resid
);
539 context
.vc_ucred
= vn
->sc_cred
;
540 if (vn
->sc_shadow_vp
!= NULL
) {
541 error
= vnode_getwithvid(vn
->sc_shadow_vp
,
544 /* the vnode is no longer available, abort */
546 vnode_put(vn
->sc_vp
);
550 error
= vnread_shadow(vn
, uio
, ioflag
, &context
);
551 vnode_put(vn
->sc_shadow_vp
);
553 error
= VNOP_READ(vn
->sc_vp
, uio
, ioflag
, &context
);
555 vnode_put(vn
->sc_vp
);
557 (void) thread_funnel_set(kernel_flock
, funnel_state
);
562 vnwrite(dev_t dev
, struct uio
*uio
, int ioflag
)
564 struct vfs_context context
;
566 boolean_t funnel_state
;
570 struct vn_softc
* vn
;
574 if (vnunit(dev
) >= NVNDEVICE
) {
578 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
579 vn
= vn_table
+ unit
;
580 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
584 if (vn
->sc_flags
& VNF_READONLY
) {
588 error
= vnode_getwithvid(vn
->sc_vp
, vn
->sc_vid
);
590 /* the vnode is no longer available, abort */
595 resid
= uio_resid(uio
);
596 offset
= uio_offset(uio
);
599 * If out of bounds return an error. If at the EOF point,
602 if (offset
>= (off_t
)vn
->sc_fsize
) {
603 if (offset
> (off_t
)vn
->sc_fsize
) {
609 * If the request crosses EOF, truncate the request.
611 if ((offset
+ resid
) > (off_t
)vn
->sc_fsize
) {
612 resid
= (off_t
)vn
->sc_fsize
- offset
;
613 uio_setresid(uio
, resid
);
617 context
.vc_ucred
= vn
->sc_cred
;
619 if (vn
->sc_shadow_vp
!= NULL
) {
620 error
= vnode_getwithvid(vn
->sc_shadow_vp
,
623 /* the vnode is no longer available, abort */
625 vnode_put(vn
->sc_vp
);
629 error
= vnwrite_shadow(vn
, uio
, ioflag
, &context
);
630 vnode_put(vn
->sc_shadow_vp
);
632 error
= VNOP_WRITE(vn
->sc_vp
, uio
, ioflag
, &context
);
634 vnode_put(vn
->sc_vp
);
636 (void) thread_funnel_set(kernel_flock
, funnel_state
);
641 shadow_read(struct vn_softc
* vn
, struct buf
* bp
, char * base
, struct proc
* p
)
643 u_long blocksize
= vn
->sc_secsize
;
644 struct vfs_context context
;
647 boolean_t read_shadow
;
652 context
.vc_ucred
= vn
->sc_cred
;
653 offset
= buf_blkno(bp
);
654 resid
= buf_resid(bp
) / blocksize
;
656 user_ssize_t temp_resid
;
661 read_shadow
= shadow_map_read(vn
->sc_shadow_map
,
663 &this_offset
, &this_resid
);
665 vp
= vn
->sc_shadow_vp
;
670 error
= file_io(vp
, &context
, UIO_READ
, base
+ start
,
671 (off_t
)this_offset
* blocksize
,
672 (user_ssize_t
)this_resid
* blocksize
,
677 this_resid
-= (temp_resid
/ blocksize
);
678 if (this_resid
== 0) {
679 printf("vn device: shadow_read zero length read\n");
683 offset
+= this_resid
;
684 start
+= this_resid
* blocksize
;
686 buf_setresid(bp
, resid
* blocksize
);
691 shadow_write(struct vn_softc
* vn
, struct buf
* bp
, char * base
,
694 u_long blocksize
= vn
->sc_secsize
;
695 struct vfs_context context
;
698 boolean_t shadow_grew
;
703 context
.vc_ucred
= vn
->sc_cred
;
704 offset
= buf_blkno(bp
);
705 resid
= buf_resid(bp
) / blocksize
;
707 user_ssize_t temp_resid
;
711 shadow_grew
= shadow_map_write(vn
->sc_shadow_map
,
713 &this_offset
, &this_resid
);
717 /* truncate the file to its new length before write */
718 size
= (off_t
)shadow_map_shadow_size(vn
->sc_shadow_map
)
720 vnode_setsize(vn
->sc_shadow_vp
, size
, IO_SYNC
,
724 error
= file_io(vn
->sc_shadow_vp
, &context
, UIO_WRITE
,
726 (off_t
)this_offset
* blocksize
,
727 (user_ssize_t
)this_resid
* blocksize
,
732 this_resid
-= (temp_resid
/ blocksize
);
733 if (this_resid
== 0) {
734 printf("vn device: shadow_write zero length write\n");
738 offset
+= this_resid
;
739 start
+= this_resid
* blocksize
;
741 buf_setresid(bp
, resid
* blocksize
);
746 vn_readwrite_io(struct vn_softc
* vn
, struct buf
* bp
, struct proc
* p
)
753 if (buf_map(bp
, &vaddr
))
754 panic("vn device: buf_map failed");
755 iov_base
= (char *)vaddr
;
757 if (vn
->sc_shadow_vp
== NULL
) {
758 struct vfs_context context
;
759 user_ssize_t temp_resid
;
762 context
.vc_ucred
= vn
->sc_cred
;
764 error
= file_io(vn
->sc_vp
, &context
,
765 buf_flags(bp
) & B_READ
? UIO_READ
: UIO_WRITE
,
767 (off_t
)buf_blkno(bp
) * vn
->sc_secsize
,
768 buf_resid(bp
), &temp_resid
);
769 buf_setresid(bp
, temp_resid
);
772 if (buf_flags(bp
) & B_READ
)
773 error
= shadow_read(vn
, bp
, iov_base
, p
);
775 error
= shadow_write(vn
, bp
, iov_base
, p
);
783 vnstrategy(struct buf
*bp
)
787 long sz
; /* in sc_secsize chunks */
789 boolean_t funnel_state
;
790 struct proc
* p
= current_proc();
791 struct vnode
* shadow_vp
= NULL
;
792 struct vnode
* vp
= NULL
;
794 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
795 vn
= vn_table
+ vnunit(buf_device(bp
));
796 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
801 buf_setresid(bp
, buf_count(bp
));
803 * Check for required alignment. Transfers must be a valid
804 * multiple of the sector size.
806 blk_num
= buf_blkno(bp
);
807 if (buf_count(bp
) % vn
->sc_secsize
!= 0) {
811 sz
= howmany(buf_count(bp
), vn
->sc_secsize
);
814 * If out of bounds return an error. If at the EOF point,
815 * simply read or write less.
817 if (blk_num
>= 0 && (u_int64_t
)blk_num
>= vn
->sc_size
) {
818 if (blk_num
> 0 && (u_int64_t
)blk_num
> vn
->sc_size
) {
824 * If the request crosses EOF, truncate the request.
826 if ((blk_num
+ sz
) > 0 && ((u_int64_t
)(blk_num
+ sz
)) > vn
->sc_size
) {
827 buf_setcount(bp
, (vn
->sc_size
- blk_num
) * vn
->sc_secsize
);
828 buf_setresid(bp
, buf_count(bp
));
835 error
= vnode_getwithvid(vp
, vn
->sc_vid
);
837 /* the vnode is no longer available, abort */
842 shadow_vp
= vn
->sc_shadow_vp
;
843 if (shadow_vp
!= NULL
) {
844 error
= vnode_getwithvid(shadow_vp
,
847 /* the vnode is no longer available, abort */
849 vnode_put(vn
->sc_vp
);
854 error
= vn_readwrite_io(vn
, bp
, p
);
856 if (shadow_vp
!= NULL
) {
857 vnode_put(shadow_vp
);
861 (void) thread_funnel_set(kernel_flock
, funnel_state
);
863 buf_seterror(bp
, error
);
871 vnioctl(dev_t dev
, u_long cmd
, caddr_t data
,
872 __unused
int flag
, struct proc
*p
,
876 struct user_vn_ioctl
*viop
;
881 struct vfsioattr ioattr
;
882 struct user_vn_ioctl user_vnio
;
883 boolean_t funnel_state
;
886 if (vnunit(dev
) >= NVNDEVICE
) {
890 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
891 vn
= vn_table
+ unit
;
892 error
= proc_suser(p
);
897 viop
= (struct user_vn_ioctl
*)data
;
898 f
= (u_int32_t
*)data
;
899 o
= (u_int64_t
*)data
;
903 case DKIOCGETBLOCKSIZE
:
904 case DKIOCSETBLOCKSIZE
:
905 case DKIOCGETMAXBLOCKCOUNTREAD
:
906 case DKIOCGETMAXBLOCKCOUNTWRITE
:
907 case DKIOCGETMAXSEGMENTCOUNTREAD
:
908 case DKIOCGETMAXSEGMENTCOUNTWRITE
:
909 case DKIOCGETMAXSEGMENTBYTECOUNTREAD
:
910 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE
:
911 case DKIOCGETBLOCKCOUNT
:
912 case DKIOCGETBLOCKCOUNT32
:
913 if ((vn
->sc_flags
& VNF_INITED
) == 0) {
922 if (vn
->sc_vp
!= NULL
)
923 vfs_ioattr(vnode_mount(vn
->sc_vp
), &ioattr
);
925 bzero(&ioattr
, sizeof(ioattr
));
931 case DKIOCGETMAXBLOCKCOUNTREAD
:
932 *o
= ioattr
.io_maxreadcnt
/ vn
->sc_secsize
;
934 case DKIOCGETMAXBLOCKCOUNTWRITE
:
935 *o
= ioattr
.io_maxwritecnt
/ vn
->sc_secsize
;
937 case DKIOCGETMAXBYTECOUNTREAD
:
938 *o
= ioattr
.io_maxreadcnt
;
940 case DKIOCGETMAXBYTECOUNTWRITE
:
941 *o
= ioattr
.io_maxwritecnt
;
943 case DKIOCGETMAXSEGMENTCOUNTREAD
:
944 *o
= ioattr
.io_segreadcnt
;
946 case DKIOCGETMAXSEGMENTCOUNTWRITE
:
947 *o
= ioattr
.io_segwritecnt
;
949 case DKIOCGETMAXSEGMENTBYTECOUNTREAD
:
950 *o
= ioattr
.io_maxsegreadsize
;
952 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE
:
953 *o
= ioattr
.io_maxsegwritesize
;
955 case DKIOCGETBLOCKSIZE
:
958 case DKIOCSETBLOCKSIZE
:
960 /* can only set block size on block device */
964 if (*f
< DEV_BSIZE
) {
968 if (vn
->sc_shadow_vp
!= NULL
) {
969 if (*f
== (unsigned)vn
->sc_secsize
) {
972 /* can't change the block size if already shadowing */
977 /* recompute the size in terms of the new blocksize */
978 vn
->sc_size
= vn
->sc_fsize
/ vn
->sc_secsize
;
980 case DKIOCISWRITABLE
:
983 case DKIOCGETBLOCKCOUNT32
:
986 case DKIOCGETBLOCKCOUNT
:
991 if (vn
->sc_shadow_vp
!= NULL
) {
995 if (vn
->sc_vp
== NULL
) {
996 /* much be attached before we can shadow */
1000 if (!proc_is64bit(p
)) {
1001 /* downstream code expects LP64 version of vn_ioctl structure */
1002 vn_ioctl_to_64((struct vn_ioctl
*)viop
, &user_vnio
);
1005 if (viop
->vn_file
== USER_ADDR_NULL
) {
1009 error
= vniocattach_shadow(vn
, viop
, dev
, 0, p
);
1015 /* attach only on block device */
1019 if (vn
->sc_flags
& VNF_INITED
) {
1023 if (!proc_is64bit(p
)) {
1024 /* downstream code expects LP64 version of vn_ioctl structure */
1025 vn_ioctl_to_64((struct vn_ioctl
*)viop
, &user_vnio
);
1028 if (viop
->vn_file
== USER_ADDR_NULL
) {
1032 error
= vniocattach_file(vn
, viop
, dev
, 0, p
);
1038 /* detach only on block device */
1042 /* Note: spec_open won't open a mounted block device */
1045 * XXX handle i/o in progress. Return EBUSY, or wait, or
1047 * XXX handle multiple opens of the device. Return EBUSY,
1048 * or revoke the fd's.
1049 * How are these problems handled for removable and failing
1050 * hardware devices? (Hint: They are not)
1061 vn_options
&= ~(*f
);
1066 vn
->sc_options
|= *f
;
1067 *f
= vn
->sc_options
;
1071 vn
->sc_options
&= ~(*f
);
1072 *f
= vn
->sc_options
;
1080 (void) thread_funnel_set(kernel_flock
, funnel_state
);
1085 vnioctl_chr(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc
*p
)
1087 return (vnioctl(dev
, cmd
, data
, flag
, p
, TRUE
));
1091 vnioctl_blk(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc
*p
)
1093 return (vnioctl(dev
, cmd
, data
, flag
, p
, FALSE
));
1099 * Attach a file to a VN partition. Return the size in the vn_size
1104 vniocattach_file(struct vn_softc
*vn
,
1105 struct user_vn_ioctl
*vniop
,
1111 struct vfs_context context
;
1113 struct nameidata nd
;
1117 context
.vc_proc
= p
;
1118 context
.vc_ucred
= proc_ucred(p
);
1120 flags
= FREAD
|FWRITE
;
1122 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, vniop
->vn_file
, &context
);
1125 NDINIT(&nd
, LOOKUP
, FOLLOW
,
1126 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
1127 vniop
->vn_file
, &context
);
1129 /* vn_open gives both long- and short-term references */
1130 error
= vn_open(&nd
, flags
, 0);
1132 if (error
!= EACCES
&& error
!= EPERM
&& error
!= EROFS
)
1136 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
,
1137 vniop
->vn_file
, &context
);
1140 NDINIT(&nd
, LOOKUP
, FOLLOW
,
1141 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
1142 vniop
->vn_file
, &context
);
1144 error
= vn_open(&nd
, flags
, 0);
1148 if (nd
.ni_vp
->v_type
!= VREG
) {
1152 error
= vnode_size(nd
.ni_vp
, &file_size
, &context
);
1155 (void) vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1156 vnode_put(nd
.ni_vp
);
1159 cred
= kauth_cred_proc_ref(p
);
1160 nd
.ni_vp
->v_flag
|= VNOCACHE_DATA
;
1161 error
= setcred(nd
.ni_vp
, p
, cred
);
1163 (void)vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1164 vnode_put(nd
.ni_vp
);
1165 kauth_cred_rele(cred
);
1168 vn
->sc_secsize
= DEV_BSIZE
;
1169 vn
->sc_fsize
= file_size
;
1170 vn
->sc_size
= file_size
/ vn
->sc_secsize
;
1171 vn
->sc_vp
= nd
.ni_vp
;
1172 vn
->sc_vid
= vnode_vid(nd
.ni_vp
);
1173 vn
->sc_open_flags
= flags
;
1175 cdev
= makedev(vndevice_cdev_major
, minor(dev
));
1176 vn
->sc_cdev
= devfs_make_node(cdev
, DEVFS_CHAR
,
1177 UID_ROOT
, GID_OPERATOR
,
1180 vn
->sc_flags
|= VNF_INITED
;
1182 vn
->sc_flags
|= VNF_READONLY
;
1183 /* lose the short-term reference */
1184 vnode_put(nd
.ni_vp
);
1189 vniocattach_shadow(struct vn_softc
*vn
, struct user_vn_ioctl
*vniop
,
1190 __unused
int dev
, int in_kernel
, struct proc
*p
)
1192 struct vfs_context context
;
1193 struct nameidata nd
;
1198 context
.vc_proc
= p
;
1199 context
.vc_ucred
= proc_ucred(p
);
1201 flags
= FREAD
|FWRITE
;
1203 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, vniop
->vn_file
, &context
);
1206 NDINIT(&nd
, LOOKUP
, FOLLOW
,
1207 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
1208 vniop
->vn_file
, &context
);
1210 /* vn_open gives both long- and short-term references */
1211 error
= vn_open(&nd
, flags
, 0);
1213 /* shadow MUST be writable! */
1216 if (nd
.ni_vp
->v_type
!= VREG
1217 || (error
= vnode_size(nd
.ni_vp
, &file_size
, &context
))) {
1218 (void)vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1219 vnode_put(nd
.ni_vp
);
1220 return (error
? error
: EINVAL
);
1222 map
= shadow_map_create(vn
->sc_fsize
, file_size
,
1225 (void)vn_close(nd
.ni_vp
, flags
, proc_ucred(p
), p
);
1226 vnode_put(nd
.ni_vp
);
1227 vn
->sc_shadow_vp
= NULL
;
1230 vn
->sc_shadow_vp
= nd
.ni_vp
;
1231 vn
->sc_shadow_vid
= vnode_vid(nd
.ni_vp
);
1232 vn
->sc_shadow_vp
->v_flag
|= VNOCACHE_DATA
;
1233 vn
->sc_shadow_map
= map
;
1234 vn
->sc_flags
&= ~VNF_READONLY
; /* we're now read/write */
1236 /* lose the short-term reference */
1237 vnode_put(nd
.ni_vp
);
1242 vndevice_root_image(char * path
, char devname
[], dev_t
* dev_p
)
1245 struct vn_softc
* vn
;
1246 struct user_vn_ioctl vnio
;
1248 vnio
.vn_file
= CAST_USER_ADDR_T(path
);
1251 vn
= vn_table
+ ROOT_IMAGE_UNIT
;
1252 *dev_p
= makedev(vndevice_bdev_major
,
1254 sprintf(devname
, "vn%d", ROOT_IMAGE_UNIT
);
1255 error
= vniocattach_file(vn
, &vnio
, *dev_p
, 1, current_proc());
1260 * Duplicate the current processes' credentials. Since we are called only
1261 * as the result of a SET ioctl and only root can do that, any future access
1262 * to this "disk" is essentially as root. Note that credentials may change
1263 * if some other uid can write directly to the mapped file (NFS).
1266 setcred(struct vnode
* vp
, struct proc
* p
, kauth_cred_t cred
)
1270 struct vfs_context context
;
1273 * Horrible kludge to establish credentials for NFS XXX.
1275 context
.vc_proc
= p
;
1276 context
.vc_ucred
= cred
;
1277 tmpbuf
= _MALLOC(DEV_BSIZE
, M_TEMP
, M_WAITOK
);
1278 error
= file_io(vp
, &context
, UIO_READ
, tmpbuf
, 0, DEV_BSIZE
, NULL
);
1279 FREE(tmpbuf
, M_TEMP
);
1284 vnclear(struct vn_softc
*vn
, struct proc
* p
)
1286 if (vn
->sc_vp
!= NULL
) {
1287 /* release long-term reference */
1288 (void)vn_close(vn
->sc_vp
, vn
->sc_open_flags
, vn
->sc_cred
, p
);
1291 if (vn
->sc_shadow_vp
!= NULL
) {
1292 /* release long-term reference */
1293 (void)vn_close(vn
->sc_shadow_vp
, FREAD
| FWRITE
,
1295 vn
->sc_shadow_vp
= NULL
;
1297 if (vn
->sc_shadow_map
!= NULL
) {
1298 shadow_map_free(vn
->sc_shadow_map
);
1299 vn
->sc_shadow_map
= NULL
;
1301 vn
->sc_flags
&= ~(VNF_INITED
| VNF_READONLY
);
1303 kauth_cred_rele(vn
->sc_cred
);
1309 devfs_remove(vn
->sc_cdev
);
1318 struct vn_softc
*vn
;
1320 boolean_t funnel_state
;
1323 if (vnunit(dev
) >= NVNDEVICE
) {
1327 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
1328 vn
= vn_table
+ unit
;
1329 if ((vn
->sc_flags
& VNF_INITED
) == 0)
1332 secsize
= vn
->sc_secsize
;
1333 (void) thread_funnel_set(kernel_flock
, funnel_state
);
1337 #define CDEV_MAJOR -1
1338 #define BDEV_MAJOR -1
1339 static int vndevice_inited
= 0;
1346 if (vndevice_inited
)
1348 vndevice_bdev_major
= bdevsw_add(BDEV_MAJOR
, &vn_bdevsw
);
1350 if (vndevice_bdev_major
< 0) {
1351 printf("vndevice_init: bdevsw_add() returned %d\n",
1352 vndevice_bdev_major
);
1355 vndevice_cdev_major
= cdevsw_add_with_bdev(CDEV_MAJOR
, &vn_cdevsw
,
1356 vndevice_bdev_major
);
1357 if (vndevice_cdev_major
< 0) {
1358 printf("vndevice_init: cdevsw_add() returned %d\n",
1359 vndevice_cdev_major
);
1362 for (i
= 0; i
< NVNDEVICE
; i
++) {
1363 dev_t dev
= makedev(vndevice_bdev_major
, i
);
1364 vn_table
[i
].sc_bdev
= devfs_make_node(dev
, DEVFS_BLOCK
,
1365 UID_ROOT
, GID_OPERATOR
,
1368 if (vn_table
[i
].sc_bdev
== NULL
)
1369 printf("vninit: devfs_make_node failed!\n");
1374 vn_ioctl_to_64(struct vn_ioctl
*from
, struct user_vn_ioctl
*to
)
1376 to
->vn_file
= CAST_USER_ADDR_T(from
->vn_file
);
1377 to
->vn_size
= from
->vn_size
;
1378 to
->vn_control
= from
->vn_control
;
1381 #endif /* NVNDEVICE */