Permalink
Browse files
Balance IOCTL
This implements IOC_BALANCE_V2, IOC_BALANCE_CTL and BALANCE_PROGRESS
including a helper for balance parameters and error handling.
BalanceArgs is a helper object that holds all balance parameters for a
single action. Naming is kept close to naming of everything in the
kernel in the balance_args struct.
Here's a simple example that uses a virtual range and a limit:
>>> import btrfs
>>> args = btrfs.ioctl.BalanceArgs(vstart=115993477120,
vend=191155404800, limit_min=2, limit_max=2)
BalanceArgs have __str__ and __repr__:
>>> print(args)
flags(VRANGE|LIMIT_RANGE) vrange=115993477120..191155404800, limit=2..2
>>> args
BalanceArgs(vstart=115993477120, vend=191155404800, limit_min=2,
limit_max=2)
The balance ioctl accepts three of these BalanceArgs at the same time,
one for data, one for metadata and one for the system type.
Let's use data only for now:
>>> fs = btrfs.FileSystem('/')
>>> btrfs.ioctl.balance_v2(fs.fd, data_args=args)
BalanceProgress(state=0x0, expected=2, considered=466, completed=2
Ok fine. we rewrote all data from two data block groups again.
Using balance_ctl, we can pause or cancel a balance. After starting
again in one terminal, we do this in another:
>>> btrfs.ioctl.balance_ctl(fs.fd, btrfs.ioctl.BALANCE_CTL_PAUSE)
Now the balance throws a BalanceError instead of exiting cleanly with a
BalanceProgress as result:
>>> btrfs.ioctl.balance_v2(fs.fd, data_args=args)
[...] # <- pause request happened in between here
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "[...]/python-btrfs/btrfs/ioctl.py", line 569, in balance
raise BalanceError(state, msg) from None
btrfs.ioctl.BalanceError: Balance paused by user
A resume is done by calling balance again, without any BalanceArgs, but
with the resume=True flag:
>>> btrfs.ioctl.balance_v2(fs.fd, resume=True)
We can also ask for progress:
>>> print(btrfs.ioctl.balance_progress(fs.fd))
state RUNNING expected 46 considered 354 completed 0
If any invalid action is done, there will be a BalanceError with
information about it.
>>> btrfs.ioctl.balance_ctl(fs.fd, btrfs.ioctl.BALANCE_CTL_CANCEL)
[...]
btrfs.ioctl.BalanceError: Balance cancel failed: Not in progress (ENOTCONN)
>>> btrfs.ioctl.balance_progress(fs.fd)
[...]
btrfs.ioctl.BalanceError: No balance found (ENOTCONN)
>>> btrfs.ioctl.balance_v2(fs.fd, data_args=args)
[...]
btrfs.ioctl.BalanceError: Balance start failed: Already in progress (EINPROGRESS)
Note 1:
I didn't bother implementing the older USAGE instead of USAGE_RANGE and
LIMIT instead of LIMIT_RANGE, because it involves too much duct taping
structs together using the simple struct module. So, using limit and
range is only supported with kernels (>= 4.4 afaik) that have the RANGE
ones.
Note 2:
When doing resume, and when not doing convert or using a usage filter,
the filters are adjusted in the kernel to skip all chunks that are more
than 90% full, because they are "probably already done".
Also if convert args are active, the soft option is turned on
automatically on resume.
Note 3:
See the code for even more details... :)- Loading branch information
Showing
with
352 additions
and 0 deletions.
- +11 −0 btrfs/ctree.py
- +341 −0 btrfs/ioctl.py