1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <linux/limits.h>
30 #include <sys/select.h>
32 #include <sys/types.h>
36 #include <sys/inotify.h>
38 #include <systemd/sd-daemon.h>
44 #include "readahead-common.h"
47 static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
49 static ReadaheadShared *shared = NULL;
51 static int unpack_file(FILE *pack) {
60 if (!fgets(fn, sizeof(fn), pack))
66 fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW);
69 if (errno != ENOENT && errno != EPERM && errno != EACCES)
70 log_warning("open(%s) failed: %m", fn);
72 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) {
73 close_nointr_nofail(fd);
77 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
78 log_error("Premature end of pack file.");
84 /* If the inode changed the file got deleted, so just
85 * ignore this entry */
86 if (st.st_ino != (uint64_t) inode) {
87 close_nointr_nofail(fd);
95 if (fread(&b, sizeof(b), 1, pack) != 1 ||
96 fread(&c, sizeof(c), 1, pack) != 1) {
97 log_error("Premature end of pack file.");
102 if (b == 0 && c == 0)
106 log_error("Invalid pack file.");
111 log_debug("%s: page %u to %u", fn, b, c);
116 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
117 log_warning("posix_fadvise() failed: %m");
122 if (!any && fd >= 0) {
123 /* if no range is encoded in the pack file this is
124 * intended to mean that the whole file shall be
127 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
128 log_warning("posix_fadvise() failed: %m");
135 close_nointr_nofail(fd);
140 static int replay(const char *root) {
144 char *pack_fn = NULL;
146 bool on_ssd, ready = false;
152 block_bump_request_nr(root);
154 if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
155 log_error("Out of memory");
160 if ((!(pack = fopen(pack_fn, "re")))) {
162 log_debug("No pack file found.");
164 log_error("Failed to open pack file: %m");
171 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
173 if ((inotify_fd = open_inotify()) < 0) {
178 if (!(fgets(line, sizeof(line), pack))) {
179 log_error("Premature end of pack file.");
186 if (!streq(line, CANONICAL_HOST ";VERSION=2\n")) {
187 log_debug("Pack file host or version type mismatch.");
191 if ((c = getc(pack)) == EOF) {
192 log_debug("Premature end of pack file.");
197 /* We do not retest SSD here, so that we can start replaying
198 * before udev is up.*/
200 log_debug("On SSD: %s", yes_no(on_ssd));
203 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
205 /* We are not using RT here, since we'd starve IO that
206 we didn't record (which is for example blkid, since
207 its disk accesses go directly to the block device and
208 are thus not visible in fallocate) to death. However,
209 we do ask for an IO prio that is slightly higher than
210 the default (which is BE. 4) */
211 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);
213 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
214 log_warning("Failed to set IDLE IO priority class: %m");
216 sd_notify(0, "STATUS=Replaying readahead data");
218 log_debug("Replaying...");
220 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
221 log_debug("Got termination request");
225 while (!feof(pack) && !ferror(pack)) {
226 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
230 if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
231 if (errno != EINTR && errno != EAGAIN) {
232 log_error("Failed to read inotify event: %m");
237 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
242 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
243 log_debug("Got termination request");
247 step = sizeof(struct inotify_event) + e->len;
248 assert(step <= (size_t) n);
250 e = (struct inotify_event*) ((uint8_t*) e + step);
255 if ((k = unpack_file(pack)) < 0) {
261 /* We delay the ready notification until we
262 * queued at least one read */
263 sd_notify(0, "READY=1");
270 sd_notify(0, "READY=1");
273 log_error("Failed to read pack file.");
285 close_nointr_nofail(inotify_fd);
293 static int help(void) {
295 printf("%s [OPTIONS...] [DIRECTORY]\n\n"
296 "Replay collected read-ahead data on early boot.\n\n"
297 " -h --help Show this help\n"
298 " --max-file-size=BYTES Maximum size of files to read ahead\n",
299 program_invocation_short_name);
304 static int parse_argv(int argc, char *argv[]) {
310 static const struct option options[] = {
311 { "help", no_argument, NULL, 'h' },
312 { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX },
321 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
329 case ARG_FILE_SIZE_MAX: {
330 unsigned long long ull;
332 if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
333 log_error("Failed to parse maximum file size %s.", optarg);
337 arg_file_size_max = (off_t) ull;
345 log_error("Unknown option code %c", c);
350 if (optind != argc &&
359 int main(int argc, char*argv[]) {
363 log_set_target(LOG_TARGET_AUTO);
364 log_parse_environment();
369 r = parse_argv(argc, argv);
371 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
373 root = optind < argc ? argv[optind] : "/";
376 log_info("Disabling readahead replay due to low memory.");
380 shared = shared_get();
384 shared->replay = getpid();
385 __sync_synchronize();
387 if (replay(root) < 0)