Ejemplo n.º 1
0
// Create ZFS pool per specs, features and properties of pool and root dataset
func PoolCreate(name string, vdevs []VDevSpec, features map[string]string,
	props PoolProperties, fsprops ZFSProperties) (pool Pool, err error) {
	// create root vdev nvroot
	var nvroot *C.nvlist_t = nil
	if r := C.nvlist_alloc(&nvroot, C.NV_UNIQUE_NAME, 0); r != 0 {
		err = errors.New("Failed to allocate root vdev")
		return
	}
	if r := C.nvlist_add_string(nvroot, C.CString(C.ZPOOL_CONFIG_TYPE),
		C.CString(string(VDevTypeRoot))); r != 0 {
		err = errors.New("Failed to allocate root vdev")
		return
	}
	defer C.nvlist_free(nvroot)

	// Now we need to build specs (vdev hierarchy)
	if err = buildVDevSpec(nvroot, VDevTypeRoot, vdevs, props); err != nil {
		return
	}

	// convert properties
	cprops := toCPoolProperties(props)
	if cprops != nil {
		defer C.nvlist_free(cprops)
	} else if len(props) > 0 {
		err = errors.New("Failed to allocate pool properties")
		return
	}
	cfsprops := toCZFSProperties(fsprops)
	if cfsprops != nil {
		defer C.nvlist_free(cfsprops)
	} else if len(fsprops) > 0 {
		err = errors.New("Failed to allocate FS properties")
		return
	}
	for fname, fval := range features {
		sfname := fmt.Sprintf("feature@%s", fname)
		r := C.add_prop_list(C.CString(sfname), C.CString(fval), &cprops,
			C.boolean_t(1))
		if r != 0 {
			if cprops != nil {
				C.nvlist_free(cprops)
				cprops = nil
			}
			return
		}
	}

	// Create actual pool then open
	if r := C.zpool_create(libzfs_handle, C.CString(name), nvroot,
		cprops, cfsprops); r != 0 {
		err = LastError()
		return
	}
	pool, err = PoolOpen(name)
	return
}
Ejemplo n.º 2
0
func datasetPropertiesTo_nvlist(props map[ZFSProp]Property) (
	cprops *C.nvlist_t, err error) {
	// convert properties to nvlist C type
	r := C.nvlist_alloc(&cprops, C.NV_UNIQUE_NAME, 0)
	if r != 0 {
		err = errors.New("Failed to allocate properties")
		return
	}
	for prop, value := range props {
		r := C.nvlist_add_string(
			cprops, C.zfs_prop_to_name(
				C.zfs_prop_t(prop)), C.CString(value.Value))
		if r != 0 {
			err = errors.New("Failed to convert property")
			return
		}
	}
	return
}
Ejemplo n.º 3
0
func buildVDevSpec(root *C.nvlist_t, rtype VDevType, vdevs []VDevSpec,
	props PoolProperties) (err error) {
	count := len(vdevs)
	if count == 0 {
		return
	}
	childrens := C.nvlist_alloc_array(C.int(count))
	if childrens == nil {
		err = errors.New("No enough memory")
		return
	}
	defer C.nvlist_free_array(childrens)
	spares := C.nvlist_alloc_array(C.int(count))
	if childrens == nil {
		err = errors.New("No enough memory")
		return
	}
	nspares := 0
	defer C.nvlist_free_array(spares)
	l2cache := C.nvlist_alloc_array(C.int(count))
	if childrens == nil {
		err = errors.New("No enough memory")
		return
	}
	nl2cache := 0
	defer C.nvlist_free_array(l2cache)
	for i, vdev := range vdevs {
		grouping, mindevs, maxdevs := vdev.isGrouping()
		var child *C.nvlist_t = nil
		// fmt.Println(vdev.Type)
		if r := C.nvlist_alloc(&child, C.NV_UNIQUE_NAME, 0); r != 0 {
			err = errors.New("Failed to allocate vdev")
			return
		}
		vcount := len(vdev.Devices)
		if vcount < mindevs || vcount > maxdevs {
			err = errors.New(fmt.Sprintf(
				"Invalid vdev specification: %s supports no less than %d or more than %d devices", vdev.Type, mindevs, maxdevs))
			return
		}
		if r := C.nvlist_add_string(child, C.CString(C.ZPOOL_CONFIG_TYPE),
			C.CString(string(vdev.Type))); r != 0 {
			err = errors.New("Failed to set vdev type")
			return
		}
		if r := C.nvlist_add_uint64(child, C.CString(C.ZPOOL_CONFIG_IS_LOG),
			vdev.isLog()); r != 0 {
			err = errors.New("Failed to allocate vdev (is_log)")
			return
		}
		if grouping {
			if vdev.Type == VDevTypeRaidz {
				r := C.nvlist_add_uint64(child,
					C.CString(C.ZPOOL_CONFIG_NPARITY),
					C.uint64_t(mindevs-1))
				if r != 0 {
					err = errors.New("Failed to allocate vdev (parity)")
					return
				}
			}
			if err = buildVDevSpec(child, vdev.Type, vdev.Devices,
				props); err != nil {
				return
			}
		} else {
			// if vdev.Type == VDevTypeDisk {
			if r := C.nvlist_add_uint64(child,
				C.CString(C.ZPOOL_CONFIG_WHOLE_DISK), 1); r != 0 {
				err = errors.New("Failed to allocate vdev child (whdisk)")
				return
			}
			// }
			if len(vdev.Path) > 0 {
				if r := C.nvlist_add_string(
					child, C.CString(C.ZPOOL_CONFIG_PATH),
					C.CString(vdev.Path)); r != 0 {
					err = errors.New("Failed to allocate vdev child (type)")
					return
				}
				ashift, _ := strconv.Atoi(props[PoolPropAshift])
				if ashift > 0 {
					if r := C.nvlist_add_uint64(child,
						C.CString(C.ZPOOL_CONFIG_ASHIFT),
						C.uint64_t(ashift)); r != 0 {
						err = errors.New("Failed to allocate vdev child (ashift)")
						return
					}
				}
			}
			if vdev.Type == VDevTypeSpare {
				C.nvlist_array_set(spares, C.int(nspares), child)
				nspares++
				count--
				continue
			} else if vdev.Type == VDevTypeL2cache {
				C.nvlist_array_set(l2cache, C.int(nl2cache), child)
				nl2cache++
				count--
				continue
			}
		}
		C.nvlist_array_set(childrens, C.int(i), child)
	}
	if count > 0 {
		if r := C.nvlist_add_nvlist_array(root,
			C.CString(C.ZPOOL_CONFIG_CHILDREN), childrens,
			C.uint_t(count)); r != 0 {
			err = errors.New("Failed to allocate vdev children")
			return
		}
		// fmt.Println("childs", root, count, rtype)
		// debug.PrintStack()
	}
	if nl2cache > 0 {
		if r := C.nvlist_add_nvlist_array(root,
			C.CString(C.ZPOOL_CONFIG_L2CACHE), l2cache,
			C.uint_t(nl2cache)); r != 0 {
			err = errors.New("Failed to allocate vdev cache")
			return
		}
	}
	if nspares > 0 {
		if r := C.nvlist_add_nvlist_array(root,
			C.CString(C.ZPOOL_CONFIG_SPARES), spares,
			C.uint_t(nspares)); r != 0 {
			err = errors.New("Failed to allocate vdev spare")
			return
		}
		// fmt.Println("spares", root, count)
	}
	return
}