- Fix remaining cgo CString memory leaks

This commit is contained in:
Faruk Kasumovic 2016-07-26 21:14:28 +02:00
parent 631236eb5e
commit a6fba76e81
6 changed files with 94 additions and 51 deletions

2
zfs.c
View File

@ -87,7 +87,7 @@ int clear_last_error(libzfs_handle_t *hdl) {
return 0; return 0;
} }
char** alloc_strings(int size) { char** alloc_cstrings(int size) {
return malloc(size*sizeof(char*)); return malloc(size*sizeof(char*));
} }

40
zfs.go
View File

@ -8,6 +8,7 @@ import "C"
import ( import (
"errors" "errors"
"unsafe"
) )
const ( const (
@ -104,7 +105,9 @@ func DatasetCloseAll(datasets []Dataset) {
// DatasetOpen 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(libzfsHandle, C.CString(path), 0xF) csPath := C.CString(path)
d.list.zh = C.zfs_open(libzfsHandle, csPath, 0xF)
C.free(unsafe.Pointer(csPath))
if d.list.zh == nil { if d.list.zh == nil {
err = LastError() err = LastError()
@ -129,9 +132,11 @@ func datasetPropertiesTonvlist(props map[Prop]Property) (
return return
} }
for prop, value := range props { for prop, value := range props {
csValue := C.CString(value.Value)
r := C.nvlist_add_string( r := C.nvlist_add_string(
cprops, C.zfs_prop_to_name( cprops, C.zfs_prop_to_name(
C.zfs_prop_t(prop)), C.CString(value.Value)) C.zfs_prop_t(prop)), csValue)
C.free(unsafe.Pointer(csValue))
if r != 0 { if r != 0 {
err = errors.New("Failed to convert property") err = errors.New("Failed to convert property")
return return
@ -150,8 +155,10 @@ func DatasetCreate(path string, dtype DatasetType,
} }
defer C.nvlist_free(cprops) defer C.nvlist_free(cprops)
errcode := C.zfs_create(libzfsHandle, C.CString(path), csPath := C.CString(path)
errcode := C.zfs_create(libzfsHandle, csPath,
C.zfs_type_t(dtype), cprops) C.zfs_type_t(dtype), cprops)
C.free(unsafe.Pointer(csPath))
if errcode != 0 { if errcode != 0 {
err = LastError() err = LastError()
} }
@ -179,6 +186,9 @@ func (d *Dataset) Destroy(Defer bool) (err error) {
return return
} }
dsType, e := d.GetProperty(DatasetPropType) dsType, e := d.GetProperty(DatasetPropType)
if e != nil {
dsType.Value = err.Error() // just put error (why it didn't fetch property type)
}
err = errors.New("Cannot destroy dataset " + path + err = errors.New("Cannot destroy dataset " + path +
": " + dsType.Value + " has children") ": " + dsType.Value + " has children")
return return
@ -276,8 +286,10 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
csValue := C.CString(value)
errcode := C.zfs_prop_set(d.list.zh, C.zfs_prop_to_name( errcode := C.zfs_prop_set(d.list.zh, C.zfs_prop_to_name(
C.zfs_prop_t(p)), C.CString(value)) C.zfs_prop_t(p)), csValue)
C.free(unsafe.Pointer(csValue))
if errcode != 0 { if errcode != 0 {
err = LastError() err = LastError()
} }
@ -300,7 +312,9 @@ func (d *Dataset) Clone(target string, props map[Prop]Property) (rd Dataset, err
return return
} }
defer C.nvlist_free(cprops) defer C.nvlist_free(cprops)
if errc := C.zfs_clone(d.list.zh, C.CString(target), cprops); errc != 0 { csTarget := C.CString(target)
defer C.free(unsafe.Pointer(csTarget))
if errc := C.zfs_clone(d.list.zh, csTarget, cprops); errc != 0 {
err = LastError() err = LastError()
return return
} }
@ -315,7 +329,9 @@ func DatasetSnapshot(path string, recur bool, props map[Prop]Property) (rd Datas
return return
} }
defer C.nvlist_free(cprops) defer C.nvlist_free(cprops)
if errc := C.zfs_snapshot(libzfsHandle, C.CString(path), booleanT(recur), cprops); errc != 0 { csPath := C.CString(path)
defer C.free(unsafe.Pointer(csPath))
if errc := C.zfs_snapshot(libzfsHandle, csPath, booleanT(recur), cprops); errc != 0 {
err = LastError() err = LastError()
return return
} }
@ -348,13 +364,15 @@ 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,
forceUnmount 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), csNewName := C.CString(newName)
defer C.free(unsafe.Pointer(csNewName))
if errc := C.zfs_rename(d.list.zh, csNewName,
booleanT(recur), booleanT(forceUnmount)); errc != 0 { booleanT(recur), booleanT(forceUnmount)); errc != 0 {
err = LastError() err = LastError()
} }
@ -370,7 +388,7 @@ func (d *Dataset) IsMounted() (mounted bool, where string) {
return false, "" return false, ""
} }
m := C.zfs_is_mounted(d.list.zh, &cw) m := C.zfs_is_mounted(d.list.zh, &cw)
defer C.free_cstring(cw) defer C.free(unsafe.Pointer(cw))
if m != 0 { if m != 0 {
return true, C.GoString(cw) return true, C.GoString(cw)
} }
@ -383,7 +401,9 @@ func (d *Dataset) Mount(options string, flags int) (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
if ec := C.zfs_mount(d.list.zh, C.CString(options), C.int(flags)); ec != 0 { csOptions := C.CString(options)
defer C.free(unsafe.Pointer(csOptions))
if ec := C.zfs_mount(d.list.zh, csOptions, C.int(flags)); ec != 0 {
err = LastError() err = LastError()
} }
return return

2
zfs.h
View File

@ -24,7 +24,7 @@ int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop);
int clear_last_error(libzfs_handle_t *libzfs); int clear_last_error(libzfs_handle_t *libzfs);
char** alloc_strings(int size); char** alloc_cstrings(int size);
void strings_setat(char **a, int at, char *v); void strings_setat(char **a, int at, char *v);
#endif #endif

View File

@ -462,10 +462,6 @@ void nvlist_free_array(nvlist_t **a) {
free(a); free(a);
} }
void free_cstring(char *str) {
free(str);
}
nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i) { nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i) {
return a[i]; return a[i];
} }

View File

@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"time" "time"
"unsafe"
) )
const ( const (
@ -129,9 +130,9 @@ type Pool struct {
// 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) {
namestr := C.CString(name) csName := C.CString(name)
pool.list = C.zpool_list_open(libzfsHandle, namestr) defer C.free(unsafe.Pointer(csName))
C.free_cstring(namestr) pool.list = C.zpool_list_open(libzfsHandle, csName)
if pool.list != nil { if pool.list != nil {
err = pool.ReloadProperties() err = pool.ReloadProperties()
@ -227,11 +228,10 @@ func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
} }
vname := C.zpool_vdev_name(libzfsHandle, nil, C.nvlist_array_at(child, c), vname := C.zpool_vdev_name(libzfsHandle, nil, C.nvlist_array_at(child, c),
C.B_TRUE) C.B_TRUE)
var vdev VDevTree var vdev VDevTree
vdev, err = poolGetConfig(C.GoString(vname), vdev, err = poolGetConfig(C.GoString(vname),
C.nvlist_array_at(child, c)) C.nvlist_array_at(child, c))
C.free_cstring(vname) C.free(unsafe.Pointer(vname))
if err != nil { if err != nil {
return return
} }
@ -251,9 +251,12 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
config = nil config = nil
var elem *C.nvpair_t var elem *C.nvpair_t
numofp := len(searchpaths) numofp := len(searchpaths)
cpaths := C.alloc_strings(C.int(numofp)) cpaths := C.alloc_cstrings(C.int(numofp))
defer C.free(unsafe.Pointer(cpaths))
for i, path := range searchpaths { for i, path := range searchpaths {
C.strings_setat(cpaths, C.int(i), C.CString(path)) csPath := C.CString(path)
defer C.free(unsafe.Pointer(csPath))
C.strings_setat(cpaths, C.int(i), csPath)
} }
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths) pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths)
@ -308,9 +311,12 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
errPoolList := errors.New("Failed to list pools") errPoolList := errors.New("Failed to list pools")
var elem *C.nvpair_t var elem *C.nvpair_t
numofp := len(searchpaths) numofp := len(searchpaths)
cpaths := C.alloc_strings(C.int(numofp)) cpaths := C.alloc_cstrings(C.int(numofp))
defer C.free(unsafe.Pointer(cpaths))
for i, path := range searchpaths { for i, path := range searchpaths {
C.strings_setat(cpaths, C.int(i), C.CString(path)) csPath := C.CString(path)
defer C.free(unsafe.Pointer(csPath))
C.strings_setat(cpaths, C.int(i), csPath)
} }
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths) pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths)
@ -446,7 +452,7 @@ func PoolStateToName(state PoolState) (name string) {
return return
} }
// Refresh the pool's vdev statistics, e.g. bytes read/written. // RefreshStats the pool's vdev statistics, e.g. bytes read/written.
func (pool *Pool) RefreshStats() (err error) { func (pool *Pool) RefreshStats() (err error) {
if 0 != C.refresh_stats(pool.list) { if 0 != C.refresh_stats(pool.list) {
return errors.New("error refreshing stats") return errors.New("error refreshing stats")
@ -520,11 +526,9 @@ func (pool *Pool) GetProperty(p Prop) (prop Property, err error) {
// 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
var sname *C.char csName := C.CString(fmt.Sprint("feature@", name))
sname = C.CString(fmt.Sprint("feature@", name)) r := C.zpool_prop_get_feature(pool.list.zph, csName, &(fvalue[0]), 512)
r := C.zpool_prop_get_feature(pool.list.zph, sname, &(fvalue[0]), 512) C.free(unsafe.Pointer(csName))
C.free_cstring(sname)
if r != 0 { if r != 0 {
err = errors.New(fmt.Sprint("Unknown zpool feature: ", name)) err = errors.New(fmt.Sprint("Unknown zpool feature: ", name))
return return
@ -545,7 +549,11 @@ func (pool *Pool) SetProperty(p Prop, value string) (err error) {
PoolPropertyToName(p))) PoolPropertyToName(p)))
return return
} }
r := C.zpool_set_prop(pool.list.zph, C.CString(PoolPropertyToName(p)), C.CString(value)) csPropName := C.CString(PoolPropertyToName(p))
csPropValue := C.CString(value)
r := C.zpool_set_prop(pool.list.zph, csPropName, csPropValue)
C.free(unsafe.Pointer(csPropName))
C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
err = LastError() err = LastError()
} else { } else {
@ -622,7 +630,9 @@ func toCPoolProperties(props PoolProperties) (cprops *C.nvlist_t) {
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))
r := C.add_prop_list(name, C.CString(value), &cprops, C.boolean_t(1)) csPropValue := C.CString(value)
r := C.add_prop_list(name, csPropValue, &cprops, C.boolean_t(1))
C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
C.nvlist_free(cprops) C.nvlist_free(cprops)
@ -638,7 +648,9 @@ 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))
r := C.add_prop_list(name, C.CString(value), &cprops, C.boolean_t(0)) csPropValue := C.CString(value)
r := C.add_prop_list(name, csPropValue, &cprops, C.boolean_t(0))
C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
C.nvlist_free(cprops) C.nvlist_free(cprops)
@ -691,8 +703,11 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
vdev.Type, mindevs, maxdevs) vdev.Type, mindevs, maxdevs)
return return
} }
if r := C.nvlist_add_string(child, C.sZPOOL_CONFIG_TYPE, csType := C.CString(string(vdev.Type))
C.CString(string(vdev.Type))); r != 0 { r := C.nvlist_add_string(child, C.sZPOOL_CONFIG_TYPE,
csType)
C.free(unsafe.Pointer(csType))
if r != 0 {
err = errors.New("Failed to set vdev type") err = errors.New("Failed to set vdev type")
return return
} }
@ -724,9 +739,12 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
} }
// } // }
if len(vdev.Path) > 0 { if len(vdev.Path) > 0 {
if r := C.nvlist_add_string( csPath := C.CString(vdev.Path)
r := C.nvlist_add_string(
child, C.sZPOOL_CONFIG_PATH, child, C.sZPOOL_CONFIG_PATH,
C.CString(vdev.Path)); r != 0 { csPath)
C.free(unsafe.Pointer(csPath))
if r != 0 {
err = errors.New("Failed to allocate vdev child (type)") err = errors.New("Failed to allocate vdev child (type)")
return return
} }
@ -793,8 +811,11 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
err = errors.New("Failed to allocate root vdev") err = errors.New("Failed to allocate root vdev")
return return
} }
if r := C.nvlist_add_string(nvroot, C.sZPOOL_CONFIG_TYPE, csTypeRoot := C.CString(string(VDevTypeRoot))
C.CString(string(VDevTypeRoot))); r != 0 { r := C.nvlist_add_string(nvroot, C.sZPOOL_CONFIG_TYPE,
csTypeRoot)
C.free(unsafe.Pointer(csTypeRoot))
if r != 0 {
err = errors.New("Failed to allocate root vdev") err = errors.New("Failed to allocate root vdev")
return return
} }
@ -821,9 +842,12 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
return return
} }
for fname, fval := range features { for fname, fval := range features {
sfname := fmt.Sprintf("feature@%s", fname) csName := C.CString(fmt.Sprintf("feature@%s", fname))
r := C.add_prop_list(C.CString(sfname), C.CString(fval), &cprops, csVal := C.CString(fval)
r := C.add_prop_list(csName, csVal, &cprops,
C.boolean_t(1)) C.boolean_t(1))
C.free(unsafe.Pointer(csName))
C.free(unsafe.Pointer(csVal))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
C.nvlist_free(cprops) C.nvlist_free(cprops)
@ -834,7 +858,9 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
} }
// Create actual pool then open // Create actual pool then open
if r := C.zpool_create(libzfsHandle, C.CString(name), nvroot, csName := C.CString(name)
defer C.free(unsafe.Pointer(csName))
if r := C.zpool_create(libzfsHandle, csName, nvroot,
cprops, cfsprops); r != 0 { cprops, cfsprops); r != 0 {
err = LastError() err = LastError()
err = errors.New(err.Error() + " (zpool_create)") err = errors.New(err.Error() + " (zpool_create)")
@ -868,7 +894,9 @@ func (pool *Pool) Destroy(logStr string) (err error) {
err = errors.New(msgPoolIsNil) err = errors.New(msgPoolIsNil)
return return
} }
retcode := C.zpool_destroy(pool.list.zph, C.CString(logStr)) csLog := C.CString(logStr)
defer C.free(unsafe.Pointer(csLog))
retcode := C.zpool_destroy(pool.list.zph, csLog)
if retcode != 0 { if retcode != 0 {
err = LastError() err = LastError()
} }
@ -884,7 +912,9 @@ func (pool *Pool) Export(force bool, log string) (err error) {
if force { if force {
forcet = 1 forcet = 1
} }
if rc := C.zpool_export(pool.list.zph, forcet, C.CString(log)); rc != 0 { csLog := C.CString(log)
defer C.free(unsafe.Pointer(csLog))
if rc := C.zpool_export(pool.list.zph, forcet, csLog); rc != 0 {
err = LastError() err = LastError()
} }
return return
@ -892,11 +922,11 @@ func (pool *Pool) Export(force bool, log string) (err error) {
// ExportForce hard force export of the pool from the system. // 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) {
logstr := C.CString(log) csLog := C.CString(log)
if rc := C.zpool_export_force(pool.list.zph, logstr); rc != 0 { defer C.free(unsafe.Pointer(csLog))
if rc := C.zpool_export_force(pool.list.zph, csLog); rc != 0 {
err = LastError() err = LastError()
} }
C.free_cstring(logstr)
return return
} }

View File

@ -52,9 +52,6 @@ void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item);
void nvlist_free_array(nvlist_t **a); void nvlist_free_array(nvlist_t **a);
nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i); nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i);
void free_cstring(char *str);
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p, int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
vdev_stat_t **vds, uint_t *c); vdev_stat_t **vds, uint_t *c);