Then, this makes loop_device_open_from_fd() or _from_path() be wrappers
of loop_device_open() with block_device_new_from_fd() or _from_path(),
respectively.
When LOOP_CONFIGURE fail, then it is not necessary to call it on any
later call of loop_configure(). Let's save the flag in a static variable
in the function.
This also fixes a leak of lock_fd, which introduced by
7f52206a2b, when fd is for a block device,
and size or offset is non-zero.
Fixes another issue in #24147.
This mirrors what we already do during allocation. We lock the control
device first, and then release the block device and then delete it.
This makes things substantially more robust as long all participants do
such locking: we won't attempt to delete a block device somebody else
already is using.
Back when I wrote this code I wasn't aware of BLKPG and what it can do.
Hence I came up with this hack to attach an empty file to delete all
partitions. But today we can do better with BLKPG: let's just explicitly
remove all partitions, and then try again.
Let's rework how we lock loopback block devices in two ways:
1. Lock a separate fd, instead of the main block device fd. We already
did that for our internal locking when allocating loopback block
devices, but do so for the exposed locking (i.e.
loop_device_flock()), too, so that the lock is independent of the
main fd we actually use of IO.
2. Instead of locking the device during allocation of the loopback
device, then unlocking it (which will make udev run), and then
re-locking things if we need, let's instead just keep the lock the
whole time, to make things a bit safer and faster, and not have to
wait for udev at all. This is done by adding a "lock_op" parameter to
loop device allocation functions that declares the initial state of
the lock, and is one of LOCK_UN/LOCK_SH/LOCK_EX. This change also
shortens a lot of code, since we allocate + immediately lock loopback
devices pretty much everywhere.
Whenever we release a loopback device, let's first synchronously delete
all partitions, so that we know that's complete and not done
asynchronously in the background. Take a BSD lock on the device while
doing so, so that udev won't make the devices busy while we do this.
No actual code changes, just splitting out of some dev_t handling
related calls from stat-util.[ch], they are quite a number already, and
deserve their own module now I think.
Also, try to settle on the name "devnum" as the name for the concept,
instead of "devno" or "dev" or "devid". "devnum" is the name exported in
udev APIs, hence probably best to stick to that. (this just renames a
few symbols to "devum", local variables are left untouched, to make the
patch not too invasive)
No actual code changes.
attach_empty() file takes a BSD file lock on the device, and we really
should release that before going to sleep. hence explicitly close the
block device before the sleep instead of relying on _cleanup_ to close
it after the sleep.
This doesn't really make any real difference, given the file should only
contain a single line. But it's conceptually more correct to just remove
the trailing newline/whitespace then the whole lines coming after that.
i.e. if the file actually contains more lines than one, this should
probably be considered an error.
The LoopDevice object supports a shortcut: if the backing fd we are
supposed to create a loopback device of refers to a
block device alrady then we'll use it as is – if we can – instead of
setting up an unnecessary loopback device that would be pretty much
the same as its backing device.
Previously, when doing this we'd just dup() the original backing fd and
use that. But that's problematic in case O_DIRECT was set on the fd,
since we'll keep that flag set on our copy too, which means we can't do
simple, regular IO on it anymore.
Thus, let's reopen the inode in this case with the exact access flags
we'd apply if we'd actually allocate and open a new loopback device.
Fixes: #21176
The whole reason loop_device_make_internal() exists (as opposed to just
loop_device_make()) is to avoid mangling the loop flags value/call
getenv twice. Hence let's actually call it when we already mangled the
flags value.