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