xref: /freebsd/sys/contrib/openzfs/man/man8/zfs-program.8 (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
1.\"
2.\" This file and its contents are supplied under the terms of the
3.\" Common Development and Distribution License ("CDDL"), version 1.0.
4.\" You may only use this file in accordance with the terms of version
5.\" 1.0 of the CDDL.
6.\"
7.\" A full copy of the text of the CDDL should have accompanied this
8.\" source.  A copy of the CDDL is also available via the Internet at
9.\" http://www.illumos.org/license/CDDL.
10.\"
11.\" Copyright (c) 2016, 2019 by Delphix. All Rights Reserved.
12.\" Copyright (c) 2019, 2020 by Christian Schwarz. All Rights Reserved.
13.\" Copyright 2020 Joyent, Inc.
14.\"
15.Dd May 27, 2021
16.Dt ZFS-PROGRAM 8
17.Os
18.
19.Sh NAME
20.Nm zfs-program
21.Nd execute ZFS channel programs
22.Sh SYNOPSIS
23.Nm zfs
24.Cm program
25.Op Fl jn
26.Op Fl t Ar instruction-limit
27.Op Fl m Ar memory-limit
28.Ar pool
29.Ar script
30.Op Ar script arguments
31.
32.Sh DESCRIPTION
33The ZFS channel program interface allows ZFS administrative operations to be
34run programmatically as a Lua script.
35The entire script is executed atomically, with no other administrative
36operations taking effect concurrently.
37A library of ZFS calls is made available to channel program scripts.
38Channel programs may only be run with root privileges.
39.Pp
40A modified version of the Lua 5.2 interpreter is used to run channel program
41scripts.
42The Lua 5.2 manual can be found at
43.Lk http://www.lua.org/manual/5.2/
44.Pp
45The channel program given by
46.Ar script
47will be run on
48.Ar pool ,
49and any attempts to access or modify other pools will cause an error.
50.
51.Sh OPTIONS
52.Bl -tag -width "-t"
53.It Fl j
54Display channel program output in JSON format.
55When this flag is specified and standard output is empty -
56channel program encountered an error.
57The details of such an error will be printed to standard error in plain text.
58.It Fl n
59Executes a read-only channel program, which runs faster.
60The program cannot change on-disk state by calling functions from the
61zfs.sync submodule.
62The program can be used to gather information such as properties and
63determining if changes would succeed (zfs.check.*).
64Without this flag, all pending changes must be synced to disk before a
65channel program can complete.
66.It Fl t Ar instruction-limit
67Limit the number of Lua instructions to execute.
68If a channel program executes more than the specified number of instructions,
69it will be stopped and an error will be returned.
70The default limit is 10 million instructions, and it can be set to a maximum of
71100 million instructions.
72.It Fl m Ar memory-limit
73Memory limit, in bytes.
74If a channel program attempts to allocate more memory than the given limit, it
75will be stopped and an error returned.
76The default memory limit is 10 MB, and can be set to a maximum of 100 MB.
77.El
78.Pp
79All remaining argument strings will be passed directly to the Lua script as
80described in the
81.Sx LUA INTERFACE
82section below.
83.
84.Sh LUA INTERFACE
85A channel program can be invoked either from the command line, or via a library
86call to
87.Fn lzc_channel_program .
88.
89.Ss Arguments
90Arguments passed to the channel program are converted to a Lua table.
91If invoked from the command line, extra arguments to the Lua script will be
92accessible as an array stored in the argument table with the key 'argv':
93.Bd -literal -compact -offset indent
94args = ...
95argv = args["argv"]
96-- argv == {1="arg1", 2="arg2", ...}
97.Ed
98.Pp
99If invoked from the libZFS interface, an arbitrary argument list can be
100passed to the channel program, which is accessible via the same
101"..." syntax in Lua:
102.Bd -literal -compact -offset indent
103args = ...
104-- args == {"foo"="bar", "baz"={...}, ...}
105.Ed
106.Pp
107Note that because Lua arrays are 1-indexed, arrays passed to Lua from the
108libZFS interface will have their indices incremented by 1.
109That is, the element
110in
111.Va arr[0]
112in a C array passed to a channel program will be stored in
113.Va arr[1]
114when accessed from Lua.
115.
116.Ss Return Values
117Lua return statements take the form:
118.Dl return ret0, ret1, ret2, ...
119.Pp
120Return statements returning multiple values are permitted internally in a
121channel program script, but attempting to return more than one value from the
122top level of the channel program is not permitted and will throw an error.
123However, tables containing multiple values can still be returned.
124If invoked from the command line, a return statement:
125.Bd -literal -compact -offset indent
126a = {foo="bar", baz=2}
127return a
128.Ed
129.Pp
130Will be output formatted as:
131.Bd -literal -compact -offset indent
132Channel program fully executed with return value:
133    return:
134        baz: 2
135        foo: 'bar'
136.Ed
137.
138.Ss Fatal Errors
139If the channel program encounters a fatal error while running, a non-zero exit
140status will be returned.
141If more information about the error is available, a singleton list will be
142returned detailing the error:
143.Dl error: \&"error string, including Lua stack trace"
144.Pp
145If a fatal error is returned, the channel program may have not executed at all,
146may have partially executed, or may have fully executed but failed to pass a
147return value back to userland.
148.Pp
149If the channel program exhausts an instruction or memory limit, a fatal error
150will be generated and the program will be stopped, leaving the program partially
151executed.
152No attempt is made to reverse or undo any operations already performed.
153Note that because both the instruction count and amount of memory used by a
154channel program are deterministic when run against the same inputs and
155filesystem state, as long as a channel program has run successfully once, you
156can guarantee that it will finish successfully against a similar size system.
157.Pp
158If a channel program attempts to return too large a value, the program will
159fully execute but exit with a nonzero status code and no return value.
160.Pp
161.Em Note :
162ZFS API functions do not generate Fatal Errors when correctly invoked, they
163return an error code and the channel program continues executing.
164See the
165.Sx ZFS API
166section below for function-specific details on error return codes.
167.
168.Ss Lua to C Value Conversion
169When invoking a channel program via the libZFS interface, it is necessary to
170translate arguments and return values from Lua values to their C equivalents,
171and vice-versa.
172.Pp
173There is a correspondence between nvlist values in C and Lua tables.
174A Lua table which is returned from the channel program will be recursively
175converted to an nvlist, with table values converted to their natural
176equivalents:
177.TS
178cw3 l c l .
179	string	->	string
180	number	->	int64
181	boolean	->	boolean_value
182	nil	->	boolean (no value)
183	table	->	nvlist
184.TE
185.Pp
186Likewise, table keys are replaced by string equivalents as follows:
187.TS
188cw3 l c l .
189	string	->	no change
190	number	->	signed decimal string ("%lld")
191	boolean	->	"true" | "false"
192.TE
193.Pp
194Any collision of table key strings (for example, the string "true" and a
195true boolean value) will cause a fatal error.
196.Pp
197Lua numbers are represented internally as signed 64-bit integers.
198.
199.Sh LUA STANDARD LIBRARY
200The following Lua built-in base library functions are available:
201.TS
202cw3 l l l l .
203	assert	rawlen	collectgarbage	rawget
204	error	rawset	getmetatable	select
205	ipairs	setmetatable	next	tonumber
206	pairs	tostring	rawequal	type
207.TE
208.Pp
209All functions in the
210.Em coroutine ,
211.Em string ,
212and
213.Em table
214built-in submodules are also available.
215A complete list and documentation of these modules is available in the Lua
216manual.
217.Pp
218The following functions base library functions have been disabled and are
219not available for use in channel programs:
220.TS
221cw3 l l l l l l .
222	dofile	loadfile	load	pcall	print	xpcall
223.TE
224.
225.Sh ZFS API
226.
227.Ss Function Arguments
228Each API function takes a fixed set of required positional arguments and
229optional keyword arguments.
230For example, the destroy function takes a single positional string argument
231(the name of the dataset to destroy) and an optional "defer" keyword boolean
232argument.
233When using parentheses to specify the arguments to a Lua function, only
234positional arguments can be used:
235.Dl Sy zfs.sync.destroy Ns Pq \&"rpool@snap"
236.Pp
237To use keyword arguments, functions must be called with a single argument that
238is a Lua table containing entries mapping integers to positional arguments and
239strings to keyword arguments:
240.Dl Sy zfs.sync.destroy Ns Pq {1="rpool@snap", defer=true}
241.Pp
242The Lua language allows curly braces to be used in place of parenthesis as
243syntactic sugar for this calling convention:
244.Dl Sy zfs.sync.snapshot Ns {"rpool@snap", defer=true}
245.
246.Ss Function Return Values
247If an API function succeeds, it returns 0.
248If it fails, it returns an error code and the channel program continues
249executing.
250API functions do not generate Fatal Errors except in the case of an
251unrecoverable internal file system error.
252.Pp
253In addition to returning an error code, some functions also return extra
254details describing what caused the error.
255This extra description is given as a second return value, and will always be a
256Lua table, or Nil if no error details were returned.
257Different keys will exist in the error details table depending on the function
258and error case.
259Any such function may be called expecting a single return value:
260.Dl errno = Sy zfs.sync.promote Ns Pq dataset
261.Pp
262Or, the error details can be retrieved:
263.Bd -literal -compact -offset indent
264.No errno, details = Sy zfs.sync.promote Ns Pq dataset
265if (errno == EEXIST) then
266    assert(details ~= Nil)
267    list_of_conflicting_snapshots = details
268end
269.Ed
270.Pp
271The following global aliases for API function error return codes are defined
272for use in channel programs:
273.TS
274cw3 l l l l l l l .
275	EPERM	ECHILD	ENODEV	ENOSPC	ENOENT	EAGAIN	ENOTDIR
276	ESPIPE	ESRCH	ENOMEM	EISDIR	EROFS	EINTR	EACCES
277	EINVAL	EMLINK	EIO	EFAULT	ENFILE	EPIPE	ENXIO
278	ENOTBLK	EMFILE	EDOM	E2BIG	EBUSY	ENOTTY	ERANGE
279	ENOEXEC	EEXIST	ETXTBSY	EDQUOT	EBADF	EXDEV	EFBIG
280.TE
281.
282.Ss API Functions
283For detailed descriptions of the exact behavior of any ZFS administrative
284operations, see the main
285.Xr zfs 8
286manual page.
287.Bl -tag -width "xx"
288.It Fn zfs.debug msg
289Record a debug message in the zfs_dbgmsg log.
290A log of these messages can be printed via mdb's "::zfs_dbgmsg" command, or
291can be monitored live by running
292.Dl dtrace -n 'zfs-dbgmsg{trace(stringof(arg0))}'
293.Pp
294.Bl -tag -compact -width "property (string)"
295.It Ar msg Pq string
296Debug message to be printed.
297.El
298.It Fn zfs.exists dataset
299Returns true if the given dataset exists, or false if it doesn't.
300A fatal error will be thrown if the dataset is not in the target pool.
301That is, in a channel program running on rpool,
302.Sy zfs.exists Ns Pq \&"rpool/nonexistent_fs"
303returns false, but
304.Sy zfs.exists Ns Pq \&"somepool/fs_that_may_exist"
305will error.
306.Pp
307.Bl -tag -compact -width "property (string)"
308.It Ar dataset Pq string
309Dataset to check for existence.
310Must be in the target pool.
311.El
312.It Fn zfs.get_prop dataset property
313Returns two values.
314First, a string, number or table containing the property value for the given
315dataset.
316Second, a string containing the source of the property (i.e. the name of the
317dataset in which it was set or nil if it is readonly).
318Throws a Lua error if the dataset is invalid or the property doesn't exist.
319Note that Lua only supports int64 number types whereas ZFS number properties
320are uint64.
321This means very large values (like GUIDs) may wrap around and appear negative.
322.Pp
323.Bl -tag -compact -width "property (string)"
324.It Ar dataset Pq string
325Filesystem or snapshot path to retrieve properties from.
326.It Ar property Pq string
327Name of property to retrieve.
328All filesystem, snapshot and volume properties are supported except for
329.Sy mounted
330and
331.Sy iscsioptions .
332Also supports the
333.Sy written@ Ns Ar snap
334and
335.Sy written# Ns Ar bookmark
336properties and the
337.Ao Sy user Ns | Ns Sy group Ac Ns Ao Sy quota Ns | Ns Sy used Ac Ns Sy @ Ns Ar id
338properties, though the id must be in numeric form.
339.El
340.El
341.Bl -tag -width "xx"
342.It Sy zfs.sync submodule
343The sync submodule contains functions that modify the on-disk state.
344They are executed in "syncing context".
345.Pp
346The available sync submodule functions are as follows:
347.Bl -tag -width "xx"
348.It Sy zfs.sync.destroy Ns Pq Ar dataset , Op Ar defer Ns = Ns Sy true Ns | Ns Sy false
349Destroy the given dataset.
350Returns 0 on successful destroy, or a nonzero error code if the dataset could
351not be destroyed (for example, if the dataset has any active children or
352clones).
353.Pp
354.Bl -tag -compact -width "newbookmark (string)"
355.It Ar dataset Pq string
356Filesystem or snapshot to be destroyed.
357.It Op Ar defer Pq boolean
358Valid only for destroying snapshots.
359If set to true, and the snapshot has holds or clones, allows the snapshot to be
360marked for deferred deletion rather than failing.
361.El
362.It Fn zfs.sync.inherit dataset property
363Clears the specified property in the given dataset, causing it to be inherited
364from an ancestor, or restored to the default if no ancestor property is set.
365The
366.Nm zfs Cm inherit Fl S
367option has not been implemented.
368Returns 0 on success, or a nonzero error code if the property could not be
369cleared.
370.Pp
371.Bl -tag -compact -width "newbookmark (string)"
372.It Ar dataset Pq string
373Filesystem or snapshot containing the property to clear.
374.It Ar property Pq string
375The property to clear.
376Allowed properties are the same as those for the
377.Nm zfs Cm inherit
378command.
379.El
380.It Fn zfs.sync.promote dataset
381Promote the given clone to a filesystem.
382Returns 0 on successful promotion, or a nonzero error code otherwise.
383If EEXIST is returned, the second return value will be an array of the clone's
384snapshots whose names collide with snapshots of the parent filesystem.
385.Pp
386.Bl -tag -compact -width "newbookmark (string)"
387.It Ar dataset Pq string
388Clone to be promoted.
389.El
390.It Fn zfs.sync.rollback filesystem
391Rollback to the previous snapshot for a dataset.
392Returns 0 on successful rollback, or a nonzero error code otherwise.
393Rollbacks can be performed on filesystems or zvols, but not on snapshots
394or mounted datasets.
395EBUSY is returned in the case where the filesystem is mounted.
396.Pp
397.Bl -tag -compact -width "newbookmark (string)"
398.It Ar filesystem Pq string
399Filesystem to rollback.
400.El
401.It Fn zfs.sync.set_prop dataset property value
402Sets the given property on a dataset.
403Currently only user properties are supported.
404Returns 0 if the property was set, or a nonzero error code otherwise.
405.Pp
406.Bl -tag -compact -width "newbookmark (string)"
407.It Ar dataset Pq string
408The dataset where the property will be set.
409.It Ar property Pq string
410The property to set.
411.It Ar value Pq string
412The value of the property to be set.
413.El
414.It Fn zfs.sync.snapshot dataset
415Create a snapshot of a filesystem.
416Returns 0 if the snapshot was successfully created,
417and a nonzero error code otherwise.
418.Pp
419Note: Taking a snapshot will fail on any pool older than legacy version 27.
420To enable taking snapshots from ZCP scripts, the pool must be upgraded.
421.Pp
422.Bl -tag -compact -width "newbookmark (string)"
423.It Ar dataset Pq string
424Name of snapshot to create.
425.El
426.It Fn zfs.sync.bookmark source newbookmark
427Create a bookmark of an existing source snapshot or bookmark.
428Returns 0 if the new bookmark was successfully created,
429and a nonzero error code otherwise.
430.Pp
431Note: Bookmarking requires the corresponding pool feature to be enabled.
432.Pp
433.Bl -tag -compact -width "newbookmark (string)"
434.It Ar source Pq string
435Full name of the existing snapshot or bookmark.
436.It Ar newbookmark Pq string
437Full name of the new bookmark.
438.El
439.El
440.It Sy zfs.check submodule
441For each function in the
442.Sy zfs.sync
443submodule, there is a corresponding
444.Sy zfs.check
445function which performs a "dry run" of the same operation.
446Each takes the same arguments as its
447.Sy zfs.sync
448counterpart and returns 0 if the operation would succeed,
449or a non-zero error code if it would fail, along with any other error details.
450That is, each has the same behavior as the corresponding sync function except
451for actually executing the requested change.
452For example,
453.Fn zfs.check.destroy \&"fs"
454returns 0 if
455.Fn zfs.sync.destroy \&"fs"
456would successfully destroy the dataset.
457.Pp
458The available
459.Sy zfs.check
460functions are:
461.Bl -tag -compact -width "xx"
462.It Sy zfs.check.destroy Ns Pq Ar dataset , Op Ar defer Ns = Ns Sy true Ns | Ns Sy false
463.It Fn zfs.check.promote dataset
464.It Fn zfs.check.rollback filesystem
465.It Fn zfs.check.set_property dataset property value
466.It Fn zfs.check.snapshot dataset
467.El
468.It Sy zfs.list submodule
469The zfs.list submodule provides functions for iterating over datasets and
470properties.
471Rather than returning tables, these functions act as Lua iterators, and are
472generally used as follows:
473.Bd -literal -compact -offset indent
474.No for child in Fn zfs.list.children \&"rpool" No do
475    ...
476end
477.Ed
478.Pp
479The available
480.Sy zfs.list
481functions are:
482.Bl -tag -width "xx"
483.It Fn zfs.list.clones snapshot
484Iterate through all clones of the given snapshot.
485.Pp
486.Bl -tag -compact -width "snapshot (string)"
487.It Ar snapshot Pq string
488Must be a valid snapshot path in the current pool.
489.El
490.It Fn zfs.list.snapshots dataset
491Iterate through all snapshots of the given dataset.
492Each snapshot is returned as a string containing the full dataset name,
493e.g. "pool/fs@snap".
494.Pp
495.Bl -tag -compact -width "snapshot (string)"
496.It Ar dataset Pq string
497Must be a valid filesystem or volume.
498.El
499.It Fn zfs.list.children dataset
500Iterate through all direct children of the given dataset.
501Each child is returned as a string containing the full dataset name,
502e.g. "pool/fs/child".
503.Pp
504.Bl -tag -compact -width "snapshot (string)"
505.It Ar dataset Pq string
506Must be a valid filesystem or volume.
507.El
508.It Fn zfs.list.bookmarks dataset
509Iterate through all bookmarks of the given dataset.
510Each bookmark is returned as a string containing the full dataset name,
511e.g. "pool/fs#bookmark".
512.Pp
513.Bl -tag -compact -width "snapshot (string)"
514.It Ar dataset Pq string
515Must be a valid filesystem or volume.
516.El
517.It Fn zfs.list.holds snapshot
518Iterate through all user holds on the given snapshot.
519Each hold is returned
520as a pair of the hold's tag and the timestamp (in seconds since the epoch) at
521which it was created.
522.Pp
523.Bl -tag -compact -width "snapshot (string)"
524.It Ar snapshot Pq string
525Must be a valid snapshot.
526.El
527.It Fn zfs.list.properties dataset
528An alias for zfs.list.user_properties (see relevant entry).
529.Pp
530.Bl -tag -compact -width "snapshot (string)"
531.It Ar dataset Pq string
532Must be a valid filesystem, snapshot, or volume.
533.El
534.It Fn zfs.list.user_properties dataset
535Iterate through all user properties for the given dataset.
536For each step of the iteration, output the property name, its value,
537and its source.
538Throws a Lua error if the dataset is invalid.
539.Pp
540.Bl -tag -compact -width "snapshot (string)"
541.It Ar dataset Pq string
542Must be a valid filesystem, snapshot, or volume.
543.El
544.It Fn zfs.list.system_properties dataset
545Returns an array of strings, the names of the valid system (non-user defined)
546properties for the given dataset.
547Throws a Lua error if the dataset is invalid.
548.Pp
549.Bl -tag -compact -width "snapshot (string)"
550.It Ar dataset Pq string
551Must be a valid filesystem, snapshot or volume.
552.El
553.El
554.El
555.
556.Sh EXAMPLES
557.
558.Ss Example 1
559The following channel program recursively destroys a filesystem and all its
560snapshots and children in a naive manner.
561Note that this does not involve any error handling or reporting.
562.Bd -literal -offset indent
563function destroy_recursive(root)
564    for child in zfs.list.children(root) do
565        destroy_recursive(child)
566    end
567    for snap in zfs.list.snapshots(root) do
568        zfs.sync.destroy(snap)
569    end
570    zfs.sync.destroy(root)
571end
572destroy_recursive("pool/somefs")
573.Ed
574.
575.Ss Example 2
576A more verbose and robust version of the same channel program, which
577properly detects and reports errors, and also takes the dataset to destroy
578as a command line argument, would be as follows:
579.Bd -literal -offset indent
580succeeded = {}
581failed = {}
582
583function destroy_recursive(root)
584    for child in zfs.list.children(root) do
585        destroy_recursive(child)
586    end
587    for snap in zfs.list.snapshots(root) do
588        err = zfs.sync.destroy(snap)
589        if (err ~= 0) then
590            failed[snap] = err
591        else
592            succeeded[snap] = err
593        end
594    end
595    err = zfs.sync.destroy(root)
596    if (err ~= 0) then
597        failed[root] = err
598    else
599        succeeded[root] = err
600    end
601end
602
603args = ...
604argv = args["argv"]
605
606destroy_recursive(argv[1])
607
608results = {}
609results["succeeded"] = succeeded
610results["failed"] = failed
611return results
612.Ed
613.
614.Ss Example 3
615The following function performs a forced promote operation by attempting to
616promote the given clone and destroying any conflicting snapshots.
617.Bd -literal -offset indent
618function force_promote(ds)
619   errno, details = zfs.check.promote(ds)
620   if (errno == EEXIST) then
621       assert(details ~= Nil)
622       for i, snap in ipairs(details) do
623           zfs.sync.destroy(ds .. "@" .. snap)
624       end
625   elseif (errno ~= 0) then
626       return errno
627   end
628   return zfs.sync.promote(ds)
629end
630.Ed
631