mirror of
https://github.com/dennwc/btrfs
synced 2025-03-11 06:48:27 +00:00
implement subvolumes list; regenerate headers; generate btrfs_tree.h
This commit is contained in:
parent
b300237e77
commit
f03fa748e7
@ -2,6 +2,8 @@ package btrfs
|
|||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
|
const maxUint64 = 1<<64 - 1
|
||||||
|
|
||||||
const BTRFS_LABEL_SIZE = 256
|
const BTRFS_LABEL_SIZE = 256
|
||||||
|
|
||||||
type FeatureFlags uint64
|
type FeatureFlags uint64
|
||||||
|
54
btrfs_tree.go
Normal file
54
btrfs_tree.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package btrfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_BTRFS_BLOCK_GROUP_PROFILE_MASK = (blockGroupRaid0 |
|
||||||
|
blockGroupRaid1 |
|
||||||
|
blockGroupRaid5 |
|
||||||
|
blockGroupRaid6 |
|
||||||
|
blockGroupDup |
|
||||||
|
blockGroupRaid10)
|
||||||
|
)
|
||||||
|
|
||||||
|
type rootRef struct {
|
||||||
|
DirID uint64
|
||||||
|
Sequence uint64
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rootRef) btrfsSize() int { return 18 }
|
||||||
|
|
||||||
|
func asUint64(p []byte) uint64 {
|
||||||
|
return *(*uint64)(unsafe.Pointer(&p[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func asUint32(p []byte) uint32 {
|
||||||
|
return *(*uint32)(unsafe.Pointer(&p[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func asUint16(p []byte) uint16 {
|
||||||
|
return *(*uint16)(unsafe.Pointer(&p[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func asTime(p []byte) time.Time {
|
||||||
|
sec, nsec := asUint64(p[0:]), asUint32(p[8:])
|
||||||
|
return time.Unix(int64(sec), int64(nsec))
|
||||||
|
}
|
||||||
|
|
||||||
|
func asRootRef(p []byte) rootRef {
|
||||||
|
const sz = 18
|
||||||
|
// assuming that it is highly unsafe to have sizeof(struct) > len(data)
|
||||||
|
// (*btrfs_root_ref)(unsafe.Pointer(&p[0])) and sizeof(btrfs_root_ref) == 24
|
||||||
|
ref := rootRef{
|
||||||
|
DirID: asUint64(p[0:]),
|
||||||
|
Sequence: asUint64(p[8:]),
|
||||||
|
}
|
||||||
|
if n := asUint16(p[16:]); n > 0 {
|
||||||
|
ref.Name = string(p[sz : sz+n : sz+n])
|
||||||
|
}
|
||||||
|
return ref
|
||||||
|
}
|
745
btrfs_tree_h.go
Normal file
745
btrfs_tree_h.go
Normal file
@ -0,0 +1,745 @@
|
|||||||
|
package btrfs
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This header contains the structure definitions and constants used
|
||||||
|
* by file system objects that can be retrieved using
|
||||||
|
* the _BTRFS_IOC_SEARCH_TREE ioctl. That means basically anything that
|
||||||
|
* is needed to describe a leaf node's key or item contents.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* holds pointers to all of the tree roots */
|
||||||
|
|
||||||
|
/* stores information about which extents are in use, and reference counts */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* chunk tree stores translations from logical -> physical block numbering
|
||||||
|
* the super block points to the chunk tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stores information about which areas of a given device are in use.
|
||||||
|
* one per device. The tree of tree roots points to the device tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* one per subvolume, storing files and directories */
|
||||||
|
|
||||||
|
/* directory objectid inside the root tree */
|
||||||
|
|
||||||
|
/* holds checksums of all the data extents */
|
||||||
|
|
||||||
|
/* holds quota configuration and tracking */
|
||||||
|
|
||||||
|
/* for storing items that use the _BTRFS_UUID_KEY* types */
|
||||||
|
|
||||||
|
/* tracks free space in block groups. */
|
||||||
|
|
||||||
|
/* device stats in the device tree */
|
||||||
|
|
||||||
|
/* for storing balance parameters in the root tree */
|
||||||
|
|
||||||
|
/* orhpan objectid for tracking unlinked/truncated files */
|
||||||
|
|
||||||
|
/* does write ahead logging to speed up fsyncs */
|
||||||
|
|
||||||
|
/* for space balancing */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extent checksums all have this objectid
|
||||||
|
* this allows them to share the logging tree
|
||||||
|
* for fsyncs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For storing free space cache */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The inode number assigned to the special inode for storing
|
||||||
|
* free ino cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* dummy objectid represents multiple objectids */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All files have objectids in this range.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the device items go into the chunk tree. The key is in the form
|
||||||
|
* [ 1 _BTRFS_DEV_ITEM_KEY device_id ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* inode items have the data typically returned from stat and store other
|
||||||
|
* info about object characteristics. There is one for every file and dir in
|
||||||
|
* the FS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* reserve 2-15 close to the inode for later flexibility */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dir items are the name -> inode pointers in a directory. There is one
|
||||||
|
* for every name in a directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extent data is for file data
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extent csums are stored in a separate tree and hold csums for
|
||||||
|
* an entire extent on disk.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* root items point to tree roots. They are typically in the root
|
||||||
|
* tree used by the super block to find all the other trees
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* root backrefs tie subvols and snapshots to the directory entries that
|
||||||
|
* reference them
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* root refs make a fast index for listing all of the snapshots and
|
||||||
|
* subvolumes referenced by a given root. They point directly to the
|
||||||
|
* directory item in the root that references the subvol
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extent items are in the extent map tree. These record which blocks
|
||||||
|
* are used, and how many references there are to each block
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The same as the _BTRFS_EXTENT_ITEM_KEY, except it's metadata we already know
|
||||||
|
* the length, so we save the level in key->offset instead of the length.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* block groups give us hints into the extent allocation trees. Which
|
||||||
|
* blocks are free etc etc
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Every block group is represented in the free space tree by a free space info
|
||||||
|
* item, which stores some accounting information. It is keyed on
|
||||||
|
* (block_group_start, FREE_SPACE_INFO, block_group_length).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A free space extent tracks an extent of space that is free in a block group.
|
||||||
|
* It is keyed on (start, FREE_SPACE_EXTENT, length).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When a block group becomes very fragmented, we convert it to use bitmaps
|
||||||
|
* instead of extents. A free space bitmap is keyed on
|
||||||
|
* (start, FREE_SPACE_BITMAP, length); the corresponding item is a bitmap with
|
||||||
|
* (length / sectorsize) bits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Records the overall state of the qgroups.
|
||||||
|
* There's only one instance of this key present,
|
||||||
|
* (0, _BTRFS_QGROUP_STATUS_KEY, 0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Records the currently used space of the qgroup.
|
||||||
|
* One key per qgroup, (0, _BTRFS_QGROUP_INFO_KEY, qgroupid).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Contains the user configured limits for the qgroup.
|
||||||
|
* One key per qgroup, (0, _BTRFS_QGROUP_LIMIT_KEY, qgroupid).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Records the child-parent relationship of qgroups. For
|
||||||
|
* each relation, 2 keys are present:
|
||||||
|
* (childid, _BTRFS_QGROUP_RELATION_KEY, parentid)
|
||||||
|
* (parentid, _BTRFS_QGROUP_RELATION_KEY, childid)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obsolete name, see _BTRFS_TEMPORARY_ITEM_KEY.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key type for tree items that are stored persistently, but do not need to
|
||||||
|
* exist for extended period of time. The items can exist in any tree.
|
||||||
|
*
|
||||||
|
* [subtype, _BTRFS_TEMPORARY_ITEM_KEY, data]
|
||||||
|
*
|
||||||
|
* Existing items:
|
||||||
|
*
|
||||||
|
* - balance status item
|
||||||
|
* (_BTRFS_BALANCE_OBJECTID, _BTRFS_TEMPORARY_ITEM_KEY, 0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obsolete name, see _BTRFS_PERSISTENT_ITEM_KEY
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key type for tree items that are stored persistently and usually exist
|
||||||
|
* for a long period, eg. filesystem lifetime. The item kinds can be status
|
||||||
|
* information, stats or preference values. The item can exist in any tree.
|
||||||
|
*
|
||||||
|
* [subtype, _BTRFS_PERSISTENT_ITEM_KEY, data]
|
||||||
|
*
|
||||||
|
* Existing items:
|
||||||
|
*
|
||||||
|
* - device statistics, store IO stats in the device tree, one key for all
|
||||||
|
* stats
|
||||||
|
* (_BTRFS_DEV_STATS_OBJECTID, _BTRFS_DEV_STATS_KEY, 0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Persistantly stores the device replace state in the device tree.
|
||||||
|
* The key is built like this: (0, _BTRFS_DEV_REPLACE_KEY, 0).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stores items that allow to quickly map UUIDs to something else.
|
||||||
|
* These items are part of the filesystem UUID tree.
|
||||||
|
* The key is built like this:
|
||||||
|
* (UUID_upper_64_bits, _BTRFS_UUID_KEY*, UUID_lower_64_bits).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* for UUIDs assigned to * received subvols */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* string items are for debugging. They just store a short string of
|
||||||
|
* data in the FS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 32 bytes in various csum fields */
|
||||||
|
|
||||||
|
/* csum types */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flags definitions for directory entry item type
|
||||||
|
*
|
||||||
|
* Used by:
|
||||||
|
* struct btrfs_dir_item.type
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key defines the order in the tree, and so it also defines (optimal)
|
||||||
|
* block layout.
|
||||||
|
*
|
||||||
|
* objectid corresponds to the inode number.
|
||||||
|
*
|
||||||
|
* type tells us things about the object, and is a kind of stream selector.
|
||||||
|
* so for a given inode, keys with type of 1 might refer to the inode data,
|
||||||
|
* type of 2 may point to file data in the btree and type == 3 may point to
|
||||||
|
* extents.
|
||||||
|
*
|
||||||
|
* offset is the starting byte offset for this key in the stream.
|
||||||
|
*
|
||||||
|
* btrfs_disk_key is in disk byte order. struct btrfs_key is always
|
||||||
|
* in cpu native order. Otherwise they are identical and their sizes
|
||||||
|
* should be the same (ie both packed)
|
||||||
|
*/
|
||||||
|
type btrfs_disk_key struct {
|
||||||
|
objectid uint64
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_key struct {
|
||||||
|
objectid uint64
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_dev_item struct {
|
||||||
|
devid uint64
|
||||||
|
total_bytes uint64
|
||||||
|
bytes_used uint64
|
||||||
|
io_align uint32
|
||||||
|
io_width uint32
|
||||||
|
sector_size uint32
|
||||||
|
type_ uint64
|
||||||
|
generation uint64
|
||||||
|
start_offset uint64
|
||||||
|
dev_group uint32
|
||||||
|
seek_speed uint8
|
||||||
|
bandwidth uint8
|
||||||
|
uuid UUID
|
||||||
|
fsid FSID
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_stripe struct {
|
||||||
|
devid uint64
|
||||||
|
offset uint64
|
||||||
|
dev_uuid UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_chunk struct {
|
||||||
|
length uint64
|
||||||
|
owner uint64
|
||||||
|
stripe_len uint64
|
||||||
|
type_ uint64
|
||||||
|
io_align uint32
|
||||||
|
io_width uint32
|
||||||
|
sector_size uint32
|
||||||
|
num_stripes uint16
|
||||||
|
sub_stripes uint16
|
||||||
|
stripe struct {
|
||||||
|
devid uint64
|
||||||
|
offset uint64
|
||||||
|
dev_uuid UUID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* additional stripes go here */
|
||||||
|
type btrfs_free_space_entry struct {
|
||||||
|
offset uint64
|
||||||
|
bytes uint64
|
||||||
|
type_ uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_free_space_header struct {
|
||||||
|
location struct {
|
||||||
|
objectid uint64
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
generation uint64
|
||||||
|
num_entries uint64
|
||||||
|
num_bitmaps uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Super block flags */
|
||||||
|
/* Errors detected */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* items in the extent btree are used to record the objectid of the
|
||||||
|
* owner of the block and the number of references
|
||||||
|
*/
|
||||||
|
type btrfs_extent_item struct {
|
||||||
|
refs uint64
|
||||||
|
generation uint64
|
||||||
|
flags uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_extent_item_v0 struct {
|
||||||
|
refs uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
/* following flags only apply to tree blocks */
|
||||||
|
|
||||||
|
/* use full backrefs for extent pointers in the block */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this flag is only used internally by scrub and may be changed at any time
|
||||||
|
* it is only declared here to avoid collisions
|
||||||
|
*/
|
||||||
|
type btrfs_tree_block_info struct {
|
||||||
|
key struct {
|
||||||
|
objectid uint64
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
level uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_extent_data_ref struct {
|
||||||
|
root uint64
|
||||||
|
objectid uint64
|
||||||
|
offset uint64
|
||||||
|
count uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_shared_data_ref struct {
|
||||||
|
count uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_extent_inline_ref struct {
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
/* old style backrefs item */
|
||||||
|
type btrfs_extent_ref_v0 struct {
|
||||||
|
root uint64
|
||||||
|
generation uint64
|
||||||
|
objectid uint64
|
||||||
|
count uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dev extents record free space on individual devices. The owner
|
||||||
|
* field points back to the chunk allocation mapping tree that allocated
|
||||||
|
* the extent. The chunk tree uuid field is a way to double check the owner
|
||||||
|
*/
|
||||||
|
type btrfs_dev_extent struct {
|
||||||
|
chunk_tree uint64
|
||||||
|
chunk_objectid uint64
|
||||||
|
chunk_offset uint64
|
||||||
|
length uint64
|
||||||
|
chunk_tree_uuid UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_inode_ref struct {
|
||||||
|
index uint64
|
||||||
|
name_len uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
/* name goes here */
|
||||||
|
type btrfs_inode_extref struct {
|
||||||
|
parent_objectid uint64
|
||||||
|
index uint64
|
||||||
|
name_len uint16
|
||||||
|
//name [0]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
/* name goes here */
|
||||||
|
type btrfs_timespec struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_inode_item struct {
|
||||||
|
generation uint64
|
||||||
|
transid uint64
|
||||||
|
size uint64
|
||||||
|
nbytes uint64
|
||||||
|
block_group uint64
|
||||||
|
nlink uint32
|
||||||
|
uid uint32
|
||||||
|
gid uint32
|
||||||
|
mode uint32
|
||||||
|
rdev uint64
|
||||||
|
flags uint64
|
||||||
|
sequence uint64
|
||||||
|
reserved [4]uint64
|
||||||
|
atime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
ctime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
mtime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
otime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_dir_log_item struct {
|
||||||
|
end uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_dir_item struct {
|
||||||
|
location struct {
|
||||||
|
objectid uint64
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
transid uint64
|
||||||
|
data_len uint16
|
||||||
|
name_len uint16
|
||||||
|
type_ uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal in-memory flag that a subvolume has been marked for deletion but
|
||||||
|
* still visible as a directory
|
||||||
|
*/
|
||||||
|
type btrfs_root_item struct {
|
||||||
|
inode struct {
|
||||||
|
generation uint64
|
||||||
|
transid uint64
|
||||||
|
size uint64
|
||||||
|
nbytes uint64
|
||||||
|
block_group uint64
|
||||||
|
nlink uint32
|
||||||
|
uid uint32
|
||||||
|
gid uint32
|
||||||
|
mode uint32
|
||||||
|
rdev uint64
|
||||||
|
flags uint64
|
||||||
|
sequence uint64
|
||||||
|
reserved [4]uint64
|
||||||
|
atime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
ctime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
mtime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
otime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generation uint64
|
||||||
|
root_dirid uint64
|
||||||
|
bytenr uint64
|
||||||
|
byte_limit uint64
|
||||||
|
bytes_used uint64
|
||||||
|
last_snapshot uint64
|
||||||
|
flags uint64
|
||||||
|
refs uint32
|
||||||
|
drop_progress struct {
|
||||||
|
objectid uint64
|
||||||
|
type_ uint8
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
drop_level uint8
|
||||||
|
level uint8
|
||||||
|
generation_v2 uint64
|
||||||
|
uuid UUID
|
||||||
|
parent_uuid UUID
|
||||||
|
received_uuid UUID
|
||||||
|
ctransid uint64
|
||||||
|
otransid uint64
|
||||||
|
stransid uint64
|
||||||
|
rtransid uint64
|
||||||
|
ctime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
otime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
stime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
rtime struct {
|
||||||
|
sec uint64
|
||||||
|
nsec uint32
|
||||||
|
}
|
||||||
|
reserved [8]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this is used for both forward and backward root refs
|
||||||
|
*/
|
||||||
|
type btrfs_root_ref struct {
|
||||||
|
dirid uint64
|
||||||
|
sequence uint64
|
||||||
|
name_len uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_disk_balance_args struct {
|
||||||
|
profiles uint64
|
||||||
|
usage uint64
|
||||||
|
usage_min uint32
|
||||||
|
usage_max uint32
|
||||||
|
devid uint64
|
||||||
|
pstart uint64
|
||||||
|
pend uint64
|
||||||
|
vstart uint64
|
||||||
|
vend uint64
|
||||||
|
target uint64
|
||||||
|
flags uint64
|
||||||
|
limit uint64
|
||||||
|
limit_min uint32
|
||||||
|
limit_max uint32
|
||||||
|
stripes_min uint32
|
||||||
|
stripes_max uint32
|
||||||
|
unused [6]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* store balance parameters to disk so that balance can be properly
|
||||||
|
* resumed after crash or unmount
|
||||||
|
*/
|
||||||
|
type btrfs_balance_item struct {
|
||||||
|
flags uint64
|
||||||
|
data struct {
|
||||||
|
profiles uint64
|
||||||
|
usage uint64
|
||||||
|
usage_min uint32
|
||||||
|
usage_max uint32
|
||||||
|
devid uint64
|
||||||
|
pstart uint64
|
||||||
|
pend uint64
|
||||||
|
vstart uint64
|
||||||
|
vend uint64
|
||||||
|
target uint64
|
||||||
|
flags uint64
|
||||||
|
limit uint64
|
||||||
|
limit_min uint32
|
||||||
|
limit_max uint32
|
||||||
|
stripes_min uint32
|
||||||
|
stripes_max uint32
|
||||||
|
unused [6]uint64
|
||||||
|
}
|
||||||
|
meta struct {
|
||||||
|
profiles uint64
|
||||||
|
usage uint64
|
||||||
|
usage_min uint32
|
||||||
|
usage_max uint32
|
||||||
|
devid uint64
|
||||||
|
pstart uint64
|
||||||
|
pend uint64
|
||||||
|
vstart uint64
|
||||||
|
vend uint64
|
||||||
|
target uint64
|
||||||
|
flags uint64
|
||||||
|
limit uint64
|
||||||
|
limit_min uint32
|
||||||
|
limit_max uint32
|
||||||
|
stripes_min uint32
|
||||||
|
stripes_max uint32
|
||||||
|
unused [6]uint64
|
||||||
|
}
|
||||||
|
sys struct {
|
||||||
|
profiles uint64
|
||||||
|
usage uint64
|
||||||
|
usage_min uint32
|
||||||
|
usage_max uint32
|
||||||
|
devid uint64
|
||||||
|
pstart uint64
|
||||||
|
pend uint64
|
||||||
|
vstart uint64
|
||||||
|
vend uint64
|
||||||
|
target uint64
|
||||||
|
flags uint64
|
||||||
|
limit uint64
|
||||||
|
limit_min uint32
|
||||||
|
limit_max uint32
|
||||||
|
stripes_min uint32
|
||||||
|
stripes_max uint32
|
||||||
|
unused [6]uint64
|
||||||
|
}
|
||||||
|
unused [4]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_file_extent_item struct {
|
||||||
|
generation uint64
|
||||||
|
ram_bytes uint64
|
||||||
|
compression uint8
|
||||||
|
encryption uint8
|
||||||
|
other_encoding uint16
|
||||||
|
type_ uint8
|
||||||
|
disk_bytenr uint64
|
||||||
|
disk_num_bytes uint64
|
||||||
|
offset uint64
|
||||||
|
num_bytes uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_csum_item struct {
|
||||||
|
csum uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_dev_stats_item struct {
|
||||||
|
values [_BTRFS_DEV_STAT_VALUES_MAX]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_dev_replace_item struct {
|
||||||
|
src_devid uint64
|
||||||
|
cursor_left uint64
|
||||||
|
cursor_right uint64
|
||||||
|
cont_reading_from_srcdev_mode uint64
|
||||||
|
replace_state uint64
|
||||||
|
time_started uint64
|
||||||
|
time_stopped uint64
|
||||||
|
num_write_errors uint64
|
||||||
|
num_uncorrectable_read_errors uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
/* different types of block groups (and chunks) */
|
||||||
|
const (
|
||||||
|
_BTRFS_RAID_RAID10 = iota
|
||||||
|
_BTRFS_RAID_RAID1
|
||||||
|
_BTRFS_RAID_DUP
|
||||||
|
_BTRFS_RAID_RAID0
|
||||||
|
_BTRFS_RAID_SINGLE
|
||||||
|
_BTRFS_RAID_RAID5
|
||||||
|
_BTRFS_RAID_RAID6
|
||||||
|
_BTRFS_NR_RAID_TYPES
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need a bit for restriper to be able to tell when chunks of type
|
||||||
|
* SINGLE are available. This "extended" profile format is used in
|
||||||
|
* fs_info->avail_*_alloc_bits (in-memory) and balance item fields
|
||||||
|
* (on-disk). The corresponding on-disk bit in chunk.type is reserved
|
||||||
|
* to avoid remappings between two formats in future.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A fake block group type that is used to communicate global block reserve
|
||||||
|
* size to userspace via the SPACE_INFO ioctl.
|
||||||
|
*/
|
||||||
|
func chunk_to_extended(flags uint64) uint64 {
|
||||||
|
if flags&uint64(_BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 {
|
||||||
|
flags |= uint64(availAllocBitSingle)
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func extended_to_chunk(flags uint64) uint64 {
|
||||||
|
return flags &^ uint64(availAllocBitSingle)
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_block_group_item struct {
|
||||||
|
used uint64
|
||||||
|
chunk_objectid uint64
|
||||||
|
flags uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_free_space_info struct {
|
||||||
|
extent_count uint32
|
||||||
|
flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func btrfs_qgroup_level(qgroupid uint64) uint64 {
|
||||||
|
return qgroupid >> uint32(qgroupLevelShift)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is subvolume quota turned on?
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RESCAN is set during the initialization phase
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some qgroup entries are known to be out of date,
|
||||||
|
* either because the configuration has changed in a way that
|
||||||
|
* makes a rescan necessary, or because the fs has been mounted
|
||||||
|
* with a non-qgroup-aware version.
|
||||||
|
* Turning qouta off and on again makes it inconsistent, too.
|
||||||
|
*/
|
||||||
|
type btrfs_qgroup_status_item struct {
|
||||||
|
version uint64
|
||||||
|
generation uint64
|
||||||
|
flags uint64
|
||||||
|
rescan uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_qgroup_info_item struct {
|
||||||
|
generation uint64
|
||||||
|
rfer uint64
|
||||||
|
rfer_cmpr uint64
|
||||||
|
excl uint64
|
||||||
|
excl_cmpr uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type btrfs_qgroup_limit_item struct {
|
||||||
|
flags uint64
|
||||||
|
max_rfer uint64
|
||||||
|
max_excl uint64
|
||||||
|
rsv_rfer uint64
|
||||||
|
rsv_excl uint64
|
||||||
|
}
|
@ -44,37 +44,37 @@ const (
|
|||||||
devStatsObjectid = 0
|
devStatsObjectid = 0
|
||||||
|
|
||||||
// For storing balance parameters in the root tree
|
// For storing balance parameters in the root tree
|
||||||
balanceObjectid = 0xfffffffffffffffc /* -4 */
|
balanceObjectid = (1<<64 - 4)
|
||||||
|
|
||||||
// Orhpan objectid for tracking unlinked/truncated files
|
// Orhpan objectid for tracking unlinked/truncated files
|
||||||
orphanObjectid = 0xfffffffffffffffb /* -5 */
|
orphanObjectid = (1<<64 - 5)
|
||||||
|
|
||||||
// Does write ahead logging to speed up fsyncs
|
// Does write ahead logging to speed up fsyncs
|
||||||
treeLogObjectid = 0xfffffffffffffffa /* -6 */
|
treeLogObjectid = (1<<64 - 6)
|
||||||
treeLogFixupObjectid = 0xfffffffffffffff9 /* -7 */
|
treeLogFixupObjectid = (1<<64 - 7)
|
||||||
|
|
||||||
// For space balancing
|
// For space balancing
|
||||||
treeRelocObjectid = 0xfffffffffffffff8 /* -8 */
|
treeRelocObjectid = (1<<64 - 8)
|
||||||
dataRelocTreeObjectid = 0xfffffffffffffff7 /* -9 */
|
dataRelocTreeObjectid = (1<<64 - 9)
|
||||||
|
|
||||||
// Extent checksums all have this objectid
|
// Extent checksums all have this objectid
|
||||||
// this allows them to share the logging tree
|
// this allows them to share the logging tree
|
||||||
// for fsyncs
|
// for fsyncs
|
||||||
extentCsumObjectid = 0xfffffffffffffff6 /* -10 */
|
extentCsumObjectid = (1<<64 - 10)
|
||||||
|
|
||||||
// For storing free space cache
|
// For storing free space cache
|
||||||
freeSpaceObjectid = 0xfffffffffffffff5 /* -11 */
|
freeSpaceObjectid = (1<<64 - 11)
|
||||||
|
|
||||||
// The inode number assigned to the special inode for storing
|
// The inode number assigned to the special inode for storing
|
||||||
// free ino cache
|
// free ino cache
|
||||||
freeInoObjectid = 0xfffffffffffffff4 /* -12 */
|
freeInoObjectid = (1<<64 - 12)
|
||||||
|
|
||||||
// Dummy objectid represents multiple objectids
|
// Dummy objectid represents multiple objectids
|
||||||
multipleObjectids = 0xffffffffffffff01 /* -255 */
|
multipleObjectids = (1<<64 - 255)
|
||||||
|
|
||||||
// All files have objectids in this range.
|
// All files have objectids in this range.
|
||||||
firstFreeObjectid = 256
|
firstFreeObjectid = 256
|
||||||
lastFreeObjectid = 0xffffffffffffff00 /* -256 */
|
lastFreeObjectid = (1<<64 - 256)
|
||||||
firstChunkTreeObjectid = 256
|
firstChunkTreeObjectid = 256
|
||||||
|
|
||||||
// The device items go into the chunk tree. The key is in the form
|
// The device items go into the chunk tree. The key is in the form
|
||||||
@ -135,6 +135,8 @@ const (
|
|||||||
|
|
||||||
extentDataRefKey = 178
|
extentDataRefKey = 178
|
||||||
|
|
||||||
|
extentRefV0Key = 180
|
||||||
|
|
||||||
sharedBlockRefKey = 182
|
sharedBlockRefKey = 182
|
||||||
|
|
||||||
sharedDataRefKey = 184
|
sharedDataRefKey = 184
|
||||||
@ -221,6 +223,7 @@ const (
|
|||||||
csumSize = 32
|
csumSize = 32
|
||||||
|
|
||||||
// Csum types
|
// Csum types
|
||||||
|
csumTypeCrc32 = 0
|
||||||
|
|
||||||
// Flags definitions for directory entry item type
|
// Flags definitions for directory entry item type
|
||||||
// Used by:
|
// Used by:
|
||||||
@ -437,7 +440,12 @@ const (
|
|||||||
blockGroupData = (1 << 0)
|
blockGroupData = (1 << 0)
|
||||||
blockGroupSystem = (1 << 1)
|
blockGroupSystem = (1 << 1)
|
||||||
blockGroupMetadata = (1 << 2)
|
blockGroupMetadata = (1 << 2)
|
||||||
|
blockGroupRaid0 = (1 << 3)
|
||||||
|
blockGroupRaid1 = (1 << 4)
|
||||||
blockGroupDup = (1 << 5)
|
blockGroupDup = (1 << 5)
|
||||||
|
blockGroupRaid10 = (1 << 6)
|
||||||
|
blockGroupRaid5 = (1 << 7)
|
||||||
|
blockGroupRaid6 = (1 << 8)
|
||||||
|
|
||||||
// We need a bit for restriper to be able to tell when chunks of type
|
// We need a bit for restriper to be able to tell when chunks of type
|
||||||
// SINGLE are available. This "extended" profile format is used in
|
// SINGLE are available. This "extended" profile format is used in
|
||||||
|
@ -17,6 +17,7 @@ func init() {
|
|||||||
SubvolumeCmd.AddCommand(
|
SubvolumeCmd.AddCommand(
|
||||||
SubvolumeCreateCmd,
|
SubvolumeCreateCmd,
|
||||||
SubvolumeDeleteCmd,
|
SubvolumeDeleteCmd,
|
||||||
|
SubvolumeListCmd,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +63,23 @@ operation is safely stored on the media.`,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var SubvolumeListCmd = &cobra.Command{
|
||||||
|
Use: "list <mount>",
|
||||||
|
Short: "List subvolumes",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return fmt.Errorf("expected one destination argument")
|
||||||
|
}
|
||||||
|
list, err := btrfs.ListSubVolumes(args[0])
|
||||||
|
if err == nil {
|
||||||
|
for _, v := range list {
|
||||||
|
fmt.Printf("%+v\n", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var SendCmd = &cobra.Command{
|
var SendCmd = &cobra.Command{
|
||||||
Use: "send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
|
Use: "send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
|
||||||
Short: "Send the subvolume(s) to stdout.",
|
Short: "Send the subvolume(s) to stdout.",
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
@ -23,7 +22,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
reDefineIntConst = regexp.MustCompile(`#define\s+([A-Za-z_]+)\s+(\(?-?\d+(?:U?LL)?(?:\s*<<\s*\d+)?\)?)`)
|
reDefineIntConst = regexp.MustCompile(`#define\s+([A-Za-z_][A-Za-z\d_]*)\s+(\(?-?\d+(?:U?LL)?(?:\s*<<\s*\d+)?\)?)`)
|
||||||
reNegULL = regexp.MustCompile(`-(\d+)ULL`)
|
reNegULL = regexp.MustCompile(`-(\d+)ULL`)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -126,11 +125,7 @@ func process(w io.Writer, path string) error {
|
|||||||
name, val := sub[1], sub[2]
|
name, val := sub[1], sub[2]
|
||||||
if sub := reNegULL.FindAllStringSubmatch(val, -1); len(sub) > 0 {
|
if sub := reNegULL.FindAllStringSubmatch(val, -1); len(sub) > 0 {
|
||||||
for _, s := range sub {
|
for _, s := range sub {
|
||||||
v, err := strconv.ParseInt(s[1], 10, 64)
|
val = strings.Replace(val, s[0], fmt.Sprintf("(1<<64 - %s)", s[1]), -1)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
val = strings.Replace(val, s[0], fmt.Sprintf("0x%x /* -%s */", uint64(-v), s[1]), -1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val = strings.Replace(val, "ULL", "", -1)
|
val = strings.Replace(val, "ULL", "", -1)
|
||||||
|
54
ioctl_h.go
54
ioctl_h.go
@ -19,9 +19,31 @@ const (
|
|||||||
UUIDSize = 16
|
UUIDSize = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var zeroUUID UUID
|
||||||
|
|
||||||
type UUID [UUIDSize]byte
|
type UUID [UUIDSize]byte
|
||||||
|
|
||||||
func (id UUID) String() string { return hex.EncodeToString(id[:]) }
|
func (id UUID) String() string {
|
||||||
|
if id == zeroUUID {
|
||||||
|
return "<zero>"
|
||||||
|
}
|
||||||
|
buf := make([]byte, UUIDSize*2+4)
|
||||||
|
i := 0
|
||||||
|
i += hex.Encode(buf[i:], id[:4])
|
||||||
|
buf[i] = '-'
|
||||||
|
i++
|
||||||
|
i += hex.Encode(buf[i:], id[4:6])
|
||||||
|
buf[i] = '-'
|
||||||
|
i++
|
||||||
|
i += hex.Encode(buf[i:], id[6:8])
|
||||||
|
buf[i] = '-'
|
||||||
|
i++
|
||||||
|
i += hex.Encode(buf[i:], id[8:10])
|
||||||
|
buf[i] = '-'
|
||||||
|
i++
|
||||||
|
i += hex.Encode(buf[i:], id[10:])
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
type FSID [FSIDSize]byte
|
type FSID [FSIDSize]byte
|
||||||
|
|
||||||
@ -121,7 +143,7 @@ type btrfs_ioctl_scrub_args struct {
|
|||||||
flags uint64 // in
|
flags uint64 // in
|
||||||
progress btrfs_scrub_progress // out
|
progress btrfs_scrub_progress // out
|
||||||
// pad to 1k
|
// pad to 1k
|
||||||
unused [1024 - 4*8 - unsafe.Sizeof(btrfs_scrub_progress{})]byte
|
_ [1024 - 4*8 - unsafe.Sizeof(btrfs_scrub_progress{})]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type contReadingFromSrcdevMode uint64
|
type contReadingFromSrcdevMode uint64
|
||||||
@ -168,7 +190,7 @@ type btrfs_ioctl_dev_replace_args_u2 struct {
|
|||||||
cmd uint64 // in
|
cmd uint64 // in
|
||||||
result uint64 // out
|
result uint64 // out
|
||||||
status btrfs_ioctl_dev_replace_status_params // out
|
status btrfs_ioctl_dev_replace_status_params // out
|
||||||
unused [unsafe.Sizeof(btrfs_ioctl_dev_replace_start_params{}) - unsafe.Sizeof(btrfs_ioctl_dev_replace_status_params{})]byte
|
_ [unsafe.Sizeof(btrfs_ioctl_dev_replace_start_params{}) - unsafe.Sizeof(btrfs_ioctl_dev_replace_status_params{})]byte
|
||||||
spare [64]uint64
|
spare [64]uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +199,7 @@ type btrfs_ioctl_dev_info_args struct {
|
|||||||
uuid UUID // in/out
|
uuid UUID // in/out
|
||||||
bytes_used uint64 // out
|
bytes_used uint64 // out
|
||||||
total_bytes uint64 // out
|
total_bytes uint64 // out
|
||||||
unused [379]uint64 // pad to 4k
|
_ [379]uint64 // pad to 4k
|
||||||
path [devicePathNameMax]byte // out
|
path [devicePathNameMax]byte // out
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +210,7 @@ type btrfs_ioctl_fs_info_args struct {
|
|||||||
nodesize uint32 // out
|
nodesize uint32 // out
|
||||||
sectorsize uint32 // out
|
sectorsize uint32 // out
|
||||||
clone_alignment uint32 // out
|
clone_alignment uint32 // out
|
||||||
reserved [122*8 + 4]byte // pad to 1k
|
_ [122*8 + 4]byte // pad to 1k
|
||||||
}
|
}
|
||||||
|
|
||||||
type btrfs_ioctl_feature_flags struct {
|
type btrfs_ioctl_feature_flags struct {
|
||||||
@ -231,7 +253,7 @@ type btrfs_balance_args struct {
|
|||||||
limit argRange
|
limit argRange
|
||||||
stripes_min uint32
|
stripes_min uint32
|
||||||
stripes_max uint32
|
stripes_max uint32
|
||||||
unused [48]byte
|
_ [48]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// report balance progress to userspace
|
// report balance progress to userspace
|
||||||
@ -256,7 +278,7 @@ type btrfs_ioctl_balance_args struct {
|
|||||||
meta btrfs_balance_args // in/out
|
meta btrfs_balance_args // in/out
|
||||||
sys btrfs_balance_args // in/out
|
sys btrfs_balance_args // in/out
|
||||||
stat btrfs_balance_progress // out
|
stat btrfs_balance_progress // out
|
||||||
unused [72 * 8]byte // pad to 1k
|
_ [72 * 8]byte // pad to 1k
|
||||||
}
|
}
|
||||||
|
|
||||||
const _BTRFS_INO_LOOKUP_PATH_MAX = 4080
|
const _BTRFS_INO_LOOKUP_PATH_MAX = 4080
|
||||||
@ -283,7 +305,7 @@ type btrfs_ioctl_search_key struct {
|
|||||||
max_type uint32
|
max_type uint32
|
||||||
// how many items did userland ask for, and how many are we returning
|
// how many items did userland ask for, and how many are we returning
|
||||||
nr_items uint32
|
nr_items uint32
|
||||||
unused [36]byte
|
_ [36]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type btrfs_ioctl_search_header struct {
|
type btrfs_ioctl_search_header struct {
|
||||||
@ -347,7 +369,7 @@ type btrfs_ioctl_same_args struct {
|
|||||||
logical_offset uint64 // in - start of extent in source
|
logical_offset uint64 // in - start of extent in source
|
||||||
length uint64 // in - length of extent
|
length uint64 // in - length of extent
|
||||||
dest_count uint16 // in - total elements in info array
|
dest_count uint16 // in - total elements in info array
|
||||||
reserved [6]byte
|
_ [6]byte
|
||||||
//info [0]btrfs_ioctl_same_extent_info
|
//info [0]btrfs_ioctl_same_extent_info
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +386,7 @@ type btrfs_ioctl_defrag_range_args struct {
|
|||||||
// which compression method to use if turning on compression
|
// which compression method to use if turning on compression
|
||||||
// for this defrag operation. If unspecified, zlib will be used
|
// for this defrag operation. If unspecified, zlib will be used
|
||||||
compress_type uint32
|
compress_type uint32
|
||||||
unused [16]byte // spare for later
|
_ [16]byte // spare for later
|
||||||
}
|
}
|
||||||
|
|
||||||
type btrfs_ioctl_space_info struct {
|
type btrfs_ioctl_space_info struct {
|
||||||
@ -390,7 +412,7 @@ type btrfs_data_container struct {
|
|||||||
type btrfs_ioctl_ino_path_args struct {
|
type btrfs_ioctl_ino_path_args struct {
|
||||||
inum uint64 // in
|
inum uint64 // in
|
||||||
size uint64 // in
|
size uint64 // in
|
||||||
reserved [32]byte
|
_ [32]byte
|
||||||
// struct btrfs_data_container *fspath; out
|
// struct btrfs_data_container *fspath; out
|
||||||
fspath uint64 // out
|
fspath uint64 // out
|
||||||
}
|
}
|
||||||
@ -398,7 +420,7 @@ type btrfs_ioctl_ino_path_args struct {
|
|||||||
type btrfs_ioctl_logical_ino_args struct {
|
type btrfs_ioctl_logical_ino_args struct {
|
||||||
logical uint64 // in
|
logical uint64 // in
|
||||||
size uint64 // in
|
size uint64 // in
|
||||||
reserved [32]byte
|
_ [32]byte
|
||||||
// struct btrfs_data_container *inodes; out
|
// struct btrfs_data_container *inodes; out
|
||||||
inodes uint64
|
inodes uint64
|
||||||
}
|
}
|
||||||
@ -428,7 +450,7 @@ type btrfs_ioctl_get_dev_stats struct {
|
|||||||
nr_items uint64 // in/out
|
nr_items uint64 // in/out
|
||||||
flags uint64 // in/out
|
flags uint64 // in/out
|
||||||
values [_BTRFS_DEV_STAT_VALUES_MAX]uint64 // out values
|
values [_BTRFS_DEV_STAT_VALUES_MAX]uint64 // out values
|
||||||
unused [128 - 2 - _BTRFS_DEV_STAT_VALUES_MAX]uint64 // pad to 1k
|
_ [128 - 2 - _BTRFS_DEV_STAT_VALUES_MAX]uint64 // pad to 1k
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -445,7 +467,7 @@ type btrfs_ioctl_quota_ctl_args struct {
|
|||||||
type btrfs_ioctl_quota_rescan_args struct {
|
type btrfs_ioctl_quota_rescan_args struct {
|
||||||
flags uint64
|
flags uint64
|
||||||
progress uint64
|
progress uint64
|
||||||
reserved [6]uint64
|
_ [6]uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type btrfs_ioctl_qgroup_assign_args struct {
|
type btrfs_ioctl_qgroup_assign_args struct {
|
||||||
@ -471,7 +493,7 @@ type btrfs_ioctl_received_subvol_args struct {
|
|||||||
stime btrfs_ioctl_timespec // in
|
stime btrfs_ioctl_timespec // in
|
||||||
rtime btrfs_ioctl_timespec // out
|
rtime btrfs_ioctl_timespec // out
|
||||||
flags uint64 // in
|
flags uint64 // in
|
||||||
reserved [16]uint64 // in
|
_ [16]uint64 // in
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -498,7 +520,7 @@ type btrfs_ioctl_send_args struct {
|
|||||||
clone_sources *uint64 // in
|
clone_sources *uint64 // in
|
||||||
parent_root uint64 // in
|
parent_root uint64 // in
|
||||||
flags uint64 // in
|
flags uint64 // in
|
||||||
reserved [4]uint64 // in
|
_ [4]uint64 // in
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -47,6 +47,10 @@ var caseSizes = []struct {
|
|||||||
{obj: btrfs_ioctl_timespec{}, size: 16},
|
{obj: btrfs_ioctl_timespec{}, size: 16},
|
||||||
{obj: btrfs_ioctl_received_subvol_args{}, size: 200},
|
{obj: btrfs_ioctl_received_subvol_args{}, size: 200},
|
||||||
{obj: btrfs_ioctl_send_args{}, size: 72},
|
{obj: btrfs_ioctl_send_args{}, size: 72},
|
||||||
|
|
||||||
|
//{obj:btrfs_root_ref{},size:18},
|
||||||
|
//{obj:btrfs_root_item{},size:439},
|
||||||
|
//{obj:btrfs_inode_item{},size:160},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSizes(t *testing.T) {
|
func TestSizes(t *testing.T) {
|
122
subvolume.go
122
subvolume.go
@ -6,6 +6,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkSubVolumeName(name string) bool {
|
func checkSubVolumeName(name string) bool {
|
||||||
@ -119,11 +120,13 @@ func SnapshotSubVolume(subvol, dst string, ro bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer fdst.Close()
|
||||||
// TODO: make SnapshotSubVolume a method on FS to use existing fd
|
// TODO: make SnapshotSubVolume a method on FS to use existing fd
|
||||||
f, err := openDir(subvol)
|
f, err := openDir(subvol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
args := btrfs_ioctl_vol_args_v2{
|
args := btrfs_ioctl_vol_args_v2{
|
||||||
fd: int64(f.Fd()),
|
fd: int64(f.Fd()),
|
||||||
}
|
}
|
||||||
@ -139,3 +142,122 @@ func SnapshotSubVolume(subvol, dst string, ro bool) error {
|
|||||||
copy(args.name[:], newName)
|
copy(args.name[:], newName)
|
||||||
return iocSnapCreateV2(fdst, &args)
|
return iocSnapCreateV2(fdst, &args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ListSubVolumes(path string) ([]Subvolume, error) {
|
||||||
|
f, err := openDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
//root, err := getPathRootID(f)
|
||||||
|
//if err != nil {
|
||||||
|
// return nil, fmt.Errorf("can't get rootid for '%s': %v", path, err)
|
||||||
|
//}
|
||||||
|
m, err := listSubVolumes(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out := make([]Subvolume, 0, len(m))
|
||||||
|
for _, v := range m {
|
||||||
|
out = append(out, v)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Subvolume struct {
|
||||||
|
ObjectID uint64
|
||||||
|
TransID uint64
|
||||||
|
Name string
|
||||||
|
RefTree uint64
|
||||||
|
DirID uint64
|
||||||
|
Gen uint64
|
||||||
|
OGen uint64
|
||||||
|
Flags uint64
|
||||||
|
UUID UUID
|
||||||
|
ParentUUID UUID
|
||||||
|
ReceivedUUID UUID
|
||||||
|
OTime time.Time
|
||||||
|
CTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func listSubVolumes(f *os.File) (map[uint64]Subvolume, error) {
|
||||||
|
sk := btrfs_ioctl_search_key{
|
||||||
|
// search in the tree of tree roots
|
||||||
|
tree_id: 1,
|
||||||
|
|
||||||
|
// Set the min and max to backref keys. The search will
|
||||||
|
// only send back this type of key now.
|
||||||
|
min_type: rootBackrefKey,
|
||||||
|
max_type: rootBackrefKey,
|
||||||
|
|
||||||
|
min_objectid: firstFreeObjectid,
|
||||||
|
|
||||||
|
// Set all the other params to the max, we'll take any objectid
|
||||||
|
// and any trans.
|
||||||
|
max_objectid: lastFreeObjectid,
|
||||||
|
max_offset: maxUint64,
|
||||||
|
max_transid: maxUint64,
|
||||||
|
|
||||||
|
nr_items: 4096, // just a big number, doesn't matter much
|
||||||
|
}
|
||||||
|
m := make(map[uint64]Subvolume)
|
||||||
|
for {
|
||||||
|
out, err := treeSearchRaw(f, sk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(out) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, obj := range out {
|
||||||
|
switch obj.Type {
|
||||||
|
case rootBackrefKey:
|
||||||
|
ref := asRootRef(obj.Data)
|
||||||
|
o := m[obj.ObjectID]
|
||||||
|
o.TransID = obj.TransID
|
||||||
|
o.ObjectID = obj.ObjectID
|
||||||
|
o.RefTree = obj.Offset
|
||||||
|
o.DirID = ref.DirID
|
||||||
|
o.Name = ref.Name
|
||||||
|
m[obj.ObjectID] = o
|
||||||
|
case rootItemKey:
|
||||||
|
o := m[obj.ObjectID]
|
||||||
|
o.TransID = obj.TransID
|
||||||
|
o.ObjectID = obj.ObjectID
|
||||||
|
// TODO: decode whole object?
|
||||||
|
o.Gen = asUint64(obj.Data[160:]) // size of btrfs_inode_item
|
||||||
|
o.Flags = asUint64(obj.Data[160+6*8:])
|
||||||
|
const sz = 439
|
||||||
|
const toff = sz - 8*8 - 4*12
|
||||||
|
o.CTime = asTime(obj.Data[toff+0*12:])
|
||||||
|
o.OTime = asTime(obj.Data[toff+1*12:])
|
||||||
|
o.OGen = asUint64(obj.Data[toff-3*8:])
|
||||||
|
const uoff = toff - 4*8 - 3*UUIDSize
|
||||||
|
copy(o.UUID[:], obj.Data[uoff+0*UUIDSize:])
|
||||||
|
copy(o.ParentUUID[:], obj.Data[uoff+1*UUIDSize:])
|
||||||
|
copy(o.ReceivedUUID[:], obj.Data[uoff+2*UUIDSize:])
|
||||||
|
m[obj.ObjectID] = o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// record the mins in key so we can make sure the
|
||||||
|
// next search doesn't repeat this root
|
||||||
|
last := out[len(out)-1]
|
||||||
|
sk.min_objectid = last.ObjectID
|
||||||
|
sk.min_type = last.Type
|
||||||
|
sk.min_offset = last.Offset + 1
|
||||||
|
if sk.min_offset == 0 { // overflow
|
||||||
|
sk.min_type++
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if sk.min_type > rootBackrefKey {
|
||||||
|
sk.min_type = rootItemKey
|
||||||
|
sk.min_objectid++
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if sk.min_objectid > sk.max_objectid {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
33
utils.go
33
utils.go
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isBtrfs(path string) (bool, error) {
|
func isBtrfs(path string) (bool, error) {
|
||||||
@ -35,3 +36,35 @@ func openDir(path string) (*os.File, error) {
|
|||||||
}
|
}
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rawItem struct {
|
||||||
|
TransID uint64
|
||||||
|
ObjectID uint64
|
||||||
|
Type uint32
|
||||||
|
Offset uint64
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func treeSearchRaw(f *os.File, key btrfs_ioctl_search_key) (out []rawItem, _ error) {
|
||||||
|
args := btrfs_ioctl_search_args{
|
||||||
|
key: key,
|
||||||
|
}
|
||||||
|
if err := iocTreeSearch(f, &args); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out = make([]rawItem, 0, args.key.nr_items)
|
||||||
|
buf := args.buf[:]
|
||||||
|
for i := 0; i < int(args.key.nr_items); i++ {
|
||||||
|
h := (*btrfs_ioctl_search_header)(unsafe.Pointer(&buf[0]))
|
||||||
|
buf = buf[unsafe.Sizeof(btrfs_ioctl_search_header{}):]
|
||||||
|
out = append(out, rawItem{
|
||||||
|
TransID: h.transid,
|
||||||
|
ObjectID: h.objectid,
|
||||||
|
Type: h.typ,
|
||||||
|
Offset: h.offset,
|
||||||
|
Data: buf[:h.len], // TODO: reallocate?
|
||||||
|
})
|
||||||
|
buf = buf[h.len:]
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user