loop: helper to get a loop and bind it

Add a new helper, `loop_for_fd` that will get (or create) an
unbounded loop device, bind it to an fd and then set its
status. Since this is racy and can fail the method does these
steps in a retry-loop.
This commit is contained in:
Christian Kellner 2021-08-03 12:14:02 +00:00 committed by Tom Gundersen
parent 099cfbcea1
commit 3c953ae49d

View file

@ -1,5 +1,6 @@
import contextlib
import ctypes
import errno
import fcntl
import os
import stat
@ -383,3 +384,43 @@ class LoopControl:
self._check_open()
return fcntl.ioctl(self.fd, self.LOOP_CTL_GET_FREE)
def loop_for_fd(self, fd: int, **kwargs):
"""
Get or create an unbound loopback device and bind it to an fd
Getting an unbound loopback device, attaching a backing file
descriptor and setting the loop device status is racy so this
method will retry until it succeeds or it fails to get an
unbound loop device.
All given keyword arguments are forwarded to `Loop.set_status`.
"""
self._check_open()
if fd < 0:
raise ValueError(f"Invalid file descriptor '{fd}'")
while True:
lo = Loop(self.get_unbound())
try:
lo.set_fd(fd)
except OSError as e:
lo.close()
if e.errno == errno.EBUSY:
continue
raise e
# `set_status` returns EBUSY when the pages from the
# previously bound file have not been fully cleared yet.
try:
lo.set_status(**kwargs)
except BlockingIOError:
lo.clear_fd()
lo.close()
continue
break
return lo