get_block_device_harder_fd() currently only traverses one level of
device mapper stacking when looking for the underlying block device.
This causes issues with nested DM setups like dm-crypt on top of
dm-integrity, where we don't traverse enough to get the actual physical
device.
Fix this by iterating through all DM layers until we reach a device with
no underlying device.
Fixes: #40419
Originating device lookups currently use separate entry points and
callers must decide between the single-step helper and manual looping.
Add a recursive flag to block_device_get_originating() and
block_get_originating(), and update callers to pass an explicit value.
udev's block device locking protocol has one pitfall not even the
example in the documentation got right so far (even though this is
explained in all detail above): udev's rescanning is only triggered when
an fd that is opened for writing is closed. This means that if a
separate locking fd is opened on a block device – one that is maintained
independently of the fd actually used for writing – it must be opened for
writing too, so that closing the lock definitely triggers a rescan. This
matters in cases where the lock fd is kept for longer than the fd used
for writing to disk. (Because otherwise udev might get the
IN_CLOSE_WRITE event, but when it tries to rescan will find the device
locked, and never retry because no IN_CLOSE_WRITE is triggred anymore.)
Let's fix that across the codebase, at 4 places:
1. in makefs (a lock fd is kept, and mkfs then invoked as child, which
uses a different fd, and the lock fd is closed only once the child
died)
2. in udevadm lock (embarassing!): which is intended to be used to wrap tools
that modify disk contents, very similar to the makefs case. The lock
is also kept until after the tool exited.
3. In storagetm: the kernel nvme-tcp layer writes to the device
directly, we just keep a lock fd.
4. the example in BLOCK_DEVICE_LOCKING.md
This is a flags type and a flag function argument, let's name it in
plural, because it allows many flags combinations. Internally, the
implementation already used plural, but let's fix the prototypes too.
Let's insist on a string literal in SYS_BLOCK_PATH_MAX() so that
we don't accidentally allocate VLAs and let's inline strempty() in
xsprintf_sys_block_path() so we don't need to include string-util.h
in blockdev-util.h
We'll remove the actual string-util.h include as part of #37344.
We have two typical styles of 'ret' param assignment + retval:
1) < 0 on actual error, 0 on nothing (ret == NULL), > 0 on something
2) recognizable errno on nothing, < 0 on other errors, >= 0 on something
but never use both at the same time.
This code seems to not be used anywhere at all, so let's drop it.
Follow up for ba8d00e859
Follow up for 85686b37b0
Follow up for aff853f8ea
Follow up for 36dad381a2
This function is just a wrapper around the BLKGETSIZE64. Which is a
pretty simple ioctl. The only reason to wrap it, is that the headers we
need to call it are a bit messy (as "linux/fs.h" is incompatible with
certain glibc headers). Hence add the simple helper that wraps it and
allows us to do the header mess needed in one file only.
It's also nicely symmetric to blockdev_get_sector_size().
We already have this nice code in system that determines the block
device backing the root file system, but it's only used internally in
systemd-gpt-generator. Let's make this more accessible and expose it
directly in bootctl.
It doesn't fit immediately into the topic of bootctl, but I think it's
close enough and behaves very similar to the existing "bootctl
--print-boot-path" and "--print-esp-path" tools.
If --print-root-device (or -R) is specified once, will show the block device
backing the root fs, and if specified twice (probably easier: -RR) it
will show the whole block device that block device belongs to in case it
is a partition block device.
Suggested use:
# cfdisk `bootctl -RR`
To get access to the partition table, behind the OS install, for
whatever it might be.
Let's explicitly let btrfs know when we're done using a loop device.
Otherwise, btrfs will keep the device UUID cached which will result
in mount() failures if we ever generate a device or filesystem with
the same UUID again.
-1 was used everywhere, but -EBADF or -EBADFD started being used in various
places. Let's make things consistent in the new style.
Note that there are two candidates:
EBADF 9 Bad file descriptor
EBADFD 77 File descriptor in bad state
Since we're initializating the fd, we're just assigning a value that means
"no fd yet", so it's just a bad file descriptor, and the first errno fits
better. If instead we had a valid file descriptor that became invalid because
of some operation or state change, the other errno would fit better.
In some places, initialization is dropped if unnecessary.
And split out the core logic as block_device_get_originating().
Hopefully, this changes no behavior. Just refactoring and preparation
for later commits.
No functional changes, just refactoring.
Note, this also makes synthesize_change() propagate the error from
synthesize_change_one(). However, the caller of synthesize_change()
ignores the failure anyway, hence the change does not take any effect.