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