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 ReadaheadShared *shared = NULL;
49 static int unpack_file(FILE *pack) {
50 _cleanup_close_ int fd = -1;
58 if (!fgets(fn, sizeof(fn), pack))
64 fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW);
66 if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP)
67 log_warning("open(%s) failed: %m", fn);
69 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0)
72 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
73 log_error("Premature end of pack file.");
78 /* If the inode changed the file got deleted, so just
79 * ignore this entry */
80 if (st.st_ino != (uint64_t) inode)
87 if (fread(&b, sizeof(b), 1, pack) != 1 ||
88 fread(&c, sizeof(c), 1, pack) != 1) {
89 log_error("Premature end of pack file.");
97 log_error("Invalid pack file.");
101 log_debug("%s: page %u to %u", fn, b, c);
106 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
107 log_warning("posix_fadvise() failed: %m");
113 if (!any && fd >= 0) {
114 /* if no range is encoded in the pack file this is
115 * intended to mean that the whole file shall be
118 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
119 log_warning("posix_fadvise() failed: %m");
127 static int replay(const char *root) {
128 _cleanup_close_ int inotify_fd = -1;
129 _cleanup_free_ char *pack_fn = NULL;
130 _cleanup_fclose_ FILE *pack = NULL;
131 bool on_ssd, ready = false;
137 block_bump_request_nr(root);
139 if (asprintf(&pack_fn, "%s/.readahead", root) < 0)
142 pack = fopen(pack_fn, "re");
144 if (errno == ENOENT) {
145 log_debug("No pack file found.");
149 log_error("Failed to open pack file: %m");
153 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
155 inotify_fd = open_inotify();
159 if (!fgets(line, sizeof(line), pack)) {
160 log_error("Premature end of pack file.");
166 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
167 log_debug("Pack file host or version type mismatch.");
173 log_debug("Premature end of pack file.");
177 /* We do not retest SSD here, so that we can start replaying
178 * before udev is up.*/
180 log_debug("On SSD: %s", yes_no(on_ssd));
183 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
185 /* We are not using RT here, since we'd starve IO that
186 we didn't record (which is for example blkid, since
187 its disk accesses go directly to the block device and
188 are thus not visible in fallocate) to death. However,
189 we do ask for an IO prio that is slightly higher than
190 the default (which is BE. 4) */
191 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);
193 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
194 log_warning("Failed to set IDLE IO priority class: %m");
196 sd_notify(0, "STATUS=Replaying readahead data");
198 log_debug("Replaying...");
200 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
201 log_debug("Got termination request");
205 while (!feof(pack) && !ferror(pack)) {
206 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
210 n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer));
212 if (errno != EINTR && errno != EAGAIN) {
213 log_error("Failed to read inotify event: %m");
217 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
222 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
223 log_debug("Got termination request");
227 step = sizeof(struct inotify_event) + e->len;
228 assert(step <= (size_t) n);
230 e = (struct inotify_event*) ((uint8_t*) e + step);
235 k = unpack_file(pack);
240 /* We delay the ready notification until we
241 * queued at least one read */
242 sd_notify(0, "READY=1");
249 log_error("Failed to read pack file.");
254 sd_notify(0, "READY=1");
260 int main_replay(const char *root) {
266 log_info("Disabling readahead replay due to low memory.");
270 shared = shared_get();
274 shared->replay = getpid();
275 __sync_synchronize();
277 if (replay(root) < 0)