- Fix issue not building on go 1.8 , and some more improvements
This commit is contained in:
parent
fa91900915
commit
8fd0833477
|
@ -0,0 +1,56 @@
|
||||||
|
#include <libzfs.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
libzfs_handle_ptr libzfsHandle;
|
||||||
|
|
||||||
|
int go_libzfs_init() {
|
||||||
|
libzfsHandle = libzfs_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libzfs_last_error() {
|
||||||
|
return libzfs_errno(libzfsHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *libzfs_last_error_str() {
|
||||||
|
return libzfs_error_description(libzfsHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int libzfs_clear_last_error() {
|
||||||
|
zfs_standard_error(libzfsHandle, EZFS_SUCCESS, "success");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
property_list_t *new_property_list() {
|
||||||
|
property_list_t *r = malloc(sizeof(property_list_t));
|
||||||
|
memset(r, 0, sizeof(property_list_t));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_properties(property_list_t *root) {
|
||||||
|
if (root != 0) {
|
||||||
|
property_list_t *tmp = 0;
|
||||||
|
do {
|
||||||
|
tmp = root->pnext;
|
||||||
|
free(root);
|
||||||
|
root = tmp;
|
||||||
|
} while(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_ptr new_property_nvlist() {
|
||||||
|
nvlist_ptr props = NULL;
|
||||||
|
int r = nvlist_alloc(&props, NV_UNIQUE_NAME, 0);
|
||||||
|
if ( r != 0 ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
int property_nvlist_add(nvlist_ptr list, const char *prop, const char *value) {
|
||||||
|
return nvlist_add_string(list, prop, value);
|
||||||
|
}
|
13
common.go
13
common.go
|
@ -14,6 +14,7 @@ package zfs
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
|
#include "common.h"
|
||||||
#include "zpool.h"
|
#include "zpool.h"
|
||||||
#include "zfs.h"
|
#include "zfs.h"
|
||||||
*/
|
*/
|
||||||
|
@ -26,10 +27,8 @@ import (
|
||||||
// VDevType type of device in the pool
|
// VDevType type of device in the pool
|
||||||
type VDevType string
|
type VDevType string
|
||||||
|
|
||||||
var libzfsHandle C.libzfs_handle_ptr
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
libzfsHandle = C.libzfs_init()
|
C.go_libzfs_init()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,17 +255,13 @@ const (
|
||||||
|
|
||||||
// LastError 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(libzfsHandle)
|
return errors.New(C.GoString(C.libzfs_last_error_str()))
|
||||||
if errno == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New(C.GoString(C.libzfs_error_description(libzfsHandle)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearLastError 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(libzfsHandle)
|
C.libzfs_clear_last_error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INT_MAX_NAME 256
|
||||||
|
#define INT_MAX_VALUE 1024
|
||||||
|
#define ZAP_OLDMAXVALUELEN 1024
|
||||||
|
#define ZFS_MAX_DATASET_NAME_LEN 256
|
||||||
|
|
||||||
|
typedef struct property_list {
|
||||||
|
char value[INT_MAX_VALUE];
|
||||||
|
char source[ZFS_MAX_DATASET_NAME_LEN];
|
||||||
|
int property;
|
||||||
|
void *pnext;
|
||||||
|
} property_list_t;
|
||||||
|
|
||||||
|
typedef struct libzfs_handle* libzfs_handle_ptr;
|
||||||
|
typedef struct nvlist* nvlist_ptr;
|
||||||
|
typedef struct property_list *property_list_ptr;
|
||||||
|
typedef struct nvpair* nvpair_ptr;
|
||||||
|
typedef struct vdev_stat* vdev_stat_ptr;
|
||||||
|
typedef char* char_ptr;
|
||||||
|
|
||||||
|
extern libzfs_handle_ptr libzfsHandle;
|
||||||
|
|
||||||
|
int go_libzfs_init();
|
||||||
|
|
||||||
|
int libzfs_last_error();
|
||||||
|
const char *libzfs_last_error_str();
|
||||||
|
int libzfs_clear_last_error();
|
||||||
|
|
||||||
|
property_list_t *new_property_list();
|
||||||
|
void free_properties(property_list_t *root);
|
||||||
|
|
||||||
|
nvlist_ptr new_property_nvlist();
|
||||||
|
int property_nvlist_add(nvlist_ptr ptr, const char* prop, const char *value);
|
||||||
|
|
147
zfs.c
147
zfs.c
|
@ -7,6 +7,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "zpool.h"
|
#include "zpool.h"
|
||||||
#include "zfs.h"
|
#include "zfs.h"
|
||||||
|
|
||||||
|
@ -46,59 +47,144 @@ int dataset_list_callb(zfs_handle_t *dataset, void *data) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first) {
|
dataset_list_ptr dataset_list_root() {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
dataset_list_t *zlist = create_dataset_list_item();
|
dataset_list_t *zlist = create_dataset_list_item();
|
||||||
err = zfs_iter_root(libzfs, dataset_list_callb, &zlist);
|
err = zfs_iter_root(libzfsHandle, dataset_list_callb, &zlist);
|
||||||
if ( zlist->zh ) {
|
if ( err != 0 || zlist->zh == NULL) {
|
||||||
*first = zlist;
|
|
||||||
} else {
|
|
||||||
*first = 0;
|
|
||||||
dataset_list_free(zlist);
|
dataset_list_free(zlist);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
return err;
|
return zlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataset_list_t *dataset_next(dataset_list_t *dataset) {
|
dataset_list_ptr dataset_next(dataset_list_t *dataset) {
|
||||||
return dataset->pnext;
|
return dataset->pnext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dataset_type(dataset_list_ptr dataset) {
|
||||||
int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first) {
|
return zfs_get_type(dataset->zh);
|
||||||
int err = 0;
|
|
||||||
dataset_list_t *zlist = create_dataset_list_item();
|
|
||||||
err = zfs_iter_children(zfs, dataset_list_callb, &zlist);
|
|
||||||
if ( zlist->zh ) {
|
|
||||||
*first = zlist;
|
|
||||||
} else {
|
|
||||||
*first = 0;
|
|
||||||
dataset_list_free(zlist);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) {
|
dataset_list_ptr dataset_open(const char *path) {
|
||||||
|
dataset_list_ptr list = create_dataset_list_item();
|
||||||
|
list->zh = zfs_open(libzfsHandle, path, 0xF);
|
||||||
|
if (list->zh == NULL) {
|
||||||
|
dataset_list_free(list);
|
||||||
|
list = NULL;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_create(const char *path, zfs_type_t type, nvlist_ptr props) {
|
||||||
|
return zfs_create(libzfsHandle, path, type, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_destroy(dataset_list_ptr dataset, boolean_t defer) {
|
||||||
|
return zfs_destroy(dataset->zh, defer);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataset_list_t *dataset_list_children(dataset_list_t *dataset) {
|
||||||
|
int err = 0;
|
||||||
|
dataset_list_t *zlist = create_dataset_list_item();
|
||||||
|
err = zfs_iter_children(dataset->zh, dataset_list_callb, &zlist);
|
||||||
|
if ( err != 0 || zlist->zh == NULL) {
|
||||||
|
dataset_list_free(zlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return zlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
zpool_list_ptr dataset_get_pool(dataset_list_ptr dataset) {
|
||||||
|
zpool_list_ptr pool = create_zpool_list_item();
|
||||||
|
if(pool != NULL) {
|
||||||
|
pool->zph = zfs_get_pool_handle(dataset->zh);
|
||||||
|
}
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_prop_set(dataset_list_ptr dataset, zfs_prop_t prop, const char *value) {
|
||||||
|
return zfs_prop_set(dataset->zh, zfs_prop_to_name(prop), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_user_prop_set(dataset_list_ptr dataset, const char *prop, const char *value) {
|
||||||
|
return zfs_prop_set(dataset->zh, prop, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_clone(dataset_list_ptr dataset, const char *target, nvlist_ptr props) {
|
||||||
|
return zfs_clone(dataset->zh, target, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_snapshot(const char *path, boolean_t recur, nvlist_ptr props) {
|
||||||
|
return zfs_snapshot(libzfsHandle, path, recur, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_rollback(dataset_list_ptr dataset, dataset_list_ptr snapshot, boolean_t force) {
|
||||||
|
return zfs_rollback(dataset->zh, snapshot->zh, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_promote(dataset_list_ptr dataset) {
|
||||||
|
return zfs_promote(dataset->zh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_rename(dataset_list_ptr dataset, const char* new_name, boolean_t recur, boolean_t force_unm) {
|
||||||
|
return zfs_rename(dataset->zh, new_name, recur, force_unm);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dataset_is_mounted(dataset_list_ptr dataset){
|
||||||
|
char *mp;
|
||||||
|
if (0 != zfs_is_mounted(dataset->zh, &mp)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_mount(dataset_list_ptr dataset, const char *options, int flags) {
|
||||||
|
return zfs_mount(dataset->zh, options, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_unmount(dataset_list_ptr dataset, int flags) {
|
||||||
|
return zfs_unmount(dataset->zh, NULL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataset_unmountall(dataset_list_ptr dataset, int flags) {
|
||||||
|
return zfs_unmountall(dataset->zh, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dataset_get_name(dataset_list_ptr ds) {
|
||||||
|
return zfs_get_name(ds->zh);
|
||||||
|
}
|
||||||
|
|
||||||
|
//int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) {
|
||||||
|
property_list_t *read_dataset_property(dataset_list_t *dataset, int prop) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
zprop_source_t source;
|
zprop_source_t source;
|
||||||
char statbuf[INT_MAX_VALUE];
|
char statbuf[INT_MAX_VALUE];
|
||||||
|
property_list_ptr list;
|
||||||
|
list = new_property_list();
|
||||||
|
|
||||||
r = zfs_prop_get(zh, prop,
|
r = zfs_prop_get(dataset->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));
|
||||||
zprop_source_tostr(list->source, source);
|
zprop_source_tostr(list->source, source);
|
||||||
|
list->property = (int)prop;
|
||||||
|
} else {
|
||||||
|
free_properties(list);
|
||||||
|
list = NULL;
|
||||||
}
|
}
|
||||||
list->property = (int)prop;
|
return list;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) {
|
// int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) {
|
||||||
nvlist_t *user_props = zfs_get_user_props(zh);
|
property_list_t *read_user_property(dataset_list_t *dataset, const char* prop) {
|
||||||
|
nvlist_t *user_props = zfs_get_user_props(dataset->zh);
|
||||||
nvlist_t *propval;
|
nvlist_t *propval;
|
||||||
zprop_source_t sourcetype;
|
zprop_source_t sourcetype;
|
||||||
char *strval;
|
char *strval;
|
||||||
char *sourceval;
|
char *sourceval;
|
||||||
// char source[ZFS_MAX_DATASET_NAME_LEN];
|
// char source[ZFS_MAX_DATASET_NAME_LEN];
|
||||||
|
property_list_ptr list = new_property_list();
|
||||||
|
|
||||||
if (nvlist_lookup_nvlist(user_props,
|
if (nvlist_lookup_nvlist(user_props,
|
||||||
prop, &propval) != 0) {
|
prop, &propval) != 0) {
|
||||||
|
@ -113,7 +199,7 @@ int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop
|
||||||
ZPROP_SOURCE, &sourceval) == 0);
|
ZPROP_SOURCE, &sourceval) == 0);
|
||||||
|
|
||||||
if (strcmp(sourceval,
|
if (strcmp(sourceval,
|
||||||
zfs_get_name(zh)) == 0) {
|
zfs_get_name(dataset->zh)) == 0) {
|
||||||
sourcetype = ZPROP_SRC_LOCAL;
|
sourcetype = ZPROP_SRC_LOCAL;
|
||||||
(void) strncpy(list->source,
|
(void) strncpy(list->source,
|
||||||
"local", sizeof (list->source));
|
"local", sizeof (list->source));
|
||||||
|
@ -130,12 +216,7 @@ int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop
|
||||||
}
|
}
|
||||||
(void) strncpy(list->value,
|
(void) strncpy(list->value,
|
||||||
strval, sizeof (list->value));
|
strval, sizeof (list->value));
|
||||||
return 0;
|
return list;
|
||||||
}
|
|
||||||
|
|
||||||
int clear_last_error(libzfs_handle_t *hdl) {
|
|
||||||
zfs_standard_error(hdl, EZFS_SUCCESS, "success");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char** alloc_cstrings(int size) {
|
char** alloc_cstrings(int size) {
|
||||||
|
|
119
zfs.go
119
zfs.go
|
@ -2,6 +2,7 @@ package zfs
|
||||||
|
|
||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
// #include <libzfs.h>
|
// #include <libzfs.h>
|
||||||
|
// #include "common.h"
|
||||||
// #include "zpool.h"
|
// #include "zpool.h"
|
||||||
// #include "zfs.h"
|
// #include "zfs.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
@ -44,12 +45,11 @@ type Dataset struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dataset) openChildren() (err error) {
|
func (d *Dataset) openChildren() (err error) {
|
||||||
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, unsafe.Pointer(&list))
|
list := C.dataset_list_children(d.list)
|
||||||
for list != nil {
|
for list != nil {
|
||||||
dataset := Dataset{list: list}
|
dataset := Dataset{list: list}
|
||||||
dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
|
dataset.Type = DatasetType(C.dataset_type(d.list))
|
||||||
dataset.Properties = make(map[Prop]Property)
|
dataset.Properties = make(map[Prop]Property)
|
||||||
err = dataset.ReloadProperties()
|
err = dataset.ReloadProperties()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,10 +58,6 @@ func (d *Dataset) openChildren() (err error) {
|
||||||
d.Children = append(d.Children, dataset)
|
d.Children = append(d.Children, dataset)
|
||||||
list = C.dataset_next(list)
|
list = C.dataset_next(list)
|
||||||
}
|
}
|
||||||
if errcode != 0 {
|
|
||||||
err = LastError()
|
|
||||||
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
|
||||||
|
@ -74,9 +70,9 @@ 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, unsafe.Pointer(&dataset.list))
|
dataset.list = C.dataset_list_root()
|
||||||
for dataset.list != nil {
|
for dataset.list != nil {
|
||||||
dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh))
|
dataset.Type = DatasetType(C.dataset_type(dataset.list))
|
||||||
err = dataset.ReloadProperties()
|
err = dataset.ReloadProperties()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -84,10 +80,6 @@ func DatasetOpenAll() (datasets []Dataset, err error) {
|
||||||
datasets = append(datasets, dataset)
|
datasets = append(datasets, dataset)
|
||||||
dataset.list = C.dataset_next(dataset.list)
|
dataset.list = C.dataset_next(dataset.list)
|
||||||
}
|
}
|
||||||
if errcode != 0 {
|
|
||||||
err = LastError()
|
|
||||||
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
|
||||||
|
@ -106,22 +98,23 @@ 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()
|
|
||||||
csPath := C.CString(path)
|
csPath := C.CString(path)
|
||||||
d.list.zh = C.zfs_open(libzfsHandle, csPath, 0xF)
|
d.list = C.dataset_open(csPath)
|
||||||
C.free(unsafe.Pointer(csPath))
|
C.free(unsafe.Pointer(csPath))
|
||||||
|
|
||||||
if d.list.zh == nil {
|
if d.list == nil || d.list.zh == nil {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = fmt.Errorf("dataset not found.")
|
err = fmt.Errorf("dataset not found.")
|
||||||
}
|
}
|
||||||
|
println("open failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.Type = DatasetType(C.zfs_get_type(d.list.zh))
|
d.Type = DatasetType(C.dataset_type(d.list))
|
||||||
d.Properties = make(map[Prop]Property)
|
d.Properties = make(map[Prop]Property)
|
||||||
err = d.ReloadProperties()
|
err = d.ReloadProperties()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
println("reload properties failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = d.openChildren()
|
err = d.openChildren()
|
||||||
|
@ -131,16 +124,15 @@ func DatasetOpen(path string) (d Dataset, err error) {
|
||||||
func datasetPropertiesTonvlist(props map[Prop]Property) (
|
func datasetPropertiesTonvlist(props map[Prop]Property) (
|
||||||
cprops C.nvlist_ptr, err error) {
|
cprops C.nvlist_ptr, err error) {
|
||||||
// convert properties to nvlist C type
|
// convert properties to nvlist C type
|
||||||
r := C.nvlist_alloc(unsafe.Pointer(&cprops), C.NV_UNIQUE_NAME, 0)
|
cprops = C.new_property_nvlist()
|
||||||
if r != 0 {
|
if cprops == nil {
|
||||||
err = errors.New("Failed to allocate properties")
|
err = errors.New("Failed to allocate properties")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for prop, value := range props {
|
for prop, value := range props {
|
||||||
csValue := C.CString(value.Value)
|
csValue := C.CString(value.Value)
|
||||||
r := C.nvlist_add_string(
|
r := C.property_nvlist_add(
|
||||||
cprops, C.zfs_prop_to_name(
|
cprops, C.zfs_prop_to_name(C.zfs_prop_t(prop)), csValue)
|
||||||
C.zfs_prop_t(prop)), csValue)
|
|
||||||
C.free(unsafe.Pointer(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")
|
||||||
|
@ -161,13 +153,13 @@ func DatasetCreate(path string, dtype DatasetType,
|
||||||
defer C.nvlist_free(cprops)
|
defer C.nvlist_free(cprops)
|
||||||
|
|
||||||
csPath := C.CString(path)
|
csPath := C.CString(path)
|
||||||
errcode := C.zfs_create(libzfsHandle, csPath,
|
errcode := C.dataset_create(csPath, C.zfs_type_t(dtype), cprops)
|
||||||
C.zfs_type_t(dtype), cprops)
|
|
||||||
C.free(unsafe.Pointer(csPath))
|
C.free(unsafe.Pointer(csPath))
|
||||||
if errcode != 0 {
|
if errcode != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return
|
return DatasetOpen(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close close dataset and all its recursive children datasets (close handle
|
// Close close dataset and all its recursive children datasets (close handle
|
||||||
|
@ -184,7 +176,8 @@ func (d *Dataset) Close() {
|
||||||
|
|
||||||
// Destroy 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. Call Close() to
|
||||||
|
// cleanup memory.
|
||||||
func (d *Dataset) Destroy(Defer bool) (err error) {
|
func (d *Dataset) Destroy(Defer bool) (err error) {
|
||||||
if len(d.Children) > 0 {
|
if len(d.Children) > 0 {
|
||||||
path, e := d.Path()
|
path, e := d.Path()
|
||||||
|
@ -200,7 +193,7 @@ func (d *Dataset) Destroy(Defer bool) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if d.list != nil {
|
if d.list != nil {
|
||||||
if ec := C.zfs_destroy(d.list.zh, booleanT(Defer)); ec != 0 {
|
if ec := C.dataset_destroy(d.list, booleanT(Defer)); ec != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,9 +225,8 @@ func (d *Dataset) Pool() (p Pool, err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.list = C.create_zpool_list_item()
|
p.list = C.dataset_get_pool(d.list)
|
||||||
p.list.zph = C.zfs_get_pool_handle(d.list.zh)
|
if p.list != nil && p.list.zph != nil {
|
||||||
if p.list != nil {
|
|
||||||
err = p.ReloadProperties()
|
err = p.ReloadProperties()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -248,14 +240,10 @@ func (d *Dataset) ReloadProperties() (err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var plist C.property_list_ptr
|
|
||||||
|
|
||||||
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()
|
plist := C.read_dataset_property(d.list, C.int(prop))
|
||||||
errcode := C.read_dataset_property(d.list.zh, plist, C.int(prop))
|
if plist == nil {
|
||||||
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]),
|
||||||
|
@ -272,14 +260,12 @@ 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_ptr
|
plist := C.read_dataset_property(d.list, C.int(p))
|
||||||
plist = C.new_property_list()
|
if plist == nil {
|
||||||
defer C.free_properties(plist)
|
|
||||||
errcode := C.read_dataset_property(d.list.zh, plist, C.int(p))
|
|
||||||
if errcode != 0 {
|
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer C.free_properties(plist)
|
||||||
prop = Property{Value: C.GoString(&(*plist).value[0]),
|
prop = Property{Value: C.GoString(&(*plist).value[0]),
|
||||||
Source: C.GoString(&(*plist).source[0])}
|
Source: C.GoString(&(*plist).source[0])}
|
||||||
d.Properties[p] = prop
|
d.Properties[p] = prop
|
||||||
|
@ -291,16 +277,14 @@ 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_ptr
|
|
||||||
plist = C.new_property_list()
|
|
||||||
defer C.free_properties(plist)
|
|
||||||
csp := C.CString(p)
|
csp := C.CString(p)
|
||||||
defer C.free(unsafe.Pointer(csp))
|
defer C.free(unsafe.Pointer(csp))
|
||||||
errcode := C.read_user_property(d.list.zh, plist, csp)
|
plist := C.read_user_property(d.list, csp)
|
||||||
if errcode != 0 {
|
if plist == nil {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer C.free_properties(plist)
|
||||||
prop = Property{Value: C.GoString(&(*plist).value[0]),
|
prop = Property{Value: C.GoString(&(*plist).value[0]),
|
||||||
Source: C.GoString(&(*plist).source[0])}
|
Source: C.GoString(&(*plist).source[0])}
|
||||||
return
|
return
|
||||||
|
@ -315,8 +299,7 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
csValue := C.CString(value)
|
csValue := C.CString(value)
|
||||||
errcode := C.zfs_prop_set(d.list.zh, C.zfs_prop_to_name(
|
errcode := C.dataset_prop_set(d.list, C.zfs_prop_t(p), csValue)
|
||||||
C.zfs_prop_t(p)), csValue)
|
|
||||||
C.free(unsafe.Pointer(csValue))
|
C.free(unsafe.Pointer(csValue))
|
||||||
if errcode != 0 {
|
if errcode != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
|
@ -335,7 +318,7 @@ func (d *Dataset) SetUserProperty(prop, value string) (err error) {
|
||||||
}
|
}
|
||||||
csValue := C.CString(value)
|
csValue := C.CString(value)
|
||||||
csProp := C.CString(prop)
|
csProp := C.CString(prop)
|
||||||
errcode := C.zfs_prop_set(d.list.zh, csProp, csValue)
|
errcode := C.dataset_user_prop_set(d.list, csProp, csValue)
|
||||||
C.free(unsafe.Pointer(csValue))
|
C.free(unsafe.Pointer(csValue))
|
||||||
C.free(unsafe.Pointer(csProp))
|
C.free(unsafe.Pointer(csProp))
|
||||||
if errcode != 0 {
|
if errcode != 0 {
|
||||||
|
@ -358,7 +341,7 @@ func (d *Dataset) Clone(target string, props map[Prop]Property) (rd Dataset, err
|
||||||
defer C.nvlist_free(cprops)
|
defer C.nvlist_free(cprops)
|
||||||
csTarget := C.CString(target)
|
csTarget := C.CString(target)
|
||||||
defer C.free(unsafe.Pointer(csTarget))
|
defer C.free(unsafe.Pointer(csTarget))
|
||||||
if errc := C.zfs_clone(d.list.zh, csTarget, cprops); errc != 0 {
|
if errc := C.dataset_clone(d.list, csTarget, cprops); errc != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -375,7 +358,7 @@ func DatasetSnapshot(path string, recur bool, props map[Prop]Property) (rd Datas
|
||||||
defer C.nvlist_free(cprops)
|
defer C.nvlist_free(cprops)
|
||||||
csPath := C.CString(path)
|
csPath := C.CString(path)
|
||||||
defer C.free(unsafe.Pointer(csPath))
|
defer C.free(unsafe.Pointer(csPath))
|
||||||
if errc := C.zfs_snapshot(libzfsHandle, csPath, booleanT(recur), cprops); errc != 0 {
|
if errc := C.dataset_snapshot(csPath, booleanT(recur), cprops); errc != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -389,7 +372,7 @@ func (d *Dataset) Path() (path string, err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := C.zfs_get_name(d.list.zh)
|
name := C.dataset_get_name(d.list)
|
||||||
path = C.GoString(name)
|
path = C.GoString(name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -400,10 +383,11 @@ func (d *Dataset) Rollback(snap *Dataset, force bool) (err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if errc := C.zfs_rollback(d.list.zh,
|
if errc := C.dataset_rollback(d.list, snap.list, booleanT(force)); errc != 0 {
|
||||||
snap.list.zh, booleanT(force)); errc != 0 {
|
|
||||||
err = LastError()
|
err = LastError()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
d.ReloadProperties()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,9 +397,11 @@ func (d *Dataset) Promote() (err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if errc := C.zfs_promote(d.list.zh); errc != 0 {
|
if errc := C.dataset_promote(d.list); errc != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
d.ReloadProperties()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,10 +414,12 @@ func (d *Dataset) Rename(newName string, recur,
|
||||||
}
|
}
|
||||||
csNewName := C.CString(newName)
|
csNewName := C.CString(newName)
|
||||||
defer C.free(unsafe.Pointer(csNewName))
|
defer C.free(unsafe.Pointer(csNewName))
|
||||||
if errc := C.zfs_rename(d.list.zh, csNewName,
|
if errc := C.dataset_rename(d.list, csNewName,
|
||||||
booleanT(recur), booleanT(forceUnmount)); errc != 0 {
|
booleanT(recur), booleanT(forceUnmount)); errc != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
d.ReloadProperties()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,16 +427,15 @@ 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_ptr
|
|
||||||
if d.list == nil {
|
if d.list == nil {
|
||||||
return false, ""
|
return
|
||||||
}
|
}
|
||||||
m := C.zfs_is_mounted(d.list.zh, unsafe.Pointer(&cw))
|
mp := C.dataset_is_mounted(d.list)
|
||||||
// defer C.free(cw)
|
// defer C.free(mp)
|
||||||
if m != 0 {
|
if mounted = (mp != nil); mounted {
|
||||||
return true, C.GoString(cw)
|
where = C.GoString(mp)
|
||||||
}
|
}
|
||||||
return false, ""
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount the given filesystem.
|
// Mount the given filesystem.
|
||||||
|
@ -459,7 +446,7 @@ func (d *Dataset) Mount(options string, flags int) (err error) {
|
||||||
}
|
}
|
||||||
csOptions := C.CString(options)
|
csOptions := C.CString(options)
|
||||||
defer C.free(unsafe.Pointer(csOptions))
|
defer C.free(unsafe.Pointer(csOptions))
|
||||||
if ec := C.zfs_mount(d.list.zh, csOptions, C.int(flags)); ec != 0 {
|
if ec := C.dataset_mount(d.list, csOptions, C.int(flags)); ec != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -471,7 +458,7 @@ func (d *Dataset) Unmount(flags int) (err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ec := C.zfs_unmount(d.list.zh, nil, C.int(flags)); ec != 0 {
|
if ec := C.dataset_unmount(d.list, C.int(flags)); ec != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -484,7 +471,7 @@ func (d *Dataset) UnmountAll(flags int) (err error) {
|
||||||
err = errors.New(msgDatasetIsNil)
|
err = errors.New(msgDatasetIsNil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ec := C.zfs_unmountall(d.list.zh, C.int(flags)); ec != 0 {
|
if ec := C.dataset_unmountall(d.list, C.int(flags)); ec != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
26
zfs.h
26
zfs.h
|
@ -18,14 +18,30 @@ 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);
|
void dataset_list_free(dataset_list_t *list);
|
||||||
|
|
||||||
int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first);
|
dataset_list_t* dataset_list_root();
|
||||||
int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first);
|
dataset_list_t* dataset_list_children(dataset_list_t *dataset);
|
||||||
dataset_list_t *dataset_next(dataset_list_t *dataset);
|
dataset_list_t *dataset_next(dataset_list_t *dataset);
|
||||||
|
int dataset_type(dataset_list_ptr dataset);
|
||||||
|
|
||||||
int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop);
|
dataset_list_ptr dataset_open(const char *path);
|
||||||
int read_user_property(zfs_handle_t *zh, property_list_t *list, const char* prop);
|
int dataset_create(const char *path, zfs_type_t type, nvlist_ptr props);
|
||||||
|
int dataset_destroy(dataset_list_ptr dataset, boolean_t defer);
|
||||||
|
zpool_list_ptr dataset_get_pool(dataset_list_ptr dataset);
|
||||||
|
int dataset_prop_set(dataset_list_ptr dataset, zfs_prop_t prop, const char *value);
|
||||||
|
int dataset_user_prop_set(dataset_list_ptr dataset, const char *prop, const char *value);
|
||||||
|
int dataset_clone(dataset_list_ptr dataset, const char *target, nvlist_ptr props);
|
||||||
|
int dataset_snapshot(const char *path, boolean_t recur, nvlist_ptr props);
|
||||||
|
int dataset_rollback(dataset_list_ptr dataset, dataset_list_ptr snapshot, boolean_t force);
|
||||||
|
int dataset_promote(dataset_list_ptr dataset);
|
||||||
|
int dataset_rename(dataset_list_ptr dataset, const char* new_name, boolean_t recur, boolean_t force_unm);
|
||||||
|
const char* dataset_is_mounted(dataset_list_ptr dataset);
|
||||||
|
int dataset_mount(dataset_list_ptr dataset, const char *options, int flags);
|
||||||
|
int dataset_unmount(dataset_list_ptr dataset, int flags);
|
||||||
|
int dataset_unmountall(dataset_list_ptr dataset, int flags);
|
||||||
|
const char *dataset_get_name(dataset_list_ptr ds);
|
||||||
|
|
||||||
int clear_last_error(libzfs_handle_t *libzfs);
|
property_list_t *read_dataset_property(dataset_list_t *dataset, int prop);
|
||||||
|
property_list_t *read_user_property(dataset_list_t *dataset, const char* prop);
|
||||||
|
|
||||||
char** alloc_cstrings(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);
|
||||||
|
|
449
zpool.c
449
zpool.c
|
@ -7,6 +7,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "zpool.h"
|
#include "zpool.h"
|
||||||
|
|
||||||
char *sZPOOL_CONFIG_VERSION = ZPOOL_CONFIG_VERSION;
|
char *sZPOOL_CONFIG_VERSION = ZPOOL_CONFIG_VERSION;
|
||||||
|
@ -109,26 +110,24 @@ int zpool_list_callb(zpool_handle_t *pool, void *data) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zpool_list(libzfs_handle_t *libzfs, zpool_list_t **first) {
|
zpool_list_ptr zpool_list_openall() {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
zpool_list_t *zlist = create_zpool_list_item();
|
zpool_list_t *zlist = create_zpool_list_item();
|
||||||
err = zpool_iter(libzfs, zpool_list_callb, &zlist);
|
err = zpool_iter(libzfsHandle, zpool_list_callb, &zlist);
|
||||||
if ( zlist->zph ) {
|
if ( err != 0 || zlist->zph == NULL ) {
|
||||||
*first = zlist;
|
zpool_list_free(zlist);
|
||||||
} else {
|
zlist = NULL;
|
||||||
*first = 0;
|
|
||||||
free(zlist);
|
|
||||||
}
|
}
|
||||||
return err;
|
return zlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
zpool_list_t* zpool_list_open(libzfs_handle_t *libzfs, const char *name) {
|
zpool_list_t* zpool_list_open(const char *name) {
|
||||||
zpool_list_t *zlist = create_zpool_list_item();
|
zpool_list_t *zlist = create_zpool_list_item();
|
||||||
zlist->zph = zpool_open(libzfs, name);
|
zlist->zph = zpool_open(libzfsHandle, name);
|
||||||
if ( zlist->zph ) {
|
if ( zlist->zph ) {
|
||||||
return zlist;
|
return zlist;
|
||||||
} else {
|
} else {
|
||||||
free(zlist);
|
zpool_list_free(zlist);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -137,26 +136,18 @@ zpool_list_t *zpool_next(zpool_list_t *pool) {
|
||||||
return pool->pnext;
|
return pool->pnext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void zpool_list_free(zpool_list_t *list) {
|
||||||
|
zpool_list_ptr next;
|
||||||
|
while(list) {
|
||||||
|
next = list->pnext;
|
||||||
|
free(list);
|
||||||
|
list = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void zpool_list_close(zpool_list_t *pool) {
|
void zpool_list_close(zpool_list_t *pool) {
|
||||||
zpool_close(pool->zph);
|
zpool_close(pool->zph);
|
||||||
free(pool);
|
zpool_list_free(pool);
|
||||||
}
|
|
||||||
|
|
||||||
property_list_t *new_property_list() {
|
|
||||||
property_list_t *r = malloc(sizeof(property_list_t));
|
|
||||||
memset(r, 0, sizeof(property_list_t));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_properties(property_list_t *root) {
|
|
||||||
if (root != 0) {
|
|
||||||
property_list_t *tmp = 0;
|
|
||||||
do {
|
|
||||||
tmp = root->pnext;
|
|
||||||
free(root);
|
|
||||||
root = tmp;
|
|
||||||
} while(tmp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
property_list_t *next_property(property_list_t *list) {
|
property_list_t *next_property(property_list_t *list) {
|
||||||
|
@ -191,161 +182,68 @@ void zprop_source_tostr(char *dst, zprop_source_t source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int read_zpool_property(zpool_handle_t *zh, property_list_t *list, int prop) {
|
property_list_ptr read_zpool_property(zpool_list_ptr pool, int prop) {
|
||||||
|
|
||||||
int r = 0;
|
int r = 0;
|
||||||
zprop_source_t source;
|
zprop_source_t source;
|
||||||
|
property_list_ptr list = new_property_list();
|
||||||
|
|
||||||
r = zpool_get_prop(zh, prop,
|
r = zpool_get_prop(pool->zph, prop,
|
||||||
list->value, INT_MAX_VALUE, &source);
|
list->value, INT_MAX_VALUE, &source);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
// strcpy(list->name, zpool_prop_to_name(prop));
|
// strcpy(list->name, zpool_prop_to_name(prop));
|
||||||
zprop_source_tostr(list->source, source);
|
zprop_source_tostr(list->source, source);
|
||||||
|
} else {
|
||||||
|
free_properties(list);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
list->property = (int)prop;
|
list->property = (int)prop;
|
||||||
return r;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_append_zpool_property(zpool_handle_t *zh, property_list_t **proot,
|
property_list_ptr read_append_zpool_property(zpool_list_ptr pool, property_list_ptr proot, zpool_prop_t prop) {
|
||||||
zpool_prop_t prop) {
|
|
||||||
int r = 0;
|
int r = 0;
|
||||||
property_list_t *newitem = NULL, *root = *proot;
|
property_list_t *newitem = NULL;
|
||||||
newitem = new_property_list();
|
|
||||||
|
|
||||||
r = read_zpool_property(zh, newitem, prop);
|
newitem = read_zpool_property(pool, prop);
|
||||||
// printf("p: %s %s %s\n", newitem->name, newitem->value, newitem->source);
|
if (newitem == NULL) {
|
||||||
newitem->pnext = root;
|
return proot;
|
||||||
*proot = root = newitem;
|
|
||||||
if (r != 0) {
|
|
||||||
free_properties(root);
|
|
||||||
*proot = NULL;
|
|
||||||
}
|
}
|
||||||
return r;
|
// printf("p: %s %s %s\n", newitem->name, newitem->value, newitem->source);
|
||||||
|
newitem->pnext = proot;
|
||||||
|
proot = newitem;
|
||||||
|
|
||||||
|
return proot;
|
||||||
}
|
}
|
||||||
|
|
||||||
property_list_t *read_zpool_properties(zpool_handle_t *zh) {
|
property_list_t *read_zpool_properties(zpool_list_ptr pool) {
|
||||||
// read pool name as first property
|
// read pool name as first property
|
||||||
property_list_t *root = NULL, *list = NULL;
|
property_list_t *root = NULL, *list = NULL;
|
||||||
|
|
||||||
int r = read_append_zpool_property(zh, &root, ZPOOL_PROP_NAME);
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_NAME);
|
||||||
if (r != 0) {
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_SIZE);
|
||||||
return 0;
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_CAPACITY);
|
||||||
}
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_ALTROOT);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_HEALTH);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_GUID);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_VERSION);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_BOOTFS);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_DELEGATION);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_AUTOREPLACE);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_CACHEFILE);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_FAILUREMODE);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_LISTSNAPS);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_AUTOEXPAND);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_DEDUPDITTO);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_DEDUPRATIO);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_FREE);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_ALLOCATED);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_READONLY);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_ASHIFT);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_COMMENT);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_EXPANDSZ);
|
||||||
|
root = read_append_zpool_property(pool, root, ZPOOL_PROP_FREEING);
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_SIZE);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_CAPACITY);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ALTROOT);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_HEALTH);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_GUID);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_VERSION);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_BOOTFS);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DELEGATION);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_AUTOREPLACE);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_CACHEFILE);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FAILUREMODE);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_LISTSNAPS);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_AUTOEXPAND);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DEDUPDITTO);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DEDUPRATIO);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FREE);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ALLOCATED);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_READONLY);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ASHIFT);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_COMMENT);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_EXPANDSZ);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FREEING);
|
|
||||||
if (r != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
list = new_property_list();
|
list = new_property_list();
|
||||||
|
@ -370,85 +268,75 @@ const char *gettext(const char *txt) {
|
||||||
/*
|
/*
|
||||||
* Add a property pair (name, string-value) into a property nvlist.
|
* Add a property pair (name, string-value) into a property nvlist.
|
||||||
*/
|
*/
|
||||||
int
|
// int
|
||||||
add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
// add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
||||||
boolean_t poolprop) {
|
// boolean_t poolprop) {
|
||||||
zpool_prop_t prop = ZPROP_INVAL;
|
// zpool_prop_t prop = ZPROP_INVAL;
|
||||||
zfs_prop_t fprop;
|
// zfs_prop_t fprop;
|
||||||
nvlist_t *proplist;
|
// nvlist_t *proplist;
|
||||||
const char *normnm;
|
// const char *normnm;
|
||||||
char *strval;
|
// char *strval;
|
||||||
|
|
||||||
if (*props == NULL &&
|
// if (*props == NULL &&
|
||||||
nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
|
// nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
|
||||||
(void) snprintf(_lasterr_, 1024, "internal error: out of memory");
|
// (void) snprintf(_lasterr_, 1024, "internal error: out of memory");
|
||||||
return (1);
|
// return (1);
|
||||||
}
|
// }
|
||||||
|
|
||||||
proplist = *props;
|
// proplist = *props;
|
||||||
|
|
||||||
if (poolprop) {
|
// if (poolprop) {
|
||||||
const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
|
// const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
|
||||||
|
|
||||||
if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
|
// if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
|
||||||
!zpool_prop_feature(propname)) {
|
// !zpool_prop_feature(propname)) {
|
||||||
(void) snprintf(_lasterr_, 1024, "property '%s' is "
|
// (void) snprintf(_lasterr_, 1024, "property '%s' is "
|
||||||
"not a valid pool property", propname);
|
// "not a valid pool property", propname);
|
||||||
return (2);
|
// return (2);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/*
|
// /*
|
||||||
* feature@ properties and version should not be specified
|
// * feature@ properties and version should not be specified
|
||||||
* at the same time.
|
// * at the same time.
|
||||||
*/
|
// */
|
||||||
// if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
|
// // if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
|
||||||
// nvlist_exists(proplist, vname)) ||
|
// // nvlist_exists(proplist, vname)) ||
|
||||||
// (prop == ZPOOL_PROP_VERSION &&
|
// // (prop == ZPOOL_PROP_VERSION &&
|
||||||
// prop_list_contains_feature(proplist))) {
|
// // prop_list_contains_feature(proplist))) {
|
||||||
// (void) fprintf(stderr, gettext("'feature@' and "
|
// // (void) fprintf(stderr, gettext("'feature@' and "
|
||||||
// "'version' properties cannot be specified "
|
// // "'version' properties cannot be specified "
|
||||||
// "together\n"));
|
// // "together\n"));
|
||||||
// return (2);
|
// // return (2);
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
|
|
||||||
if (zpool_prop_feature(propname))
|
// if (zpool_prop_feature(propname))
|
||||||
normnm = propname;
|
// normnm = propname;
|
||||||
else
|
// else
|
||||||
normnm = zpool_prop_to_name(prop);
|
// normnm = zpool_prop_to_name(prop);
|
||||||
} else {
|
// } else {
|
||||||
if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
|
// if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
|
||||||
normnm = zfs_prop_to_name(fprop);
|
// normnm = zfs_prop_to_name(fprop);
|
||||||
} else {
|
// } else {
|
||||||
normnm = propname;
|
// normnm = propname;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
|
// if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
|
||||||
prop != ZPOOL_PROP_CACHEFILE) {
|
// prop != ZPOOL_PROP_CACHEFILE) {
|
||||||
(void) snprintf(_lasterr_, 1024, "property '%s' "
|
// (void) snprintf(_lasterr_, 1024, "property '%s' "
|
||||||
"specified multiple times", propname);
|
// "specified multiple times", propname);
|
||||||
return (2);
|
// return (2);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (nvlist_add_string(proplist, normnm, propval) != 0) {
|
// if (nvlist_add_string(proplist, normnm, propval) != 0) {
|
||||||
(void) snprintf(_lasterr_, 1024, "internal "
|
// (void) snprintf(_lasterr_, 1024, "internal "
|
||||||
"error: out of memory\n");
|
// "error: out of memory\n");
|
||||||
return (1);
|
// return (1);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (0);
|
// return (0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
|
|
||||||
vdev_stat_t **vds, uint_t *c) {
|
|
||||||
return nvlist_lookup_uint64_array(nv, p, (uint64_t**)vds, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nvlist_lookup_uint64_array_ps(nvlist_t *nv, const char *p,
|
|
||||||
pool_scan_stat_t **vds, uint_t *c) {
|
|
||||||
return nvlist_lookup_uint64_array(nv, p, (uint64_t**)vds, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvlist_t** nvlist_alloc_array(int count) {
|
nvlist_t** nvlist_alloc_array(int count) {
|
||||||
return malloc(count*sizeof(nvlist_t*));
|
return malloc(count*sizeof(nvlist_t*));
|
||||||
|
@ -478,3 +366,100 @@ int refresh_stats(zpool_list_t *pool)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_vdev_type(nvlist_ptr nv) {
|
||||||
|
char *value = NULL;
|
||||||
|
int r = nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &value);
|
||||||
|
if(r != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vdev_stat_ptr get_vdev_stats(nvlist_ptr nv) {
|
||||||
|
vdev_stat_ptr vs = NULL;
|
||||||
|
uint_t count;
|
||||||
|
int r = nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t**)&vs, &count);
|
||||||
|
if(r != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return vs;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_scan_stat_ptr get_vdev_scan_stats(nvlist_t *nv) {
|
||||||
|
pool_scan_stat_ptr vds = NULL;
|
||||||
|
uint_t c;
|
||||||
|
int r = nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, (uint64_t**)&vds, &c);
|
||||||
|
if(r != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return vds;
|
||||||
|
}
|
||||||
|
|
||||||
|
vdev_children_ptr get_vdev_children(nvlist_t *nv) {
|
||||||
|
int r;
|
||||||
|
vdev_children_ptr children = malloc(sizeof(vdev_children_t));
|
||||||
|
memset(children, 0, sizeof(vdev_children_t));
|
||||||
|
r = nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &(children->first), &(children->count));
|
||||||
|
if (r != 0) {
|
||||||
|
free(children);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_vdev_path(nvlist_ptr nv) {
|
||||||
|
char *path = NULL;
|
||||||
|
uint64_t notpresent = 0;
|
||||||
|
int r = nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, ¬present);
|
||||||
|
if (r == 0 || notpresent != 0) {
|
||||||
|
if ( 0 != nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t get_vdev_is_log(nvlist_ptr nv) {
|
||||||
|
uint64_t islog = B_FALSE;
|
||||||
|
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &islog);
|
||||||
|
return islog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return
|
||||||
|
uint64_t get_zpool_state(nvlist_ptr nv) {
|
||||||
|
uint64_t state = 0;
|
||||||
|
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_POOL_STATE, &state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t get_zpool_guid(nvlist_ptr nv) {
|
||||||
|
uint64_t guid = 0;
|
||||||
|
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_POOL_GUID, &guid);
|
||||||
|
return guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_zpool_name(nvlist_ptr nv) {
|
||||||
|
char *name = NULL;
|
||||||
|
if (0 != nvlist_lookup_string(nv, ZPOOL_CONFIG_POOL_NAME, &name)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_zpool_comment(nvlist_ptr nv) {
|
||||||
|
char *comment = NULL;
|
||||||
|
if (0 != nvlist_lookup_string(nv, ZPOOL_CONFIG_COMMENT, &comment)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_ptr get_zpool_vdev_tree(nvlist_ptr nv) {
|
||||||
|
nvlist_ptr vdev_tree = NULL;
|
||||||
|
if ( 0 != nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return vdev_tree;
|
||||||
|
}
|
152
zpool.go
152
zpool.go
|
@ -2,6 +2,7 @@ package zfs
|
||||||
|
|
||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
// #include <libzfs.h>
|
// #include <libzfs.h>
|
||||||
|
// #include "common.h"
|
||||||
// #include "zpool.h"
|
// #include "zpool.h"
|
||||||
// #include "zfs.h"
|
// #include "zfs.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
@ -138,7 +139,7 @@ type Pool struct {
|
||||||
func PoolOpen(name string) (pool Pool, err error) {
|
func PoolOpen(name string) (pool Pool, err error) {
|
||||||
csName := C.CString(name)
|
csName := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(csName))
|
defer C.free(unsafe.Pointer(csName))
|
||||||
pool.list = C.zpool_list_open(libzfsHandle, csName)
|
pool.list = C.zpool_list_open(csName)
|
||||||
|
|
||||||
if pool.list != nil {
|
if pool.list != nil {
|
||||||
err = pool.ReloadProperties()
|
err = pool.ReloadProperties()
|
||||||
|
@ -150,12 +151,10 @@ func PoolOpen(name string) (pool Pool, err error) {
|
||||||
|
|
||||||
func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
|
func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
|
||||||
var dtype C.char_ptr
|
var dtype C.char_ptr
|
||||||
var c, children C.uint_t
|
|
||||||
var notpresent C.uint64_t
|
|
||||||
var vs C.vdev_stat_ptr
|
var vs C.vdev_stat_ptr
|
||||||
var ps C.pool_scan_stat_ptr
|
var ps C.pool_scan_stat_ptr
|
||||||
var child *C.nvlist_ptr
|
var children C.vdev_children_ptr
|
||||||
if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_TYPE, unsafe.Pointer(&dtype)) {
|
if dtype = C.get_vdev_type(nv); dtype == nil {
|
||||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE)
|
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -166,8 +165,7 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (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 vs = C.get_vdev_stats(nv); vs == nil {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -192,8 +190,7 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
|
||||||
vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation)
|
vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation)
|
||||||
|
|
||||||
// Fetch vdev scan stats
|
// Fetch vdev scan stats
|
||||||
if 0 == C.nvlist_lookup_uint64_array_ps(nv, C.sZPOOL_CONFIG_SCAN_STATS,
|
if ps = C.get_vdev_scan_stats(nv); ps != nil {
|
||||||
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)
|
||||||
|
@ -208,35 +205,28 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the children
|
// Fetch the children
|
||||||
if C.nvlist_lookup_nvlist_array(nv, C.sZPOOL_CONFIG_CHILDREN,
|
children = C.get_vdev_children(nv)
|
||||||
unsafe.Pointer(&child), &children) != 0 {
|
if children != nil {
|
||||||
children = 0
|
// this object that reference childrens and count should be deallocated from memory
|
||||||
|
defer C.free(unsafe.Pointer(children))
|
||||||
|
vdevs.Devices = make([]VDevTree, 0, children.count)
|
||||||
}
|
}
|
||||||
if children > 0 {
|
path := C.get_vdev_path(nv)
|
||||||
vdevs.Devices = make([]VDevTree, 0, children)
|
if path != nil {
|
||||||
}
|
|
||||||
if C.nvlist_lookup_uint64(nv, C.sZPOOL_CONFIG_NOT_PRESENT,
|
|
||||||
¬present) == 0 || notpresent != 0 {
|
|
||||||
var path C.char_ptr
|
|
||||||
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)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
vdevs.Path = C.GoString(path)
|
vdevs.Path = C.GoString(path)
|
||||||
}
|
}
|
||||||
for c = 0; c < children; c++ {
|
for c := C.uint_t(0); children != nil && c < children.count; c++ {
|
||||||
var islog = C.uint64_t(C.B_FALSE)
|
var islog = C.uint64_t(C.B_FALSE)
|
||||||
|
|
||||||
C.nvlist_lookup_uint64(C.nvlist_array_at(child, c),
|
islog = C.get_vdev_is_log(C.nvlist_array_at(children.first, c))
|
||||||
C.sZPOOL_CONFIG_IS_LOG, &islog)
|
|
||||||
if islog != C.B_FALSE {
|
if islog != C.B_FALSE {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
vname := C.zpool_vdev_name(libzfsHandle, nil, C.nvlist_array_at(child, c),
|
vname := C.zpool_vdev_name(C.libzfsHandle, nil, C.nvlist_array_at(children.first, 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(children.first, c))
|
||||||
C.free(unsafe.Pointer(vname))
|
C.free(unsafe.Pointer(vname))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -251,7 +241,6 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
|
||||||
func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
|
func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
|
||||||
var config, nvroot C.nvlist_ptr
|
var config, nvroot C.nvlist_ptr
|
||||||
var cname, msgid, comment C.char_ptr
|
var cname, msgid, comment C.char_ptr
|
||||||
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
|
||||||
|
@ -265,41 +254,35 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
|
||||||
C.strings_setat(cpaths, C.int(i), csPath)
|
C.strings_setat(cpaths, C.int(i), csPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths)
|
pools := C.zpool_find_import(C.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)
|
||||||
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, unsafe.Pointer(&config)) != 0 {
|
if C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&config)) != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if C.nvlist_lookup_uint64(config, C.sZPOOL_CONFIG_POOL_STATE,
|
|
||||||
&poolState) != 0 {
|
ep.State = PoolState(C.get_zpool_state(config))
|
||||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_STATE)
|
|
||||||
return
|
if cname = C.get_zpool_name(config); cname == nil {
|
||||||
}
|
|
||||||
ep.State = PoolState(poolState)
|
|
||||||
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
|
||||||
}
|
}
|
||||||
ep.Name = C.GoString(cname)
|
ep.Name = C.GoString(cname)
|
||||||
if C.nvlist_lookup_uint64(config, C.sZPOOL_CONFIG_POOL_GUID, &guid) != 0 {
|
|
||||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_GUID)
|
ep.GUID = uint64(C.get_zpool_guid(config))
|
||||||
return
|
|
||||||
}
|
reason = C.zpool_import_status(config, (**C.char)(&msgid), &errata)
|
||||||
ep.GUID = uint64(guid)
|
|
||||||
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, unsafe.Pointer(&comment)) == 0 {
|
if comment = C.get_zpool_comment(config); comment != nil {
|
||||||
ep.Comment = C.GoString(comment)
|
ep.Comment = C.GoString(comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE,
|
if nvroot = C.get_zpool_vdev_tree(config); nvroot == nil {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -325,33 +308,26 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
|
||||||
C.strings_setat(cpaths, C.int(i), csPath)
|
C.strings_setat(cpaths, C.int(i), csPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths)
|
pools := C.zpool_find_import(C.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)
|
||||||
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, unsafe.Pointer(&tconfig))
|
retcode := C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&tconfig))
|
||||||
if retcode != 0 {
|
if retcode != 0 {
|
||||||
err = errPoolList
|
err = errPoolList
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if guid {
|
if guid {
|
||||||
var iguid C.uint64_t
|
sguid := fmt.Sprint(C.get_zpool_guid(tconfig))
|
||||||
if retcode = C.nvlist_lookup_uint64(tconfig,
|
|
||||||
C.sZPOOL_CONFIG_POOL_GUID, &iguid); retcode != 0 {
|
|
||||||
err = errPoolList
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sguid := fmt.Sprint(iguid)
|
|
||||||
if q == sguid {
|
if q == sguid {
|
||||||
config = tconfig
|
config = tconfig
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if retcode = C.nvlist_lookup_string(tconfig,
|
if cq = C.get_zpool_name(tconfig); cq == nil {
|
||||||
C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cq)); retcode != 0 {
|
|
||||||
err = errPoolList
|
err = errPoolList
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -369,14 +345,13 @@ 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 cname = C.get_zpool_name(config); cname == nil {
|
||||||
C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)); retcode != 0 {
|
|
||||||
err = errPoolList
|
err = errPoolList
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name = C.GoString(cname)
|
name = C.GoString(cname)
|
||||||
}
|
}
|
||||||
if retcode := C.zpool_import(libzfsHandle, config, cname,
|
if retcode := C.zpool_import(C.libzfsHandle, config, cname,
|
||||||
nil); retcode != 0 {
|
nil); retcode != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
|
@ -416,17 +391,19 @@ 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, unsafe.Pointer(&pool.list))
|
if pool.list = C.zpool_list_openall(); pool.list == nil {
|
||||||
|
err = LastError()
|
||||||
|
return
|
||||||
|
}
|
||||||
for pool.list != nil {
|
for pool.list != nil {
|
||||||
err = pool.ReloadProperties()
|
err = pool.ReloadProperties()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
next := C.zpool_next(pool.list)
|
||||||
|
pool.list.pnext = nil
|
||||||
pools = append(pools, pool)
|
pools = append(pools, pool)
|
||||||
pool.list = C.zpool_next(pool.list)
|
pool.list = next
|
||||||
}
|
|
||||||
if errcode != 0 {
|
|
||||||
err = LastError()
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -469,7 +446,7 @@ func (pool *Pool) RefreshStats() (err error) {
|
||||||
// ReloadProperties re-read ZFS pool properties and features, refresh
|
// ReloadProperties re-read ZFS pool properties and features, refresh
|
||||||
// Pool.Properties and 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)
|
||||||
if propList == nil {
|
if propList == nil {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
|
@ -515,11 +492,12 @@ func (pool *Pool) GetProperty(p Prop) (prop Property, err error) {
|
||||||
PoolPropertyToName(p)))
|
PoolPropertyToName(p)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var list C.property_list_t
|
list := C.read_zpool_property(pool.list, C.int(p))
|
||||||
r := C.read_zpool_property(pool.list.zph, unsafe.Pointer(&list), C.int(p))
|
if list == nil {
|
||||||
if r != 0 {
|
|
||||||
err = LastError()
|
err = LastError()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
defer C.free_properties(list)
|
||||||
prop.Value = C.GoString(&(list.value[0]))
|
prop.Value = C.GoString(&(list.value[0]))
|
||||||
prop.Source = C.GoString(&(list.source[0]))
|
prop.Source = C.GoString(&(list.source[0]))
|
||||||
pool.Properties[p] = prop
|
pool.Properties[p] = prop
|
||||||
|
@ -576,8 +554,10 @@ func (pool *Pool) SetProperty(p Prop, value string) (err error) {
|
||||||
// Close ZFS pool handler and release associated memory.
|
// Close ZFS pool handler and release associated memory.
|
||||||
// Do not use Pool object after this.
|
// Do not use Pool object after this.
|
||||||
func (pool *Pool) Close() {
|
func (pool *Pool) Close() {
|
||||||
C.zpool_list_close(pool.list)
|
if pool.list != nil {
|
||||||
pool.list = nil
|
C.zpool_list_close(pool.list)
|
||||||
|
pool.list = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name get (re-read) ZFS pool name property
|
// Name get (re-read) ZFS pool name property
|
||||||
|
@ -633,11 +613,11 @@ func (vdev *VDevTree) isLog() (r C.uint64_t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) {
|
func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) {
|
||||||
cprops = nil
|
cprops = C.new_property_nvlist()
|
||||||
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, unsafe.Pointer(&cprops), C.boolean_t(1))
|
r := C.property_nvlist_add(cprops, name, csPropValue)
|
||||||
C.free(unsafe.Pointer(csPropValue))
|
C.free(unsafe.Pointer(csPropValue))
|
||||||
if r != 0 {
|
if r != 0 {
|
||||||
if cprops != nil {
|
if cprops != nil {
|
||||||
|
@ -651,11 +631,11 @@ func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCDatasetProperties(props DatasetProperties) (cprops C.nvlist_ptr) {
|
func toCDatasetProperties(props DatasetProperties) (cprops C.nvlist_ptr) {
|
||||||
cprops = nil
|
cprops = C.new_property_nvlist()
|
||||||
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, unsafe.Pointer(&cprops), C.boolean_t(0))
|
r := C.property_nvlist_add(cprops, name, csPropValue)
|
||||||
C.free(unsafe.Pointer(csPropValue))
|
C.free(unsafe.Pointer(csPropValue))
|
||||||
if r != 0 {
|
if r != 0 {
|
||||||
if cprops != nil {
|
if cprops != nil {
|
||||||
|
@ -696,9 +676,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_ptr
|
var child *C.struct_nvlist
|
||||||
// fmt.Println(vdev.Type)
|
// fmt.Println(vdev.Type)
|
||||||
if r := C.nvlist_alloc(unsafe.Pointer(&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")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -812,8 +792,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_ptr
|
var nvroot *C.struct_nvlist
|
||||||
if r := C.nvlist_alloc(unsafe.Pointer(&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
|
||||||
}
|
}
|
||||||
|
@ -860,8 +840,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, unsafe.Pointer(&cprops),
|
r := C.property_nvlist_add(cprops, csName, csVal)
|
||||||
C.boolean_t(1))
|
|
||||||
C.free(unsafe.Pointer(csName))
|
C.free(unsafe.Pointer(csName))
|
||||||
C.free(unsafe.Pointer(csVal))
|
C.free(unsafe.Pointer(csVal))
|
||||||
if r != 0 {
|
if r != 0 {
|
||||||
|
@ -876,7 +855,7 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
|
||||||
// Create actual pool then open
|
// Create actual pool then open
|
||||||
csName := C.CString(name)
|
csName := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(csName))
|
defer C.free(unsafe.Pointer(csName))
|
||||||
if r := C.zpool_create(libzfsHandle, csName, nvroot,
|
if r := C.zpool_create(C.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)")
|
||||||
|
@ -890,14 +869,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_ptr
|
var msgid *C.char
|
||||||
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, unsafe.Pointer(&msgid), &errata)
|
reason = C.zpool_get_status(pool.list.zph, &msgid, &errata)
|
||||||
status = PoolStatus(reason)
|
status = PoolStatus(reason)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -948,15 +927,14 @@ 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_ptr
|
var nvroot *C.struct_nvlist
|
||||||
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 {
|
||||||
err = fmt.Errorf("Failed zpool_get_config")
|
err = fmt.Errorf("Failed zpool_get_config")
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
64
zpool.h
64
zpool.h
|
@ -5,72 +5,68 @@
|
||||||
#ifndef SERVERWARE_ZPOOL_H
|
#ifndef SERVERWARE_ZPOOL_H
|
||||||
#define SERVERWARE_ZPOOL_H
|
#define SERVERWARE_ZPOOL_H
|
||||||
|
|
||||||
#define INT_MAX_NAME 256
|
|
||||||
#define INT_MAX_VALUE 1024
|
|
||||||
#define ZAP_OLDMAXVALUELEN 1024
|
|
||||||
#define ZFS_MAX_DATASET_NAME_LEN 256
|
|
||||||
|
|
||||||
struct zpool_list {
|
struct zpool_list {
|
||||||
zpool_handle_t *zph;
|
zpool_handle_t *zph;
|
||||||
void *pnext;
|
void *pnext;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct property_list {
|
struct vdev_children {
|
||||||
char value[INT_MAX_VALUE];
|
nvlist_t **first;
|
||||||
char source[ZFS_MAX_DATASET_NAME_LEN];
|
uint_t count;
|
||||||
int property;
|
};
|
||||||
void *pnext;
|
|
||||||
} 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 zpool_list* zpool_list_ptr;
|
||||||
typedef struct libzfs_handle* libzfs_handle_ptr;
|
typedef struct vdev_children vdev_children_t;
|
||||||
typedef struct nvlist* nvlist_ptr;
|
typedef struct vdev_children* vdev_children_ptr;
|
||||||
typedef struct property_list *property_list_ptr;
|
|
||||||
typedef struct pool_scan_stat* pool_scan_stat_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();
|
|
||||||
|
|
||||||
zpool_list_t *create_zpool_list_item();
|
zpool_list_t *create_zpool_list_item();
|
||||||
void zprop_source_tostr(char *dst, zprop_source_t source);
|
void zprop_source_tostr(char *dst, zprop_source_t source);
|
||||||
|
|
||||||
zpool_list_t* zpool_list_open(libzfs_handle_t *libzfs, const char *name);
|
zpool_list_t* zpool_list_open(const char *name);
|
||||||
int zpool_list(libzfs_handle_t *libzfs, zpool_list_t **first);
|
zpool_list_ptr zpool_list_openall();
|
||||||
zpool_list_t *zpool_next(zpool_list_t *pool);
|
zpool_list_t *zpool_next(zpool_list_t *pool);
|
||||||
|
|
||||||
|
void zpool_list_free(zpool_list_t *list);
|
||||||
void zpool_list_close(zpool_list_t *pool);
|
void zpool_list_close(zpool_list_t *pool);
|
||||||
|
|
||||||
int read_zpool_property(zpool_handle_t *zh, property_list_t *list, int prop);
|
property_list_ptr read_zpool_property(zpool_list_ptr pool, int prop);
|
||||||
property_list_t *read_zpool_properties(zpool_handle_t *zh);
|
property_list_t *read_zpool_properties(zpool_list_ptr pool);
|
||||||
property_list_t *next_property(property_list_t *list);
|
property_list_t *next_property(property_list_t *list);
|
||||||
void free_properties(property_list_t *root);
|
|
||||||
|
|
||||||
pool_state_t zpool_read_state(zpool_handle_t *zh);
|
pool_state_t zpool_read_state(zpool_handle_t *zh);
|
||||||
|
|
||||||
|
|
||||||
const char *lasterr(void);
|
const char *lasterr(void);
|
||||||
|
|
||||||
int
|
// int
|
||||||
add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
// add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
||||||
boolean_t poolprop);
|
// boolean_t poolprop);
|
||||||
|
|
||||||
nvlist_t** nvlist_alloc_array(int count);
|
nvlist_t** nvlist_alloc_array(int count);
|
||||||
void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item);
|
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);
|
||||||
|
|
||||||
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
|
|
||||||
vdev_stat_t **vds, uint_t *c);
|
|
||||||
|
|
||||||
int nvlist_lookup_uint64_array_ps(nvlist_t *nv, const char *p,
|
|
||||||
pool_scan_stat_t **vds, uint_t *c);
|
|
||||||
|
|
||||||
int refresh_stats(zpool_list_t *pool);
|
int refresh_stats(zpool_list_t *pool);
|
||||||
|
|
||||||
|
const char *get_vdev_type(nvlist_ptr nv);
|
||||||
|
const vdev_stat_ptr get_vdev_stats(nvlist_ptr nv);
|
||||||
|
pool_scan_stat_ptr get_vdev_scan_stats(nvlist_t *nv);
|
||||||
|
vdev_children_ptr get_vdev_children(nvlist_t *nv);
|
||||||
|
const char *get_vdev_path(nvlist_ptr nv);
|
||||||
|
uint64_t get_vdev_is_log(nvlist_ptr nv);
|
||||||
|
|
||||||
|
uint64_t get_zpool_state(nvlist_ptr nv);
|
||||||
|
uint64_t get_zpool_guid(nvlist_ptr nv);
|
||||||
|
const char *get_zpool_name(nvlist_ptr nv);
|
||||||
|
const char *get_zpool_comment(nvlist_ptr nv);
|
||||||
|
|
||||||
|
nvlist_ptr get_zpool_vdev_tree(nvlist_ptr nv);
|
||||||
|
|
||||||
|
|
||||||
char *sZPOOL_CONFIG_VERSION;
|
char *sZPOOL_CONFIG_VERSION;
|
||||||
char *sZPOOL_CONFIG_POOL_NAME;
|
char *sZPOOL_CONFIG_POOL_NAME;
|
||||||
char *sZPOOL_CONFIG_POOL_STATE;
|
char *sZPOOL_CONFIG_POOL_STATE;
|
||||||
|
|
|
@ -159,7 +159,7 @@ func zpoolTestPoolDestroy(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Close()
|
||||||
if err = p.Destroy("Test of pool destroy (" + TSTPoolName + ")"); err != nil {
|
if err = p.Destroy(TSTPoolName); err != nil {
|
||||||
t.Error(err.Error())
|
t.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue