X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Freadahead%2Freadahead-common.c;h=aea1fbeea4ff8fe02e8f226f7b5c5f25ecb65363;hp=766b3a1936cd7d8afb21fb1475e45b20181844d4;hb=fb818b2ea194ec182aa3e776d38883dc615910a1;hpb=268ba0ef6095df82966e1f1eda671e43ab1b31ab diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c index 766b3a193..aea1fbeea 100644 --- a/src/readahead/readahead-common.c +++ b/src/readahead/readahead-common.c @@ -27,11 +27,14 @@ #include #include #include -#include #include "log.h" #include "readahead-common.h" #include "util.h" +#include "missing.h" +#include "fileio.h" +#include "libudev.h" +#include "udev-util.h" int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) { assert(fd >= 0); @@ -58,18 +61,67 @@ int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) { int fs_on_ssd(const char *p) { struct stat st; - struct udev *udev = NULL; - struct udev_device *udev_device = NULL, *look_at = NULL; - bool b = false; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; + struct udev_device *look_at = NULL; const char *devtype, *rotational, *model, *id; + int r; assert(p); if (stat(p, &st) < 0) return -errno; - if (major(st.st_dev) == 0) + if (major(st.st_dev) == 0) { + _cleanup_fclose_ FILE *f = NULL; + int mount_id; + struct file_handle *h; + + /* Might be btrfs, which exposes "ssd" as mount flag if it is on ssd. + * + * We first determine the mount ID here, if we can, + * and then lookup the mount ID in mountinfo to find + * the mount options. */ + + h = alloca(MAX_HANDLE_SZ); + h->handle_bytes = MAX_HANDLE_SZ; + r = name_to_handle_at(AT_FDCWD, p, h, &mount_id, AT_SYMLINK_FOLLOW); + if (r < 0) + return false; + + f = fopen("/proc/self/mountinfo", "re"); + if (!f) + return false; + + for (;;) { + char line[LINE_MAX], *e; + _cleanup_free_ char *opts = NULL; + int mid; + + if (!fgets(line, sizeof(line), f)) + return false; + + truncate_nl(line); + + if (sscanf(line, "%i", &mid) != 1) + continue; + + if (mid != mount_id) + continue; + + e = strstr(line, " - "); + if (!e) + continue; + + if (sscanf(e+3, "%*s %*s %ms", &opts) != 1) + continue; + + if (streq(opts, "ssd") || startswith(opts, "ssd,") || endswith(opts, ",ssd") || strstr(opts, ",ssd,")) + return true; + } + return false; + } udev = udev_new(); if (!udev) @@ -77,7 +129,7 @@ int fs_on_ssd(const char *p) { udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); if (!udev_device) - goto finish; + return false; devtype = udev_device_get_property_value(udev_device, "DEVTYPE"); if (devtype && streq(devtype, "partition")) @@ -86,45 +138,34 @@ int fs_on_ssd(const char *p) { look_at = udev_device; if (!look_at) - goto finish; + return false; /* First, try high-level property */ id = udev_device_get_property_value(look_at, "ID_SSD"); - if (id) { - b = streq(id, "1"); - goto finish; - } + if (id) + return streq(id, "1"); /* Second, try kernel attribute */ rotational = udev_device_get_sysattr_value(look_at, "queue/rotational"); if (rotational) - if ((b = streq(rotational, "0"))) - goto finish; + return streq(rotational, "0"); /* Finally, fallback to heuristics */ look_at = udev_device_get_parent(look_at); if (!look_at) - goto finish; + return false; model = udev_device_get_sysattr_value(look_at, "model"); if (model) - b = !!strstr(model, "SSD"); - -finish: - if (udev_device) - udev_device_unref(udev_device); + return !!strstr(model, "SSD"); - if (udev) - udev_unref(udev); - - return b; + return false; } int fs_on_read_only(const char *p) { struct stat st; - struct udev *udev = NULL; - struct udev_device *udev_device = NULL; - bool b = false; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; const char *read_only; assert(p); @@ -135,24 +176,19 @@ int fs_on_read_only(const char *p) { if (major(st.st_dev) == 0) return false; - if (!(udev = udev_new())) + udev = udev_new(); + if (!udev) return -ENOMEM; - if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev))) - goto finish; - - if ((read_only = udev_device_get_sysattr_value(udev_device, "ro"))) - if ((b = streq(read_only, "1"))) - goto finish; - -finish: - if (udev_device) - udev_device_unref(udev_device); + udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); + if (!udev_device) + return false; - if (udev) - udev_unref(udev); + read_only = udev_device_get_sysattr_value(udev_device, "ro"); + if (read_only) + return streq(read_only, "1"); - return b; + return false; } bool enough_ram(void) { @@ -164,16 +200,23 @@ bool enough_ram(void) { return si.totalram > 127 * 1024*1024 / si.mem_unit; } +static void mkdirs(void) { + if (mkdir("/run/systemd", 0755) && errno != EEXIST) + log_warning("Failed to create /run/systemd: %m"); + if (mkdir("/run/systemd/readahead", 0755) && errno != EEXIST) + log_warning("Failed to create /run/systemd: %m"); +} + int open_inotify(void) { int fd; - if ((fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { + fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); + if (fd < 0) { log_error("Failed to create inotify handle: %m"); return -errno; } - mkdir("/run/systemd", 0755); - mkdir("/run/systemd/readahead", 0755); + mkdirs(); if (inotify_add_watch(fd, "/run/systemd/readahead", IN_CREATE) < 0) { log_error("Failed to watch /run/systemd/readahead: %m"); @@ -185,36 +228,36 @@ int open_inotify(void) { } ReadaheadShared *shared_get(void) { - int fd; + int _cleanup_close_ fd = -1; ReadaheadShared *m = NULL; - mkdir("/run/systemd", 0755); - mkdir("/run/systemd/readahead", 0755); + mkdirs(); - if ((fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644)) < 0) { + fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644); + if (fd < 0) { log_error("Failed to create shared memory segment: %m"); - goto finish; + return NULL; } if (ftruncate(fd, sizeof(ReadaheadShared)) < 0) { log_error("Failed to truncate shared memory segment: %m"); - goto finish; + return NULL; } - if ((m = mmap(NULL, sizeof(ReadaheadShared), PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + m = mmap(NULL, sizeof(ReadaheadShared), PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); + if (m == MAP_FAILED) { log_error("Failed to mmap shared memory segment: %m"); - m = NULL; - goto finish; + return NULL; } -finish: - if (fd >= 0) - close_nointr_nofail(fd); - return m; } -#define BUMP_REQUEST_NR (16*1024) +/* We use 20K instead of the more human digestable 16K here. Why? + Simply so that it is more unlikely that users end up picking this + value too so that we can recognize better whether the user changed + the value while we had it temporarily bumped. */ +#define BUMP_REQUEST_NR (20*1024) int block_bump_request_nr(const char *p) { struct stat st; @@ -260,7 +303,7 @@ int block_bump_request_nr(const char *p) { goto finish; } - r = write_one_line_file(ap, line); + r = write_string_file(ap, line); if (r < 0) goto finish; @@ -343,7 +386,7 @@ int block_set_readahead(const char *p, uint64_t bytes) { goto finish; } - r = write_one_line_file(ap, line); + r = write_string_file(ap, line); if (r < 0) goto finish;