461 return (0);
462 }
463
464 /* otherwise, the mapping should already exist */
465 lsp = ddi_get_soft_state(lofi_statep, minor);
466 if (lsp == NULL) {
467 mutex_exit(&lofi_lock);
468 return (EINVAL);
469 }
470
471 if (lsp->ls_vp == NULL) {
472 mutex_exit(&lofi_lock);
473 return (ENXIO);
474 }
475
476 if (mark_opened(lsp, otyp) == -1) {
477 mutex_exit(&lofi_lock);
478 return (EINVAL);
479 }
480
481 mutex_exit(&lofi_lock);
482 return (0);
483 }
484
485 /*ARGSUSED*/
486 static int
487 lofi_close(dev_t dev, int flag, int otyp, struct cred *credp)
488 {
489 minor_t minor;
490 struct lofi_state *lsp;
491
492 mutex_enter(&lofi_lock);
493 minor = getminor(dev);
494 lsp = ddi_get_soft_state(lofi_statep, minor);
495 if (lsp == NULL) {
496 mutex_exit(&lofi_lock);
497 return (EINVAL);
498 }
499
500 if (minor == 0) {
501 mutex_exit(&lofi_lock);
1603 error = ddi_copyout(klip, ulip, sizeof (struct lofi_ioctl), flag);
1604 if (error)
1605 return (EFAULT);
1606 return (0);
1607 }
1608
1609 static int
1610 lofi_access(struct lofi_state *lsp)
1611 {
1612 ASSERT(MUTEX_HELD(&lofi_lock));
1613 if (INGLOBALZONE(curproc) || lsp->ls_zone.zref_zone == curzone)
1614 return (0);
1615 return (EPERM);
1616 }
1617
1618 /*
1619 * Find the lofi state for the given filename. We compare by vnode to
1620 * allow the global zone visibility into NGZ lofi nodes.
1621 */
1622 static int
1623 file_to_lofi_nocheck(char *filename, struct lofi_state **lspp)
1624 {
1625 struct lofi_state *lsp;
1626 vnode_t *vp = NULL;
1627 int err = 0;
1628
1629 ASSERT(MUTEX_HELD(&lofi_lock));
1630
1631 if ((err = lookupname(filename, UIO_SYSSPACE, FOLLOW,
1632 NULLVPP, &vp)) != 0)
1633 goto out;
1634
1635 if (vp->v_type == VREG) {
1636 vnode_t *realvp;
1637 if (VOP_REALVP(vp, &realvp, NULL) == 0) {
1638 VN_HOLD(realvp);
1639 VN_RELE(vp);
1640 vp = realvp;
1641 }
1642 }
1643
1644 for (lsp = list_head(&lofi_list); lsp != NULL;
1645 lsp = list_next(&lofi_list, lsp)) {
1646 if (lsp->ls_vp == vp) {
1647 if (lspp != NULL)
1648 *lspp = lsp;
1649 goto out;
1650 }
1651 }
1652
1653 err = ENOENT;
1654
1655 out:
1656 if (vp != NULL)
1657 VN_RELE(vp);
1658 return (err);
1659 }
1660
1661 /*
1662 * Find the minor for the given filename, checking the zone can access
1663 * it.
1664 */
1665 static int
1666 file_to_lofi(char *filename, struct lofi_state **lspp)
1667 {
1668 int err = 0;
1669
1670 ASSERT(MUTEX_HELD(&lofi_lock));
1671
1672 if ((err = file_to_lofi_nocheck(filename, lspp)) != 0)
1673 return (err);
1674
1675 if ((err = lofi_access(*lspp)) != 0)
1676 return (err);
1677
1678 return (0);
1679 }
1680
1681 /*
1682 * Fakes up a disk geometry, and one big partition, based on the size
1683 * of the file. This is needed because we allow newfs'ing the device,
1684 * and newfs will do several disk ioctls to figure out the geometry and
1685 * partition information. It uses that information to determine the parameters
1686 * to pass to mkfs. Geometry is pretty much irrelevant these days, but we
1687 * have to support it.
1688 */
1689 static void
1690 fake_disk_geometry(struct lofi_state *lsp)
1691 {
1692 u_offset_t dsize = lsp->ls_vp_size - lsp->ls_crypto_offset;
2105 vattr_t vattr;
2106 int flag;
2107 dev_t newdev;
2108 char namebuf[50];
2109
2110 error = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
2111 if (error != 0)
2112 return (error);
2113
2114 mutex_enter(&lofi_lock);
2115
2116 mutex_enter(&curproc->p_lock);
2117 if ((error = rctl_incr_lofi(curproc, curproc->p_zone, 1)) != 0) {
2118 mutex_exit(&curproc->p_lock);
2119 mutex_exit(&lofi_lock);
2120 free_lofi_ioctl(klip);
2121 return (error);
2122 }
2123 mutex_exit(&curproc->p_lock);
2124
2125 if (file_to_lofi_nocheck(klip->li_filename, NULL) == 0) {
2126 error = EBUSY;
2127 goto err;
2128 }
2129
2130 if (pickminor) {
2131 minor = (minor_t)id_allocff_nosleep(lofi_minor_id);
2132 if (minor == (minor_t)-1) {
2133 error = EAGAIN;
2134 goto err;
2135 }
2136 } else {
2137 if (ddi_get_soft_state(lofi_statep, klip->li_minor) != NULL) {
2138 error = EEXIST;
2139 goto err;
2140 }
2141
2142 minor = (minor_t)
2143 id_alloc_specific_nosleep(lofi_minor_id, klip->li_minor);
2144 ASSERT(minor != (minor_t)-1);
2145 }
2226 */
2227 VN_HOLD(realvp);
2228 lsp->ls_vp = realvp;
2229 }
2230 }
2231
2232 lsp->ls_vp_size = vattr.va_size;
2233 lsp->ls_vp_comp_size = lsp->ls_vp_size;
2234
2235 lsp->ls_kstat = kstat_create_zone(LOFI_DRIVER_NAME, minor,
2236 NULL, "disk", KSTAT_TYPE_IO, 1, 0, getzoneid());
2237
2238 if (lsp->ls_kstat == NULL) {
2239 error = ENOMEM;
2240 goto err;
2241 }
2242
2243 lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
2244 kstat_zone_add(lsp->ls_kstat, GLOBAL_ZONEID);
2245
2246 if ((error = lofi_init_crypto(lsp, klip)) != 0)
2247 goto err;
2248
2249 if ((error = lofi_init_compress(lsp)) != 0)
2250 goto err;
2251
2252 fake_disk_geometry(lsp);
2253
2254 /* create minor nodes */
2255
2256 (void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
2257 error = ddi_create_minor_node(lofi_dip, namebuf, S_IFBLK, minor,
2258 DDI_PSEUDO, NULL);
2259 if (error != DDI_SUCCESS) {
2260 error = ENXIO;
2261 goto err;
2262 }
2263
2264 (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
2265 error = ddi_create_minor_node(lofi_dip, namebuf, S_IFCHR, minor,
2326 return (error);
2327 }
2328
2329 /*
2330 * unmap a file.
2331 */
2332 static int
2333 lofi_unmap_file(struct lofi_ioctl *ulip, int byfilename,
2334 struct cred *credp, int ioctl_flag)
2335 {
2336 struct lofi_state *lsp;
2337 struct lofi_ioctl *klip;
2338 int err;
2339
2340 err = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
2341 if (err != 0)
2342 return (err);
2343
2344 mutex_enter(&lofi_lock);
2345 if (byfilename) {
2346 if ((err = file_to_lofi(klip->li_filename, &lsp)) != 0) {
2347 mutex_exit(&lofi_lock);
2348 return (err);
2349 }
2350 } else if (klip->li_minor == 0) {
2351 mutex_exit(&lofi_lock);
2352 free_lofi_ioctl(klip);
2353 return (ENXIO);
2354 } else {
2355 lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
2356 }
2357
2358 if (lsp == NULL || lsp->ls_vp == NULL || lofi_access(lsp) != 0) {
2359 mutex_exit(&lofi_lock);
2360 free_lofi_ioctl(klip);
2361 return (ENXIO);
2362 }
2363
2364 klip->li_minor = getminor(lsp->ls_dev);
2365
2366 /*
2443 }
2444
2445 mutex_enter(&lofi_lock);
2446 lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
2447 if (lsp == NULL || lofi_access(lsp) != 0) {
2448 mutex_exit(&lofi_lock);
2449 free_lofi_ioctl(klip);
2450 return (ENXIO);
2451 }
2452
2453 /*
2454 * This may fail if, for example, we're trying to look
2455 * up a zoned NFS path from the global zone.
2456 */
2457 if (vnodetopath(NULL, lsp->ls_stacked_vp, klip->li_filename,
2458 sizeof (klip->li_filename), CRED()) != 0) {
2459 (void) strlcpy(klip->li_filename, "?",
2460 sizeof (klip->li_filename));
2461 }
2462
2463 (void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
2464 sizeof (klip->li_algorithm));
2465 klip->li_crypto_enabled = lsp->ls_crypto_enabled;
2466 mutex_exit(&lofi_lock);
2467 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
2468 free_lofi_ioctl(klip);
2469 return (error);
2470 case LOFI_GET_MINOR:
2471 mutex_enter(&lofi_lock);
2472 error = file_to_lofi(klip->li_filename, &lsp);
2473 if (error == 0)
2474 klip->li_minor = getminor(lsp->ls_dev);
2475 mutex_exit(&lofi_lock);
2476
2477 if (error == 0)
2478 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
2479
2480 free_lofi_ioctl(klip);
2481 return (error);
2482 case LOFI_CHECK_COMPRESSED:
2483 mutex_enter(&lofi_lock);
2484 error = file_to_lofi(klip->li_filename, &lsp);
2485 if (error != 0) {
2486 mutex_exit(&lofi_lock);
2487 free_lofi_ioctl(klip);
2488 return (error);
2489 }
2490
2491 klip->li_minor = getminor(lsp->ls_dev);
2492 (void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
2493 sizeof (klip->li_algorithm));
2494
2495 mutex_exit(&lofi_lock);
2496 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
2497 free_lofi_ioctl(klip);
2498 return (error);
2499 default:
2500 free_lofi_ioctl(klip);
2501 return (EINVAL);
2502 }
2503 }
2504
|
461 return (0);
462 }
463
464 /* otherwise, the mapping should already exist */
465 lsp = ddi_get_soft_state(lofi_statep, minor);
466 if (lsp == NULL) {
467 mutex_exit(&lofi_lock);
468 return (EINVAL);
469 }
470
471 if (lsp->ls_vp == NULL) {
472 mutex_exit(&lofi_lock);
473 return (ENXIO);
474 }
475
476 if (mark_opened(lsp, otyp) == -1) {
477 mutex_exit(&lofi_lock);
478 return (EINVAL);
479 }
480
481 if (lsp->ls_readonly && (flag & FWRITE)) {
482 mutex_exit(&lofi_lock);
483 return (EROFS);
484 }
485
486 mutex_exit(&lofi_lock);
487 return (0);
488 }
489
490 /*ARGSUSED*/
491 static int
492 lofi_close(dev_t dev, int flag, int otyp, struct cred *credp)
493 {
494 minor_t minor;
495 struct lofi_state *lsp;
496
497 mutex_enter(&lofi_lock);
498 minor = getminor(dev);
499 lsp = ddi_get_soft_state(lofi_statep, minor);
500 if (lsp == NULL) {
501 mutex_exit(&lofi_lock);
502 return (EINVAL);
503 }
504
505 if (minor == 0) {
506 mutex_exit(&lofi_lock);
1608 error = ddi_copyout(klip, ulip, sizeof (struct lofi_ioctl), flag);
1609 if (error)
1610 return (EFAULT);
1611 return (0);
1612 }
1613
1614 static int
1615 lofi_access(struct lofi_state *lsp)
1616 {
1617 ASSERT(MUTEX_HELD(&lofi_lock));
1618 if (INGLOBALZONE(curproc) || lsp->ls_zone.zref_zone == curzone)
1619 return (0);
1620 return (EPERM);
1621 }
1622
1623 /*
1624 * Find the lofi state for the given filename. We compare by vnode to
1625 * allow the global zone visibility into NGZ lofi nodes.
1626 */
1627 static int
1628 file_to_lofi_nocheck(char *filename, boolean_t readonly,
1629 struct lofi_state **lspp)
1630 {
1631 struct lofi_state *lsp;
1632 vnode_t *vp = NULL;
1633 int err = 0;
1634 int rdfiles = 0;
1635
1636 ASSERT(MUTEX_HELD(&lofi_lock));
1637
1638 if ((err = lookupname(filename, UIO_SYSSPACE, FOLLOW,
1639 NULLVPP, &vp)) != 0)
1640 goto out;
1641
1642 if (vp->v_type == VREG) {
1643 vnode_t *realvp;
1644 if (VOP_REALVP(vp, &realvp, NULL) == 0) {
1645 VN_HOLD(realvp);
1646 VN_RELE(vp);
1647 vp = realvp;
1648 }
1649 }
1650
1651 for (lsp = list_head(&lofi_list); lsp != NULL;
1652 lsp = list_next(&lofi_list, lsp)) {
1653 if (lsp->ls_vp == vp) {
1654 if (lspp != NULL)
1655 *lspp = lsp;
1656 if (lsp->ls_readonly) {
1657 rdfiles++;
1658 /* Skip if '-r' is specified */
1659 if (readonly)
1660 continue;
1661 }
1662 goto out;
1663 }
1664 }
1665
1666 err = ENOENT;
1667
1668 /*
1669 * If a filename is given as an argument for lofi_unmap, we shouldn't
1670 * allow unmap if there are multiple read-only lofi devices associated
1671 * with this file.
1672 */
1673 if (lspp != NULL) {
1674 if (rdfiles == 1)
1675 err = 0;
1676 else if (rdfiles > 1)
1677 err = EBUSY;
1678 }
1679
1680 out:
1681 if (vp != NULL)
1682 VN_RELE(vp);
1683 return (err);
1684 }
1685
1686 /*
1687 * Find the minor for the given filename, checking the zone can access
1688 * it.
1689 */
1690 static int
1691 file_to_lofi(char *filename, boolean_t readonly, struct lofi_state **lspp)
1692 {
1693 int err = 0;
1694
1695 ASSERT(MUTEX_HELD(&lofi_lock));
1696
1697 if ((err = file_to_lofi_nocheck(filename, readonly, lspp)) != 0)
1698 return (err);
1699
1700 if ((err = lofi_access(*lspp)) != 0)
1701 return (err);
1702
1703 return (0);
1704 }
1705
1706 /*
1707 * Fakes up a disk geometry, and one big partition, based on the size
1708 * of the file. This is needed because we allow newfs'ing the device,
1709 * and newfs will do several disk ioctls to figure out the geometry and
1710 * partition information. It uses that information to determine the parameters
1711 * to pass to mkfs. Geometry is pretty much irrelevant these days, but we
1712 * have to support it.
1713 */
1714 static void
1715 fake_disk_geometry(struct lofi_state *lsp)
1716 {
1717 u_offset_t dsize = lsp->ls_vp_size - lsp->ls_crypto_offset;
2130 vattr_t vattr;
2131 int flag;
2132 dev_t newdev;
2133 char namebuf[50];
2134
2135 error = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
2136 if (error != 0)
2137 return (error);
2138
2139 mutex_enter(&lofi_lock);
2140
2141 mutex_enter(&curproc->p_lock);
2142 if ((error = rctl_incr_lofi(curproc, curproc->p_zone, 1)) != 0) {
2143 mutex_exit(&curproc->p_lock);
2144 mutex_exit(&lofi_lock);
2145 free_lofi_ioctl(klip);
2146 return (error);
2147 }
2148 mutex_exit(&curproc->p_lock);
2149
2150 if (file_to_lofi_nocheck(klip->li_filename, klip->li_readonly,
2151 NULL) == 0) {
2152 error = EBUSY;
2153 goto err;
2154 }
2155
2156 if (pickminor) {
2157 minor = (minor_t)id_allocff_nosleep(lofi_minor_id);
2158 if (minor == (minor_t)-1) {
2159 error = EAGAIN;
2160 goto err;
2161 }
2162 } else {
2163 if (ddi_get_soft_state(lofi_statep, klip->li_minor) != NULL) {
2164 error = EEXIST;
2165 goto err;
2166 }
2167
2168 minor = (minor_t)
2169 id_alloc_specific_nosleep(lofi_minor_id, klip->li_minor);
2170 ASSERT(minor != (minor_t)-1);
2171 }
2252 */
2253 VN_HOLD(realvp);
2254 lsp->ls_vp = realvp;
2255 }
2256 }
2257
2258 lsp->ls_vp_size = vattr.va_size;
2259 lsp->ls_vp_comp_size = lsp->ls_vp_size;
2260
2261 lsp->ls_kstat = kstat_create_zone(LOFI_DRIVER_NAME, minor,
2262 NULL, "disk", KSTAT_TYPE_IO, 1, 0, getzoneid());
2263
2264 if (lsp->ls_kstat == NULL) {
2265 error = ENOMEM;
2266 goto err;
2267 }
2268
2269 lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
2270 kstat_zone_add(lsp->ls_kstat, GLOBAL_ZONEID);
2271
2272 lsp->ls_readonly = klip->li_readonly;
2273
2274 if ((error = lofi_init_crypto(lsp, klip)) != 0)
2275 goto err;
2276
2277 if ((error = lofi_init_compress(lsp)) != 0)
2278 goto err;
2279
2280 fake_disk_geometry(lsp);
2281
2282 /* create minor nodes */
2283
2284 (void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
2285 error = ddi_create_minor_node(lofi_dip, namebuf, S_IFBLK, minor,
2286 DDI_PSEUDO, NULL);
2287 if (error != DDI_SUCCESS) {
2288 error = ENXIO;
2289 goto err;
2290 }
2291
2292 (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
2293 error = ddi_create_minor_node(lofi_dip, namebuf, S_IFCHR, minor,
2354 return (error);
2355 }
2356
2357 /*
2358 * unmap a file.
2359 */
2360 static int
2361 lofi_unmap_file(struct lofi_ioctl *ulip, int byfilename,
2362 struct cred *credp, int ioctl_flag)
2363 {
2364 struct lofi_state *lsp;
2365 struct lofi_ioctl *klip;
2366 int err;
2367
2368 err = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
2369 if (err != 0)
2370 return (err);
2371
2372 mutex_enter(&lofi_lock);
2373 if (byfilename) {
2374 if ((err = file_to_lofi(klip->li_filename, klip->li_readonly,
2375 &lsp)) != 0) {
2376 mutex_exit(&lofi_lock);
2377 return (err);
2378 }
2379 } else if (klip->li_minor == 0) {
2380 mutex_exit(&lofi_lock);
2381 free_lofi_ioctl(klip);
2382 return (ENXIO);
2383 } else {
2384 lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
2385 }
2386
2387 if (lsp == NULL || lsp->ls_vp == NULL || lofi_access(lsp) != 0) {
2388 mutex_exit(&lofi_lock);
2389 free_lofi_ioctl(klip);
2390 return (ENXIO);
2391 }
2392
2393 klip->li_minor = getminor(lsp->ls_dev);
2394
2395 /*
2472 }
2473
2474 mutex_enter(&lofi_lock);
2475 lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
2476 if (lsp == NULL || lofi_access(lsp) != 0) {
2477 mutex_exit(&lofi_lock);
2478 free_lofi_ioctl(klip);
2479 return (ENXIO);
2480 }
2481
2482 /*
2483 * This may fail if, for example, we're trying to look
2484 * up a zoned NFS path from the global zone.
2485 */
2486 if (vnodetopath(NULL, lsp->ls_stacked_vp, klip->li_filename,
2487 sizeof (klip->li_filename), CRED()) != 0) {
2488 (void) strlcpy(klip->li_filename, "?",
2489 sizeof (klip->li_filename));
2490 }
2491
2492 klip->li_readonly = lsp->ls_readonly;
2493
2494 (void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
2495 sizeof (klip->li_algorithm));
2496 klip->li_crypto_enabled = lsp->ls_crypto_enabled;
2497 mutex_exit(&lofi_lock);
2498 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
2499 free_lofi_ioctl(klip);
2500 return (error);
2501 case LOFI_GET_MINOR:
2502 mutex_enter(&lofi_lock);
2503 error = file_to_lofi(klip->li_filename,
2504 klip->li_readonly, &lsp);
2505 if (error == 0)
2506 klip->li_minor = getminor(lsp->ls_dev);
2507 mutex_exit(&lofi_lock);
2508
2509 if (error == 0)
2510 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
2511
2512 free_lofi_ioctl(klip);
2513 return (error);
2514 case LOFI_CHECK_COMPRESSED:
2515 mutex_enter(&lofi_lock);
2516 error = file_to_lofi(klip->li_filename,
2517 klip->li_readonly, &lsp);
2518 if (error != 0) {
2519 mutex_exit(&lofi_lock);
2520 free_lofi_ioctl(klip);
2521 return (error);
2522 }
2523
2524 klip->li_minor = getminor(lsp->ls_dev);
2525 (void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
2526 sizeof (klip->li_algorithm));
2527
2528 mutex_exit(&lofi_lock);
2529 error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
2530 free_lofi_ioctl(klip);
2531 return (error);
2532 default:
2533 free_lofi_ioctl(klip);
2534 return (EINVAL);
2535 }
2536 }
2537
|