- Implemented PoolImportByGUID and renamed VDevSpec to VDevTree
This commit is contained in:
parent
bc19737222
commit
4f32480fa0
|
@ -12,7 +12,7 @@ func Test(t *testing.T) {
|
||||||
zpoolTestExport(t)
|
zpoolTestExport(t)
|
||||||
zpoolTestImport(t)
|
zpoolTestImport(t)
|
||||||
zpoolTestExportForce(t)
|
zpoolTestExportForce(t)
|
||||||
zpoolTestImport(t)
|
zpoolTestImportByGUID(t)
|
||||||
zpoolTestPoolProp(t)
|
zpoolTestPoolProp(t)
|
||||||
zpoolTestPoolStatusAndState(t)
|
zpoolTestPoolStatusAndState(t)
|
||||||
zpoolTestPoolOpenAll(t)
|
zpoolTestPoolOpenAll(t)
|
||||||
|
|
115
zpool.go
115
zpool.go
|
@ -20,6 +20,14 @@ const (
|
||||||
// PoolProperties type is map of pool properties name -> value
|
// PoolProperties type is map of pool properties name -> value
|
||||||
type PoolProperties map[Prop]string
|
type PoolProperties map[Prop]string
|
||||||
|
|
||||||
|
// VDevTree ZFS virtual device tree
|
||||||
|
type VDevTree struct {
|
||||||
|
Type VDevType
|
||||||
|
Devices []VDevTree // groups other devices (e.g. mirror)
|
||||||
|
Parity uint
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
// Pool object represents handler to single ZFS pool
|
// Pool object represents handler to single ZFS pool
|
||||||
//
|
//
|
||||||
/* Pool.Properties map[string]Property
|
/* Pool.Properties map[string]Property
|
||||||
|
@ -48,12 +56,13 @@ func PoolOpen(name string) (pool Pool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoolImport given a list of directories to search, find and import pool with matching
|
func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
|
||||||
// name stored on disk.
|
err error) {
|
||||||
func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
|
var config *C.nvlist_t
|
||||||
|
var cname *C.char
|
||||||
|
config = nil
|
||||||
errPoolList := errors.New("Failed to list pools")
|
errPoolList := errors.New("Failed to list pools")
|
||||||
var elem *C.nvpair_t
|
var elem *C.nvpair_t
|
||||||
var config *C.nvlist_t
|
|
||||||
numofp := len(searchpaths)
|
numofp := len(searchpaths)
|
||||||
cpaths := C.alloc_strings(C.int(numofp))
|
cpaths := C.alloc_strings(C.int(numofp))
|
||||||
for i, path := range searchpaths {
|
for i, path := range searchpaths {
|
||||||
|
@ -65,39 +74,87 @@ func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
|
||||||
|
|
||||||
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 cname *C.char
|
var cq *C.char
|
||||||
var tconfig *C.nvlist_t
|
var tconfig *C.nvlist_t
|
||||||
retcode := C.nvpair_value_nvlist(elem, &tconfig)
|
retcode := C.nvpair_value_nvlist(elem, &tconfig)
|
||||||
if retcode != 0 {
|
if retcode != 0 {
|
||||||
err = errPoolList
|
err = errPoolList
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
retcode = C.nvlist_lookup_string(tconfig,
|
if guid {
|
||||||
C.CString(C.ZPOOL_CONFIG_POOL_NAME), &cname)
|
var iguid C.uint64_t
|
||||||
if retcode != 0 {
|
if retcode = C.nvlist_lookup_uint64(tconfig,
|
||||||
|
C.CString(C.ZPOOL_CONFIG_POOL_GUID), &iguid); retcode != 0 {
|
||||||
err = errPoolList
|
err = errPoolList
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
oname := C.GoString(cname)
|
sguid := fmt.Sprint(iguid)
|
||||||
if name == oname {
|
if q == sguid {
|
||||||
|
config = tconfig
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if retcode = C.nvlist_lookup_string(tconfig,
|
||||||
|
C.CString(C.ZPOOL_CONFIG_POOL_NAME), &cq); retcode != 0 {
|
||||||
|
err = errPoolList
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cname = cq
|
||||||
|
name = C.GoString(cq)
|
||||||
|
if q == name {
|
||||||
config = tconfig
|
config = tconfig
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if config == nil {
|
if config == nil {
|
||||||
err = errors.New("No pools to import found with name " + name)
|
err = fmt.Errorf("No pool found %s", q)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if guid {
|
||||||
retcode := C.zpool_import(libzfsHandle, config, C.CString(name), nil)
|
// We need to get name so we can open pool by name
|
||||||
if retcode != 0 {
|
if retcode := C.nvlist_lookup_string(config,
|
||||||
|
C.CString(C.ZPOOL_CONFIG_POOL_NAME), &cname); retcode != 0 {
|
||||||
|
err = errPoolList
|
||||||
|
return
|
||||||
|
}
|
||||||
|
name = C.GoString(cname)
|
||||||
|
}
|
||||||
|
if retcode := C.zpool_import(libzfsHandle, config, cname,
|
||||||
|
nil); retcode != 0 {
|
||||||
err = LastError()
|
err = LastError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// PoolImport given a list of directories to search, find and import pool with matching
|
||||||
|
// name stored on disk.
|
||||||
|
func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
|
||||||
|
_, err = poolSearchImport(name, searchpaths, false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
pool, err = PoolOpen(name)
|
pool, err = PoolOpen(name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PoolImportByGUID given a list of directories to search, find and import pool
|
||||||
|
// with matching GUID stored on disk.
|
||||||
|
func PoolImportByGUID(guid string, searchpaths []string) (pool Pool, err error) {
|
||||||
|
var name string
|
||||||
|
name, err = poolSearchImport(guid, searchpaths, true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pool, err = PoolOpen(name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// func PoolList(paths []string, cache string) (pools []Pool, err error) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
// PoolOpenAll open all active ZFS pools on current system.
|
// PoolOpenAll open all active ZFS pools on current system.
|
||||||
// Returns array of Pool handlers, each have to be closed after not needed
|
// Returns array of Pool handlers, each have to be closed after not needed
|
||||||
// anymore. Call Pool.Close() method.
|
// anymore. Call Pool.Close() method.
|
||||||
|
@ -166,7 +223,15 @@ func (pool *Pool) ReloadProperties() (err error) {
|
||||||
pool.Features = map[string]string{
|
pool.Features = map[string]string{
|
||||||
"async_destroy": "disabled",
|
"async_destroy": "disabled",
|
||||||
"empty_bpobj": "disabled",
|
"empty_bpobj": "disabled",
|
||||||
"lz4_compress": "disabled"}
|
"lz4_compress": "disabled",
|
||||||
|
"spacemap_histogram": "disabled",
|
||||||
|
"enabled_txg": "disabled",
|
||||||
|
"hole_birth": "disabled",
|
||||||
|
"extensible_dataset": "disabled",
|
||||||
|
"embedded_data": "disabled",
|
||||||
|
"bookmarks": "disabled",
|
||||||
|
"filesystem_limits": "disabled",
|
||||||
|
"large_blocks": "disabled"}
|
||||||
for name := range pool.Features {
|
for name := range pool.Features {
|
||||||
pool.GetFeature(name)
|
pool.GetFeature(name)
|
||||||
}
|
}
|
||||||
|
@ -265,15 +330,7 @@ func (pool *Pool) State() (state PoolState, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// VDevSpec ZFS virtual device specification
|
func (vdev *VDevTree) isGrouping() (grouping bool, mindevs, maxdevs int) {
|
||||||
type VDevSpec struct {
|
|
||||||
Type VDevType
|
|
||||||
Devices []VDevSpec // groups other devices (e.g. mirror)
|
|
||||||
Parity uint
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vdev *VDevSpec) isGrouping() (grouping bool, mindevs, maxdevs int) {
|
|
||||||
maxdevs = int(^uint(0) >> 1)
|
maxdevs = int(^uint(0) >> 1)
|
||||||
if vdev.Type == VDevTypeRaidz {
|
if vdev.Type == VDevTypeRaidz {
|
||||||
grouping = true
|
grouping = true
|
||||||
|
@ -295,7 +352,7 @@ func (vdev *VDevSpec) isGrouping() (grouping bool, mindevs, maxdevs int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vdev *VDevSpec) isLog() (r C.uint64_t) {
|
func (vdev *VDevTree) isLog() (r C.uint64_t) {
|
||||||
r = 0
|
r = 0
|
||||||
if vdev.Type == VDevTypeLog {
|
if vdev.Type == VDevTypeLog {
|
||||||
r = 1
|
r = 1
|
||||||
|
@ -335,7 +392,7 @@ func toCDatasetProperties(props DatasetProperties) (cprops *C.nvlist_t) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
|
func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
|
||||||
props PoolProperties) (err error) {
|
props PoolProperties) (err error) {
|
||||||
count := len(vdevs)
|
count := len(vdevs)
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
|
@ -396,7 +453,7 @@ func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = buildVDevSpec(child, vdev.Type, vdev.Devices,
|
if err = buildVDevTree(child, vdev.Type, vdev.Devices,
|
||||||
props); err != nil {
|
props); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -470,7 +527,7 @@ func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoolCreate create ZFS pool per specs, features and properties of pool and root dataset
|
// PoolCreate create ZFS pool per specs, features and properties of pool and root dataset
|
||||||
func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
|
func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
|
||||||
props PoolProperties, fsprops DatasetProperties) (pool Pool, err error) {
|
props PoolProperties, fsprops DatasetProperties) (pool Pool, err error) {
|
||||||
// create root vdev nvroot
|
// create root vdev nvroot
|
||||||
var nvroot *C.nvlist_t
|
var nvroot *C.nvlist_t
|
||||||
|
@ -486,7 +543,7 @@ func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
|
||||||
defer C.nvlist_free(nvroot)
|
defer C.nvlist_free(nvroot)
|
||||||
|
|
||||||
// Now we need to build specs (vdev hierarchy)
|
// Now we need to build specs (vdev hierarchy)
|
||||||
if err = buildVDevSpec(nvroot, VDevTypeRoot, vdevs, props); err != nil {
|
if err = buildVDevTree(nvroot, VDevTypeRoot, vdevs, props); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// HELPERS:
|
// HELPERS:
|
||||||
|
|
||||||
var TSTPoolName = "TESTPOOL"
|
var TSTPoolName = "TESTPOOL"
|
||||||
|
var TSTPoolGUID string
|
||||||
|
|
||||||
func CreateTmpSparse(prefix string, size int64) (path string, err error) {
|
func CreateTmpSparse(prefix string, size int64) (path string, err error) {
|
||||||
sf, err := ioutil.TempFile("/tmp", prefix)
|
sf, err := ioutil.TempFile("/tmp", prefix)
|
||||||
|
@ -83,16 +84,16 @@ func zpoolTestPoolCreate(t *testing.T) {
|
||||||
|
|
||||||
disks := [2]string{s1path, s2path}
|
disks := [2]string{s1path, s2path}
|
||||||
|
|
||||||
var vdevs, mdevs, sdevs []zfs.VDevSpec
|
var vdevs, mdevs, sdevs []zfs.VDevTree
|
||||||
for _, d := range disks {
|
for _, d := range disks {
|
||||||
mdevs = append(mdevs,
|
mdevs = append(mdevs,
|
||||||
zfs.VDevSpec{Type: zfs.VDevTypeFile, Path: d})
|
zfs.VDevTree{Type: zfs.VDevTypeFile, Path: d})
|
||||||
}
|
}
|
||||||
sdevs = []zfs.VDevSpec{
|
sdevs = []zfs.VDevTree{
|
||||||
{Type: zfs.VDevTypeFile, Path: s3path}}
|
{Type: zfs.VDevTypeFile, Path: s3path}}
|
||||||
vdevs = []zfs.VDevSpec{
|
vdevs = []zfs.VDevTree{
|
||||||
zfs.VDevSpec{Type: zfs.VDevTypeMirror, Devices: mdevs},
|
zfs.VDevTree{Type: zfs.VDevTypeMirror, Devices: mdevs},
|
||||||
zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
|
zfs.VDevTree{Type: zfs.VDevTypeSpare, Devices: sdevs},
|
||||||
}
|
}
|
||||||
|
|
||||||
props := make(map[zfs.Prop]string)
|
props := make(map[zfs.Prop]string)
|
||||||
|
@ -114,6 +115,9 @@ func zpoolTestPoolCreate(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
|
|
||||||
|
pguid, _ := pool.GetProperty(zfs.PoolPropGUID)
|
||||||
|
TSTPoolGUID = pguid.Value
|
||||||
|
|
||||||
print("PASS\n\n")
|
print("PASS\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +213,17 @@ func zpoolTestImport(t *testing.T) {
|
||||||
print("PASS\n\n")
|
print("PASS\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func zpoolTestImportByGUID(t *testing.T) {
|
||||||
|
println("TEST POOL ImportByGUID( ", TSTPoolGUID, " ) ... ")
|
||||||
|
p, err := zfs.PoolImportByGUID(TSTPoolGUID, []string{"/tmp"})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer p.Close()
|
||||||
|
print("PASS\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
func zpoolTestPoolProp(t *testing.T) {
|
func zpoolTestPoolProp(t *testing.T) {
|
||||||
println("TEST PoolProp on ", TSTPoolName, " ... ")
|
println("TEST PoolProp on ", TSTPoolName, " ... ")
|
||||||
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
|
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
|
||||||
|
@ -335,22 +350,22 @@ func ExamplePoolOpenAll() {
|
||||||
func ExamplePoolCreate() {
|
func ExamplePoolCreate() {
|
||||||
disks := [2]string{"/dev/disk/by-id/ATA-123", "/dev/disk/by-id/ATA-456"}
|
disks := [2]string{"/dev/disk/by-id/ATA-123", "/dev/disk/by-id/ATA-456"}
|
||||||
|
|
||||||
var vdevs, mdevs, sdevs []zfs.VDevSpec
|
var vdevs, mdevs, sdevs []zfs.VDevTree
|
||||||
|
|
||||||
// build mirror devices specs
|
// build mirror devices specs
|
||||||
for _, d := range disks {
|
for _, d := range disks {
|
||||||
mdevs = append(mdevs,
|
mdevs = append(mdevs,
|
||||||
zfs.VDevSpec{Type: zfs.VDevTypeDisk, Path: d})
|
zfs.VDevTree{Type: zfs.VDevTypeDisk, Path: d})
|
||||||
}
|
}
|
||||||
|
|
||||||
// spare device specs
|
// spare device specs
|
||||||
sdevs = []zfs.VDevSpec{
|
sdevs = []zfs.VDevTree{
|
||||||
{Type: zfs.VDevTypeDisk, Path: "/dev/disk/by-id/ATA-789"}}
|
{Type: zfs.VDevTypeDisk, Path: "/dev/disk/by-id/ATA-789"}}
|
||||||
|
|
||||||
// pool specs
|
// pool specs
|
||||||
vdevs = []zfs.VDevSpec{
|
vdevs = []zfs.VDevTree{
|
||||||
zfs.VDevSpec{Type: zfs.VDevTypeMirror, Devices: mdevs},
|
zfs.VDevTree{Type: zfs.VDevTypeMirror, Devices: mdevs},
|
||||||
zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
|
zfs.VDevTree{Type: zfs.VDevTypeSpare, Devices: sdevs},
|
||||||
}
|
}
|
||||||
|
|
||||||
// pool properties
|
// pool properties
|
||||||
|
|
Loading…
Reference in New Issue