- Changes to make library interface more clear and to better suit go package standards
This commit is contained in:
		
							parent
							
								
									db4703b708
								
							
						
					
					
						commit
						bc19737222
					
				| 
						 | 
					@ -46,10 +46,10 @@ props := make(map[ZFSProp]Property)
 | 
				
			||||||
// similar to convert in to string (base 10) from numeric type.
 | 
					// similar to convert in to string (base 10) from numeric type.
 | 
				
			||||||
strSize := "1073741824"
 | 
					strSize := "1073741824"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
props[ZFSPropVolsize] = Property{Value: strSize}
 | 
					props[DatasetPropVolsize] = Property{Value: strSize}
 | 
				
			||||||
// In addition I explicitly choose some more properties to be set.
 | 
					// In addition I explicitly choose some more properties to be set.
 | 
				
			||||||
props[ZFSPropVolblocksize] = Property{Value: "4096"}
 | 
					props[DatasetPropVolblocksize] = Property{Value: "4096"}
 | 
				
			||||||
props[ZFSPropReservation] = Property{Value: strSize}
 | 
					props[DatasetPropReservation] = Property{Value: strSize}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Lets create desired volume
 | 
					// Lets create desired volume
 | 
				
			||||||
d, err := DatasetCreate("TESTPOOL/VOLUME1", DatasetTypeVolume, props)
 | 
					d, err := DatasetCreate("TESTPOOL/VOLUME1", DatasetTypeVolume, props)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										329
									
								
								common.go
								
								
								
								
							
							
						
						
									
										329
									
								
								common.go
								
								
								
								
							| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
// Implements basic manipulation of ZFS pools and data sets.
 | 
					// Package zfs implements basic manipulation of ZFS pools and data sets.
 | 
				
			||||||
// Use libzfs C library instead CLI zfs tools, with goal
 | 
					// Use libzfs C library instead CLI zfs tools, with goal
 | 
				
			||||||
// to let using and manipulating OpenZFS form with in go project.
 | 
					// to let using and manipulating OpenZFS form with in go project.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
| 
						 | 
					@ -23,36 +23,41 @@ import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VDevType type of device in the pool
 | 
				
			||||||
type VDevType string
 | 
					type VDevType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var libzfs_handle *C.struct_libzfs_handle
 | 
					var libzfsHandle *C.struct_libzfs_handle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	libzfs_handle = C.libzfs_init()
 | 
						libzfsHandle = C.libzfs_init()
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Types of Virtual Devices
 | 
					// Types of Virtual Devices
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	VDevTypeRoot      VDevType = "root"
 | 
						VDevTypeRoot      VDevType = "root"      // VDevTypeRoot root device in ZFS pool
 | 
				
			||||||
	VDevTypeMirror             = "mirror"
 | 
						VDevTypeMirror             = "mirror"    // VDevTypeMirror mirror device in ZFS pool
 | 
				
			||||||
	VDevTypeReplacing          = "replacing"
 | 
						VDevTypeReplacing          = "replacing" // VDevTypeReplacing replacing
 | 
				
			||||||
	VDevTypeRaidz              = "raidz"
 | 
						VDevTypeRaidz              = "raidz"     // VDevTypeRaidz RAIDZ device
 | 
				
			||||||
	VDevTypeDisk               = "disk"
 | 
						VDevTypeDisk               = "disk"      // VDevTypeDisk device is disk
 | 
				
			||||||
	VDevTypeFile               = "file"
 | 
						VDevTypeFile               = "file"      // VDevTypeFile device is file
 | 
				
			||||||
	VDevTypeMissing            = "missing"
 | 
						VDevTypeMissing            = "missing"   // VDevTypeMissing missing device
 | 
				
			||||||
	VDevTypeHole               = "hole"
 | 
						VDevTypeHole               = "hole"      // VDevTypeHole hole
 | 
				
			||||||
	VDevTypeSpare              = "spare"
 | 
						VDevTypeSpare              = "spare"     // VDevTypeSpare spare device
 | 
				
			||||||
	VDevTypeLog                = "log"
 | 
						VDevTypeLog                = "log"       // VDevTypeLog ZIL device
 | 
				
			||||||
	VDevTypeL2cache            = "l2cache"
 | 
						VDevTypeL2cache            = "l2cache"   // VDevTypeL2cache cache device (disk)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PoolProp int
 | 
					// Prop type to enumerate all different properties suppoerted by ZFS
 | 
				
			||||||
type ZFSProp int
 | 
					type Prop int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PoolStatus type representing status of the pool
 | 
				
			||||||
type PoolStatus int
 | 
					type PoolStatus int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PoolState type representing pool state
 | 
				
			||||||
type PoolState uint64
 | 
					type PoolState uint64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Zfs pool or dataset property
 | 
					// Property ZFS pool or dataset property value
 | 
				
			||||||
type Property struct {
 | 
					type Property struct {
 | 
				
			||||||
	Value  string
 | 
						Value  string
 | 
				
			||||||
	Source string
 | 
						Source string
 | 
				
			||||||
| 
						 | 
					@ -64,21 +69,21 @@ const (
 | 
				
			||||||
	 * The following correspond to faults as defined in the (fault.fs.zfs.*)
 | 
						 * The following correspond to faults as defined in the (fault.fs.zfs.*)
 | 
				
			||||||
	 * event namespace.  Each is associated with a corresponding message ID.
 | 
						 * event namespace.  Each is associated with a corresponding message ID.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	PoolStatusCorrupt_cache       PoolStatus = iota /* corrupt /kernel/drv/zpool.cache */
 | 
						PoolStatusCorruptCache      PoolStatus = iota /* corrupt /kernel/drv/zpool.cache */
 | 
				
			||||||
	PoolStatusMissing_dev_r                         /* missing device with replicas */
 | 
						PoolStatusMissingDevR                         /* missing device with replicas */
 | 
				
			||||||
	PoolStatusMissing_dev_nr                        /* missing device with no replicas */
 | 
						PoolStatusMissingDevNr                        /* missing device with no replicas */
 | 
				
			||||||
	PoolStatusCorrupt_label_r                       /* bad device label with replicas */
 | 
						PoolStatusCorruptLabelR                       /* bad device label with replicas */
 | 
				
			||||||
	PoolStatusCorrupt_label_nr                      /* bad device label with no replicas */
 | 
						PoolStatusCorruptLabelNr                      /* bad device label with no replicas */
 | 
				
			||||||
	PoolStatusBad_guid_sum                          /* sum of device guids didn't match */
 | 
						PoolStatusBadGUIDSum                          /* sum of device guids didn't match */
 | 
				
			||||||
	PoolStatusCorrupt_pool                          /* pool metadata is corrupted */
 | 
						PoolStatusCorruptPool                         /* pool metadata is corrupted */
 | 
				
			||||||
	PoolStatusCorrupt_data                          /* data errors in user (meta)data */
 | 
						PoolStatusCorruptData                         /* data errors in user (meta)data */
 | 
				
			||||||
	PoolStatusFailing_dev                           /* device experiencing errors */
 | 
						PoolStatusFailingDev                          /* device experiencing errors */
 | 
				
			||||||
	PoolStatusVersion_newer                         /* newer on-disk version */
 | 
						PoolStatusVersionNewer                        /* newer on-disk version */
 | 
				
			||||||
	PoolStatusHostid_mismatch                       /* last accessed by another system */
 | 
						PoolStatusHostidMismatch                      /* last accessed by another system */
 | 
				
			||||||
	PoolStatusIo_failure_wait                       /* failed I/O, failmode 'wait' */
 | 
						PoolStatusIoFailureWait                       /* failed I/O, failmode 'wait' */
 | 
				
			||||||
	PoolStatusIo_failure_continue                   /* failed I/O, failmode 'continue' */
 | 
						PoolStatusIoFailureContinue                   /* failed I/O, failmode 'continue' */
 | 
				
			||||||
	PoolStatusBad_log                               /* cannot read log chain(s) */
 | 
						PoolStatusBadLog                              /* cannot read log chain(s) */
 | 
				
			||||||
	PoolStatusErrata                                /* informational errata available */
 | 
						PoolStatusErrata                              /* informational errata available */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If the pool has unsupported features but can still be opened in
 | 
						 * If the pool has unsupported features but can still be opened in
 | 
				
			||||||
| 
						 | 
					@ -86,27 +91,27 @@ const (
 | 
				
			||||||
	 * pool has unsupported features but cannot be opened at all, its
 | 
						 * pool has unsupported features but cannot be opened at all, its
 | 
				
			||||||
	 * status is ZPOOL_STATUS_UNSUP_FEAT_READ.
 | 
						 * status is ZPOOL_STATUS_UNSUP_FEAT_READ.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	PoolStatusUnsup_feat_read  /* unsupported features for read */
 | 
						PoolStatusUnsupFeatRead  /* unsupported features for read */
 | 
				
			||||||
	PoolStatusUnsup_feat_write /* unsupported features for write */
 | 
						PoolStatusUnsupFeatWrite /* unsupported features for write */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * These faults have no corresponding message ID.  At the time we are
 | 
						 * These faults have no corresponding message ID.  At the time we are
 | 
				
			||||||
	 * checking the status, the original reason for the FMA fault (I/O or
 | 
						 * checking the status, the original reason for the FMA fault (I/O or
 | 
				
			||||||
	 * checksum errors) has been lost.
 | 
						 * checksum errors) has been lost.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	PoolStatusFaulted_dev_r  /* faulted device with replicas */
 | 
						PoolStatusFaultedDevR  /* faulted device with replicas */
 | 
				
			||||||
	PoolStatusFaulted_dev_nr /* faulted device with no replicas */
 | 
						PoolStatusFaultedDevNr /* faulted device with no replicas */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The following are not faults per se, but still an error possibly
 | 
						 * The following are not faults per se, but still an error possibly
 | 
				
			||||||
	 * requiring administrative attention.  There is no corresponding
 | 
						 * requiring administrative attention.  There is no corresponding
 | 
				
			||||||
	 * message ID.
 | 
						 * message ID.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	PoolStatusVersion_older /* older legacy on-disk version */
 | 
						PoolStatusVersionOlder /* older legacy on-disk version */
 | 
				
			||||||
	PoolStatusFeat_disabled /* supported features are disabled */
 | 
						PoolStatusFeatDisabled /* supported features are disabled */
 | 
				
			||||||
	PoolStatusResilvering   /* device being resilvered */
 | 
						PoolStatusResilvering  /* device being resilvered */
 | 
				
			||||||
	PoolStatusOffline_dev   /* device online */
 | 
						PoolStatusOfflineDev   /* device online */
 | 
				
			||||||
	PoolStatusRemoved_dev   /* removed device */
 | 
						PoolStatusRemovedDev   /* removed device */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Finally, the following indicates a healthy pool.
 | 
						 * Finally, the following indicates a healthy pool.
 | 
				
			||||||
| 
						 | 
					@ -129,12 +134,12 @@ const (
 | 
				
			||||||
// Pool properties. Enumerates available ZFS pool properties. Use it to access
 | 
					// Pool properties. Enumerates available ZFS pool properties. Use it to access
 | 
				
			||||||
// pool properties either to read or set soecific property.
 | 
					// pool properties either to read or set soecific property.
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	PoolPropName PoolProp = iota
 | 
						PoolPropName Prop = iota
 | 
				
			||||||
	PoolPropSize
 | 
						PoolPropSize
 | 
				
			||||||
	PoolPropCapacity
 | 
						PoolPropCapacity
 | 
				
			||||||
	PoolPropAltroot
 | 
						PoolPropAltroot
 | 
				
			||||||
	PoolPropHealth
 | 
						PoolPropHealth
 | 
				
			||||||
	PoolPropGuid
 | 
						PoolPropGUID
 | 
				
			||||||
	PoolPropVersion
 | 
						PoolPropVersion
 | 
				
			||||||
	PoolPropBootfs
 | 
						PoolPropBootfs
 | 
				
			||||||
	PoolPropDelegation
 | 
						PoolPropDelegation
 | 
				
			||||||
| 
						 | 
					@ -166,102 +171,178 @@ const (
 | 
				
			||||||
 * the property table in module/zcommon/zfs_prop.c.
 | 
					 * the property table in module/zcommon/zfs_prop.c.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	ZFSPropType ZFSProp = iota
 | 
						DatasetPropType Prop = iota
 | 
				
			||||||
	ZFSPropCreation
 | 
						DatasetPropCreation
 | 
				
			||||||
	ZFSPropUsed
 | 
						DatasetPropUsed
 | 
				
			||||||
	ZFSPropAvailable
 | 
						DatasetPropAvailable
 | 
				
			||||||
	ZFSPropReferenced
 | 
						DatasetPropReferenced
 | 
				
			||||||
	ZFSPropCompressratio
 | 
						DatasetPropCompressratio
 | 
				
			||||||
	ZFSPropMounted
 | 
						DatasetPropMounted
 | 
				
			||||||
	ZFSPropOrigin
 | 
						DatasetPropOrigin
 | 
				
			||||||
	ZFSPropQuota
 | 
						DatasetPropQuota
 | 
				
			||||||
	ZFSPropReservation
 | 
						DatasetPropReservation
 | 
				
			||||||
	ZFSPropVolsize
 | 
						DatasetPropVolsize
 | 
				
			||||||
	ZFSPropVolblocksize
 | 
						DatasetPropVolblocksize
 | 
				
			||||||
	ZFSPropRecordsize
 | 
						DatasetPropRecordsize
 | 
				
			||||||
	ZFSPropMountpoint
 | 
						DatasetPropMountpoint
 | 
				
			||||||
	ZFSPropSharenfs
 | 
						DatasetPropSharenfs
 | 
				
			||||||
	ZFSPropChecksum
 | 
						DatasetPropChecksum
 | 
				
			||||||
	ZFSPropCompression
 | 
						DatasetPropCompression
 | 
				
			||||||
	ZFSPropAtime
 | 
						DatasetPropAtime
 | 
				
			||||||
	ZFSPropDevices
 | 
						DatasetPropDevices
 | 
				
			||||||
	ZFSPropExec
 | 
						DatasetPropExec
 | 
				
			||||||
	ZFSPropSetuid
 | 
						DatasetPropSetuid
 | 
				
			||||||
	ZFSPropReadonly
 | 
						DatasetPropReadonly
 | 
				
			||||||
	ZFSPropZoned
 | 
						DatasetPropZoned
 | 
				
			||||||
	ZFSPropSnapdir
 | 
						DatasetPropSnapdir
 | 
				
			||||||
	ZFSPropPrivate /* not exposed to user, temporary */
 | 
						DatasetPropPrivate /* not exposed to user, temporary */
 | 
				
			||||||
	ZFSPropAclinherit
 | 
						DatasetPropAclinherit
 | 
				
			||||||
	ZFSPropCreatetxg /* not exposed to the user */
 | 
						DatasetPropCreatetxg /* not exposed to the user */
 | 
				
			||||||
	ZFSPropName      /* not exposed to the user */
 | 
						DatasetPropName      /* not exposed to the user */
 | 
				
			||||||
	ZFSPropCanmount
 | 
						DatasetPropCanmount
 | 
				
			||||||
	ZFSPropIscsioptions /* not exposed to the user */
 | 
						DatasetPropIscsioptions /* not exposed to the user */
 | 
				
			||||||
	ZFSPropXattr
 | 
						DatasetPropXattr
 | 
				
			||||||
	ZFSPropNumclones /* not exposed to the user */
 | 
						DatasetPropNumclones /* not exposed to the user */
 | 
				
			||||||
	ZFSPropCopies
 | 
						DatasetPropCopies
 | 
				
			||||||
	ZFSPropVersion
 | 
						DatasetPropVersion
 | 
				
			||||||
	ZFSPropUtf8only
 | 
						DatasetPropUtf8only
 | 
				
			||||||
	ZFSPropNormalize
 | 
						DatasetPropNormalize
 | 
				
			||||||
	ZFSPropCase
 | 
						DatasetPropCase
 | 
				
			||||||
	ZFSPropVscan
 | 
						DatasetPropVscan
 | 
				
			||||||
	ZFSPropNbmand
 | 
						DatasetPropNbmand
 | 
				
			||||||
	ZFSPropSharesmb
 | 
						DatasetPropSharesmb
 | 
				
			||||||
	ZFSPropRefquota
 | 
						DatasetPropRefquota
 | 
				
			||||||
	ZFSPropRefreservation
 | 
						DatasetPropRefreservation
 | 
				
			||||||
	ZFSPropGuid
 | 
						DatasetPropGUID
 | 
				
			||||||
	ZFSPropPrimarycache
 | 
						DatasetPropPrimarycache
 | 
				
			||||||
	ZFSPropSecondarycache
 | 
						DatasetPropSecondarycache
 | 
				
			||||||
	ZFSPropUsedsnap
 | 
						DatasetPropUsedsnap
 | 
				
			||||||
	ZFSPropUsedds
 | 
						DatasetPropUsedds
 | 
				
			||||||
	ZFSPropUsedchild
 | 
						DatasetPropUsedchild
 | 
				
			||||||
	ZFSPropUsedrefreserv
 | 
						DatasetPropUsedrefreserv
 | 
				
			||||||
	ZFSPropUseraccounting /* not exposed to the user */
 | 
						DatasetPropUseraccounting /* not exposed to the user */
 | 
				
			||||||
	ZFSPropStmf_shareinfo /* not exposed to the user */
 | 
						DatasetPropStmfShareinfo  /* not exposed to the user */
 | 
				
			||||||
	ZFSPropDefer_destroy
 | 
						DatasetPropDeferDestroy
 | 
				
			||||||
	ZFSPropUserrefs
 | 
						DatasetPropUserrefs
 | 
				
			||||||
	ZFSPropLogbias
 | 
						DatasetPropLogbias
 | 
				
			||||||
	ZFSPropUnique   /* not exposed to the user */
 | 
						DatasetPropUnique   /* not exposed to the user */
 | 
				
			||||||
	ZFSPropObjsetid /* not exposed to the user */
 | 
						DatasetPropObjsetid /* not exposed to the user */
 | 
				
			||||||
	ZFSPropDedup
 | 
						DatasetPropDedup
 | 
				
			||||||
	ZFSPropMlslabel
 | 
						DatasetPropMlslabel
 | 
				
			||||||
	ZFSPropSync
 | 
						DatasetPropSync
 | 
				
			||||||
	ZFSPropRefratio
 | 
						DatasetPropRefratio
 | 
				
			||||||
	ZFSPropWritten
 | 
						DatasetPropWritten
 | 
				
			||||||
	ZFSPropClones
 | 
						DatasetPropClones
 | 
				
			||||||
	ZFSPropLogicalused
 | 
						DatasetPropLogicalused
 | 
				
			||||||
	ZFSPropLogicalreferenced
 | 
						DatasetPropLogicalreferenced
 | 
				
			||||||
	ZFSPropInconsistent /* not exposed to the user */
 | 
						DatasetPropInconsistent /* not exposed to the user */
 | 
				
			||||||
	ZFSPropSnapdev
 | 
						DatasetPropSnapdev
 | 
				
			||||||
	ZFSPropAcltype
 | 
						DatasetPropAcltype
 | 
				
			||||||
	ZFSPropSelinux_context
 | 
						DatasetPropSelinuxContext
 | 
				
			||||||
	ZFSPropSelinux_fscontext
 | 
						DatasetPropSelinuxFsContext
 | 
				
			||||||
	ZFSPropSelinux_defcontext
 | 
						DatasetPropSelinuxDefContext
 | 
				
			||||||
	ZFSPropSelinux_rootcontext
 | 
						DatasetPropSelinuxRootContext
 | 
				
			||||||
	ZFSPropRelatime
 | 
						DatasetPropRelatime
 | 
				
			||||||
	ZFSPropRedundant_metadata
 | 
						DatasetPropRedundantMetadata
 | 
				
			||||||
	ZFSPropOverlay
 | 
						DatasetPropOverlay
 | 
				
			||||||
	ZFSNumProps
 | 
						DatasetNumProps
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get last underlying libzfs error description if any
 | 
					// LastError get last underlying libzfs error description if any
 | 
				
			||||||
func LastError() (err error) {
 | 
					func LastError() (err error) {
 | 
				
			||||||
	errno := C.libzfs_errno(libzfs_handle)
 | 
						errno := C.libzfs_errno(libzfsHandle)
 | 
				
			||||||
	if errno == 0 {
 | 
						if errno == 0 {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return errors.New(C.GoString(C.libzfs_error_description(libzfs_handle)))
 | 
						return errors.New(C.GoString(C.libzfs_error_description(libzfsHandle)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Force clear of any last error set by undeliying libzfs
 | 
					// ClearLastError force clear of any last error set by undeliying libzfs
 | 
				
			||||||
func ClearLastError() (err error) {
 | 
					func ClearLastError() (err error) {
 | 
				
			||||||
	err = LastError()
 | 
						err = LastError()
 | 
				
			||||||
	C.clear_last_error(libzfs_handle)
 | 
						C.clear_last_error(libzfsHandle)
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func boolean_t(b bool) (r C.boolean_t) {
 | 
					func booleanT(b bool) (r C.boolean_t) {
 | 
				
			||||||
	if b {
 | 
						if b {
 | 
				
			||||||
		return 1
 | 
							return 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0
 | 
						return 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ZFS errors
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ESuccess            = 0            /* no error -- success */
 | 
				
			||||||
 | 
						ENomem              = 2000 << iota /* out of memory */
 | 
				
			||||||
 | 
						EBadprop                           /* invalid property value */
 | 
				
			||||||
 | 
						EPropreadonly                      /* cannot set readonly property */
 | 
				
			||||||
 | 
						EProptype                          /* property does not apply to dataset type */
 | 
				
			||||||
 | 
						EPropnoninherit                    /* property is not inheritable */
 | 
				
			||||||
 | 
						EPropspace                         /* bad quota or reservation */
 | 
				
			||||||
 | 
						EBadtype                           /* dataset is not of appropriate type */
 | 
				
			||||||
 | 
						EBusy                              /* pool or dataset is busy */
 | 
				
			||||||
 | 
						EExists                            /* pool or dataset already exists */
 | 
				
			||||||
 | 
						ENoent                             /* no such pool or dataset */
 | 
				
			||||||
 | 
						EBadstream                         /* bad backup stream */
 | 
				
			||||||
 | 
						EDsreadonly                        /* dataset is readonly */
 | 
				
			||||||
 | 
						EVoltoobig                         /* volume is too large for 32-bit system */
 | 
				
			||||||
 | 
						EInvalidname                       /* invalid dataset name */
 | 
				
			||||||
 | 
						EBadrestore                        /* unable to restore to destination */
 | 
				
			||||||
 | 
						EBadbackup                         /* backup failed */
 | 
				
			||||||
 | 
						EBadtarget                         /* bad attach/detach/replace target */
 | 
				
			||||||
 | 
						ENodevice                          /* no such device in pool */
 | 
				
			||||||
 | 
						EBaddev                            /* invalid device to add */
 | 
				
			||||||
 | 
						ENoreplicas                        /* no valid replicas */
 | 
				
			||||||
 | 
						EResilvering                       /* currently resilvering */
 | 
				
			||||||
 | 
						EBadversion                        /* unsupported version */
 | 
				
			||||||
 | 
						EPoolunavail                       /* pool is currently unavailable */
 | 
				
			||||||
 | 
						EDevoverflow                       /* too many devices in one vdev */
 | 
				
			||||||
 | 
						EBadpath                           /* must be an absolute path */
 | 
				
			||||||
 | 
						ECrosstarget                       /* rename or clone across pool or dataset */
 | 
				
			||||||
 | 
						EZoned                             /* used improperly in local zone */
 | 
				
			||||||
 | 
						EMountfailed                       /* failed to mount dataset */
 | 
				
			||||||
 | 
						EUmountfailed                      /* failed to unmount dataset */
 | 
				
			||||||
 | 
						EUnsharenfsfailed                  /* unshare(1M) failed */
 | 
				
			||||||
 | 
						ESharenfsfailed                    /* share(1M) failed */
 | 
				
			||||||
 | 
						EPerm                              /* permission denied */
 | 
				
			||||||
 | 
						ENospc                             /* out of space */
 | 
				
			||||||
 | 
						EFault                             /* bad address */
 | 
				
			||||||
 | 
						EIo                                /* I/O error */
 | 
				
			||||||
 | 
						EIntr                              /* signal received */
 | 
				
			||||||
 | 
						EIsspare                           /* device is a hot spare */
 | 
				
			||||||
 | 
						EInvalconfig                       /* invalid vdev configuration */
 | 
				
			||||||
 | 
						ERecursive                         /* recursive dependency */
 | 
				
			||||||
 | 
						ENohistory                         /* no history object */
 | 
				
			||||||
 | 
						EPoolprops                         /* couldn't retrieve pool props */
 | 
				
			||||||
 | 
						EPoolNotsup                        /* ops not supported for this type of pool */
 | 
				
			||||||
 | 
						EPoolInvalarg                      /* invalid argument for this pool operation */
 | 
				
			||||||
 | 
						ENametoolong                       /* dataset name is too long */
 | 
				
			||||||
 | 
						EOpenfailed                        /* open of device failed */
 | 
				
			||||||
 | 
						ENocap                             /* couldn't get capacity */
 | 
				
			||||||
 | 
						ELabelfailed                       /* write of label failed */
 | 
				
			||||||
 | 
						EBadwho                            /* invalid permission who */
 | 
				
			||||||
 | 
						EBadperm                           /* invalid permission */
 | 
				
			||||||
 | 
						EBadpermset                        /* invalid permission set name */
 | 
				
			||||||
 | 
						ENodelegation                      /* delegated administration is disabled */
 | 
				
			||||||
 | 
						EUnsharesmbfailed                  /* failed to unshare over smb */
 | 
				
			||||||
 | 
						ESharesmbfailed                    /* failed to share over smb */
 | 
				
			||||||
 | 
						EBadcache                          /* bad cache file */
 | 
				
			||||||
 | 
						EIsl2CACHE                         /* device is for the level 2 ARC */
 | 
				
			||||||
 | 
						EVdevnotsup                        /* unsupported vdev type */
 | 
				
			||||||
 | 
						ENotsup                            /* ops not supported on this dataset */
 | 
				
			||||||
 | 
						EActiveSpare                       /* pool has active shared spare devices */
 | 
				
			||||||
 | 
						EUnplayedLogs                      /* log device has unplayed logs */
 | 
				
			||||||
 | 
						EReftagRele                        /* snapshot release: tag not found */
 | 
				
			||||||
 | 
						EReftagHold                        /* snapshot hold: tag already exists */
 | 
				
			||||||
 | 
						ETagtoolong                        /* snapshot hold/rele: tag too long */
 | 
				
			||||||
 | 
						EPipefailed                        /* pipe create failed */
 | 
				
			||||||
 | 
						EThreadcreatefailed                /* thread create failed */
 | 
				
			||||||
 | 
						EPostsplitOnline                   /* onlining a disk after splitting it */
 | 
				
			||||||
 | 
						EScrubbing                         /* currently scrubbing */
 | 
				
			||||||
 | 
						ENoScrub                           /* no active scrub */
 | 
				
			||||||
 | 
						EDiff                              /* general failure of zfs diff */
 | 
				
			||||||
 | 
						EDiffdata                          /* bad zfs diff data */
 | 
				
			||||||
 | 
						EPoolreadonly                      /* pool is in read-only mode */
 | 
				
			||||||
 | 
						EUnknown
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								zfs.c
								
								
								
								
							
							
						
						
									
										4
									
								
								zfs.c
								
								
								
								
							| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
/* C wrappers around some zfs calls and C in general that should simplify
 | 
					/* C wrappers around some zfs calls and C in general that should simplify
 | 
				
			||||||
 * using libzfs from go language, make go code shorter and more readable.
 | 
					 * using libzfs from go language, make go code shorter and more readable.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
					
 | 
				
			||||||
#include <libzfs.h>
 | 
					#include <libzfs.h>
 | 
				
			||||||
#include <memory.h>
 | 
					#include <memory.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) {
 | 
				
			||||||
	zprop_source_t source;
 | 
						zprop_source_t source;
 | 
				
			||||||
	char statbuf[INT_MAX_VALUE];
 | 
						char statbuf[INT_MAX_VALUE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r = zfs_prop_get(zh, prop, 
 | 
						r = zfs_prop_get(zh, prop,
 | 
				
			||||||
		list->value, INT_MAX_VALUE, &source, statbuf, INT_MAX_VALUE, 1);
 | 
							list->value, INT_MAX_VALUE, &source, statbuf, INT_MAX_VALUE, 1);
 | 
				
			||||||
	if (r == 0) {
 | 
						if (r == 0) {
 | 
				
			||||||
		// strcpy(list->name, zpool_prop_to_name(prop));
 | 
							// strcpy(list->name, zpool_prop_to_name(prop));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										112
									
								
								zfs.go
								
								
								
								
							
							
						
						
									
										112
									
								
								zfs.go
								
								
								
								
							| 
						 | 
					@ -14,20 +14,30 @@ const (
 | 
				
			||||||
	msgDatasetIsNil = "Dataset handle not initialized or its closed"
 | 
						msgDatasetIsNil = "Dataset handle not initialized or its closed"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DatasetProperties type is map of dataset or volume properties prop -> value
 | 
				
			||||||
 | 
					type DatasetProperties map[Prop]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DatasetType defines enum of dataset types
 | 
				
			||||||
type DatasetType int32
 | 
					type DatasetType int32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 | 
						// DatasetTypeFilesystem - file system dataset
 | 
				
			||||||
	DatasetTypeFilesystem DatasetType = (1 << 0)
 | 
						DatasetTypeFilesystem DatasetType = (1 << 0)
 | 
				
			||||||
	DatasetTypeSnapshot               = (1 << 1)
 | 
						// DatasetTypeSnapshot - snapshot of dataset
 | 
				
			||||||
	DatasetTypeVolume                 = (1 << 2)
 | 
						DatasetTypeSnapshot = (1 << 1)
 | 
				
			||||||
	DatasetTypePool                   = (1 << 3)
 | 
						// DatasetTypeVolume - volume (virtual block device) dataset
 | 
				
			||||||
	DatasetTypeBookmark               = (1 << 4)
 | 
						DatasetTypeVolume = (1 << 2)
 | 
				
			||||||
 | 
						// DatasetTypePool - pool dataset
 | 
				
			||||||
 | 
						DatasetTypePool = (1 << 3)
 | 
				
			||||||
 | 
						// DatasetTypeBookmark - bookmark dataset
 | 
				
			||||||
 | 
						DatasetTypeBookmark = (1 << 4)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Dataset - ZFS dataset object
 | 
				
			||||||
type Dataset struct {
 | 
					type Dataset struct {
 | 
				
			||||||
	list       *C.dataset_list_t
 | 
						list       *C.dataset_list_t
 | 
				
			||||||
	Type       DatasetType
 | 
						Type       DatasetType
 | 
				
			||||||
	Properties map[ZFSProp]Property
 | 
						Properties map[Prop]Property
 | 
				
			||||||
	Children   []Dataset
 | 
						Children   []Dataset
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +47,7 @@ func (d *Dataset) openChildren() (err error) {
 | 
				
			||||||
	errcode := C.dataset_list_children(d.list.zh, &(dataset.list))
 | 
						errcode := C.dataset_list_children(d.list.zh, &(dataset.list))
 | 
				
			||||||
	for dataset.list != nil {
 | 
						for dataset.list != nil {
 | 
				
			||||||
		dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
 | 
							dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
 | 
				
			||||||
		dataset.Properties = make(map[ZFSProp]Property)
 | 
							dataset.Properties = make(map[Prop]Property)
 | 
				
			||||||
		err = dataset.ReloadProperties()
 | 
							err = dataset.ReloadProperties()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
| 
						 | 
					@ -49,7 +59,7 @@ func (d *Dataset) openChildren() (err error) {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for ci, _ := range d.Children {
 | 
						for ci := range d.Children {
 | 
				
			||||||
		if err = d.Children[ci].openChildren(); err != nil {
 | 
							if err = d.Children[ci].openChildren(); err != nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -57,11 +67,11 @@ func (d *Dataset) openChildren() (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Recursive get handles to all available datasets on system
 | 
					// DatasetOpenAll recursive get handles to all available datasets on system
 | 
				
			||||||
// (file-systems, volumes or snapshots).
 | 
					// (file-systems, volumes or snapshots).
 | 
				
			||||||
func DatasetOpenAll() (datasets []Dataset, err error) {
 | 
					func DatasetOpenAll() (datasets []Dataset, err error) {
 | 
				
			||||||
	var dataset Dataset
 | 
						var dataset Dataset
 | 
				
			||||||
	errcode := C.dataset_list_root(libzfs_handle, &dataset.list)
 | 
						errcode := C.dataset_list_root(libzfsHandle, &dataset.list)
 | 
				
			||||||
	for dataset.list != nil {
 | 
						for dataset.list != nil {
 | 
				
			||||||
		dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
 | 
							dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
 | 
				
			||||||
		err = dataset.ReloadProperties()
 | 
							err = dataset.ReloadProperties()
 | 
				
			||||||
| 
						 | 
					@ -75,7 +85,7 @@ func DatasetOpenAll() (datasets []Dataset, err error) {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for ci, _ := range datasets {
 | 
						for ci := range datasets {
 | 
				
			||||||
		if err = datasets[ci].openChildren(); err != nil {
 | 
							if err = datasets[ci].openChildren(); err != nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -83,24 +93,25 @@ func DatasetOpenAll() (datasets []Dataset, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Close all datasets in slice and all of its recursive children datasets
 | 
					// DatasetCloseAll close all datasets in slice and all of its recursive
 | 
				
			||||||
 | 
					// children datasets
 | 
				
			||||||
func DatasetCloseAll(datasets []Dataset) {
 | 
					func DatasetCloseAll(datasets []Dataset) {
 | 
				
			||||||
	for _, d := range datasets {
 | 
						for _, d := range datasets {
 | 
				
			||||||
		d.Close()
 | 
							d.Close()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Open dataset and all of its recursive children datasets
 | 
					// DatasetOpen open dataset and all of its recursive children datasets
 | 
				
			||||||
func DatasetOpen(path string) (d Dataset, err error) {
 | 
					func DatasetOpen(path string) (d Dataset, err error) {
 | 
				
			||||||
	d.list = C.create_dataset_list_item()
 | 
						d.list = C.create_dataset_list_item()
 | 
				
			||||||
	d.list.zh = C.zfs_open(libzfs_handle, C.CString(path), 0xF)
 | 
						d.list.zh = C.zfs_open(libzfsHandle, C.CString(path), 0xF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if d.list.zh == nil {
 | 
						if d.list.zh == nil {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.Type = DatasetType(C.zfs_get_type(d.list.zh))
 | 
						d.Type = DatasetType(C.zfs_get_type(d.list.zh))
 | 
				
			||||||
	d.Properties = make(map[ZFSProp]Property)
 | 
						d.Properties = make(map[Prop]Property)
 | 
				
			||||||
	err = d.ReloadProperties()
 | 
						err = d.ReloadProperties()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -109,7 +120,7 @@ func DatasetOpen(path string) (d Dataset, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func datasetPropertiesTo_nvlist(props map[ZFSProp]Property) (
 | 
					func datasetPropertiesTonvlist(props map[Prop]Property) (
 | 
				
			||||||
	cprops *C.nvlist_t, err error) {
 | 
						cprops *C.nvlist_t, err error) {
 | 
				
			||||||
	// convert properties to nvlist C type
 | 
						// convert properties to nvlist C type
 | 
				
			||||||
	r := C.nvlist_alloc(&cprops, C.NV_UNIQUE_NAME, 0)
 | 
						r := C.nvlist_alloc(&cprops, C.NV_UNIQUE_NAME, 0)
 | 
				
			||||||
| 
						 | 
					@ -129,16 +140,17 @@ func datasetPropertiesTo_nvlist(props map[ZFSProp]Property) (
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create a new filesystem or volume on path representing pool/dataset or pool/parent/dataset
 | 
					// DatasetCreate create a new filesystem or volume on path representing
 | 
				
			||||||
 | 
					// pool/dataset or pool/parent/dataset
 | 
				
			||||||
func DatasetCreate(path string, dtype DatasetType,
 | 
					func DatasetCreate(path string, dtype DatasetType,
 | 
				
			||||||
	props map[ZFSProp]Property) (d Dataset, err error) {
 | 
						props map[Prop]Property) (d Dataset, err error) {
 | 
				
			||||||
	var cprops *C.nvlist_t
 | 
						var cprops *C.nvlist_t
 | 
				
			||||||
	if cprops, err = datasetPropertiesTo_nvlist(props); err != nil {
 | 
						if cprops, err = datasetPropertiesTonvlist(props); err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer C.nvlist_free(cprops)
 | 
						defer C.nvlist_free(cprops)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	errcode := C.zfs_create(libzfs_handle, C.CString(path),
 | 
						errcode := C.zfs_create(libzfsHandle, C.CString(path),
 | 
				
			||||||
		C.zfs_type_t(dtype), cprops)
 | 
							C.zfs_type_t(dtype), cprops)
 | 
				
			||||||
	if errcode != 0 {
 | 
						if errcode != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
| 
						 | 
					@ -146,7 +158,8 @@ func DatasetCreate(path string, dtype DatasetType,
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Close dataset and all its recursive children datasets (close handle and cleanup dataset object/s from memory)
 | 
					// Close close dataset and all its recursive children datasets (close handle
 | 
				
			||||||
 | 
					// and cleanup dataset object/s from memory)
 | 
				
			||||||
func (d *Dataset) Close() {
 | 
					func (d *Dataset) Close() {
 | 
				
			||||||
	if d.list != nil && d.list.zh != nil {
 | 
						if d.list != nil && d.list.zh != nil {
 | 
				
			||||||
		C.dataset_list_close(d.list)
 | 
							C.dataset_list_close(d.list)
 | 
				
			||||||
| 
						 | 
					@ -156,7 +169,7 @@ func (d *Dataset) Close() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Destroys the dataset.  The caller must make sure that the filesystem
 | 
					// Destroy destroys the dataset.  The caller must make sure that the filesystem
 | 
				
			||||||
// isn't mounted, and that there are no active dependents. Set Defer argument
 | 
					// isn't mounted, and that there are no active dependents. Set Defer argument
 | 
				
			||||||
// to true to defer destruction for when dataset is not in use.
 | 
					// to true to defer destruction for when dataset is not in use.
 | 
				
			||||||
func (d *Dataset) Destroy(Defer bool) (err error) {
 | 
					func (d *Dataset) Destroy(Defer bool) (err error) {
 | 
				
			||||||
| 
						 | 
					@ -165,13 +178,13 @@ func (d *Dataset) Destroy(Defer bool) (err error) {
 | 
				
			||||||
		if e != nil {
 | 
							if e != nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		dsType, e := d.GetProperty(ZFSPropType)
 | 
							dsType, e := d.GetProperty(DatasetPropType)
 | 
				
			||||||
		err = errors.New("Cannot destroy dataset " + path +
 | 
							err = errors.New("Cannot destroy dataset " + path +
 | 
				
			||||||
			": " + dsType.Value + " has children")
 | 
								": " + dsType.Value + " has children")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if d.list != nil {
 | 
						if d.list != nil {
 | 
				
			||||||
		if ec := C.zfs_destroy(d.list.zh, boolean_t(Defer)); ec != 0 {
 | 
							if ec := C.zfs_destroy(d.list.zh, booleanT(Defer)); ec != 0 {
 | 
				
			||||||
			err = LastError()
 | 
								err = LastError()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -180,7 +193,7 @@ func (d *Dataset) Destroy(Defer bool) (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Recursively destroy children of dataset and dataset.
 | 
					// DestroyRecursive recursively destroy children of dataset and dataset.
 | 
				
			||||||
func (d *Dataset) DestroyRecursive() (err error) {
 | 
					func (d *Dataset) DestroyRecursive() (err error) {
 | 
				
			||||||
	if len(d.Children) > 0 {
 | 
						if len(d.Children) > 0 {
 | 
				
			||||||
		for _, c := range d.Children {
 | 
							for _, c := range d.Children {
 | 
				
			||||||
| 
						 | 
					@ -197,6 +210,7 @@ func (d *Dataset) DestroyRecursive() (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pool returns pool dataset belongs to
 | 
				
			||||||
func (d *Dataset) Pool() (p Pool, err error) {
 | 
					func (d *Dataset) Pool() (p Pool, err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
| 
						 | 
					@ -212,6 +226,7 @@ func (d *Dataset) Pool() (p Pool, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReloadProperties re-read dataset's properties
 | 
				
			||||||
func (d *Dataset) ReloadProperties() (err error) {
 | 
					func (d *Dataset) ReloadProperties() (err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
| 
						 | 
					@ -220,8 +235,8 @@ func (d *Dataset) ReloadProperties() (err error) {
 | 
				
			||||||
	var plist *C.property_list_t
 | 
						var plist *C.property_list_t
 | 
				
			||||||
	plist = C.new_property_list()
 | 
						plist = C.new_property_list()
 | 
				
			||||||
	defer C.free_properties(plist)
 | 
						defer C.free_properties(plist)
 | 
				
			||||||
	d.Properties = make(map[ZFSProp]Property)
 | 
						d.Properties = make(map[Prop]Property)
 | 
				
			||||||
	for prop := ZFSPropType; prop < ZFSNumProps; prop++ {
 | 
						for prop := DatasetPropType; prop < DatasetNumProps; prop++ {
 | 
				
			||||||
		errcode := C.read_dataset_property(d.list.zh, plist, C.int(prop))
 | 
							errcode := C.read_dataset_property(d.list.zh, plist, C.int(prop))
 | 
				
			||||||
		if errcode != 0 {
 | 
							if errcode != 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
| 
						 | 
					@ -232,9 +247,9 @@ func (d *Dataset) ReloadProperties() (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Reload and return single specified property. This also reloads requested
 | 
					// GetProperty reload and return single specified property. This also reloads requested
 | 
				
			||||||
// property in Properties map.
 | 
					// property in Properties map.
 | 
				
			||||||
func (d *Dataset) GetProperty(p ZFSProp) (prop Property, err error) {
 | 
					func (d *Dataset) GetProperty(p Prop) (prop Property, err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -253,10 +268,10 @@ func (d *Dataset) GetProperty(p ZFSProp) (prop Property, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Set ZFS dataset property to value. Not all properties can be set,
 | 
					// SetProperty set ZFS dataset property to value. Not all properties can be set,
 | 
				
			||||||
// some can be set only at creation time and some are read only.
 | 
					// some can be set only at creation time and some are read only.
 | 
				
			||||||
// Always check if returned error and its description.
 | 
					// Always check if returned error and its description.
 | 
				
			||||||
func (d *Dataset) SetProperty(p ZFSProp, value string) (err error) {
 | 
					func (d *Dataset) SetProperty(p Prop, value string) (err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -273,15 +288,15 @@ func (d *Dataset) SetProperty(p ZFSProp, value string) (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clones the dataset.  The target must be of the same type as
 | 
					// Clone - clones the dataset.  The target must be of the same type as
 | 
				
			||||||
// the source.
 | 
					// the source.
 | 
				
			||||||
func (d *Dataset) Clone(target string, props map[ZFSProp]Property) (rd Dataset, err error) {
 | 
					func (d *Dataset) Clone(target string, props map[Prop]Property) (rd Dataset, err error) {
 | 
				
			||||||
	var cprops *C.nvlist_t
 | 
						var cprops *C.nvlist_t
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if cprops, err = datasetPropertiesTo_nvlist(props); err != nil {
 | 
						if cprops, err = datasetPropertiesTonvlist(props); err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer C.nvlist_free(cprops)
 | 
						defer C.nvlist_free(cprops)
 | 
				
			||||||
| 
						 | 
					@ -293,14 +308,14 @@ func (d *Dataset) Clone(target string, props map[ZFSProp]Property) (rd Dataset,
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create dataset snapshot. Set recur to true to snapshot child datasets.
 | 
					// DatasetSnapshot create dataset snapshot. Set recur to true to snapshot child datasets.
 | 
				
			||||||
func DatasetSnapshot(path string, recur bool, props map[ZFSProp]Property) (rd Dataset, err error) {
 | 
					func DatasetSnapshot(path string, recur bool, props map[Prop]Property) (rd Dataset, err error) {
 | 
				
			||||||
	var cprops *C.nvlist_t
 | 
						var cprops *C.nvlist_t
 | 
				
			||||||
	if cprops, err = datasetPropertiesTo_nvlist(props); err != nil {
 | 
						if cprops, err = datasetPropertiesTonvlist(props); err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer C.nvlist_free(cprops)
 | 
						defer C.nvlist_free(cprops)
 | 
				
			||||||
	if errc := C.zfs_snapshot(libzfs_handle, C.CString(path), boolean_t(recur), cprops); errc != 0 {
 | 
						if errc := C.zfs_snapshot(libzfsHandle, C.CString(path), booleanT(recur), cprops); errc != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -308,7 +323,7 @@ func DatasetSnapshot(path string, recur bool, props map[ZFSProp]Property) (rd Da
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Return zfs dataset path/name
 | 
					// Path return zfs dataset path/name
 | 
				
			||||||
func (d *Dataset) Path() (path string, err error) {
 | 
					func (d *Dataset) Path() (path string, err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
| 
						 | 
					@ -319,14 +334,14 @@ func (d *Dataset) Path() (path string, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Rollabck dataset snapshot
 | 
					// Rollback rollabck's dataset snapshot
 | 
				
			||||||
func (d *Dataset) Rollback(snap *Dataset, force bool) (err error) {
 | 
					func (d *Dataset) Rollback(snap *Dataset, force bool) (err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if errc := C.zfs_rollback(d.list.zh,
 | 
						if errc := C.zfs_rollback(d.list.zh,
 | 
				
			||||||
		snap.list.zh, boolean_t(force)); errc != 0 {
 | 
							snap.list.zh, booleanT(force)); errc != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
| 
						 | 
					@ -334,20 +349,20 @@ func (d *Dataset) Rollback(snap *Dataset, force bool) (err error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Rename dataset
 | 
					// Rename dataset
 | 
				
			||||||
func (d *Dataset) Rename(newname string, recur,
 | 
					func (d *Dataset) Rename(newname string, recur,
 | 
				
			||||||
	force_umount bool) (err error) {
 | 
						forceUnmount bool) (err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if errc := C.zfs_rename(d.list.zh, C.CString(newname),
 | 
						if errc := C.zfs_rename(d.list.zh, C.CString(newname),
 | 
				
			||||||
		boolean_t(recur), boolean_t(force_umount)); errc != 0 {
 | 
							booleanT(recur), booleanT(forceUnmount)); errc != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Checks to see if the mount is active.  If the filesystem is mounted, fills
 | 
					// IsMounted checks to see if the mount is active.  If the filesystem is mounted,
 | 
				
			||||||
// in 'where' with the current mountpoint, and returns true.  Otherwise,
 | 
					// sets in 'where' argument the current mountpoint, and returns true.  Otherwise,
 | 
				
			||||||
// returns false.
 | 
					// returns false.
 | 
				
			||||||
func (d *Dataset) IsMounted() (mounted bool, where string) {
 | 
					func (d *Dataset) IsMounted() (mounted bool, where string) {
 | 
				
			||||||
	var cw *C.char
 | 
						var cw *C.char
 | 
				
			||||||
| 
						 | 
					@ -386,7 +401,8 @@ func (d *Dataset) Unmount(flags int) (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Unmount this filesystem and any children inheriting the mountpoint property.
 | 
					// UnmountAll unmount this filesystem and any children inheriting the
 | 
				
			||||||
 | 
					// mountpoint property.
 | 
				
			||||||
func (d *Dataset) UnmountAll(flags int) (err error) {
 | 
					func (d *Dataset) UnmountAll(flags int) (err error) {
 | 
				
			||||||
	if d.list == nil {
 | 
						if d.list == nil {
 | 
				
			||||||
		err = errors.New(msgDatasetIsNil)
 | 
							err = errors.New(msgDatasetIsNil)
 | 
				
			||||||
| 
						 | 
					@ -398,12 +414,12 @@ func (d *Dataset) UnmountAll(flags int) (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Convert property to name
 | 
					// DatasetPropertyToName convert property to name
 | 
				
			||||||
// ( returns built in string representation of property name).
 | 
					// ( returns built in string representation of property name).
 | 
				
			||||||
// This is optional, you can represent each property with string
 | 
					// This is optional, you can represent each property with string
 | 
				
			||||||
// name of choice.
 | 
					// name of choice.
 | 
				
			||||||
func DatasetPropertyToName(p ZFSProp) (name string) {
 | 
					func DatasetPropertyToName(p Prop) (name string) {
 | 
				
			||||||
	if p == ZFSNumProps {
 | 
						if p == DatasetNumProps {
 | 
				
			||||||
		return "numofprops"
 | 
							return "numofprops"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	prop := C.zfs_prop_t(p)
 | 
						prop := C.zfs_prop_t(p)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										74
									
								
								zfs_test.go
								
								
								
								
							
							
						
						
									
										74
									
								
								zfs_test.go
								
								
								
								
							| 
						 | 
					@ -2,15 +2,16 @@ package zfs_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/bicomsystems/go-libzfs"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/bicomsystems/go-libzfs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------------------- */
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
// HELPERS:
 | 
					// HELPERS:
 | 
				
			||||||
var TST_DATASET_PATH = TST_POOL_NAME + "/DATASET"
 | 
					var TSTDatasetPath = TSTPoolName + "/DATASET"
 | 
				
			||||||
var TST_VOLUME_PATH = TST_DATASET_PATH + "/VOLUME"
 | 
					var TSTVolumePath = TSTDatasetPath + "/VOLUME"
 | 
				
			||||||
var TST_DATASET_PATH_SNAP = TST_DATASET_PATH + "@test"
 | 
					var TSTDatasetPathSnap = TSTDatasetPath + "@test"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func printDatasets(ds []zfs.Dataset) error {
 | 
					func printDatasets(ds []zfs.Dataset) error {
 | 
				
			||||||
	for _, d := range ds {
 | 
						for _, d := range ds {
 | 
				
			||||||
| 
						 | 
					@ -19,7 +20,7 @@ func printDatasets(ds []zfs.Dataset) error {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		p, err := d.GetProperty(zfs.ZFSPropType)
 | 
							p, err := d.GetProperty(zfs.DatasetPropType)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -36,45 +37,45 @@ func printDatasets(ds []zfs.Dataset) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zfsTestDatasetCreate(t *testing.T) {
 | 
					func zfsTestDatasetCreate(t *testing.T) {
 | 
				
			||||||
	// reinit names used in case TESTPOOL was in conflict
 | 
						// reinit names used in case TESTPOOL was in conflict
 | 
				
			||||||
	TST_DATASET_PATH = TST_POOL_NAME + "/DATASET"
 | 
						TSTDatasetPath = TSTPoolName + "/DATASET"
 | 
				
			||||||
	TST_VOLUME_PATH = TST_DATASET_PATH + "/VOLUME"
 | 
						TSTVolumePath = TSTDatasetPath + "/VOLUME"
 | 
				
			||||||
	TST_DATASET_PATH_SNAP = TST_DATASET_PATH + "@test"
 | 
						TSTDatasetPathSnap = TSTDatasetPath + "@test"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	println("TEST DatasetCreate(", TST_DATASET_PATH, ") (filesystem) ... ")
 | 
						println("TEST DatasetCreate(", TSTDatasetPath, ") (filesystem) ... ")
 | 
				
			||||||
	props := make(map[zfs.ZFSProp]zfs.Property)
 | 
						props := make(map[zfs.Prop]zfs.Property)
 | 
				
			||||||
	d, err := zfs.DatasetCreate(TST_DATASET_PATH, zfs.DatasetTypeFilesystem, props)
 | 
						d, err := zfs.DatasetCreate(TSTDatasetPath, zfs.DatasetTypeFilesystem, props)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.Close()
 | 
						d.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	strSize := "536870912" // 512M
 | 
						strSize := "536870912" // 512M
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	println("TEST DatasetCreate(", TST_VOLUME_PATH, ") (volume) ... ")
 | 
						println("TEST DatasetCreate(", TSTVolumePath, ") (volume) ... ")
 | 
				
			||||||
	props[zfs.ZFSPropVolsize] = zfs.Property{Value: strSize}
 | 
						props[zfs.DatasetPropVolsize] = zfs.Property{Value: strSize}
 | 
				
			||||||
	// In addition I explicitly choose some more properties to be set.
 | 
						// In addition I explicitly choose some more properties to be set.
 | 
				
			||||||
	props[zfs.ZFSPropVolblocksize] = zfs.Property{Value: "4096"}
 | 
						props[zfs.DatasetPropVolblocksize] = zfs.Property{Value: "4096"}
 | 
				
			||||||
	props[zfs.ZFSPropReservation] = zfs.Property{Value: strSize}
 | 
						props[zfs.DatasetPropReservation] = zfs.Property{Value: strSize}
 | 
				
			||||||
	d, err = zfs.DatasetCreate(TST_VOLUME_PATH, zfs.DatasetTypeVolume, props)
 | 
						d, err = zfs.DatasetCreate(TSTVolumePath, zfs.DatasetTypeVolume, props)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.Close()
 | 
						d.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zfsTestDatasetOpen(t *testing.T) {
 | 
					func zfsTestDatasetOpen(t *testing.T) {
 | 
				
			||||||
	println("TEST DatasetOpen(", TST_DATASET_PATH, ") ... ")
 | 
						println("TEST DatasetOpen(", TSTDatasetPath, ") ... ")
 | 
				
			||||||
	d, err := zfs.DatasetOpen(TST_DATASET_PATH)
 | 
						d, err := zfs.DatasetOpen(TSTDatasetPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.Close()
 | 
						d.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zfsTestDatasetOpenAll(t *testing.T) {
 | 
					func zfsTestDatasetOpenAll(t *testing.T) {
 | 
				
			||||||
| 
						 | 
					@ -90,24 +91,24 @@ func zfsTestDatasetOpenAll(t *testing.T) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	zfs.DatasetCloseAll(ds)
 | 
						zfs.DatasetCloseAll(ds)
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zfsTestDatasetSnapshot(t *testing.T) {
 | 
					func zfsTestDatasetSnapshot(t *testing.T) {
 | 
				
			||||||
	println("TEST DatasetSnapshot(", TST_DATASET_PATH, ", true, ...) ... ")
 | 
						println("TEST DatasetSnapshot(", TSTDatasetPath, ", true, ...) ... ")
 | 
				
			||||||
	props := make(map[zfs.ZFSProp]zfs.Property)
 | 
						props := make(map[zfs.Prop]zfs.Property)
 | 
				
			||||||
	d, err := zfs.DatasetSnapshot(TST_DATASET_PATH_SNAP, true, props)
 | 
						d, err := zfs.DatasetSnapshot(TSTDatasetPathSnap, true, props)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer d.Close()
 | 
						defer d.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zfsTestDatasetDestroy(t *testing.T) {
 | 
					func zfsTestDatasetDestroy(t *testing.T) {
 | 
				
			||||||
	println("TEST DATASET Destroy( ", TST_DATASET_PATH, " ) ... ")
 | 
						println("TEST DATASET Destroy( ", TSTDatasetPath, " ) ... ")
 | 
				
			||||||
	d, err := zfs.DatasetOpen(TST_DATASET_PATH)
 | 
						d, err := zfs.DatasetOpen(TSTDatasetPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -117,7 +118,7 @@ func zfsTestDatasetDestroy(t *testing.T) {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------------------- */
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -128,7 +129,7 @@ func ExampleDatasetCreate() {
 | 
				
			||||||
	// Create map to represent ZFS dataset properties. This is equivalent to
 | 
						// Create map to represent ZFS dataset properties. This is equivalent to
 | 
				
			||||||
	// list of properties you can get from ZFS CLI tool, and some more
 | 
						// list of properties you can get from ZFS CLI tool, and some more
 | 
				
			||||||
	// internally used by libzfs.
 | 
						// internally used by libzfs.
 | 
				
			||||||
	props := make(map[zfs.ZFSProp]zfs.Property)
 | 
						props := make(map[zfs.Prop]zfs.Property)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// I choose to create (block) volume 1GiB in size. Size is just ZFS dataset
 | 
						// I choose to create (block) volume 1GiB in size. Size is just ZFS dataset
 | 
				
			||||||
	// property and this is done as map of strings. So, You have to either
 | 
						// property and this is done as map of strings. So, You have to either
 | 
				
			||||||
| 
						 | 
					@ -136,10 +137,10 @@ func ExampleDatasetCreate() {
 | 
				
			||||||
	// similar to convert in to string (base 10) from numeric type.
 | 
						// similar to convert in to string (base 10) from numeric type.
 | 
				
			||||||
	strSize := "1073741824"
 | 
						strSize := "1073741824"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	props[zfs.ZFSPropVolsize] = zfs.Property{Value: strSize}
 | 
						props[zfs.DatasetPropVolsize] = zfs.Property{Value: strSize}
 | 
				
			||||||
	// In addition I explicitly choose some more properties to be set.
 | 
						// In addition I explicitly choose some more properties to be set.
 | 
				
			||||||
	props[zfs.ZFSPropVolblocksize] = zfs.Property{Value: "4096"}
 | 
						props[zfs.DatasetPropVolblocksize] = zfs.Property{Value: "4096"}
 | 
				
			||||||
	props[zfs.ZFSPropReservation] = zfs.Property{Value: strSize}
 | 
						props[zfs.DatasetPropReservation] = zfs.Property{Value: strSize}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Lets create desired volume
 | 
						// Lets create desired volume
 | 
				
			||||||
	d, err := zfs.DatasetCreate("TESTPOOL/VOLUME1", zfs.DatasetTypeVolume, props)
 | 
						d, err := zfs.DatasetCreate("TESTPOOL/VOLUME1", zfs.DatasetTypeVolume, props)
 | 
				
			||||||
| 
						 | 
					@ -161,10 +162,11 @@ func ExampleDatasetOpen() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer d.Close()
 | 
						defer d.Close()
 | 
				
			||||||
	var p zfs.Property
 | 
						var p zfs.Property
 | 
				
			||||||
	if p, err = d.GetProperty(zfs.ZFSPropAvailable); err != nil {
 | 
						if p, err = d.GetProperty(zfs.DatasetPropAvailable); err != nil {
 | 
				
			||||||
		panic(err.Error())
 | 
							panic(err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	println(zfs.DatasetPropertyToName(zfs.ZFSPropAvailable), " = ", p.Value)
 | 
						println(zfs.DatasetPropertyToName(zfs.DatasetPropAvailable), " = ",
 | 
				
			||||||
 | 
							p.Value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ExampleDatasetOpenAll() {
 | 
					func ExampleDatasetOpenAll() {
 | 
				
			||||||
| 
						 | 
					@ -180,7 +182,7 @@ func ExampleDatasetOpenAll() {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			panic(err.Error())
 | 
								panic(err.Error())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		p, err := d.GetProperty(zfs.ZFSPropType)
 | 
							p, err := d.GetProperty(zfs.DatasetPropType)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			panic(err.Error())
 | 
								panic(err.Error())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										123
									
								
								zpool.go
								
								
								
								
							
							
						
						
									
										123
									
								
								zpool.go
								
								
								
								
							| 
						 | 
					@ -10,16 +10,17 @@ import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	msgPoolIsNil = "Pool handle not initialized or its closed"
 | 
						msgPoolIsNil = "Pool handle not initialized or its closed"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PoolProperties map[PoolProp]string
 | 
					// PoolProperties type is map of pool properties name -> value
 | 
				
			||||||
type ZFSProperties map[ZFSProp]string
 | 
					type PoolProperties map[Prop]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Object represents handler to single ZFS pool
 | 
					// Pool object represents handler to single ZFS pool
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
/* Pool.Properties map[string]Property
 | 
					/* Pool.Properties map[string]Property
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -34,11 +35,11 @@ type Pool struct {
 | 
				
			||||||
	Features   map[string]string
 | 
						Features   map[string]string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Open ZFS pool handler by name.
 | 
					// PoolOpen open ZFS pool handler by name.
 | 
				
			||||||
// Returns Pool object, requires Pool.Close() to be called explicitly
 | 
					// Returns Pool object, requires Pool.Close() to be called explicitly
 | 
				
			||||||
// for memory cleanup after object is not needed anymore.
 | 
					// for memory cleanup after object is not needed anymore.
 | 
				
			||||||
func PoolOpen(name string) (pool Pool, err error) {
 | 
					func PoolOpen(name string) (pool Pool, err error) {
 | 
				
			||||||
	pool.list = C.zpool_list_open(libzfs_handle, C.CString(name))
 | 
						pool.list = C.zpool_list_open(libzfsHandle, C.CString(name))
 | 
				
			||||||
	if pool.list != nil {
 | 
						if pool.list != nil {
 | 
				
			||||||
		err = pool.ReloadProperties()
 | 
							err = pool.ReloadProperties()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -47,7 +48,7 @@ func PoolOpen(name string) (pool Pool, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Given a list of directories to search, find and import pool with matching
 | 
					// PoolImport given a list of directories to search, find and import pool with matching
 | 
				
			||||||
// name stored on disk.
 | 
					// name stored on disk.
 | 
				
			||||||
func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
 | 
					func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
 | 
				
			||||||
	errPoolList := errors.New("Failed to list pools")
 | 
						errPoolList := errors.New("Failed to list pools")
 | 
				
			||||||
| 
						 | 
					@ -59,7 +60,7 @@ func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
 | 
				
			||||||
		C.strings_setat(cpaths, C.int(i), C.CString(path))
 | 
							C.strings_setat(cpaths, C.int(i), C.CString(path))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pools := C.zpool_find_import(libzfs_handle, C.int(numofp), cpaths)
 | 
						pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths)
 | 
				
			||||||
	defer C.nvlist_free(pools)
 | 
						defer C.nvlist_free(pools)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem = C.nvlist_next_nvpair(pools, elem)
 | 
						elem = C.nvlist_next_nvpair(pools, elem)
 | 
				
			||||||
| 
						 | 
					@ -88,7 +89,7 @@ func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retcode := C.zpool_import(libzfs_handle, config, C.CString(name), nil)
 | 
						retcode := C.zpool_import(libzfsHandle, config, C.CString(name), nil)
 | 
				
			||||||
	if retcode != 0 {
 | 
						if retcode != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -97,12 +98,12 @@ func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Open all active ZFS pools on current system.
 | 
					// PoolOpenAll open all active ZFS pools on current system.
 | 
				
			||||||
// Returns array of Pool handlers, each have to be closed after not needed
 | 
					// Returns array of Pool handlers, each have to be closed after not needed
 | 
				
			||||||
// anymore. Call Pool.Close() method.
 | 
					// anymore. Call Pool.Close() method.
 | 
				
			||||||
func PoolOpenAll() (pools []Pool, err error) {
 | 
					func PoolOpenAll() (pools []Pool, err error) {
 | 
				
			||||||
	var pool Pool
 | 
						var pool Pool
 | 
				
			||||||
	errcode := C.zpool_list(libzfs_handle, &pool.list)
 | 
						errcode := C.zpool_list(libzfsHandle, &pool.list)
 | 
				
			||||||
	for pool.list != nil {
 | 
						for pool.list != nil {
 | 
				
			||||||
		err = pool.ReloadProperties()
 | 
							err = pool.ReloadProperties()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -117,17 +118,18 @@ func PoolOpenAll() (pools []Pool, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PoolCloseAll close all pools in given slice
 | 
				
			||||||
func PoolCloseAll(pools []Pool) {
 | 
					func PoolCloseAll(pools []Pool) {
 | 
				
			||||||
	for _, p := range pools {
 | 
						for _, p := range pools {
 | 
				
			||||||
		p.Close()
 | 
							p.Close()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Convert property to name
 | 
					// PoolPropertyToName convert property to name
 | 
				
			||||||
// ( returns built in string representation of property name).
 | 
					// ( returns built in string representation of property name).
 | 
				
			||||||
// This is optional, you can represent each property with string
 | 
					// This is optional, you can represent each property with string
 | 
				
			||||||
// name of choice.
 | 
					// name of choice.
 | 
				
			||||||
func PoolPropertyToName(p PoolProp) (name string) {
 | 
					func PoolPropertyToName(p Prop) (name string) {
 | 
				
			||||||
	if p == PoolNumProps {
 | 
						if p == PoolNumProps {
 | 
				
			||||||
		return "numofprops"
 | 
							return "numofprops"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -136,15 +138,15 @@ func PoolPropertyToName(p PoolProp) (name string) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Map POOL STATE to string.
 | 
					// PoolStateToName maps POOL STATE to string.
 | 
				
			||||||
func PoolStateToName(state PoolState) (name string) {
 | 
					func PoolStateToName(state PoolState) (name string) {
 | 
				
			||||||
	ps := C.pool_state_t(state)
 | 
						ps := C.pool_state_t(state)
 | 
				
			||||||
	name = C.GoString(C.zpool_pool_state_to_name(ps))
 | 
						name = C.GoString(C.zpool_pool_state_to_name(ps))
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Re-read ZFS pool properties and features, refresh Pool.Properties and
 | 
					// ReloadProperties re-read ZFS pool properties and features, refresh
 | 
				
			||||||
// Pool.Features map
 | 
					// Pool.Properties and Pool.Features map
 | 
				
			||||||
func (pool *Pool) ReloadProperties() (err error) {
 | 
					func (pool *Pool) ReloadProperties() (err error) {
 | 
				
			||||||
	propList := C.read_zpool_properties(pool.list.zph)
 | 
						propList := C.read_zpool_properties(pool.list.zph)
 | 
				
			||||||
	if propList == nil {
 | 
						if propList == nil {
 | 
				
			||||||
| 
						 | 
					@ -165,15 +167,15 @@ func (pool *Pool) ReloadProperties() (err error) {
 | 
				
			||||||
		"async_destroy": "disabled",
 | 
							"async_destroy": "disabled",
 | 
				
			||||||
		"empty_bpobj":   "disabled",
 | 
							"empty_bpobj":   "disabled",
 | 
				
			||||||
		"lz4_compress":  "disabled"}
 | 
							"lz4_compress":  "disabled"}
 | 
				
			||||||
	for name, _ := range pool.Features {
 | 
						for name := range pool.Features {
 | 
				
			||||||
		pool.GetFeature(name)
 | 
							pool.GetFeature(name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Reload and return single specified property. This also reloads requested
 | 
					// GetProperty reload and return single specified property. This also reloads requested
 | 
				
			||||||
// property in Properties map.
 | 
					// property in Properties map.
 | 
				
			||||||
func (pool *Pool) GetProperty(p PoolProp) (prop Property, err error) {
 | 
					func (pool *Pool) GetProperty(p Prop) (prop Property, err error) {
 | 
				
			||||||
	if pool.list != nil {
 | 
						if pool.list != nil {
 | 
				
			||||||
		// First check if property exist at all
 | 
							// First check if property exist at all
 | 
				
			||||||
		if p < PoolPropName || p > PoolNumProps {
 | 
							if p < PoolPropName || p > PoolNumProps {
 | 
				
			||||||
| 
						 | 
					@ -194,7 +196,7 @@ func (pool *Pool) GetProperty(p PoolProp) (prop Property, err error) {
 | 
				
			||||||
	return prop, errors.New(msgPoolIsNil)
 | 
						return prop, errors.New(msgPoolIsNil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Reload and return single specified feature. This also reloads requested
 | 
					// GetFeature reload and return single specified feature. This also reloads requested
 | 
				
			||||||
// feature in Features map.
 | 
					// feature in Features map.
 | 
				
			||||||
func (pool *Pool) GetFeature(name string) (value string, err error) {
 | 
					func (pool *Pool) GetFeature(name string) (value string, err error) {
 | 
				
			||||||
	var fvalue [512]C.char
 | 
						var fvalue [512]C.char
 | 
				
			||||||
| 
						 | 
					@ -209,10 +211,10 @@ func (pool *Pool) GetFeature(name string) (value string, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Set ZFS pool property to value. Not all properties can be set,
 | 
					// SetProperty set ZFS pool property to value. Not all properties can be set,
 | 
				
			||||||
// some can be set only at creation time and some are read only.
 | 
					// some can be set only at creation time and some are read only.
 | 
				
			||||||
// Always check if returned error and its description.
 | 
					// Always check if returned error and its description.
 | 
				
			||||||
func (pool *Pool) SetProperty(p PoolProp, value string) (err error) {
 | 
					func (pool *Pool) SetProperty(p Prop, value string) (err error) {
 | 
				
			||||||
	if pool.list != nil {
 | 
						if pool.list != nil {
 | 
				
			||||||
		// First check if property exist at all
 | 
							// First check if property exist at all
 | 
				
			||||||
		if p < PoolPropName || p > PoolNumProps {
 | 
							if p < PoolPropName || p > PoolNumProps {
 | 
				
			||||||
| 
						 | 
					@ -241,7 +243,7 @@ func (pool *Pool) Close() {
 | 
				
			||||||
	pool.list = nil
 | 
						pool.list = nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get (re-read) ZFS pool name property
 | 
					// Name get (re-read) ZFS pool name property
 | 
				
			||||||
func (pool *Pool) Name() (name string, err error) {
 | 
					func (pool *Pool) Name() (name string, err error) {
 | 
				
			||||||
	if pool.list == nil {
 | 
						if pool.list == nil {
 | 
				
			||||||
		err = errors.New(msgPoolIsNil)
 | 
							err = errors.New(msgPoolIsNil)
 | 
				
			||||||
| 
						 | 
					@ -252,7 +254,7 @@ func (pool *Pool) Name() (name string, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get ZFS pool state
 | 
					// State get ZFS pool state
 | 
				
			||||||
// Return the state of the pool (ACTIVE or UNAVAILABLE)
 | 
					// Return the state of the pool (ACTIVE or UNAVAILABLE)
 | 
				
			||||||
func (pool *Pool) State() (state PoolState, err error) {
 | 
					func (pool *Pool) State() (state PoolState, err error) {
 | 
				
			||||||
	if pool.list == nil {
 | 
						if pool.list == nil {
 | 
				
			||||||
| 
						 | 
					@ -263,7 +265,7 @@ func (pool *Pool) State() (state PoolState, err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ZFS virtual device specification
 | 
					// VDevSpec ZFS virtual device specification
 | 
				
			||||||
type VDevSpec struct {
 | 
					type VDevSpec struct {
 | 
				
			||||||
	Type    VDevType
 | 
						Type    VDevType
 | 
				
			||||||
	Devices []VDevSpec // groups other devices (e.g. mirror)
 | 
						Devices []VDevSpec // groups other devices (e.g. mirror)
 | 
				
			||||||
| 
						 | 
					@ -271,31 +273,31 @@ type VDevSpec struct {
 | 
				
			||||||
	Path    string
 | 
						Path    string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *VDevSpec) isGrouping() (grouping bool, mindevs, maxdevs int) {
 | 
					func (vdev *VDevSpec) isGrouping() (grouping bool, mindevs, maxdevs int) {
 | 
				
			||||||
	maxdevs = int(^uint(0) >> 1)
 | 
						maxdevs = int(^uint(0) >> 1)
 | 
				
			||||||
	if self.Type == VDevTypeRaidz {
 | 
						if vdev.Type == VDevTypeRaidz {
 | 
				
			||||||
		grouping = true
 | 
							grouping = true
 | 
				
			||||||
		if self.Parity == 0 {
 | 
							if vdev.Parity == 0 {
 | 
				
			||||||
			self.Parity = 1
 | 
								vdev.Parity = 1
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if self.Parity > 254 {
 | 
							if vdev.Parity > 254 {
 | 
				
			||||||
			self.Parity = 254
 | 
								vdev.Parity = 254
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		mindevs = int(self.Parity) + 1
 | 
							mindevs = int(vdev.Parity) + 1
 | 
				
			||||||
		maxdevs = 255
 | 
							maxdevs = 255
 | 
				
			||||||
	} else if self.Type == VDevTypeMirror {
 | 
						} else if vdev.Type == VDevTypeMirror {
 | 
				
			||||||
		grouping = true
 | 
							grouping = true
 | 
				
			||||||
		mindevs = 2
 | 
							mindevs = 2
 | 
				
			||||||
	} else if self.Type == VDevTypeLog || self.Type == VDevTypeSpare || self.Type == VDevTypeL2cache {
 | 
						} else if vdev.Type == VDevTypeLog || vdev.Type == VDevTypeSpare || vdev.Type == VDevTypeL2cache {
 | 
				
			||||||
		grouping = true
 | 
							grouping = true
 | 
				
			||||||
		mindevs = 1
 | 
							mindevs = 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *VDevSpec) isLog() (r C.uint64_t) {
 | 
					func (vdev *VDevSpec) isLog() (r C.uint64_t) {
 | 
				
			||||||
	r = 0
 | 
						r = 0
 | 
				
			||||||
	if self.Type == VDevTypeLog {
 | 
						if vdev.Type == VDevTypeLog {
 | 
				
			||||||
		r = 1
 | 
							r = 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
| 
						 | 
					@ -317,7 +319,7 @@ func toCPoolProperties(props PoolProperties) (cprops *C.nvlist_t) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func toCZFSProperties(props ZFSProperties) (cprops *C.nvlist_t) {
 | 
					func toCDatasetProperties(props DatasetProperties) (cprops *C.nvlist_t) {
 | 
				
			||||||
	cprops = nil
 | 
						cprops = nil
 | 
				
			||||||
	for prop, value := range props {
 | 
						for prop, value := range props {
 | 
				
			||||||
		name := C.zfs_prop_to_name(C.zfs_prop_t(prop))
 | 
							name := C.zfs_prop_to_name(C.zfs_prop_t(prop))
 | 
				
			||||||
| 
						 | 
					@ -361,7 +363,7 @@ func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
 | 
				
			||||||
	defer C.nvlist_free_array(l2cache)
 | 
						defer C.nvlist_free_array(l2cache)
 | 
				
			||||||
	for i, vdev := range vdevs {
 | 
						for i, vdev := range vdevs {
 | 
				
			||||||
		grouping, mindevs, maxdevs := vdev.isGrouping()
 | 
							grouping, mindevs, maxdevs := vdev.isGrouping()
 | 
				
			||||||
		var child *C.nvlist_t = nil
 | 
							var child *C.nvlist_t
 | 
				
			||||||
		// fmt.Println(vdev.Type)
 | 
							// fmt.Println(vdev.Type)
 | 
				
			||||||
		if r := C.nvlist_alloc(&child, C.NV_UNIQUE_NAME, 0); r != 0 {
 | 
							if r := C.nvlist_alloc(&child, C.NV_UNIQUE_NAME, 0); r != 0 {
 | 
				
			||||||
			err = errors.New("Failed to allocate vdev")
 | 
								err = errors.New("Failed to allocate vdev")
 | 
				
			||||||
| 
						 | 
					@ -369,8 +371,9 @@ func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		vcount := len(vdev.Devices)
 | 
							vcount := len(vdev.Devices)
 | 
				
			||||||
		if vcount < mindevs || vcount > maxdevs {
 | 
							if vcount < mindevs || vcount > maxdevs {
 | 
				
			||||||
			err = errors.New(fmt.Sprintf(
 | 
								err = fmt.Errorf(
 | 
				
			||||||
				"Invalid vdev specification: %s supports no less than %d or more than %d devices", vdev.Type, mindevs, maxdevs))
 | 
									"Invalid vdev specification: %s supports no less than %d or more than %d devices",
 | 
				
			||||||
 | 
									vdev.Type, mindevs, maxdevs)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if r := C.nvlist_add_string(child, C.CString(C.ZPOOL_CONFIG_TYPE),
 | 
							if r := C.nvlist_add_string(child, C.CString(C.ZPOOL_CONFIG_TYPE),
 | 
				
			||||||
| 
						 | 
					@ -466,11 +469,11 @@ func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create ZFS pool per specs, features and properties of pool and root dataset
 | 
					// PoolCreate create ZFS pool per specs, features and properties of pool and root dataset
 | 
				
			||||||
func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
 | 
					func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
 | 
				
			||||||
	props PoolProperties, fsprops ZFSProperties) (pool Pool, err error) {
 | 
						props PoolProperties, fsprops DatasetProperties) (pool Pool, err error) {
 | 
				
			||||||
	// create root vdev nvroot
 | 
						// create root vdev nvroot
 | 
				
			||||||
	var nvroot *C.nvlist_t = nil
 | 
						var nvroot *C.nvlist_t
 | 
				
			||||||
	if r := C.nvlist_alloc(&nvroot, C.NV_UNIQUE_NAME, 0); r != 0 {
 | 
						if r := C.nvlist_alloc(&nvroot, C.NV_UNIQUE_NAME, 0); r != 0 {
 | 
				
			||||||
		err = errors.New("Failed to allocate root vdev")
 | 
							err = errors.New("Failed to allocate root vdev")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -495,7 +498,7 @@ func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
 | 
				
			||||||
		err = errors.New("Failed to allocate pool properties")
 | 
							err = errors.New("Failed to allocate pool properties")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cfsprops := toCZFSProperties(fsprops)
 | 
						cfsprops := toCDatasetProperties(fsprops)
 | 
				
			||||||
	if cfsprops != nil {
 | 
						if cfsprops != nil {
 | 
				
			||||||
		defer C.nvlist_free(cfsprops)
 | 
							defer C.nvlist_free(cfsprops)
 | 
				
			||||||
	} else if len(fsprops) > 0 {
 | 
						} else if len(fsprops) > 0 {
 | 
				
			||||||
| 
						 | 
					@ -516,16 +519,34 @@ func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create actual pool then open
 | 
						// Create actual pool then open
 | 
				
			||||||
	if r := C.zpool_create(libzfs_handle, C.CString(name), nvroot,
 | 
						if r := C.zpool_create(libzfsHandle, C.CString(name), nvroot,
 | 
				
			||||||
		cprops, cfsprops); r != 0 {
 | 
							cprops, cfsprops); r != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
 | 
							err = errors.New(err.Error() + " (zpool_create)")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pool, err = PoolOpen(name)
 | 
					
 | 
				
			||||||
 | 
						// It can happen that pool is not immediately available,
 | 
				
			||||||
 | 
						// we know we just created it with success so lets wait and retry
 | 
				
			||||||
 | 
						// but only in case EZFS_NOENT error
 | 
				
			||||||
 | 
						retr := 0
 | 
				
			||||||
 | 
						for pool, err = PoolOpen(name); err != nil && retr < 3; retr++ {
 | 
				
			||||||
 | 
							errno := C.libzfs_errno(libzfsHandle)
 | 
				
			||||||
 | 
							if errno == ENoent {
 | 
				
			||||||
 | 
								time.Sleep(500 * time.Millisecond)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = errors.New(err.Error() + " (PoolOpen)")
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pool, err = PoolOpen(name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							err = errors.New(err.Error() + " (PoolOpen)")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get pool status. Let you check if pool healthy.
 | 
					// Status get pool status. Let you check if pool healthy.
 | 
				
			||||||
func (pool *Pool) Status() (status PoolStatus, err error) {
 | 
					func (pool *Pool) Status() (status PoolStatus, err error) {
 | 
				
			||||||
	var msgid *C.char
 | 
						var msgid *C.char
 | 
				
			||||||
	var reason C.zpool_status_t
 | 
						var reason C.zpool_status_t
 | 
				
			||||||
| 
						 | 
					@ -554,22 +575,22 @@ func (pool *Pool) Destroy(logStr string) (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Exports the pool from the system.
 | 
					// Export exports the pool from the system.
 | 
				
			||||||
// Before exporting the pool, all datasets within the pool are unmounted.
 | 
					// Before exporting the pool, all datasets within the pool are unmounted.
 | 
				
			||||||
// A pool can not be exported if it has a shared spare that is currently
 | 
					// A pool can not be exported if it has a shared spare that is currently
 | 
				
			||||||
// being used.
 | 
					// being used.
 | 
				
			||||||
func (pool *Pool) Export(force bool, log string) (err error) {
 | 
					func (pool *Pool) Export(force bool, log string) (err error) {
 | 
				
			||||||
	var force_t C.boolean_t = 0
 | 
						var forcet C.boolean_t
 | 
				
			||||||
	if force {
 | 
						if force {
 | 
				
			||||||
		force_t = 1
 | 
							forcet = 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if rc := C.zpool_export(pool.list.zph, force_t, C.CString(log)); rc != 0 {
 | 
						if rc := C.zpool_export(pool.list.zph, forcet, C.CString(log)); rc != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Hard force
 | 
					// ExportForce hard force export of the pool from the system.
 | 
				
			||||||
func (pool *Pool) ExportForce(log string) (err error) {
 | 
					func (pool *Pool) ExportForce(log string) (err error) {
 | 
				
			||||||
	if rc := C.zpool_export_force(pool.list.zph, C.CString(log)); rc != 0 {
 | 
						if rc := C.zpool_export_force(pool.list.zph, C.CString(log)); rc != 0 {
 | 
				
			||||||
		err = LastError()
 | 
							err = LastError()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,16 +2,17 @@ package zfs_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/bicomsystems/go-libzfs"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/bicomsystems/go-libzfs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------------------- */
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
// HELPERS:
 | 
					// HELPERS:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var TST_POOL_NAME = "TESTPOOL"
 | 
					var TSTPoolName = "TESTPOOL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func CreateTmpSparse(prefix string, size int64) (path string, err error) {
 | 
					func CreateTmpSparse(prefix string, size int64) (path string, err error) {
 | 
				
			||||||
	sf, err := ioutil.TempFile("/tmp", prefix)
 | 
						sf, err := ioutil.TempFile("/tmp", prefix)
 | 
				
			||||||
| 
						 | 
					@ -66,12 +67,12 @@ func zpoolTestPoolCreate(t *testing.T) {
 | 
				
			||||||
	// first check if pool with same name already exist
 | 
						// first check if pool with same name already exist
 | 
				
			||||||
	// we don't want conflict
 | 
						// we don't want conflict
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		p, err := zfs.PoolOpen(TST_POOL_NAME)
 | 
							p, err := zfs.PoolOpen(TSTPoolName)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		p.Close()
 | 
							p.Close()
 | 
				
			||||||
		TST_POOL_NAME += "0"
 | 
							TSTPoolName += "0"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,15 +95,15 @@ func zpoolTestPoolCreate(t *testing.T) {
 | 
				
			||||||
		zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
 | 
							zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	props := make(map[zfs.PoolProp]string)
 | 
						props := make(map[zfs.Prop]string)
 | 
				
			||||||
	fsprops := make(map[zfs.ZFSProp]string)
 | 
						fsprops := make(map[zfs.Prop]string)
 | 
				
			||||||
	features := make(map[string]string)
 | 
						features := make(map[string]string)
 | 
				
			||||||
	fsprops[zfs.ZFSPropMountpoint] = "none"
 | 
						fsprops[zfs.DatasetPropMountpoint] = "none"
 | 
				
			||||||
	features["async_destroy"] = "enabled"
 | 
						features["async_destroy"] = "enabled"
 | 
				
			||||||
	features["empty_bpobj"] = "enabled"
 | 
						features["empty_bpobj"] = "enabled"
 | 
				
			||||||
	features["lz4_compress"] = "enabled"
 | 
						features["lz4_compress"] = "enabled"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool, err := zfs.PoolCreate(TST_POOL_NAME, vdevs, features, props, fsprops)
 | 
						pool, err := zfs.PoolCreate(TSTPoolName, vdevs, features, props, fsprops)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		// try cleanup
 | 
							// try cleanup
 | 
				
			||||||
| 
						 | 
					@ -113,7 +114,7 @@ func zpoolTestPoolCreate(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer pool.Close()
 | 
						defer pool.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Open and list all pools and them state on the system
 | 
					// Open and list all pools and them state on the system
 | 
				
			||||||
| 
						 | 
					@ -143,22 +144,22 @@ func zpoolTestPoolOpenAll(t *testing.T) {
 | 
				
			||||||
		println("\tPool: ", pname, " state: ", pstate)
 | 
							println("\tPool: ", pname, " state: ", pstate)
 | 
				
			||||||
		p.Close()
 | 
							p.Close()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestPoolDestroy(t *testing.T) {
 | 
					func zpoolTestPoolDestroy(t *testing.T) {
 | 
				
			||||||
	println("TEST POOL Destroy( ", TST_POOL_NAME, " ) ... ")
 | 
						println("TEST POOL Destroy( ", TSTPoolName, " ) ... ")
 | 
				
			||||||
	p, err := zfs.PoolOpen(TST_POOL_NAME)
 | 
						p, err := zfs.PoolOpen(TSTPoolName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer p.Close()
 | 
						defer p.Close()
 | 
				
			||||||
	if err = p.Destroy("Test of pool destroy (" + TST_POOL_NAME + ")"); err != nil {
 | 
						if err = p.Destroy("Test of pool destroy (" + TSTPoolName + ")"); err != nil {
 | 
				
			||||||
		t.Error(err.Error())
 | 
							t.Error(err.Error())
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestFailPoolOpen(t *testing.T) {
 | 
					func zpoolTestFailPoolOpen(t *testing.T) {
 | 
				
			||||||
| 
						 | 
					@ -166,7 +167,7 @@ func zpoolTestFailPoolOpen(t *testing.T) {
 | 
				
			||||||
	pname := "fail to open this pool"
 | 
						pname := "fail to open this pool"
 | 
				
			||||||
	p, err := zfs.PoolOpen(pname)
 | 
						p, err := zfs.PoolOpen(pname)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		println("PASS\n")
 | 
							print("PASS\n\n")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t.Error("PoolOpen pass when it should fail")
 | 
						t.Error("PoolOpen pass when it should fail")
 | 
				
			||||||
| 
						 | 
					@ -174,43 +175,43 @@ func zpoolTestFailPoolOpen(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestExport(t *testing.T) {
 | 
					func zpoolTestExport(t *testing.T) {
 | 
				
			||||||
	println("TEST POOL Export( ", TST_POOL_NAME, " ) ... ")
 | 
						println("TEST POOL Export( ", TSTPoolName, " ) ... ")
 | 
				
			||||||
	p, err := zfs.PoolOpen(TST_POOL_NAME)
 | 
						p, err := zfs.PoolOpen(TSTPoolName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.Export(false, "Test exporting pool")
 | 
						p.Export(false, "Test exporting pool")
 | 
				
			||||||
	defer p.Close()
 | 
						defer p.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestExportForce(t *testing.T) {
 | 
					func zpoolTestExportForce(t *testing.T) {
 | 
				
			||||||
	println("TEST POOL ExportForce( ", TST_POOL_NAME, " ) ... ")
 | 
						println("TEST POOL ExportForce( ", TSTPoolName, " ) ... ")
 | 
				
			||||||
	p, err := zfs.PoolOpen(TST_POOL_NAME)
 | 
						p, err := zfs.PoolOpen(TSTPoolName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.ExportForce("Test force exporting pool")
 | 
						p.ExportForce("Test force exporting pool")
 | 
				
			||||||
	defer p.Close()
 | 
						defer p.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestImport(t *testing.T) {
 | 
					func zpoolTestImport(t *testing.T) {
 | 
				
			||||||
	println("TEST POOL Import( ", TST_POOL_NAME, " ) ... ")
 | 
						println("TEST POOL Import( ", TSTPoolName, " ) ... ")
 | 
				
			||||||
	p, err := zfs.PoolImport(TST_POOL_NAME, []string{"/tmp"})
 | 
						p, err := zfs.PoolImport(TSTPoolName, []string{"/tmp"})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer p.Close()
 | 
						defer p.Close()
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestPoolProp(t *testing.T) {
 | 
					func zpoolTestPoolProp(t *testing.T) {
 | 
				
			||||||
	println("TEST PoolProp on ", TST_POOL_NAME, " ... ")
 | 
						println("TEST PoolProp on ", TSTPoolName, " ... ")
 | 
				
			||||||
	if pool, err := zfs.PoolOpen(TST_POOL_NAME); err == nil {
 | 
						if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
 | 
				
			||||||
		defer pool.Close()
 | 
							defer pool.Close()
 | 
				
			||||||
		// Turn on snapshot listing for pool
 | 
							// Turn on snapshot listing for pool
 | 
				
			||||||
		pool.SetProperty(zfs.PoolPropListsnaps, "on")
 | 
							pool.SetProperty(zfs.PoolPropListsnaps, "on")
 | 
				
			||||||
| 
						 | 
					@ -247,12 +248,12 @@ func zpoolTestPoolProp(t *testing.T) {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zpoolTestPoolStatusAndState(t *testing.T) {
 | 
					func zpoolTestPoolStatusAndState(t *testing.T) {
 | 
				
			||||||
	println("TEST pool Status/State ( ", TST_POOL_NAME, " ) ... ")
 | 
						println("TEST pool Status/State ( ", TSTPoolName, " ) ... ")
 | 
				
			||||||
	pool, err := zfs.PoolOpen(TST_POOL_NAME)
 | 
						pool, err := zfs.PoolOpen(TSTPoolName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err.Error())
 | 
							t.Error(err.Error())
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -269,9 +270,9 @@ func zpoolTestPoolStatusAndState(t *testing.T) {
 | 
				
			||||||
		t.Error(err.Error())
 | 
							t.Error(err.Error())
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	println("POOL", TST_POOL_NAME, "state:", zfs.PoolStateToName(pstate))
 | 
						println("POOL", TSTPoolName, "state:", zfs.PoolStateToName(pstate))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	println("PASS\n")
 | 
						print("PASS\n\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------------------- */
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -315,7 +316,7 @@ func ExamplePoolOpenAll() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Iterate pool properties and print name, value and source
 | 
							// Iterate pool properties and print name, value and source
 | 
				
			||||||
		for key, prop := range p.Properties {
 | 
							for key, prop := range p.Properties {
 | 
				
			||||||
			pkey := zfs.PoolProp(key)
 | 
								pkey := zfs.Prop(key)
 | 
				
			||||||
			if pkey == zfs.PoolPropName {
 | 
								if pkey == zfs.PoolPropName {
 | 
				
			||||||
				continue // Skip name its already printed above
 | 
									continue // Skip name its already printed above
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -353,14 +354,14 @@ func ExamplePoolCreate() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// pool properties
 | 
						// pool properties
 | 
				
			||||||
	props := make(map[zfs.PoolProp]string)
 | 
						props := make(map[zfs.Prop]string)
 | 
				
			||||||
	// root dataset filesystem properties
 | 
						// root dataset filesystem properties
 | 
				
			||||||
	fsprops := make(map[zfs.ZFSProp]string)
 | 
						fsprops := make(map[zfs.Prop]string)
 | 
				
			||||||
	// pool features
 | 
						// pool features
 | 
				
			||||||
	features := make(map[string]string)
 | 
						features := make(map[string]string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Turn off auto mounting by ZFS
 | 
						// Turn off auto mounting by ZFS
 | 
				
			||||||
	fsprops[zfs.ZFSPropMountpoint] = "none"
 | 
						fsprops[zfs.DatasetPropMountpoint] = "none"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Enable some features
 | 
						// Enable some features
 | 
				
			||||||
	features["async_destroy"] = "enabled"
 | 
						features["async_destroy"] = "enabled"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue