- Implemented PoolImportByGUID and renamed VDevSpec to VDevTree

This commit is contained in:
Faruk Kasumovic 2015-12-06 21:54:43 +01:00
parent bc19737222
commit 4f32480fa0
3 changed files with 121 additions and 49 deletions

View File

@ -12,7 +12,7 @@ func Test(t *testing.T) {
zpoolTestExport(t)
zpoolTestImport(t)
zpoolTestExportForce(t)
zpoolTestImport(t)
zpoolTestImportByGUID(t)
zpoolTestPoolProp(t)
zpoolTestPoolStatusAndState(t)
zpoolTestPoolOpenAll(t)

129
zpool.go
View File

@ -20,6 +20,14 @@ const (
// PoolProperties type is map of pool properties name -> value
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.Properties map[string]Property
@ -48,12 +56,13 @@ func PoolOpen(name string) (pool Pool, err error) {
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) {
func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
err error) {
var config *C.nvlist_t
var cname *C.char
config = nil
errPoolList := errors.New("Failed to list pools")
var elem *C.nvpair_t
var config *C.nvlist_t
numofp := len(searchpaths)
cpaths := C.alloc_strings(C.int(numofp))
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)
for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
var cname *C.char
var cq *C.char
var tconfig *C.nvlist_t
retcode := C.nvpair_value_nvlist(elem, &tconfig)
if retcode != 0 {
err = errPoolList
return
}
retcode = C.nvlist_lookup_string(tconfig,
C.CString(C.ZPOOL_CONFIG_POOL_NAME), &cname)
if retcode != 0 {
err = errPoolList
return
}
oname := C.GoString(cname)
if name == oname {
config = tconfig
break
if guid {
var iguid C.uint64_t
if retcode = C.nvlist_lookup_uint64(tconfig,
C.CString(C.ZPOOL_CONFIG_POOL_GUID), &iguid); retcode != 0 {
err = errPoolList
return
}
sguid := fmt.Sprint(iguid)
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
break
}
}
}
if config == nil {
err = errors.New("No pools to import found with name " + name)
err = fmt.Errorf("No pool found %s", q)
return
}
retcode := C.zpool_import(libzfsHandle, config, C.CString(name), nil)
if retcode != 0 {
if guid {
// We need to get name so we can open pool by name
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()
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)
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.
// Returns array of Pool handlers, each have to be closed after not needed
// anymore. Call Pool.Close() method.
@ -164,9 +221,17 @@ func (pool *Pool) ReloadProperties() (err error) {
// read features
pool.Features = map[string]string{
"async_destroy": "disabled",
"empty_bpobj": "disabled",
"lz4_compress": "disabled"}
"async_destroy": "disabled",
"empty_bpobj": "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 {
pool.GetFeature(name)
}
@ -265,15 +330,7 @@ func (pool *Pool) State() (state PoolState, err error) {
return
}
// VDevSpec ZFS virtual device specification
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) {
func (vdev *VDevTree) isGrouping() (grouping bool, mindevs, maxdevs int) {
maxdevs = int(^uint(0) >> 1)
if vdev.Type == VDevTypeRaidz {
grouping = true
@ -295,7 +352,7 @@ func (vdev *VDevSpec) isGrouping() (grouping bool, mindevs, maxdevs int) {
return
}
func (vdev *VDevSpec) isLog() (r C.uint64_t) {
func (vdev *VDevTree) isLog() (r C.uint64_t) {
r = 0
if vdev.Type == VDevTypeLog {
r = 1
@ -335,7 +392,7 @@ func toCDatasetProperties(props DatasetProperties) (cprops *C.nvlist_t) {
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) {
count := len(vdevs)
if count == 0 {
@ -396,7 +453,7 @@ func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
return
}
}
if err = buildVDevSpec(child, vdev.Type, vdev.Devices,
if err = buildVDevTree(child, vdev.Type, vdev.Devices,
props); err != nil {
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
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) {
// create root vdev nvroot
var nvroot *C.nvlist_t
@ -486,7 +543,7 @@ func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
defer C.nvlist_free(nvroot)
// 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
}

View File

@ -13,6 +13,7 @@ import (
// HELPERS:
var TSTPoolName = "TESTPOOL"
var TSTPoolGUID string
func CreateTmpSparse(prefix string, size int64) (path string, err error) {
sf, err := ioutil.TempFile("/tmp", prefix)
@ -83,16 +84,16 @@ func zpoolTestPoolCreate(t *testing.T) {
disks := [2]string{s1path, s2path}
var vdevs, mdevs, sdevs []zfs.VDevSpec
var vdevs, mdevs, sdevs []zfs.VDevTree
for _, d := range disks {
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}}
vdevs = []zfs.VDevSpec{
zfs.VDevSpec{Type: zfs.VDevTypeMirror, Devices: mdevs},
zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
vdevs = []zfs.VDevTree{
zfs.VDevTree{Type: zfs.VDevTypeMirror, Devices: mdevs},
zfs.VDevTree{Type: zfs.VDevTypeSpare, Devices: sdevs},
}
props := make(map[zfs.Prop]string)
@ -114,6 +115,9 @@ func zpoolTestPoolCreate(t *testing.T) {
}
defer pool.Close()
pguid, _ := pool.GetProperty(zfs.PoolPropGUID)
TSTPoolGUID = pguid.Value
print("PASS\n\n")
}
@ -209,6 +213,17 @@ func zpoolTestImport(t *testing.T) {
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) {
println("TEST PoolProp on ", TSTPoolName, " ... ")
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
@ -335,22 +350,22 @@ func ExamplePoolOpenAll() {
func ExamplePoolCreate() {
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
for _, d := range disks {
mdevs = append(mdevs,
zfs.VDevSpec{Type: zfs.VDevTypeDisk, Path: d})
zfs.VDevTree{Type: zfs.VDevTypeDisk, Path: d})
}
// spare device specs
sdevs = []zfs.VDevSpec{
sdevs = []zfs.VDevTree{
{Type: zfs.VDevTypeDisk, Path: "/dev/disk/by-id/ATA-789"}}
// pool specs
vdevs = []zfs.VDevSpec{
zfs.VDevSpec{Type: zfs.VDevTypeMirror, Devices: mdevs},
zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
vdevs = []zfs.VDevTree{
zfs.VDevTree{Type: zfs.VDevTypeMirror, Devices: mdevs},
zfs.VDevTree{Type: zfs.VDevTypeSpare, Devices: sdevs},
}
// pool properties