Print this page
OS-1566 dataset quota 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 ↓ 43 lines elided ↑ open up ↑
  44   44  #include <sys/zfs_znode.h>
  45   45  #include <zfs_fletcher.h>
  46   46  #include <sys/avl.h>
  47   47  #include <sys/ddt.h>
  48   48  #include <sys/zfs_onexit.h>
  49   49  
  50   50  /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
  51   51  int zfs_send_corrupt_data = B_FALSE;
  52   52  
  53   53  static char *dmu_recv_tag = "dmu_recv_tag";
       54 +char *tmp_dmu_recv_tag = "tmp_dmu_recv_tag";
  54   55  
  55   56  static int
  56   57  dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
  57   58  {
  58   59          dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset;
  59   60          ssize_t resid; /* have to get resid to get detailed errno */
  60   61          ASSERT0(len % 8);
  61   62  
  62   63          fletcher_4_incremental_native(buf, len, &dsp->dsa_zc);
  63   64          dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp,
↓ open down ↓ 572 lines elided ↑ open up ↑
 636  637          if (rbsa->origin) {
 637  638                  /* make sure it's a snap in the same pool */
 638  639                  if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
 639  640                          return (EXDEV);
 640  641                  if (!dsl_dataset_is_snapshot(rbsa->origin))
 641  642                          return (EINVAL);
 642  643                  if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
 643  644                          return (ENODEV);
 644  645          }
 645  646  
      647 +        /*
      648 +         * Check dataset and snapshot quotas before receiving. We'll recheck
      649 +         * again at the end, but might as well abort before receiving if we're
      650 +         * already over quota.
      651 +         */
      652 +        if (dd->dd_parent != NULL) {
      653 +                err = dsl_dir_dscount_check(dd->dd_parent, NULL, 1, NULL);
      654 +                if (err != 0)
      655 +                        return (err);
      656 +        }
      657 +
      658 +        err = dsl_snapcount_check(dd, tx, 1, NULL);
      659 +        if (err != 0)
      660 +                return (err);
      661 +
      662 +
 646  663          return (0);
 647  664  }
 648  665  
 649  666  static void
 650  667  recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 651  668  {
 652  669          dsl_dir_t *dd = arg1;
 653  670          struct recvbeginsyncarg *rbsa = arg2;
 654  671          uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
 655  672          uint64_t dsobj;
↓ open down ↓ 62 lines elided ↑ open up ↑
 718  735                                  obj = snap->ds_phys->ds_prev_snap_obj;
 719  736                                  dsl_dataset_rele(snap, FTAG);
 720  737                          }
 721  738                          if (obj == 0)
 722  739                                  return (ENODEV);
 723  740                  }
 724  741          } else {
 725  742                  /* if full, most recent snapshot must be $ORIGIN */
 726  743                  if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
 727  744                          return (ENODEV);
      745 +
      746 +                /* Check snapshot quota before receiving */
      747 +                err = dsl_snapcount_check(ds->ds_dir, tx, 1, NULL);
      748 +                if (err != 0)
      749 +                        return (err);
 728  750          }
 729  751  
 730  752          /* temporary clone name must not exist */
 731  753          err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
 732  754              ds->ds_dir->dd_phys->dd_child_dir_zapobj,
 733  755              rbsa->clonelastname, 8, 1, &val);
 734  756          if (err == 0)
 735  757                  return (EEXIST);
 736  758          if (err != ENOENT)
 737  759                  return (err);
↓ open down ↓ 802 lines elided ↑ open up ↑
1540 1562  
1541 1563          kmem_free(ra.buf, ra.bufsize);
1542 1564          *voffp = ra.voff;
1543 1565          return (ra.err);
1544 1566  }
1545 1567  
1546 1568  struct recvendsyncarg {
1547 1569          char *tosnap;
1548 1570          uint64_t creation_time;
1549 1571          uint64_t toguid;
     1572 +        boolean_t is_new;
1550 1573  };
1551 1574  
1552 1575  static int
1553 1576  recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1554 1577  {
1555 1578          dsl_dataset_t *ds = arg1;
1556 1579          struct recvendsyncarg *resa = arg2;
1557 1580  
1558      -        return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));
     1581 +        if (resa->is_new) {
     1582 +                /* re-check the dataset quota now that recv is complete */
     1583 +                dsl_dir_t *dd;
     1584 +                int err;
     1585 +
     1586 +                dd = ds->ds_dir;
     1587 +                if (dd->dd_parent != NULL) {
     1588 +                        err = dsl_dir_dscount_check(dd->dd_parent, NULL, 1,
     1589 +                            NULL);
     1590 +                        if (err != 0)
     1591 +                                return (err);
     1592 +                }
     1593 +        }
     1594 +
     1595 +        return (dsl_dataset_snapshot_check(ds, resa->tosnap, 1, tx));
1559 1596  }
1560 1597  
1561 1598  static void
1562 1599  recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1563 1600  {
1564 1601          dsl_dataset_t *ds = arg1;
1565 1602          struct recvendsyncarg *resa = arg2;
1566 1603  
     1604 +        if (resa->is_new)
     1605 +                /* update the dataset counts */
     1606 +                dsl_dir_dscount_adjust(ds->ds_dir->dd_parent, tx, 1, B_FALSE,
     1607 +                    B_TRUE);
     1608 +
1567 1609          dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1568 1610  
1569 1611          /* set snapshot's creation time and guid */
1570 1612          dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1571 1613          ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1572 1614          ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1573 1615          ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1574 1616  
1575 1617          dmu_buf_will_dirty(ds->ds_dbuf, tx);
1576 1618          ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
↓ open down ↓ 32 lines elided ↑ open up ↑
1609 1651          int err, myerr;
1610 1652  
1611 1653          if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
1612 1654                  err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
1613 1655                      drc->drc_force);
1614 1656                  if (err)
1615 1657                          goto out;
1616 1658          } else {
1617 1659                  mutex_exit(&ds->ds_recvlock);
1618 1660                  dsl_dataset_rele(ds, dmu_recv_tag);
1619      -                (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
     1661 +                /* tag indicates temporary ds to dsl_dir_destroy_sync */
     1662 +                (void) dsl_dataset_destroy(drc->drc_real_ds, tmp_dmu_recv_tag,
1620 1663                      B_FALSE);
1621 1664                  return (EBUSY);
1622 1665          }
1623 1666  
1624 1667          resa.creation_time = drc->drc_drrb->drr_creation_time;
1625 1668          resa.toguid = drc->drc_drrb->drr_toguid;
1626 1669          resa.tosnap = drc->drc_tosnap;
     1670 +        resa.is_new = B_FALSE;
1627 1671  
1628 1672          err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1629 1673              recv_end_check, recv_end_sync, ds, &resa, 3);
1630 1674          if (err) {
1631 1675                  /* swap back */
1632 1676                  (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE);
1633 1677          }
1634 1678  
1635 1679  out:
1636 1680          mutex_exit(&ds->ds_recvlock);
1637 1681          if (err == 0 && drc->drc_guid_to_ds_map != NULL)
1638 1682                  (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1639 1683          dsl_dataset_disown(ds, dmu_recv_tag);
1640      -        myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
     1684 +        /* tag indicates temporary ds to dsl_dir_destroy_sync */
     1685 +        myerr = dsl_dataset_destroy(drc->drc_real_ds, tmp_dmu_recv_tag,
     1686 +            B_FALSE);
1641 1687          ASSERT0(myerr);
1642 1688          return (err);
1643 1689  }
1644 1690  
1645 1691  static int
1646 1692  dmu_recv_new_end(dmu_recv_cookie_t *drc)
1647 1693  {
1648 1694          struct recvendsyncarg resa;
1649 1695          dsl_dataset_t *ds = drc->drc_logical_ds;
1650 1696          int err;
↓ open down ↓ 1 lines elided ↑ open up ↑
1652 1698          /*
1653 1699           * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
1654 1700           * expects it to have a ds_user_ptr (and zil), but clone_swap()
1655 1701           * can close it.
1656 1702           */
1657 1703          txg_wait_synced(ds->ds_dir->dd_pool, 0);
1658 1704  
1659 1705          resa.creation_time = drc->drc_drrb->drr_creation_time;
1660 1706          resa.toguid = drc->drc_drrb->drr_toguid;
1661 1707          resa.tosnap = drc->drc_tosnap;
     1708 +        resa.is_new = B_TRUE;
1662 1709  
1663 1710          err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1664 1711              recv_end_check, recv_end_sync, ds, &resa, 3);
1665 1712          if (err) {
1666 1713                  /* clean up the fs we just recv'd into */
1667 1714                  (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE);
1668 1715          } else {
1669 1716                  if (drc->drc_guid_to_ds_map != NULL)
1670 1717                          (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1671 1718                  /* release the hold from dmu_recv_begin */
↓ open down ↓ 13 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX