1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: Utah Hdr: vn.c 1.13 94/04/02 39 * 40 * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 41 * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $ 42 * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.38 2008/07/01 02:02:53 dillon Exp $ 43 */ 44 45 /* 46 * Vnode disk driver. 47 * 48 * Block/character interface to a vnode. Allows one to treat a file 49 * as a disk (e.g. build a filesystem in it, mount it, etc.). 50 * 51 * NOTE 1: There is a security issue involved with this driver. 52 * Once mounted all access to the contents of the "mapped" file via 53 * the special file is controlled by the permissions on the special 54 * file, the protection of the mapped file is ignored (effectively, 55 * by using root credentials in all transactions). 56 * 57 * NOTE 2: Doesn't interact with leases, should it? 58 */ 59 60 #include "use_vn.h" 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/kernel.h> 64 #include <sys/proc.h> 65 #include <sys/priv.h> 66 #include <sys/nlookup.h> 67 #include <sys/buf.h> 68 #include <sys/malloc.h> 69 #include <sys/mount.h> 70 #include <sys/vnode.h> 71 #include <sys/fcntl.h> 72 #include <sys/conf.h> 73 #include <sys/diskslice.h> 74 #include <sys/disk.h> 75 #include <sys/stat.h> 76 #include <sys/module.h> 77 #include <sys/vnioctl.h> 78 79 #include <vm/vm.h> 80 #include <vm/vm_object.h> 81 #include <vm/vm_page.h> 82 #include <vm/vm_pager.h> 83 #include <vm/vm_pageout.h> 84 #include <vm/swap_pager.h> 85 #include <vm/vm_extern.h> 86 #include <vm/vm_zone.h> 87 #include <sys/devfs.h> 88 89 static d_ioctl_t vnioctl; 90 static d_open_t vnopen; 91 static d_close_t vnclose; 92 static d_psize_t vnsize; 93 static d_strategy_t vnstrategy; 94 static d_clone_t vnclone; 95 96 DEVFS_DECLARE_CLONE_BITMAP(vn); 97 98 #if NVN <= 1 99 #define VN_PREALLOCATED_UNITS 4 100 #else 101 #define VN_PREALLOCATED_UNITS NVN 102 #endif 103 104 #define CDEV_MAJOR 43 105 106 #define VN_BSIZE_BEST 8192 107 108 /* 109 * dev_ops 110 * D_DISK we want to look like a disk 111 * D_CANFREE We support BUF_CMD_FREEBLKS 112 */ 113 114 static struct dev_ops vn_ops = { 115 { "vn", CDEV_MAJOR, D_DISK | D_CANFREE }, 116 .d_open = vnopen, 117 .d_close = vnclose, 118 .d_read = physread, 119 .d_write = physwrite, 120 .d_ioctl = vnioctl, 121 .d_strategy = vnstrategy, 122 .d_psize = vnsize 123 }; 124 125 struct vn_softc { 126 int sc_unit; 127 int sc_flags; /* flags */ 128 u_int64_t sc_size; /* size of vn, sc_secsize scale */ 129 int sc_secsize; /* sector size */ 130 struct disk sc_disk; 131 struct vnode *sc_vp; /* vnode if not NULL */ 132 vm_object_t sc_object; /* backing object if not NULL */ 133 struct ucred *sc_cred; /* credentials */ 134 int sc_maxactive; /* max # of active requests */ 135 struct buf sc_tab; /* transfer queue */ 136 u_long sc_options; /* options */ 137 cdev_t sc_devlist; /* devices that refer to this unit */ 138 SLIST_ENTRY(vn_softc) sc_list; 139 }; 140 141 static SLIST_HEAD(, vn_softc) vn_list; 142 143 /* sc_flags */ 144 #define VNF_INITED 0x01 145 #define VNF_READONLY 0x02 146 147 static u_long vn_options; 148 149 #define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt)) 150 #define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt)) 151 152 static int vnsetcred (struct vn_softc *vn, struct ucred *cred); 153 static void vnclear (struct vn_softc *vn); 154 static int vnget (cdev_t dev, struct vn_softc *vn , struct vn_user *vnu); 155 static int vn_modevent (module_t, int, void *); 156 static int vniocattach_file (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred); 157 static int vniocattach_swap (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred); 158 static cdev_t vn_create(int unit, struct devfs_bitmap *bitmap); 159 160 static int 161 vnclone(struct dev_clone_args *ap) 162 { 163 int unit; 164 165 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(vn), 0); 166 ap->a_dev = vn_create(unit, &DEVFS_CLONE_BITMAP(vn)); 167 168 return 0; 169 } 170 171 static int 172 vnclose(struct dev_close_args *ap) 173 { 174 return (0); 175 } 176 177 static struct vn_softc * 178 vncreatevn(void) 179 { 180 struct vn_softc *vn; 181 182 vn = kmalloc(sizeof *vn, M_DEVBUF, M_WAITOK | M_ZERO); 183 return vn; 184 } 185 186 static void 187 vninitvn(struct vn_softc *vn, cdev_t dev) 188 { 189 int unit; 190 191 KKASSERT(vn != NULL); 192 KKASSERT(dev != NULL); 193 unit = dkunit(dev); 194 195 vn->sc_unit = unit; 196 dev->si_drv1 = vn; 197 vn->sc_devlist = dev; 198 if (vn->sc_devlist->si_drv1 == NULL) { 199 reference_dev(vn->sc_devlist); 200 vn->sc_devlist->si_drv1 = vn; 201 vn->sc_devlist->si_drv2 = NULL; 202 } 203 if (vn->sc_devlist != dev) { 204 dev->si_drv1 = vn; 205 dev->si_drv2 = vn->sc_devlist; 206 vn->sc_devlist = dev; 207 reference_dev(dev); 208 } 209 SLIST_INSERT_HEAD(&vn_list, vn, sc_list); 210 } 211 212 /* 213 * Called only when si_drv1 is NULL. Locate the associated vn node and 214 * attach the device to it. 215 */ 216 static struct vn_softc * 217 vnfindvn(cdev_t dev) 218 { 219 int unit; 220 struct vn_softc *vn; 221 222 unit = dkunit(dev); 223 SLIST_FOREACH(vn, &vn_list, sc_list) { 224 if (vn->sc_unit == unit) { 225 dev->si_drv1 = vn; 226 dev->si_drv2 = vn->sc_devlist; 227 vn->sc_devlist = dev; 228 reference_dev(dev); 229 break; 230 } 231 } 232 233 KKASSERT(vn != NULL); 234 235 return vn; 236 } 237 238 static int 239 vnopen(struct dev_open_args *ap) 240 { 241 cdev_t dev = ap->a_head.a_dev; 242 struct vn_softc *vn; 243 244 /* 245 * Locate preexisting device 246 */ 247 248 if ((vn = dev->si_drv1) == NULL) 249 vn = vnfindvn(dev); 250 251 /* 252 * Update si_bsize fields for device. This data will be overriden by 253 * the slice/parition code for vn accesses through partitions, and 254 * used directly if you open the 'whole disk' device. 255 * 256 * si_bsize_best must be reinitialized in case VN has been 257 * reconfigured, plus make it at least VN_BSIZE_BEST for efficiency. 258 */ 259 dev->si_bsize_phys = vn->sc_secsize; 260 dev->si_bsize_best = vn->sc_secsize; 261 if (dev->si_bsize_best < VN_BSIZE_BEST) 262 dev->si_bsize_best = VN_BSIZE_BEST; 263 264 if ((ap->a_oflags & FWRITE) && (vn->sc_flags & VNF_READONLY)) 265 return (EACCES); 266 267 IFOPT(vn, VN_FOLLOW) 268 kprintf("vnopen(%s, 0x%x, 0x%x)\n", 269 devtoname(dev), ap->a_oflags, ap->a_devtype); 270 271 return(0); 272 } 273 274 /* 275 * vnstrategy: 276 * 277 * Run strategy routine for VN device. We use VOP_READ/VOP_WRITE calls 278 * for vnode-backed vn's, and the swap_pager_strategy() call for 279 * vm_object-backed vn's. 280 */ 281 static int 282 vnstrategy(struct dev_strategy_args *ap) 283 { 284 cdev_t dev = ap->a_head.a_dev; 285 struct bio *bio = ap->a_bio; 286 struct buf *bp; 287 struct bio *nbio; 288 int unit; 289 struct vn_softc *vn; 290 int error; 291 292 unit = dkunit(dev); 293 if ((vn = dev->si_drv1) == NULL) 294 vn = vnfindvn(dev); 295 296 bp = bio->bio_buf; 297 298 IFOPT(vn, VN_DEBUG) 299 kprintf("vnstrategy(%p): unit %d\n", bp, unit); 300 301 if ((vn->sc_flags & VNF_INITED) == 0) { 302 bp->b_error = ENXIO; 303 bp->b_flags |= B_ERROR; 304 biodone(bio); 305 return(0); 306 } 307 308 bp->b_resid = bp->b_bcount; 309 310 /* 311 * The vnode device is using disk/slice label support. 312 * 313 * The dscheck() function is called for validating the 314 * slices that exist ON the vnode device itself, and 315 * translate the "slice-relative" block number, again. 316 * dscheck() will call biodone() and return NULL if 317 * we are at EOF or beyond the device size. 318 */ 319 320 nbio = bio; 321 322 /* 323 * Use the translated nbio from this point on 324 */ 325 if (vn->sc_vp && bp->b_cmd == BUF_CMD_FREEBLKS) { 326 /* 327 * Freeblks is not handled for vnode-backed elements yet. 328 */ 329 bp->b_resid = 0; 330 /* operation complete */ 331 } else if (vn->sc_vp) { 332 /* 333 * VNODE I/O 334 * 335 * If an error occurs, we set B_ERROR but we do not set 336 * B_INVAL because (for a write anyway), the buffer is 337 * still valid. 338 */ 339 struct uio auio; 340 struct iovec aiov; 341 342 bzero(&auio, sizeof(auio)); 343 344 aiov.iov_base = bp->b_data; 345 aiov.iov_len = bp->b_bcount; 346 auio.uio_iov = &aiov; 347 auio.uio_iovcnt = 1; 348 auio.uio_offset = nbio->bio_offset; 349 auio.uio_segflg = UIO_SYSSPACE; 350 if (bp->b_cmd == BUF_CMD_READ) 351 auio.uio_rw = UIO_READ; 352 else 353 auio.uio_rw = UIO_WRITE; 354 auio.uio_resid = bp->b_bcount; 355 auio.uio_td = curthread; 356 357 /* 358 * Don't use IO_DIRECT here, it really gets in the way 359 * due to typical blocksize differences between the 360 * fs backing the VN device and whatever is running on 361 * the VN device. 362 */ 363 if (bp->b_cmd == BUF_CMD_READ) { 364 vn_lock(vn->sc_vp, LK_SHARED | LK_RETRY); 365 error = VOP_READ(vn->sc_vp, &auio, IO_RECURSE, 366 vn->sc_cred); 367 } else { 368 vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY); 369 error = VOP_WRITE(vn->sc_vp, &auio, IO_RECURSE, 370 vn->sc_cred); 371 } 372 vn_unlock(vn->sc_vp); 373 bp->b_resid = auio.uio_resid; 374 if (error) { 375 bp->b_error = error; 376 bp->b_flags |= B_ERROR; 377 } 378 /* operation complete */ 379 } else if (vn->sc_object) { 380 /* 381 * OBJT_SWAP I/O (handles read, write, freebuf) 382 * 383 * We have nothing to do if freeing blocks on a reserved 384 * swap area, othrewise execute the op. 385 */ 386 if (bp->b_cmd == BUF_CMD_FREEBLKS && TESTOPT(vn, VN_RESERVE)) { 387 bp->b_resid = 0; 388 /* operation complete */ 389 } else { 390 swap_pager_strategy(vn->sc_object, nbio); 391 return(0); 392 /* NOT REACHED */ 393 } 394 } else { 395 bp->b_resid = bp->b_bcount; 396 bp->b_flags |= B_ERROR | B_INVAL; 397 bp->b_error = EINVAL; 398 /* operation complete */ 399 } 400 biodone(nbio); 401 return(0); 402 } 403 404 /* ARGSUSED */ 405 static int 406 vnioctl(struct dev_ioctl_args *ap) 407 { 408 cdev_t dev = ap->a_head.a_dev; 409 struct vn_softc *vn; 410 struct vn_ioctl *vio; 411 int error; 412 u_long *f; 413 414 vn = dev->si_drv1; 415 IFOPT(vn,VN_FOLLOW) { 416 kprintf("vnioctl(%s, 0x%lx, %p, 0x%x): unit %d\n", 417 devtoname(dev), ap->a_cmd, ap->a_data, ap->a_fflag, 418 dkunit(dev)); 419 } 420 421 switch (ap->a_cmd) { 422 case VNIOCATTACH: 423 case VNIOCDETACH: 424 case VNIOCGSET: 425 case VNIOCGCLEAR: 426 case VNIOCGET: 427 case VNIOCUSET: 428 case VNIOCUCLEAR: 429 goto vn_specific; 430 } 431 432 #if 0 433 if (dkslice(dev) != WHOLE_DISK_SLICE || 434 dkpart(dev) != WHOLE_SLICE_PART) 435 return (ENOTTY); 436 #endif 437 438 vn_specific: 439 440 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0); 441 if (error) 442 return (error); 443 444 vio = (struct vn_ioctl *)ap->a_data; 445 f = (u_long*)ap->a_data; 446 447 switch (ap->a_cmd) { 448 case VNIOCATTACH: 449 if (vn->sc_flags & VNF_INITED) 450 return(EBUSY); 451 452 if (vio->vn_file == NULL) 453 error = vniocattach_swap(vn, vio, dev, ap->a_fflag, ap->a_cred); 454 else 455 error = vniocattach_file(vn, vio, dev, ap->a_fflag, ap->a_cred); 456 break; 457 458 case VNIOCDETACH: 459 if ((vn->sc_flags & VNF_INITED) == 0) 460 return(ENXIO); 461 /* 462 * XXX handle i/o in progress. Return EBUSY, or wait, or 463 * flush the i/o. 464 * XXX handle multiple opens of the device. Return EBUSY, 465 * or revoke the fd's. 466 * How are these problems handled for removable and failing 467 * hardware devices? (Hint: They are not) 468 */ 469 if (count_dev(vn->sc_devlist) > 1) 470 return (EBUSY); 471 472 vnclear(vn); 473 IFOPT(vn, VN_FOLLOW) 474 kprintf("vnioctl: CLRed\n"); 475 476 if (dkunit(dev) >= VN_PREALLOCATED_UNITS) { 477 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(vn), dkunit(dev)); 478 disk_destroy(&vn->sc_disk); 479 SLIST_REMOVE(&vn_list, vn, vn_softc, sc_list); 480 } 481 482 break; 483 484 case VNIOCGET: 485 error = vnget(dev, vn, (struct vn_user *) ap->a_data); 486 break; 487 488 case VNIOCGSET: 489 vn_options |= *f; 490 *f = vn_options; 491 break; 492 493 case VNIOCGCLEAR: 494 vn_options &= ~(*f); 495 *f = vn_options; 496 break; 497 498 case VNIOCUSET: 499 vn->sc_options |= *f; 500 *f = vn->sc_options; 501 break; 502 503 case VNIOCUCLEAR: 504 vn->sc_options &= ~(*f); 505 *f = vn->sc_options; 506 break; 507 508 default: 509 error = ENOTTY; 510 break; 511 } 512 return(error); 513 } 514 515 /* 516 * vniocattach_file: 517 * 518 * Attach a file to a VN partition. Return the size in the vn_size 519 * field. 520 */ 521 522 static int 523 vniocattach_file(struct vn_softc *vn, struct vn_ioctl *vio, cdev_t dev, 524 int flag, struct ucred *cred) 525 { 526 struct vattr vattr; 527 struct nlookupdata nd; 528 int error, flags; 529 struct vnode *vp; 530 struct disk_info info; 531 532 flags = FREAD|FWRITE; 533 error = nlookup_init(&nd, vio->vn_file, 534 UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); 535 if (error) 536 return (error); 537 if ((error = vn_open(&nd, NULL, flags, 0)) != 0) { 538 if (error != EACCES && error != EPERM && error != EROFS) 539 goto done; 540 flags &= ~FWRITE; 541 nlookup_done(&nd); 542 error = nlookup_init(&nd, vio->vn_file, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); 543 if (error) 544 return (error); 545 if ((error = vn_open(&nd, NULL, flags, 0)) != 0) 546 goto done; 547 } 548 vp = nd.nl_open_vp; 549 if (vp->v_type != VREG || 550 (error = VOP_GETATTR(vp, &vattr))) { 551 if (error == 0) 552 error = EINVAL; 553 goto done; 554 } 555 vn_unlock(vp); 556 vn->sc_secsize = DEV_BSIZE; 557 vn->sc_vp = vp; 558 nd.nl_open_vp = NULL; 559 560 /* 561 * If the size is specified, override the file attributes. Note that 562 * the vn_size argument is in PAGE_SIZE sized blocks. 563 */ 564 if (vio->vn_size) 565 vn->sc_size = vio->vn_size * PAGE_SIZE / vn->sc_secsize; 566 else 567 vn->sc_size = vattr.va_size / vn->sc_secsize; 568 error = vnsetcred(vn, cred); 569 if (error) { 570 vn->sc_vp = NULL; 571 vn_close(vp, flags); 572 goto done; 573 } 574 vn->sc_flags |= VNF_INITED; 575 if (flags == FREAD) 576 vn->sc_flags |= VNF_READONLY; 577 578 /* 579 * Set the disk info so that probing is triggered 580 */ 581 bzero(&info, sizeof(struct disk_info)); 582 info.d_media_blksize = vn->sc_secsize; 583 info.d_media_blocks = vn->sc_size; 584 /* 585 * reserve mbr sector for backwards compatibility 586 * when no slices exist. 587 */ 588 info.d_dsflags = DSO_COMPATMBR; 589 info.d_secpertrack = 32; 590 info.d_nheads = 64 / (vn->sc_secsize / DEV_BSIZE); 591 info.d_secpercyl = info.d_secpertrack * info.d_nheads; 592 info.d_ncylinders = vn->sc_size / info.d_secpercyl; 593 disk_setdiskinfo_sync(&vn->sc_disk, &info); 594 595 error = dev_dopen(dev, flag, S_IFCHR, cred); 596 if (error) 597 vnclear(vn); 598 599 IFOPT(vn, VN_FOLLOW) 600 kprintf("vnioctl: SET vp %p size %llx blks\n", 601 vn->sc_vp, (long long)vn->sc_size); 602 done: 603 nlookup_done(&nd); 604 return(error); 605 } 606 607 /* 608 * vniocattach_swap: 609 * 610 * Attach swap backing store to a VN partition of the size specified 611 * in vn_size. 612 */ 613 614 static int 615 vniocattach_swap(struct vn_softc *vn, struct vn_ioctl *vio, cdev_t dev, 616 int flag, struct ucred *cred) 617 { 618 int error; 619 struct disk_info info; 620 621 /* 622 * Range check. Disallow negative sizes or any size less then the 623 * size of a page. Then round to a page. 624 */ 625 626 if (vio->vn_size <= 0) 627 return(EDOM); 628 629 /* 630 * Allocate an OBJT_SWAP object. 631 * 632 * sc_secsize is PAGE_SIZE'd 633 * 634 * vio->vn_size is in PAGE_SIZE'd chunks. 635 * sc_size must be in PAGE_SIZE'd chunks. 636 * Note the truncation. 637 */ 638 639 vn->sc_secsize = PAGE_SIZE; 640 vn->sc_size = vio->vn_size; 641 vn->sc_object = swap_pager_alloc(NULL, 642 vn->sc_secsize * (off_t)vio->vn_size, 643 VM_PROT_DEFAULT, 0); 644 IFOPT(vn, VN_RESERVE) { 645 if (swap_pager_reserve(vn->sc_object, 0, vn->sc_size) < 0) { 646 vm_pager_deallocate(vn->sc_object); 647 vn->sc_object = NULL; 648 return(EDOM); 649 } 650 } 651 vn->sc_flags |= VNF_INITED; 652 653 error = vnsetcred(vn, cred); 654 if (error == 0) { 655 /* 656 * Set the disk info so that probing is triggered 657 */ 658 bzero(&info, sizeof(struct disk_info)); 659 info.d_media_blksize = vn->sc_secsize; 660 info.d_media_blocks = vn->sc_size; 661 /* 662 * reserve mbr sector for backwards compatibility 663 * when no slices exist. 664 */ 665 info.d_dsflags = DSO_COMPATMBR; 666 info.d_secpertrack = 32; 667 info.d_nheads = 64 / (vn->sc_secsize / DEV_BSIZE); 668 info.d_secpercyl = info.d_secpertrack * info.d_nheads; 669 info.d_ncylinders = vn->sc_size / info.d_secpercyl; 670 disk_setdiskinfo_sync(&vn->sc_disk, &info); 671 672 error = dev_dopen(dev, flag, S_IFCHR, cred); 673 } 674 if (error == 0) { 675 IFOPT(vn, VN_FOLLOW) { 676 kprintf("vnioctl: SET vp %p size %llx\n", 677 vn->sc_vp, (long long)vn->sc_size); 678 } 679 } 680 if (error) 681 vnclear(vn); 682 return(error); 683 } 684 685 /* 686 * Duplicate the current processes' credentials. Since we are called only 687 * as the result of a SET ioctl and only root can do that, any future access 688 * to this "disk" is essentially as root. Note that credentials may change 689 * if some other uid can write directly to the mapped file (NFS). 690 */ 691 int 692 vnsetcred(struct vn_softc *vn, struct ucred *cred) 693 { 694 char *tmpbuf; 695 int error = 0; 696 697 /* 698 * Set credits in our softc 699 */ 700 701 if (vn->sc_cred) 702 crfree(vn->sc_cred); 703 vn->sc_cred = crdup(cred); 704 705 /* 706 * Horrible kludge to establish credentials for NFS XXX. 707 */ 708 709 if (vn->sc_vp) { 710 struct uio auio; 711 struct iovec aiov; 712 713 tmpbuf = kmalloc(vn->sc_secsize, M_TEMP, M_WAITOK); 714 bzero(&auio, sizeof(auio)); 715 716 aiov.iov_base = tmpbuf; 717 aiov.iov_len = vn->sc_secsize; 718 auio.uio_iov = &aiov; 719 auio.uio_iovcnt = 1; 720 auio.uio_offset = 0; 721 auio.uio_rw = UIO_READ; 722 auio.uio_segflg = UIO_SYSSPACE; 723 auio.uio_resid = aiov.iov_len; 724 vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY); 725 error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred); 726 vn_unlock(vn->sc_vp); 727 kfree(tmpbuf, M_TEMP); 728 } 729 return (error); 730 } 731 732 void 733 vnclear(struct vn_softc *vn) 734 { 735 IFOPT(vn, VN_FOLLOW) 736 kprintf("vnclear(%p): vp=%p\n", vn, vn->sc_vp); 737 vn->sc_flags &= ~VNF_INITED; 738 if (vn->sc_vp != NULL) { 739 vn_close(vn->sc_vp, 740 (vn->sc_flags & VNF_READONLY) ? FREAD : (FREAD|FWRITE)); 741 vn->sc_vp = NULL; 742 } 743 vn->sc_flags &= ~VNF_READONLY; 744 if (vn->sc_cred) { 745 crfree(vn->sc_cred); 746 vn->sc_cred = NULL; 747 } 748 if (vn->sc_object != NULL) { 749 vm_pager_deallocate(vn->sc_object); 750 vn->sc_object = NULL; 751 } 752 753 disk_unprobe(&vn->sc_disk); 754 755 vn->sc_size = 0; 756 } 757 758 /* 759 * vnget: 760 * 761 * populate a struct vn_user for the VNIOCGET ioctl. 762 * interface conventions defined in sys/sys/vnioctl.h. 763 */ 764 765 static int 766 vnget(cdev_t dev, struct vn_softc *vn, struct vn_user *vnu) 767 { 768 int error, found = 0; 769 char *freepath, *fullpath; 770 struct vattr vattr; 771 772 if (vnu->vnu_unit == -1) { 773 vnu->vnu_unit = dkunit(dev); 774 } 775 else if (vnu->vnu_unit < 0) 776 return (EINVAL); 777 778 SLIST_FOREACH(vn, &vn_list, sc_list) { 779 780 if(vn->sc_unit != vnu->vnu_unit) 781 continue; 782 783 found = 1; 784 785 if (vn->sc_flags & VNF_INITED && vn->sc_vp != NULL) { 786 787 /* note: u_cred checked in vnioctl above */ 788 error = VOP_GETATTR(vn->sc_vp, &vattr); 789 if (error) { 790 kprintf("vnget: VOP_GETATTR for %p failed\n", 791 vn->sc_vp); 792 return (error); 793 } 794 795 error = vn_fullpath(curproc, vn->sc_vp, 796 &fullpath, &freepath, 0); 797 798 if (error) { 799 kprintf("vnget: unable to resolve vp %p\n", 800 vn->sc_vp); 801 return(error); 802 } 803 804 strlcpy(vnu->vnu_file, fullpath, 805 sizeof(vnu->vnu_file)); 806 kfree(freepath, M_TEMP); 807 vnu->vnu_dev = vattr.va_fsid; 808 vnu->vnu_ino = vattr.va_fileid; 809 810 } 811 else if (vn->sc_flags & VNF_INITED && vn->sc_object != NULL){ 812 813 strlcpy(vnu->vnu_file, _VN_USER_SWAP, 814 sizeof(vnu->vnu_file)); 815 vnu->vnu_size = vn->sc_size; 816 vnu->vnu_secsize = vn->sc_secsize; 817 818 } else { 819 820 bzero(vnu->vnu_file, sizeof(vnu->vnu_file)); 821 vnu->vnu_dev = 0; 822 vnu->vnu_ino = 0; 823 824 } 825 break; 826 } 827 828 if (!found) 829 return(ENXIO); 830 831 return(0); 832 } 833 834 static int 835 vnsize(struct dev_psize_args *ap) 836 { 837 cdev_t dev = ap->a_head.a_dev; 838 struct vn_softc *vn; 839 840 vn = dev->si_drv1; 841 if (!vn) 842 return(ENXIO); 843 if ((vn->sc_flags & VNF_INITED) == 0) 844 return(ENXIO); 845 ap->a_result = (int64_t)vn->sc_size; 846 return(0); 847 } 848 849 static cdev_t 850 vn_create(int unit, struct devfs_bitmap *bitmap) 851 { 852 struct vn_softc *vn; 853 struct disk_info info; 854 cdev_t dev; 855 856 vn = vncreatevn(); 857 dev = disk_create(unit, &vn->sc_disk, &vn_ops); 858 vninitvn(vn, dev); 859 860 bzero(&info, sizeof(struct disk_info)); 861 info.d_media_blksize = 512; 862 info.d_media_blocks = 0; 863 info.d_dsflags = DSO_MBRQUIET; 864 info.d_secpertrack = 32; 865 info.d_nheads = 64; 866 info.d_secpercyl = info.d_secpertrack * info.d_nheads; 867 info.d_ncylinders = 0; 868 disk_setdiskinfo_sync(&vn->sc_disk, &info); 869 870 if (bitmap != NULL) 871 devfs_clone_bitmap_set(bitmap, unit); 872 873 return dev; 874 } 875 876 static int 877 vn_modevent(module_t mod, int type, void *data) 878 { 879 struct vn_softc *vn; 880 static cdev_t dev = NULL; 881 int i; 882 883 switch (type) { 884 case MOD_LOAD: 885 dev = make_autoclone_dev(&vn_ops, &DEVFS_CLONE_BITMAP(vn), vnclone, UID_ROOT, 886 GID_OPERATOR, 0640, "vn"); 887 888 for (i = 0; i < VN_PREALLOCATED_UNITS; i++) { 889 vn_create(i, &DEVFS_CLONE_BITMAP(vn)); 890 } 891 break; 892 case MOD_UNLOAD: 893 destroy_autoclone_dev(dev, &DEVFS_CLONE_BITMAP(vn)); 894 /* fall through */ 895 case MOD_SHUTDOWN: 896 while ((vn = SLIST_FIRST(&vn_list)) != NULL) { 897 SLIST_REMOVE_HEAD(&vn_list, sc_list); 898 if (vn->sc_flags & VNF_INITED) 899 vnclear(vn); 900 /* Cleanup all cdev_t's that refer to this unit */ 901 disk_destroy(&vn->sc_disk); 902 while ((dev = vn->sc_devlist) != NULL) { 903 vn->sc_devlist = dev->si_drv2; 904 dev->si_drv1 = dev->si_drv2 = NULL; 905 destroy_dev(dev); 906 } 907 kfree(vn, M_DEVBUF); 908 } 909 dev_ops_remove_all(&vn_ops); 910 break; 911 default: 912 break; 913 } 914 return 0; 915 } 916 917 DEV_MODULE(vn, vn_modevent, 0); 918