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