Skip to content

Commit 79979a9

Browse files
committed
ioctl: Add the defrag_range ioctl
1 parent 034fce6 commit 79979a9

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

btrfs/ioctl.py

+67
Original file line numberDiff line numberDiff line change
@@ -1450,3 +1450,70 @@ def get_features(fd):
14501450
fcntl.ioctl(fd, IOC_GET_FEATURES, buf)
14511451
compat_flags, compat_ro_flags, incompat_flags = ioctl_feature_flags.unpack(buf)
14521452
return FeatureFlags(compat_flags, compat_ro_flags, incompat_flags)
1453+
1454+
1455+
DEFRAG_RANGE_COMPRESS = 1 << 0 #: Flag to enable (re)compression functionality
1456+
DEFRAG_RANGE_START_IO = 1 << 1 #: Flag to more quickly start writing back data
1457+
1458+
ioctl_defrag_range_args = struct.Struct('=QQQLL16x')
1459+
IOC_DEFRAG_RANGE = _IOW(BTRFS_IOCTL_MAGIC, 16, ioctl_defrag_range_args)
1460+
1461+
1462+
def defrag_range(fd, start=0, length=ULLONG_MAX, flags=0, extent_thresh=0, compress_type=0):
1463+
"""Call the `BTRFS_IOC_DEFRAG_RANGE` ioctl.
1464+
1465+
Using the defrag_range function, we can:
1466+
1467+
- Defragment (parts of) files (when fd points to a regular file).
1468+
- Defragment subvolume metadata (when fd points to a directory).
1469+
- (Re)compress (parts of) files to a certain compression type.
1470+
1471+
:param int fd: Open file descriptor to a regular file or a directory.
1472+
:param int start: Offset to start the defragmentation at. Defaults
1473+
to 0.
1474+
:param int length: Amount of bytes to defrag, from the start position.
1475+
Defaults to 2**64-1.
1476+
:param int flags: Flags, mainly to activate the (re)compression
1477+
functionality. See below for more information. By default, no flags are
1478+
set.
1479+
:param int extent_thresh: Skip extents larger than this value in bytes.
1480+
Warning: this value might be ignored by kernel code, especially for
1481+
small-ish values. Defaults to 0, which in turn means it will be set to
1482+
the kernel code default value of 256kiB.
1483+
:param int compress_type: Compression type to use when (re)compressing file
1484+
content. Use one of the `COMPRESS_*` values from the
1485+
:class:`btrfs.ctree` module, e.g. `btrfs.ctree.COMPRESS_ZSTD`.
1486+
1487+
Example::
1488+
1489+
>>> # In the first 40MiB of the file, try to combine together all
1490+
>>> # extents that have a length of less than a MiB.
1491+
>>> MiB = 2**20
1492+
>>> fd = os.open('defrag_me', os.O_RDONLY)
1493+
>>> btrfs.ioctl.defrag_range(fd, start=0, length=40*MiB, extent_thresh=MiB)
1494+
1495+
About using defrag to (re)compress file content:
1496+
1497+
- To turn on the (re)compression functionality, provide
1498+
`DEFRAG_RANGE_COMPRESS` as flags. (Internally, this also sets the
1499+
`DEFRAG_RANGE_START_IO` flag and forces extent_thresh to 2**64-1.)
1500+
- Additionally, specify the target type as compression_type.
1501+
- It is not possible to decompress existing compressed data using this
1502+
function. This is because only a compress_type value greater than 0 is
1503+
considered, while the kernel default value is to use ZLIB. IOW, providing
1504+
value 0 selects ZLIB instead.
1505+
1506+
Example::
1507+
1508+
>>> MiB = 2**20
1509+
>>> fd = os.open('compress_me', os.O_RDONLY)
1510+
>>> btrfs.ioctl.defrag_range(fd, start=50*MiB, length=25*MiB,
1511+
... flags=btrfs.ioctl.DEFRAG_RANGE_COMPRESS,
1512+
... compress_type=btrfs.ctree.COMPRESS_ZSTD)
1513+
1514+
Note: the parameter 'length' is called 'len' in kernel code, but 'len' is a
1515+
reserved keyword in Python.
1516+
"""
1517+
args = bytearray(ioctl_defrag_range_args.size)
1518+
ioctl_defrag_range_args.pack_into(args, 0, start, length, flags, extent_thresh, compress_type)
1519+
fcntl.ioctl(fd, IOC_DEFRAG_RANGE, args)

0 commit comments

Comments
 (0)