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 +        err = dsl_dir_fscount_check(dd, 1, NULL, rbsa->cr);
      652 +        if (err != 0)
      653 +                return (err);
      654 +
      655 +        err = dsl_snapcount_check(dd, 1, NULL, rbsa->cr);
      656 +        if (err != 0)
      657 +                return (err);
      658 +
 646  659          return (0);
 647  660  }
 648  661  
 649  662  static void
 650  663  recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 651  664  {
 652  665          dsl_dir_t *dd = arg1;
 653  666          struct recvbeginsyncarg *rbsa = arg2;
 654  667          uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
 655  668          uint64_t dsobj;
↓ open down ↓ 5 lines elided ↑ open up ↑
 661  674              B_TRUE, dmu_recv_tag, &rbsa->ds));
 662  675  
 663  676          if (rbsa->origin == NULL) {
 664  677                  (void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
 665  678                      rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);
 666  679          }
 667  680  
 668  681          spa_history_log_internal_ds(rbsa->ds, "receive new", tx, "");
 669  682  }
 670  683  
      684 +/*
      685 + * Note that we do not check the file system limit with dsl_dir_fscount_check
      686 + * because the temporary %clones don't count against that limit.
      687 + */
 671  688  /* ARGSUSED */
 672  689  static int
 673  690  recv_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
 674  691  {
 675  692          dsl_dataset_t *ds = arg1;
 676  693          struct recvbeginsyncarg *rbsa = arg2;
 677  694          int err;
 678  695          uint64_t val;
 679  696  
 680  697          /* must not have any changes since most recent snapshot */
↓ open down ↓ 37 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 limit before receiving */
      747 +                err = dsl_snapcount_check(ds->ds_dir, 1, NULL, rbsa->cr);
      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;
     1573 +        cred_t *cr;
1550 1574  };
1551 1575  
1552 1576  static int
1553 1577  recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1554 1578  {
1555 1579          dsl_dataset_t *ds = arg1;
1556 1580          struct recvendsyncarg *resa = arg2;
1557 1581  
1558      -        return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));
     1582 +        if (resa->is_new) {
     1583 +                /* re-check the filesystem limit now that recv is complete */
     1584 +                int err;
     1585 +
     1586 +                err = dsl_dir_fscount_check(ds->ds_dir, 1, NULL, resa->cr);
     1587 +                if (err != 0)
     1588 +                        return (err);
     1589 +        }
     1590 +
     1591 +        return (dsl_dataset_snapshot_check(ds, resa->tosnap, 1, tx, resa->cr));
1559 1592  }
1560 1593  
1561 1594  static void
1562 1595  recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1563 1596  {
1564 1597          dsl_dataset_t *ds = arg1;
1565 1598          struct recvendsyncarg *resa = arg2;
1566 1599  
     1600 +        if (resa->is_new) {
     1601 +                /* update the filesystem counts */
     1602 +                dsl_dir_fscount_adjust(ds->ds_dir->dd_parent, tx, 1, B_TRUE);
     1603 +        }
     1604 +
1567 1605          dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1568 1606  
1569 1607          /* set snapshot's creation time and guid */
1570 1608          dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1571 1609          ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1572 1610          ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1573 1611          ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1574 1612  
1575 1613          dmu_buf_will_dirty(ds->ds_dbuf, tx);
1576 1614          ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
↓ open down ↓ 40 lines elided ↑ open up ↑
1617 1655                  mutex_exit(&ds->ds_recvlock);
1618 1656                  dsl_dataset_rele(ds, dmu_recv_tag);
1619 1657                  (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1620 1658                      B_FALSE);
1621 1659                  return (EBUSY);
1622 1660          }
1623 1661  
1624 1662          resa.creation_time = drc->drc_drrb->drr_creation_time;
1625 1663          resa.toguid = drc->drc_drrb->drr_toguid;
1626 1664          resa.tosnap = drc->drc_tosnap;
     1665 +        resa.is_new = B_FALSE;
     1666 +        resa.cr = CRED();
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;
     1703 +        resa.cr = CRED();
1662 1704  
1663 1705          err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1664 1706              recv_end_check, recv_end_sync, ds, &resa, 3);
1665 1707          if (err) {
1666 1708                  /* clean up the fs we just recv'd into */
1667 1709                  (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE);
1668 1710          } else {
1669 1711                  if (drc->drc_guid_to_ds_map != NULL)
1670 1712                          (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1671 1713                  /* release the hold from dmu_recv_begin */
↓ open down ↓ 13 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX