Print this page
PSARC 2007/569 lofi(7D) compression support
6618343 lofi compression support
6603856 Lofi(7D) can thrash the page cache


  82  *      lofi on itself. The simple lock strategy (lofi_lock) precludes this
  83  *      because you'll be in lofi_ioctl, holding the lock when you open the
  84  *      file, which, if it's lofi, will grab lofi_lock. We prevent this for
  85  *      now, though not using ddi_soft_state(9F) would make it possible to
  86  *      do. Though it would still be silly.
  87  *
  88  * Interesting things to do:
  89  *
  90  *      Allow multiple files for each device. A poor-man's metadisk, basically.
  91  *
  92  *      Pass-through ioctls on block devices. You can (though it's not
  93  *      documented), give lofi a block device as a file name. Then we shouldn't
  94  *      need to fake a geometry. But this is also silly unless you're replacing
  95  *      metadisk.
  96  *
  97  *      Encryption. tpm would like this. Apparently Windows 2000 has it, and
  98  *      so does Linux.
  99  */
 100 
 101 #include <sys/types.h>

 102 #include <sys/sysmacros.h>
 103 #include <sys/cmn_err.h>
 104 #include <sys/uio.h>
 105 #include <sys/kmem.h>
 106 #include <sys/cred.h>
 107 #include <sys/mman.h>
 108 #include <sys/errno.h>
 109 #include <sys/aio_req.h>
 110 #include <sys/stat.h>
 111 #include <sys/file.h>
 112 #include <sys/modctl.h>
 113 #include <sys/conf.h>
 114 #include <sys/debug.h>
 115 #include <sys/vnode.h>
 116 #include <sys/lofi.h>
 117 #include <sys/fcntl.h>
 118 #include <sys/pathname.h>
 119 #include <sys/filio.h>
 120 #include <sys/fdio.h>
 121 #include <sys/open.h>
 122 #include <sys/disp.h>
 123 #include <vm/seg_map.h>
 124 #include <sys/ddi.h>
 125 #include <sys/sunddi.h>

 126 
 127 /* seems safer than having to get the string right many times */
 128 #define NBLOCKS_PROP_NAME       "Nblocks"
 129 #define SIZE_PROP_NAME  "Size"
 130 
 131 static dev_info_t *lofi_dip;
 132 static void     *lofi_statep;
 133 static kmutex_t lofi_lock;              /* state lock */
 134 
 135 /*
 136  * Because lofi_taskq_nthreads limits the actual swamping of the device, the
 137  * maxalloc parameter (lofi_taskq_maxalloc) should be tuned conservatively
 138  * high.  If we want to be assured that the underlying device is always busy,
 139  * we must be sure that the number of bytes enqueued when the number of
 140  * enqueued tasks exceeds maxalloc is sufficient to keep the device busy for
 141  * the duration of the sleep time in taskq_ent_alloc().  That is, lofi should
 142  * set maxalloc to be the maximum throughput (in bytes per second) of the
 143  * underlying device divided by the minimum I/O size.  We assume a realistic
 144  * maximum throughput of one hundred megabytes per second; we set maxalloc on
 145  * the lofi task queue to be 104857600 divided by DEV_BSIZE.
 146  */
 147 static int lofi_taskq_maxalloc = 104857600 / DEV_BSIZE;
 148 static int lofi_taskq_nthreads = 4;     /* # of taskq threads per device */
 149 
 150 uint32_t lofi_max_files = LOFI_MAX_FILES;
 151 









 152 static int
 153 lofi_busy(void)
 154 {
 155         minor_t minor;
 156 
 157         /*
 158          * We need to make sure no mappings exist - mod_remove won't
 159          * help because the device isn't open.
 160          */
 161         mutex_enter(&lofi_lock);
 162         for (minor = 1; minor <= lofi_max_files; minor++) {
 163                 if (ddi_get_soft_state(lofi_statep, minor) != NULL) {
 164                         mutex_exit(&lofi_lock);
 165                         return (EBUSY);
 166                 }
 167         }
 168         mutex_exit(&lofi_lock);
 169         return (0);
 170 }
 171 


 206                 break;
 207         case OTYP_BLK:
 208                 lsp->ls_blk_open = 0;
 209                 break;
 210         case OTYP_LYR:
 211                 lsp->ls_lyr_open_count--;
 212                 break;
 213         default:
 214                 break;
 215         }
 216 }
 217 
 218 static void
 219 lofi_free_handle(dev_t dev, minor_t minor, struct lofi_state *lsp,
 220     cred_t *credp)
 221 {
 222         dev_t   newdev;
 223         char    namebuf[50];
 224 
 225         if (lsp->ls_vp) {
 226                 (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag,
 227                     1, 0, credp, NULL);
 228                 VN_RELE(lsp->ls_vp);
 229                 lsp->ls_vp = NULL;
 230         }
 231 
 232         newdev = makedevice(getmajor(dev), minor);
 233         (void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
 234         (void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
 235 
 236         (void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
 237         ddi_remove_minor_node(lofi_dip, namebuf);
 238         (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
 239         ddi_remove_minor_node(lofi_dip, namebuf);
 240 
 241         kmem_free(lsp->ls_filename, lsp->ls_filename_sz);
 242         taskq_destroy(lsp->ls_taskq);
 243         if (lsp->ls_kstat) {
 244                 kstat_delete(lsp->ls_kstat);
 245                 mutex_destroy(&lsp->ls_kstat_lock);
 246         }
 247         ddi_soft_state_free(lofi_statep, minor);


 307 
 308         mutex_enter(&lofi_lock);
 309         minor = getminor(dev);
 310         lsp = ddi_get_soft_state(lofi_statep, minor);
 311         if (lsp == NULL) {
 312                 mutex_exit(&lofi_lock);
 313                 return (EINVAL);
 314         }
 315         mark_closed(lsp, otyp);
 316 
 317         /*
 318          * If we have forcibly closed the underlying device, and this is the
 319          * last close, then tear down the rest of the device.
 320          */
 321         if (minor != 0 && lsp->ls_vp == NULL && !is_opened(lsp))
 322                 lofi_free_handle(dev, minor, lsp, credp);
 323         mutex_exit(&lofi_lock);
 324         return (0);
 325 }
 326 
 327 /*
 328  * This is basically what strategy used to be before we found we
 329  * needed task queues.
 330  */
 331 static void
 332 lofi_strategy_task(void *arg)
 333 {
 334         struct buf *bp = (struct buf *)arg;
 335         int error;
 336         struct lofi_state *lsp;
 337         offset_t        offset, alignedoffset;
 338         offset_t        mapoffset;
 339         caddr_t bufaddr;
 340         caddr_t mapaddr;
 341         size_t  xfersize;
 342         size_t  len;
 343         int     isread;
 344         int     smflags;


 345         enum seg_rw srw;
 346 
 347         lsp = ddi_get_soft_state(lofi_statep, getminor(bp->b_edev));
 348         if (lsp->ls_kstat) {
 349                 mutex_enter(lsp->ls_kstat->ks_lock);
 350                 kstat_waitq_to_runq(KSTAT_IO_PTR(lsp->ls_kstat));
 351                 mutex_exit(lsp->ls_kstat->ks_lock);
 352         }
 353         bp_mapin(bp);
 354         bufaddr = bp->b_un.b_addr;
 355         offset = bp->b_lblkno * DEV_BSIZE;   /* offset within file */
 356 
 357         /*
 358          * We used to always use vn_rdwr here, but we cannot do that because
 359          * we might decide to read or write from the the underlying
 360          * file during this call, which would be a deadlock because
 361          * we have the rw_lock. So instead we page, unless it's not
 362          * mapable or it's a character device.
 363          */
 364         if (lsp->ls_vp == NULL || lsp->ls_vp_closereq) {
 365                 error = EIO;
 366         } else if (((lsp->ls_vp->v_flag & VNOMAP) == 0) &&
 367             (lsp->ls_vp->v_type != VCHR)) {
 368                 /*
 369                  * segmap always gives us an 8K (MAXBSIZE) chunk, aligned on
 370                  * an 8K boundary, but the buf transfer address may not be
 371                  * aligned on more than a 512-byte boundary (we don't
 372                  * enforce that, though we could). This matters since the
 373                  * initial part of the transfer may not start at offset 0
 374                  * within the segmap'd chunk. So we have to compensate for
 375                  * that with 'mapoffset'. Subsequent chunks always start
 376                  * off at the beginning, and the last is capped by b_resid.
 377                  */
 378                 mapoffset = offset & MAXBOFFSET;
 379                 alignedoffset = offset - mapoffset;     /* now map-aligned */
 380                 bp->b_resid = bp->b_bcount;
 381                 isread = bp->b_flags & B_READ;
 382                 srw = isread ? S_READ : S_WRITE;
 383                 do {
 384                         xfersize = MIN(lsp->ls_vp_size - offset,
 385                             MIN(MAXBSIZE - mapoffset, bp->b_resid));
 386                         len = roundup(mapoffset + xfersize, PAGESIZE);
 387                         mapaddr = segmap_getmapflt(segkmap, lsp->ls_vp,
 388                             alignedoffset, MAXBSIZE, 1, srw);
 389                         /*
 390                          * Now fault in the pages. This lets us check
 391                          * for errors before we reference mapaddr and
 392                          * try to resolve the fault in bcopy (which would
 393                          * panic instead). And this can easily happen,
 394                          * particularly if you've lofi'd a file over NFS
 395                          * and someone deletes the file on the server.
 396                          */
 397                         error = segmap_fault(kas.a_hat, segkmap, mapaddr,
 398                             len, F_SOFTLOCK, srw);
 399                         if (error) {
 400                                 (void) segmap_release(segkmap, mapaddr, 0);
 401                                 if (FC_CODE(error) == FC_OBJERR)
 402                                         error = FC_ERRNO(error);
 403                                 else
 404                                         error = EIO;
 405                                 break;
 406                         }
 407                         smflags = 0;
 408                         if (isread) {









 409                                 bcopy(mapaddr + mapoffset, bufaddr, xfersize);
 410                         } else {
 411                                 smflags |= SM_WRITE;
 412                                 bcopy(bufaddr, mapaddr + mapoffset, xfersize);
 413                         }
 414                         bp->b_resid -= xfersize;
 415                         bufaddr += xfersize;
 416                         offset += xfersize;
 417                         (void) segmap_fault(kas.a_hat, segkmap, mapaddr,
 418                             len, F_SOFTUNLOCK, srw);
 419                         error = segmap_release(segkmap, mapaddr, smflags);
 420                         /* only the first map may start partial */
 421                         mapoffset = 0;
 422                         alignedoffset += MAXBSIZE;
 423                 } while ((error == 0) && (bp->b_resid > 0) &&
 424                     (offset < lsp->ls_vp_size));















































































































 425         } else {



































































































 426                 ssize_t resid;
 427                 enum uio_rw rw;
 428 
 429                 if (bp->b_flags & B_READ)
 430                         rw = UIO_READ;
 431                 else
 432                         rw = UIO_WRITE;
 433                 error = vn_rdwr(rw, lsp->ls_vp, bufaddr, bp->b_bcount,
 434                     offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
 435                 bp->b_resid = resid;
 436         }
 437 






 438         if (lsp->ls_kstat) {
 439                 size_t n_done = bp->b_bcount - bp->b_resid;
 440                 kstat_io_t *kioptr;
 441 
 442                 mutex_enter(lsp->ls_kstat->ks_lock);
 443                 kioptr = KSTAT_IO_PTR(lsp->ls_kstat);
 444                 if (bp->b_flags & B_READ) {
 445                         kioptr->nread += n_done;
 446                         kioptr->reads++;
 447                 } else {
 448                         kioptr->nwritten += n_done;
 449                         kioptr->writes++;
 450                 }
 451                 kstat_runq_exit(kioptr);
 452                 mutex_exit(lsp->ls_kstat->ks_lock);
 453         }
 454 
 455         mutex_enter(&lsp->ls_vp_lock);
 456         if (--lsp->ls_vp_iocount == 0)
 457                 cv_broadcast(&lsp->ls_vp_cv);


 614 }
 615 
 616 /*
 617  * These two just simplify the rest of the ioctls that need to copyin/out
 618  * the lofi_ioctl structure.
 619  */
 620 struct lofi_ioctl *
 621 copy_in_lofi_ioctl(const struct lofi_ioctl *ulip, int flag)
 622 {
 623         struct lofi_ioctl *klip;
 624         int     error;
 625 
 626         klip = kmem_alloc(sizeof (struct lofi_ioctl), KM_SLEEP);
 627         error = ddi_copyin(ulip, klip, sizeof (struct lofi_ioctl), flag);
 628         if (error) {
 629                 kmem_free(klip, sizeof (struct lofi_ioctl));
 630                 return (NULL);
 631         }
 632 
 633         /* make sure filename is always null-terminated */
 634         klip->li_filename[MAXPATHLEN] = '\0';
 635 
 636         /* validate minor number */
 637         if (klip->li_minor > lofi_max_files) {
 638                 kmem_free(klip, sizeof (struct lofi_ioctl));
 639                 return (NULL);
 640         }
 641         return (klip);
 642 }
 643 
 644 int
 645 copy_out_lofi_ioctl(const struct lofi_ioctl *klip, struct lofi_ioctl *ulip,
 646         int flag)
 647 {
 648         int     error;
 649 
 650         error = ddi_copyout(klip, ulip, sizeof (struct lofi_ioctl), flag);
 651         if (error)
 652                 return (EFAULT);
 653         return (0);
 654 }


 736         lsp->ls_dkg.dkg_obs1 = 0;
 737         lsp->ls_dkg.dkg_intrlv = 0;
 738         lsp->ls_dkg.dkg_obs2 = 0;
 739         lsp->ls_dkg.dkg_obs3 = 0;
 740         lsp->ls_dkg.dkg_apc = 0;
 741         lsp->ls_dkg.dkg_rpm = 7200;
 742         lsp->ls_dkg.dkg_pcyl = lsp->ls_dkg.dkg_ncyl + lsp->ls_dkg.dkg_acyl;
 743         lsp->ls_dkg.dkg_nsect = lsp->ls_vp_size /
 744             (DEV_BSIZE * lsp->ls_dkg.dkg_ncyl);
 745         lsp->ls_dkg.dkg_write_reinstruct = 0;
 746         lsp->ls_dkg.dkg_read_reinstruct = 0;
 747 
 748         /* vtoc - see dkio(7I) */
 749         bzero(&lsp->ls_vtoc, sizeof (struct vtoc));
 750         lsp->ls_vtoc.v_sanity = VTOC_SANE;
 751         lsp->ls_vtoc.v_version = V_VERSION;
 752         bcopy(LOFI_DRIVER_NAME, lsp->ls_vtoc.v_volume, 7);
 753         lsp->ls_vtoc.v_sectorsz = DEV_BSIZE;
 754         lsp->ls_vtoc.v_nparts = 1;
 755         lsp->ls_vtoc.v_part[0].p_tag = V_UNASSIGNED;








 756         lsp->ls_vtoc.v_part[0].p_flag = V_UNMNT;

 757         lsp->ls_vtoc.v_part[0].p_start = (daddr_t)0;
 758         /*
 759          * The partition size cannot just be the number of sectors, because
 760          * that might not end on a cylinder boundary. And if that's the case,
 761          * newfs/mkfs will print a scary warning. So just figure the size
 762          * based on the number of cylinders and sectors/cylinder.
 763          */
 764         lsp->ls_vtoc.v_part[0].p_size = lsp->ls_dkg.dkg_pcyl *
 765             lsp->ls_dkg.dkg_nsect * lsp->ls_dkg.dkg_nhead;
 766 
 767         /* dk_cinfo - see dkio(7I) */
 768         bzero(&lsp->ls_ci, sizeof (struct dk_cinfo));
 769         (void) strcpy(lsp->ls_ci.dki_cname, LOFI_DRIVER_NAME);
 770         lsp->ls_ci.dki_ctype = DKC_MD;
 771         lsp->ls_ci.dki_flags = 0;
 772         lsp->ls_ci.dki_cnum = 0;
 773         lsp->ls_ci.dki_addr = 0;
 774         lsp->ls_ci.dki_space = 0;
 775         lsp->ls_ci.dki_prio = 0;
 776         lsp->ls_ci.dki_vec = 0;
 777         (void) strcpy(lsp->ls_ci.dki_dname, LOFI_DRIVER_NAME);
 778         lsp->ls_ci.dki_unit = 0;
 779         lsp->ls_ci.dki_slave = 0;
 780         lsp->ls_ci.dki_partition = 0;
 781         /*
 782          * newfs uses this to set maxcontig. Must not be < 16, or it
 783          * will be 0 when newfs multiplies it by DEV_BSIZE and divides
 784          * it by the block size. Then tunefs doesn't work because
 785          * maxcontig is 0.
 786          */
 787         lsp->ls_ci.dki_maxtransfer = 16;
 788 }
 789 
 790 /*

























































































































 791  * map a file to a minor number. Return the minor number.
 792  */
 793 static int
 794 lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
 795     int *rvalp, struct cred *credp, int ioctl_flag)
 796 {
 797         minor_t newminor;
 798         struct lofi_state *lsp;
 799         struct lofi_ioctl *klip;
 800         int     error;
 801         struct vnode *vp;
 802         int64_t Nblocks_prop_val;
 803         int64_t Size_prop_val;

 804         vattr_t vattr;
 805         int     flag;
 806         enum vtype v_type;
 807         int zalloced = 0;
 808         dev_t   newdev;
 809         char    namebuf[50];




 810 
 811         klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
 812         if (klip == NULL)
 813                 return (EFAULT);
 814 
 815         mutex_enter(&lofi_lock);
 816 
 817         if (!valid_filename(klip->li_filename)) {
 818                 error = EINVAL;
 819                 goto out;
 820         }
 821 
 822         if (file_to_minor(klip->li_filename) != 0) {
 823                 error = EBUSY;
 824                 goto out;
 825         }
 826 
 827         if (pickminor) {
 828                 /* Find a free one */
 829                 for (newminor = 1; newminor <= lofi_max_files; newminor++)


 848                 goto out;
 849         }
 850         v_type = vp->v_type;
 851         VN_RELE(vp);
 852         if (!V_ISLOFIABLE(v_type)) {
 853                 error = EINVAL;
 854                 goto out;
 855         }
 856         flag = FREAD | FWRITE | FOFFMAX | FEXCL;
 857         error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, &vp, 0, 0);
 858         if (error) {
 859                 /* try read-only */
 860                 flag &= ~FWRITE;
 861                 error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0,
 862                     &vp, 0, 0);
 863                 if (error) {
 864                         goto out;
 865                 }
 866         }
 867         vattr.va_mask = AT_SIZE;
 868         error = VOP_GETATTR(vp, &vattr, 0, credp, NULL);
 869         if (error) {
 870                 goto closeout;
 871         }
 872         /* the file needs to be a multiple of the block size */
 873         if ((vattr.va_size % DEV_BSIZE) != 0) {
 874                 error = EINVAL;
 875                 goto closeout;
 876         }
 877         newdev = makedevice(getmajor(dev), newminor);
 878         Size_prop_val = vattr.va_size;
 879         if ((ddi_prop_update_int64(newdev, lofi_dip,
 880             SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) {
 881                 error = EINVAL;
 882                 goto closeout;
 883         }
 884         Nblocks_prop_val = vattr.va_size / DEV_BSIZE;
 885         if ((ddi_prop_update_int64(newdev, lofi_dip,
 886             NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) {
 887                 error = EINVAL;
 888                 goto propout;


 920         lsp->ls_kstat = kstat_create(LOFI_DRIVER_NAME, newminor,
 921             NULL, "disk", KSTAT_TYPE_IO, 1, 0);
 922         if (lsp->ls_kstat) {
 923                 mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL);
 924                 lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
 925                 kstat_install(lsp->ls_kstat);
 926         }
 927         cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL);
 928         mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL);
 929 
 930         /*
 931          * save open mode so file can be closed properly and vnode counts
 932          * updated correctly.
 933          */
 934         lsp->ls_openflag = flag;
 935 
 936         /*
 937          * Try to handle stacked lofs vnodes.
 938          */
 939         if (vp->v_type == VREG) {
 940                 if (VOP_REALVP(vp, &lsp->ls_vp, NULL) != 0) {
 941                         lsp->ls_vp = vp;
 942                 } else {
 943                         /*
 944                          * Even though vp was obtained via vn_open(), we
 945                          * can't call vn_close() on it, since lofs will
 946                          * pass the VOP_CLOSE() on down to the realvp
 947                          * (which we are about to use). Hence we merely
 948                          * drop the reference to the lofs vnode and hold
 949                          * the realvp so things behave as if we've
 950                          * opened the realvp without any interaction
 951                          * with lofs.
 952                          */
 953                         VN_HOLD(lsp->ls_vp);
 954                         VN_RELE(vp);
 955                 }
 956         } else {
 957                 lsp->ls_vp = vp;
 958         }
 959         lsp->ls_vp_size = vattr.va_size;
 960         (void) strcpy(lsp->ls_filename, klip->li_filename);
 961         if (rvalp)
 962                 *rvalp = (int)newminor;
 963         klip->li_minor = newminor;
 964 










































 965         fake_disk_geometry(lsp);
 966         mutex_exit(&lofi_lock);
 967         (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
 968         free_lofi_ioctl(klip);
 969         return (0);
 970 
 971 propout:
 972         (void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
 973         (void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
 974 closeout:
 975         (void) VOP_CLOSE(vp, flag, 1, 0, credp, NULL);
 976         VN_RELE(vp);
 977 out:
 978         if (zalloced)
 979                 ddi_soft_state_free(lofi_statep, newminor);
 980         mutex_exit(&lofi_lock);
 981         free_lofi_ioctl(klip);
 982         return (error);
 983 }
 984 
 985 /*
 986  * unmap a file.
 987  */
 988 static int
 989 lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename,
 990     struct cred *credp, int ioctl_flag)
 991 {
 992         struct lofi_state *lsp;
 993         struct lofi_ioctl *klip;
 994         minor_t minor;
 995 


1019                 /*
1020                  * If the 'force' flag is set, then we forcibly close the
1021                  * underlying file.  Subsequent operations will fail, and the
1022                  * DKIOCSTATE ioctl will return DKIO_DEV_GONE.  When the device
1023                  * is last closed, the device will be cleaned up appropriately.
1024                  *
1025                  * This is complicated by the fact that we may have outstanding
1026                  * dispatched I/Os.  Rather than having a single mutex to
1027                  * serialize all I/O, we keep a count of the number of
1028                  * outstanding I/O requests, as well as a flag to indicate that
1029                  * no new I/Os should be dispatched.  We set the flag, wait for
1030                  * the number of outstanding I/Os to reach 0, and then close the
1031                  * underlying vnode.
1032                  */
1033                 if (klip->li_force) {
1034                         mutex_enter(&lsp->ls_vp_lock);
1035                         lsp->ls_vp_closereq = B_TRUE;
1036                         while (lsp->ls_vp_iocount > 0)
1037                                 cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock);
1038                         (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0,
1039                             credp, NULL);
1040                         VN_RELE(lsp->ls_vp);
1041                         lsp->ls_vp = NULL;
1042                         cv_broadcast(&lsp->ls_vp_cv);
1043                         mutex_exit(&lsp->ls_vp_lock);
1044                         mutex_exit(&lofi_lock);
1045                         klip->li_minor = minor;
1046                         (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1047                         free_lofi_ioctl(klip);
1048                         return (0);
1049                 }
1050                 mutex_exit(&lofi_lock);
1051                 free_lofi_ioctl(klip);
1052                 return (EBUSY);
1053         }
1054 





1055         lofi_free_handle(dev, minor, lsp, credp);
1056 
1057         klip->li_minor = minor;
1058         mutex_exit(&lofi_lock);
1059         (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1060         free_lofi_ioctl(klip);
1061         return (0);
1062 }
1063 
1064 /*
1065  * get the filename given the minor number, or the minor number given
1066  * the name.
1067  */
1068 /*ARGSUSED*/
1069 static int
1070 lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which,
1071     struct cred *credp, int ioctl_flag)
1072 {
1073         struct lofi_state *lsp;
1074         struct lofi_ioctl *klip;


1078         klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
1079         if (klip == NULL)
1080                 return (EFAULT);
1081 
1082         switch (which) {
1083         case LOFI_GET_FILENAME:
1084                 minor = klip->li_minor;
1085                 if (minor == 0) {
1086                         free_lofi_ioctl(klip);
1087                         return (EINVAL);
1088                 }
1089 
1090                 mutex_enter(&lofi_lock);
1091                 lsp = ddi_get_soft_state(lofi_statep, minor);
1092                 if (lsp == NULL) {
1093                         mutex_exit(&lofi_lock);
1094                         free_lofi_ioctl(klip);
1095                         return (ENXIO);
1096                 }
1097                 (void) strcpy(klip->li_filename, lsp->ls_filename);






1098                 mutex_exit(&lofi_lock);
1099                 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1100                 free_lofi_ioctl(klip);
1101                 return (error);
1102         case LOFI_GET_MINOR:
1103                 mutex_enter(&lofi_lock);
1104                 klip->li_minor = file_to_minor(klip->li_filename);
1105                 mutex_exit(&lofi_lock);
1106                 if (klip->li_minor == 0) {
1107                         free_lofi_ioctl(klip);
1108                         return (ENOENT);
1109                 }
1110                 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1111                 free_lofi_ioctl(klip);
1112                 return (error);




























1113         default:
1114                 free_lofi_ioctl(klip);
1115                 return (EINVAL);
1116         }
1117 
1118 }
1119 
1120 static int
1121 lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp,
1122     int *rvalp)
1123 {
1124         int     error;
1125         enum dkio_state dkstate;
1126         struct lofi_state *lsp;
1127         minor_t minor;
1128 
1129 #ifdef lint
1130         credp = credp;
1131 #endif
1132 


1152                 case LOFI_UNMAP_FILE:
1153                         if ((flag & FWRITE) == 0)
1154                                 return (EPERM);
1155                         return (lofi_unmap_file(dev, lip, 1, credp, flag));
1156                 case LOFI_UNMAP_FILE_MINOR:
1157                         if ((flag & FWRITE) == 0)
1158                                 return (EPERM);
1159                         return (lofi_unmap_file(dev, lip, 0, credp, flag));
1160                 case LOFI_GET_FILENAME:
1161                         return (lofi_get_info(dev, lip, LOFI_GET_FILENAME,
1162                             credp, flag));
1163                 case LOFI_GET_MINOR:
1164                         return (lofi_get_info(dev, lip, LOFI_GET_MINOR,
1165                             credp, flag));
1166                 case LOFI_GET_MAXMINOR:
1167                         error = ddi_copyout(&lofi_max_files, &lip->li_minor,
1168                             sizeof (lofi_max_files), flag);
1169                         if (error)
1170                                 return (EFAULT);
1171                         return (0);



1172                 default:
1173                         break;
1174                 }
1175         }
1176 
1177         lsp = ddi_get_soft_state(lofi_statep, minor);
1178         if (lsp == NULL)
1179                 return (ENXIO);
1180 
1181         /*
1182          * We explicitly allow DKIOCSTATE, but all other ioctls should fail with
1183          * EIO as if the device was no longer present.
1184          */
1185         if (lsp->ls_vp == NULL && cmd != DKIOCSTATE)
1186                 return (EIO);
1187 
1188         /* these are for faking out utilities like newfs */
1189         switch (cmd) {
1190         case DKIOCGVTOC:
1191                 switch (ddi_model_convert_from(flag & FMODELS)) {




  82  *      lofi on itself. The simple lock strategy (lofi_lock) precludes this
  83  *      because you'll be in lofi_ioctl, holding the lock when you open the
  84  *      file, which, if it's lofi, will grab lofi_lock. We prevent this for
  85  *      now, though not using ddi_soft_state(9F) would make it possible to
  86  *      do. Though it would still be silly.
  87  *
  88  * Interesting things to do:
  89  *
  90  *      Allow multiple files for each device. A poor-man's metadisk, basically.
  91  *
  92  *      Pass-through ioctls on block devices. You can (though it's not
  93  *      documented), give lofi a block device as a file name. Then we shouldn't
  94  *      need to fake a geometry. But this is also silly unless you're replacing
  95  *      metadisk.
  96  *
  97  *      Encryption. tpm would like this. Apparently Windows 2000 has it, and
  98  *      so does Linux.
  99  */
 100 
 101 #include <sys/types.h>
 102 #include <netinet/in.h>
 103 #include <sys/sysmacros.h>
 104 #include <sys/cmn_err.h>
 105 #include <sys/uio.h>
 106 #include <sys/kmem.h>
 107 #include <sys/cred.h>
 108 #include <sys/mman.h>
 109 #include <sys/errno.h>
 110 #include <sys/aio_req.h>
 111 #include <sys/stat.h>
 112 #include <sys/file.h>
 113 #include <sys/modctl.h>
 114 #include <sys/conf.h>
 115 #include <sys/debug.h>
 116 #include <sys/vnode.h>
 117 #include <sys/lofi.h>
 118 #include <sys/fcntl.h>
 119 #include <sys/pathname.h>
 120 #include <sys/filio.h>
 121 #include <sys/fdio.h>
 122 #include <sys/open.h>
 123 #include <sys/disp.h>
 124 #include <vm/seg_map.h>
 125 #include <sys/ddi.h>
 126 #include <sys/sunddi.h>
 127 #include <sys/zmod.h>
 128 

 129 #define NBLOCKS_PROP_NAME       "Nblocks"
 130 #define SIZE_PROP_NAME          "Size"
 131 
 132 static dev_info_t *lofi_dip;
 133 static void     *lofi_statep;
 134 static kmutex_t lofi_lock;              /* state lock */
 135 
 136 /*
 137  * Because lofi_taskq_nthreads limits the actual swamping of the device, the
 138  * maxalloc parameter (lofi_taskq_maxalloc) should be tuned conservatively
 139  * high.  If we want to be assured that the underlying device is always busy,
 140  * we must be sure that the number of bytes enqueued when the number of
 141  * enqueued tasks exceeds maxalloc is sufficient to keep the device busy for
 142  * the duration of the sleep time in taskq_ent_alloc().  That is, lofi should
 143  * set maxalloc to be the maximum throughput (in bytes per second) of the
 144  * underlying device divided by the minimum I/O size.  We assume a realistic
 145  * maximum throughput of one hundred megabytes per second; we set maxalloc on
 146  * the lofi task queue to be 104857600 divided by DEV_BSIZE.
 147  */
 148 static int lofi_taskq_maxalloc = 104857600 / DEV_BSIZE;
 149 static int lofi_taskq_nthreads = 4;     /* # of taskq threads per device */
 150 
 151 uint32_t lofi_max_files = LOFI_MAX_FILES;
 152 
 153 static int gzip_decompress(void *src, size_t srclen, void *dst,
 154         size_t *destlen, int level);
 155 
 156 lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = {
 157         {gzip_decompress,       NULL,   6,      "gzip"}, /* default */
 158         {gzip_decompress,       NULL,   6,      "gzip-6"},
 159         {gzip_decompress,       NULL,   9,      "gzip-9"}
 160 };
 161 
 162 static int
 163 lofi_busy(void)
 164 {
 165         minor_t minor;
 166 
 167         /*
 168          * We need to make sure no mappings exist - mod_remove won't
 169          * help because the device isn't open.
 170          */
 171         mutex_enter(&lofi_lock);
 172         for (minor = 1; minor <= lofi_max_files; minor++) {
 173                 if (ddi_get_soft_state(lofi_statep, minor) != NULL) {
 174                         mutex_exit(&lofi_lock);
 175                         return (EBUSY);
 176                 }
 177         }
 178         mutex_exit(&lofi_lock);
 179         return (0);
 180 }
 181 


 216                 break;
 217         case OTYP_BLK:
 218                 lsp->ls_blk_open = 0;
 219                 break;
 220         case OTYP_LYR:
 221                 lsp->ls_lyr_open_count--;
 222                 break;
 223         default:
 224                 break;
 225         }
 226 }
 227 
 228 static void
 229 lofi_free_handle(dev_t dev, minor_t minor, struct lofi_state *lsp,
 230     cred_t *credp)
 231 {
 232         dev_t   newdev;
 233         char    namebuf[50];
 234 
 235         if (lsp->ls_vp) {
 236                 (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0, credp);

 237                 VN_RELE(lsp->ls_vp);
 238                 lsp->ls_vp = NULL;
 239         }
 240 
 241         newdev = makedevice(getmajor(dev), minor);
 242         (void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
 243         (void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
 244 
 245         (void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
 246         ddi_remove_minor_node(lofi_dip, namebuf);
 247         (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
 248         ddi_remove_minor_node(lofi_dip, namebuf);
 249 
 250         kmem_free(lsp->ls_filename, lsp->ls_filename_sz);
 251         taskq_destroy(lsp->ls_taskq);
 252         if (lsp->ls_kstat) {
 253                 kstat_delete(lsp->ls_kstat);
 254                 mutex_destroy(&lsp->ls_kstat_lock);
 255         }
 256         ddi_soft_state_free(lofi_statep, minor);


 316 
 317         mutex_enter(&lofi_lock);
 318         minor = getminor(dev);
 319         lsp = ddi_get_soft_state(lofi_statep, minor);
 320         if (lsp == NULL) {
 321                 mutex_exit(&lofi_lock);
 322                 return (EINVAL);
 323         }
 324         mark_closed(lsp, otyp);
 325 
 326         /*
 327          * If we have forcibly closed the underlying device, and this is the
 328          * last close, then tear down the rest of the device.
 329          */
 330         if (minor != 0 && lsp->ls_vp == NULL && !is_opened(lsp))
 331                 lofi_free_handle(dev, minor, lsp, credp);
 332         mutex_exit(&lofi_lock);
 333         return (0);
 334 }
 335 
 336 static int
 337 lofi_mapped_rdwr(caddr_t bufaddr, offset_t offset, struct buf *bp,
 338         struct lofi_state *lsp)



 339 {

 340         int error;
 341         offset_t alignedoffset, mapoffset;




 342         size_t  xfersize;

 343         int     isread;
 344         int     smflags;
 345         caddr_t mapaddr;
 346         size_t  len;
 347         enum seg_rw srw;
 348 










 349         /*











 350          * segmap always gives us an 8K (MAXBSIZE) chunk, aligned on
 351          * an 8K boundary, but the buf transfer address may not be
 352          * aligned on more than a 512-byte boundary (we don't enforce
 353          * that even though we could). This matters since the initial
 354          * part of the transfer may not start at offset 0 within the
 355          * segmap'd chunk. So we have to compensate for that with
 356          * 'mapoffset'. Subsequent chunks always start off at the
 357          * beginning, and the last is capped by b_resid
 358          */
 359         mapoffset = offset & MAXBOFFSET;
 360         alignedoffset = offset - mapoffset;
 361         bp->b_resid = bp->b_bcount;
 362         isread = bp->b_flags & B_READ;
 363         srw = isread ? S_READ : S_WRITE;
 364         do {
 365                 xfersize = MIN(lsp->ls_vp_comp_size - offset,
 366                     MIN(MAXBSIZE - mapoffset, bp->b_resid));
 367                 len = roundup(mapoffset + xfersize, PAGESIZE);
 368                 mapaddr = segmap_getmapflt(segkmap, lsp->ls_vp,
 369                     alignedoffset, MAXBSIZE, 1, srw);
 370                 /*
 371                  * Now fault in the pages. This lets us check
 372                  * for errors before we reference mapaddr and
 373                  * try to resolve the fault in bcopy (which would
 374                  * panic instead). And this can easily happen,
 375                  * particularly if you've lofi'd a file over NFS
 376                  * and someone deletes the file on the server.
 377                  */
 378                 error = segmap_fault(kas.a_hat, segkmap, mapaddr,
 379                     len, F_SOFTLOCK, srw);
 380                 if (error) {
 381                         (void) segmap_release(segkmap, mapaddr, 0);
 382                         if (FC_CODE(error) == FC_OBJERR)
 383                                 error = FC_ERRNO(error);
 384                         else
 385                                 error = EIO;
 386                         break;
 387                 }
 388                 smflags = 0;
 389                 if (isread) {
 390                         smflags |= SM_FREE;
 391                         /*
 392                          * If we're reading an entire page starting
 393                          * at a page boundary, there's a good chance
 394                          * we won't need it again. Put it on the
 395                          * head of the freelist.
 396                          */
 397                         if (mapoffset == 0 && xfersize == PAGESIZE)
 398                                 smflags |= SM_DONTNEED;
 399                         bcopy(mapaddr + mapoffset, bufaddr, xfersize);
 400                 } else {
 401                         smflags |= SM_WRITE;
 402                         bcopy(bufaddr, mapaddr + mapoffset, xfersize);
 403                 }
 404                 bp->b_resid -= xfersize;
 405                 bufaddr += xfersize;
 406                 offset += xfersize;
 407                 (void) segmap_fault(kas.a_hat, segkmap, mapaddr,
 408                     len, F_SOFTUNLOCK, srw);
 409                 error = segmap_release(segkmap, mapaddr, smflags);
 410                 /* only the first map may start partial */
 411                 mapoffset = 0;
 412                 alignedoffset += MAXBSIZE;
 413         } while ((error == 0) && (bp->b_resid > 0) &&
 414             (offset < lsp->ls_vp_comp_size));
 415 
 416         return (error);
 417 }
 418 
 419 /*ARGSUSED*/
 420 static int gzip_decompress(void *src, size_t srclen, void *dst,
 421     size_t *dstlen, int level)
 422 {
 423         ASSERT(*dstlen >= srclen);
 424 
 425         if (z_uncompress(dst, dstlen, src, srclen) != Z_OK)
 426                 return (-1);
 427         return (0);
 428 }
 429 
 430 /*
 431  * This is basically what strategy used to be before we found we
 432  * needed task queues.
 433  */
 434 static void
 435 lofi_strategy_task(void *arg)
 436 {
 437         struct buf *bp = (struct buf *)arg;
 438         int error;
 439         struct lofi_state *lsp;
 440         uint64_t sblkno, eblkno, cmpbytes;
 441         offset_t offset, sblkoff, eblkoff;
 442         offset_t salign, ealign;
 443         offset_t sdiff;
 444         uint32_t comp_data_sz;
 445         caddr_t bufaddr;
 446         unsigned char *compressed_seg = NULL, *cmpbuf;
 447         unsigned char *uncompressed_seg = NULL;
 448         lofi_compress_info_t *li;
 449         size_t oblkcount, xfersize;
 450         unsigned long seglen;
 451 
 452         lsp = ddi_get_soft_state(lofi_statep, getminor(bp->b_edev));
 453         if (lsp->ls_kstat) {
 454                 mutex_enter(lsp->ls_kstat->ks_lock);
 455                 kstat_waitq_to_runq(KSTAT_IO_PTR(lsp->ls_kstat));
 456                 mutex_exit(lsp->ls_kstat->ks_lock);
 457         }
 458         bp_mapin(bp);
 459         bufaddr = bp->b_un.b_addr;
 460         offset = bp->b_lblkno * DEV_BSIZE;   /* offset within file */
 461 
 462         /*
 463          * We used to always use vn_rdwr here, but we cannot do that because
 464          * we might decide to read or write from the the underlying
 465          * file during this call, which would be a deadlock because
 466          * we have the rw_lock. So instead we page, unless it's not
 467          * mapable or it's a character device.
 468          */
 469         if (lsp->ls_vp == NULL || lsp->ls_vp_closereq) {
 470                 error = EIO;
 471         } else if (((lsp->ls_vp->v_flag & VNOMAP) == 0) &&
 472             (lsp->ls_vp->v_type != VCHR)) {
 473                 uint64_t i;
 474 
 475                 /*
 476                  * Handle uncompressed files with a regular read
 477                  */
 478                 if (lsp->ls_uncomp_seg_sz == 0) {
 479                         error = lofi_mapped_rdwr(bufaddr, offset, bp, lsp);
 480                         goto done;
 481                 }
 482 
 483                 /*
 484                  * From here on we're dealing primarily with compressed files
 485                  */
 486 
 487                 /*
 488                  * Compressed files can only be read from and
 489                  * not written to
 490                  */
 491                 if (!(bp->b_flags & B_READ)) {
 492                         bp->b_resid = bp->b_bcount;
 493                         error = EROFS;
 494                         goto done;
 495                 }
 496 
 497                 ASSERT(lsp->ls_comp_algorithm_index >= 0);
 498                 li = &lofi_compress_table[lsp->ls_comp_algorithm_index];
 499                 /*
 500                  * Compute starting and ending compressed segment numbers
 501                  * We use only bitwise operations avoiding division and
 502                  * modulus because we enforce the compression segment size
 503                  * to a power of 2
 504                  */
 505                 sblkno = offset >> lsp->ls_comp_seg_shift;
 506                 sblkoff = offset & (lsp->ls_uncomp_seg_sz - 1);
 507                 eblkno = (offset + bp->b_bcount) >> lsp->ls_comp_seg_shift;
 508                 eblkoff = (offset + bp->b_bcount) & (lsp->ls_uncomp_seg_sz - 1);
 509 
 510                 /*
 511                  * Align start offset to block boundary for segmap
 512                  */
 513                 salign = lsp->ls_comp_seg_index[sblkno];
 514                 sdiff = salign & (DEV_BSIZE - 1);
 515                 salign -= sdiff;
 516                 if (eblkno >= (lsp->ls_comp_index_sz - 1)) {
 517                         /*
 518                          * We're dealing with the last segment of
 519                          * the compressed file -- the size of this
 520                          * segment *may not* be the same as the
 521                          * segment size for the file
 522                          */
 523                         eblkoff = (offset + bp->b_bcount) &
 524                             (lsp->ls_uncomp_last_seg_sz - 1);
 525                         ealign = lsp->ls_vp_comp_size;
 526                 } else {
 527                         ealign = lsp->ls_comp_seg_index[eblkno + 1];
 528                 }
 529 
 530                 /*
 531                  * Preserve original request paramaters
 532                  */
 533                 oblkcount = bp->b_bcount;
 534 
 535                 /*
 536                  * Assign the calculated parameters
 537                  */
 538                 comp_data_sz = ealign - salign;
 539                 bp->b_bcount = comp_data_sz;
 540 
 541                 /*
 542                  * Allocate fixed size memory blocks to hold one
 543                  * compressed and uncompressed segment since we
 544                  * uncompress segments one at a time
 545                  */
 546                 compressed_seg = kmem_alloc(bp->b_bcount, KM_SLEEP);
 547                 uncompressed_seg = kmem_alloc(lsp->ls_uncomp_seg_sz, KM_SLEEP);
 548                 /*
 549                  * Map in the calculated number of blocks
 550                  */
 551                 error = lofi_mapped_rdwr((caddr_t)compressed_seg, salign,
 552                     bp, lsp);
 553 
 554                 bp->b_bcount = oblkcount;
 555                 bp->b_resid = oblkcount;
 556                 if (error != 0)
 557                         goto done;
 558 
 559                 /*
 560                  * We have the compressed blocks, now uncompress them
 561                  */
 562                 cmpbuf = compressed_seg + sdiff;
 563                 for (i = sblkno; i < (eblkno + 1) && i < lsp->ls_comp_index_sz;
 564                     i++) {
 565                         /*
 566                          * Each of the segment index entries contains
 567                          * the starting block number for that segment.
 568                          * The number of compressed bytes in a segment
 569                          * is thus the difference between the starting
 570                          * block number of this segment and the starting
 571                          * block number of the next segment.
 572                          */
 573                         if ((i == eblkno) &&
 574                             (i == lsp->ls_comp_index_sz - 1)) {
 575                                 cmpbytes = lsp->ls_vp_comp_size -
 576                                     lsp->ls_comp_seg_index[i];
 577                         } else {
 578                                 cmpbytes = lsp->ls_comp_seg_index[i + 1] -
 579                                     lsp->ls_comp_seg_index[i];
 580                         }
 581 
 582                         /*
 583                          * The first byte in a compressed segment is a flag
 584                          * that indicates whether is this segment is
 585                          * compressed at all
 586                          */
 587                         if (*cmpbuf == UNCOMPRESSED) {
 588                                 bcopy((cmpbuf + SEGHDR), uncompressed_seg,
 589                                     (cmpbytes - SEGHDR));
 590                         } else {
 591                                 seglen = lsp->ls_uncomp_seg_sz;
 592 
 593                                 if (li->l_decompress((cmpbuf + SEGHDR),
 594                                     (cmpbytes - SEGHDR), uncompressed_seg,
 595                                     &seglen, li->l_level) != 0) {
 596                                         error = EIO;
 597                                         goto done;
 598                                 }
 599                         }
 600 
 601                         /*
 602                          * Determine how much uncompressed data we
 603                          * have to copy and copy it
 604                          */
 605                         xfersize = lsp->ls_uncomp_seg_sz - sblkoff;
 606                         if (i == eblkno) {
 607                                 if (i == (lsp->ls_comp_index_sz - 1))
 608                                         xfersize -= (lsp->ls_uncomp_last_seg_sz
 609                                             - eblkoff);
 610                                 else
 611                                         xfersize -=
 612                                             (lsp->ls_uncomp_seg_sz - eblkoff);
 613                         }
 614 
 615                         bcopy((uncompressed_seg + sblkoff), bufaddr, xfersize);
 616 
 617                         cmpbuf += cmpbytes;
 618                         bufaddr += xfersize;
 619                         bp->b_resid -= xfersize;
 620                         sblkoff = 0;
 621 
 622                         if (bp->b_resid == 0)
 623                                 break;
 624                 }
 625         } else {
 626                 ssize_t resid;
 627                 enum uio_rw rw;
 628 
 629                 if (bp->b_flags & B_READ)
 630                         rw = UIO_READ;
 631                 else
 632                         rw = UIO_WRITE;
 633                 error = vn_rdwr(rw, lsp->ls_vp, bufaddr, bp->b_bcount,
 634                     offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
 635                 bp->b_resid = resid;
 636         }
 637 
 638 done:
 639         if (compressed_seg != NULL)
 640                 kmem_free(compressed_seg, comp_data_sz);
 641         if (uncompressed_seg != NULL)
 642                 kmem_free(uncompressed_seg, lsp->ls_uncomp_seg_sz);
 643 
 644         if (lsp->ls_kstat) {
 645                 size_t n_done = bp->b_bcount - bp->b_resid;
 646                 kstat_io_t *kioptr;
 647 
 648                 mutex_enter(lsp->ls_kstat->ks_lock);
 649                 kioptr = KSTAT_IO_PTR(lsp->ls_kstat);
 650                 if (bp->b_flags & B_READ) {
 651                         kioptr->nread += n_done;
 652                         kioptr->reads++;
 653                 } else {
 654                         kioptr->nwritten += n_done;
 655                         kioptr->writes++;
 656                 }
 657                 kstat_runq_exit(kioptr);
 658                 mutex_exit(lsp->ls_kstat->ks_lock);
 659         }
 660 
 661         mutex_enter(&lsp->ls_vp_lock);
 662         if (--lsp->ls_vp_iocount == 0)
 663                 cv_broadcast(&lsp->ls_vp_cv);


 820 }
 821 
 822 /*
 823  * These two just simplify the rest of the ioctls that need to copyin/out
 824  * the lofi_ioctl structure.
 825  */
 826 struct lofi_ioctl *
 827 copy_in_lofi_ioctl(const struct lofi_ioctl *ulip, int flag)
 828 {
 829         struct lofi_ioctl *klip;
 830         int     error;
 831 
 832         klip = kmem_alloc(sizeof (struct lofi_ioctl), KM_SLEEP);
 833         error = ddi_copyin(ulip, klip, sizeof (struct lofi_ioctl), flag);
 834         if (error) {
 835                 kmem_free(klip, sizeof (struct lofi_ioctl));
 836                 return (NULL);
 837         }
 838 
 839         /* make sure filename is always null-terminated */
 840         klip->li_filename[MAXPATHLEN - 1] = '\0';
 841 
 842         /* validate minor number */
 843         if (klip->li_minor > lofi_max_files) {
 844                 kmem_free(klip, sizeof (struct lofi_ioctl));
 845                 return (NULL);
 846         }
 847         return (klip);
 848 }
 849 
 850 int
 851 copy_out_lofi_ioctl(const struct lofi_ioctl *klip, struct lofi_ioctl *ulip,
 852         int flag)
 853 {
 854         int     error;
 855 
 856         error = ddi_copyout(klip, ulip, sizeof (struct lofi_ioctl), flag);
 857         if (error)
 858                 return (EFAULT);
 859         return (0);
 860 }


 942         lsp->ls_dkg.dkg_obs1 = 0;
 943         lsp->ls_dkg.dkg_intrlv = 0;
 944         lsp->ls_dkg.dkg_obs2 = 0;
 945         lsp->ls_dkg.dkg_obs3 = 0;
 946         lsp->ls_dkg.dkg_apc = 0;
 947         lsp->ls_dkg.dkg_rpm = 7200;
 948         lsp->ls_dkg.dkg_pcyl = lsp->ls_dkg.dkg_ncyl + lsp->ls_dkg.dkg_acyl;
 949         lsp->ls_dkg.dkg_nsect = lsp->ls_vp_size /
 950             (DEV_BSIZE * lsp->ls_dkg.dkg_ncyl);
 951         lsp->ls_dkg.dkg_write_reinstruct = 0;
 952         lsp->ls_dkg.dkg_read_reinstruct = 0;
 953 
 954         /* vtoc - see dkio(7I) */
 955         bzero(&lsp->ls_vtoc, sizeof (struct vtoc));
 956         lsp->ls_vtoc.v_sanity = VTOC_SANE;
 957         lsp->ls_vtoc.v_version = V_VERSION;
 958         bcopy(LOFI_DRIVER_NAME, lsp->ls_vtoc.v_volume, 7);
 959         lsp->ls_vtoc.v_sectorsz = DEV_BSIZE;
 960         lsp->ls_vtoc.v_nparts = 1;
 961         lsp->ls_vtoc.v_part[0].p_tag = V_UNASSIGNED;
 962 
 963         /*
 964          * A compressed file is read-only, other files can
 965          * be read-write
 966          */
 967         if (lsp->ls_uncomp_seg_sz > 0) {
 968                 lsp->ls_vtoc.v_part[0].p_flag = V_UNMNT | V_RONLY;
 969         } else {
 970                 lsp->ls_vtoc.v_part[0].p_flag = V_UNMNT;
 971         }
 972         lsp->ls_vtoc.v_part[0].p_start = (daddr_t)0;
 973         /*
 974          * The partition size cannot just be the number of sectors, because
 975          * that might not end on a cylinder boundary. And if that's the case,
 976          * newfs/mkfs will print a scary warning. So just figure the size
 977          * based on the number of cylinders and sectors/cylinder.
 978          */
 979         lsp->ls_vtoc.v_part[0].p_size = lsp->ls_dkg.dkg_pcyl *
 980             lsp->ls_dkg.dkg_nsect * lsp->ls_dkg.dkg_nhead;
 981 
 982         /* dk_cinfo - see dkio(7I) */
 983         bzero(&lsp->ls_ci, sizeof (struct dk_cinfo));
 984         (void) strcpy(lsp->ls_ci.dki_cname, LOFI_DRIVER_NAME);
 985         lsp->ls_ci.dki_ctype = DKC_MD;
 986         lsp->ls_ci.dki_flags = 0;
 987         lsp->ls_ci.dki_cnum = 0;
 988         lsp->ls_ci.dki_addr = 0;
 989         lsp->ls_ci.dki_space = 0;
 990         lsp->ls_ci.dki_prio = 0;
 991         lsp->ls_ci.dki_vec = 0;
 992         (void) strcpy(lsp->ls_ci.dki_dname, LOFI_DRIVER_NAME);
 993         lsp->ls_ci.dki_unit = 0;
 994         lsp->ls_ci.dki_slave = 0;
 995         lsp->ls_ci.dki_partition = 0;
 996         /*
 997          * newfs uses this to set maxcontig. Must not be < 16, or it
 998          * will be 0 when newfs multiplies it by DEV_BSIZE and divides
 999          * it by the block size. Then tunefs doesn't work because
1000          * maxcontig is 0.
1001          */
1002         lsp->ls_ci.dki_maxtransfer = 16;
1003 }
1004 
1005 /*
1006  * map in a compressed file
1007  *
1008  * Read in the header and the index that follows.
1009  *
1010  * The header is as follows -
1011  *
1012  * Signature (name of the compression algorithm)
1013  * Compression segment size (a multiple of 512)
1014  * Number of index entries
1015  * Size of the last block
1016  * The array containing the index entries
1017  *
1018  * The header information is always stored in
1019  * network byte order on disk.
1020  */
1021 static int
1022 lofi_map_compressed_file(struct lofi_state *lsp, char *buf)
1023 {
1024         uint32_t index_sz, header_len, i;
1025         ssize_t resid;
1026         enum uio_rw rw;
1027         char *tbuf = buf;
1028         int error;
1029 
1030         /* The signature has already been read */
1031         tbuf += lsp->ls_comp_algorithm_len;
1032         bcopy(tbuf, &(lsp->ls_uncomp_seg_sz), sizeof (lsp->ls_uncomp_seg_sz));
1033         lsp->ls_uncomp_seg_sz = ntohl(lsp->ls_uncomp_seg_sz);
1034 
1035         /*
1036          * The compressed segment size must be a power of 2
1037          */
1038         if (lsp->ls_uncomp_seg_sz % 2)
1039                 return (EINVAL);
1040 
1041         for (i = 0; !((lsp->ls_uncomp_seg_sz >> i) & 1); i++)
1042                 ;
1043 
1044         lsp->ls_comp_seg_shift = i;
1045 
1046         tbuf += sizeof (lsp->ls_uncomp_seg_sz);
1047         bcopy(tbuf, &(lsp->ls_comp_index_sz), sizeof (lsp->ls_comp_index_sz));
1048         lsp->ls_comp_index_sz = ntohl(lsp->ls_comp_index_sz);
1049 
1050         tbuf += sizeof (lsp->ls_comp_index_sz);
1051         bcopy(tbuf, &(lsp->ls_uncomp_last_seg_sz),
1052             sizeof (lsp->ls_uncomp_last_seg_sz));
1053         lsp->ls_uncomp_last_seg_sz = ntohl(lsp->ls_uncomp_last_seg_sz);
1054 
1055         /*
1056          * Compute the total size of the uncompressed data
1057          * for use in fake_disk_geometry and other calculations.
1058          * Disk geometry has to be faked with respect to the
1059          * actual uncompressed data size rather than the
1060          * compressed file size.
1061          */
1062         /* XXX '2' shouldn't subtracted here - should be '1' */
1063         lsp->ls_vp_size = (lsp->ls_comp_index_sz - 2) * lsp->ls_uncomp_seg_sz
1064             + lsp->ls_uncomp_last_seg_sz;
1065 
1066         /*
1067          * Index size is rounded up to a 512 byte boundary for ease
1068          * of segmapping
1069          */
1070         index_sz = sizeof (lsp->ls_comp_seg_index) * lsp->ls_comp_index_sz;
1071         header_len = lsp->ls_comp_algorithm_len +
1072             sizeof (lsp->ls_uncomp_seg_sz) +
1073             sizeof (lsp->ls_comp_index_sz) +
1074             sizeof (lsp->ls_uncomp_last_seg_sz);
1075         lsp->ls_comp_offbase = header_len + index_sz;
1076 
1077         index_sz += header_len;
1078         index_sz = roundup(index_sz, DEV_BSIZE);
1079 
1080         lsp->ls_comp_index_data = kmem_alloc(index_sz, KM_SLEEP);
1081         lsp->ls_comp_index_data_sz = index_sz;
1082 
1083         /*
1084          * Read in the index -- this has a side-effect
1085          * of reading in the header as well
1086          */
1087         rw = UIO_READ;
1088         error = vn_rdwr(rw, lsp->ls_vp, lsp->ls_comp_index_data, index_sz,
1089             0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
1090 
1091         if (error != 0)
1092                 return (error);
1093 
1094         /* Skip the header, this is where the index really begins */
1095         lsp->ls_comp_seg_index =
1096             /*LINTED*/
1097             (uint64_t *)(lsp->ls_comp_index_data + header_len);
1098 
1099         /* Now map the index into memory */
1100         for (i = 0; i < lsp->ls_comp_index_sz; i++)
1101                 lsp->ls_comp_seg_index[i] = lsp->ls_comp_offbase +
1102                     lsp->ls_comp_seg_index[i];
1103 
1104         return (error);
1105 }
1106 
1107 /*
1108  * Check to see if the passed in signature is a valid
1109  * one. If it is valid, return the index into
1110  * lofi_compress_table.
1111  *
1112  * Return -1 if it is invalid
1113  */
1114 static int lofi_compress_select(char *signature)
1115 {
1116         int i;
1117 
1118         for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) {
1119                 if (strcmp(lofi_compress_table[i].l_name, signature) == 0)
1120                         return (i);
1121         }
1122 
1123         return (-1);
1124 }
1125 
1126 /*
1127  * map a file to a minor number. Return the minor number.
1128  */
1129 static int
1130 lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
1131     int *rvalp, struct cred *credp, int ioctl_flag)
1132 {
1133         minor_t newminor;
1134         struct lofi_state *lsp;
1135         struct lofi_ioctl *klip;
1136         int     error;
1137         struct vnode *vp;
1138         int64_t Nblocks_prop_val;
1139         int64_t Size_prop_val;
1140         int     compress_index;
1141         vattr_t vattr;
1142         int     flag;
1143         enum vtype v_type;
1144         int zalloced = 0;
1145         dev_t   newdev;
1146         char    namebuf[50];
1147         char    buf[DEV_BSIZE];
1148         char    *tbuf;
1149         ssize_t resid;
1150         enum uio_rw rw;
1151 
1152         klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
1153         if (klip == NULL)
1154                 return (EFAULT);
1155 
1156         mutex_enter(&lofi_lock);
1157 
1158         if (!valid_filename(klip->li_filename)) {
1159                 error = EINVAL;
1160                 goto out;
1161         }
1162 
1163         if (file_to_minor(klip->li_filename) != 0) {
1164                 error = EBUSY;
1165                 goto out;
1166         }
1167 
1168         if (pickminor) {
1169                 /* Find a free one */
1170                 for (newminor = 1; newminor <= lofi_max_files; newminor++)


1189                 goto out;
1190         }
1191         v_type = vp->v_type;
1192         VN_RELE(vp);
1193         if (!V_ISLOFIABLE(v_type)) {
1194                 error = EINVAL;
1195                 goto out;
1196         }
1197         flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1198         error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, &vp, 0, 0);
1199         if (error) {
1200                 /* try read-only */
1201                 flag &= ~FWRITE;
1202                 error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0,
1203                     &vp, 0, 0);
1204                 if (error) {
1205                         goto out;
1206                 }
1207         }
1208         vattr.va_mask = AT_SIZE;
1209         error = VOP_GETATTR(vp, &vattr, 0, credp);
1210         if (error) {
1211                 goto closeout;
1212         }
1213         /* the file needs to be a multiple of the block size */
1214         if ((vattr.va_size % DEV_BSIZE) != 0) {
1215                 error = EINVAL;
1216                 goto closeout;
1217         }
1218         newdev = makedevice(getmajor(dev), newminor);
1219         Size_prop_val = vattr.va_size;
1220         if ((ddi_prop_update_int64(newdev, lofi_dip,
1221             SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) {
1222                 error = EINVAL;
1223                 goto closeout;
1224         }
1225         Nblocks_prop_val = vattr.va_size / DEV_BSIZE;
1226         if ((ddi_prop_update_int64(newdev, lofi_dip,
1227             NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) {
1228                 error = EINVAL;
1229                 goto propout;


1261         lsp->ls_kstat = kstat_create(LOFI_DRIVER_NAME, newminor,
1262             NULL, "disk", KSTAT_TYPE_IO, 1, 0);
1263         if (lsp->ls_kstat) {
1264                 mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL);
1265                 lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
1266                 kstat_install(lsp->ls_kstat);
1267         }
1268         cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL);
1269         mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL);
1270 
1271         /*
1272          * save open mode so file can be closed properly and vnode counts
1273          * updated correctly.
1274          */
1275         lsp->ls_openflag = flag;
1276 
1277         /*
1278          * Try to handle stacked lofs vnodes.
1279          */
1280         if (vp->v_type == VREG) {
1281                 if (VOP_REALVP(vp, &lsp->ls_vp) != 0) {
1282                         lsp->ls_vp = vp;
1283                 } else {
1284                         /*
1285                          * Even though vp was obtained via vn_open(), we
1286                          * can't call vn_close() on it, since lofs will
1287                          * pass the VOP_CLOSE() on down to the realvp
1288                          * (which we are about to use). Hence we merely
1289                          * drop the reference to the lofs vnode and hold
1290                          * the realvp so things behave as if we've
1291                          * opened the realvp without any interaction
1292                          * with lofs.
1293                          */
1294                         VN_HOLD(lsp->ls_vp);
1295                         VN_RELE(vp);
1296                 }
1297         } else {
1298                 lsp->ls_vp = vp;
1299         }
1300         lsp->ls_vp_size = vattr.va_size;
1301         (void) strcpy(lsp->ls_filename, klip->li_filename);
1302         if (rvalp)
1303                 *rvalp = (int)newminor;
1304         klip->li_minor = newminor;
1305 
1306         /*
1307          * Read the file signature to check if it is compressed.
1308          * 'rw' is set to read since only reads are allowed to
1309          * a compressed file.
1310          */
1311         rw = UIO_READ;
1312         error = vn_rdwr(rw, lsp->ls_vp, buf, DEV_BSIZE, 0, UIO_SYSSPACE,
1313             0, RLIM64_INFINITY, kcred, &resid);
1314 
1315         if (error != 0)
1316                 goto propout;
1317 
1318         tbuf = buf;
1319         lsp->ls_uncomp_seg_sz = 0;
1320         lsp->ls_vp_comp_size = lsp->ls_vp_size;
1321         lsp->ls_comp_algorithm_len = 0;
1322 
1323         compress_index = lofi_compress_select(tbuf);
1324         if (compress_index != -1) {
1325                 lsp->ls_comp_algorithm_index = compress_index;
1326                 lsp->ls_comp_algorithm_len =
1327                     strlen(lofi_compress_table[compress_index].l_name);
1328                 error = lofi_map_compressed_file(lsp, buf);
1329                 if (error != 0)
1330                         goto propout;
1331 
1332                 /* update DDI properties */
1333                 Size_prop_val = lsp->ls_vp_size;
1334                 if ((ddi_prop_update_int64(newdev, lofi_dip, SIZE_PROP_NAME,
1335                     Size_prop_val)) != DDI_PROP_SUCCESS) {
1336                         error = EINVAL;
1337                         goto propout;
1338                 }
1339 
1340                 Nblocks_prop_val = lsp->ls_vp_size / DEV_BSIZE;
1341                 if ((ddi_prop_update_int64(newdev, lofi_dip, NBLOCKS_PROP_NAME,
1342                     Nblocks_prop_val)) != DDI_PROP_SUCCESS) {
1343                         error = EINVAL;
1344                         goto propout;
1345                 }
1346         }
1347 
1348         fake_disk_geometry(lsp);
1349         mutex_exit(&lofi_lock);
1350         (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1351         free_lofi_ioctl(klip);
1352         return (0);
1353 
1354 propout:
1355         (void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
1356         (void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
1357 closeout:
1358         (void) VOP_CLOSE(vp, flag, 1, 0, credp);
1359         VN_RELE(vp);
1360 out:
1361         if (zalloced)
1362                 ddi_soft_state_free(lofi_statep, newminor);
1363         mutex_exit(&lofi_lock);
1364         free_lofi_ioctl(klip);
1365         return (error);
1366 }
1367 
1368 /*
1369  * unmap a file.
1370  */
1371 static int
1372 lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename,
1373     struct cred *credp, int ioctl_flag)
1374 {
1375         struct lofi_state *lsp;
1376         struct lofi_ioctl *klip;
1377         minor_t minor;
1378 


1402                 /*
1403                  * If the 'force' flag is set, then we forcibly close the
1404                  * underlying file.  Subsequent operations will fail, and the
1405                  * DKIOCSTATE ioctl will return DKIO_DEV_GONE.  When the device
1406                  * is last closed, the device will be cleaned up appropriately.
1407                  *
1408                  * This is complicated by the fact that we may have outstanding
1409                  * dispatched I/Os.  Rather than having a single mutex to
1410                  * serialize all I/O, we keep a count of the number of
1411                  * outstanding I/O requests, as well as a flag to indicate that
1412                  * no new I/Os should be dispatched.  We set the flag, wait for
1413                  * the number of outstanding I/Os to reach 0, and then close the
1414                  * underlying vnode.
1415                  */
1416                 if (klip->li_force) {
1417                         mutex_enter(&lsp->ls_vp_lock);
1418                         lsp->ls_vp_closereq = B_TRUE;
1419                         while (lsp->ls_vp_iocount > 0)
1420                                 cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock);
1421                         (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0,
1422                             credp);
1423                         VN_RELE(lsp->ls_vp);
1424                         lsp->ls_vp = NULL;
1425                         cv_broadcast(&lsp->ls_vp_cv);
1426                         mutex_exit(&lsp->ls_vp_lock);
1427                         mutex_exit(&lofi_lock);
1428                         klip->li_minor = minor;
1429                         (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1430                         free_lofi_ioctl(klip);
1431                         return (0);
1432                 }
1433                 mutex_exit(&lofi_lock);
1434                 free_lofi_ioctl(klip);
1435                 return (EBUSY);
1436         }
1437 
1438         if (lsp->ls_uncomp_seg_sz > 0) {
1439                 kmem_free(lsp->ls_comp_index_data, lsp->ls_comp_index_data_sz);
1440                 lsp->ls_uncomp_seg_sz = 0;
1441         }
1442 
1443         lofi_free_handle(dev, minor, lsp, credp);
1444 
1445         klip->li_minor = minor;
1446         mutex_exit(&lofi_lock);
1447         (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1448         free_lofi_ioctl(klip);
1449         return (0);
1450 }
1451 
1452 /*
1453  * get the filename given the minor number, or the minor number given
1454  * the name.
1455  */
1456 /*ARGSUSED*/
1457 static int
1458 lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which,
1459     struct cred *credp, int ioctl_flag)
1460 {
1461         struct lofi_state *lsp;
1462         struct lofi_ioctl *klip;


1466         klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
1467         if (klip == NULL)
1468                 return (EFAULT);
1469 
1470         switch (which) {
1471         case LOFI_GET_FILENAME:
1472                 minor = klip->li_minor;
1473                 if (minor == 0) {
1474                         free_lofi_ioctl(klip);
1475                         return (EINVAL);
1476                 }
1477 
1478                 mutex_enter(&lofi_lock);
1479                 lsp = ddi_get_soft_state(lofi_statep, minor);
1480                 if (lsp == NULL) {
1481                         mutex_exit(&lofi_lock);
1482                         free_lofi_ioctl(klip);
1483                         return (ENXIO);
1484                 }
1485                 (void) strcpy(klip->li_filename, lsp->ls_filename);
1486                 if (lsp->ls_comp_algorithm_len == 0)
1487                         klip->li_algorithm[0] = '\0';
1488                 else
1489                         (void) strlcpy(klip->li_algorithm, lofi_compress_table[
1490                             lsp->ls_comp_algorithm_index].l_name,
1491                             lsp->ls_comp_algorithm_len + 1);
1492                 mutex_exit(&lofi_lock);
1493                 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1494                 free_lofi_ioctl(klip);
1495                 return (error);
1496         case LOFI_GET_MINOR:
1497                 mutex_enter(&lofi_lock);
1498                 klip->li_minor = file_to_minor(klip->li_filename);
1499                 mutex_exit(&lofi_lock);
1500                 if (klip->li_minor == 0) {
1501                         free_lofi_ioctl(klip);
1502                         return (ENOENT);
1503                 }
1504                 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1505                 free_lofi_ioctl(klip);
1506                 return (error);
1507         case LOFI_CHECK_COMPRESSED:
1508                 mutex_enter(&lofi_lock);
1509                 klip->li_minor = file_to_minor(klip->li_filename);
1510                 mutex_exit(&lofi_lock);
1511                 if (klip->li_minor == 0) {
1512                         free_lofi_ioctl(klip);
1513                         return (ENOENT);
1514                 }
1515                 mutex_enter(&lofi_lock);
1516                 lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
1517                 if (lsp == NULL) {
1518                         mutex_exit(&lofi_lock);
1519                         free_lofi_ioctl(klip);
1520                         return (ENXIO);
1521                 }
1522                 ASSERT(strcmp(klip->li_filename, lsp->ls_filename) == 0);
1523 
1524                 if (lsp->ls_comp_algorithm_len == 0)
1525                         klip->li_algorithm[0] = '\0';
1526                 else
1527                         (void) strlcpy(klip->li_algorithm, lofi_compress_table[
1528                             lsp->ls_comp_algorithm_index].l_name,
1529                             lsp->ls_comp_algorithm_len + 1);
1530 
1531                 mutex_exit(&lofi_lock);
1532                 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
1533                 free_lofi_ioctl(klip);
1534                 return (error);
1535         default:
1536                 free_lofi_ioctl(klip);
1537                 return (EINVAL);
1538         }
1539 
1540 }
1541 
1542 static int
1543 lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp,
1544     int *rvalp)
1545 {
1546         int     error;
1547         enum dkio_state dkstate;
1548         struct lofi_state *lsp;
1549         minor_t minor;
1550 
1551 #ifdef lint
1552         credp = credp;
1553 #endif
1554 


1574                 case LOFI_UNMAP_FILE:
1575                         if ((flag & FWRITE) == 0)
1576                                 return (EPERM);
1577                         return (lofi_unmap_file(dev, lip, 1, credp, flag));
1578                 case LOFI_UNMAP_FILE_MINOR:
1579                         if ((flag & FWRITE) == 0)
1580                                 return (EPERM);
1581                         return (lofi_unmap_file(dev, lip, 0, credp, flag));
1582                 case LOFI_GET_FILENAME:
1583                         return (lofi_get_info(dev, lip, LOFI_GET_FILENAME,
1584                             credp, flag));
1585                 case LOFI_GET_MINOR:
1586                         return (lofi_get_info(dev, lip, LOFI_GET_MINOR,
1587                             credp, flag));
1588                 case LOFI_GET_MAXMINOR:
1589                         error = ddi_copyout(&lofi_max_files, &lip->li_minor,
1590                             sizeof (lofi_max_files), flag);
1591                         if (error)
1592                                 return (EFAULT);
1593                         return (0);
1594                 case LOFI_CHECK_COMPRESSED:
1595                         return (lofi_get_info(dev, lip, LOFI_CHECK_COMPRESSED,
1596                             credp, flag));
1597                 default:
1598                         break;
1599                 }
1600         }
1601 
1602         lsp = ddi_get_soft_state(lofi_statep, minor);
1603         if (lsp == NULL)
1604                 return (ENXIO);
1605 
1606         /*
1607          * We explicitly allow DKIOCSTATE, but all other ioctls should fail with
1608          * EIO as if the device was no longer present.
1609          */
1610         if (lsp->ls_vp == NULL && cmd != DKIOCSTATE)
1611                 return (EIO);
1612 
1613         /* these are for faking out utilities like newfs */
1614         switch (cmd) {
1615         case DKIOCGVTOC:
1616                 switch (ddi_model_convert_from(flag & FMODELS)) {