ZFS: dedup toggle per pool and dedup option for new datasets
build / build (push) Successful in 1m4s
build / build (push) Successful in 1m4s
Pool cards show the dedup ratio and can set dedup=on|off on the pool root dataset (inherited by children); the new-dataset form gets a dedup option. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Package zfsadm performs the few mutating ZFS operations the UI offers
|
||||
// (create / destroy datasets). Commands go through a Runner so they can be
|
||||
// (create / destroy datasets, toggle pool dedup). Commands go through a Runner so they can be
|
||||
// executed on the host via systemd-run: nasmon runs in a sandboxed mount
|
||||
// namespace (ProtectSystem=strict), where a plain "zfs create" would mount the
|
||||
// new dataset only inside the service and leave the host without it.
|
||||
@@ -59,6 +59,7 @@ func (a *Admin) ctx() (context.Context, context.CancelFunc) {
|
||||
// CreateOpts are the user-visible knobs of "zfs create".
|
||||
type CreateOpts struct {
|
||||
Compression string // "", lz4, zstd, off ("" = inherit)
|
||||
Dedup string // "", on, off ("" = inherit)
|
||||
Quota string // "", or a size like 100G / 1.5T
|
||||
Owner string // uid:gid applied to the mountpoint; "" = leave root
|
||||
}
|
||||
@@ -71,6 +72,9 @@ func (a *Admin) Create(full string, o CreateOpts) error {
|
||||
if err := ValidateCompression(o.Compression); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ValidateDedup(o.Dedup); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ValidateSize(o.Quota); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -81,6 +85,9 @@ func (a *Admin) Create(full string, o CreateOpts) error {
|
||||
if o.Compression != "" {
|
||||
args = append(args, "-o", "compression="+o.Compression)
|
||||
}
|
||||
if o.Dedup != "" {
|
||||
args = append(args, "-o", "dedup="+o.Dedup)
|
||||
}
|
||||
if o.Quota != "" {
|
||||
args = append(args, "-o", "quota="+o.Quota)
|
||||
}
|
||||
@@ -106,6 +113,25 @@ func (a *Admin) Create(full string, o CreateOpts) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDedup sets the dedup property (on/off) on the root dataset of pool, so it
|
||||
// applies to every dataset that does not override it. Only newly written
|
||||
// blocks are affected either way.
|
||||
func (a *Admin) SetDedup(pool, value string) error {
|
||||
if err := ValidateFullName(pool); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(pool, "/") {
|
||||
return errors.New("dedup is set on the pool root dataset only")
|
||||
}
|
||||
if value != "on" && value != "off" {
|
||||
return errors.New("dedup must be on or off")
|
||||
}
|
||||
ctx, cancel := a.ctx()
|
||||
defer cancel()
|
||||
_, err := a.Run(ctx, "zfs", "set", "dedup="+value, pool)
|
||||
return err
|
||||
}
|
||||
|
||||
// EmptyRefer is the upper bound of "referenced" bytes for a dataset we still
|
||||
// consider empty (a fresh dataset refers ~96-128 KiB of metadata).
|
||||
const EmptyRefer = 1 << 20
|
||||
@@ -206,6 +232,14 @@ func ValidateCompression(s string) error {
|
||||
return errors.New("compression must be inherit, lz4, zstd or off")
|
||||
}
|
||||
|
||||
func ValidateDedup(s string) error {
|
||||
switch s {
|
||||
case "", "on", "off":
|
||||
return nil
|
||||
}
|
||||
return errors.New("dedup must be inherit, on or off")
|
||||
}
|
||||
|
||||
func ValidateOwner(s string) error {
|
||||
if s == "" || reOwner.MatchString(s) {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user