// 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 }
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 }
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 }