- ZFS send/receive
This commit is contained in:
		
							parent
							
								
									8fd0833477
								
							
						
					
					
						commit
						1b47551b87
					
				| 
						 | 
					@ -22,6 +22,7 @@ import "C"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// VDevType type of device in the pool
 | 
					// VDevType type of device in the pool
 | 
				
			||||||
| 
						 | 
					@ -68,6 +69,10 @@ type Property struct {
 | 
				
			||||||
	Source string
 | 
						Source string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Global struct {
 | 
				
			||||||
 | 
						Mtx sync.Mutex
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pool status
 | 
					// Pool status
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,269 @@
 | 
				
			||||||
 | 
					package zfs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #include <stdlib.h>
 | 
				
			||||||
 | 
					// #include <libzfs.h>
 | 
				
			||||||
 | 
					// #include "common.h"
 | 
				
			||||||
 | 
					// #include "zpool.h"
 | 
				
			||||||
 | 
					// #include "zfs.h"
 | 
				
			||||||
 | 
					import "C"
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"syscall"
 | 
				
			||||||
 | 
						"unsafe"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SendFlags struct {
 | 
				
			||||||
 | 
						Verbose    bool
 | 
				
			||||||
 | 
						Replicate  bool
 | 
				
			||||||
 | 
						DoAll      bool
 | 
				
			||||||
 | 
						FromOrigin bool
 | 
				
			||||||
 | 
						Dedup      bool
 | 
				
			||||||
 | 
						Props      bool
 | 
				
			||||||
 | 
						DryRun     bool
 | 
				
			||||||
 | 
						// Parsable   bool
 | 
				
			||||||
 | 
						// Progress   bool
 | 
				
			||||||
 | 
						LargeBlock bool
 | 
				
			||||||
 | 
						EmbedData  bool
 | 
				
			||||||
 | 
						// Compress   bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RecvFlags struct {
 | 
				
			||||||
 | 
						Verbose     bool
 | 
				
			||||||
 | 
						IsPrefix    bool
 | 
				
			||||||
 | 
						IsTail      bool
 | 
				
			||||||
 | 
						DryRun      bool
 | 
				
			||||||
 | 
						Force       bool
 | 
				
			||||||
 | 
						CanmountOff bool
 | 
				
			||||||
 | 
						Resumable   bool
 | 
				
			||||||
 | 
						ByteSwap    bool
 | 
				
			||||||
 | 
						NoMount     bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func to_boolean_t(a bool) C.boolean_t {
 | 
				
			||||||
 | 
						if a {
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func to_sendflags_t(flags *SendFlags) (cflags *C.sendflags_t) {
 | 
				
			||||||
 | 
						cflags = C.alloc_sendflags()
 | 
				
			||||||
 | 
						cflags.verbose = to_boolean_t(flags.Verbose)
 | 
				
			||||||
 | 
						cflags.replicate = to_boolean_t(flags.Replicate)
 | 
				
			||||||
 | 
						cflags.doall = to_boolean_t(flags.DoAll)
 | 
				
			||||||
 | 
						cflags.fromorigin = to_boolean_t(flags.FromOrigin)
 | 
				
			||||||
 | 
						cflags.dedup = to_boolean_t(flags.Dedup)
 | 
				
			||||||
 | 
						cflags.props = to_boolean_t(flags.Props)
 | 
				
			||||||
 | 
						cflags.dryrun = to_boolean_t(flags.DryRun)
 | 
				
			||||||
 | 
						// cflags.parsable = to_boolean_t(flags.Parsable)
 | 
				
			||||||
 | 
						// cflags.progress = to_boolean_t(flags.Progress)
 | 
				
			||||||
 | 
						cflags.largeblock = to_boolean_t(flags.LargeBlock)
 | 
				
			||||||
 | 
						cflags.embed_data = to_boolean_t(flags.EmbedData)
 | 
				
			||||||
 | 
						// cflags.compress = to_boolean_t(flags.Compress)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func to_recvflags_t(flags *RecvFlags) (cflags *C.recvflags_t) {
 | 
				
			||||||
 | 
						cflags = C.alloc_recvflags()
 | 
				
			||||||
 | 
						cflags.verbose = to_boolean_t(flags.Verbose)
 | 
				
			||||||
 | 
						cflags.isprefix = to_boolean_t(flags.IsPrefix)
 | 
				
			||||||
 | 
						cflags.istail = to_boolean_t(flags.IsTail)
 | 
				
			||||||
 | 
						cflags.dryrun = to_boolean_t(flags.DryRun)
 | 
				
			||||||
 | 
						cflags.force = to_boolean_t(flags.Force)
 | 
				
			||||||
 | 
						cflags.canmountoff = to_boolean_t(flags.CanmountOff)
 | 
				
			||||||
 | 
						// cflags.resumable = to_boolean_t(flags.Resumable)
 | 
				
			||||||
 | 
						cflags.byteswap = to_boolean_t(flags.ByteSwap)
 | 
				
			||||||
 | 
						cflags.nomount = to_boolean_t(flags.NoMount)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Dataset) send(FromName string, outf *os.File, flags *SendFlags) (err error) {
 | 
				
			||||||
 | 
						var cfromname, ctoname *C.char
 | 
				
			||||||
 | 
						var dpath string
 | 
				
			||||||
 | 
						var pd Dataset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d.Type != DatasetTypeSnapshot || (len(FromName) > 0 && strings.Contains(FromName, "#")) {
 | 
				
			||||||
 | 
							err = fmt.Errorf(
 | 
				
			||||||
 | 
								"Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cflags := to_sendflags_t(flags)
 | 
				
			||||||
 | 
						defer C.free(unsafe.Pointer(cflags))
 | 
				
			||||||
 | 
						if dpath, err = d.Path(); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(FromName) > 0 {
 | 
				
			||||||
 | 
							if FromName[0] == '#' || FromName[0] == '@' {
 | 
				
			||||||
 | 
								FromName = dpath + FromName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cfromname = C.CString(FromName)
 | 
				
			||||||
 | 
							defer C.free(unsafe.Pointer(cfromname))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sendparams := strings.Split(dpath, "@")
 | 
				
			||||||
 | 
						parent := sendparams[0]
 | 
				
			||||||
 | 
						ctoname = C.CString(sendparams[1])
 | 
				
			||||||
 | 
						defer C.free(unsafe.Pointer(ctoname))
 | 
				
			||||||
 | 
						if pd, err = DatasetOpen(parent); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer pd.Close()
 | 
				
			||||||
 | 
						cerr := C.zfs_send(pd.list.zh, cfromname, ctoname, cflags, C.int(outf.Fd()), nil, nil, nil)
 | 
				
			||||||
 | 
						if cerr != 0 {
 | 
				
			||||||
 | 
							err = LastError()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Dataset) SendOne(FromName string, outf *os.File, flags *SendFlags) (err error) {
 | 
				
			||||||
 | 
						var cfromname, ctoname *C.char
 | 
				
			||||||
 | 
						var dpath string
 | 
				
			||||||
 | 
						var lzc_send_flags uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d.Type == DatasetTypeSnapshot || (len(FromName) > 0 && !strings.Contains(FromName, "#")) {
 | 
				
			||||||
 | 
							err = fmt.Errorf(
 | 
				
			||||||
 | 
								"Unsupported with snapshot. Use func Send() for that purpose.")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flags.Replicate || flags.DoAll || flags.Props || flags.Dedup || flags.DryRun {
 | 
				
			||||||
 | 
							err = fmt.Errorf("Unsupported flag with filesystem or bookmark.")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if flags.LargeBlock {
 | 
				
			||||||
 | 
							lzc_send_flags |= C.LZC_SEND_FLAG_LARGE_BLOCK
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flags.EmbedData {
 | 
				
			||||||
 | 
							lzc_send_flags |= C.LZC_SEND_FLAG_EMBED_DATA
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// if (flags.Compress)
 | 
				
			||||||
 | 
						// 	lzc_send_flags |= LZC_SEND_FLAG_COMPRESS;
 | 
				
			||||||
 | 
						if dpath, err = d.Path(); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(FromName) > 0 {
 | 
				
			||||||
 | 
							if FromName[0] == '#' || FromName[0] == '@' {
 | 
				
			||||||
 | 
								FromName = dpath + FromName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cfromname = C.CString(FromName)
 | 
				
			||||||
 | 
							defer C.free(unsafe.Pointer(cfromname))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctoname = C.CString(path.Base(dpath))
 | 
				
			||||||
 | 
						defer C.free(unsafe.Pointer(ctoname))
 | 
				
			||||||
 | 
						cerr := C.zfs_send_one(d.list.zh, cfromname, C.int(outf.Fd()), lzc_send_flags)
 | 
				
			||||||
 | 
						if cerr != 0 {
 | 
				
			||||||
 | 
							err = LastError()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Dataset) Send(outf *os.File, flags SendFlags) (err error) {
 | 
				
			||||||
 | 
						if flags.Replicate {
 | 
				
			||||||
 | 
							flags.DoAll = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = d.send("", outf, &flags)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Dataset) SendFrom(FromName string, outf *os.File, flags SendFlags) (err error) {
 | 
				
			||||||
 | 
						var porigin Property
 | 
				
			||||||
 | 
						var from, dest []string
 | 
				
			||||||
 | 
						if err = d.ReloadProperties(); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						porigin, _ = d.GetProperty(DatasetPropOrigin)
 | 
				
			||||||
 | 
						if len(porigin.Value) > 0 && porigin.Value == FromName {
 | 
				
			||||||
 | 
							FromName = ""
 | 
				
			||||||
 | 
							flags.FromOrigin = true
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							var dpath string
 | 
				
			||||||
 | 
							if dpath, err = d.Path(); err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dest = strings.Split(dpath, "@")
 | 
				
			||||||
 | 
							from = strings.Split(FromName, "@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if len(from[0]) > 0 && from[0] != dest[0] {
 | 
				
			||||||
 | 
								err = fmt.Errorf("Incremental source must be in same filesystem.")
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(from) < 2 || strings.Contains(from[1], "@") || strings.Contains(from[1], "/") {
 | 
				
			||||||
 | 
								err = fmt.Errorf("Invalid incremental source.")
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = d.send(from[1], outf, &flags)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Dataset) SendSize(FromName string, flags SendFlags) (size uint64, err error) {
 | 
				
			||||||
 | 
						var porigin Property
 | 
				
			||||||
 | 
						var from Dataset
 | 
				
			||||||
 | 
						var dpath string
 | 
				
			||||||
 | 
						if dpath, err = d.Path(); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						zc := C.new_zfs_cmd()
 | 
				
			||||||
 | 
						defer C.free(unsafe.Pointer(zc))
 | 
				
			||||||
 | 
						dpath = strings.Split(dpath, "@")[0]
 | 
				
			||||||
 | 
						if len(FromName) > 0 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if FromName[0] == '#' || FromName[0] == '@' {
 | 
				
			||||||
 | 
								FromName = dpath + FromName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							porigin, _ = d.GetProperty(DatasetPropOrigin)
 | 
				
			||||||
 | 
							if len(porigin.Value) > 0 && porigin.Value == FromName {
 | 
				
			||||||
 | 
								FromName = ""
 | 
				
			||||||
 | 
								flags.FromOrigin = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if from, err = DatasetOpen(FromName); err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							zc.zc_fromobj = C.zfs_prop_get_int(from.list.zh, C.ZFS_PROP_OBJSETID)
 | 
				
			||||||
 | 
							from.Close()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							zc.zc_fromobj = 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						zc.zc_obj = C.uint64_t(to_boolean_t(flags.FromOrigin))
 | 
				
			||||||
 | 
						zc.zc_sendobj = C.zfs_prop_get_int(d.list.zh, C.ZFS_PROP_OBJSETID)
 | 
				
			||||||
 | 
						zc.zc_guid = 1
 | 
				
			||||||
 | 
						zc.zc_flags = 0
 | 
				
			||||||
 | 
						if flags.LargeBlock {
 | 
				
			||||||
 | 
							zc.zc_flags |= C.LZC_SEND_FLAG_LARGE_BLOCK
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if flags.EmbedData {
 | 
				
			||||||
 | 
							zc.zc_flags |= C.LZC_SEND_FLAG_EMBED_DATA
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// C.estimate_ioctl(d.list.zhp, prevsnap_obj, to_boolean_t(flags.FromOrigin), lzc_send_flags, unsafe.Pointer(&size))
 | 
				
			||||||
 | 
						if ec, e := C.estimate_send_size(zc); ec != 0 {
 | 
				
			||||||
 | 
							err = fmt.Errorf("Failed to estimate send size. %s %d", e.Error(), e.(syscall.Errno))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size = uint64(zc.zc_objset_type)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Dataset) Receive(name string, inf *os.File, flags RecvFlags) (err error) {
 | 
				
			||||||
 | 
						var dpath string
 | 
				
			||||||
 | 
						if dpath, err = d.Path(); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						props := C.new_property_nvlist()
 | 
				
			||||||
 | 
						if props == nil {
 | 
				
			||||||
 | 
							err = fmt.Errorf("Out of memory func (d *Dataset) Recv()")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer C.nvlist_free(props)
 | 
				
			||||||
 | 
						cflags := to_recvflags_t(&flags)
 | 
				
			||||||
 | 
						defer C.free(unsafe.Pointer(cflags))
 | 
				
			||||||
 | 
						dest := C.CString(dpath + "/" + name)
 | 
				
			||||||
 | 
						defer C.free(unsafe.Pointer(dest))
 | 
				
			||||||
 | 
						ec := C.zfs_receive(C.libzfsHandle, dest, cflags, C.int(inf.Fd()), nil)
 | 
				
			||||||
 | 
						if ec != 0 {
 | 
				
			||||||
 | 
							err = fmt.Errorf("ZFS receive of %s failed. %s", C.GoString(dest), LastError().Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								zfs.c
								
								
								
								
							
							
						
						
									
										29
									
								
								zfs.c
								
								
								
								
							| 
						 | 
					@ -160,16 +160,16 @@ property_list_t *read_dataset_property(dataset_list_t *dataset, int prop) {
 | 
				
			||||||
	int r = 0;
 | 
						int r = 0;
 | 
				
			||||||
	zprop_source_t source;
 | 
						zprop_source_t source;
 | 
				
			||||||
	char statbuf[INT_MAX_VALUE];
 | 
						char statbuf[INT_MAX_VALUE];
 | 
				
			||||||
	property_list_ptr list;
 | 
						property_list_ptr list = NULL;
 | 
				
			||||||
	list = new_property_list();
 | 
						list = new_property_list();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r = zfs_prop_get(dataset->zh, prop,
 | 
						r = zfs_prop_get(dataset->zh, prop,
 | 
				
			||||||
		list->value, INT_MAX_VALUE, &source, statbuf, INT_MAX_VALUE, 1);
 | 
							list->value, INT_MAX_VALUE, &source, statbuf, INT_MAX_VALUE, 1);
 | 
				
			||||||
	if (r == 0) {
 | 
						if (r == 0 && list != NULL) {
 | 
				
			||||||
		// strcpy(list->name, zpool_prop_to_name(prop));
 | 
							// strcpy(list->name, zpool_prop_to_name(prop));
 | 
				
			||||||
		zprop_source_tostr(list->source, source);
 | 
							zprop_source_tostr(list->source, source);
 | 
				
			||||||
		list->property = (int)prop;
 | 
							list->property = (int)prop;
 | 
				
			||||||
	} else {
 | 
						} else if (list != NULL) {
 | 
				
			||||||
		free_properties(list);
 | 
							free_properties(list);
 | 
				
			||||||
		list = NULL;
 | 
							list = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -226,3 +226,26 @@ char** alloc_cstrings(int size) {
 | 
				
			||||||
void strings_setat(char **a, int at, char *v) {
 | 
					void strings_setat(char **a, int at, char *v) {
 | 
				
			||||||
	a[at] = v;
 | 
						a[at] = v;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendflags_t *alloc_sendflags() {
 | 
				
			||||||
 | 
						sendflags_t *r = malloc(sizeof(sendflags_t));
 | 
				
			||||||
 | 
						memset(r, 0, sizeof(sendflags_t));
 | 
				
			||||||
 | 
						return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					recvflags_t *alloc_recvflags() {
 | 
				
			||||||
 | 
						recvflags_t *r = malloc(sizeof(recvflags_t));
 | 
				
			||||||
 | 
						memset(r, 0, sizeof(recvflags_t));
 | 
				
			||||||
 | 
						return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct zfs_cmd *new_zfs_cmd(){
 | 
				
			||||||
 | 
						struct zfs_cmd *cmd = malloc(sizeof(struct zfs_cmd));
 | 
				
			||||||
 | 
						memset(cmd, 0, sizeof(struct zfs_cmd));
 | 
				
			||||||
 | 
						return cmd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int estimate_send_size(struct zfs_cmd *zc) {
 | 
				
			||||||
 | 
						return zfs_ioctl(libzfsHandle, ZFS_IOC_SEND, zc);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								zfs.go
								
								
								
								
							
							
						
						
									
										2
									
								
								zfs.go
								
								
								
								
							| 
						 | 
					@ -107,7 +107,7 @@ func DatasetOpen(path string) (d Dataset, err error) {
 | 
				
			||||||
		if err == nil {
 | 
							if err == nil {
 | 
				
			||||||
			err = fmt.Errorf("dataset not found.")
 | 
								err = fmt.Errorf("dataset not found.")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		println("open failed")
 | 
							err = fmt.Errorf("%s - %s", err.Error(), path)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.Type = DatasetType(C.dataset_type(d.list))
 | 
						d.Type = DatasetType(C.dataset_type(d.list))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										108
									
								
								zfs.h
								
								
								
								
							
							
						
						
									
										108
									
								
								zfs.h
								
								
								
								
							| 
						 | 
					@ -10,6 +10,107 @@ struct dataset_list {
 | 
				
			||||||
	void *pnext;
 | 
						void *pnext;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct zfs_share {
 | 
				
			||||||
 | 
						uint64_t	z_exportdata;
 | 
				
			||||||
 | 
						uint64_t	z_sharedata;
 | 
				
			||||||
 | 
						uint64_t	z_sharetype;	/* 0 = share, 1 = unshare */
 | 
				
			||||||
 | 
						uint64_t	z_sharemax;  /* max length of share string */
 | 
				
			||||||
 | 
					} zfs_share_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct drr_begin {
 | 
				
			||||||
 | 
						uint64_t drr_magic;
 | 
				
			||||||
 | 
						uint64_t drr_versioninfo; /* was drr_version */
 | 
				
			||||||
 | 
						uint64_t drr_creation_time;
 | 
				
			||||||
 | 
						dmu_objset_type_t drr_type;
 | 
				
			||||||
 | 
						uint32_t drr_flags;
 | 
				
			||||||
 | 
						uint64_t drr_toguid;
 | 
				
			||||||
 | 
						uint64_t drr_fromguid;
 | 
				
			||||||
 | 
						char drr_toname[MAXNAMELEN];
 | 
				
			||||||
 | 
					} drr_begin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * A limited number of zpl level stats are retrievable
 | 
				
			||||||
 | 
					 * with an ioctl.  zfs diff is the current consumer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct zfs_stat {
 | 
				
			||||||
 | 
						uint64_t	zs_gen;
 | 
				
			||||||
 | 
						uint64_t	zs_mode;
 | 
				
			||||||
 | 
						uint64_t	zs_links;
 | 
				
			||||||
 | 
						uint64_t	zs_ctime[2];
 | 
				
			||||||
 | 
					} zfs_stat_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct zinject_record {
 | 
				
			||||||
 | 
						uint64_t	zi_objset;
 | 
				
			||||||
 | 
						uint64_t	zi_object;
 | 
				
			||||||
 | 
						uint64_t	zi_start;
 | 
				
			||||||
 | 
						uint64_t	zi_end;
 | 
				
			||||||
 | 
						uint64_t	zi_guid;
 | 
				
			||||||
 | 
						uint32_t	zi_level;
 | 
				
			||||||
 | 
						uint32_t	zi_error;
 | 
				
			||||||
 | 
						uint64_t	zi_type;
 | 
				
			||||||
 | 
						uint32_t	zi_freq;
 | 
				
			||||||
 | 
						uint32_t	zi_failfast;
 | 
				
			||||||
 | 
						char		zi_func[MAXNAMELEN];
 | 
				
			||||||
 | 
						uint32_t	zi_iotype;
 | 
				
			||||||
 | 
						int32_t		zi_duration;
 | 
				
			||||||
 | 
						uint64_t	zi_timer;
 | 
				
			||||||
 | 
						uint64_t	zi_nlanes;
 | 
				
			||||||
 | 
						uint32_t	zi_cmd;
 | 
				
			||||||
 | 
						uint32_t	zi_pad;
 | 
				
			||||||
 | 
					} zinject_record_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct dmu_objset_stats {
 | 
				
			||||||
 | 
						uint64_t dds_num_clones; /* number of clones of this */
 | 
				
			||||||
 | 
						uint64_t dds_creation_txg;
 | 
				
			||||||
 | 
						uint64_t dds_guid;
 | 
				
			||||||
 | 
						dmu_objset_type_t dds_type;
 | 
				
			||||||
 | 
						uint8_t dds_is_snapshot;
 | 
				
			||||||
 | 
						uint8_t dds_inconsistent;
 | 
				
			||||||
 | 
						char dds_origin[ZFS_MAX_DATASET_NAME_LEN];
 | 
				
			||||||
 | 
					} dmu_objset_stats_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct zfs_cmd {
 | 
				
			||||||
 | 
						char		zc_name[MAXPATHLEN];	/* name of pool or dataset */
 | 
				
			||||||
 | 
						uint64_t	zc_nvlist_src;		/* really (char *) */
 | 
				
			||||||
 | 
						uint64_t	zc_nvlist_src_size;
 | 
				
			||||||
 | 
						uint64_t	zc_nvlist_dst;		/* really (char *) */
 | 
				
			||||||
 | 
						uint64_t	zc_nvlist_dst_size;
 | 
				
			||||||
 | 
						boolean_t	zc_nvlist_dst_filled;	/* put an nvlist in dst? */
 | 
				
			||||||
 | 
						int		zc_pad2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The following members are for legacy ioctls which haven't been
 | 
				
			||||||
 | 
						 * converted to the new method.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						uint64_t	zc_history;		/* really (char *) */
 | 
				
			||||||
 | 
						char		zc_value[MAXPATHLEN * 2];
 | 
				
			||||||
 | 
						char		zc_string[MAXNAMELEN];
 | 
				
			||||||
 | 
						uint64_t	zc_guid;
 | 
				
			||||||
 | 
						uint64_t	zc_nvlist_conf;		/* really (char *) */
 | 
				
			||||||
 | 
						uint64_t	zc_nvlist_conf_size;
 | 
				
			||||||
 | 
						uint64_t	zc_cookie;
 | 
				
			||||||
 | 
						uint64_t	zc_objset_type;
 | 
				
			||||||
 | 
						uint64_t	zc_perm_action;
 | 
				
			||||||
 | 
						uint64_t	zc_history_len;
 | 
				
			||||||
 | 
						uint64_t	zc_history_offset;
 | 
				
			||||||
 | 
						uint64_t	zc_obj;
 | 
				
			||||||
 | 
						uint64_t	zc_iflags;		/* internal to zfs(7fs) */
 | 
				
			||||||
 | 
						zfs_share_t	zc_share;
 | 
				
			||||||
 | 
						dmu_objset_stats_t zc_objset_stats;
 | 
				
			||||||
 | 
						struct drr_begin zc_begin_record;
 | 
				
			||||||
 | 
						zinject_record_t zc_inject_record;
 | 
				
			||||||
 | 
						uint32_t	zc_defer_destroy;
 | 
				
			||||||
 | 
						uint32_t	zc_flags;
 | 
				
			||||||
 | 
						uint64_t	zc_action_handle;
 | 
				
			||||||
 | 
						int		zc_cleanup_fd;
 | 
				
			||||||
 | 
						uint8_t		zc_simple;
 | 
				
			||||||
 | 
						uint8_t		zc_pad[3];		/* alignment */
 | 
				
			||||||
 | 
						uint64_t	zc_sendobj;
 | 
				
			||||||
 | 
						uint64_t	zc_fromobj;
 | 
				
			||||||
 | 
						uint64_t	zc_createtxg;
 | 
				
			||||||
 | 
						zfs_stat_t	zc_stat;
 | 
				
			||||||
 | 
					} zfs_cmd_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct dataset_list dataset_list_t;
 | 
					typedef struct dataset_list dataset_list_t;
 | 
				
			||||||
typedef struct dataset_list* dataset_list_ptr;
 | 
					typedef struct dataset_list* dataset_list_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,5 +147,12 @@ property_list_t *read_user_property(dataset_list_t *dataset, const char* prop);
 | 
				
			||||||
char** alloc_cstrings(int size);
 | 
					char** alloc_cstrings(int size);
 | 
				
			||||||
void strings_setat(char **a, int at, char *v);
 | 
					void strings_setat(char **a, int at, char *v);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendflags_t *alloc_sendflags();
 | 
				
			||||||
 | 
					recvflags_t *alloc_recvflags();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct zfs_cmd *new_zfs_cmd();
 | 
				
			||||||
 | 
					int estimate_send_size(struct zfs_cmd *zc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
/* SERVERWARE_ZFS_H */
 | 
					/* SERVERWARE_ZFS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue