[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#947919: schroot: Support for ZFS snapshotting



Package: schroot
Version: 1.6.10-6.1
Severity: wishlist
Tags: patch
User: ubuntu-devel@lists.ubuntu.com
Usertags: origin-ubuntu focal ubuntu-patch

schroot currently supports using LVM and btrfs volumes as a source for
snapshot-based chroots, to good effect.  It is also possible to use ZFS as a
filesystem on Linux, via the zfs-linux package; it would be useful to users
of ZFS for schroot to support ZFS snapshots in addition to the other two
snapshot-based backends.

Attached is a preliminary patch which adds support for a zfs-snapshot type. 
It currently has a bug I've only just detected which prevents it from
working correctly for source chroots, so I'll revise it shortly.

-- 
Steve Langasek                   Give me a lever long enough and a Free OS
Debian Developer                   to set it on, and I can move the world.
Ubuntu Developer                                   https://www.debian.org/
slangasek@ubuntu.com                                     vorlon@debian.org
diff -Nru schroot-1.6.10/debian/control schroot-1.6.10/debian/control
--- schroot-1.6.10/debian/control	2018-09-01 02:25:59.000000000 -0500
+++ schroot-1.6.10/debian/control	2019-12-30 23:59:11.000000000 -0600
@@ -54,7 +54,7 @@
  sbuild (<< 0.62.6),
 # We need the --find option of update-binfmts
  binfmt-support (<< 2.0.1)
-Suggests: debootstrap, lvm2, btrfs-tools, aufs-tools | unionfs-fuse, qemu-user-static
+Suggests: debootstrap, lvm2, btrfs-tools, zfsutils-linux, aufs-tools | unionfs-fuse, qemu-user-static
 Description: Execute commands in a chroot environment
  schroot allows users to execute commands or interactive shells in
  different chroots.  Any number of named chroots may be created, and
@@ -67,7 +67,7 @@
  Several different types of chroot are supported, including normal
  directories in the filesystem, and also block devices.  Sessions,
  persistent chroots created on the fly from files (tar with optional
- compression) and Btrfs and LVM snapshots are also supported.
+ compression) and Btrfs, ZFS, and LVM snapshots are also supported.
  .
  schroot supports kernel personalities, allowing the programs run
  inside the chroot to have a different personality.  For example,
@@ -76,7 +76,7 @@
  .
  schroot also integrates with sbuild, to allow building packages with
  all supported chroot types, including session-managed chroot types
- such as Btrfs and LVM snapshots.
+ such as Btrfs, ZFS, and LVM snapshots.
  .
  schroot shares most of its options with dchroot, but offers vastly
  more functionality.
diff -Nru schroot-1.6.10/debian/patches/series schroot-1.6.10/debian/patches/series
--- schroot-1.6.10/debian/patches/series	2018-09-01 02:25:59.000000000 -0500
+++ schroot-1.6.10/debian/patches/series	2019-12-30 19:40:44.000000000 -0600
@@ -13,3 +13,4 @@
 update_czech_schroot_translation.patch
 update_french_schroot_manpage_translation_2018.patch
 update_german_schroot_manpage_translation_2018.patch
+zfs-snapshot-support.patch
diff -Nru schroot-1.6.10/debian/patches/zfs-snapshot-support.patch schroot-1.6.10/debian/patches/zfs-snapshot-support.patch
--- schroot-1.6.10/debian/patches/zfs-snapshot-support.patch	1969-12-31 18:00:00.000000000 -0600
+++ schroot-1.6.10/debian/patches/zfs-snapshot-support.patch	2019-12-30 23:59:11.000000000 -0600
@@ -0,0 +1,1186 @@
+Description: add support for a zfs-snapshot backend.
+Author: Steve Langasek <vorlon@debian.org>
+Last-Update: 2020-01-01
+
+Index: schroot-1.6.10/sbuild/sbuild-chroot-zfs-snapshot.cc
+===================================================================
+--- /dev/null
++++ schroot-1.6.10/sbuild/sbuild-chroot-zfs-snapshot.cc
+@@ -0,0 +1,259 @@
++/* Copyright © 2005-2009  Roger Leigh <rleigh@debian.org>
++ * Copyright © 2019       Steve Langasek <vorlon@debian.org>
++ *
++ * schroot is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * schroot is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see
++ * <http://www.gnu.org/licenses/>.
++ *
++ *********************************************************************/
++
++#include <config.h>
++
++#include "sbuild-chroot-zfs-snapshot.h"
++#include "sbuild-chroot-block-device.h"
++#include "sbuild-chroot-facet-session.h"
++#include "sbuild-chroot-facet-session-clonable.h"
++#include "sbuild-chroot-facet-source-clonable.h"
++#include "sbuild-chroot-facet-mountable.h"
++#include "sbuild-format-detail.h"
++
++#include <cassert>
++#include <cerrno>
++
++#include <boost/format.hpp>
++
++using std::endl;
++using boost::format;
++using namespace sbuild;
++
++chroot_zfs_snapshot::chroot_zfs_snapshot ():
++  chroot_block_device_base(),
++  clone_name(),
++  snapshot_name(),
++  snapshot_options()
++{
++  add_facet(chroot_facet_source_clonable::create());
++}
++
++chroot_zfs_snapshot::chroot_zfs_snapshot (const chroot_zfs_snapshot& rhs):
++  chroot_block_device_base(rhs),
++  clone_name(rhs.clone_name),
++  snapshot_name(rhs.snapshot_name),
++  snapshot_options(rhs.snapshot_options)
++{
++}
++
++chroot_zfs_snapshot::~chroot_zfs_snapshot ()
++{
++}
++
++void
++chroot_zfs_snapshot::set_device (std::string const& device)
++{
++  // overload to omit the requirement of an absolute path, not applicable to
++  // ZFS volumes
++  this->device = device;
++}
++
++sbuild::chroot::ptr
++chroot_zfs_snapshot::clone () const
++{
++  return ptr(new chroot_zfs_snapshot(*this));
++}
++
++sbuild::chroot::ptr
++chroot_zfs_snapshot::clone_session (std::string const& session_id,
++                                    std::string const& alias,
++                                    std::string const& user,
++                                    bool               root) const
++{
++  chroot_facet_session_clonable::const_ptr psess
++    (get_facet<chroot_facet_session_clonable>());
++  assert(psess);
++
++  ptr session(new chroot_zfs_snapshot(*this));
++  psess->clone_session_setup(*this, session, session_id, alias, user, root);
++
++  return session;
++}
++
++sbuild::chroot::ptr
++chroot_zfs_snapshot::clone_source () const
++{
++  ptr clone(new chroot_block_device(*this));
++
++  chroot_facet_source_clonable::const_ptr psrc
++    (get_facet<chroot_facet_source_clonable>());
++  assert(psrc);
++
++  psrc->clone_source_setup(*this, clone);
++
++  return clone;
++}
++
++std::string const&
++chroot_zfs_snapshot::get_clone_name () const
++{
++  return this->clone_name;
++}
++
++void
++chroot_zfs_snapshot::set_clone_name (std::string const& clone_name)
++{
++  this->clone_name = clone_name;
++
++  chroot_facet_mountable::ptr pmnt
++    (get_facet<chroot_facet_mountable>());
++  if (pmnt)
++    pmnt->set_mount_device(this->clone_name);
++}
++
++std::string const&
++chroot_zfs_snapshot::get_snapshot_name () const
++{
++  return this->snapshot_name;
++}
++
++void
++chroot_zfs_snapshot::set_snapshot_name (std::string const& snapshot_name)
++{
++  this->snapshot_name = snapshot_name;
++}
++
++std::string const&
++chroot_zfs_snapshot::get_snapshot_options () const
++{
++  return this->snapshot_options;
++}
++
++void
++chroot_zfs_snapshot::set_snapshot_options (std::string const& snapshot_options)
++{
++  this->snapshot_options = snapshot_options;
++}
++
++std::string const&
++chroot_zfs_snapshot::get_chroot_type () const
++{
++  static const std::string type("zfs-snapshot");
++
++  return type;
++}
++
++void
++chroot_zfs_snapshot::setup_env (chroot const& chroot,
++                                environment&  env) const
++{
++  chroot_block_device_base::setup_env(chroot, env);
++
++  env.add("CHROOT_ZFS_SNAPSHOT_NAME", get_snapshot_name());
++  env.add("CHROOT_ZFS_CLONE_NAME", get_clone_name());
++  env.add("CHROOT_ZFS_SNAPSHOT_OPTIONS", get_snapshot_options());
++}
++
++void
++chroot_zfs_snapshot::setup_lock (chroot::setup_type type,
++                                 bool               lock,
++                                 int                status)
++{
++  /* Create or unlink session information. */
++  if ((type == SETUP_START && lock == true) ||
++      (type == SETUP_STOP && lock == false && status == 0))
++    {
++      bool start = (type == SETUP_START);
++      setup_session_info(start);
++    }
++}
++
++sbuild::chroot::session_flags
++chroot_zfs_snapshot::get_session_flags (chroot const& chroot) const
++{
++  session_flags flags = SESSION_NOFLAGS;
++
++  if (get_facet<chroot_facet_session>())
++    flags = flags | SESSION_PURGE;
++
++  return flags;
++}
++
++void
++chroot_zfs_snapshot::get_details (chroot const& chroot,
++                                  format_detail& detail) const
++{
++  chroot_block_device_base::get_details(chroot, detail);
++
++  if (!this->snapshot_name.empty())
++    detail.add(_("ZFS Snapshot Name"), get_snapshot_name());
++  if (!this->clone_name.empty())
++    detail.add(_("ZFS Clone Dataset"), get_clone_name());
++  if (!this->snapshot_options.empty())
++    detail.add(_("ZFS Snapshot Options"), get_snapshot_options());
++}
++
++void
++chroot_zfs_snapshot::get_keyfile (chroot const& chroot,
++                                  keyfile& keyfile) const
++{
++  chroot_block_device_base::get_keyfile(chroot, keyfile);
++
++  bool session = static_cast<bool>(get_facet<chroot_facet_session>());
++
++  if (session)
++  {
++    keyfile::set_object_value(*this,
++                              &chroot_zfs_snapshot::get_snapshot_name,
++                              keyfile, get_name(),
++                              "zfs-snapshot-name");
++    keyfile::set_object_value(*this,
++                              &chroot_zfs_snapshot::get_clone_name,
++                              keyfile, get_name(),
++                              "zfs-clone-name");
++  }
++
++  if (!session)
++    keyfile::set_object_value(*this,
++                              &chroot_zfs_snapshot::get_snapshot_options,
++                              keyfile, get_name(),
++                              "zfs-snapshot-options");
++}
++
++void
++chroot_zfs_snapshot::set_keyfile (chroot&        chroot,
++                                  keyfile const& keyfile,
++                                  string_list&   used_keys)
++{
++  chroot_block_device_base::set_keyfile(chroot, keyfile, used_keys);
++
++  bool session = static_cast<bool>(get_facet<chroot_facet_session>());
++
++  keyfile::get_object_value(*this, &chroot_zfs_snapshot::set_snapshot_name,
++                            keyfile, get_name(), "zfs-snapshot-name",
++                            session ?
++                            keyfile::PRIORITY_REQUIRED :
++                            keyfile::PRIORITY_DISALLOWED);
++  used_keys.push_back("zfs-snapshot-name");
++
++  keyfile::get_object_value(*this, &chroot_zfs_snapshot::set_clone_name,
++                            keyfile, get_name(), "zfs-clone-name",
++                            session ?
++                            keyfile::PRIORITY_REQUIRED :
++                            keyfile::PRIORITY_DISALLOWED);
++  used_keys.push_back("zfs-clone-name");
++
++  keyfile::get_object_value(*this, &chroot_zfs_snapshot::set_snapshot_options,
++                            keyfile, get_name(), "zfs-snapshot-options",
++                            session ?
++                            keyfile::PRIORITY_DISALLOWED :
++                            keyfile::PRIORITY_OPTIONAL); // Only needed for creating snapshot, not using snapshot
++  used_keys.push_back("zfs-snapshot-options");
++}
+Index: schroot-1.6.10/test/sbuild-chroot-zfs-snapshot.cc
+===================================================================
+--- /dev/null
++++ schroot-1.6.10/test/sbuild-chroot-zfs-snapshot.cc
+@@ -0,0 +1,314 @@
++/* Copyright © 2006-2008  Roger Leigh <rleigh@debian.org>
++ * Copyright © 2019       Steve Langasek <vorlon@debian.org>
++ *
++ * schroot is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * schroot is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see
++ * <http://www.gnu.org/licenses/>.
++ *
++ *********************************************************************/
++
++#include <config.h>
++
++#include <sbuild/sbuild-chroot-zfs-snapshot.h>
++#include <sbuild/sbuild-chroot-facet-mountable.h>
++#include <sbuild/sbuild-i18n.h>
++#include <sbuild/sbuild-util.h>
++
++#include "test-helpers.h"
++#include "test-sbuild-chroot.h"
++
++#include <algorithm>
++#include <set>
++
++#include <cppunit/extensions/HelperMacros.h>
++
++using namespace CppUnit;
++
++using sbuild::_;
++
++class chroot_zfs_snapshot : public sbuild::chroot_zfs_snapshot
++{
++public:
++  chroot_zfs_snapshot():
++    sbuild::chroot_zfs_snapshot()
++  {}
++
++  virtual ~chroot_zfs_snapshot()
++  {}
++};
++
++class test_chroot_zfs_snapshot : public test_chroot_base<chroot_zfs_snapshot>
++{
++  CPPUNIT_TEST_SUITE(test_chroot_zfs_snapshot);
++  CPPUNIT_TEST(test_snapshot_name);
++  CPPUNIT_TEST(test_snapshot_options);
++  CPPUNIT_TEST(test_chroot_type);
++  CPPUNIT_TEST(test_setup_env);
++  CPPUNIT_TEST(test_setup_env_session);
++  CPPUNIT_TEST(test_setup_env_source);
++  CPPUNIT_TEST(test_setup_env_session_source);
++  CPPUNIT_TEST(test_setup_keyfile);
++  CPPUNIT_TEST(test_setup_keyfile_session);
++  CPPUNIT_TEST(test_setup_keyfile_source);
++  CPPUNIT_TEST(test_setup_keyfile_session_source);
++  CPPUNIT_TEST(test_session_flags);
++  CPPUNIT_TEST(test_print_details);
++  CPPUNIT_TEST(test_print_config);
++  CPPUNIT_TEST(test_run_setup_scripts);
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  test_chroot_zfs_snapshot():
++    test_chroot_base<chroot_zfs_snapshot>()
++  {}
++
++  void setUp()
++  {
++    test_chroot_base<chroot_zfs_snapshot>::setUp();
++    CPPUNIT_ASSERT(chroot);
++    CPPUNIT_ASSERT(session);
++    CPPUNIT_ASSERT(source);
++    CPPUNIT_ASSERT(session_source);
++  }
++
++  virtual void setup_chroot_props (sbuild::chroot::ptr& chroot)
++  {
++    test_chroot_base<chroot_zfs_snapshot>::setup_chroot_props(chroot);
++
++    std::shared_ptr<sbuild::chroot_zfs_snapshot> c = std::dynamic_pointer_cast<sbuild::chroot_zfs_snapshot>(chroot);
++
++    c->set_device("schroot-pool/testdev");
++    c->set_snapshot_options("--size 1G");
++
++    sbuild::chroot_facet_mountable::ptr pmnt(chroot->get_facet<sbuild::chroot_facet_mountable>());
++    CPPUNIT_ASSERT(pmnt);
++
++    pmnt->set_mount_options("-t jfs -o quota,rw");
++    pmnt->set_location("/squeeze");
++  }
++
++  void
++  test_snapshot_name()
++  {
++    std::shared_ptr<sbuild::chroot_zfs_snapshot> c = std::dynamic_pointer_cast<sbuild::chroot_zfs_snapshot>(chroot);
++    CPPUNIT_ASSERT(c);
++    c->set_snapshot_name("some-snapshot-name");
++    CPPUNIT_ASSERT(c->get_snapshot_name() == "some-snapshot-name");
++  }
++
++  void
++  test_snapshot_options()
++  {
++    std::shared_ptr<sbuild::chroot_zfs_snapshot> c = std::dynamic_pointer_cast<sbuild::chroot_zfs_snapshot>(chroot);
++    CPPUNIT_ASSERT(c);
++    c->set_snapshot_options("-o opt1,opt2");
++    CPPUNIT_ASSERT(c->get_snapshot_options() == "-o opt1,opt2");
++  }
++
++  void test_chroot_type()
++  {
++    CPPUNIT_ASSERT(chroot->get_chroot_type() == "zfs-snapshot");
++  }
++
++  void setup_env_gen(sbuild::environment &expected)
++  {
++    setup_env_chroot(expected);
++    expected.add("CHROOT_LOCATION",       "/squeeze");
++    expected.add("CHROOT_MOUNT_LOCATION", "/mnt/mount-location");
++    expected.add("CHROOT_PATH",           "/mnt/mount-location/squeeze");
++    expected.add("CHROOT_DEVICE",         "schroot-pool/testdev");
++    expected.add("CHROOT_MOUNT_OPTIONS",  "-t jfs -o quota,rw");
++  }
++
++  void test_setup_env()
++  {
++    sbuild::environment expected;
++    setup_env_gen(expected);
++    expected.add("CHROOT_TYPE",           "zfs-snapshot");
++    expected.add("CHROOT_ZFS_SNAPSHOT_OPTIONS", "--size 1G");
++    expected.add("CHROOT_SESSION_CLONE",  "true");
++    expected.add("CHROOT_SESSION_CREATE", "true");
++    expected.add("CHROOT_SESSION_PURGE",  "false");
++    expected.add("CHROOT_SESSION_SOURCE", "false");
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_env(chroot, expected);
++  }
++
++  void test_setup_env_session()
++  {
++    std::shared_ptr<sbuild::chroot_zfs_snapshot> c = std::dynamic_pointer_cast<sbuild::chroot_zfs_snapshot>(chroot);
++
++    sbuild::environment expected;
++    setup_env_gen(expected);
++    expected.add("CHROOT_TYPE",           "zfs-snapshot");
++    expected.add("SESSION_ID",            "test-session-name");
++    expected.add("CHROOT_ALIAS",          "test-session-name");
++    expected.add("CHROOT_DESCRIPTION",     chroot->get_description() + ' ' + _("(session chroot)"));
++    expected.add("CHROOT_MOUNT_DEVICE",   "schroot-pool/testdev/schroot-test-session-name");
++    expected.add("CHROOT_ZFS_SNAPSHOT_NAME",    "schroot-pool/testdev@test-session-name");
++    expected.add("CHROOT_ZFS_CLONE_NAME",   "schroot-pool/testdev/schroot-test-session-name");
++    expected.add("CHROOT_ZFS_SNAPSHOT_OPTIONS", "--size 1G");
++    expected.add("CHROOT_SESSION_CLONE",  "false");
++    expected.add("CHROOT_SESSION_CREATE", "false");
++    expected.add("CHROOT_SESSION_PURGE",  "true");
++    expected.add("CHROOT_SESSION_SOURCE", "false");
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_env(session, expected);
++  }
++
++  void test_setup_env_source()
++  {
++    sbuild::environment expected;
++    setup_env_gen(expected);
++    expected.add("CHROOT_TYPE",           "block-device");
++    expected.add("CHROOT_NAME",           "test-name");
++    expected.add("CHROOT_DESCRIPTION",     chroot->get_description() + ' ' + _("(source chroot)"));
++    expected.add("CHROOT_SESSION_CLONE",  "false");
++    expected.add("CHROOT_SESSION_CREATE", "true");
++    expected.add("CHROOT_SESSION_PURGE",  "false");
++    expected.add("CHROOT_SESSION_SOURCE", "false");
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_env(source, expected);
++  }
++
++  void test_setup_env_session_source()
++  {
++    sbuild::environment expected;
++    setup_env_gen(expected);
++    expected.add("CHROOT_TYPE",           "block-device");
++    expected.add("CHROOT_NAME",           "test-name");
++    expected.add("SESSION_ID",            "test-session-name");
++    expected.add("CHROOT_DESCRIPTION",     chroot->get_description() + ' ' + _("(source chroot) (session chroot)"));
++    expected.add("CHROOT_ALIAS",          "test-session-name");
++    expected.add("CHROOT_MOUNT_DEVICE",   "schroot-pool/testdev");
++    expected.add("CHROOT_SESSION_CLONE",  "false");
++    expected.add("CHROOT_SESSION_CREATE", "false");
++    expected.add("CHROOT_SESSION_PURGE",  "false");
++    expected.add("CHROOT_SESSION_SOURCE", "true");
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_env(session_source, expected);
++  }
++
++  void setup_keyfile_zfs(sbuild::keyfile &expected, std::string group)
++  {
++    expected.set_value(group, "device", "schroot-pool/testdev");
++    expected.set_value(group, "location", "/squeeze");
++    expected.set_value(group, "mount-options", "-t jfs -o quota,rw");
++  }
++
++  void test_setup_keyfile()
++  {
++    sbuild::keyfile expected;
++    std::string group = chroot->get_name();
++    setup_keyfile_chroot(expected, group);
++    setup_keyfile_source(expected, group);
++    setup_keyfile_zfs(expected, group);
++    expected.set_value(group, "type", "zfs-snapshot");
++    expected.set_value(group, "zfs-snapshot-options", "--size 1G");
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_keyfile
++      (chroot,expected, chroot->get_name());
++  }
++
++  void test_setup_keyfile_session()
++  {
++    sbuild::keyfile expected;
++    const std::string group(session->get_name());
++    setup_keyfile_session(expected, group);
++    setup_keyfile_zfs(expected, group);
++    expected.set_value(group, "type", "zfs-snapshot");
++    expected.set_value(group, "name", "test-session-name");
++    expected.set_value(group, "selected-name", "test-session-name");
++    expected.set_value(group, "description", chroot->get_description() + ' ' + _("(session chroot)"));
++    expected.set_value(group, "aliases", "");
++    expected.set_value(group, "zfs-snapshot-name", "schroot-pool/testdev@test-session-name");
++    expected.set_value(group, "zfs-clone-name", "schroot-pool/testdev/schroot-test-session-name");
++    expected.set_value(group, "mount-device", "schroot-pool/testdev/schroot-test-session-name");
++    expected.set_value(group, "mount-location", "/mnt/mount-location");
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_keyfile
++      (session, expected, group);
++  }
++
++  void test_setup_keyfile_source()
++  {
++    sbuild::keyfile expected;
++    const std::string group(source->get_name());
++    setup_keyfile_chroot(expected, group);
++    setup_keyfile_zfs(expected, group);
++    expected.set_value(group, "type", "block-device");
++    expected.set_value(group, "description", chroot->get_description() + ' ' + _("(source chroot)"));
++    expected.set_value(group, "aliases", "test-name-source,test-alias-1-source,test-alias-2-source");
++    setup_keyfile_source_clone(expected, group);
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_keyfile
++      (source, expected, group);
++  }
++
++  void test_setup_keyfile_session_source()
++  {
++    sbuild::keyfile expected;
++    const std::string group(source->get_name());
++    setup_keyfile_chroot(expected, group);
++    setup_keyfile_zfs(expected, group);
++    expected.set_value(group, "type", "block-device");
++    expected.set_value(group, "mount-device", "schroot-pool/testdev");
++    expected.set_value(group, "mount-location", "/mnt/mount-location");
++    setup_keyfile_session_source_clone(expected, group);
++
++    test_chroot_base<chroot_zfs_snapshot>::test_setup_keyfile
++      (session_source, expected, group);
++  }
++
++  void test_session_flags()
++  {
++    CPPUNIT_ASSERT(chroot->get_session_flags() ==
++                   (sbuild::chroot::SESSION_CREATE |
++                    sbuild::chroot::SESSION_CLONE));
++
++    CPPUNIT_ASSERT(session->get_session_flags() ==
++                   (sbuild::chroot::SESSION_PURGE));
++
++    /// @todo: Should return NOFLAGS?  This depends upon if source
++    /// chroots need transforming into sessions as well (which should
++    /// probably happen and be tested for independently).
++    CPPUNIT_ASSERT(source->get_session_flags() ==
++                   (sbuild::chroot::SESSION_CREATE));
++  }
++
++  void test_print_details()
++  {
++    std::ostringstream os;
++    os << chroot;
++    // TODO: Compare output.
++    CPPUNIT_ASSERT(!os.str().empty());
++  }
++
++  void test_print_config()
++  {
++    std::ostringstream os;
++    sbuild::keyfile config;
++    config << chroot;
++    os << config;
++    // TODO: Compare output.
++    CPPUNIT_ASSERT(!os.str().empty());
++  }
++
++  void test_run_setup_scripts()
++  {
++    CPPUNIT_ASSERT(chroot->get_run_setup_scripts());
++  }
++
++};
++
++CPPUNIT_TEST_SUITE_REGISTRATION(test_chroot_zfs_snapshot);
+Index: schroot-1.6.10/etc/setup.d/05zfs
+===================================================================
+--- /dev/null
++++ schroot-1.6.10/etc/setup.d/05zfs
+@@ -0,0 +1,67 @@
++#!/bin/sh
++# Copyright © 2005-2007  Roger Leigh <rleigh@debian.org>
++# Copyright © 2019       Steve Langasek <vorlon@debian.org>
++#
++# schroot is free software: you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# schroot is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see
++# <http://www.gnu.org/licenses/>.
++#
++#####################################################################
++
++set -e
++
++. "$SETUP_DATA_DIR/common-data"
++. "$SETUP_DATA_DIR/common-functions"
++. "$SETUP_DATA_DIR/common-config"
++
++if [ "$CHROOT_TYPE" = "zfs-snapshot" ]; then
++
++    if [ $STAGE = "setup-start" ]; then
++
++        if ! zfs list "$CHROOT_DEVICE" >/dev/null 2>&1; then
++            fatal "Device '$CHROOT_DEVICE' does not exist"
++        fi
++
++        if [ "$VERBOSE" = "verbose" ]; then
++            zfs snapshot "$CHROOT_ZFS_SNAPSHOT_NAME" \
++                $CHROOT_ZFS_SNAPSHOT_OPTIONS
++            zfs clone "$CHROOT_ZFS_SNAPSHOT_NAME" \
++                "$CHROOT_ZFS_CLONE_NAME" -o mountpoint=legacy
++        else
++            zfs snapshot "$CHROOT_ZFS_SNAPSHOT_NAME" \
++                $CHROOT_ZFS_SNAPSHOT_OPTIONS > /dev/null
++            zfs clone "$CHROOT_ZFS_SNAPSHOT_NAME" \
++                "$CHROOT_ZFS_CLONE_NAME" -o mountpoint=legacy > /dev/null
++        fi
++
++    elif [ $STAGE = "setup-stop" ]; then
++
++        if zfs list "$CHROOT_ZFS_CLONE_NAME" >/dev/null 2>&1
++        then
++            if [ "$VERBOSE" = "verbose" ]; then
++                zfs destroy "$CHROOT_ZFS_CLONE_NAME"
++                zfs destroy "$CHROOT_ZFS_SNAPSHOT_NAME"
++            else
++                zfs destroy "$CHROOT_ZFS_CLONE_NAME" > /dev/null
++                zfs destroy "$CHROOT_ZFS_SNAPSHOT_NAME" > /dev/null
++            fi
++        else
++            # The dataset no longer exists, or was never created,
++            # for example on zfs clone failure.
++            warn "$CHROOT_ZFS_SNAPSHOT_NAME does not exist (it may have been removed previously)"
++        fi
++
++    fi
++
++fi
++
+Index: schroot-1.6.10/sbuild/sbuild-chroot-block-device.cc
+===================================================================
+--- schroot-1.6.10.orig/sbuild/sbuild-chroot-block-device.cc
++++ schroot-1.6.10/sbuild/sbuild-chroot-block-device.cc
+@@ -64,6 +64,17 @@
+ }
+ #endif // SBUILD_FEATURE_LVMSNAP
+ 
++#ifdef SBUILD_FEATURE_ZFSSNAP
++chroot_block_device::chroot_block_device (const chroot_zfs_snapshot& rhs):
++  chroot_block_device_base(rhs)
++{
++#ifdef SBUILD_FEATURE_UNION
++  if (!get_facet<chroot_facet_union>())
++    add_facet(chroot_facet_union::create());
++#endif // SBUILD_FEATURE_UNION
++}
++#endif // SBUILD_FEATURE_ZFSSNAP
++
+ sbuild::chroot::ptr
+ chroot_block_device::clone () const
+ {
+Index: schroot-1.6.10/sbuild/sbuild-chroot-block-device.h
+===================================================================
+--- schroot-1.6.10.orig/sbuild/sbuild-chroot-block-device.h
++++ schroot-1.6.10/sbuild/sbuild-chroot-block-device.h
+@@ -22,6 +22,7 @@
+ #include <sbuild/sbuild-config.h>
+ #include <sbuild/sbuild-chroot-block-device-base.h>
+ #include <sbuild/sbuild-chroot-lvm-snapshot.h>
++#include <sbuild/sbuild-chroot-zfs-snapshot.h>
+ 
+ namespace sbuild
+ {
+@@ -49,10 +50,18 @@
+     chroot_block_device (const chroot_lvm_snapshot& rhs);
+ #endif
+ 
++#ifdef SBUILD_FEATURE_ZFSSNAP
++    /// The copy constructor.
++    chroot_block_device (const chroot_zfs_snapshot& rhs);
++#endif
++
+     friend class chroot;
+ #ifdef SBUILD_FEATURE_LVMSNAP
+     friend class chroot_lvm_snapshot;
+ #endif
++#ifdef SBUILD_FEATURE_LVMSNAP
++    friend class chroot_zfs_snapshot;
++#endif
+ 
+   public:
+     /// The destructor.
+Index: schroot-1.6.10/sbuild/sbuild-chroot-zfs-snapshot.h
+===================================================================
+--- /dev/null
++++ schroot-1.6.10/sbuild/sbuild-chroot-zfs-snapshot.h
+@@ -0,0 +1,157 @@
++/* Copyright © 2005-2008  Roger Leigh <rleigh@debian.org>
++ * Copyright © 2019       Steve Langasek <vorlon@debian.org>
++ *
++ * schroot is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * schroot is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see
++ * <http://www.gnu.org/licenses/>.
++ *
++ *********************************************************************/
++
++#ifndef SBUILD_CHROOT_ZFS_SNAPSHOT_H
++#define SBUILD_CHROOT_ZFS_SNAPSHOT_H
++
++#include <sbuild/sbuild-chroot-block-device-base.h>
++
++namespace sbuild
++{
++
++  /**
++   * A chroot stored on a ZFS dataset.
++   *
++   * A clone dataset will be created and mounted on demand.
++   */
++  class chroot_zfs_snapshot : public chroot_block_device_base
++  {
++  protected:
++    /// The constructor.
++    chroot_zfs_snapshot ();
++
++    /// The copy constructor.
++    chroot_zfs_snapshot (const chroot_zfs_snapshot& rhs);
++
++    friend class chroot;
++
++  public:
++    /// The destructor.
++    virtual ~chroot_zfs_snapshot ();
++
++    virtual chroot::ptr
++    clone () const;
++
++    void
++    set_device (std::string const& device);
++
++    virtual chroot::ptr
++    clone_session (std::string const& session_id,
++                   std::string const& alias,
++                   std::string const& user,
++                   bool               root) const;
++
++    virtual chroot::ptr
++    clone_source () const;
++
++    /**
++     * Get the ZFS clone name.  This is used by "zfs clone".
++     *
++     * @returns the clone name.
++     */
++    std::string const&
++    get_clone_name () const;
++
++    /**
++     * Set the clone name.  This is used by "zfs clone".
++     *
++     * @param clone_name the clone name.
++     */
++    void
++    set_clone_name (std::string const& clone_name);
++
++    /**
++     * Get the ZFS snapshot name.  This is used by "zfs snapshot".
++     *
++     * @returns the snapshot name.
++     */
++    std::string const&
++    get_snapshot_name () const;
++
++    /**
++     * Set the snapshot name.  This is used by "zfs snapshot".
++     *
++     * @param snapshot_name the snapshot name.
++     */
++    void
++    set_snapshot_name (std::string const& snapshot_name);
++
++    /**
++     * Get the ZFS snapshot options.  These are used by "zfs snapshot".
++     *
++     * @returns the options.
++     */
++    std::string const&
++    get_snapshot_options () const;
++
++    /**
++     * Set the ZFS snapshot options.  These are used by "zfs snapshot".
++     *
++     * @param snapshot_options the options.
++     */
++    void
++    set_snapshot_options (std::string const& snapshot_options);
++
++    virtual std::string const&
++    get_chroot_type () const;
++
++    virtual void
++    setup_env (chroot const& chroot,
++               environment&  env) const;
++
++    virtual session_flags
++    get_session_flags (chroot const& chroot) const;
++
++  protected:
++    virtual void
++    setup_lock (chroot::setup_type type,
++                bool               lock,
++                int                status);
++
++    virtual void
++    get_details (chroot const& chroot,
++                 format_detail& detail) const;
++
++    virtual void
++    get_keyfile (chroot const& chroot,
++                 keyfile& keyfile) const;
++
++    virtual void
++    set_keyfile (chroot&        chroot,
++                 keyfile const& keyfile,
++                 string_list&   used_keys);
++
++  private:
++    /// ZFS clone name for "zfs clone"
++    std::string clone_name;
++    /// ZFS snapshot name for "zfs snapshot"
++    std::string snapshot_name;
++    /// ZFS snapshot options for "zfs snapshot"
++    std::string snapshot_options;
++  };
++
++}
++
++#endif /* SBUILD_CHROOT_ZFS_SNAPSHOT_H */
++
++/*
++ * Local Variables:
++ * mode:C++
++ * End:
++ */
+Index: schroot-1.6.10/CMakeLists.txt
+===================================================================
+--- schroot-1.6.10.orig/CMakeLists.txt
++++ schroot-1.6.10/CMakeLists.txt
+@@ -223,6 +223,19 @@
+   set(BLOCKDEV_DEFAULT ON)
+ endif(lvm-snapshot)
+ 
++# ZFS snapshot mount feature
++find_program(ZFS_EXECUTABLE zfs PATHS /sbin /usr/sbin /usr/local/sbin)
++set(ZFSSNAP_DEFAULT OFF)
++if (ZFS_EXECUTABLE)
++  set (ZFSSNAP_DEFAULT ON)
++endif (ZFS_EXECUTABLE)
++option(zfs-snapshot "Enable support for ZFS snapshots (requires ZFS)" ${ZFSSNAP_DEFAULT})
++set(BUILD_ZFSSNAP ${zfs-snapshot})
++set(SBUILD_FEATURE_ZFSSNAP ${zfs-snapshot})
++if (zfs-snapshot)
++  set(BLOCKDEV_DEFAULT ON)
++endif(zfs-snapshot)
++
+ # Btrfs snapshot mount feature
+ find_program(BTRFS_EXECUTABLE btrfs PATHS /sbin /usr/sbin /usr/local/sbin)
+ set(BTRFSSNAP_DEFAULT OFF)
+@@ -244,6 +257,9 @@
+ if(lvm-snapshot AND NOT block-device)
+   message(FATAL_ERROR "block-device must be enabled when lvm-snapshot is enabled")
+ endif(lvm-snapshot AND NOT block-device)
++if(zfs-snapshot AND NOT block-device)
++  message(FATAL_ERROR "block-device must be enabled when zfs-snapshot is enabled")
++endif(zfs-snapshot AND NOT block-device)
+ if(btrfs-snapshot AND NOT block-device)
+   message(FATAL_ERROR "block-device must be enabled when btrfs-snapshot is enabled")
+ endif(btrfs-snapshot AND NOT block-device)
+Index: schroot-1.6.10/test/CMakeLists.txt
+===================================================================
+--- schroot-1.6.10.orig/test/CMakeLists.txt
++++ schroot-1.6.10/test/CMakeLists.txt
+@@ -46,6 +46,11 @@
+       sbuild-chroot-lvm-snapshot.cc)
+ endif(BUILD_LVMSNAP)
+ 
++if(BUILD_ZFSSNAP)
++  set(sbuild_chroot_zfssnap_sources
++      sbuild-chroot-zfs-snapshot.cc)
++endif(BUILD_ZFSSNAP)
++
+ if(BUILD_BTRFSSNAP)
+   set(sbuild_chroot_btrfssnap_sources
+       sbuild-chroot-btrfs-snapshot.cc)
+@@ -64,6 +69,7 @@
+     sbuild-chroot-directory.cc
+     ${sbuild_chroot_blockdev_sources}
+     ${sbuild_chroot_lvmsnap_sources}
++    ${sbuild_chroot_zfssnap_sources}
+     ${sbuild_chroot_btrfssnap_sources}
+     ${sbuild_chroot_loopback_sources}
+     sbuild-chroot-facet-userdata.cc)
+Index: schroot-1.6.10/test/Makefile.am
+===================================================================
+--- schroot-1.6.10.orig/test/Makefile.am
++++ schroot-1.6.10/test/Makefile.am
+@@ -36,6 +36,7 @@
+ 	sbuild-chroot-loopback		\
+ 	sbuild-chroot-lvm-snapshot	\
+ 	sbuild-chroot-btrfs-snapshot	\
++	sbuild-chroot-zfs-snapshot	\
+ 	sbuild-chroot-config		\
+ 	sbuild-chroot-facet-userdata	\
+ 	sbuild-environment		\
+@@ -62,6 +63,7 @@
+ 	sbuild-chroot-loopback		\
+ 	sbuild-chroot-lvm-snapshot	\
+ 	sbuild-chroot-btrfs-snapshot	\
++	sbuild-chroot-zfs-snapshot	\
+ 	sbuild-chroot-config		\
+ 	sbuild-chroot-facet-userdata	\
+ 	sbuild-environment		\
+@@ -102,6 +104,11 @@
+ 	sbuild-chroot-btrfs-snapshot.cc
+ endif
+ 
++if BUILD_ZFSSNAP
++sbuild_chroot_zfssnap_sources =	\
++	sbuild-chroot-zfs-snapshot.cc
++endif
++
+ sbuild_chroot_SOURCES =		\
+ 	sbuild-chroot.cc	\
+ 	test-sbuild-chroot.h
+@@ -142,6 +149,11 @@
+ 	test-sbuild-chroot.h
+ sbuild_chroot_btrfs_snapshot_LDADD =  libtest.la
+ 
++sbuild_chroot_zfs_snapshot_SOURCES =		\
++	$(sbuild_chroot_zfssnap_sources)	\
++	test-sbuild-chroot.h
++sbuild_chroot_zfs_snapshot_LDADD =  libtest.la
++
+ sbuild_chroot_loopback_SOURCES =		\
+ 	$(sbuild_chroot_loopback_sources)	\
+ 	test-sbuild-chroot.h
+Index: schroot-1.6.10/sbuild/CMakeLists.txt
+===================================================================
+--- schroot-1.6.10.orig/sbuild/CMakeLists.txt
++++ schroot-1.6.10/sbuild/CMakeLists.txt
+@@ -59,6 +59,13 @@
+       sbuild-chroot-lvm-snapshot.cc)
+ endif(BUILD_LVMSNAP)
+ 
++if(BUILD_ZFSSNAP)
++  set(public_zfssnap_h_sources
++      sbuild-chroot-zfs-snapshot.h)
++  set(public_zfssnap_cc_sources
++      sbuild-chroot-zfs-snapshot.cc)
++endif(BUILD_ZFSSNAP)
++
+ if(BUILD_BTRFSSNAP)
+   set(public_btrfssnap_h_sources
+       sbuild-chroot-btrfs-snapshot.h)
+@@ -148,6 +155,7 @@
+     ${public_blockdev_base_h_sources}
+     ${public_blockdev_h_sources}
+     ${public_lvmsnap_h_sources}
++    ${public_zfssnap_h_sources}
+     ${public_btrfssnap_h_sources}
+     ${public_loopback_h_sources})
+ 
+@@ -162,6 +170,7 @@
+     ${public_blockdev_base_cc_sources}
+     ${public_blockdev_cc_sources}
+     ${public_lvmsnap_cc_sources}
++    ${public_zfssnap_cc_sources}
+     ${public_btrfssnap_cc_sources}
+     ${public_loopback_cc_sources})
+ 
+Index: schroot-1.6.10/sbuild/sbuild-chroot-block-device-base.h
+===================================================================
+--- schroot-1.6.10.orig/sbuild/sbuild-chroot-block-device-base.h
++++ schroot-1.6.10/sbuild/sbuild-chroot-block-device-base.h
+@@ -65,7 +65,7 @@
+      *
+      * @param device the device.
+      */
+-    void
++    virtual void
+     set_device (std::string const& device);
+ 
+     virtual std::string
+Index: schroot-1.6.10/config.h.cmake
+===================================================================
+--- schroot-1.6.10.orig/config.h.cmake
++++ schroot-1.6.10/config.h.cmake
+@@ -140,6 +140,9 @@
+ /* Set if the lvm-snapshot chroot type is present */
+ #cmakedefine SBUILD_FEATURE_LVMSNAP 1
+ 
++/* Set if the zfs-snapshot chroot type is present */
++#cmakedefine SBUILD_FEATURE_ZFSSNAP 1
++
+ /* Set if PAM support is available */
+ #cmakedefine SBUILD_FEATURE_PAM 1
+ 
+Index: schroot-1.6.10/sbuild/sbuild-chroot-facet-session-clonable.cc
+===================================================================
+--- schroot-1.6.10.orig/sbuild/sbuild-chroot-facet-session-clonable.cc
++++ schroot-1.6.10/sbuild/sbuild-chroot-facet-session-clonable.cc
+@@ -36,6 +36,9 @@
+ #ifdef SBUILD_FEATURE_BTRFSSNAP
+ #include "sbuild-chroot-btrfs-snapshot.h"
+ #endif // SBUILD_FEATURE_BTRFSSNAP
++#ifdef SBUILD_FEATURE_ZFSSNAP
++#include "sbuild-chroot-zfs-snapshot.h"
++#endif // SBUILD_FEATURE_ZFSSNAP
+ #ifdef SBUILD_FEATURE_UNION
+ #include "sbuild-chroot-facet-union.h"
+ #endif // SBUILD_FEATURE_UNION
+@@ -194,6 +197,20 @@
+     }
+ #endif // SBUILD_FEATURE_BTRFSSNAP
+ 
++#ifdef SBUILD_FEATURE_ZFSSNAP
++  /* ZFS devices need the snapshot device name specifying. */
++  std::shared_ptr<chroot_zfs_snapshot> zfs_snapshot(std::dynamic_pointer_cast<chroot_zfs_snapshot>(clone));
++  if (zfs_snapshot && !zfs_snapshot->get_device().empty())
++    {
++      std::string snapname(zfs_snapshot->get_device());
++      snapname += "@" + clone->get_name();
++      zfs_snapshot->set_snapshot_name(snapname);
++
++      std::string clonename(zfs_snapshot->get_device());
++      clonename += "/schroot-" + clone->get_name();
++      zfs_snapshot->set_clone_name(clonename);
++    }
++#endif // SBUILD_FEATURE_LVMSNAP
+ #ifdef SBUILD_FEATURE_UNION
+   // If the parent did not have a union facet, then neither should we.
+   chroot_facet_union::const_ptr pparentuni(parent.get_facet<chroot_facet_union>());
+Index: schroot-1.6.10/etc/schroot.conf
+===================================================================
+--- schroot-1.6.10.orig/etc/schroot.conf
++++ schroot-1.6.10/etc/schroot.conf
+@@ -37,6 +37,17 @@
+ #groups=root,sbuild
+ #root-groups=root,sbuild
+ #
++#[sid-znap]
++#type=zfs-snapshot
++#description=Debian sid ZFS snapshot
++#groups=sbuild,root
++#root-users=rleigh
++#root-groups=root,sbuild
++#source-root-users=rleigh
++#device=rpool/CHROOT/sid
++#mount-options=-o atime,sync,user_xattr
++#zfs-snapshot-options=--size 2G
++#
+ #[squeeze]
+ #description=Debian squeeze (stable) 32-bit
+ #directory=/srv/chroot/squeeze
+Index: schroot-1.6.10/man/schroot.conf.5.man
+===================================================================
+--- schroot-1.6.10.orig/man/schroot.conf.5.man
++++ schroot-1.6.10/man/schroot.conf.5.man
+@@ -46,7 +46,7 @@
+ \f[CBI]type=\fP\f[CI]type\fP
+ The type of the chroot.  Valid types are \[oq]plain\[cq], \[oq]directory\[cq],
+ \[oq]file\[cq], \[oq]loopback\[cq], \[oq]block\-device\[cq],
+-\[oq]btrfs\-snapshot\[cq] and \[oq]lvm\-snapshot\[cq].  If empty or omitted,
++\[oq]btrfs\-snapshot\[cq], \[oq]zfs\-snapshot\[cq] and \[oq]lvm\-snapshot\[cq].  If empty or omitted,
+ the default type is \[oq]plain\[cq].  Note that \[oq]plain\[cq] chroots do not
+ run setup scripts and mount filesystems; \[oq]directory\[cq] is recommended for
+ normal use (see \[lq]\fIPlain and directory chroots\fP\[rq], below).
+@@ -323,6 +323,20 @@
+ .TP
+ \f[CBI]btrfs\-snapshot\-directory=\fP\f[CI]directory\fP
+ The directory in which to store the snapshots of the above source subvolume.
++.SS ZFS snapshot chroots
++Chroots of type \[oq]zfs\-snapshot\[cq] are a ZFS clone created from an
++existing ZFS dataset.  A snapshot and clone will be created from this source
++subvolume on demand at the start of a session, and then the clone will be
++mounted.  At the end of the session, the clone will be unmounted and the
++clone and snapshot will be deleted.  This chroot type implements the
++\fBsource chroot\fP options (see \[lq]\fISource chroot options\fP\[rq],
++below).  Note that a corresponding source chroot (of type
++\[oq]directory\[cq]) will be created for each chroot of this type; this is
++for convenient access to the source volume. These additional options are
++also implemented:
++.TP
++\f[CBI]zfs\-snapshot\-options=\fP\f[CI]snapshot_options\fP
++Snapshot options.  These are additional options to pass to zfs snapshot.
+ .SS LVM snapshot chroots
+ Chroots of type \[oq]lvm\-snapshot\[cq] are a filesystem available on an LVM
+ logical volume (LV).  A snapshot LV will be created from this LV on demand, and
+Index: schroot-1.6.10/sbuild/sbuild-chroot.cc
+===================================================================
+--- schroot-1.6.10.orig/sbuild/sbuild-chroot.cc
++++ schroot-1.6.10/sbuild/sbuild-chroot.cc
+@@ -33,6 +33,9 @@
+ #ifdef SBUILD_FEATURE_LVMSNAP
+ #include "sbuild-chroot-lvm-snapshot.h"
+ #endif // SBUILD_FEATURE_LVMSNAP
++#ifdef SBUILD_FEATURE_ZFSSNAP
++#include "sbuild-chroot-zfs-snapshot.h"
++#endif // SBUILD_FEATURE_LVMSNAP
+ #ifdef SBUILD_FEATURE_BTRFSSNAP
+ #include "sbuild-chroot-btrfs-snapshot.h"
+ #endif // SBUILD_FEATURE_BTRFSSNAP
+@@ -193,6 +196,10 @@
+   else if (type == "lvm-snapshot")
+     new_chroot = new chroot_lvm_snapshot();
+ #endif // SBUILD_FEATURE_LVMSNAP
++#ifdef SBUILD_FEATURE_ZFSSNAP
++  else if (type == "zfs-snapshot")
++    new_chroot = new chroot_zfs_snapshot();
++#endif // SBUILD_FEATURE_LVMSNAP
+ #ifdef SBUILD_FEATURE_BTRFSSNAP
+   else if (type == "btrfs-snapshot")
+     new_chroot = new chroot_btrfs_snapshot();
+Index: schroot-1.6.10/etc/setup.d/CMakeLists.txt
+===================================================================
+--- schroot-1.6.10.orig/etc/setup.d/CMakeLists.txt
++++ schroot-1.6.10/etc/setup.d/CMakeLists.txt
+@@ -27,6 +27,7 @@
+     05btrfs
+     05lvm
+     05union
++    05zfs
+     10mount
+     15binfmt
+     15killprocs
+Index: schroot-1.6.10/etc/setup.d/10mount
+===================================================================
+--- schroot-1.6.10.orig/etc/setup.d/10mount
++++ schroot-1.6.10/etc/setup.d/10mount
+@@ -156,6 +156,7 @@
+     || [ "$CHROOT_TYPE" = "loopback" ] \
+     || [ "$CHROOT_TYPE" = "block-device" ] \
+     || [ "$CHROOT_TYPE" = "lvm-snapshot" ] \
++    || [ "$CHROOT_TYPE" = "zfs-snapshot" ] \
+     || [ "$CHROOT_TYPE" = "btrfs-snapshot" ]; then
+ 
+     if [ "${CHROOT_UNION_TYPE:-none}" != "none" ]; then
+@@ -211,6 +212,8 @@
+                     fi
+                     ;;
+             esac
++        elif [ "$CHROOT_TYPE" = "zfs-snapshot" ]; then
++            CHROOT_MOUNT_OPTIONS="-t zfs $CHROOT_MOUNT_OPTIONS"
+         fi
+ 
+         if [ ! -d "$CHROOT_MOUNT_LOCATION" ]; then
diff -Nru schroot-1.6.10/debian/rules schroot-1.6.10/debian/rules
--- schroot-1.6.10/debian/rules	2018-09-01 02:25:59.000000000 -0500
+++ schroot-1.6.10/debian/rules	2019-12-30 23:58:24.000000000 -0600
@@ -10,9 +10,11 @@
 ifneq ($(DEB_HOST_ARCH_OS),linux)
 	LVMSNAP_OPTIONS = -Dlvm-snapshot=OFF
 	BTRFSSNAP_OPTIONS = -Dbtrfs-snapshot=OFF
+	ZFSSNAP_OPTIONS = -Dzfs-snapshot=OFF
 else
 	LVMSNAP_OPTIONS = -Dlvm-snapshot=ON
 	BTRFSSNAP_OPTIONS = -Dbtrfs-snapshot=ON
+	ZFSSNAP_OPTIONS = -Dzfs-snapshot=ON
 endif
 
 ifneq ($(DEB_HOST_ARCH_OS),kfreebsd)
@@ -56,10 +58,11 @@
 	        -DSCHROOT_LIBEXEC_DIR=/$(LIBDIR)/schroot \
 	        -Ddebug=OFF -Ddchroot=OFF -Ddchroot-dsa=OFF \
 	        -Dbash_completion_dir=/usr/share/bash-completion/completions \
-	        $(LVMSNAP_OPTIONS) $(BTRFSSNAP_OPTIONS) \
+	        $(LVMSNAP_OPTIONS) $(BTRFSSNAP_OPTIONS) $(ZFSSNAP_OPTIONS) \
 	        -DBTRFS_EXECUTABLE=/sbin/btrfs \
 	        -DLVCREATE_EXECUTABLE=/sbin/lvcreate \
 	        -DLVREMOVE_EXECUTABLE=/sbin/lvremove \
+	        -DZFS_EXECUTABLE=/sbin/zfs \
 	        $(CURDIR)
 	dh_testdir
 

Reply to: