Print this page
OS-1566 filesystem limits for ZFS datasets

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dmu_send.c
          +++ new/usr/src/uts/common/fs/zfs/dmu_send.c
↓ open down ↓ 635 lines elided ↑ open up ↑
 636  636          if (rbsa->origin) {
 637  637                  /* make sure it's a snap in the same pool */
 638  638                  if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
 639  639                          return (EXDEV);
 640  640                  if (!dsl_dataset_is_snapshot(rbsa->origin))
 641  641                          return (EINVAL);
 642  642                  if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
 643  643                          return (ENODEV);
 644  644          }
 645  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 +
 646  661          return (0);
 647  662  }
 648  663  
 649  664  static void
 650  665  recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 651  666  {
 652  667          dsl_dir_t *dd = arg1;
 653  668          struct recvbeginsyncarg *rbsa = arg2;
 654  669          uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
 655  670          uint64_t dsobj;
↓ open down ↓ 62 lines elided ↑ open up ↑
 718  733                                  obj = snap->ds_phys->ds_prev_snap_obj;
 719  734                                  dsl_dataset_rele(snap, FTAG);
 720  735                          }
 721  736                          if (obj == 0)
 722  737                                  return (ENODEV);
 723  738                  }
 724  739          } else {
 725  740                  /* if full, most recent snapshot must be $ORIGIN */
 726  741                  if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
 727  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);
 728  748          }
 729  749  
 730  750          /* temporary clone name must not exist */
 731  751          err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
 732  752              ds->ds_dir->dd_phys->dd_child_dir_zapobj,
 733  753              rbsa->clonelastname, 8, 1, &val);
 734  754          if (err == 0)
 735  755                  return (EEXIST);
 736  756          if (err != ENOENT)
 737  757                  return (err);
↓ open down ↓ 802 lines elided ↑ open up ↑
1540 1560  
1541 1561          kmem_free(ra.buf, ra.bufsize);
1542 1562          *voffp = ra.voff;
1543 1563          return (ra.err);
1544 1564  }
1545 1565  
1546 1566  struct recvendsyncarg {
1547 1567          char *tosnap;
1548 1568          uint64_t creation_time;
1549 1569          uint64_t toguid;
     1570 +        boolean_t is_new;
1550 1571  };
1551 1572  
1552 1573  static int
1553 1574  recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1554 1575  {
1555 1576          dsl_dataset_t *ds = arg1;
1556 1577          struct recvendsyncarg *resa = arg2;
1557 1578  
1558      -        return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));
     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));
1559 1593  }
1560 1594  
1561 1595  static void
1562 1596  recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1563 1597  {
1564 1598          dsl_dataset_t *ds = arg1;
1565 1599          struct recvendsyncarg *resa = arg2;
1566 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 +
1567 1606          dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1568 1607  
1569 1608          /* set snapshot's creation time and guid */
1570 1609          dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1571 1610          ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1572 1611          ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1573 1612          ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1574 1613  
1575 1614          dmu_buf_will_dirty(ds->ds_dbuf, tx);
1576 1615          ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
↓ open down ↓ 40 lines elided ↑ open up ↑
1617 1656                  mutex_exit(&ds->ds_recvlock);
1618 1657                  dsl_dataset_rele(ds, dmu_recv_tag);
1619 1658                  (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1620 1659                      B_FALSE);
1621 1660                  return (EBUSY);
1622 1661          }
1623 1662  
1624 1663          resa.creation_time = drc->drc_drrb->drr_creation_time;
1625 1664          resa.toguid = drc->drc_drrb->drr_toguid;
1626 1665          resa.tosnap = drc->drc_tosnap;
     1666 +        resa.is_new = B_FALSE;
1627 1667  
1628 1668          err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1629 1669              recv_end_check, recv_end_sync, ds, &resa, 3);
1630 1670          if (err) {
1631 1671                  /* swap back */
1632 1672                  (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE);
1633 1673          }
1634 1674  
1635 1675  out:
1636 1676          mutex_exit(&ds->ds_recvlock);
↓ open down ↓ 15 lines elided ↑ open up ↑
1652 1692          /*
1653 1693           * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
1654 1694           * expects it to have a ds_user_ptr (and zil), but clone_swap()
1655 1695           * can close it.
1656 1696           */
1657 1697          txg_wait_synced(ds->ds_dir->dd_pool, 0);
1658 1698  
1659 1699          resa.creation_time = drc->drc_drrb->drr_creation_time;
1660 1700          resa.toguid = drc->drc_drrb->drr_toguid;
1661 1701          resa.tosnap = drc->drc_tosnap;
     1702 +        resa.is_new = B_TRUE;
1662 1703  
1663 1704          err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1664 1705              recv_end_check, recv_end_sync, ds, &resa, 3);
1665 1706          if (err) {
1666 1707                  /* clean up the fs we just recv'd into */
1667 1708                  (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE);
1668 1709          } else {
1669 1710                  if (drc->drc_guid_to_ds_map != NULL)
1670 1711                          (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1671 1712                  /* release the hold from dmu_recv_begin */
↓ open down ↓ 13 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX