mirror of
https://github.com/systemd/systemd.git
synced 2024-12-01 06:13:38 +08:00
Merge pull request #9255 from poettering/block-dev-fixes
some block device handling fixes
This commit is contained in:
commit
24d169e092
@ -81,38 +81,26 @@ int get_block_device(const char *path, dev_t *dev) {
|
||||
if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
|
||||
return btrfs_get_block_device(path, dev);
|
||||
|
||||
*dev = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
int block_get_originating(dev_t dt, dev_t *ret) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
char p[SYS_BLOCK_PATH_MAX("/slaves")];
|
||||
struct dirent *de, *found = NULL;
|
||||
const char *q;
|
||||
unsigned maj, min;
|
||||
dev_t dt;
|
||||
const char *q;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(dev);
|
||||
|
||||
/* Gets the backing block device for a file system, and
|
||||
* handles LUKS encrypted file systems, looking for its
|
||||
* immediate parent, if there is one. */
|
||||
|
||||
r = get_block_device(path, &dt);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
/* For the specified block device tries to chase it through the layers, in case LUKS-style DM stacking is used,
|
||||
* trying to find the next underlying layer. */
|
||||
|
||||
xsprintf_sys_block_path(p, "/slaves", dt);
|
||||
d = opendir(p);
|
||||
if (!d) {
|
||||
if (errno == ENOENT)
|
||||
goto fallback;
|
||||
|
||||
if (!d)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
FOREACH_DIRENT_ALL(de, d, return -errno) {
|
||||
|
||||
@ -140,34 +128,28 @@ int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_one_line_file(u, &a);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", u);
|
||||
goto fallback;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to read %s: %m", u);
|
||||
|
||||
r = read_one_line_file(v, &b);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", v);
|
||||
goto fallback;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to read %s: %m", v);
|
||||
|
||||
/* Check if the parent device is the same. If not, then the two backing devices are on
|
||||
* different physical devices, and we don't support that. */
|
||||
if (!streq(a, b))
|
||||
goto fallback;
|
||||
return -ENOTUNIQ;
|
||||
}
|
||||
|
||||
found = de;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto fallback;
|
||||
return -ENOENT;
|
||||
|
||||
q = strjoina(p, "/", found->d_name, "/dev");
|
||||
|
||||
r = read_one_line_file(q, &t);
|
||||
if (r == -ENOENT)
|
||||
goto fallback;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -175,12 +157,28 @@ int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
return -EINVAL;
|
||||
|
||||
if (maj == 0)
|
||||
goto fallback;
|
||||
return -ENOENT;
|
||||
|
||||
*ret = makedev(maj, min);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_block_device_harder(const char *path, dev_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
/* Gets the backing block device for a file system, and handles LUKS encrypted file systems, looking for its
|
||||
* immediate parent, if there is one. */
|
||||
|
||||
r = get_block_device(path, ret);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = block_get_originating(*ret, ret);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to chase block device '%s', ignoring: %m", path);
|
||||
|
||||
*dev = makedev(maj, min);
|
||||
return 1;
|
||||
|
||||
fallback:
|
||||
*dev = dt;
|
||||
return 1;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix))
|
||||
|
||||
int block_get_whole_disk(dev_t d, dev_t *ret);
|
||||
int block_get_originating(dev_t d, dev_t *ret);
|
||||
|
||||
int get_block_device(const char *path, dev_t *dev);
|
||||
|
||||
|
@ -277,8 +277,10 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) {
|
||||
return -errno;
|
||||
|
||||
/* We won't do this for btrfs RAID */
|
||||
if (fsi.num_devices != 1)
|
||||
if (fsi.num_devices != 1) {
|
||||
*dev = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (id = 1; id <= fsi.max_id; id++) {
|
||||
struct btrfs_ioctl_dev_info_args di = {
|
||||
|
@ -886,17 +886,36 @@ bool hidden_or_backup_file(const char *filename) {
|
||||
|
||||
bool is_device_path(const char *path) {
|
||||
|
||||
/* Returns true on paths that refer to a device, either in
|
||||
* sysfs or in /dev */
|
||||
/* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */
|
||||
|
||||
return path_startswith(path, "/dev/") ||
|
||||
path_startswith(path, "/sys/");
|
||||
return PATH_STARTSWITH_SET(path, "/dev/", "/sys/");
|
||||
}
|
||||
|
||||
bool is_deviceallow_pattern(const char *path) {
|
||||
return path_startswith(path, "/dev/") ||
|
||||
startswith(path, "block-") ||
|
||||
startswith(path, "char-");
|
||||
bool valid_device_node_path(const char *path) {
|
||||
|
||||
/* Some superficial checks whether the specified path is a valid device node path, all without looking at the
|
||||
* actual device node. */
|
||||
|
||||
if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/"))
|
||||
return false;
|
||||
|
||||
if (endswith(path, "/")) /* can't be a device node if it ends in a slash */
|
||||
return false;
|
||||
|
||||
return path_is_normalized(path);
|
||||
}
|
||||
|
||||
bool valid_device_allow_pattern(const char *path) {
|
||||
assert(path);
|
||||
|
||||
/* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny=
|
||||
* accept it */
|
||||
|
||||
if (startswith(path, "block-") ||
|
||||
startswith(path, "char-"))
|
||||
return true;
|
||||
|
||||
return valid_device_node_path(path);
|
||||
}
|
||||
|
||||
int systemd_installation_has_version(const char *root, unsigned minimal_version) {
|
||||
|
@ -147,7 +147,9 @@ char *file_in_same_dir(const char *path, const char *filename);
|
||||
bool hidden_or_backup_file(const char *filename) _pure_;
|
||||
|
||||
bool is_device_path(const char *path);
|
||||
bool is_deviceallow_pattern(const char *path);
|
||||
|
||||
bool valid_device_node_path(const char *path);
|
||||
bool valid_device_allow_pattern(const char *path);
|
||||
|
||||
int systemd_installation_has_version(const char *root, unsigned minimal_version);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "bpf-firewall.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "bus-error.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "cgroup.h"
|
||||
@ -306,30 +307,36 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
||||
}
|
||||
}
|
||||
|
||||
static int lookup_block_device(const char *p, dev_t *dev) {
|
||||
static int lookup_block_device(const char *p, dev_t *ret) {
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(dev);
|
||||
assert(ret);
|
||||
|
||||
if (stat(p, &st) < 0)
|
||||
return log_warning_errno(errno, "Couldn't stat device %s: %m", p);
|
||||
return log_warning_errno(errno, "Couldn't stat device '%s': %m", p);
|
||||
|
||||
if (S_ISBLK(st.st_mode))
|
||||
*dev = st.st_rdev;
|
||||
else if (major(st.st_dev) != 0) {
|
||||
/* If this is not a device node then find the block
|
||||
* device this file is stored on */
|
||||
*dev = st.st_dev;
|
||||
|
||||
/* If this is a partition, try to get the originating
|
||||
* block device */
|
||||
(void) block_get_whole_disk(*dev, dev);
|
||||
} else {
|
||||
log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
|
||||
return -ENODEV;
|
||||
*ret = st.st_rdev;
|
||||
else if (major(st.st_dev) != 0)
|
||||
*ret = st.st_dev; /* If this is not a device node then use the block device this file is stored on */
|
||||
else {
|
||||
/* If this is btrfs, getting the backing block device is a bit harder */
|
||||
r = btrfs_get_block_device(p, ret);
|
||||
if (r < 0 && r != -ENOTTY)
|
||||
return log_warning_errno(r, "Failed to determine block device backing btrfs file system '%s': %m", p);
|
||||
if (r == -ENOTTY) {
|
||||
log_warning("'%s' is not a block device node, and file system block device cannot be determined or is not local.", p);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is a LUKS device, try to get the originating block device */
|
||||
(void) block_get_originating(*ret, ret);
|
||||
|
||||
/* If this is a partition, try to get the originating block device */
|
||||
(void) block_get_whole_disk(*ret, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -687,9 +687,8 @@ int bus_cgroup_set_property(
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
|
||||
|
||||
if (!path_startswith(path, "/dev") &&
|
||||
!path_startswith(path, "/run/systemd/inaccessible/"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
|
||||
if (!path_is_normalized(path))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
CGroupIODeviceLimit *a = NULL, *b;
|
||||
@ -775,9 +774,8 @@ int bus_cgroup_set_property(
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
|
||||
|
||||
if (!path_startswith(path, "/dev") &&
|
||||
!path_startswith(path, "/run/systemd/inaccessible/"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
|
||||
if (!path_is_normalized(path))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
|
||||
|
||||
if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
|
||||
@ -861,9 +859,8 @@ int bus_cgroup_set_property(
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
|
||||
|
||||
if (!path_startswith(path, "/dev") &&
|
||||
!path_startswith(path, "/run/systemd/inaccessible/"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
|
||||
if (!path_is_normalized(path))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
CGroupBlockIODeviceBandwidth *a = NULL, *b;
|
||||
@ -961,9 +958,8 @@ int bus_cgroup_set_property(
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
|
||||
|
||||
if (!path_startswith(path, "/dev") &&
|
||||
!path_startswith(path, "/run/systemd/inaccessible/"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
|
||||
if (!path_is_normalized(path))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
|
||||
|
||||
if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
|
||||
@ -1063,15 +1059,12 @@ int bus_cgroup_set_property(
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
|
||||
|
||||
if ((!is_deviceallow_pattern(path) &&
|
||||
!path_startswith(path, "/run/systemd/inaccessible/")) ||
|
||||
strpbrk(path, WHITESPACE))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
|
||||
if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
|
||||
|
||||
if (isempty(rwm))
|
||||
rwm = "rwm";
|
||||
|
||||
if (!in_charset(rwm, "rwm"))
|
||||
else if (!in_charset(rwm, "rwm"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
|
@ -546,8 +546,7 @@ static int device_process_new(Manager *m, struct udev_device *dev) {
|
||||
/* Don't bother with the /dev/block links */
|
||||
p = udev_list_entry_get_name(item);
|
||||
|
||||
if (path_startswith(p, "/dev/block/") ||
|
||||
path_startswith(p, "/dev/char/"))
|
||||
if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/"))
|
||||
continue;
|
||||
|
||||
/* Verify that the symlink in the FS actually belongs
|
||||
|
@ -3234,14 +3234,16 @@ int config_parse_device_allow(
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
if (!startswith(resolved, "block-") && !startswith(resolved, "char-")) {
|
||||
|
||||
if (!is_deviceallow_pattern(resolved) &&
|
||||
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
|
||||
return 0;
|
||||
r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (!valid_device_node_path(resolved)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isempty(p) && !in_charset(p, "rwm")) {
|
||||
@ -3317,12 +3319,6 @@ int config_parse_io_device_weight(
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (!path_startswith(resolved, "/dev") &&
|
||||
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = cg_weight_parse(p, &u);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid, ignoring: %m", p);
|
||||
@ -3400,15 +3396,9 @@ int config_parse_io_limit(
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (!path_startswith(resolved, "/dev") &&
|
||||
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq("infinity", p)) {
|
||||
if (streq("infinity", p))
|
||||
num = CGROUP_LIMIT_MAX;
|
||||
} else {
|
||||
else {
|
||||
r = parse_size(p, 1000, &num);
|
||||
if (r < 0 || num <= 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid IO limit '%s', ignoring.", p);
|
||||
@ -3497,12 +3487,6 @@ int config_parse_blockio_device_weight(
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (!path_startswith(resolved, "/dev") &&
|
||||
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", resolved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = cg_blkio_weight_parse(p, &u);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid block IO weight '%s', ignoring: %m", p);
|
||||
@ -3581,12 +3565,6 @@ int config_parse_blockio_bandwidth(
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (!path_startswith(resolved, "/dev") &&
|
||||
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_size(p, 1000, &bytes);
|
||||
if (r < 0 || bytes <= 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Block IO Bandwidth '%s', ignoring.", p);
|
||||
|
Loading…
Reference in New Issue
Block a user