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