zfs-program.8 (21299B)
- .\"
- .\" This file and its contents are supplied under the terms of the
- .\" Common Development and Distribution License ("CDDL"), version 1.0.
- .\" You may only use this file in accordance with the terms of version
- .\" 1.0 of the CDDL.
- .\"
- .\" A full copy of the text of the CDDL should have accompanied this
- .\" source. A copy of the CDDL is also available via the Internet at
- .\" http://www.illumos.org/license/CDDL.
- .\"
- .\" Copyright (c) 2016, 2019 by Delphix. All Rights Reserved.
- .\" Copyright (c) 2019, 2020 by Christian Schwarz. All Rights Reserved.
- .\" Copyright 2020 Joyent, Inc.
- .\"
- .Dd May 27, 2021
- .Dt ZFS-PROGRAM 8
- .Os
- .
- .Sh NAME
- .Nm zfs-program
- .Nd execute ZFS channel programs
- .Sh SYNOPSIS
- .Nm zfs
- .Cm program
- .Op Fl jn
- .Op Fl t Ar instruction-limit
- .Op Fl m Ar memory-limit
- .Ar pool
- .Ar script
- .Op Ar script arguments
- .
- .Sh DESCRIPTION
- The ZFS channel program interface allows ZFS administrative operations to be
- run programmatically as a Lua script.
- The entire script is executed atomically, with no other administrative
- operations taking effect concurrently.
- A library of ZFS calls is made available to channel program scripts.
- Channel programs may only be run with root privileges.
- .Pp
- A modified version of the Lua 5.2 interpreter is used to run channel program
- scripts.
- The Lua 5.2 manual can be found at
- .Lk http://www.lua.org/manual/5.2/
- .Pp
- The channel program given by
- .Ar script
- will be run on
- .Ar pool ,
- and any attempts to access or modify other pools will cause an error.
- .
- .Sh OPTIONS
- .Bl -tag -width "-t"
- .It Fl j , -json
- Display channel program output in JSON format.
- When this flag is specified and standard output is empty -
- channel program encountered an error.
- The details of such an error will be printed to standard error in plain text.
- .It Fl n
- Executes a read-only channel program, which runs faster.
- The program cannot change on-disk state by calling functions from the
- zfs.sync submodule.
- The program can be used to gather information such as properties and
- determining if changes would succeed (zfs.check.*).
- Without this flag, all pending changes must be synced to disk before a
- channel program can complete.
- .It Fl t Ar instruction-limit
- Limit the number of Lua instructions to execute.
- If a channel program executes more than the specified number of instructions,
- it will be stopped and an error will be returned.
- The default limit is 10 million instructions, and it can be set to a maximum of
- 100 million instructions.
- .It Fl m Ar memory-limit
- Memory limit, in bytes.
- If a channel program attempts to allocate more memory than the given limit, it
- will be stopped and an error returned.
- The default memory limit is 10 MiB, and can be set to a maximum of 100 MiB.
- .El
- .Pp
- All remaining argument strings will be passed directly to the Lua script as
- described in the
- .Sx LUA INTERFACE
- section below.
- .
- .Sh LUA INTERFACE
- A channel program can be invoked either from the command line, or via a library
- call to
- .Fn lzc_channel_program .
- .
- .Ss Arguments
- Arguments passed to the channel program are converted to a Lua table.
- If invoked from the command line, extra arguments to the Lua script will be
- accessible as an array stored in the argument table with the key 'argv':
- .Bd -literal -compact -offset indent
- args = ...
- argv = args["argv"]
- -- argv == {1="arg1", 2="arg2", ...}
- .Ed
- .Pp
- If invoked from the libzfs interface, an arbitrary argument list can be
- passed to the channel program, which is accessible via the same
- .Qq Li ...
- syntax in Lua:
- .Bd -literal -compact -offset indent
- args = ...
- -- args == {"foo"="bar", "baz"={...}, ...}
- .Ed
- .Pp
- Note that because Lua arrays are 1-indexed, arrays passed to Lua from the
- libzfs interface will have their indices incremented by 1.
- That is, the element
- in
- .Va arr[0]
- in a C array passed to a channel program will be stored in
- .Va arr[1]
- when accessed from Lua.
- .
- .Ss Return Values
- Lua return statements take the form:
- .Dl return ret0, ret1, ret2, ...
- .Pp
- Return statements returning multiple values are permitted internally in a
- channel program script, but attempting to return more than one value from the
- top level of the channel program is not permitted and will throw an error.
- However, tables containing multiple values can still be returned.
- If invoked from the command line, a return statement:
- .Bd -literal -compact -offset indent
- a = {foo="bar", baz=2}
- return a
- .Ed
- .Pp
- Will be output formatted as:
- .Bd -literal -compact -offset indent
- Channel program fully executed with return value:
- return:
- baz: 2
- foo: 'bar'
- .Ed
- .
- .Ss Fatal Errors
- If the channel program encounters a fatal error while running, a non-zero exit
- status will be returned.
- If more information about the error is available, a singleton list will be
- returned detailing the error:
- .Dl error: \&"error string, including Lua stack trace"
- .Pp
- If a fatal error is returned, the channel program may have not executed at all,
- may have partially executed, or may have fully executed but failed to pass a
- return value back to userland.
- .Pp
- If the channel program exhausts an instruction or memory limit, a fatal error
- will be generated and the program will be stopped, leaving the program partially
- executed.
- No attempt is made to reverse or undo any operations already performed.
- Note that because both the instruction count and amount of memory used by a
- channel program are deterministic when run against the same inputs and
- filesystem state, as long as a channel program has run successfully once, you
- can guarantee that it will finish successfully against a similar size system.
- .Pp
- If a channel program attempts to return too large a value, the program will
- fully execute but exit with a nonzero status code and no return value.
- .Pp
- .Em Note :
- ZFS API functions do not generate Fatal Errors when correctly invoked, they
- return an error code and the channel program continues executing.
- See the
- .Sx ZFS API
- section below for function-specific details on error return codes.
- .
- .Ss Lua to C Value Conversion
- When invoking a channel program via the libzfs interface, it is necessary to
- translate arguments and return values from Lua values to their C equivalents,
- and vice-versa.
- .Pp
- There is a correspondence between nvlist values in C and Lua tables.
- A Lua table which is returned from the channel program will be recursively
- converted to an nvlist, with table values converted to their natural
- equivalents:
- .TS
- cw3 l c l .
- string -> string
- number -> int64
- boolean -> boolean_value
- nil -> boolean (no value)
- table -> nvlist
- .TE
- .Pp
- Likewise, table keys are replaced by string equivalents as follows:
- .TS
- cw3 l c l .
- string -> no change
- number -> signed decimal string ("%lld")
- boolean -> "true" | "false"
- .TE
- .Pp
- Any collision of table key strings (for example, the string "true" and a
- true boolean value) will cause a fatal error.
- .Pp
- Lua numbers are represented internally as signed 64-bit integers.
- .
- .Sh LUA STANDARD LIBRARY
- The following Lua built-in base library functions are available:
- .TS
- cw3 l l l l .
- assert rawlen collectgarbage rawget
- error rawset getmetatable select
- ipairs setmetatable next tonumber
- pairs tostring rawequal type
- .TE
- .Pp
- All functions in the
- .Em coroutine ,
- .Em string ,
- and
- .Em table
- built-in submodules are also available.
- A complete list and documentation of these modules is available in the Lua
- manual.
- .Pp
- The following functions base library functions have been disabled and are
- not available for use in channel programs:
- .TS
- cw3 l l l l l l .
- dofile loadfile load pcall print xpcall
- .TE
- .
- .Sh ZFS API
- .
- .Ss Function Arguments
- Each API function takes a fixed set of required positional arguments and
- optional keyword arguments.
- For example, the destroy function takes a single positional string argument
- (the name of the dataset to destroy) and an optional "defer" keyword boolean
- argument.
- When using parentheses to specify the arguments to a Lua function, only
- positional arguments can be used:
- .Dl Sy zfs.sync.destroy Ns Pq \&"rpool@snap"
- .Pp
- To use keyword arguments, functions must be called with a single argument that
- is a Lua table containing entries mapping integers to positional arguments and
- strings to keyword arguments:
- .Dl Sy zfs.sync.destroy Ns Pq {1="rpool@snap", defer=true}
- .Pp
- The Lua language allows curly braces to be used in place of parenthesis as
- syntactic sugar for this calling convention:
- .Dl Sy zfs.sync.snapshot Ns {"rpool@snap", defer=true}
- .
- .Ss Function Return Values
- If an API function succeeds, it returns 0.
- If it fails, it returns an error code and the channel program continues
- executing.
- API functions do not generate Fatal Errors except in the case of an
- unrecoverable internal file system error.
- .Pp
- In addition to returning an error code, some functions also return extra
- details describing what caused the error.
- This extra description is given as a second return value, and will always be a
- Lua table, or Nil if no error details were returned.
- Different keys will exist in the error details table depending on the function
- and error case.
- Any such function may be called expecting a single return value:
- .Dl errno = Sy zfs.sync.promote Ns Pq dataset
- .Pp
- Or, the error details can be retrieved:
- .Bd -literal -compact -offset indent
- .No errno, details = Sy zfs.sync.promote Ns Pq dataset
- if (errno == EEXIST) then
- assert(details ~= Nil)
- list_of_conflicting_snapshots = details
- end
- .Ed
- .Pp
- The following global aliases for API function error return codes are defined
- for use in channel programs:
- .TS
- cw3 l l l l l l l .
- EPERM ECHILD ENODEV ENOSPC ENOENT EAGAIN ENOTDIR
- ESPIPE ESRCH ENOMEM EISDIR EROFS EINTR EACCES
- EINVAL EMLINK EIO EFAULT ENFILE EPIPE ENXIO
- ENOTBLK EMFILE EDOM E2BIG EBUSY ENOTTY ERANGE
- ENOEXEC EEXIST ETXTBSY EDQUOT EBADF EXDEV EFBIG
- .TE
- .
- .Ss API Functions
- For detailed descriptions of the exact behavior of any ZFS administrative
- operations, see the main
- .Xr zfs 8
- manual page.
- .Bl -tag -width "xx"
- .It Fn zfs.debug msg
- Record a debug message in the zfs_dbgmsg log.
- A log of these messages can be printed via mdb's "::zfs_dbgmsg" command, or
- can be monitored live by running
- .Dl dtrace -n 'zfs-dbgmsg{trace(stringof(arg0))}'
- .Pp
- .Bl -tag -compact -width "property (string)"
- .It Ar msg Pq string
- Debug message to be printed.
- .El
- .It Fn zfs.exists dataset
- Returns true if the given dataset exists, or false if it doesn't.
- A fatal error will be thrown if the dataset is not in the target pool.
- That is, in a channel program running on rpool,
- .Sy zfs.exists Ns Pq \&"rpool/nonexistent_fs"
- returns false, but
- .Sy zfs.exists Ns Pq \&"somepool/fs_that_may_exist"
- will error.
- .Pp
- .Bl -tag -compact -width "property (string)"
- .It Ar dataset Pq string
- Dataset to check for existence.
- Must be in the target pool.
- .El
- .It Fn zfs.get_prop dataset property
- Returns two values.
- First, a string, number or table containing the property value for the given
- dataset.
- Second, a string containing the source of the property (i.e. the name of the
- dataset in which it was set or nil if it is readonly).
- Throws a Lua error if the dataset is invalid or the property doesn't exist.
- Note that Lua only supports int64 number types whereas ZFS number properties
- are uint64.
- This means very large values (like GUIDs) may wrap around and appear negative.
- .Pp
- .Bl -tag -compact -width "property (string)"
- .It Ar dataset Pq string
- Filesystem or snapshot path to retrieve properties from.
- .It Ar property Pq string
- Name of property to retrieve.
- All filesystem, snapshot and volume properties are supported except for
- .Sy mounted
- and
- .Sy iscsioptions .
- Also supports the
- .Sy written@ Ns Ar snap
- and
- .Sy written# Ns Ar bookmark
- properties and the
- .Ao Sy user Ns | Ns Sy group Ac Ns Ao Sy quota Ns | Ns Sy used Ac Ns Sy @ Ns Ar id
- properties, though the id must be in numeric form.
- .El
- .El
- .Bl -tag -width "xx"
- .It Sy zfs.sync submodule
- The sync submodule contains functions that modify the on-disk state.
- They are executed in "syncing context".
- .Pp
- The available sync submodule functions are as follows:
- .Bl -tag -width "xx"
- .It Sy zfs.sync.destroy Ns Pq Ar dataset , Op Ar defer Ns = Ns Sy true Ns | Ns Sy false
- Destroy the given dataset.
- Returns 0 on successful destroy, or a nonzero error code if the dataset could
- not be destroyed (for example, if the dataset has any active children or
- clones).
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar dataset Pq string
- Filesystem or snapshot to be destroyed.
- .It Op Ar defer Pq boolean
- Valid only for destroying snapshots.
- If set to true, and the snapshot has holds or clones, allows the snapshot to be
- marked for deferred deletion rather than failing.
- .El
- .It Fn zfs.sync.inherit dataset property
- Clears the specified property in the given dataset, causing it to be inherited
- from an ancestor, or restored to the default if no ancestor property is set.
- The
- .Nm zfs Cm inherit Fl S
- option has not been implemented.
- Returns 0 on success, or a nonzero error code if the property could not be
- cleared.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar dataset Pq string
- Filesystem or snapshot containing the property to clear.
- .It Ar property Pq string
- The property to clear.
- Allowed properties are the same as those for the
- .Nm zfs Cm inherit
- command.
- .El
- .It Fn zfs.sync.promote dataset
- Promote the given clone to a filesystem.
- Returns 0 on successful promotion, or a nonzero error code otherwise.
- If EEXIST is returned, the second return value will be an array of the clone's
- snapshots whose names collide with snapshots of the parent filesystem.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar dataset Pq string
- Clone to be promoted.
- .El
- .It Fn zfs.sync.rollback filesystem
- Rollback to the previous snapshot for a dataset.
- Returns 0 on successful rollback, or a nonzero error code otherwise.
- Rollbacks can be performed on filesystems or zvols, but not on snapshots
- or mounted datasets.
- EBUSY is returned in the case where the filesystem is mounted.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar filesystem Pq string
- Filesystem to rollback.
- .El
- .It Fn zfs.sync.set_prop dataset property value
- Sets the given property on a dataset.
- Currently only user properties are supported.
- Returns 0 if the property was set, or a nonzero error code otherwise.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar dataset Pq string
- The dataset where the property will be set.
- .It Ar property Pq string
- The property to set.
- .It Ar value Pq string
- The value of the property to be set.
- .El
- .It Fn zfs.sync.snapshot dataset
- Create a snapshot of a filesystem.
- Returns 0 if the snapshot was successfully created,
- and a nonzero error code otherwise.
- .Pp
- Note: Taking a snapshot will fail on any pool older than legacy version 27.
- To enable taking snapshots from ZCP scripts, the pool must be upgraded.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar dataset Pq string
- Name of snapshot to create.
- .El
- .It Fn zfs.sync.rename_snapshot dataset oldsnapname newsnapname
- Rename a snapshot of a filesystem or a volume.
- Returns 0 if the snapshot was successfully renamed,
- and a nonzero error code otherwise.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar dataset Pq string
- Name of the snapshot's parent dataset.
- .It Ar oldsnapname Pq string
- Original name of the snapshot.
- .It Ar newsnapname Pq string
- New name of the snapshot.
- .El
- .It Fn zfs.sync.bookmark source newbookmark
- Create a bookmark of an existing source snapshot or bookmark.
- Returns 0 if the new bookmark was successfully created,
- and a nonzero error code otherwise.
- .Pp
- Note: Bookmarking requires the corresponding pool feature to be enabled.
- .Pp
- .Bl -tag -compact -width "newbookmark (string)"
- .It Ar source Pq string
- Full name of the existing snapshot or bookmark.
- .It Ar newbookmark Pq string
- Full name of the new bookmark.
- .El
- .El
- .It Sy zfs.check submodule
- For each function in the
- .Sy zfs.sync
- submodule, there is a corresponding
- .Sy zfs.check
- function which performs a "dry run" of the same operation.
- Each takes the same arguments as its
- .Sy zfs.sync
- counterpart and returns 0 if the operation would succeed,
- or a non-zero error code if it would fail, along with any other error details.
- That is, each has the same behavior as the corresponding sync function except
- for actually executing the requested change.
- For example,
- .Fn zfs.check.destroy \&"fs"
- returns 0 if
- .Fn zfs.sync.destroy \&"fs"
- would successfully destroy the dataset.
- .Pp
- The available
- .Sy zfs.check
- functions are:
- .Bl -tag -compact -width "xx"
- .It Sy zfs.check.destroy Ns Pq Ar dataset , Op Ar defer Ns = Ns Sy true Ns | Ns Sy false
- .It Fn zfs.check.promote dataset
- .It Fn zfs.check.rollback filesystem
- .It Fn zfs.check.set_property dataset property value
- .It Fn zfs.check.snapshot dataset
- .El
- .It Sy zfs.list submodule
- The zfs.list submodule provides functions for iterating over datasets and
- properties.
- Rather than returning tables, these functions act as Lua iterators, and are
- generally used as follows:
- .Bd -literal -compact -offset indent
- .No for child in Fn zfs.list.children \&"rpool" No do
- ...
- end
- .Ed
- .Pp
- The available
- .Sy zfs.list
- functions are:
- .Bl -tag -width "xx"
- .It Fn zfs.list.clones snapshot
- Iterate through all clones of the given snapshot.
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar snapshot Pq string
- Must be a valid snapshot path in the current pool.
- .El
- .It Fn zfs.list.snapshots dataset
- Iterate through all snapshots of the given dataset.
- Each snapshot is returned as a string containing the full dataset name,
- e.g. "pool/fs@snap".
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar dataset Pq string
- Must be a valid filesystem or volume.
- .El
- .It Fn zfs.list.children dataset
- Iterate through all direct children of the given dataset.
- Each child is returned as a string containing the full dataset name,
- e.g. "pool/fs/child".
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar dataset Pq string
- Must be a valid filesystem or volume.
- .El
- .It Fn zfs.list.bookmarks dataset
- Iterate through all bookmarks of the given dataset.
- Each bookmark is returned as a string containing the full dataset name,
- e.g. "pool/fs#bookmark".
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar dataset Pq string
- Must be a valid filesystem or volume.
- .El
- .It Fn zfs.list.holds snapshot
- Iterate through all user holds on the given snapshot.
- Each hold is returned
- as a pair of the hold's tag and the timestamp (in seconds since the epoch) at
- which it was created.
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar snapshot Pq string
- Must be a valid snapshot.
- .El
- .It Fn zfs.list.properties dataset
- An alias for zfs.list.user_properties (see relevant entry).
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar dataset Pq string
- Must be a valid filesystem, snapshot, or volume.
- .El
- .It Fn zfs.list.user_properties dataset
- Iterate through all user properties for the given dataset.
- For each step of the iteration, output the property name, its value,
- and its source.
- Throws a Lua error if the dataset is invalid.
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar dataset Pq string
- Must be a valid filesystem, snapshot, or volume.
- .El
- .It Fn zfs.list.system_properties dataset
- Returns an array of strings, the names of the valid system (non-user defined)
- properties for the given dataset.
- Throws a Lua error if the dataset is invalid.
- .Pp
- .Bl -tag -compact -width "snapshot (string)"
- .It Ar dataset Pq string
- Must be a valid filesystem, snapshot or volume.
- .El
- .El
- .El
- .
- .Sh EXAMPLES
- .
- .Ss Example 1
- The following channel program recursively destroys a filesystem and all its
- snapshots and children in a naive manner.
- Note that this does not involve any error handling or reporting.
- .Bd -literal -offset indent
- function destroy_recursive(root)
- for child in zfs.list.children(root) do
- destroy_recursive(child)
- end
- for snap in zfs.list.snapshots(root) do
- zfs.sync.destroy(snap)
- end
- zfs.sync.destroy(root)
- end
- destroy_recursive("pool/somefs")
- .Ed
- .
- .Ss Example 2
- A more verbose and robust version of the same channel program, which
- properly detects and reports errors, and also takes the dataset to destroy
- as a command line argument, would be as follows:
- .Bd -literal -offset indent
- succeeded = {}
- failed = {}
- function destroy_recursive(root)
- for child in zfs.list.children(root) do
- destroy_recursive(child)
- end
- for snap in zfs.list.snapshots(root) do
- err = zfs.sync.destroy(snap)
- if (err ~= 0) then
- failed[snap] = err
- else
- succeeded[snap] = err
- end
- end
- err = zfs.sync.destroy(root)
- if (err ~= 0) then
- failed[root] = err
- else
- succeeded[root] = err
- end
- end
- args = ...
- argv = args["argv"]
- destroy_recursive(argv[1])
- results = {}
- results["succeeded"] = succeeded
- results["failed"] = failed
- return results
- .Ed
- .
- .Ss Example 3
- The following function performs a forced promote operation by attempting to
- promote the given clone and destroying any conflicting snapshots.
- .Bd -literal -offset indent
- function force_promote(ds)
- errno, details = zfs.check.promote(ds)
- if (errno == EEXIST) then
- assert(details ~= Nil)
- for i, snap in ipairs(details) do
- zfs.sync.destroy(ds .. "@" .. snap)
- end
- elseif (errno ~= 0) then
- return errno
- end
- return zfs.sync.promote(ds)
- end
- .Ed