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