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.24 2006/05/06 02:43:03 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 <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/kernel.h> 63 #include <sys/proc.h> 64 #include <sys/nlookup.h> 65 #include <sys/buf.h> 66 #include <sys/malloc.h> 67 #include <sys/mount.h> 68 #include <sys/vnode.h> 69 #include <sys/fcntl.h> 70 #include <sys/conf.h> 71 #include <sys/disklabel.h> 72 #include <sys/diskslice.h> 73 #include <sys/stat.h> 74 #include <sys/module.h> 75 #include <sys/vnioctl.h> 76 77 #include <vm/vm.h> 78 #include <vm/vm_object.h> 79 #include <vm/vm_page.h> 80 #include <vm/vm_pager.h> 81 #include <vm/vm_pageout.h> 82 #include <vm/swap_pager.h> 83 #include <vm/vm_extern.h> 84 #include <vm/vm_zone.h> 85 86 static d_ioctl_t vnioctl; 87 static d_open_t vnopen; 88 static d_close_t vnclose; 89 static d_psize_t vnsize; 90 static d_strategy_t vnstrategy; 91 92 #define CDEV_MAJOR 43 93 94 #define VN_BSIZE_BEST 8192 95 96 /* 97 * cdevsw 98 * D_DISK we want to look like a disk 99 * D_CANFREE We support BUF_CMD_FREEBLKS 100 */ 101 102 static struct cdevsw vn_cdevsw = { 103 /* name */ "vn", 104 /* maj */ CDEV_MAJOR, 105 /* flags */ D_DISK|D_CANFREE, 106 /* port */ NULL, 107 /* clone */ NULL, 108 109 /* open */ vnopen, 110 /* close */ vnclose, 111 /* read */ physread, 112 /* write */ physwrite, 113 /* ioctl */ vnioctl, 114 /* poll */ nopoll, 115 /* mmap */ nommap, 116 /* strategy */ vnstrategy, 117 /* dump */ nodump, 118 /* psize */ vnsize 119 }; 120 121 struct vn_softc { 122 int sc_unit; 123 int sc_flags; /* flags */ 124 int sc_size; /* size of vn, sc_secsize scale */ 125 int sc_secsize; /* sector size */ 126 struct diskslices *sc_slices; 127 struct vnode *sc_vp; /* vnode if not NULL */ 128 vm_object_t sc_object; /* backing object if not NULL */ 129 struct ucred *sc_cred; /* credentials */ 130 int sc_maxactive; /* max # of active requests */ 131 struct buf sc_tab; /* transfer queue */ 132 u_long sc_options; /* options */ 133 dev_t sc_devlist; /* devices that refer to this unit */ 134 SLIST_ENTRY(vn_softc) sc_list; 135 }; 136 137 static SLIST_HEAD(, vn_softc) vn_list; 138 139 /* sc_flags */ 140 #define VNF_INITED 0x01 141 #define VNF_READONLY 0x02 142 143 static u_long vn_options; 144 145 #define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt)) 146 #define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt)) 147 148 static int vnsetcred (struct vn_softc *vn, struct ucred *cred); 149 static void vnclear (struct vn_softc *vn); 150 static int vn_modevent (module_t, int, void *); 151 static int vniocattach_file (struct vn_softc *, struct vn_ioctl *, dev_t dev, int flag, struct thread *p); 152 static int vniocattach_swap (struct vn_softc *, struct vn_ioctl *, dev_t dev, int flag, struct thread *p); 153 154 static int 155 vnclose(dev_t dev, int flags, int mode, struct thread *td) 156 { 157 struct vn_softc *vn = dev->si_drv1; 158 159 IFOPT(vn, VN_LABELS) 160 if (vn->sc_slices != NULL) 161 dsclose(dev, mode, vn->sc_slices); 162 return (0); 163 } 164 165 /* 166 * Called only when si_drv1 is NULL. Locate the associated vn node and 167 * attach the device to it. 168 */ 169 static struct vn_softc * 170 vnfindvn(dev_t dev) 171 { 172 int unit; 173 struct vn_softc *vn; 174 175 unit = dkunit(dev); 176 SLIST_FOREACH(vn, &vn_list, sc_list) { 177 if (vn->sc_unit == unit) { 178 dev->si_drv1 = vn; 179 dev->si_drv2 = vn->sc_devlist; 180 vn->sc_devlist = dev; 181 reference_dev(dev); 182 break; 183 } 184 } 185 if (vn == NULL) { 186 vn = malloc(sizeof *vn, M_DEVBUF, M_WAITOK | M_ZERO); 187 vn->sc_unit = unit; 188 dev->si_drv1 = vn; 189 vn->sc_devlist = make_dev(&vn_cdevsw, 0, UID_ROOT, 190 GID_OPERATOR, 0640, "vn%d", unit); 191 if (vn->sc_devlist->si_drv1 == NULL) { 192 reference_dev(vn->sc_devlist); 193 vn->sc_devlist->si_drv1 = vn; 194 vn->sc_devlist->si_drv2 = NULL; 195 } 196 if (vn->sc_devlist != dev) { 197 dev->si_drv1 = vn; 198 dev->si_drv2 = vn->sc_devlist; 199 vn->sc_devlist = dev; 200 reference_dev(dev); 201 } 202 SLIST_INSERT_HEAD(&vn_list, vn, sc_list); 203 } 204 return (vn); 205 } 206 207 static int 208 vnopen(dev_t dev, int flags, int mode, struct thread *td) 209 { 210 struct vn_softc *vn; 211 212 /* 213 * Locate preexisting device 214 */ 215 216 if ((vn = dev->si_drv1) == NULL) 217 vn = vnfindvn(dev); 218 219 /* 220 * Update si_bsize fields for device. This data will be overriden by 221 * the slice/parition code for vn accesses through partitions, and 222 * used directly if you open the 'whole disk' device. 223 * 224 * si_bsize_best must be reinitialized in case VN has been 225 * reconfigured, plus make it at least VN_BSIZE_BEST for efficiency. 226 */ 227 dev->si_bsize_phys = vn->sc_secsize; 228 dev->si_bsize_best = vn->sc_secsize; 229 if (dev->si_bsize_best < VN_BSIZE_BEST) 230 dev->si_bsize_best = VN_BSIZE_BEST; 231 232 if ((flags & FWRITE) && (vn->sc_flags & VNF_READONLY)) 233 return (EACCES); 234 235 IFOPT(vn, VN_FOLLOW) 236 printf("vnopen(%s, 0x%x, 0x%x, %p)\n", 237 devtoname(dev), flags, mode, (void *)td); 238 239 /* 240 * Initialize label 241 */ 242 243 IFOPT(vn, VN_LABELS) { 244 if (vn->sc_flags & VNF_INITED) { 245 struct disklabel label; 246 247 /* Build label for whole disk. */ 248 bzero(&label, sizeof label); 249 label.d_secsize = vn->sc_secsize; 250 label.d_nsectors = 32; 251 label.d_ntracks = 64 / (vn->sc_secsize / DEV_BSIZE); 252 label.d_secpercyl = label.d_nsectors * label.d_ntracks; 253 label.d_ncylinders = vn->sc_size / label.d_secpercyl; 254 label.d_secperunit = vn->sc_size; 255 label.d_partitions[RAW_PART].p_size = vn->sc_size; 256 257 return (dsopen(dev, mode, 0, &vn->sc_slices, &label)); 258 } 259 if (dkslice(dev) != WHOLE_DISK_SLICE || 260 dkpart(dev) != RAW_PART || 261 mode != S_IFCHR) { 262 return (ENXIO); 263 } 264 } 265 return(0); 266 } 267 268 /* 269 * vnstrategy: 270 * 271 * Run strategy routine for VN device. We use VOP_READ/VOP_WRITE calls 272 * for vnode-backed vn's, and the new vm_pager_strategy() call for 273 * vm_object-backed vn's. 274 * 275 * Currently B_ASYNC is only partially handled - for OBJT_SWAP I/O only. 276 */ 277 static void 278 vnstrategy(dev_t dev, struct bio *bio) 279 { 280 struct buf *bp; 281 struct bio *nbio; 282 int unit; 283 struct vn_softc *vn; 284 int error; 285 286 unit = dkunit(dev); 287 if ((vn = dev->si_drv1) == NULL) 288 vn = vnfindvn(dev); 289 290 bp = bio->bio_buf; 291 292 IFOPT(vn, VN_DEBUG) 293 printf("vnstrategy(%p): unit %d\n", bp, unit); 294 295 if ((vn->sc_flags & VNF_INITED) == 0) { 296 bp->b_error = ENXIO; 297 bp->b_flags |= B_ERROR; 298 biodone(bio); 299 return; 300 } 301 302 bp->b_resid = bp->b_bcount; 303 304 IFOPT(vn, VN_LABELS) { 305 /* 306 * The vnode device is using disk/slice label support. 307 * 308 * The dscheck() function is called for validating the 309 * slices that exist ON the vnode device itself, and 310 * translate the "slice-relative" block number, again. 311 * dscheck() will call biodone() and return NULL if 312 * we are at EOF or beyond the device size. 313 */ 314 if (vn->sc_slices == NULL) { 315 nbio = bio; 316 } else if ((nbio = dscheck(dev, bio, vn->sc_slices)) == NULL) { 317 goto done; 318 } 319 } else { 320 int pbn; /* in sc_secsize chunks */ 321 long sz; /* in sc_secsize chunks */ 322 323 /* 324 * Check for required alignment. Transfers must be a valid 325 * multiple of the sector size. 326 */ 327 if (bp->b_bcount % vn->sc_secsize != 0 || 328 bio->bio_offset % vn->sc_secsize != 0) { 329 goto bad; 330 } 331 332 pbn = bio->bio_offset / vn->sc_secsize; 333 sz = howmany(bp->b_bcount, vn->sc_secsize); 334 335 /* 336 * Check for an illegal pbn or EOF truncation 337 */ 338 if (pbn < 0) 339 goto bad; 340 if (pbn + sz > vn->sc_size) { 341 if (pbn > vn->sc_size || (bp->b_flags & B_BNOCLIP)) 342 goto bad; 343 if (pbn == vn->sc_size) { 344 bp->b_resid = bp->b_bcount; 345 bp->b_flags |= B_INVAL; 346 goto done; 347 } 348 bp->b_bcount = (vn->sc_size - pbn) * vn->sc_secsize; 349 } 350 nbio = push_bio(bio); 351 nbio->bio_offset = pbn * vn->sc_secsize; 352 } 353 354 /* 355 * Use the translated nbio from this point on 356 */ 357 if (vn->sc_vp && bp->b_cmd == BUF_CMD_FREEBLKS) { 358 /* 359 * Freeblks is not handled for vnode-backed elements yet. 360 */ 361 bp->b_resid = 0; 362 /* operation complete */ 363 } else if (vn->sc_vp) { 364 /* 365 * VNODE I/O 366 * 367 * If an error occurs, we set B_ERROR but we do not set 368 * B_INVAL because (for a write anyway), the buffer is 369 * still valid. 370 */ 371 struct uio auio; 372 struct iovec aiov; 373 374 bzero(&auio, sizeof(auio)); 375 376 aiov.iov_base = bp->b_data; 377 aiov.iov_len = bp->b_bcount; 378 auio.uio_iov = &aiov; 379 auio.uio_iovcnt = 1; 380 auio.uio_offset = nbio->bio_offset; 381 auio.uio_segflg = UIO_SYSSPACE; 382 if (bp->b_cmd == BUF_CMD_READ) 383 auio.uio_rw = UIO_READ; 384 else 385 auio.uio_rw = UIO_WRITE; 386 auio.uio_resid = bp->b_bcount; 387 auio.uio_td = curthread; 388 vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY); 389 if (bp->b_cmd == BUF_CMD_READ) 390 error = VOP_READ(vn->sc_vp, &auio, IO_DIRECT, vn->sc_cred); 391 else 392 error = VOP_WRITE(vn->sc_vp, &auio, IO_NOWDRAIN, vn->sc_cred); 393 VOP_UNLOCK(vn->sc_vp, 0); 394 bp->b_resid = auio.uio_resid; 395 if (error) { 396 bp->b_error = error; 397 bp->b_flags |= B_ERROR; 398 } 399 /* operation complete */ 400 } else if (vn->sc_object) { 401 /* 402 * OBJT_SWAP I/O (handles read, write, freebuf) 403 * 404 * We have nothing to do if freeing blocks on a reserved 405 * swap area, othrewise execute the op. 406 */ 407 if (bp->b_cmd == BUF_CMD_FREEBLKS && TESTOPT(vn, VN_RESERVE)) { 408 bp->b_resid = 0; 409 /* operation complete */ 410 } else { 411 vm_pager_strategy(vn->sc_object, nbio); 412 return; 413 /* NOT REACHED */ 414 } 415 } else { 416 bp->b_resid = bp->b_bcount; 417 bp->b_flags |= B_ERROR | B_INVAL; 418 bp->b_error = EINVAL; 419 /* operation complete */ 420 } 421 biodone(nbio); 422 return; 423 424 /* 425 * Shortcuts / check failures on the original bio (not nbio). 426 */ 427 bad: 428 bp->b_error = EINVAL; 429 bp->b_flags |= B_ERROR | B_INVAL; 430 done: 431 biodone(bio); 432 } 433 434 /* ARGSUSED */ 435 static int 436 vnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 437 { 438 struct vn_softc *vn; 439 struct vn_ioctl *vio; 440 int error; 441 u_long *f; 442 443 vn = dev->si_drv1; 444 IFOPT(vn,VN_FOLLOW) 445 printf("vnioctl(%s, 0x%lx, %p, 0x%x, %p): unit %d\n", 446 devtoname(dev), cmd, (void *)data, flag, (void *)td, 447 dkunit(dev)); 448 449 switch (cmd) { 450 case VNIOCATTACH: 451 case VNIOCDETACH: 452 case VNIOCGSET: 453 case VNIOCGCLEAR: 454 case VNIOCUSET: 455 case VNIOCUCLEAR: 456 goto vn_specific; 457 } 458 459 IFOPT(vn,VN_LABELS) { 460 if (vn->sc_slices != NULL) { 461 error = dsioctl(dev, cmd, data, flag, &vn->sc_slices); 462 if (error != ENOIOCTL) 463 return (error); 464 } 465 if (dkslice(dev) != WHOLE_DISK_SLICE || 466 dkpart(dev) != RAW_PART) 467 return (ENOTTY); 468 } 469 470 vn_specific: 471 472 error = suser(td); 473 if (error) 474 return (error); 475 476 vio = (struct vn_ioctl *)data; 477 f = (u_long*)data; 478 switch (cmd) { 479 480 case VNIOCATTACH: 481 if (vn->sc_flags & VNF_INITED) 482 return(EBUSY); 483 484 if (vio->vn_file == NULL) 485 error = vniocattach_swap(vn, vio, dev, flag, td); 486 else 487 error = vniocattach_file(vn, vio, dev, flag, td); 488 break; 489 490 case VNIOCDETACH: 491 if ((vn->sc_flags & VNF_INITED) == 0) 492 return(ENXIO); 493 /* 494 * XXX handle i/o in progress. Return EBUSY, or wait, or 495 * flush the i/o. 496 * XXX handle multiple opens of the device. Return EBUSY, 497 * or revoke the fd's. 498 * How are these problems handled for removable and failing 499 * hardware devices? (Hint: They are not) 500 */ 501 vnclear(vn); 502 IFOPT(vn, VN_FOLLOW) 503 printf("vnioctl: CLRed\n"); 504 break; 505 506 case VNIOCGSET: 507 vn_options |= *f; 508 *f = vn_options; 509 break; 510 511 case VNIOCGCLEAR: 512 vn_options &= ~(*f); 513 *f = vn_options; 514 break; 515 516 case VNIOCUSET: 517 vn->sc_options |= *f; 518 *f = vn->sc_options; 519 break; 520 521 case VNIOCUCLEAR: 522 vn->sc_options &= ~(*f); 523 *f = vn->sc_options; 524 break; 525 526 default: 527 error = ENOTTY; 528 break; 529 } 530 return(error); 531 } 532 533 /* 534 * vniocattach_file: 535 * 536 * Attach a file to a VN partition. Return the size in the vn_size 537 * field. 538 */ 539 540 static int 541 vniocattach_file(struct vn_softc *vn, struct vn_ioctl *vio, dev_t dev, 542 int flag, struct thread *td) 543 { 544 struct vattr vattr; 545 struct nlookupdata nd; 546 int error, flags; 547 struct vnode *vp; 548 struct proc *p = td->td_proc; 549 550 KKASSERT(p != NULL); 551 552 flags = FREAD|FWRITE; 553 error = nlookup_init(&nd, vio->vn_file, 554 UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); 555 if (error) 556 return (error); 557 if ((error = vn_open(&nd, NULL, flags, 0)) != 0) { 558 if (error != EACCES && error != EPERM && error != EROFS) 559 goto done; 560 flags &= ~FWRITE; 561 nlookup_done(&nd); 562 error = nlookup_init(&nd, vio->vn_file, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); 563 if (error) 564 return (error); 565 if ((error = vn_open(&nd, NULL, flags, 0)) != 0) 566 goto done; 567 } 568 vp = nd.nl_open_vp; 569 if (vp->v_type != VREG || 570 (error = VOP_GETATTR(vp, &vattr))) { 571 if (error == 0) 572 error = EINVAL; 573 goto done; 574 } 575 VOP_UNLOCK(vp, 0); 576 vn->sc_secsize = DEV_BSIZE; 577 vn->sc_vp = vp; 578 nd.nl_open_vp = NULL; 579 580 /* 581 * If the size is specified, override the file attributes. Note that 582 * the vn_size argument is in PAGE_SIZE sized blocks. 583 */ 584 if (vio->vn_size) 585 vn->sc_size = (quad_t)vio->vn_size * PAGE_SIZE / vn->sc_secsize; 586 else 587 vn->sc_size = vattr.va_size / vn->sc_secsize; 588 error = vnsetcred(vn, p->p_ucred); 589 if (error) { 590 vn->sc_vp = NULL; 591 vn_close(vp, flags); 592 goto done; 593 } 594 vn->sc_flags |= VNF_INITED; 595 if (flags == FREAD) 596 vn->sc_flags |= VNF_READONLY; 597 IFOPT(vn, VN_LABELS) { 598 /* 599 * Reopen so that `ds' knows which devices are open. 600 * If this is the first VNIOCSET, then we've 601 * guaranteed that the device is the cdev and that 602 * no other slices or labels are open. Otherwise, 603 * we rely on VNIOCCLR not being abused. 604 */ 605 error = vnopen(dev, flag, S_IFCHR, td); 606 if (error) 607 vnclear(vn); 608 } 609 IFOPT(vn, VN_FOLLOW) 610 printf("vnioctl: SET vp %p size %x blks\n", 611 vn->sc_vp, vn->sc_size); 612 done: 613 nlookup_done(&nd); 614 return(error); 615 } 616 617 /* 618 * vniocattach_swap: 619 * 620 * Attach swap backing store to a VN partition of the size specified 621 * in vn_size. 622 */ 623 624 static int 625 vniocattach_swap(struct vn_softc *vn, struct vn_ioctl *vio, dev_t dev, 626 int flag, struct thread *td) 627 { 628 int error; 629 struct proc *p = td->td_proc; 630 631 KKASSERT(p != NULL); 632 /* 633 * Range check. Disallow negative sizes or any size less then the 634 * size of a page. Then round to a page. 635 */ 636 637 if (vio->vn_size <= 0) 638 return(EDOM); 639 640 /* 641 * Allocate an OBJT_SWAP object. 642 * 643 * sc_secsize is PAGE_SIZE'd 644 * 645 * vio->vn_size is in PAGE_SIZE'd chunks. 646 * sc_size must be in PAGE_SIZE'd chunks. 647 * Note the truncation. 648 */ 649 650 vn->sc_secsize = PAGE_SIZE; 651 vn->sc_size = vio->vn_size; 652 vn->sc_object = vm_pager_allocate(OBJT_SWAP, NULL, 653 vn->sc_secsize * (off_t)vio->vn_size, 654 VM_PROT_DEFAULT, 0); 655 IFOPT(vn, VN_RESERVE) { 656 if (swap_pager_reserve(vn->sc_object, 0, vn->sc_size) < 0) { 657 vm_pager_deallocate(vn->sc_object); 658 vn->sc_object = NULL; 659 return(EDOM); 660 } 661 } 662 vn->sc_flags |= VNF_INITED; 663 664 error = vnsetcred(vn, p->p_ucred); 665 if (error == 0) { 666 IFOPT(vn, VN_LABELS) { 667 /* 668 * Reopen so that `ds' knows which devices are open. 669 * If this is the first VNIOCSET, then we've 670 * guaranteed that the device is the cdev and that 671 * no other slices or labels are open. Otherwise, 672 * we rely on VNIOCCLR not being abused. 673 */ 674 error = vnopen(dev, flag, S_IFCHR, td); 675 } 676 } 677 if (error == 0) { 678 IFOPT(vn, VN_FOLLOW) { 679 printf("vnioctl: SET vp %p size %x\n", 680 vn->sc_vp, vn->sc_size); 681 } 682 } 683 if (error) 684 vnclear(vn); 685 return(error); 686 } 687 688 /* 689 * Duplicate the current processes' credentials. Since we are called only 690 * as the result of a SET ioctl and only root can do that, any future access 691 * to this "disk" is essentially as root. Note that credentials may change 692 * if some other uid can write directly to the mapped file (NFS). 693 */ 694 int 695 vnsetcred(struct vn_softc *vn, struct ucred *cred) 696 { 697 char *tmpbuf; 698 int error = 0; 699 700 /* 701 * Set credits in our softc 702 */ 703 704 if (vn->sc_cred) 705 crfree(vn->sc_cred); 706 vn->sc_cred = crdup(cred); 707 708 /* 709 * Horrible kludge to establish credentials for NFS XXX. 710 */ 711 712 if (vn->sc_vp) { 713 struct uio auio; 714 struct iovec aiov; 715 716 tmpbuf = malloc(vn->sc_secsize, M_TEMP, M_WAITOK); 717 bzero(&auio, sizeof(auio)); 718 719 aiov.iov_base = tmpbuf; 720 aiov.iov_len = vn->sc_secsize; 721 auio.uio_iov = &aiov; 722 auio.uio_iovcnt = 1; 723 auio.uio_offset = 0; 724 auio.uio_rw = UIO_READ; 725 auio.uio_segflg = UIO_SYSSPACE; 726 auio.uio_resid = aiov.iov_len; 727 vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY); 728 error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred); 729 VOP_UNLOCK(vn->sc_vp, 0); 730 free(tmpbuf, M_TEMP); 731 } 732 return (error); 733 } 734 735 void 736 vnclear(struct vn_softc *vn) 737 { 738 IFOPT(vn, VN_FOLLOW) 739 printf("vnclear(%p): vp=%p\n", vn, vn->sc_vp); 740 if (vn->sc_slices != NULL) 741 dsgone(&vn->sc_slices); 742 vn->sc_flags &= ~VNF_INITED; 743 if (vn->sc_vp != NULL) { 744 vn_close(vn->sc_vp, 745 (vn->sc_flags & VNF_READONLY) ? FREAD : (FREAD|FWRITE)); 746 vn->sc_vp = NULL; 747 } 748 vn->sc_flags &= ~VNF_READONLY; 749 if (vn->sc_cred) { 750 crfree(vn->sc_cred); 751 vn->sc_cred = NULL; 752 } 753 if (vn->sc_object != NULL) { 754 vm_pager_deallocate(vn->sc_object); 755 vn->sc_object = NULL; 756 } 757 vn->sc_size = 0; 758 } 759 760 static int 761 vnsize(dev_t dev) 762 { 763 struct vn_softc *vn; 764 765 vn = dev->si_drv1; 766 if (!vn) 767 return(-1); 768 if ((vn->sc_flags & VNF_INITED) == 0) 769 return(-1); 770 771 return(vn->sc_size); 772 } 773 774 static int 775 vn_modevent(module_t mod, int type, void *data) 776 { 777 struct vn_softc *vn; 778 dev_t dev; 779 780 switch (type) { 781 case MOD_LOAD: 782 cdevsw_add(&vn_cdevsw, 0, 0); 783 break; 784 case MOD_UNLOAD: 785 /* fall through */ 786 case MOD_SHUTDOWN: 787 while ((vn = SLIST_FIRST(&vn_list)) != NULL) { 788 SLIST_REMOVE_HEAD(&vn_list, sc_list); 789 if (vn->sc_flags & VNF_INITED) 790 vnclear(vn); 791 /* Cleanup all dev_t's that refer to this unit */ 792 while ((dev = vn->sc_devlist) != NULL) { 793 vn->sc_devlist = dev->si_drv2; 794 dev->si_drv1 = dev->si_drv2 = NULL; 795 destroy_dev(dev); 796 } 797 free(vn, M_DEVBUF); 798 } 799 cdevsw_remove(&vn_cdevsw, 0, 0); 800 break; 801 default: 802 break; 803 } 804 return 0; 805 } 806 807 DEV_MODULE(vn, vn_modevent, 0); 808