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