- ZFS send/receive
This commit is contained in:
		
							parent
							
								
									8fd0833477
								
							
						
					
					
						commit
						1b47551b87
					
				| 
						 | 
				
			
			@ -22,6 +22,7 @@ import "C"
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// VDevType type of device in the pool
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +69,10 @@ type Property struct {
 | 
			
		|||
	Source string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Global struct {
 | 
			
		||||
	Mtx sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pool status
 | 
			
		||||
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;
 | 
			
		||||
	zprop_source_t source;
 | 
			
		||||
	char statbuf[INT_MAX_VALUE];
 | 
			
		||||
	property_list_ptr list;
 | 
			
		||||
	property_list_ptr list = NULL;
 | 
			
		||||
	list = new_property_list();
 | 
			
		||||
 | 
			
		||||
	r = zfs_prop_get(dataset->zh, prop,
 | 
			
		||||
		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));
 | 
			
		||||
		zprop_source_tostr(list->source, source);
 | 
			
		||||
		list->property = (int)prop;
 | 
			
		||||
	} else {
 | 
			
		||||
	} else if (list != NULL) {
 | 
			
		||||
		free_properties(list);
 | 
			
		||||
		list = NULL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -226,3 +226,26 @@ char** alloc_cstrings(int size) {
 | 
			
		|||
void strings_setat(char **a, int at, char *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 {
 | 
			
		||||
			err = fmt.Errorf("dataset not found.")
 | 
			
		||||
		}
 | 
			
		||||
		println("open failed")
 | 
			
		||||
		err = fmt.Errorf("%s - %s", err.Error(), path)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	d.Type = DatasetType(C.dataset_type(d.list))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										108
									
								
								zfs.h
								
								
								
								
							
							
						
						
									
										108
									
								
								zfs.h
								
								
								
								
							| 
						 | 
				
			
			@ -10,6 +10,107 @@ struct dataset_list {
 | 
			
		|||
	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_ptr;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -46,5 +147,12 @@ property_list_t *read_user_property(dataset_list_t *dataset, const char* prop);
 | 
			
		|||
char** alloc_cstrings(int size);
 | 
			
		||||
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
 | 
			
		||||
/* SERVERWARE_ZFS_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue