summaryrefslogtreecommitdiffstats
path: root/src/shared/loop-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-11-04 15:01:33 +0100
committerTopi Miettinen <topimiettinen@users.noreply.github.com>2021-11-05 08:08:16 +0100
commitd7654742eeb808c9a82fcf4ef3591d5cd582190f (patch)
treeb85bb0816cc89aa0e7ab421f27edc89c5f35900e /src/shared/loop-util.c
parentMerge pull request #21229 from keszybz/improve-m-hint (diff)
downloadsystemd-d7654742eeb808c9a82fcf4ef3591d5cd582190f.tar.xz
systemd-d7654742eeb808c9a82fcf4ef3591d5cd582190f.zip
loop-util: reopen device node if we shortcut loop device creation
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
Diffstat (limited to '')
-rw-r--r--src/shared/loop-util.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index 2da101b748..49afa4dac6 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -442,11 +442,16 @@ static int loop_device_make_internal(
_cleanup_close_ int copy = -1;
uint64_t diskseq = 0;
- /* If this is already a block device, store a copy of the fd as it is */
-
- copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ /* If this is already a block device and we are supposed to cover the whole of it
+ * then store an fd to the original open device node — and do not actually create an
+ * unnecessary loopback device for it. Note that we reopen the inode here, instead of
+ * keeping just a dup() clone of it around, since we want to ensure that the O_DIRECT
+ * flag of the handle we keep is off, we have our own file index, and have the right
+ * read/write mode in effect. */
+
+ copy = fd_reopen(fd, open_flags|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
if (copy < 0)
- return -errno;
+ return copy;
r = loop_get_diskseq(copy, &diskseq);
if (r < 0 && r != -EOPNOTSUPP)