From 5a4d618fa5fe376e5cf3b03d82c5036f04b19089 Mon Sep 17 00:00:00 2001 From: Asmir Selimovic Date: Wed, 22 Apr 2020 15:41:23 +0200 Subject: [PATCH] - Implemented pool initialization actions --- a_test.go | 1 + zpool.c | 24 ++++++++++++++++++ zpool.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ zpool.h | 1 + zpool_test.go | 37 +++++++++++++++++++++++++++- 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/a_test.go b/a_test.go index ab32e3b..ca0b1ef 100644 --- a/a_test.go +++ b/a_test.go @@ -13,6 +13,7 @@ func Test(t *testing.T) { zpoolTestExport(t) zpoolTestPoolImportSearch(t) zpoolTestImport(t) + zpoolTestInitialization(t) zpoolTestExportForce(t) zpoolTestImportByGUID(t) zpoolTestPoolProp(t) diff --git a/zpool.c b/zpool.c index 1dc3b9a..df64295 100644 --- a/zpool.c +++ b/zpool.c @@ -526,3 +526,27 @@ int do_zpool_clear(zpool_list_t *pool, const char *device, u_int32_t load_policy return (ret); } + +void collect_zpool_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *nv){ + uint_t children = 0; + nvlist_t **child; + uint_t i; + + (void) nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, + &child, &children); + + if (children == 0) { + char *path = zpool_vdev_name(libzfsHandle, zhp, nvroot, + VDEV_NAME_PATH); + + if (strcmp(path, VDEV_TYPE_INDIRECT) != 0) + fnvlist_add_boolean(nv, path); + + free(path); + return; + } + + for (i = 0; i < children; i++) { + collect_zpool_leaves(zhp, child[i], nv); + } +} \ No newline at end of file diff --git a/zpool.go b/zpool.go index 1990b2d..5b3c784 100644 --- a/zpool.go +++ b/zpool.go @@ -59,6 +59,16 @@ const ( PoolScanFuncs // Number of scan functions ) +// PoolInitializeAction type representing pool initialize action +type PoolInitializeAction int + +// Initialize actions +const ( + PoolInitializeStart PoolInitializeAction = iota // start initialization + PoolInitializeCancel // cancel initialization + PoolInitializeSuspend // suspend initialization +) + // VDevStat - Vdev statistics. Note: all fields should be 64-bit because this // is passed between kernel and userland as an nvlist uint64 array. type VDevStat struct { @@ -1055,6 +1065,50 @@ func (pool *Pool) VDevTree() (vdevs VDevTree, err error) { return } +// Initialize - initializes pool +func (pool *Pool) Initialize() (err error) { + return pool.initialize(PoolInitializeStart) +} + +// CancelInitialization - cancels ongoing initialization +func (pool *Pool) CancelInitialization() (err error) { + return pool.initialize(PoolInitializeCancel) +} + +// SuspendInitialization - suspends ongoing initialization +func (pool *Pool) SuspendInitialization() (err error) { + return pool.initialize(PoolInitializeSuspend) +} + +func (pool *Pool) initialize(action PoolInitializeAction) (err error) { + var nvroot *C.struct_nvlist + + config := C.zpool_get_config(pool.list.zph, nil) + if config == nil { + err = fmt.Errorf("Failed zpool_get_config") + return + } + if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0 { + err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) + return + } + + var vds *C.nvlist_t + if r := C.nvlist_alloc(&vds, C.NV_UNIQUE_NAME, 0); r != 0 { + err = errors.New("Failed to allocate vdev") + return + } + defer C.nvlist_free(vds) + + C.collect_zpool_leaves(pool.list.zph, nvroot, vds) + + if C.zpool_initialize(pool.list.zph, C.pool_initialize_func_t(action), vds) != 0 { + err = fmt.Errorf("Initialization action %s failed", action.String()) + return + } + return +} + func (s PoolState) String() string { switch s { case PoolStateActive: @@ -1186,3 +1240,16 @@ func (s PoolStatus) String() string { return "OK" } } + +func (s PoolInitializeAction) String() string { + switch s { + case PoolInitializeStart: + return "START" + case PoolInitializeCancel: + return "CANCEL" + case PoolInitializeSuspend: + return "SUSPEND" + default: + return "UNKNOWN" + } +} diff --git a/zpool.h b/zpool.h index d46676a..f37db38 100644 --- a/zpool.h +++ b/zpool.h @@ -82,6 +82,7 @@ nvlist_ptr go_zpool_search_import(libzfs_handle_ptr zfsh, int paths, char **path uint64_t set_zpool_vdev_online(zpool_list_t *pool, const char *path, int flags); int set_zpool_vdev_offline(zpool_list_t *pool, const char *path, boolean_t istmp, boolean_t force); int do_zpool_clear(zpool_list_t *pool, const char *device, u_int32_t rewind_policy); +void collect_zpool_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *nv); extern char *sZPOOL_CONFIG_VERSION; diff --git a/zpool_test.go b/zpool_test.go index 56fda54..4f8d120 100644 --- a/zpool_test.go +++ b/zpool_test.go @@ -5,8 +5,9 @@ import ( "io/ioutil" "os" "testing" + "time" - "github.com/bicomsystems/go-libzfs" + zfs "github.com/bicomsystems/go-libzfs" ) /* ------------------------------------------------------------------------- */ @@ -362,6 +363,40 @@ func zpoolTestPoolVDevTree(t *testing.T) { print("PASS\n\n") } +func zpoolTestInitialization(t *testing.T) { + println("TEST POOL Initialization ( ", TSTPoolName, " ) ... ") + pool, err := zfs.PoolOpen(TSTPoolName) + if err != nil { + t.Error(err.Error()) + return + } + defer pool.Close() + + err = pool.Initialize() + if err != nil { + t.Error(err.Error()) + return + } + time.Sleep(1 * time.Second) + err = pool.SuspendInitialization() + if err != nil { + t.Error(err.Error()) + return + } + err = pool.Initialize() + if err != nil { + t.Error(err.Error()) + return + } + time.Sleep(1 * time.Second) + err = pool.CancelInitialization() + if err != nil { + t.Error(err.Error()) + return + } + print("PASS\n\n") +} + /* ------------------------------------------------------------------------- */ // EXAMPLES: