Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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) |