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
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.
11 .\" Copyright (c) 2016, 2017 by Delphix. All rights reserved.
18 .Nd executes ZFS channel programs
22 .Op Fl t Ar instruction-limit
23 .Op Fl m Ar memory-limit
26 .\".Op Ar optional arguments to channel program
28 The ZFS channel program interface allows ZFS administrative operations to be
29 run programmatically as a Lua script.
30 The entire script is executed atomically, with no other administrative
31 operations taking effect concurrently.
32 A library of ZFS calls is made available to channel program scripts.
33 Channel programs may only be run with root privileges.
35 A modified version of the Lua 5.2 interpreter is used to run channel program
37 The Lua 5.2 manual can be found at:
38 .Bd -centered -offset indent
39 .Lk http://www.lua.org/manual/5.2/
42 The channel program given by
46 and any attempts to access or modify other pools will cause an error.
50 Executes a read-only channel program, which runs faster.
51 The program cannot change on-disk state by calling functions from the
53 The program can be used to gather information such as properties and
54 determining if changes would succeed (zfs.check.*).
55 Without this flag, all pending changes must be synced to disk before a
56 channel program can complete.
57 .It Fl t Ar instruction-limit
58 Execution time limit, in number of Lua instructions to execute.
59 If a channel program executes more than the specified number of instructions,
60 it will be stopped and an error will be returned.
61 The default limit is 10 million instructions, and it can be set to a maximum of
62 100 million instructions.
63 .It Fl m Ar memory-limit
64 Memory limit, in bytes.
65 If a channel program attempts to allocate more memory than the given limit, it
66 will be stopped and an error returned.
67 The default memory limit is 10 MB, and can be set to a maximum of 100 MB.
70 All remaining argument strings will be passed directly to the Lua script as
75 A channel program can be invoked either from the command line, or via a library
77 .Fn lzc_channel_program .
79 Arguments passed to the channel program are converted to a Lua table.
80 If invoked from the command line, extra arguments to the Lua script will be
81 accessible as an array stored in the argument table with the key 'argv':
82 .Bd -literal -offset indent
85 -- argv == {1="arg1", 2="arg2", ...}
88 If invoked from the libZFS interface, an arbitrary argument list can be
89 passed to the channel program, which is accessible via the same
91 .Bd -literal -offset indent
93 -- args == {"foo"="bar", "baz"={...}, ...}
96 Note that because Lua arrays are 1-indexed, arrays passed to Lua from the
97 libZFS interface will have their indices incremented by 1.
101 in a C array passed to a channel program will be stored in
103 when accessed from Lua.
105 Lua return statements take the form:
106 .Bd -literal -offset indent
107 return ret0, ret1, ret2, ...
110 Return statements returning multiple values are permitted internally in a
111 channel program script, but attempting to return more than one value from the
112 top level of the channel program is not permitted and will throw an error.
113 However, tables containing multiple values can still be returned.
114 If invoked from the command line, a return statement:
115 .Bd -literal -offset indent
116 a = {foo="bar", baz=2}
120 Will be output formatted as:
121 .Bd -literal -offset indent
122 Channel program fully executed with return value:
128 If the channel program encounters a fatal error while running, a non-zero exit
129 status will be returned.
130 If more information about the error is available, a singleton list will be
131 returned detailing the error:
132 .Bd -literal -offset indent
133 error: "error string, including Lua stack trace"
136 If a fatal error is returned, the channel program may have not executed at all,
137 may have partially executed, or may have fully executed but failed to pass a
138 return value back to userland.
140 If the channel program exhausts an instruction or memory limit, a fatal error
141 will be generated and the program will be stopped, leaving the program partially
143 No attempt is made to reverse or undo any operations already performed.
144 Note that because both the instruction count and amount of memory used by a
145 channel program are deterministic when run against the same inputs and
146 filesystem state, as long as a channel program has run successfully once, you
147 can guarantee that it will finish successfully against a similar size system.
149 If a channel program attempts to return too large a value, the program will
150 fully execute but exit with a nonzero status code and no return value.
153 ZFS API functions do not generate Fatal Errors when correctly invoked, they
154 return an error code and the channel program continues executing.
157 section below for function-specific details on error return codes.
158 .Ss Lua to C Value Conversion
159 When invoking a channel program via the libZFS interface, it is necessary to
160 translate arguments and return values from Lua values to their C equivalents,
163 There is a correspondence between nvlist values in C and Lua tables.
164 A Lua table which is returned from the channel program will be recursively
165 converted to an nvlist, with table values converted to their natural
167 .Bd -literal -offset indent
170 boolean -> boolean_value
171 nil -> boolean (no value)
175 Likewise, table keys are replaced by string equivalents as follows:
176 .Bd -literal -offset indent
178 number -> signed decimal string ("%lld")
179 boolean -> "true" | "false"
182 Any collision of table key strings (for example, the string "true" and a
183 true boolean value) will cause a fatal error.
185 Lua numbers are represented internally as signed 64-bit integers.
186 .Sh LUA STANDARD LIBRARY
187 The following Lua built-in base library functions are available:
188 .Bd -literal -offset indent
190 collectgarbage rawget
204 built-in submodules are also available.
205 A complete list and documentation of these modules is available in the Lua
208 The following functions base library functions have been disabled and are
209 not available for use in channel programs:
210 .Bd -literal -offset indent
219 .Ss Function Arguments
220 Each API function takes a fixed set of required positional arguments and
221 optional keyword arguments.
222 For example, the destroy function takes a single positional string argument
223 (the name of the dataset to destroy) and an optional "defer" keyword boolean
225 When using parentheses to specify the arguments to a Lua function, only
226 positional arguments can be used:
227 .Bd -literal -offset indent
228 zfs.sync.destroy("rpool@snap")
231 To use keyword arguments, functions must be called with a single argument that
232 is a Lua table containing entries mapping integers to positional arguments and
233 strings to keyword arguments:
234 .Bd -literal -offset indent
235 zfs.sync.destroy({1="rpool@snap", defer=true})
238 The Lua language allows curly braces to be used in place of parenthesis as
239 syntactic sugar for this calling convention:
240 .Bd -literal -offset indent
241 zfs.sync.snapshot{"rpool@snap", defer=true}
243 .Ss Function Return Values
244 If an API function succeeds, it returns 0.
245 If it fails, it returns an error code and the channel program continues
247 API functions do not generate Fatal Errors except in the case of an
248 unrecoverable internal file system error.
250 In addition to returning an error code, some functions also return extra
251 details describing what caused the error.
252 This extra description is given as a second return value, and will always be a
253 Lua table, or Nil if no error details were returned.
254 Different keys will exist in the error details table depending on the function
256 Any such function may be called expecting a single return value:
257 .Bd -literal -offset indent
258 errno = zfs.sync.promote(dataset)
261 Or, the error details can be retrieved:
262 .Bd -literal -offset indent
263 errno, details = zfs.sync.promote(dataset)
264 if (errno == EEXIST) then
265 assert(details ~= Nil)
266 list_of_conflicting_snapshots = details
270 The following global aliases for API function error return codes are defined
271 for use in channel programs:
272 .Bd -literal -offset indent
273 EPERM ECHILD ENODEV ENOSPC
274 ENOENT EAGAIN ENOTDIR ESPIPE
275 ESRCH ENOMEM EISDIR EROFS
276 EINTR EACCES EINVAL EMLINK
277 EIO EFAULT ENFILE EPIPE
278 ENXIO ENOTBLK EMFILE EDOM
279 E2BIG EBUSY ENOTTY ERANGE
280 ENOEXEC EEXIST ETXTBSY EDQUOT
284 For detailed descriptions of the exact behavior of any zfs administrative
285 operations, see the main
289 .It Em zfs.debug(msg)
290 Record a debug message in the zfs_dbgmsg log.
291 A log of these messages can be printed via mdb's "::zfs_dbgmsg" command, or
292 can be monitored live by running:
293 .Bd -literal -offset indent
294 dtrace -n 'zfs-dbgmsg{trace(stringof(arg0))}'
298 .Bd -ragged -compact -offset "xxxx"
299 Debug message to be printed.
301 .It Em zfs.exists(dataset)
302 Returns true if the given dataset exists, or false if it doesn't.
303 A fatal error will be thrown if the dataset is not in the target pool.
304 That is, in a channel program running on rpool,
305 zfs.exists("rpool/nonexistent_fs") returns false, but
306 zfs.exists("somepool/fs_that_may_exist") will error.
309 .Bd -ragged -compact -offset "xxxx"
310 Dataset to check for existence.
311 Must be in the target pool.
313 .It Em zfs.get_prop(dataset, property)
315 First, a string, number or table containing the property value for the given
317 Second, a string containing the source of the property (i.e. the name of the
318 dataset in which it was set or nil if it is readonly).
319 Throws a Lua error if the dataset is invalid or the property doesn't exist.
320 Note that Lua only supports int64 number types whereas ZFS number properties
322 This means very large values (like guid) may wrap around and appear negative.
325 .Bd -ragged -compact -offset "xxxx"
326 Filesystem or snapshot path to retrieve properties from.
330 .Bd -ragged -compact -offset "xxxx"
331 Name of property to retrieve.
332 All filesystem, snapshot and volume properties are supported except
333 for 'mounted' and 'iscsioptions.'
334 Also supports the 'written@snap' and 'written#bookmark' properties and
335 the '<user|group><quota|used>@id' properties, though the id must be in numeric
340 .It Sy zfs.sync submodule
341 The sync submodule contains functions that modify the on-disk state.
342 They are executed in "syncing context".
344 The available sync submodule functions are as follows:
346 .It Em zfs.sync.destroy(dataset, [defer=true|false])
347 Destroy the given dataset.
348 Returns 0 on successful destroy, or a nonzero error code if the dataset could
349 not be destroyed (for example, if the dataset has any active children or
353 .Bd -ragged -compact -offset "xxxx"
354 Filesystem or snapshot to be destroyed.
357 [optional] defer (boolean)
358 .Bd -ragged -compact -offset "xxxx"
359 Valid only for destroying snapshots.
360 If set to true, and the snapshot has holds or clones, allows the snapshot to be
361 marked for deferred deletion rather than failing.
363 .It Em zfs.sync.promote(dataset)
364 Promote the given clone to a filesystem.
365 Returns 0 on successful promotion, or a nonzero error code otherwise.
366 If EEXIST is returned, the second return value will be an array of the clone's
367 snapshots whose names collide with snapshots of the parent filesystem.
370 .Bd -ragged -compact -offset "xxxx"
371 Clone to be promoted.
373 .It Em zfs.sync.rollback(filesystem)
374 Rollback to the previous snapshot for a dataset.
375 Returns 0 on successful rollback, or a nonzero error code otherwise.
376 Rollbacks can be performed on filesystems or zvols, but not on snapshots
378 EBUSY is returned in the case where the filesystem is mounted.
381 .Bd -ragged -compact -offset "xxxx"
382 Filesystem to rollback.
384 .It Em zfs.sync.snapshot(dataset)
385 Create a snapshot of a filesystem.
386 Returns 0 if the snapshot was successfully created,
387 and a nonzero error code otherwise.
389 Note: Taking a snapshot will fail on any pool older than legacy version 27.
390 To enable taking snapshots from ZCP scripts, the pool must be upgraded.
393 .Bd -ragged -compact -offset "xxxx"
394 Name of snapshot to create.
397 .It Sy zfs.check submodule
398 For each function in the zfs.sync submodule, there is a corresponding zfs.check
399 function which performs a "dry run" of the same operation.
400 Each takes the same arguments as its zfs.sync counterpart and returns 0 if the
401 operation would succeed, or a non-zero error code if it would fail, along with
402 any other error details.
403 That is, each has the same behavior as the corresponding sync function except
404 for actually executing the requested change.
406 .Em zfs.check.destroy("fs")
408 .Em zfs.sync.destroy("fs")
409 would successfully destroy the dataset.
411 The available zfs.check functions are:
413 .It Em zfs.check.destroy(dataset, [defer=true|false])
414 .It Em zfs.check.promote(dataset)
415 .It Em zfs.check.rollback(filesystem)
416 .It Em zfs.check.snapshot(dataset)
418 .It Sy zfs.list submodule
419 The zfs.list submodule provides functions for iterating over datasets and
421 Rather than returning tables, these functions act as Lua iterators, and are
422 generally used as follows:
423 .Bd -literal -offset indent
424 for child in zfs.list.children("rpool") do
429 The available zfs.list functions are:
431 .It Em zfs.list.clones(snapshot)
432 Iterate through all clones of the given snapshot.
435 .Bd -ragged -compact -offset "xxxx"
436 Must be a valid snapshot path in the current pool.
438 .It Em zfs.list.snapshots(dataset)
439 Iterate through all snapshots of the given dataset.
440 Each snapshot is returned as a string containing the full dataset name, e.g.
444 .Bd -ragged -compact -offset "xxxx"
445 Must be a valid filesystem or volume.
447 .It Em zfs.list.children(dataset)
448 Iterate through all direct children of the given dataset.
449 Each child is returned as a string containing the full dataset name, e.g.
453 .Bd -ragged -compact -offset "xxxx"
454 Must be a valid filesystem or volume.
456 .It Em zfs.list.properties(dataset)
457 Iterate through all user properties for the given dataset.
460 .Bd -ragged -compact -offset "xxxx"
461 Must be a valid filesystem, snapshot, or volume.
463 .It Em zfs.list.system_properties(dataset)
464 Returns an array of strings, the names of the valid system (non-user defined)
465 properties for the given dataset.
466 Throws a Lua error if the dataset is invalid.
469 .Bd -ragged -compact -offset "xxxx"
470 Must be a valid filesystem, snapshot or volume.
476 The following channel program recursively destroys a filesystem and all its
477 snapshots and children in a naive manner.
478 Note that this does not involve any error handling or reporting.
479 .Bd -literal -offset indent
480 function destroy_recursive(root)
481 for child in zfs.list.children(root) do
482 destroy_recursive(child)
484 for snap in zfs.list.snapshots(root) do
485 zfs.sync.destroy(snap)
487 zfs.sync.destroy(root)
489 destroy_recursive("pool/somefs")
492 A more verbose and robust version of the same channel program, which
493 properly detects and reports errors, and also takes the dataset to destroy
494 as a command line argument, would be as follows:
495 .Bd -literal -offset indent
499 function destroy_recursive(root)
500 for child in zfs.list.children(root) do
501 destroy_recursive(child)
503 for snap in zfs.list.snapshots(root) do
504 err = zfs.sync.destroy(snap)
508 succeeded[snap] = err
511 err = zfs.sync.destroy(root)
515 succeeded[root] = err
522 destroy_recursive(argv[1])
525 results["succeeded"] = succeeded
526 results["failed"] = failed
530 The following function performs a forced promote operation by attempting to
531 promote the given clone and destroying any conflicting snapshots.
532 .Bd -literal -offset indent
533 function force_promote(ds)
534 errno, details = zfs.check.promote(ds)
535 if (errno == EEXIST) then
536 assert(details ~= Nil)
537 for i, snap in ipairs(details) do
538 zfs.sync.destroy(ds .. "@" .. snap)
540 elseif (errno ~= 0) then
543 return zfs.sync.promote(ds)