Permalink
Browse files
Implement setting received uuid ioctl
When using send/receive, the received subvolume gets some attributes set
right before it's made read only: received_uuid, rtime, rtransid, stime
and stransid. Because receive is user space code, it uses the ioctl to
do so.
* The received_uuid is set to the uuid of the subvolume that was sent.
* rtime and rtransid is set by the kernel code to current time and
generation of the fs.
* stime and stransid are provided by us. The receive code puts the
ctransid value of the sent subvolume into rtransid, and as it seems
never sets the value of stime, so it's always zero.
Having this ioctl available also means we can abuse it ourselves to play
around with it. :]
Here's the struct from the kernel source:
struct btrfs_ioctl_received_subvol_args {
char uuid[BTRFS_UUID_SIZE]; /* in */
__u64 stransid; /* in */
__u64 rtransid; /* out */
struct btrfs_ioctl_timespec stime; /* in */
struct btrfs_ioctl_timespec rtime; /* out */
__u64 flags; /* in */
__u64 reserved[16]; /* in */
};
The flags are not used at all. The ioctl code also does not do strict
checks to make sure that unused fields in the input are all zeroed out.
This means that the flags and reserved space can't be used for anything
in the future without creating an IOC_SET_RECEIVED_SUBVOL_V2... D:
The input to set_received_subvol is:
* an open file descriptor to the subvolume root directory (inode 256)
* the uuid (a python uuid object) we want to have set as received_uuid
* stransid as a number
* stime we want to have set, as a btrfs.ctree.TimeSpec object
Since all objects in the btrfs.ctree module are created from search
ioctl results, there is no nice way to just create new ones from
scratch. For TimeSpec, I started adding this possibility by adding a
factory method called from_values, which initialized a new object based
on the values we want to have for all attributes.
I yolo'ed around a bit with the args structs to keep the amount of lines
of code down.
Also, an example script is added, which shows how to call this new
function.- Loading branch information
Showing
with
76 additions
and 0 deletions.
- +7 −0 btrfs/ctree.py
- +17 −0 btrfs/ioctl.py
- +52 −0 examples/set_received_uuid.py
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/python3 | ||
|
|
||
| import btrfs | ||
| import os | ||
| import sys | ||
| import uuid | ||
|
|
||
| if len(sys.argv) < 5: | ||
| print("Usage: {} <received-uuid> <stransid> <stime> <snapshot>".format(sys.argv[0])) | ||
| print("Example: {} 00000000-1234-5678-90ab-cdef00000000 " | ||
| "31337 1234.5678 /path/to/snapshot".format(sys.argv[0])) | ||
| sys.exit(1) | ||
|
|
||
| received_uuid = uuid.UUID(sys.argv[1]) | ||
| stransid = int(sys.argv[2]) | ||
| stime_sec, stime_nsec = [int(x) for x in sys.argv[3].split('.')] | ||
| stime = btrfs.ctree.TimeSpec.from_values(stime_sec, stime_nsec) | ||
| subvol_path = sys.argv[4] | ||
|
|
||
| inum = os.stat(subvol_path).st_ino | ||
| if inum != 256: | ||
| print("{} is not the start of a subvolume (inum {} != 256)".format(subvol_path, inum)) | ||
| sys.exit(1) | ||
|
|
||
| subvol_fd = os.open(subvol_path, os.O_RDONLY) | ||
| tree, _ = btrfs.ioctl.ino_lookup(subvol_fd) | ||
|
|
||
|
|
||
| def print_subvol_info(root): | ||
| print(" subvol_id: {}".format(root.key.objectid)) | ||
| print(" received_uuid: {}".format(root.received_uuid)) | ||
| print(" stime: {}".format(root.stime)) | ||
| print(" stransid: {}".format(root.stransid)) | ||
| print(" rtime: {}".format(root.rtime)) | ||
| print(" rtransid: {}".format(root.rtransid)) | ||
| print() | ||
|
|
||
|
|
||
| fs = btrfs.FileSystem(subvol_path) | ||
|
|
||
| print("Current subvolume information:") | ||
| root = list(fs.subvolumes(min_id=tree, max_id=tree))[0] | ||
| print_subvol_info(root) | ||
|
|
||
| print("Setting received subvolume...") | ||
| print() | ||
| rtransid, rtime = btrfs.ioctl.set_received_subvol(subvol_fd, received_uuid, stransid, stime) | ||
| os.close(subvol_fd) | ||
|
|
||
| print("Resulting subvolume information:") | ||
| root = list(fs.subvolumes(min_id=tree, max_id=tree))[0] | ||
| print_subvol_info(root) |