Print this page
OS-1566 filesystem limits for ZFS datasets


 626         objset_t *mos = dd->dd_pool->dp_meta_objset;
 627         uint64_t val;
 628         int err;
 629 
 630         err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj,
 631             strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val);
 632 
 633         if (err != ENOENT)
 634                 return (err ? err : EEXIST);
 635 
 636         if (rbsa->origin) {
 637                 /* make sure it's a snap in the same pool */
 638                 if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
 639                         return (EXDEV);
 640                 if (!dsl_dataset_is_snapshot(rbsa->origin))
 641                         return (EINVAL);
 642                 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
 643                         return (ENODEV);
 644         }
 645 















 646         return (0);
 647 }
 648 
 649 static void
 650 recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 651 {
 652         dsl_dir_t *dd = arg1;
 653         struct recvbeginsyncarg *rbsa = arg2;
 654         uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
 655         uint64_t dsobj;
 656 
 657         /* Create and open new dataset. */
 658         dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1,
 659             rbsa->origin, flags, rbsa->cr, tx);
 660         VERIFY(0 == dsl_dataset_own_obj(dd->dd_pool, dsobj,
 661             B_TRUE, dmu_recv_tag, &rbsa->ds));
 662 
 663         if (rbsa->origin == NULL) {
 664                 (void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
 665                     rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);


 708                                 if (err)
 709                                         return (ENODEV);
 710                                 if (snap->ds_phys->ds_creation_txg < birth) {
 711                                         dsl_dataset_rele(snap, FTAG);
 712                                         return (ENODEV);
 713                                 }
 714                                 if (snap->ds_phys->ds_guid == rbsa->fromguid) {
 715                                         dsl_dataset_rele(snap, FTAG);
 716                                         break; /* it's ok */
 717                                 }
 718                                 obj = snap->ds_phys->ds_prev_snap_obj;
 719                                 dsl_dataset_rele(snap, FTAG);
 720                         }
 721                         if (obj == 0)
 722                                 return (ENODEV);
 723                 }
 724         } else {
 725                 /* if full, most recent snapshot must be $ORIGIN */
 726                 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
 727                         return (ENODEV);





 728         }
 729 
 730         /* temporary clone name must not exist */
 731         err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
 732             ds->ds_dir->dd_phys->dd_child_dir_zapobj,
 733             rbsa->clonelastname, 8, 1, &val);
 734         if (err == 0)
 735                 return (EEXIST);
 736         if (err != ENOENT)
 737                 return (err);
 738 
 739         return (0);
 740 }
 741 
 742 /* ARGSUSED */
 743 static void
 744 recv_existing_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 745 {
 746         dsl_dataset_t *ohds = arg1;
 747         struct recvbeginsyncarg *rbsa = arg2;


1530                  */
1531                 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
1532 
1533                 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1534                     B_FALSE);
1535                 if (drc->drc_real_ds != drc->drc_logical_ds) {
1536                         mutex_exit(&drc->drc_logical_ds->ds_recvlock);
1537                         dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
1538                 }
1539         }
1540 
1541         kmem_free(ra.buf, ra.bufsize);
1542         *voffp = ra.voff;
1543         return (ra.err);
1544 }
1545 
1546 struct recvendsyncarg {
1547         char *tosnap;
1548         uint64_t creation_time;
1549         uint64_t toguid;

1550 };
1551 
1552 static int
1553 recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1554 {
1555         dsl_dataset_t *ds = arg1;
1556         struct recvendsyncarg *resa = arg2;
1557 
1558         return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));













1559 }
1560 
1561 static void
1562 recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1563 {
1564         dsl_dataset_t *ds = arg1;
1565         struct recvendsyncarg *resa = arg2;
1566 





1567         dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1568 
1569         /* set snapshot's creation time and guid */
1570         dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1571         ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1572         ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1573         ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1574 
1575         dmu_buf_will_dirty(ds->ds_dbuf, tx);
1576         ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1577         spa_history_log_internal_ds(ds, "finished receiving", tx, "");
1578 }
1579 
1580 static int
1581 add_ds_to_guidmap(avl_tree_t *guid_map, dsl_dataset_t *ds)
1582 {
1583         dsl_pool_t *dp = ds->ds_dir->dd_pool;
1584         uint64_t snapobj = ds->ds_phys->ds_prev_snap_obj;
1585         dsl_dataset_t *snapds;
1586         guid_map_entry_t *gmep;


1607         struct recvendsyncarg resa;
1608         dsl_dataset_t *ds = drc->drc_logical_ds;
1609         int err, myerr;
1610 
1611         if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
1612                 err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
1613                     drc->drc_force);
1614                 if (err)
1615                         goto out;
1616         } else {
1617                 mutex_exit(&ds->ds_recvlock);
1618                 dsl_dataset_rele(ds, dmu_recv_tag);
1619                 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1620                     B_FALSE);
1621                 return (EBUSY);
1622         }
1623 
1624         resa.creation_time = drc->drc_drrb->drr_creation_time;
1625         resa.toguid = drc->drc_drrb->drr_toguid;
1626         resa.tosnap = drc->drc_tosnap;

1627 
1628         err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1629             recv_end_check, recv_end_sync, ds, &resa, 3);
1630         if (err) {
1631                 /* swap back */
1632                 (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE);
1633         }
1634 
1635 out:
1636         mutex_exit(&ds->ds_recvlock);
1637         if (err == 0 && drc->drc_guid_to_ds_map != NULL)
1638                 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1639         dsl_dataset_disown(ds, dmu_recv_tag);
1640         myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
1641         ASSERT0(myerr);
1642         return (err);
1643 }
1644 
1645 static int
1646 dmu_recv_new_end(dmu_recv_cookie_t *drc)
1647 {
1648         struct recvendsyncarg resa;
1649         dsl_dataset_t *ds = drc->drc_logical_ds;
1650         int err;
1651 
1652         /*
1653          * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
1654          * expects it to have a ds_user_ptr (and zil), but clone_swap()
1655          * can close it.
1656          */
1657         txg_wait_synced(ds->ds_dir->dd_pool, 0);
1658 
1659         resa.creation_time = drc->drc_drrb->drr_creation_time;
1660         resa.toguid = drc->drc_drrb->drr_toguid;
1661         resa.tosnap = drc->drc_tosnap;

1662 
1663         err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1664             recv_end_check, recv_end_sync, ds, &resa, 3);
1665         if (err) {
1666                 /* clean up the fs we just recv'd into */
1667                 (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE);
1668         } else {
1669                 if (drc->drc_guid_to_ds_map != NULL)
1670                         (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1671                 /* release the hold from dmu_recv_begin */
1672                 dsl_dataset_disown(ds, dmu_recv_tag);
1673         }
1674         return (err);
1675 }
1676 
1677 int
1678 dmu_recv_end(dmu_recv_cookie_t *drc)
1679 {
1680         if (drc->drc_logical_ds != drc->drc_real_ds)
1681                 return (dmu_recv_existing_end(drc));


 626         objset_t *mos = dd->dd_pool->dp_meta_objset;
 627         uint64_t val;
 628         int err;
 629 
 630         err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj,
 631             strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val);
 632 
 633         if (err != ENOENT)
 634                 return (err ? err : EEXIST);
 635 
 636         if (rbsa->origin) {
 637                 /* make sure it's a snap in the same pool */
 638                 if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
 639                         return (EXDEV);
 640                 if (!dsl_dataset_is_snapshot(rbsa->origin))
 641                         return (EINVAL);
 642                 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
 643                         return (ENODEV);
 644         }
 645 
 646         /*
 647          * Check filesystem and snapshot limits before receiving. We'll recheck
 648          * again at the end, but might as well abort before receiving if we're
 649          * already over the limit.
 650          */
 651         if (dd->dd_parent != NULL) {
 652                 err = dsl_dir_fscount_check(dd->dd_parent, 1, NULL);
 653                 if (err != 0)
 654                         return (err);
 655         }
 656 
 657         err = dsl_snapcount_check(dd, 1, NULL);
 658         if (err != 0)
 659                 return (err);
 660 
 661         return (0);
 662 }
 663 
 664 static void
 665 recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 666 {
 667         dsl_dir_t *dd = arg1;
 668         struct recvbeginsyncarg *rbsa = arg2;
 669         uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
 670         uint64_t dsobj;
 671 
 672         /* Create and open new dataset. */
 673         dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1,
 674             rbsa->origin, flags, rbsa->cr, tx);
 675         VERIFY(0 == dsl_dataset_own_obj(dd->dd_pool, dsobj,
 676             B_TRUE, dmu_recv_tag, &rbsa->ds));
 677 
 678         if (rbsa->origin == NULL) {
 679                 (void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
 680                     rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);


 723                                 if (err)
 724                                         return (ENODEV);
 725                                 if (snap->ds_phys->ds_creation_txg < birth) {
 726                                         dsl_dataset_rele(snap, FTAG);
 727                                         return (ENODEV);
 728                                 }
 729                                 if (snap->ds_phys->ds_guid == rbsa->fromguid) {
 730                                         dsl_dataset_rele(snap, FTAG);
 731                                         break; /* it's ok */
 732                                 }
 733                                 obj = snap->ds_phys->ds_prev_snap_obj;
 734                                 dsl_dataset_rele(snap, FTAG);
 735                         }
 736                         if (obj == 0)
 737                                 return (ENODEV);
 738                 }
 739         } else {
 740                 /* if full, most recent snapshot must be $ORIGIN */
 741                 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
 742                         return (ENODEV);
 743 
 744                 /* Check snapshot limit before receiving */
 745                 err = dsl_snapcount_check(ds->ds_dir, 1, NULL);
 746                 if (err != 0)
 747                         return (err);
 748         }
 749 
 750         /* temporary clone name must not exist */
 751         err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
 752             ds->ds_dir->dd_phys->dd_child_dir_zapobj,
 753             rbsa->clonelastname, 8, 1, &val);
 754         if (err == 0)
 755                 return (EEXIST);
 756         if (err != ENOENT)
 757                 return (err);
 758 
 759         return (0);
 760 }
 761 
 762 /* ARGSUSED */
 763 static void
 764 recv_existing_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 765 {
 766         dsl_dataset_t *ohds = arg1;
 767         struct recvbeginsyncarg *rbsa = arg2;


1550                  */
1551                 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
1552 
1553                 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1554                     B_FALSE);
1555                 if (drc->drc_real_ds != drc->drc_logical_ds) {
1556                         mutex_exit(&drc->drc_logical_ds->ds_recvlock);
1557                         dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
1558                 }
1559         }
1560 
1561         kmem_free(ra.buf, ra.bufsize);
1562         *voffp = ra.voff;
1563         return (ra.err);
1564 }
1565 
1566 struct recvendsyncarg {
1567         char *tosnap;
1568         uint64_t creation_time;
1569         uint64_t toguid;
1570         boolean_t is_new;
1571 };
1572 
1573 static int
1574 recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1575 {
1576         dsl_dataset_t *ds = arg1;
1577         struct recvendsyncarg *resa = arg2;
1578 
1579         if (resa->is_new) {
1580                 /* re-check the filesystem limit now that recv is complete */
1581                 dsl_dir_t *dd;
1582                 int err;
1583 
1584                 dd = ds->ds_dir;
1585                 if (dd->dd_parent != NULL) {
1586                         err = dsl_dir_fscount_check(dd->dd_parent, 1, NULL);
1587                         if (err != 0)
1588                                 return (err);
1589                 }
1590         }
1591 
1592         return (dsl_dataset_snapshot_check(ds, resa->tosnap, 1, tx));
1593 }
1594 
1595 static void
1596 recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1597 {
1598         dsl_dataset_t *ds = arg1;
1599         struct recvendsyncarg *resa = arg2;
1600 
1601         if (resa->is_new)
1602                 /* update the filesystem counts */
1603                 dsl_dir_fscount_adjust(ds->ds_dir->dd_parent, tx, 1, B_FALSE,
1604                     B_TRUE);
1605 
1606         dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1607 
1608         /* set snapshot's creation time and guid */
1609         dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1610         ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1611         ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1612         ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1613 
1614         dmu_buf_will_dirty(ds->ds_dbuf, tx);
1615         ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1616         spa_history_log_internal_ds(ds, "finished receiving", tx, "");
1617 }
1618 
1619 static int
1620 add_ds_to_guidmap(avl_tree_t *guid_map, dsl_dataset_t *ds)
1621 {
1622         dsl_pool_t *dp = ds->ds_dir->dd_pool;
1623         uint64_t snapobj = ds->ds_phys->ds_prev_snap_obj;
1624         dsl_dataset_t *snapds;
1625         guid_map_entry_t *gmep;


1646         struct recvendsyncarg resa;
1647         dsl_dataset_t *ds = drc->drc_logical_ds;
1648         int err, myerr;
1649 
1650         if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
1651                 err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
1652                     drc->drc_force);
1653                 if (err)
1654                         goto out;
1655         } else {
1656                 mutex_exit(&ds->ds_recvlock);
1657                 dsl_dataset_rele(ds, dmu_recv_tag);
1658                 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1659                     B_FALSE);
1660                 return (EBUSY);
1661         }
1662 
1663         resa.creation_time = drc->drc_drrb->drr_creation_time;
1664         resa.toguid = drc->drc_drrb->drr_toguid;
1665         resa.tosnap = drc->drc_tosnap;
1666         resa.is_new = B_FALSE;
1667 
1668         err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1669             recv_end_check, recv_end_sync, ds, &resa, 3);
1670         if (err) {
1671                 /* swap back */
1672                 (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE);
1673         }
1674 
1675 out:
1676         mutex_exit(&ds->ds_recvlock);
1677         if (err == 0 && drc->drc_guid_to_ds_map != NULL)
1678                 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1679         dsl_dataset_disown(ds, dmu_recv_tag);
1680         myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
1681         ASSERT0(myerr);
1682         return (err);
1683 }
1684 
1685 static int
1686 dmu_recv_new_end(dmu_recv_cookie_t *drc)
1687 {
1688         struct recvendsyncarg resa;
1689         dsl_dataset_t *ds = drc->drc_logical_ds;
1690         int err;
1691 
1692         /*
1693          * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
1694          * expects it to have a ds_user_ptr (and zil), but clone_swap()
1695          * can close it.
1696          */
1697         txg_wait_synced(ds->ds_dir->dd_pool, 0);
1698 
1699         resa.creation_time = drc->drc_drrb->drr_creation_time;
1700         resa.toguid = drc->drc_drrb->drr_toguid;
1701         resa.tosnap = drc->drc_tosnap;
1702         resa.is_new = B_TRUE;
1703 
1704         err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1705             recv_end_check, recv_end_sync, ds, &resa, 3);
1706         if (err) {
1707                 /* clean up the fs we just recv'd into */
1708                 (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE);
1709         } else {
1710                 if (drc->drc_guid_to_ds_map != NULL)
1711                         (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1712                 /* release the hold from dmu_recv_begin */
1713                 dsl_dataset_disown(ds, dmu_recv_tag);
1714         }
1715         return (err);
1716 }
1717 
1718 int
1719 dmu_recv_end(dmu_recv_cookie_t *drc)
1720 {
1721         if (drc->drc_logical_ds != drc->drc_real_ds)
1722                 return (dmu_recv_existing_end(drc));