- Improved pointer handling between go and C and elimination of associated memory leaks and potential corruptions

This commit is contained in:
Faruk Kasumovic 2017-02-23 11:29:17 +01:00
parent fe36016d7e
commit 07270bcff8
6 changed files with 90 additions and 61 deletions

View File

@ -26,7 +26,7 @@ import (
// VDevType type of device in the pool // VDevType type of device in the pool
type VDevType string type VDevType string
var libzfsHandle *C.struct_libzfs_handle var libzfsHandle C.libzfs_handle_ptr
func init() { func init() {
libzfsHandle = C.libzfs_init() libzfsHandle = C.libzfs_init()

14
zfs.c
View File

@ -20,6 +20,16 @@ dataset_list_t *create_dataset_list_item() {
void dataset_list_close(dataset_list_t *list) { void dataset_list_close(dataset_list_t *list) {
zfs_close(list->zh); zfs_close(list->zh);
free(list); free(list);
// dataset_list_free(list);
}
void dataset_list_free(dataset_list_t *list) {
dataset_list_t *next;
while(list) {
next = list->pnext;
free(list);
list = next;
}
} }
int dataset_list_callb(zfs_handle_t *dataset, void *data) { int dataset_list_callb(zfs_handle_t *dataset, void *data) {
@ -44,7 +54,7 @@ int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first) {
*first = zlist; *first = zlist;
} else { } else {
*first = 0; *first = 0;
free(zlist); dataset_list_free(zlist);
} }
return err; return err;
} }
@ -62,7 +72,7 @@ int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first) {
*first = zlist; *first = zlist;
} else { } else {
*first = 0; *first = 0;
free(zlist); dataset_list_free(zlist);
} }
return err; return err;
} }

46
zfs.go
View File

@ -8,6 +8,7 @@ import "C"
import ( import (
"errors" "errors"
"fmt"
"unsafe" "unsafe"
) )
@ -36,17 +37,18 @@ const (
// Dataset - ZFS dataset object // Dataset - ZFS dataset object
type Dataset struct { type Dataset struct {
list *C.dataset_list_t list C.dataset_list_ptr
Type DatasetType Type DatasetType
Properties map[Prop]Property Properties map[Prop]Property
Children []Dataset Children []Dataset
} }
func (d *Dataset) openChildren() (err error) { func (d *Dataset) openChildren() (err error) {
var dataset Dataset var list C.dataset_list_ptr
d.Children = make([]Dataset, 0, 5) d.Children = make([]Dataset, 0, 5)
errcode := C.dataset_list_children(d.list.zh, &(dataset.list)) errcode := C.dataset_list_children(d.list.zh, unsafe.Pointer(&list))
for dataset.list != nil { for list != nil {
dataset := Dataset{list: list}
dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh)) dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
dataset.Properties = make(map[Prop]Property) dataset.Properties = make(map[Prop]Property)
err = dataset.ReloadProperties() err = dataset.ReloadProperties()
@ -54,7 +56,7 @@ func (d *Dataset) openChildren() (err error) {
return return
} }
d.Children = append(d.Children, dataset) d.Children = append(d.Children, dataset)
dataset.list = C.dataset_next(dataset.list) list = C.dataset_next(list)
} }
if errcode != 0 { if errcode != 0 {
err = LastError() err = LastError()
@ -72,7 +74,7 @@ func (d *Dataset) openChildren() (err error) {
// (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(libzfsHandle, &dataset.list) errcode := C.dataset_list_root(libzfsHandle, unsafe.Pointer(&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()
@ -111,6 +113,9 @@ func DatasetOpen(path string) (d Dataset, err error) {
if d.list.zh == nil { if d.list.zh == nil {
err = LastError() err = LastError()
if err == nil {
err = fmt.Errorf("dataset not found.")
}
return return
} }
d.Type = DatasetType(C.zfs_get_type(d.list.zh)) d.Type = DatasetType(C.zfs_get_type(d.list.zh))
@ -124,9 +129,9 @@ func DatasetOpen(path string) (d Dataset, err error) {
} }
func datasetPropertiesTonvlist(props map[Prop]Property) ( func datasetPropertiesTonvlist(props map[Prop]Property) (
cprops *C.nvlist_t, err error) { cprops C.nvlist_ptr, 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(unsafe.Pointer(&cprops), C.NV_UNIQUE_NAME, 0)
if r != 0 { if r != 0 {
err = errors.New("Failed to allocate properties") err = errors.New("Failed to allocate properties")
return return
@ -149,7 +154,7 @@ func datasetPropertiesTonvlist(props map[Prop]Property) (
// pool/dataset or pool/parent/dataset // pool/dataset or pool/parent/dataset
func DatasetCreate(path string, dtype DatasetType, func DatasetCreate(path string, dtype DatasetType,
props map[Prop]Property) (d Dataset, err error) { props map[Prop]Property) (d Dataset, err error) {
var cprops *C.nvlist_t var cprops C.nvlist_ptr
if cprops, err = datasetPropertiesTonvlist(props); err != nil { if cprops, err = datasetPropertiesTonvlist(props); err != nil {
return return
} }
@ -170,6 +175,7 @@ func DatasetCreate(path string, dtype DatasetType,
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)
d.list = nil
} }
for _, cd := range d.Children { for _, cd := range d.Children {
cd.Close() cd.Close()
@ -242,17 +248,19 @@ func (d *Dataset) ReloadProperties() (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
var plist *C.property_list_t var plist C.property_list_ptr
plist = C.new_property_list()
defer C.free_properties(plist)
d.Properties = make(map[Prop]Property) d.Properties = make(map[Prop]Property)
for prop := DatasetPropType; prop < DatasetNumProps; prop++ { for prop := DatasetPropType; prop < DatasetNumProps; prop++ {
plist = C.new_property_list()
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 {
C.free_properties(plist)
continue continue
} }
d.Properties[prop] = Property{Value: C.GoString(&(*plist).value[0]), d.Properties[prop] = Property{Value: C.GoString(&(*plist).value[0]),
Source: C.GoString(&(*plist).source[0])} Source: C.GoString(&(*plist).source[0])}
C.free_properties(plist)
} }
return return
} }
@ -264,7 +272,7 @@ func (d *Dataset) GetProperty(p Prop) (prop Property, err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
var plist *C.property_list_t var plist C.property_list_ptr
plist = C.new_property_list() plist = C.new_property_list()
defer C.free_properties(plist) defer C.free_properties(plist)
errcode := C.read_dataset_property(d.list.zh, plist, C.int(p)) errcode := C.read_dataset_property(d.list.zh, plist, C.int(p))
@ -283,7 +291,7 @@ func (d *Dataset) GetUserProperty(p string) (prop Property, err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
var plist *C.property_list_t var plist C.property_list_ptr
plist = C.new_property_list() plist = C.new_property_list()
defer C.free_properties(plist) defer C.free_properties(plist)
csp := C.CString(p) csp := C.CString(p)
@ -339,7 +347,7 @@ func (d *Dataset) SetUserProperty(prop, value string) (err error) {
// Clone - 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[Prop]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_ptr
if d.list == nil { if d.list == nil {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
@ -360,7 +368,7 @@ func (d *Dataset) Clone(target string, props map[Prop]Property) (rd Dataset, err
// DatasetSnapshot 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[Prop]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_ptr
if cprops, err = datasetPropertiesTonvlist(props); err != nil { if cprops, err = datasetPropertiesTonvlist(props); err != nil {
return return
} }
@ -419,12 +427,12 @@ func (d *Dataset) Rename(newName string, recur,
// sets in 'where' argument 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_ptr
if d.list == nil { if d.list == nil {
return false, "" return false, ""
} }
m := C.zfs_is_mounted(d.list.zh, &cw) m := C.zfs_is_mounted(d.list.zh, unsafe.Pointer(&cw))
defer C.free(unsafe.Pointer(cw)) // defer C.free(cw)
if m != 0 { if m != 0 {
return true, C.GoString(cw) return true, C.GoString(cw)
} }

2
zfs.h
View File

@ -11,10 +11,12 @@ struct dataset_list {
}; };
typedef struct dataset_list dataset_list_t; typedef struct dataset_list dataset_list_t;
typedef struct dataset_list* dataset_list_ptr;
dataset_list_t *create_dataset_list_item(); dataset_list_t *create_dataset_list_item();
void dataset_list_close(dataset_list_t *list); void dataset_list_close(dataset_list_t *list);
void dataset_list_free(dataset_list_t *list);
int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first); int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first);
int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first); int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first);

View File

@ -127,7 +127,7 @@ type ExportedPool struct {
// give easy access to listing all available properties. It can be refreshed // give easy access to listing all available properties. It can be refreshed
// with up to date values with call to (*Pool) ReloadProperties // with up to date values with call to (*Pool) ReloadProperties
type Pool struct { type Pool struct {
list *C.zpool_list_t list C.zpool_list_ptr
Properties []Property Properties []Property
Features map[string]string Features map[string]string
} }
@ -148,14 +148,14 @@ func PoolOpen(name string) (pool Pool, err error) {
return return
} }
func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) { func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
var dtype *C.char var dtype C.char_ptr
var c, children C.uint_t var c, children C.uint_t
var notpresent C.uint64_t var notpresent C.uint64_t
var vs *C.vdev_stat_t var vs C.vdev_stat_ptr
var ps *C.pool_scan_stat_t var ps C.pool_scan_stat_ptr
var child **C.nvlist_t var child *C.nvlist_ptr
if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_TYPE, &dtype) { if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_TYPE, unsafe.Pointer(&dtype)) {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE)
return return
} }
@ -167,7 +167,7 @@ func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
// Fetch vdev state // Fetch vdev state
if 0 != C.nvlist_lookup_uint64_array_vds(nv, C.sZPOOL_CONFIG_VDEV_STATS, if 0 != C.nvlist_lookup_uint64_array_vds(nv, C.sZPOOL_CONFIG_VDEV_STATS,
&vs, &c) { unsafe.Pointer(&vs), &c) {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS)
return return
} }
@ -193,7 +193,7 @@ func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
// Fetch vdev scan stats // Fetch vdev scan stats
if 0 == C.nvlist_lookup_uint64_array_ps(nv, C.sZPOOL_CONFIG_SCAN_STATS, if 0 == C.nvlist_lookup_uint64_array_ps(nv, C.sZPOOL_CONFIG_SCAN_STATS,
&ps, &c) { unsafe.Pointer(&ps), &c) {
vdevs.ScanStat.Func = uint64(ps.pss_func) vdevs.ScanStat.Func = uint64(ps.pss_func)
vdevs.ScanStat.State = uint64(ps.pss_state) vdevs.ScanStat.State = uint64(ps.pss_state)
vdevs.ScanStat.StartTime = uint64(ps.pss_start_time) vdevs.ScanStat.StartTime = uint64(ps.pss_start_time)
@ -209,7 +209,7 @@ func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
// Fetch the children // Fetch the children
if C.nvlist_lookup_nvlist_array(nv, C.sZPOOL_CONFIG_CHILDREN, if C.nvlist_lookup_nvlist_array(nv, C.sZPOOL_CONFIG_CHILDREN,
&child, &children) != 0 { unsafe.Pointer(&child), &children) != 0 {
return return
} }
if children > 0 { if children > 0 {
@ -217,8 +217,8 @@ func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
} }
if C.nvlist_lookup_uint64(nv, C.sZPOOL_CONFIG_NOT_PRESENT, if C.nvlist_lookup_uint64(nv, C.sZPOOL_CONFIG_NOT_PRESENT,
&notpresent) == 0 { &notpresent) == 0 {
var path *C.char var path C.char_ptr
if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_PATH, &path) { if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_PATH, unsafe.Pointer(&path)) {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_PATH) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_PATH)
return return
} }
@ -249,13 +249,13 @@ func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
// PoolImportSearch - Search pools available to import but not imported. // PoolImportSearch - Search pools available to import but not imported.
// Returns array of found pools. // Returns array of found pools.
func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) { func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
var config, nvroot *C.nvlist_t var config, nvroot C.nvlist_ptr
var cname, msgid, comment *C.char var cname, msgid, comment C.char_ptr
var poolState, guid C.uint64_t var poolState, guid C.uint64_t
var reason C.zpool_status_t var reason C.zpool_status_t
var errata C.zpool_errata_t var errata C.zpool_errata_t
config = nil config = nil
var elem *C.nvpair_t var elem C.nvpair_ptr
numofp := len(searchpaths) numofp := len(searchpaths)
cpaths := C.alloc_cstrings(C.int(numofp)) cpaths := C.alloc_cstrings(C.int(numofp))
defer C.free(unsafe.Pointer(cpaths)) defer C.free(unsafe.Pointer(cpaths))
@ -271,7 +271,7 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
epools = make([]ExportedPool, 0, 1) epools = make([]ExportedPool, 0, 1)
for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) { for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
ep := ExportedPool{} ep := ExportedPool{}
if C.nvpair_value_nvlist(elem, &config) != 0 { if C.nvpair_value_nvlist(elem, unsafe.Pointer(&config)) != 0 {
err = LastError() err = LastError()
return return
} }
@ -281,7 +281,7 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
return return
} }
ep.State = PoolState(poolState) ep.State = PoolState(poolState)
if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_POOL_NAME, &cname) != 0 { if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_NAME) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_NAME)
return return
} }
@ -294,12 +294,12 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
reason = C.zpool_import_status(config, &msgid, &errata) reason = C.zpool_import_status(config, &msgid, &errata)
ep.Status = PoolStatus(reason) ep.Status = PoolStatus(reason)
if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_COMMENT, &comment) == 0 { if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_COMMENT, unsafe.Pointer(&comment)) == 0 {
ep.Comment = C.GoString(comment) ep.Comment = C.GoString(comment)
} }
if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE,
&nvroot) != 0 { unsafe.Pointer(&nvroot)) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
return return
} }
@ -311,8 +311,8 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
func poolSearchImport(q string, searchpaths []string, guid bool) (name string, func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
err error) { err error) {
var config *C.nvlist_t var config C.nvlist_ptr
var cname *C.char var cname C.char_ptr
config = nil config = nil
errPoolList := errors.New("Failed to list pools") errPoolList := errors.New("Failed to list pools")
var elem *C.nvpair_t var elem *C.nvpair_t
@ -332,7 +332,7 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) { for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
var cq *C.char var cq *C.char
var tconfig *C.nvlist_t var tconfig *C.nvlist_t
retcode := C.nvpair_value_nvlist(elem, &tconfig) retcode := C.nvpair_value_nvlist(elem, unsafe.Pointer(&tconfig))
if retcode != 0 { if retcode != 0 {
err = errPoolList err = errPoolList
return return
@ -351,7 +351,7 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
} }
} else { } else {
if retcode = C.nvlist_lookup_string(tconfig, if retcode = C.nvlist_lookup_string(tconfig,
C.sZPOOL_CONFIG_POOL_NAME, &cq); retcode != 0 { C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cq)); retcode != 0 {
err = errPoolList err = errPoolList
return return
} }
@ -370,7 +370,7 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
if guid { if guid {
// We need to get name so we can open pool by name // We need to get name so we can open pool by name
if retcode := C.nvlist_lookup_string(config, if retcode := C.nvlist_lookup_string(config,
C.sZPOOL_CONFIG_POOL_NAME, &cname); retcode != 0 { C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)); retcode != 0 {
err = errPoolList err = errPoolList
return return
} }
@ -416,7 +416,7 @@ func PoolImportByGUID(guid string, searchpaths []string) (pool Pool, err error)
// 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(libzfsHandle, &pool.list) errcode := C.zpool_list(libzfsHandle, unsafe.Pointer(&pool.list))
for pool.list != nil { for pool.list != nil {
err = pool.ReloadProperties() err = pool.ReloadProperties()
if err != nil { if err != nil {
@ -516,7 +516,7 @@ func (pool *Pool) GetProperty(p Prop) (prop Property, err error) {
return return
} }
var list C.property_list_t var list C.property_list_t
r := C.read_zpool_property(pool.list.zph, &list, C.int(p)) r := C.read_zpool_property(pool.list.zph, unsafe.Pointer(&list), C.int(p))
if r != 0 { if r != 0 {
err = LastError() err = LastError()
} }
@ -632,12 +632,12 @@ func (vdev *VDevTree) isLog() (r C.uint64_t) {
return return
} }
func toCPoolProperties(props PoolProperties) (cprops *C.nvlist_t) { func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) {
cprops = nil cprops = nil
for prop, value := range props { for prop, value := range props {
name := C.zpool_prop_to_name(C.zpool_prop_t(prop)) name := C.zpool_prop_to_name(C.zpool_prop_t(prop))
csPropValue := C.CString(value) csPropValue := C.CString(value)
r := C.add_prop_list(name, csPropValue, &cprops, C.boolean_t(1)) r := C.add_prop_list(name, csPropValue, unsafe.Pointer(&cprops), C.boolean_t(1))
C.free(unsafe.Pointer(csPropValue)) C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
@ -650,12 +650,12 @@ func toCPoolProperties(props PoolProperties) (cprops *C.nvlist_t) {
return return
} }
func toCDatasetProperties(props DatasetProperties) (cprops *C.nvlist_t) { func toCDatasetProperties(props DatasetProperties) (cprops C.nvlist_ptr) {
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))
csPropValue := C.CString(value) csPropValue := C.CString(value)
r := C.add_prop_list(name, csPropValue, &cprops, C.boolean_t(0)) r := C.add_prop_list(name, csPropValue, unsafe.Pointer(&cprops), C.boolean_t(0))
C.free(unsafe.Pointer(csPropValue)) C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
@ -696,9 +696,9 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
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 var child C.nvlist_ptr
// 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(unsafe.Pointer(&child), C.NV_UNIQUE_NAME, 0); r != 0 {
err = errors.New("Failed to allocate vdev") err = errors.New("Failed to allocate vdev")
return return
} }
@ -812,8 +812,8 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
func PoolCreate(name string, vdevs []VDevTree, features map[string]string, func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
props PoolProperties, fsprops DatasetProperties) (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 var nvroot C.nvlist_ptr
if r := C.nvlist_alloc(&nvroot, C.NV_UNIQUE_NAME, 0); r != 0 { if r := C.nvlist_alloc(unsafe.Pointer(&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
} }
@ -860,7 +860,7 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
for fname, fval := range features { for fname, fval := range features {
csName := C.CString(fmt.Sprintf("feature@%s", fname)) csName := C.CString(fmt.Sprintf("feature@%s", fname))
csVal := C.CString(fval) csVal := C.CString(fval)
r := C.add_prop_list(csName, csVal, &cprops, r := C.add_prop_list(csName, csVal, unsafe.Pointer(&cprops),
C.boolean_t(1)) C.boolean_t(1))
C.free(unsafe.Pointer(csName)) C.free(unsafe.Pointer(csName))
C.free(unsafe.Pointer(csVal)) C.free(unsafe.Pointer(csVal))
@ -890,14 +890,14 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
// Status 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_ptr
var reason C.zpool_status_t var reason C.zpool_status_t
var errata C.zpool_errata_t var errata C.zpool_errata_t
if pool.list == nil { if pool.list == nil {
err = errors.New(msgPoolIsNil) err = errors.New(msgPoolIsNil)
return return
} }
reason = C.zpool_get_status(pool.list.zph, &msgid, &errata) reason = C.zpool_get_status(pool.list.zph, unsafe.Pointer(&msgid), &errata)
status = PoolStatus(reason) status = PoolStatus(reason)
return return
} }
@ -948,7 +948,7 @@ func (pool *Pool) ExportForce(log string) (err error) {
// VDevTree - Fetch pool's current vdev tree configuration, state and stats // VDevTree - Fetch pool's current vdev tree configuration, state and stats
func (pool *Pool) VDevTree() (vdevs VDevTree, err error) { func (pool *Pool) VDevTree() (vdevs VDevTree, err error) {
var nvroot *C.nvlist_t var nvroot C.nvlist_ptr
var poolName string var poolName string
config := C.zpool_get_config(pool.list.zph, nil) config := C.zpool_get_config(pool.list.zph, nil)
if config == nil { if config == nil {
@ -956,7 +956,7 @@ func (pool *Pool) VDevTree() (vdevs VDevTree, err error) {
return return
} }
if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE,
&nvroot) != 0 { unsafe.Pointer(&nvroot)) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
return return
} }

View File

@ -23,6 +23,15 @@ typedef struct property_list {
} property_list_t; } property_list_t;
typedef struct zpool_list zpool_list_t; typedef struct zpool_list zpool_list_t;
typedef struct zpool_list* zpool_list_ptr;
typedef struct libzfs_handle* libzfs_handle_ptr;
typedef struct nvlist* nvlist_ptr;
typedef struct property_list *property_list_ptr;
typedef struct pool_scan_stat* pool_scan_stat_ptr;
typedef struct nvpair* nvpair_ptr;
typedef struct vdev_stat* vdev_stat_ptr;
typedef char* char_ptr;
property_list_t *new_property_list(); property_list_t *new_property_list();