- 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)
 | 
			
		||||
	zpoolTestImport(t)
 | 
			
		||||
	zpoolTestExportForce(t)
 | 
			
		||||
	zpoolTestImport(t)
 | 
			
		||||
	zpoolTestImportByGUID(t)
 | 
			
		||||
	zpoolTestPoolProp(t)
 | 
			
		||||
	zpoolTestPoolStatusAndState(t)
 | 
			
		||||
	zpoolTestPoolOpenAll(t)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										129
									
								
								zpool.go
								
								
								
								
							
							
						
						
									
										129
									
								
								zpool.go
								
								
								
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue