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