1
0
mirror of https://github.com/systemd/systemd synced 2025-11-19 16:54:46 +01:00

Compare commits

..

No commits in common. "cc7ccd3c6a2be9203057f81be4ef55e94b2ab85c" and "d62ab43fd0ddb077514f8294ac5345d78e1a7ef3" have entirely different histories.

22 changed files with 103 additions and 775 deletions

View File

@ -223,12 +223,11 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
// try to take an exclusive and nonblocking BSD lock (use O_WRONLY mode to ensure udev
// rescans the device once the lock is closed)
// try to take an exclusive and nonblocking BSD lock
__attribute__((cleanup(closep))) int fd =
lock_whole_disk_from_devname(
argv[1],
O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY,
O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY,
LOCK_EX|LOCK_NB);
if (fd < 0)

View File

@ -215,8 +215,7 @@
<term><varname>Multicast=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, the multicast flag on the device is enabled. Defaults
to unset and the flag is unchanged. When disabled, <varname>IPv6AcceptRA=</varname> and
<varname>IPv6SendRA=</varname> cannot be enabled.</para>
to unset.</para>
<xi:include href="version-info.xml" xpointer="v239"/>
</listitem>
@ -943,19 +942,10 @@ DuplicateAddressDetection=none</programlisting></para>
<para>Takes a boolean. Controls IPv6 Router Advertisement (RA) reception support for the interface.
If true, RAs are accepted; if false, RAs are ignored. When RAs are accepted, they may trigger the
start of the DHCPv6 client if the relevant flags are set in the RA data, or if no routers are found
on the link.</para>
<para>This cannot be enabled on devices aggregated in a bond device, or when IPv6 link-local
addressing (see <varname>LinkLocalAddressing=</varname>) or multicasting (see
<varname>Multicast=</varname>) is disabled. Note, multicasting is disabled by default for some
configurations, e.g. bridge ports. Hence, in that case <varname>Multicast=</varname> needs to be
explicitly enabled to make this feature usable. When <varname>IPv6SendRA=</varname>,
<varname>IPv6Forwarding=</varname>, or <varname>IPMasquerade=</varname> is enabled, this feature is
disabled by default, but can be overridden by explicitly enabling this setting. Note,
<varname>IPv6Forwarding=</varname> may be indirectly enabled when the global setting with the same
name is enabled, or when <varname>IPMasquerade=</varname> is enabled on <emphasis>any other
interfaces</emphasis>. See also <varname>IPv6Forwarding=</varname> and
<varname>IPMasquerade=</varname> for more details. Enabled by default otherwise.</para>
on the link. Defaults to false for bridge devices, when <varname>IPv6Forwarding=</varname>,
<varname>IPv6SendRA=</varname>, or <varname>KeepMaster=</varname> is enabled. Otherwise, enabled by
default. Cannot be enabled on devices aggregated in a bond device or when link-local addressing is
disabled.</para>
<para>Further settings for the IPv6 RA support may be configured in the [IPv6AcceptRA]
section, see below.</para>

View File

@ -41,7 +41,7 @@ static int run(int argc, char *argv[]) {
if (S_ISBLK(st.st_mode)) {
/* Lock the device so that udev doesn't interfere with our work */
lock_fd = lock_whole_block_device(st.st_rdev, O_WRONLY, LOCK_EX);
lock_fd = lock_whole_block_device(st.st_rdev, LOCK_EX);
if (lock_fd < 0)
return log_error_errno(lock_fd, "Failed to lock whole block device of \"%s\": %m", device);
} else

View File

@ -53,7 +53,6 @@
#include "path-util.h"
#include "process-util.h"
#include "random-util.h"
#include "reread-partition-table.h"
#include "resize-fs.h"
#include "string-util.h"
#include "strv.h"
@ -2498,7 +2497,7 @@ int home_create_luks(
if (disk_uuid_path)
/* Reread partition table if this is a block device */
(void) reread_partition_table_fd(setup->image_fd, /* flags= */ 0);
(void) ioctl(setup->image_fd, BLKRRPART, 0);
else {
assert(setup->temporary_image_path);
@ -3470,8 +3469,8 @@ int home_resize_luks(
if (r > 0)
log_info("Growing of partition completed.");
if (S_ISBLK(st.st_mode))
(void) reread_partition_table_fd(image_fd, /* flags= */ 0);
if (S_ISBLK(st.st_mode) && ioctl(image_fd, BLKRRPART, 0) < 0)
log_debug_errno(errno, "BLKRRPART failed on block device, ignoring: %m");
/* Tell LUKS about the new bigger size too */
r = sym_crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512U);
@ -3570,8 +3569,8 @@ int home_resize_luks(
if (r > 0)
log_info("Shrinking of partition completed.");
if (S_ISBLK(st.st_mode))
(void) reread_partition_table_fd(image_fd, /* flags= */ 0);
if (S_ISBLK(st.st_mode) && ioctl(image_fd, BLKRRPART, 0) < 0)
log_debug_errno(errno, "BLKRRPART failed on block device, ignoring: %m");
} else { /* → Grow */
if (!FLAGS_SET(flags, HOME_SETUP_RESIZE_DONT_SYNC_IDENTITIES)) {

View File

@ -713,7 +713,7 @@ int sd_lldp_tx_describe(sd_lldp_tx *lldp_tx, sd_json_variant **ret) {
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR_ID128("ChassisID", machine_id),
SD_JSON_BUILD_PAIR_STRING("ChassisID", SD_ID128_TO_STRING(machine_id)),
SD_JSON_BUILD_PAIR_BYTE_ARRAY("RawChassisID", chassis_id, chassis_id_len),
SD_JSON_BUILD_PAIR_STRING("PortID", lldp_tx->ifname),
SD_JSON_BUILD_PAIR_BYTE_ARRAY("RawPortID", port_id, port_id_len),

View File

@ -14,7 +14,6 @@ int device_opendir(sd_device *device, const char *subdir, DIR **ret);
int device_get_sysnum_unsigned(sd_device *device, unsigned *ret);
int device_get_property_bool(sd_device *device, const char *key);
int device_get_property_int(sd_device *device, const char *key, int *ret);
int device_get_property_uint(sd_device *device, const char *key, unsigned *ret);
int device_get_ifname(sd_device *device, const char **ret);
int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value);
int device_get_sysattr_unsigned_full(sd_device *device, const char *sysattr, unsigned base, unsigned *ret_value);

View File

@ -2319,27 +2319,6 @@ int device_get_property_int(sd_device *device, const char *key, int *ret) {
return 0;
}
int device_get_property_uint(sd_device *device, const char *key, unsigned *ret) {
const char *value;
int r;
assert(device);
assert(key);
r = sd_device_get_property_value(device, key, &value);
if (r < 0)
return r;
unsigned v;
r = safe_atou(value, &v);
if (r < 0)
return r;
if (ret)
*ret = v;
return 0;
}
_public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
const char *s;
sd_id128_t id;

View File

@ -65,7 +65,6 @@
#include "process-util.h"
#include "random-util.h"
#include "ratelimit.h"
#include "reread-partition-table.h"
#include "resize-fs.h"
#include "rm-rf.h"
#include "set.h"
@ -856,16 +855,6 @@ static Context* context_free(Context *context) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Context*, context_free);
static void context_disarm_auto_removal(Context *context) {
assert(context);
/* Make sure automatic removal of half-written artifacts is disarmed */
context->node = mfree(context->node);
LIST_FOREACH(partitions, p, context->partitions)
p->split_path = mfree(p->split_path);
}
static int context_add_free_area(
Context *context,
uint64_t size,
@ -7271,8 +7260,12 @@ static int context_write_partition_table(Context *context) {
else if (capable < 0)
return log_error_errno(capable, "Failed to check if block device supports partition scanning: %m");
else if (capable > 0) {
log_info("Informing kernel about changed partitions...");
r = reread_partition_table_fd(fdisk_get_devfd(context->fdisk_context), /* flags= */ 0);
log_info("Telling kernel to reread partition table.");
if (context->from_scratch)
r = fdisk_reread_partition_table(context->fdisk_context);
else
r = fdisk_reread_changes(context->fdisk_context, original_table);
if (r < 0)
return log_error_errno(r, "Failed to reread partition table: %m");
} else
@ -10184,7 +10177,10 @@ static int run(int argc, char *argv[]) {
(void) context_dump(context, /*late=*/ true);
context_disarm_auto_removal(context);
context->node = mfree(context->node);
LIST_FOREACH(partitions, p, context->partitions)
p->split_path = mfree(p->split_path);
return 0;
}

View File

@ -24,7 +24,7 @@
#include "path-util.h"
#include "string-util.h"
static int fd_get_devnum(int fd, BlockDeviceLookupFlags flags, dev_t *ret) {
static int fd_get_devnum(int fd, BlockDeviceLookupFlag flags, dev_t *ret) {
struct stat st;
dev_t devnum;
int r;
@ -148,7 +148,7 @@ int block_device_get_originating(sd_device *dev, sd_device **ret) {
return 0;
}
int block_device_new_from_fd(int fd, BlockDeviceLookupFlags flags, sd_device **ret) {
int block_device_new_from_fd(int fd, BlockDeviceLookupFlag flags, sd_device **ret) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
dev_t devnum;
int r;
@ -194,7 +194,7 @@ int block_device_new_from_fd(int fd, BlockDeviceLookupFlags flags, sd_device **r
return 0;
}
int block_device_new_from_path(const char *path, BlockDeviceLookupFlags flags, sd_device **ret) {
int block_device_new_from_path(const char *path, BlockDeviceLookupFlag flags, sd_device **ret) {
_cleanup_close_ int fd = -EBADF;
assert(path);
@ -340,24 +340,20 @@ int get_block_device_harder(const char *path, dev_t *ret) {
return get_block_device_harder_fd(fd, ret);
}
int lock_whole_block_device(dev_t devt, int open_flags, int operation) {
int lock_whole_block_device(dev_t devt, int operation) {
_cleanup_close_ int lock_fd = -EBADF;
dev_t whole_devt;
int r;
/* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING
*
* NB: it matters whether open_flags indicates open for write: only then will the eventual closing of
* the fd trigger udev's partitioning rescanning of the device (as it watches for IN_CLOSE_WRITE),
* hence make sure to pass the right value there. */
/* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
r = block_get_whole_disk(devt, &whole_devt);
if (r < 0)
return r;
lock_fd = device_open_from_devnum(S_IFBLK, whole_devt, open_flags|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, NULL);
if (lock_fd < 0)
return lock_fd;
lock_fd = r = device_open_from_devnum(S_IFBLK, whole_devt, O_RDONLY|O_CLOEXEC|O_NONBLOCK, NULL);
if (r < 0)
return r;
if (flock(lock_fd, operation) < 0)
return -errno;
@ -418,12 +414,6 @@ int blockdev_partscan_enabled(sd_device *dev) {
assert(dev);
r = device_in_subsystem(dev, "block");
if (r < 0)
return r;
if (r == 0)
return -ENOTBLK;
/* For v6.10 or newer. */
r = device_get_sysattr_bool(dev, "partscan");
if (r != -ENOENT)
@ -808,6 +798,27 @@ int block_device_remove_all_partitions(sd_device *dev, int fd) {
return k < 0 ? k : has_partitions;
}
int blockdev_reread_partition_table(sd_device *dev) {
_cleanup_close_ int fd = -EBADF;
assert(dev);
/* Try to re-read the partition table. This only succeeds if none of the devices is busy. */
fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
return fd;
if (flock(fd, LOCK_EX|LOCK_NB) < 0)
return -errno;
if (ioctl(fd, BLKRRPART, 0) < 0)
return -errno;
return 0;
}
int blockdev_get_sector_size(int fd, uint32_t *ret) {
int ssz = 0;
@ -887,46 +898,3 @@ int blockdev_get_root(int level, dev_t *ret) {
return 1;
}
int partition_node_of(const char *node, unsigned nr, char **ret) {
int r;
assert(node);
assert(nr > 0);
assert(ret);
/* Given a device node path to a block device returns the device node path to the partition block
* device of the specified partition */
_cleanup_free_ char *fn = NULL;
r = path_extract_filename(node, &fn);
if (r < 0)
return r;
if (r == O_DIRECTORY)
return -EISDIR;
_cleanup_free_ char *dn = NULL;
r = path_extract_directory(node, &dn);
if (r < 0 && r != -EDESTADDRREQ) /* allow if only filename is specified */
return r;
size_t l = strlen(fn);
assert(l > 0); /* underflow check for the subtraction below */
bool need_p = ascii_isdigit(fn[l-1]); /* Last char a digit? */
_cleanup_free_ char *subnode = NULL;
if (asprintf(&subnode, "%s%s%u", fn, need_p ? "p" : "", nr) < 0)
return -ENOMEM;
if (dn) {
_cleanup_free_ char *j = path_join(dn, subnode);
if (!j)
return -ENOMEM;
*ret = TAKE_PTR(j);
} else
*ret = TAKE_PTR(subnode);
return 0;
}

View File

@ -11,16 +11,16 @@
#define xsprintf_sys_block_path(buf, suffix, devno) \
xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), suffix ?: "")
typedef enum BlockDeviceLookupFlags {
typedef enum BlockDeviceLookupFlag {
BLOCK_DEVICE_LOOKUP_WHOLE_DISK = 1 << 0, /* whole block device, e.g. sda, nvme0n1, or loop0. */
BLOCK_DEVICE_LOOKUP_BACKING = 1 << 1, /* fd may be regular file or directory on file system, in
* which case backing block device is determined. */
BLOCK_DEVICE_LOOKUP_ORIGINATING = 1 << 2, /* Try to find the underlying layer device for stacked
* block device, e.g. LUKS-style DM. */
} BlockDeviceLookupFlags;
} BlockDeviceLookupFlag;
int block_device_new_from_fd(int fd, BlockDeviceLookupFlags flags, sd_device **ret);
int block_device_new_from_path(const char *path, BlockDeviceLookupFlags flags, sd_device **ret);
int block_device_new_from_fd(int fd, BlockDeviceLookupFlag flag, sd_device **ret);
int block_device_new_from_path(const char *path, BlockDeviceLookupFlag flag, sd_device **ret);
int block_device_is_whole_disk(sd_device *dev);
int block_device_get_whole_disk(sd_device *dev, sd_device **ret);
@ -35,7 +35,7 @@ int get_block_device(const char *path, dev_t *dev);
int get_block_device_harder_fd(int fd, dev_t *dev);
int get_block_device_harder(const char *path, dev_t *dev);
int lock_whole_block_device(dev_t devt, int open_flags, int operation);
int lock_whole_block_device(dev_t devt, int operation);
int blockdev_partscan_enabled(sd_device *d);
int blockdev_partscan_enabled_fd(int fd);
@ -51,10 +51,9 @@ int block_device_remove_partition(int fd, const char *name, int nr);
int block_device_resize_partition(int fd, int nr, uint64_t start, uint64_t size);
int partition_enumerator_new(sd_device *dev, sd_device_enumerator **ret);
int block_device_remove_all_partitions(sd_device *dev, int fd);
int blockdev_reread_partition_table(sd_device *dev);
int blockdev_get_sector_size(int fd, uint32_t *ret);
int blockdev_get_device_size(int fd, uint64_t *ret);
int blockdev_get_root(int level, dev_t *ret);
int partition_node_of(const char *node, unsigned nr, char **ret);

View File

@ -70,12 +70,12 @@ int bus_property_get_id128(
void *userdata,
sd_bus_error *reterr_error) {
sd_id128_t *id = ASSERT_PTR(userdata);
sd_id128_t *id = userdata;
if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
return sd_bus_message_append(reply, "ay", 0);
return sd_bus_message_append_array(reply, 'y', id->bytes, sizeof(sd_id128_t));
else
return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
}
#if __SIZEOF_SIZE_T__ != 8

View File

@ -627,9 +627,14 @@ static int make_partition_devname(
if (!s)
return -ENOMEM;
} else {
r = partition_node_of(whole_devname, nr, &s);
if (r < 0)
return r;
size_t l = strlen(whole_devname);
if (l < 1) /* underflow check for the subtraction below */
return -EINVAL;
bool need_p = ascii_isdigit(whole_devname[l-1]); /* Last char a digit? */
if (asprintf(&s, "%s%s%i", whole_devname, need_p ? "p" : "", nr) < 0)
return -ENOMEM;
}
} else {
if (nr < 0) /* whole disk? */

View File

@ -167,7 +167,6 @@ shared_sources = files(
'quota-util.c',
'reboot-util.c',
'recovery-key.c',
'reread-partition-table.c',
'resize-fs.c',
'resolve-util.c',
'rm-rf.c',

View File

@ -1,396 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/fs.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include "sd-device.h"
#include "alloc-util.h"
#include "blkid-util.h"
#include "blockdev-util.h"
#include "device-private.h"
#include "device-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "log.h"
#include "parse-util.h"
#include "reread-partition-table.h"
#include "set.h"
#include "string-util.h"
static int trigger_partitions(sd_device *dev, bool blkrrpart_success) {
int ret = 0, r;
assert(dev);
/* search for partitions */
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
r = partition_enumerator_new(dev, &e);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to initialize partition enumerator: %m");
/* We have partitions and re-read the table, the kernel already sent out a "change"
* event for the disk, and "remove/add" for all partitions. */
if (blkrrpart_success && sd_device_enumerator_get_device_first(e))
return 0;
/* We have partitions but re-reading the partition table did not work, synthesize
* "change" for the disk and all partitions. */
r = sd_device_trigger(dev, SD_DEVICE_CHANGE);
if (r < 0)
RET_GATHER(ret, log_device_debug_errno(dev, r, "Failed to trigger 'change' uevent, proceeding: %m"));
FOREACH_DEVICE(e, d) {
r = sd_device_trigger(d, SD_DEVICE_CHANGE);
if (r < 0)
RET_GATHER(ret, log_device_debug_errno(d, r, "Failed to trigger 'change' uevent, proceeding: %m"));
}
return ret;
}
static int fallback_ioctl(sd_device *d, int fd, RereadPartitionTableFlags flags) {
int r;
assert(d);
assert(fd >= 0);
r = RET_NERRNO(ioctl(fd, BLKRRPART, 0));
if (r < 0)
log_device_debug_errno(d, r, "Failed to reread partition table via BLKRRPART: %m");
else
log_device_debug(d, "Successfully reread partition table via BLKRRPART.");
if (FLAGS_SET(flags, REREADPT_FORCE_UEVENT))
RET_GATHER(r, trigger_partitions(d, r >= 0));
return r;
}
#if HAVE_BLKID
static int process_partition(
sd_device *d,
int fd,
blkid_partition pp,
sd_device_enumerator *e,
Set **partnos,
RereadPartitionTableFlags flags,
bool *changed) {
int r;
assert(d);
assert(fd >= 0);
assert(pp);
assert(e);
assert(partnos);
assert(changed);
const char *node;
r = sd_device_get_devname(d, &node);
if (r < 0)
return log_device_debug_errno(d, r, "Failed to acquire device node path: %m");
errno = 0;
int nr = sym_blkid_partition_get_partno(pp);
if (nr < 0)
return log_debug_errno(errno_or_else(EIO), "Failed to read partition number of partition: %m");
log_device_debug(d, "Processing partition %i...", nr);
errno = 0;
blkid_loff_t start = sym_blkid_partition_get_start(pp);
if (start < 0)
return log_debug_errno(errno_or_else(EIO), "Failed to read partition start offset of partition %i: %m", nr);
assert((uint64_t) start < UINT64_MAX / 512U);
errno = 0;
blkid_loff_t size = sym_blkid_partition_get_size(pp);
if (size < 0)
return log_debug_errno(errno_or_else(EIO), "Failed to read partition size of partition %i: %m", nr);
assert((uint64_t) size < UINT64_MAX / 512U);
if (set_ensure_put(partnos, /* hash_ops= */ NULL, UINT_TO_PTR(nr)) < 0)
return log_oom_debug();
_cleanup_free_ char *subnode = NULL;
r = partition_node_of(node, nr, &subnode);
if (r < 0)
return log_device_debug_errno(d, r, "Failed to determine partition node %i for '%s': %m", nr, node);
_cleanup_(sd_device_unrefp) sd_device *partition = NULL;
r = sd_device_new_from_devname(&partition, subnode);
if (r < 0) {
if (r != -ENODEV)
return log_device_debug_errno(d, r, "Failed to acquire device '%s': %m", subnode);
} else {
uint64_t start_kernel;
r = device_get_sysattr_u64(partition, "start", &start_kernel);
if (r < 0)
return log_device_debug_errno(partition, r, "Failed to get start of kernel partition device '%s': %m", subnode);
uint64_t size_kernel;
r = device_get_sysattr_u64(partition, "size", &size_kernel);
if (r < 0)
return log_device_debug_errno(partition, r, "Failed to get size of kernel partition device '%s': %m", subnode);
if (start_kernel == (uint64_t) start && size_kernel == (uint64_t) size) {
log_device_debug(partition, "Kernel partition device '%s' already matches partition table, not modifying.", subnode);
if (FLAGS_SET(flags, REREADPT_FORCE_UEVENT)) {
if (!*changed) {
/* Make sure to synthesize a change event on the main device, before we issue the first one on a partition device */
r = sd_device_trigger(d, SD_DEVICE_CHANGE);
if (r < 0)
return log_device_debug_errno(d, r, "Failed to issue 'change' uevent on device '%s': %m", node);
log_device_debug(d, "Successfully issued 'change' uevent on device '%s'.", node);
*changed = true;
}
r = sd_device_trigger(partition, SD_DEVICE_CHANGE);
if (r < 0)
return log_device_debug_errno(partition, r, "Failed to issue 'change' uevent on partition '%s': %m", subnode);
log_device_debug(partition, "Successfully issued 'change' uevent on partition '%s'.", subnode);
}
return 0;
}
if (start_kernel == (uint64_t) start) {
/* If the start offsize doesn't change we can just resize the partition */
log_device_debug(partition, "Resizing partition %i...", nr);
r = block_device_resize_partition(fd, nr, (uint64_t) start * 512U, (uint64_t) size * 512U);
if (r < 0)
return log_device_debug_errno(partition, r, "Failed to resize kernel partition device '%s' to partition table values: %m", subnode);
log_device_debug(partition, "Successfully resized kernel partition device '%s' to match partition table.", subnode);
*changed = true;
return 1;
}
/* If the start offset changed we need to remove and recreate the partition */
log_device_debug(partition, "Removing and recreating partition %i...", nr);
/* NB: when logging below we use the parent device now, after all the partition device ceased
* existing by now, most likely. Let's explicitly get rid of the obsolete device object now,
* just to make a point. */
partition = sd_device_unref(partition);
r = block_device_remove_partition(fd, subnode, (int) nr);
if (r < 0)
return log_device_debug_errno(d, r, "Failed to remove kernel partition device '%s' in order to recreate it: %m", subnode);
/* And now add it the partition anew*/
log_device_debug(d, "Successfully removed kernel partition device '%s' in order to recreate it.", subnode);
}
log_device_debug(d, "Adding partition %i...", nr);
r = block_device_add_partition(fd, subnode, nr, (uint64_t) start * 512U, (uint64_t) size * 512U);
if (r < 0)
return log_device_debug_errno(d, r, "Failed to add kernel partition device %i to partition table values: %m", nr);
log_device_debug(d, "Successfully added kernel partition device %i to match partition table.", nr);
*changed = true;
return 1;
}
static int remove_partitions(sd_device *d, int fd, sd_device_enumerator *e, Set *partnos, bool *changed) {
int r;
assert(d);
assert(fd >= 0);
assert(e);
assert(changed);
/* Removes all partitions of the specified device that we didn't find in the partition table (as
* listed in the specified Set object) */
int ret = 0;
FOREACH_DEVICE(e, partition) {
const char *devname;
r = sd_device_get_devname(partition, &devname);
if (r < 0)
return log_device_debug_errno(partition, r, "Failed to get name of partition: %m");
unsigned nr;
r = device_get_property_uint(partition, "PARTN", &nr);
if (r < 0)
return log_device_debug_errno(partition, r, "Failed to read partition number property: %m");
if (set_contains(partnos, UINT_TO_PTR(nr))) {
log_device_debug(partition, "Found kernel partition device %u in partition table, leaving around.", nr);
continue;
}
log_device_debug(partition, "Kernel knows partition %u which we didn't find, removing.", nr);
r = block_device_remove_partition(fd, devname, (int) nr);
if (r < 0) /* NB: when logging we use the parent device below, after all the partition device ceased existing by now, most likely */
RET_GATHER(ret, log_device_debug_errno(d, r, "Failed to remove kernel partition device '%s' that vanished from partition table: %m", devname));
else {
log_device_debug(d, "Removed partition %u from kernel.", nr);
*changed = true;
}
}
return ret;
}
#endif
static int reread_partition_table_full(sd_device *dev, int fd, RereadPartitionTableFlags flags) {
int r;
assert(dev);
assert(fd >= 0);
const char *p;
r = sd_device_get_devname(dev, &p);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get block device name: %m");
_cleanup_close_ int lock_fd = -EBADF;
if (FLAGS_SET(flags, REREADPT_BSD_LOCK)) {
lock_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (lock_fd < 0)
return log_device_debug_errno(dev, r, "Failed top open lock fd for block device '%s': %m", p);
if (flock(lock_fd, LOCK_SH|LOCK_NB) < 0)
return log_device_debug_errno(dev, errno, "Failed to take BSD lock on block device '%s': %m", p);
}
r = blockdev_partscan_enabled(dev);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to test if block device '%s' knows partition scanning: %m", p);
if (r == 0) {
/* No partition scanning? Generate a uevent at least, if that's requested */
if (FLAGS_SET(flags, REREADPT_FORCE_UEVENT)) {
r = sd_device_trigger(dev, SD_DEVICE_CHANGE);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to trigger 'change' uevent, proceeding: %m");
return 0;
}
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENOTTY), "Block device '%s' does not support partition scanning.", p);
}
#if HAVE_BLKID
r = dlopen_libblkid();
if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
log_device_debug(dev, "We don't have libblkid, falling back to BLKRRPART on '%s'.", p);
return fallback_ioctl(dev, fd, flags);
}
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to load libblkid: %m");
_cleanup_(blkid_free_probep) blkid_probe b = sym_blkid_new_probe();
if (!b)
return log_oom_debug();
errno = 0;
r = sym_blkid_probe_set_device(b, fd, /* off= */ 0, /* size= */ 0);
if (r != 0)
return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to open block device '%s': %m", p);
(void) sym_blkid_probe_enable_partitions(b, 1);
(void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0;
r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR)
return log_device_debug_errno(dev, errno_or_else(EIO), "Unable to probe for partition table of '%s': %m", p);
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) {
log_device_debug(dev, "Didn't find partition table on block device '%s', falling back to BLKRRPART.", p);
return fallback_ioctl(dev, fd, flags);
}
assert(r == _BLKID_SAFEPROBE_FOUND);
const char *pttype = NULL;
(void) sym_blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
if (!streq_ptr(pttype, "gpt")) {
log_device_debug(dev, "Didn't find a GPT partition table on '%s', falling back to BLKRRPART.", p);
return fallback_ioctl(dev, fd, flags);
}
errno = 0;
blkid_partlist pl = sym_blkid_probe_get_partitions(b);
if (!pl)
return log_device_debug_errno(dev, errno_or_else(EIO), "Unable to read partition table of '%s': %m", p);
errno = 0;
int n_partitions = sym_blkid_partlist_numof_partitions(pl);
if (n_partitions < 0)
return log_device_debug_errno(dev, errno_or_else(EIO), "Unable to acquire number of entries in partition table of '%s': %m", p);
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
r = partition_enumerator_new(dev, &e);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to enumerate kernel partition devices: %m");
log_device_debug(dev, "Updating/adding kernel partition devices...");
_cleanup_(set_freep) Set *found_partnos = NULL;
bool changed = false;
int ret = 0;
for (int i = 0; i < n_partitions; i++) {
errno = 0;
blkid_partition pp = sym_blkid_partlist_get_partition(pl, i);
if (!pp)
return log_device_debug_errno(dev, errno_or_else(EIO), "Unable to get partition data of partition %i of partition table of '%s': %m", i, p);
RET_GATHER(ret, process_partition(dev, fd, pp, e, &found_partnos, flags, &changed));
}
/* Only delete unrecognized partitions if everything else worked */
if (ret < 0)
return ret;
log_device_debug(dev, "Removing old kernel partition devices...");
r = remove_partitions(dev, fd, e, found_partnos, &changed);
if (r < 0)
return r;
if (changed)
return 1;
if (FLAGS_SET(flags, REREADPT_FORCE_UEVENT)) {
/* No change? Then trigger an event manually if we were told to */
r = sd_device_trigger(dev, SD_DEVICE_CHANGE);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to issue 'change' uevent on device '%s': %m", p);
}
return 0;
#else
log_device_debug(dev, "We don't have libblkid, falling back to BLKRRPART on '%s'.", p);
return fallback_ioctl(dev, fd, flags);
#endif
}
int reread_partition_table(sd_device *dev, RereadPartitionTableFlags flags) {
assert(dev);
_cleanup_close_ int fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
return log_debug_errno(fd, "Failed to open block device: %m");
return reread_partition_table_full(dev, fd, flags);
}
int reread_partition_table_fd(int fd, RereadPartitionTableFlags flags) {
int r;
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
r = block_device_new_from_fd(fd, /* flags= */ 0, &dev);
if (r < 0)
return log_debug_errno(r, "Failed to get block device object: %m");
return reread_partition_table_full(dev, fd, flags);
}

View File

@ -1,14 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-forward.h"
#include "shared-forward.h"
typedef enum RereadPartitionTableFlags {
REREADPT_FORCE_UEVENT = 1 << 0, /* Force a "change" ueven out on partitions we didn't resize/remove/add */
REREADPT_BSD_LOCK = 1 << 1, /* Take a BSD lock on the device around the rescan operation */
} RereadPartitionTableFlags;
int reread_partition_table_fd(int fd, RereadPartitionTableFlags flags);
int reread_partition_table(sd_device *dev, RereadPartitionTableFlags flags);

View File

@ -390,7 +390,7 @@ static int nvme_subsystem_add(const char *node, int consumed_fd, sd_device *devi
return log_oom();
if (fd < 0) {
fd = RET_NERRNO(open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK));
fd = RET_NERRNO(open(node, O_RDONLY|O_CLOEXEC|O_NONBLOCK));
if (fd < 0)
return log_error_errno(fd, "Failed to open '%s': %m", node);
}

View File

@ -432,13 +432,6 @@ executables += [
'dependencies' : libm,
'timeout' : 120,
},
test_template + {
'sources' : files('test-reread-partition-table.c'),
},
test_template + {
'sources' : files('test-reread-partition-table-manual.c'),
'type' : 'manual',
},
test_template + {
'sources' : files('test-sbat.c'),
'conditions' : ['ENABLE_BOOTLOADER'],

View File

@ -77,30 +77,4 @@ TEST(partscan_enabled) {
}
}
static void test_partition_node_of_one(const char *main, unsigned partition, const char *result, int retval) {
_cleanup_free_ char *s = NULL;
int r;
r = partition_node_of(main, partition, &s);
ASSERT_EQ(r, retval);
if (r < 0)
return;
ASSERT_STREQ(s, result);
log_info("%s with %u → %s", main, partition, result);
}
TEST(partition_node_of) {
test_partition_node_of_one("/dev/sda", 2, "/dev/sda2", 0);
test_partition_node_of_one("sda", 3, "sda3", 0);
test_partition_node_of_one("/dev/nvme0n1", 7, "/dev/nvme0n1p7", 0);
test_partition_node_of_one("nvme0n1", 8, "nvme0n1p8", 0);
test_partition_node_of_one("/dev/loop1", 3, "/dev/loop1p3", 0);
test_partition_node_of_one("", 1, NULL, -EINVAL);
test_partition_node_of_one("/", 1, NULL, -EADDRNOTAVAIL);
test_partition_node_of_one("/dev/", 1, NULL, -EISDIR);
test_partition_node_of_one("/sda", 1, "/sda1", 0);
test_partition_node_of_one(".", 1, NULL, -EADDRNOTAVAIL);
}
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -1,28 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "fd-util.h"
#include "log.h"
#include "main-func.h"
#include "reread-partition-table.h"
static int run(int argc, char *argv[]) {
int r;
log_set_max_level(LOG_DEBUG);
log_setup();
if (argc != 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected single parameter, the device node to open.");
_cleanup_close_ int fd = open(argv[1], O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
r = reread_partition_table_fd(fd, REREADPT_BSD_LOCK|REREADPT_FORCE_UEVENT);
if (r < 0)
return log_error_errno(r, "Failed to reread partition table: %m");
return 0;
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -1,162 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/loop.h>
#include "blockdev-util.h"
#include "fd-util.h"
#include "loop-util.h"
#include "memfd-util.h"
#include "path-util.h"
#include "process-util.h"
#include "reread-partition-table.h"
#include "tests.h"
#include "tmpfile-util.h"
#include "virt.h"
static void sfdisk(const char *sfdisk_path, LoopDevice *loop, const char *definition) {
int r;
assert(sfdisk_path);
assert(loop);
assert(definition);
_cleanup_close_ int memfd = memfd_new_and_seal("sfdisk", definition, SIZE_MAX);
ASSERT_OK(memfd);
r = safe_fork_full(
"(sfdisk)",
(int[]) { memfd, STDOUT_FILENO, STDERR_FILENO },
/* except_fds= */ NULL,
/* n_except_fds= */ 0,
FORK_CLOSE_ALL_FDS|FORK_RESET_SIGNALS|FORK_REARRANGE_STDIO|FORK_LOG|FORK_WAIT,
/* ret_pid= */ NULL);
if (r == 0) {
/* child */
execl(sfdisk_path, "fdisk", "--no-tell-kernel", "--no-reread", loop->node, NULL);
_exit(EXIT_FAILURE);
}
ASSERT_OK(r);
}
TEST(rereadpt) {
int r;
if (detect_container() > 0)
return (void) log_tests_skipped("test not available in container");
if (running_in_chroot() > 0)
return (void) log_tests_skipped("test not available in chroot()");
_cleanup_free_ char *sfdisk_path = NULL;
r = find_executable("sfdisk", &sfdisk_path);
if (r == -ENOENT)
return (void) log_tests_skipped("sfdisk not found");
ASSERT_OK(r);
_cleanup_close_ int fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR);
ASSERT_FD(fd);
ASSERT_OK_ERRNO(ftruncate(fd, 100 * 1024 * 1024));
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
r = loop_device_make(
fd,
O_RDWR,
/* offset= */ 0,
/* size= */ UINT64_MAX,
/* sector_size= */ 512U,
LO_FLAGS_PARTSCAN,
LOCK_EX, &loop);
if (ERRNO_IS_NEG_PRIVILEGE(r) || ERRNO_IS_NOT_SUPPORTED(r))
return (void) log_tests_skipped("loopback block devices not available");
_cleanup_free_ char *p = NULL;
ASSERT_OK(partition_node_of(loop->node, 1, &p));
ASSERT_ERROR_ERRNO(access(p, F_OK), ENOENT);
/* No change */
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
ASSERT_ERROR_ERRNO(access(p, F_OK), ENOENT);
/* Create */
log_notice("CREATING 20M");
sfdisk(sfdisk_path,
loop,
"label: gpt\n"
"start=, size=20M, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7\n");
ASSERT_ERROR_ERRNO(access(p, F_OK), ENOENT);
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
_cleanup_close_ int pfd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
ASSERT_OK_ERRNO(pfd);
uint64_t size;
ASSERT_OK(blockdev_get_device_size(pfd, &size));
ASSERT_EQ(size, 20U*1024U*1024U);
/* No change */
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
/* No change, but synthesize change anyway */
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ REREADPT_FORCE_UEVENT));
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
/* Resize */
log_notice("RESIZING TO 30M");
sfdisk(sfdisk_path,
loop,
"label: gpt\n"
"start=, size=30M, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7\n");
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
ASSERT_OK(blockdev_get_device_size(pfd, &size));
ASSERT_EQ(size, 30U*1024U*1024U);
/* No change */
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
/* Move */
log_notice("MOVING BY 50M");
sfdisk(sfdisk_path,
loop,
"label: gpt\n"
"start=50M, size=15M, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7\n");
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
ASSERT_ERROR(reread_partition_table_fd(loop->fd, /* flags= */ 0), EBUSY);
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
safe_close(pfd);
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
pfd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
ASSERT_OK_ERRNO(pfd);
ASSERT_OK(blockdev_get_device_size(pfd, &size));
ASSERT_EQ(size, 15U*1024U*1024U);
/* No change */
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
/* Remove */
log_notice("REMOVING");
sfdisk(sfdisk_path,
loop,
"label: gpt\n");
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
ASSERT_ERROR(reread_partition_table_fd(loop->fd, /* flags= */ 0), EBUSY);
ASSERT_OK_ZERO_ERRNO(access(p, F_OK));
pfd = safe_close(pfd);
ASSERT_OK(reread_partition_table_fd(loop->fd, /* flags= */ 0));
ASSERT_ERROR_ERRNO(access(p, F_OK), ENOENT);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -22,7 +22,6 @@
#include "parse-util.h"
#include "pidref.h"
#include "process-util.h"
#include "reread-partition-table.h"
#include "rm-rf.h"
#include "set.h"
#include "signal-util.h"
@ -162,6 +161,36 @@ static int synthesize_change_one(sd_device *dev, sd_device *target) {
return 0;
}
static int synthesize_change_all(sd_device *dev) {
int r;
assert(dev);
r = blockdev_reread_partition_table(dev);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to re-read partition table, ignoring: %m");
bool part_table_read = r >= 0;
/* search for partitions */
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
r = partition_enumerator_new(dev, &e);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to initialize partition enumerator, ignoring: %m");
/* We have partitions and re-read the table, the kernel already sent out a "change"
* event for the disk, and "remove/add" for all partitions. */
if (part_table_read && sd_device_enumerator_get_device_first(e))
return 0;
/* We have partitions but re-reading the partition table did not work, synthesize
* "change" for the disk and all partitions. */
r = synthesize_change_one(dev, dev);
FOREACH_DEVICE(e, d)
RET_GATHER(r, synthesize_change_one(dev, d));
return r;
}
static int synthesize_change_child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
assert(s);
@ -197,7 +226,7 @@ static int synthesize_change(Manager *manager, sd_device *dev) {
return r;
if (r == 0) {
/* child */
(void) reread_partition_table(dev, REREADPT_FORCE_UEVENT|REREADPT_BSD_LOCK);
(void) synthesize_change_all(dev);
_exit(EXIT_SUCCESS);
}

View File

@ -184,8 +184,7 @@ static int lock_device(
struct stat st;
int r;
/* We open in O_WRONLY mode here, to trigger a rescan in udev once we are done */
fd = open(path, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", path);