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