Compare commits
No commits in common. "c53da7ed02a5d732c9449f79c19675b90a6032e3" and "96a4ce9f1d4fe5e28dfe04d5002b6e1b04338b67" have entirely different histories.
c53da7ed02
...
96a4ce9f1d
3
TODO
3
TODO
|
@ -20,6 +20,9 @@ Features:
|
||||||
* make use of the new statx mountid and rootmount fields in path_get_mnt_id()
|
* make use of the new statx mountid and rootmount fields in path_get_mnt_id()
|
||||||
and fd_is_mount_point()
|
and fd_is_mount_point()
|
||||||
|
|
||||||
|
* make use of new loopback setup ioctl to setup loopback devices in one atomic
|
||||||
|
ioctl
|
||||||
|
|
||||||
* nspawn: move "incoming mount" directory to /run/host, move "inaccessible"
|
* nspawn: move "incoming mount" directory to /run/host, move "inaccessible"
|
||||||
nodes to /run/host, move notify socket (for sd_notify() between payload and
|
nodes to /run/host, move notify socket (for sd_notify() between payload and
|
||||||
container manager)
|
container manager)
|
||||||
|
|
|
@ -217,7 +217,7 @@
|
||||||
this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
|
this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
|
||||||
below) should be set to open access to the notification socket provided by systemd. If
|
below) should be set to open access to the notification socket provided by systemd. If
|
||||||
<varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
|
<varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
|
||||||
<option>main</option>.</para></listitem>
|
<option>main</option></para></listitem>.
|
||||||
|
|
||||||
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
|
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
|
||||||
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
|
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
|
||||||
|
|
|
@ -214,40 +214,3 @@ int lock_whole_block_device(dev_t devt, int operation) {
|
||||||
|
|
||||||
return TAKE_FD(lock_fd);
|
return TAKE_FD(lock_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockdev_partscan_enabled(int fd) {
|
|
||||||
_cleanup_free_ char *p = NULL, *buf = NULL;
|
|
||||||
unsigned long long ull;
|
|
||||||
struct stat st;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* Checks if partition scanning is correctly enabled on the block device */
|
|
||||||
|
|
||||||
if (fstat(fd, &st) < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
if (!S_ISBLK(st.st_mode))
|
|
||||||
return -ENOTBLK;
|
|
||||||
|
|
||||||
if (asprintf(&p, "/sys/dev/block/%u:%u/capability", major(st.st_rdev), minor(st.st_rdev)) < 0)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
r = read_one_line_file(p, &buf);
|
|
||||||
if (r == -ENOENT) /* If the capability file doesn't exist then we are most likely looking at a
|
|
||||||
* partition block device, not the whole block device. And that means we have no
|
|
||||||
* partition scanning on for it (we do for its parent, but not for the partition
|
|
||||||
* itself). */
|
|
||||||
return false;
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = safe_atollu_full(buf, 16, &ull);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
#ifndef GENHD_FL_NO_PART_SCAN
|
|
||||||
#define GENHD_FL_NO_PART_SCAN (0x0200)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return !FLAGS_SET(ull, GENHD_FL_NO_PART_SCAN);
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,5 +20,3 @@ int get_block_device(const char *path, dev_t *dev);
|
||||||
int get_block_device_harder(const char *path, dev_t *dev);
|
int get_block_device_harder(const char *path, dev_t *dev);
|
||||||
|
|
||||||
int lock_whole_block_device(dev_t devt, int operation);
|
int lock_whole_block_device(dev_t devt, int operation);
|
||||||
|
|
||||||
int blockdev_partscan_enabled(int fd);
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <linux/loop.h>
|
|
||||||
|
|
||||||
#ifndef LOOP_CONFIGURE
|
|
||||||
struct loop_config {
|
|
||||||
__u32 fd;
|
|
||||||
__u32 block_size;
|
|
||||||
struct loop_info64 info;
|
|
||||||
__u64 __reserved[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LOOP_CONFIGURE 0x4C0A
|
|
||||||
#endif
|
|
|
@ -215,18 +215,22 @@ static int wait_for_partitions_to_appear(
|
||||||
break;
|
break;
|
||||||
r = -errno;
|
r = -errno;
|
||||||
if (r == -EINVAL) {
|
if (r == -EINVAL) {
|
||||||
/* If we are running on a block device that has partition scanning off, return an
|
struct loop_info64 info;
|
||||||
* explicit recognizable error about this, so that callers can generate a proper
|
|
||||||
* message explaining the situation. */
|
|
||||||
|
|
||||||
r = blockdev_partscan_enabled(fd);
|
/* If we are running on a loop device that has partition scanning off, return
|
||||||
if (r < 0)
|
* an explicit recognizable error about this, so that callers can generate a
|
||||||
return r;
|
* proper message explaining the situation. */
|
||||||
if (r == 0)
|
|
||||||
|
if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0) {
|
||||||
|
#if HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
/* Valgrind currently doesn't know LOOP_GET_STATUS64. Remove this once it does */
|
||||||
|
VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((info.lo_flags & LO_FLAGS_PARTSCAN) == 0)
|
||||||
return log_debug_errno(EPROTONOSUPPORT,
|
return log_debug_errno(EPROTONOSUPPORT,
|
||||||
"Device is a loop device and partition scanning is off!");
|
"Device is a loop device and partition scanning is off!");
|
||||||
|
}
|
||||||
return -EINVAL; /* original error */
|
|
||||||
}
|
}
|
||||||
if (r != -EBUSY)
|
if (r != -EBUSY)
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -14,68 +14,20 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "blockdev-util.h"
|
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "loop-util.h"
|
#include "loop-util.h"
|
||||||
#include "missing_loop.h"
|
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
static void cleanup_clear_loop_close(int *fd) {
|
static void cleanup_clear_loop_close(int *fd) {
|
||||||
if (*fd < 0)
|
if (*fd >= 0) {
|
||||||
return;
|
|
||||||
|
|
||||||
(void) ioctl(*fd, LOOP_CLR_FD);
|
(void) ioctl(*fd, LOOP_CLR_FD);
|
||||||
(void) safe_close(*fd);
|
(void) safe_close(*fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int loop_configure(int fd, const struct loop_config *c) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(fd >= 0);
|
|
||||||
assert(c);
|
|
||||||
|
|
||||||
if (ioctl(fd, LOOP_CONFIGURE, c) < 0) {
|
|
||||||
/* Do fallback only if LOOP_CONFIGURE is not supported, propagate all other errors. Note that
|
|
||||||
* the kernel is weird: non-existing ioctls currently return EINVAL rather than ENOTTY on
|
|
||||||
* loopback block devices. They should fix that in the kernel, but in the meantime we accept
|
|
||||||
* both here. */
|
|
||||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
|
|
||||||
return -errno;
|
|
||||||
} else {
|
|
||||||
if (!FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Kernel 5.8 vanilla doesn't properly propagate the partition scanning flag into the
|
|
||||||
* block device. Let's hence verify if things work correctly here before returning. */
|
|
||||||
|
|
||||||
r = blockdev_partscan_enabled(fd);
|
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
if (r > 0)
|
|
||||||
return 0; /* All is good. */
|
|
||||||
|
|
||||||
/* Otherwise, undo the attachment and use the old APIs */
|
|
||||||
(void) ioctl(fd, LOOP_CLR_FD);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(fd, LOOP_SET_FD, c->fd) < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
if (ioctl(fd, LOOP_SET_STATUS64, &c->info) < 0) {
|
|
||||||
r = -errno;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
(void) ioctl(fd, LOOP_CLR_FD);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int loop_device_make(
|
int loop_device_make(
|
||||||
|
@ -87,7 +39,7 @@ int loop_device_make(
|
||||||
LoopDevice **ret) {
|
LoopDevice **ret) {
|
||||||
|
|
||||||
_cleanup_free_ char *loopdev = NULL;
|
_cleanup_free_ char *loopdev = NULL;
|
||||||
struct loop_config config;
|
struct loop_info64 info;
|
||||||
LoopDevice *d = NULL;
|
LoopDevice *d = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int nr = -1, r;
|
int nr = -1, r;
|
||||||
|
@ -100,14 +52,14 @@ int loop_device_make(
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (S_ISBLK(st.st_mode)) {
|
if (S_ISBLK(st.st_mode)) {
|
||||||
if (ioctl(fd, LOOP_GET_STATUS64, &config.info) >= 0) {
|
if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0) {
|
||||||
/* Oh! This is a loopback device? That's interesting! */
|
/* Oh! This is a loopback device? That's interesting! */
|
||||||
|
|
||||||
#if HAVE_VALGRIND_MEMCHECK_H
|
#if HAVE_VALGRIND_MEMCHECK_H
|
||||||
/* Valgrind currently doesn't know LOOP_GET_STATUS64. Remove this once it does */
|
/* Valgrind currently doesn't know LOOP_GET_STATUS64. Remove this once it does */
|
||||||
VALGRIND_MAKE_MEM_DEFINED(&config.info, sizeof(config.info));
|
VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info));
|
||||||
#endif
|
#endif
|
||||||
nr = config.info.lo_number;
|
nr = info.lo_number;
|
||||||
|
|
||||||
if (asprintf(&loopdev, "/dev/loop%i", nr) < 0)
|
if (asprintf(&loopdev, "/dev/loop%i", nr) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -148,16 +100,6 @@ int loop_device_make(
|
||||||
if (control < 0)
|
if (control < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
config = (struct loop_config) {
|
|
||||||
.fd = fd,
|
|
||||||
.info = {
|
|
||||||
/* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
|
|
||||||
.lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((loop_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
|
|
||||||
.lo_offset = offset,
|
|
||||||
.lo_sizelimit = size == UINT64_MAX ? 0 : size,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Loop around LOOP_CTL_GET_FREE, since at the moment we attempt to open the returned device it might
|
/* Loop around LOOP_CTL_GET_FREE, since at the moment we attempt to open the returned device it might
|
||||||
* be gone already, taken by somebody else racing against us. */
|
* be gone already, taken by somebody else racing against us. */
|
||||||
for (unsigned n_attempts = 0;;) {
|
for (unsigned n_attempts = 0;;) {
|
||||||
|
@ -177,13 +119,12 @@ int loop_device_make(
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
} else {
|
} else {
|
||||||
r = loop_configure(loop, &config);
|
if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
|
||||||
if (r >= 0) {
|
|
||||||
loop_with_fd = TAKE_FD(loop);
|
loop_with_fd = TAKE_FD(loop);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (r != -EBUSY)
|
if (errno != EBUSY)
|
||||||
return r;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++n_attempts >= 64) /* Give up eventually */
|
if (++n_attempts >= 64) /* Give up eventually */
|
||||||
|
@ -192,6 +133,16 @@ int loop_device_make(
|
||||||
loopdev = mfree(loopdev);
|
loopdev = mfree(loopdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info = (struct loop_info64) {
|
||||||
|
/* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
|
||||||
|
.lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((loop_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
|
||||||
|
.lo_offset = offset,
|
||||||
|
.lo_sizelimit = size == UINT64_MAX ? 0 : size,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ioctl(loop_with_fd, LOOP_SET_STATUS64, &info) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
d = new(LoopDevice, 1);
|
d = new(LoopDevice, 1);
|
||||||
if (!d)
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
Loading…
Reference in New Issue