X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Freadahead%2Freadahead-collect.c;h=c4bcd4e16250e433d6cbbc0960b0b32b7fba4a8a;hb=cae544bcdb073134bcaa2031aeb1f1705030046e;hp=3e91d5c28a16ac2389ed3e97baa8bbd28a5ff4bc;hpb=5430f7f2bc7330f3088b894166bf3524a067e3d8;p=elogind.git diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c index 3e91d5c28..c4bcd4e16 100644 --- a/src/readahead/readahead-collect.c +++ b/src/readahead/readahead-collect.c @@ -86,6 +86,7 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { void *start = MAP_FAILED; uint8_t *vec; uint32_t b, c; + uint64_t inode; size_t l, pages; bool mapped; int r = 0, fd = -1, k; @@ -93,7 +94,8 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { assert(pack); assert(fn); - if ((fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW)) < 0) { + fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) { if (errno == ENOENT) return 0; @@ -106,7 +108,8 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { goto finish; } - if ((k = file_verify(fd, fn, arg_file_size_max, &st)) <= 0) { + k = file_verify(fd, fn, arg_file_size_max, &st); + if (k <= 0) { r = k; goto finish; } @@ -115,14 +118,14 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { btrfs_defrag(fd); l = PAGE_ALIGN(st.st_size); - if ((start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0); + if (start == MAP_FAILED) { log_warning("mmap(%s) failed: %m", fn); r = -errno; goto finish; } pages = l / page_size(); - vec = alloca(pages); memset(vec, 0, pages); if (mincore(start, l, vec) < 0) { @@ -134,6 +137,10 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { fputs(fn, pack); fputc('\n', pack); + /* Store the inode, so that we notice when the file is deleted */ + inode = (uint64_t) st.st_ino; + fwrite(&inode, sizeof(inode), 1, pack); + mapped = false; for (c = 0; c < pages; c++) { bool new_mapped = !!(vec[c] & 1); @@ -233,10 +240,25 @@ static int collect(const char *root) { bool on_ssd, on_btrfs; struct statfs sfs; usec_t not_after; + uint64_t previous_block_readahead; + bool previous_block_readahead_set = false; assert(root); - write_one_line_file("/proc/self/oom_score_adj", "1000"); + if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + /* If there's no pack file yet we lower the kernel readahead + * so that mincore() is accurate. If there is a pack file + * already we assume it is accurate enough so that kernel + * readahead is never triggered. */ + previous_block_readahead_set = + access(pack_fn, F_OK) < 0 && + block_get_readahead(root, &previous_block_readahead) >= 0 && + block_set_readahead(root, 8*1024) >= 0; if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0) log_warning("Failed to set IDLE IO priority class: %m"); @@ -458,22 +480,20 @@ done: on_btrfs = statfs(root, &sfs) >= 0 && (long) sfs.f_type == (long) BTRFS_SUPER_MAGIC; log_debug("On btrfs: %s", yes_no(on_btrfs)); - asprintf(&pack_fn, "%s/.readahead", root); - asprintf(&pack_fn_new, "%s/.readahead.new", root); - - if (!pack_fn || !pack_fn_new) { + if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) { log_error("Out of memory"); r = -ENOMEM; goto finish; } - if (!(pack = fopen(pack_fn_new, "we"))) { + pack = fopen(pack_fn_new, "we"); + if (!pack) { log_error("Failed to open pack file: %m"); r = -errno; goto finish; } - fputs(CANONICAL_HOST "\n", pack); + fputs(CANONICAL_HOST READAHEAD_PACK_FILE_VERSION, pack); putc(on_ssd ? 'S' : 'R', pack); if (on_ssd || on_btrfs) { @@ -551,7 +571,6 @@ finish: fclose(pack); unlink(pack_fn_new); } - free(pack_fn_new); free(pack_fn); @@ -560,6 +579,16 @@ finish: hashmap_free(files); + if (previous_block_readahead_set) { + uint64_t bytes; + + /* Restore the original kernel readahead setting if we + * changed it, and nobody has overwritten it since + * yet. */ + if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024) + block_set_readahead(root, previous_block_readahead); + } + return r; } @@ -654,17 +683,23 @@ int main(int argc, char *argv[]) { int r; const char *root; - log_set_target(LOG_TARGET_AUTO); + log_set_target(LOG_TARGET_SAFE); log_parse_environment(); log_open(); umask(0022); - if ((r = parse_argv(argc, argv)) <= 0) + r = parse_argv(argc, argv); + if (r <= 0) return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; root = optind < argc ? argv[optind] : "/"; + /* Skip this step on read-only media. Note that we check the + * underlying block device here, not he read-only flag of the + * file system on top, since that one is most likely mounted + * read-only anyway at boot, even if the underlying block + * device is theoretically writable. */ if (fs_on_read_only(root) > 0) { log_info("Disabling readahead collector due to read-only media."); return 0; @@ -675,12 +710,8 @@ int main(int argc, char *argv[]) { return 0; } - if (detect_virtualization(NULL) > 0) { - log_info("Disabling readahead collector due to execution in virtualized environment."); - return 0; - } - - if (!(shared = shared_get())) + shared = shared_get(); + if (!shared) return 1; shared->collect = getpid();