github.com/dennwc/btrfs@v0.0.0-20221026161108-3097362dc072/ioctl_h.go (about)

     1  package btrfs
     2  
     3  import (
     4  	"encoding/binary"
     5  	"encoding/hex"
     6  	"github.com/dennwc/ioctl"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"unsafe"
    11  )
    12  
    13  var order = binary.LittleEndian
    14  
    15  const ioctlMagic = 0x94
    16  
    17  const devicePathNameMax = 1024
    18  
    19  const (
    20  	FSIDSize = 16
    21  	UUIDSize = 16
    22  )
    23  
    24  var zeroUUID UUID
    25  
    26  type UUID [UUIDSize]byte
    27  
    28  func (id UUID) IsZero() bool { return id == zeroUUID }
    29  func (id UUID) String() string {
    30  	if id.IsZero() {
    31  		return "<zero>"
    32  	}
    33  	buf := make([]byte, UUIDSize*2+4)
    34  	i := 0
    35  	i += hex.Encode(buf[i:], id[:4])
    36  	buf[i] = '-'
    37  	i++
    38  	i += hex.Encode(buf[i:], id[4:6])
    39  	buf[i] = '-'
    40  	i++
    41  	i += hex.Encode(buf[i:], id[6:8])
    42  	buf[i] = '-'
    43  	i++
    44  	i += hex.Encode(buf[i:], id[8:10])
    45  	buf[i] = '-'
    46  	i++
    47  	i += hex.Encode(buf[i:], id[10:])
    48  	return string(buf)
    49  }
    50  
    51  type FSID [FSIDSize]byte
    52  
    53  func (id FSID) String() string { return hex.EncodeToString(id[:]) }
    54  
    55  const volNameMax = 4087
    56  
    57  // this should be 4k
    58  type btrfs_ioctl_vol_args struct {
    59  	fd   int64
    60  	name [volNameMax + 1]byte
    61  }
    62  
    63  func (arg *btrfs_ioctl_vol_args) SetName(name string) {
    64  	n := copy(arg.name[:], name)
    65  	arg.name[n] = 0
    66  }
    67  
    68  type btrfs_qgroup_limit struct {
    69  	flags          uint64
    70  	max_referenced uint64
    71  	max_exclusive  uint64
    72  	rsv_referenced uint64
    73  	rsv_exclusive  uint64
    74  }
    75  
    76  type btrfs_qgroup_inherit struct {
    77  	flags           uint64
    78  	num_qgroups     uint64
    79  	num_ref_copies  uint64
    80  	num_excl_copies uint64
    81  	lim             btrfs_qgroup_limit
    82  	//qgroups [0]uint64
    83  }
    84  
    85  type btrfs_ioctl_qgroup_limit_args struct {
    86  	qgroupid uint64
    87  	lim      btrfs_qgroup_limit
    88  }
    89  
    90  type btrfs_ioctl_vol_args_v2_u1 struct {
    91  	size           uint64
    92  	qgroup_inherit *btrfs_qgroup_inherit
    93  }
    94  
    95  const subvolNameMax = 4039
    96  
    97  type SubvolFlags uint64
    98  
    99  func (f SubvolFlags) ReadOnly() bool {
   100  	return f&SubvolReadOnly != 0
   101  }
   102  func (f SubvolFlags) String() string {
   103  	if f == 0 {
   104  		return "<nil>"
   105  	}
   106  	var out []string
   107  	if f&SubvolReadOnly != 0 {
   108  		out = append(out, "RO")
   109  		f = f & (^SubvolReadOnly)
   110  	}
   111  	if f != 0 {
   112  		out = append(out, "0x"+strconv.FormatInt(int64(f), 16))
   113  	}
   114  	return strings.Join(out, "|")
   115  }
   116  
   117  // flags for subvolumes
   118  //
   119  // Used by:
   120  // struct btrfs_ioctl_vol_args_v2.flags
   121  //
   122  // BTRFS_SUBVOL_RDONLY is also provided/consumed by the following ioctls:
   123  // - BTRFS_IOC_SUBVOL_GETFLAGS
   124  // - BTRFS_IOC_SUBVOL_SETFLAGS
   125  const (
   126  	subvolCreateAsync   = SubvolFlags(1 << 0)
   127  	SubvolReadOnly      = SubvolFlags(1 << 1)
   128  	subvolQGroupInherit = SubvolFlags(1 << 2)
   129  )
   130  
   131  type btrfs_ioctl_vol_args_v2 struct {
   132  	fd      int64
   133  	transid uint64
   134  	flags   SubvolFlags
   135  	btrfs_ioctl_vol_args_v2_u1
   136  	unused [2]uint64
   137  	name   [subvolNameMax + 1]byte
   138  }
   139  
   140  // structure to report errors and progress to userspace, either as a
   141  // result of a finished scrub, a canceled scrub or a progress inquiry
   142  type btrfs_scrub_progress struct {
   143  	data_extents_scrubbed uint64 // # of data extents scrubbed
   144  	tree_extents_scrubbed uint64 // # of tree extents scrubbed
   145  	data_bytes_scrubbed   uint64 // # of data bytes scrubbed
   146  	tree_bytes_scrubbed   uint64 // # of tree bytes scrubbed
   147  	read_errors           uint64 // # of read errors encountered (EIO)
   148  	csum_errors           uint64 // # of failed csum checks
   149  	// # of occurences, where the metadata of a tree block did not match the expected values, like generation or logical
   150  	verify_errors uint64
   151  	// # of 4k data block for which no csum is present, probably the result of data written with nodatasum
   152  	no_csum              uint64
   153  	csum_discards        uint64 // # of csum for which no data was found in the extent tree.
   154  	super_errors         uint64 // # of bad super blocks encountered
   155  	malloc_errors        uint64 // # of internal kmalloc errors. These will likely cause an incomplete scrub
   156  	uncorrectable_errors uint64 // # of errors where either no intact copy was found or the writeback failed
   157  	corrected_errors     uint64 // # of errors corrected
   158  	// last physical address scrubbed. In case a scrub was aborted, this can be used to restart the scrub
   159  	last_physical uint64
   160  	// # of occurences where a read for a full (64k) bio failed, but the re-
   161  	// check succeeded for each 4k piece. Intermittent error.
   162  	unverified_errors uint64
   163  }
   164  
   165  type btrfs_ioctl_scrub_args struct {
   166  	devid    uint64               // in
   167  	start    uint64               // in
   168  	end      uint64               // in
   169  	flags    uint64               // in
   170  	progress btrfs_scrub_progress // out
   171  	// pad to 1k
   172  	_ [1024 - 4*8 - unsafe.Sizeof(btrfs_scrub_progress{})]byte
   173  }
   174  
   175  type contReadingFromSrcdevMode uint64
   176  
   177  const (
   178  	_BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS contReadingFromSrcdevMode = 0
   179  	_BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID  contReadingFromSrcdevMode = 1
   180  )
   181  
   182  type btrfs_ioctl_dev_replace_start_params struct {
   183  	srcdevid                      uint64                      // in, if 0, use srcdev_name instead
   184  	cont_reading_from_srcdev_mode contReadingFromSrcdevMode   // in
   185  	srcdev_name                   [devicePathNameMax + 1]byte // in
   186  	tgtdev_name                   [devicePathNameMax + 1]byte // in
   187  }
   188  
   189  type devReplaceState uint64
   190  
   191  const (
   192  	_BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED devReplaceState = 0
   193  	_BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED       devReplaceState = 1
   194  	_BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED      devReplaceState = 2
   195  	_BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED      devReplaceState = 3
   196  	_BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED     devReplaceState = 4
   197  )
   198  
   199  type btrfs_ioctl_dev_replace_status_params struct {
   200  	replace_state                 devReplaceState // out
   201  	progress_1000                 uint64          // out, 0 <= x <= 1000
   202  	time_started                  uint64          // out, seconds since 1-Jan-1970
   203  	time_stopped                  uint64          // out, seconds since 1-Jan-1970
   204  	num_write_errors              uint64          // out
   205  	num_uncorrectable_read_errors uint64          // out
   206  }
   207  
   208  type btrfs_ioctl_dev_replace_args_u1 struct {
   209  	cmd    uint64                               // in
   210  	result uint64                               // out
   211  	start  btrfs_ioctl_dev_replace_start_params // in
   212  	spare  [64]uint64
   213  }
   214  
   215  type btrfs_ioctl_dev_replace_args_u2 struct {
   216  	cmd    uint64                                // in
   217  	result uint64                                // out
   218  	status btrfs_ioctl_dev_replace_status_params // out
   219  	_      [unsafe.Sizeof(btrfs_ioctl_dev_replace_start_params{}) - unsafe.Sizeof(btrfs_ioctl_dev_replace_status_params{})]byte
   220  	spare  [64]uint64
   221  }
   222  
   223  type btrfs_ioctl_dev_info_args struct {
   224  	devid       uint64                  // in/out
   225  	uuid        UUID                    // in/out
   226  	bytes_used  uint64                  // out
   227  	total_bytes uint64                  // out
   228  	_           [379]uint64             // pad to 4k
   229  	path        [devicePathNameMax]byte // out
   230  }
   231  
   232  type btrfs_ioctl_fs_info_args struct {
   233  	max_id          uint64          // out
   234  	num_devices     uint64          // out
   235  	fsid            FSID            // out
   236  	nodesize        uint32          // out
   237  	sectorsize      uint32          // out
   238  	clone_alignment uint32          // out
   239  	_               [122*8 + 4]byte // pad to 1k
   240  }
   241  
   242  type btrfs_ioctl_feature_flags struct {
   243  	compat_flags    FeatureFlags
   244  	compat_ro_flags FeatureFlags
   245  	incompat_flags  IncompatFeatures
   246  }
   247  
   248  type argRange [8]byte
   249  
   250  func (u argRange) asN() uint64 {
   251  	return order.Uint64(u[:])
   252  }
   253  func (u argRange) asMinMax() (min, max uint32) {
   254  	return order.Uint32(u[:4]), order.Uint32(u[4:])
   255  }
   256  
   257  // balance control ioctl modes
   258  //#define BTRFS_BALANCE_CTL_PAUSE		1
   259  //#define BTRFS_BALANCE_CTL_CANCEL	2
   260  //#define BTRFS_BALANCE_CTL_RESUME	3
   261  
   262  // this is packed, because it should be exactly the same as its disk
   263  // byte order counterpart (struct btrfs_disk_balance_args)
   264  type btrfs_balance_args struct {
   265  	profiles uint64
   266  	// usage filter
   267  	// BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N'
   268  	// BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max
   269  	usage  argRange
   270  	devid  uint64
   271  	pstart uint64
   272  	pend   uint64
   273  	vstart uint64
   274  	vend   uint64
   275  	target uint64
   276  	flags  uint64
   277  	// BTRFS_BALANCE_ARGS_LIMIT with value 'limit' (limit number of processed chunks)
   278  	// BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum and maximum
   279  	limit       argRange
   280  	stripes_min uint32
   281  	stripes_max uint32
   282  	_           [48]byte
   283  }
   284  
   285  // Report balance progress to userspace.
   286  //
   287  // btrfs_balance_progress
   288  type BalanceProgress struct {
   289  	Expected   uint64 // estimated # of chunks that will be relocated to fulfill the request
   290  	Considered uint64 // # of chunks we have considered so far
   291  	Completed  uint64 // # of chunks relocated so far
   292  }
   293  
   294  type BalanceState uint64
   295  
   296  const (
   297  	BalanceStateRunning   BalanceState = (1 << 0)
   298  	BalanceStatePauseReq  BalanceState = (1 << 1)
   299  	BalanceStateCancelReq BalanceState = (1 << 2)
   300  )
   301  
   302  type btrfs_ioctl_balance_args struct {
   303  	flags BalanceFlags       // in/out
   304  	state BalanceState       // out
   305  	data  btrfs_balance_args // in/out
   306  	meta  btrfs_balance_args // in/out
   307  	sys   btrfs_balance_args // in/out
   308  	stat  BalanceProgress    // out
   309  	_     [72 * 8]byte       // pad to 1k
   310  }
   311  
   312  const _BTRFS_INO_LOOKUP_PATH_MAX = 4080
   313  
   314  type btrfs_ioctl_ino_lookup_args struct {
   315  	treeid   objectID
   316  	objectid objectID
   317  	name     [_BTRFS_INO_LOOKUP_PATH_MAX]byte
   318  }
   319  
   320  func (arg *btrfs_ioctl_ino_lookup_args) Name() string {
   321  	n := 0
   322  	for i, b := range arg.name {
   323  		if b == '\x00' {
   324  			n = i
   325  			break
   326  		}
   327  	}
   328  	return string(arg.name[:n])
   329  }
   330  
   331  type btrfs_ioctl_search_key struct {
   332  	tree_id objectID // which root are we searching.  0 is the tree of tree roots
   333  	// keys returned will be >= min and <= max
   334  	min_objectid objectID
   335  	max_objectid objectID
   336  	// keys returned will be >= min and <= max
   337  	min_offset uint64
   338  	max_offset uint64
   339  	// max and min transids to search for
   340  	min_transid uint64
   341  	max_transid uint64
   342  	// keys returned will be >= min and <= max
   343  	min_type treeKeyType
   344  	max_type treeKeyType
   345  	// how many items did userland ask for, and how many are we returning
   346  	nr_items uint32
   347  	_        [36]byte
   348  }
   349  
   350  type btrfs_ioctl_search_header struct {
   351  	transid  uint64
   352  	objectid objectID
   353  	offset   uint64
   354  	typ      treeKeyType
   355  	len      uint32
   356  }
   357  
   358  const _BTRFS_SEARCH_ARGS_BUFSIZE = (4096 - unsafe.Sizeof(btrfs_ioctl_search_key{}))
   359  
   360  // the buf is an array of search headers where
   361  // each header is followed by the actual item
   362  // the type field is expanded to 32 bits for alignment
   363  type btrfs_ioctl_search_args struct {
   364  	key btrfs_ioctl_search_key
   365  	buf [_BTRFS_SEARCH_ARGS_BUFSIZE]byte
   366  }
   367  
   368  // Extended version of TREE_SEARCH ioctl that can return more than 4k of bytes.
   369  // The allocated size of the buffer is set in buf_size.
   370  type btrfs_ioctl_search_args_v2 struct {
   371  	key      btrfs_ioctl_search_key // in/out - search parameters
   372  	buf_size uint64                 // in - size of buffer; out - on EOVERFLOW: needed size to store item
   373  	//buf      [0]uint64 // out - found items
   374  }
   375  
   376  // With a @src_length of zero, the range from @src_offset->EOF is cloned!
   377  type btrfs_ioctl_clone_range_args struct {
   378  	src_fd      int64
   379  	src_offset  uint64
   380  	src_length  uint64
   381  	dest_offset uint64
   382  }
   383  
   384  // flags for the defrag range ioctl
   385  type defragRange uint64
   386  
   387  const (
   388  	_BTRFS_DEFRAG_RANGE_COMPRESS defragRange = 1
   389  	_BTRFS_DEFRAG_RANGE_START_IO defragRange = 2
   390  )
   391  
   392  const _BTRFS_SAME_DATA_DIFFERS = 1
   393  
   394  // For extent-same ioctl
   395  type btrfs_ioctl_same_extent_info struct {
   396  	fd             int64  // in - destination file
   397  	logical_offset uint64 // in - start of extent in destination
   398  	bytes_deduped  uint64 // out - total # of bytes we were able to dedupe from this file
   399  	// out; status of this dedupe operation:
   400  	// 0 if dedup succeeds
   401  	// < 0 for error
   402  	// == BTRFS_SAME_DATA_DIFFERS if data differs
   403  	status   int32
   404  	reserved uint32
   405  }
   406  
   407  type btrfs_ioctl_same_args struct {
   408  	logical_offset uint64 // in - start of extent in source
   409  	length         uint64 // in - length of extent
   410  	dest_count     uint16 // in - total elements in info array
   411  	_              [6]byte
   412  	//info           [0]btrfs_ioctl_same_extent_info
   413  }
   414  
   415  type btrfs_ioctl_defrag_range_args struct {
   416  	start uint64 // start of the defrag operation
   417  	len   uint64 // number of bytes to defrag, use (u64)-1 to say all
   418  	// flags for the operation, which can include turning
   419  	// on compression for this one defrag
   420  	flags uint64
   421  	// any extent bigger than this will be considered
   422  	// already defragged.  Use 0 to take the kernel default
   423  	// Use 1 to say every single extent must be rewritten
   424  	extent_thresh uint32
   425  	// which compression method to use if turning on compression
   426  	// for this defrag operation.  If unspecified, zlib will be used
   427  	compress_type uint32
   428  	_             [16]byte // spare for later
   429  }
   430  
   431  type btrfs_ioctl_space_info struct {
   432  	flags       uint64
   433  	total_bytes uint64
   434  	used_bytes  uint64
   435  }
   436  
   437  type btrfs_ioctl_space_args struct {
   438  	space_slots  uint64
   439  	total_spaces uint64
   440  	//spaces       [0]btrfs_ioctl_space_info
   441  }
   442  
   443  type btrfs_data_container struct {
   444  	bytes_left    uint32 // out -- bytes not needed to deliver output
   445  	bytes_missing uint32 // out -- additional bytes needed for result
   446  	elem_cnt      uint32 // out
   447  	elem_missed   uint32 // out
   448  	//val           [0]uint64
   449  }
   450  
   451  type btrfs_ioctl_ino_path_args struct {
   452  	inum uint64 // in
   453  	size uint64 // in
   454  	_    [32]byte
   455  	// struct btrfs_data_container	*fspath;	   out
   456  	fspath uint64 // out
   457  }
   458  
   459  type btrfs_ioctl_logical_ino_args struct {
   460  	logical uint64 // in
   461  	size    uint64 // in
   462  	_       [32]byte
   463  	// struct btrfs_data_container	*inodes;	out
   464  	inodes uint64
   465  }
   466  
   467  // disk I/O failure stats
   468  const (
   469  	_BTRFS_DEV_STAT_WRITE_ERRS = iota // EIO or EREMOTEIO from lower layers
   470  	_BTRFS_DEV_STAT_READ_ERRS         // EIO or EREMOTEIO from lower layers
   471  	_BTRFS_DEV_STAT_FLUSH_ERRS        // EIO or EREMOTEIO from lower layers
   472  
   473  	// stats for indirect indications for I/O failures
   474  
   475  	// checksum error, bytenr error or contents is illegal: this is an
   476  	// indication that the block was damaged during read or write, or written to
   477  	// wrong location or read from wrong location
   478  	_BTRFS_DEV_STAT_CORRUPTION_ERRS
   479  	_BTRFS_DEV_STAT_GENERATION_ERRS // an indication that blocks have not been written
   480  
   481  	_BTRFS_DEV_STAT_VALUES_MAX
   482  )
   483  
   484  // Reset statistics after reading; needs SYS_ADMIN capability
   485  const _BTRFS_DEV_STATS_RESET = (1 << 0)
   486  
   487  type btrfs_ioctl_get_dev_stats struct {
   488  	devid    uint64                                       // in
   489  	nr_items uint64                                       // in/out
   490  	flags    uint64                                       // in/out
   491  	values   [_BTRFS_DEV_STAT_VALUES_MAX]uint64           // out values
   492  	_        [128 - 2 - _BTRFS_DEV_STAT_VALUES_MAX]uint64 // pad to 1k
   493  }
   494  
   495  const (
   496  	_BTRFS_QUOTA_CTL_ENABLE  = 1
   497  	_BTRFS_QUOTA_CTL_DISABLE = 2
   498  	// 3 has formerly been reserved for BTRFS_QUOTA_CTL_RESCAN
   499  )
   500  
   501  type btrfs_ioctl_quota_ctl_args struct {
   502  	cmd    uint64
   503  	status uint64
   504  }
   505  
   506  type btrfs_ioctl_quota_rescan_args struct {
   507  	flags    uint64
   508  	progress uint64
   509  	_        [6]uint64
   510  }
   511  
   512  type btrfs_ioctl_qgroup_assign_args struct {
   513  	assign uint64
   514  	src    uint64
   515  	dst    uint64
   516  }
   517  
   518  type btrfs_ioctl_qgroup_create_args struct {
   519  	create   uint64
   520  	qgroupid uint64
   521  }
   522  
   523  type btrfs_ioctl_timespec struct {
   524  	sec  uint64
   525  	nsec uint32
   526  }
   527  
   528  type btrfs_ioctl_received_subvol_args struct {
   529  	uuid     UUID                 // in
   530  	stransid uint64               // in
   531  	rtransid uint64               // out
   532  	stime    btrfs_ioctl_timespec // in
   533  	rtime    btrfs_ioctl_timespec // out
   534  	flags    uint64               // in
   535  	_        [16]uint64           // in
   536  }
   537  
   538  const (
   539  	// Caller doesn't want file data in the send stream, even if the
   540  	// search of clone sources doesn't find an extent. UPDATE_EXTENT
   541  	// commands will be sent instead of WRITE commands.
   542  	_BTRFS_SEND_FLAG_NO_FILE_DATA = 0x1
   543  	// Do not add the leading stream header. Used when multiple snapshots
   544  	// are sent back to back.
   545  	_BTRFS_SEND_FLAG_OMIT_STREAM_HEADER = 0x2
   546  	// Omit the command at the end of the stream that indicated the end
   547  	// of the stream. This option is used when multiple snapshots are
   548  	// sent back to back.
   549  	_BTRFS_SEND_FLAG_OMIT_END_CMD = 0x4
   550  
   551  	_BTRFS_SEND_FLAG_MASK = _BTRFS_SEND_FLAG_NO_FILE_DATA |
   552  		_BTRFS_SEND_FLAG_OMIT_STREAM_HEADER |
   553  		_BTRFS_SEND_FLAG_OMIT_END_CMD
   554  )
   555  
   556  type btrfs_ioctl_send_args struct {
   557  	send_fd             int64     // in
   558  	clone_sources_count uint64    // in
   559  	clone_sources       *objectID // in
   560  	parent_root         objectID  // in
   561  	flags               uint64    // in
   562  	_                   [4]uint64 // in
   563  }
   564  
   565  var (
   566  	_BTRFS_IOC_SNAP_CREATE            = ioctl.IOW(ioctlMagic, 1, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   567  	_BTRFS_IOC_DEFRAG                 = ioctl.IOW(ioctlMagic, 2, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   568  	_BTRFS_IOC_RESIZE                 = ioctl.IOW(ioctlMagic, 3, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   569  	_BTRFS_IOC_SCAN_DEV               = ioctl.IOW(ioctlMagic, 4, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   570  	_BTRFS_IOC_TRANS_START            = ioctl.IO(ioctlMagic, 6)
   571  	_BTRFS_IOC_TRANS_END              = ioctl.IO(ioctlMagic, 7)
   572  	_BTRFS_IOC_SYNC                   = ioctl.IO(ioctlMagic, 8)
   573  	_BTRFS_IOC_CLONE                  = ioctl.IOW(ioctlMagic, 9, 4) // int32
   574  	_BTRFS_IOC_ADD_DEV                = ioctl.IOW(ioctlMagic, 10, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   575  	_BTRFS_IOC_RM_DEV                 = ioctl.IOW(ioctlMagic, 11, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   576  	_BTRFS_IOC_BALANCE                = ioctl.IOW(ioctlMagic, 12, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   577  	_BTRFS_IOC_CLONE_RANGE            = ioctl.IOW(ioctlMagic, 13, unsafe.Sizeof(btrfs_ioctl_clone_range_args{}))
   578  	_BTRFS_IOC_SUBVOL_CREATE          = ioctl.IOW(ioctlMagic, 14, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   579  	_BTRFS_IOC_SNAP_DESTROY           = ioctl.IOW(ioctlMagic, 15, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   580  	_BTRFS_IOC_DEFRAG_RANGE           = ioctl.IOW(ioctlMagic, 16, unsafe.Sizeof(btrfs_ioctl_defrag_range_args{}))
   581  	_BTRFS_IOC_TREE_SEARCH            = ioctl.IOWR(ioctlMagic, 17, unsafe.Sizeof(btrfs_ioctl_search_args{}))
   582  	_BTRFS_IOC_INO_LOOKUP             = ioctl.IOWR(ioctlMagic, 18, unsafe.Sizeof(btrfs_ioctl_ino_lookup_args{}))
   583  	_BTRFS_IOC_DEFAULT_SUBVOL         = ioctl.IOW(ioctlMagic, 19, 8) // uint64
   584  	_BTRFS_IOC_SPACE_INFO             = ioctl.IOWR(ioctlMagic, 20, unsafe.Sizeof(btrfs_ioctl_space_args{}))
   585  	_BTRFS_IOC_START_SYNC             = ioctl.IOR(ioctlMagic, 24, 8) // uint64
   586  	_BTRFS_IOC_WAIT_SYNC              = ioctl.IOW(ioctlMagic, 22, 8) // uint64
   587  	_BTRFS_IOC_SNAP_CREATE_V2         = ioctl.IOW(ioctlMagic, 23, unsafe.Sizeof(btrfs_ioctl_vol_args_v2{}))
   588  	_BTRFS_IOC_SUBVOL_CREATE_V2       = ioctl.IOW(ioctlMagic, 24, unsafe.Sizeof(btrfs_ioctl_vol_args_v2{}))
   589  	_BTRFS_IOC_SUBVOL_GETFLAGS        = ioctl.IOR(ioctlMagic, 25, 8) // uint64
   590  	_BTRFS_IOC_SUBVOL_SETFLAGS        = ioctl.IOW(ioctlMagic, 26, 8) // uint64
   591  	_BTRFS_IOC_SCRUB                  = ioctl.IOWR(ioctlMagic, 27, unsafe.Sizeof(btrfs_ioctl_scrub_args{}))
   592  	_BTRFS_IOC_SCRUB_CANCEL           = ioctl.IO(ioctlMagic, 28)
   593  	_BTRFS_IOC_SCRUB_PROGRESS         = ioctl.IOWR(ioctlMagic, 29, unsafe.Sizeof(btrfs_ioctl_scrub_args{}))
   594  	_BTRFS_IOC_DEV_INFO               = ioctl.IOWR(ioctlMagic, 30, unsafe.Sizeof(btrfs_ioctl_dev_info_args{}))
   595  	_BTRFS_IOC_FS_INFO                = ioctl.IOR(ioctlMagic, 31, unsafe.Sizeof(btrfs_ioctl_fs_info_args{}))
   596  	_BTRFS_IOC_BALANCE_V2             = ioctl.IOWR(ioctlMagic, 32, unsafe.Sizeof(btrfs_ioctl_balance_args{}))
   597  	_BTRFS_IOC_BALANCE_CTL            = ioctl.IOW(ioctlMagic, 33, 4) // int32
   598  	_BTRFS_IOC_BALANCE_PROGRESS       = ioctl.IOR(ioctlMagic, 34, unsafe.Sizeof(btrfs_ioctl_balance_args{}))
   599  	_BTRFS_IOC_INO_PATHS              = ioctl.IOWR(ioctlMagic, 35, unsafe.Sizeof(btrfs_ioctl_ino_path_args{}))
   600  	_BTRFS_IOC_LOGICAL_INO            = ioctl.IOWR(ioctlMagic, 36, unsafe.Sizeof(btrfs_ioctl_ino_path_args{}))
   601  	_BTRFS_IOC_SET_RECEIVED_SUBVOL    = ioctl.IOWR(ioctlMagic, 37, unsafe.Sizeof(btrfs_ioctl_received_subvol_args{}))
   602  	_BTRFS_IOC_SEND                   = ioctl.IOW(ioctlMagic, 38, unsafe.Sizeof(btrfs_ioctl_send_args{}))
   603  	_BTRFS_IOC_DEVICES_READY          = ioctl.IOR(ioctlMagic, 39, unsafe.Sizeof(btrfs_ioctl_vol_args{}))
   604  	_BTRFS_IOC_QUOTA_CTL              = ioctl.IOWR(ioctlMagic, 40, unsafe.Sizeof(btrfs_ioctl_quota_ctl_args{}))
   605  	_BTRFS_IOC_QGROUP_ASSIGN          = ioctl.IOW(ioctlMagic, 41, unsafe.Sizeof(btrfs_ioctl_qgroup_assign_args{}))
   606  	_BTRFS_IOC_QGROUP_CREATE          = ioctl.IOW(ioctlMagic, 42, unsafe.Sizeof(btrfs_ioctl_qgroup_create_args{}))
   607  	_BTRFS_IOC_QGROUP_LIMIT           = ioctl.IOR(ioctlMagic, 43, unsafe.Sizeof(btrfs_ioctl_qgroup_limit_args{}))
   608  	_BTRFS_IOC_QUOTA_RESCAN           = ioctl.IOW(ioctlMagic, 44, unsafe.Sizeof(btrfs_ioctl_quota_rescan_args{}))
   609  	_BTRFS_IOC_QUOTA_RESCAN_STATUS    = ioctl.IOR(ioctlMagic, 45, unsafe.Sizeof(btrfs_ioctl_quota_rescan_args{}))
   610  	_BTRFS_IOC_QUOTA_RESCAN_WAIT      = ioctl.IO(ioctlMagic, 46)
   611  	_BTRFS_IOC_GET_FSLABEL            = ioctl.IOR(ioctlMagic, 49, labelSize)
   612  	_BTRFS_IOC_SET_FSLABEL            = ioctl.IOW(ioctlMagic, 50, labelSize)
   613  	_BTRFS_IOC_GET_DEV_STATS          = ioctl.IOWR(ioctlMagic, 52, unsafe.Sizeof(btrfs_ioctl_get_dev_stats{}))
   614  	_BTRFS_IOC_DEV_REPLACE            = ioctl.IOWR(ioctlMagic, 53, unsafe.Sizeof(btrfs_ioctl_dev_replace_args_u1{}))
   615  	_BTRFS_IOC_FILE_EXTENT_SAME       = ioctl.IOWR(ioctlMagic, 54, unsafe.Sizeof(btrfs_ioctl_same_args{}))
   616  	_BTRFS_IOC_GET_FEATURES           = ioctl.IOR(ioctlMagic, 57, unsafe.Sizeof(btrfs_ioctl_feature_flags{}))
   617  	_BTRFS_IOC_SET_FEATURES           = ioctl.IOW(ioctlMagic, 57, unsafe.Sizeof([2]btrfs_ioctl_feature_flags{}))
   618  	_BTRFS_IOC_GET_SUPPORTED_FEATURES = ioctl.IOR(ioctlMagic, 57, unsafe.Sizeof([3]btrfs_ioctl_feature_flags{}))
   619  )
   620  
   621  func iocSnapCreate(f *os.File, in *btrfs_ioctl_vol_args) error {
   622  	return ioctl.Do(f, _BTRFS_IOC_SNAP_CREATE, in)
   623  }
   624  
   625  func iocSnapCreateV2(f *os.File, in *btrfs_ioctl_vol_args_v2) error {
   626  	return ioctl.Do(f, _BTRFS_IOC_SNAP_CREATE_V2, in)
   627  }
   628  
   629  func iocDefrag(f *os.File, out *btrfs_ioctl_vol_args) error {
   630  	return ioctl.Do(f, _BTRFS_IOC_DEFRAG, out)
   631  }
   632  
   633  func iocResize(f *os.File, in *btrfs_ioctl_vol_args) error {
   634  	return ioctl.Do(f, _BTRFS_IOC_RESIZE, in)
   635  }
   636  
   637  func iocScanDev(f *os.File, out *btrfs_ioctl_vol_args) error {
   638  	return ioctl.Do(f, _BTRFS_IOC_SCAN_DEV, out)
   639  }
   640  
   641  func iocTransStart(f *os.File) error {
   642  	return ioctl.Do(f, _BTRFS_IOC_TRANS_START, nil)
   643  }
   644  
   645  func iocTransEnd(f *os.File) error {
   646  	return ioctl.Do(f, _BTRFS_IOC_TRANS_END, nil)
   647  }
   648  
   649  func iocSync(f *os.File) error {
   650  	return ioctl.Do(f, _BTRFS_IOC_SYNC, nil)
   651  }
   652  
   653  func iocClone(dst, src *os.File) error {
   654  	return ioctl.Ioctl(dst, _BTRFS_IOC_CLONE, src.Fd())
   655  }
   656  
   657  func iocAddDev(f *os.File, out *btrfs_ioctl_vol_args) error {
   658  	return ioctl.Do(f, _BTRFS_IOC_ADD_DEV, out)
   659  }
   660  
   661  func iocRmDev(f *os.File, out *btrfs_ioctl_vol_args) error {
   662  	return ioctl.Do(f, _BTRFS_IOC_RM_DEV, out)
   663  }
   664  
   665  func iocBalance(f *os.File, out *btrfs_ioctl_vol_args) error {
   666  	return ioctl.Do(f, _BTRFS_IOC_BALANCE, out)
   667  }
   668  
   669  func iocCloneRange(f *os.File, out *btrfs_ioctl_clone_range_args) error {
   670  	return ioctl.Do(f, _BTRFS_IOC_CLONE_RANGE, out)
   671  }
   672  
   673  func iocSubvolCreate(f *os.File, in *btrfs_ioctl_vol_args) error {
   674  	return ioctl.Do(f, _BTRFS_IOC_SUBVOL_CREATE, in)
   675  }
   676  
   677  func iocSubvolCreateV2(f *os.File, in *btrfs_ioctl_vol_args_v2) error {
   678  	return ioctl.Do(f, _BTRFS_IOC_SUBVOL_CREATE, in)
   679  }
   680  
   681  func iocSnapDestroy(f *os.File, in *btrfs_ioctl_vol_args) error {
   682  	return ioctl.Do(f, _BTRFS_IOC_SNAP_DESTROY, in)
   683  }
   684  
   685  func iocDefragRange(f *os.File, out *btrfs_ioctl_defrag_range_args) error {
   686  	return ioctl.Do(f, _BTRFS_IOC_DEFRAG_RANGE, out)
   687  }
   688  
   689  func iocTreeSearch(f *os.File, out *btrfs_ioctl_search_args) error {
   690  	return ioctl.Do(f, _BTRFS_IOC_TREE_SEARCH, out)
   691  }
   692  
   693  func iocInoLookup(f *os.File, out *btrfs_ioctl_ino_lookup_args) error {
   694  	return ioctl.Do(f, _BTRFS_IOC_INO_LOOKUP, out)
   695  }
   696  
   697  func iocDefaultSubvol(f *os.File, out *uint64) error {
   698  	return ioctl.Do(f, _BTRFS_IOC_DEFAULT_SUBVOL, out)
   699  }
   700  
   701  type spaceFlags uint64
   702  
   703  func (f spaceFlags) BlockGroup() blockGroup {
   704  	return blockGroup(f) & _BTRFS_BLOCK_GROUP_MASK
   705  }
   706  
   707  type spaceInfo struct {
   708  	Flags      spaceFlags
   709  	TotalBytes uint64
   710  	UsedBytes  uint64
   711  }
   712  
   713  func iocSpaceInfo(f *os.File) ([]spaceInfo, error) {
   714  	arg := &btrfs_ioctl_space_args{}
   715  	if err := ioctl.Do(f, _BTRFS_IOC_SPACE_INFO, arg); err != nil {
   716  		return nil, err
   717  	}
   718  	n := arg.total_spaces
   719  	if n == 0 {
   720  		return nil, nil
   721  	}
   722  	const (
   723  		argSize  = unsafe.Sizeof(btrfs_ioctl_space_args{})
   724  		infoSize = unsafe.Sizeof(btrfs_ioctl_space_info{})
   725  	)
   726  	buf := make([]byte, argSize+uintptr(n)*infoSize)
   727  	basePtr := unsafe.Pointer(&buf[0])
   728  	arg = (*btrfs_ioctl_space_args)(basePtr)
   729  	arg.space_slots = n
   730  	if err := ioctl.Do(f, _BTRFS_IOC_SPACE_INFO, arg); err != nil {
   731  		return nil, err
   732  	} else if arg.total_spaces == 0 {
   733  		return nil, nil
   734  	}
   735  	if n > arg.total_spaces {
   736  		n = arg.total_spaces
   737  	}
   738  	out := make([]spaceInfo, n)
   739  	ptr := uintptr(basePtr) + argSize
   740  	for i := 0; i < int(n); i++ {
   741  		info := (*btrfs_ioctl_space_info)(unsafe.Pointer(ptr))
   742  		out[i] = spaceInfo{
   743  			Flags:      spaceFlags(info.flags),
   744  			TotalBytes: info.total_bytes,
   745  			UsedBytes:  info.used_bytes,
   746  		}
   747  		ptr += infoSize
   748  	}
   749  	return out, nil
   750  }
   751  
   752  func iocStartSync(f *os.File, out *uint64) error {
   753  	return ioctl.Do(f, _BTRFS_IOC_START_SYNC, out)
   754  }
   755  
   756  func iocWaitSync(f *os.File, out *uint64) error {
   757  	return ioctl.Do(f, _BTRFS_IOC_WAIT_SYNC, out)
   758  }
   759  
   760  func iocSubvolGetflags(f *os.File) (out SubvolFlags, err error) {
   761  	err = ioctl.Do(f, _BTRFS_IOC_SUBVOL_GETFLAGS, &out)
   762  	return
   763  }
   764  
   765  func iocSubvolSetflags(f *os.File, flags SubvolFlags) error {
   766  	v := uint64(flags)
   767  	return ioctl.Do(f, _BTRFS_IOC_SUBVOL_SETFLAGS, &v)
   768  }
   769  
   770  func iocScrub(f *os.File, out *btrfs_ioctl_scrub_args) error {
   771  	return ioctl.Do(f, _BTRFS_IOC_SCRUB, out)
   772  }
   773  
   774  func iocScrubCancel(f *os.File) error {
   775  	return ioctl.Do(f, _BTRFS_IOC_SCRUB_CANCEL, nil)
   776  }
   777  
   778  func iocScrubProgress(f *os.File, out *btrfs_ioctl_scrub_args) error {
   779  	return ioctl.Do(f, _BTRFS_IOC_SCRUB_PROGRESS, out)
   780  }
   781  
   782  func iocFsInfo(f *os.File) (out btrfs_ioctl_fs_info_args, err error) {
   783  	err = ioctl.Do(f, _BTRFS_IOC_FS_INFO, &out)
   784  	return
   785  }
   786  
   787  func iocDevInfo(f *os.File, devid uint64, uuid UUID) (out btrfs_ioctl_dev_info_args, err error) {
   788  	out.devid = devid
   789  	out.uuid = uuid
   790  	err = ioctl.Do(f, _BTRFS_IOC_DEV_INFO, &out)
   791  	return
   792  }
   793  
   794  func iocBalanceV2(f *os.File, out *btrfs_ioctl_balance_args) error {
   795  	return ioctl.Do(f, _BTRFS_IOC_BALANCE_V2, out)
   796  }
   797  
   798  func iocBalanceCtl(f *os.File, out *int32) error {
   799  	return ioctl.Do(f, _BTRFS_IOC_BALANCE_CTL, out)
   800  }
   801  
   802  func iocBalanceProgress(f *os.File, out *btrfs_ioctl_balance_args) error {
   803  	return ioctl.Do(f, _BTRFS_IOC_BALANCE_PROGRESS, out)
   804  }
   805  
   806  func iocInoPaths(f *os.File, out *btrfs_ioctl_ino_path_args) error {
   807  	return ioctl.Do(f, _BTRFS_IOC_INO_PATHS, out)
   808  }
   809  
   810  func iocLogicalIno(f *os.File, out *btrfs_ioctl_ino_path_args) error {
   811  	return ioctl.Do(f, _BTRFS_IOC_LOGICAL_INO, out)
   812  }
   813  
   814  func iocSetReceivedSubvol(f *os.File, out *btrfs_ioctl_received_subvol_args) error {
   815  	return ioctl.Do(f, _BTRFS_IOC_SET_RECEIVED_SUBVOL, out)
   816  }
   817  
   818  func iocSend(f *os.File, in *btrfs_ioctl_send_args) error {
   819  	return ioctl.Do(f, _BTRFS_IOC_SEND, in)
   820  }
   821  
   822  func iocDevicesReady(f *os.File, out *btrfs_ioctl_vol_args) error {
   823  	return ioctl.Do(f, _BTRFS_IOC_DEVICES_READY, out)
   824  }
   825  
   826  func iocQuotaCtl(f *os.File, out *btrfs_ioctl_quota_ctl_args) error {
   827  	return ioctl.Do(f, _BTRFS_IOC_QUOTA_CTL, out)
   828  }
   829  
   830  func iocQgroupAssign(f *os.File, out *btrfs_ioctl_qgroup_assign_args) error {
   831  	return ioctl.Do(f, _BTRFS_IOC_QGROUP_ASSIGN, out)
   832  }
   833  
   834  func iocQgroupCreate(f *os.File, out *btrfs_ioctl_qgroup_create_args) error {
   835  	return ioctl.Do(f, _BTRFS_IOC_QGROUP_CREATE, out)
   836  }
   837  
   838  func iocQgroupLimit(f *os.File, out *btrfs_ioctl_qgroup_limit_args) error {
   839  	return ioctl.Do(f, _BTRFS_IOC_QGROUP_LIMIT, out)
   840  }
   841  
   842  func iocQuotaRescan(f *os.File, out *btrfs_ioctl_quota_rescan_args) error {
   843  	return ioctl.Do(f, _BTRFS_IOC_QUOTA_RESCAN, out)
   844  }
   845  
   846  func iocQuotaRescanStatus(f *os.File, out *btrfs_ioctl_quota_rescan_args) error {
   847  	return ioctl.Do(f, _BTRFS_IOC_QUOTA_RESCAN_STATUS, out)
   848  }
   849  
   850  func iocQuotaRescanWait(f *os.File) error {
   851  	return ioctl.Do(f, _BTRFS_IOC_QUOTA_RESCAN_WAIT, nil)
   852  }
   853  
   854  func iocGetFslabel(f *os.File, out *[labelSize]byte) error {
   855  	return ioctl.Do(f, _BTRFS_IOC_GET_FSLABEL, out)
   856  }
   857  
   858  func iocSetFslabel(f *os.File, out *[labelSize]byte) error {
   859  	return ioctl.Do(f, _BTRFS_IOC_SET_FSLABEL, out)
   860  }
   861  
   862  func iocGetDevStats(f *os.File, out *btrfs_ioctl_get_dev_stats) error {
   863  	return ioctl.Do(f, _BTRFS_IOC_GET_DEV_STATS, out)
   864  }
   865  
   866  //func iocDevReplace(f *os.File, out *btrfs_ioctl_dev_replace_args) error {
   867  //	return ioctl.Do(f, _BTRFS_IOC_DEV_REPLACE, out)
   868  //}
   869  
   870  func iocFileExtentSame(f *os.File, out *btrfs_ioctl_same_args) error {
   871  	return ioctl.Do(f, _BTRFS_IOC_FILE_EXTENT_SAME, out)
   872  }
   873  
   874  func iocSetFeatures(f *os.File, out *[2]btrfs_ioctl_feature_flags) error {
   875  	return ioctl.Do(f, _BTRFS_IOC_SET_FEATURES, out)
   876  }