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) {
58 if (!fgets(fn, sizeof(fn), pack))
64 fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW);
67 if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP)
68 log_warning("open(%s) failed: %m", fn);
70 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0)
73 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
74 log_error("Premature end of pack file.");
80 /* If the inode changed the file got deleted, so just
81 * ignore this entry */
82 if (st.st_ino != (uint64_t) inode)
89 if (fread(&b, sizeof(b), 1, pack) != 1 ||
90 fread(&c, sizeof(c), 1, pack) != 1) {
91 log_error("Premature end of pack file.");
100 log_error("Invalid pack file.");
105 log_debug("%s: page %u to %u", fn, b, c);
110 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
111 log_warning("posix_fadvise() failed: %m");
116 if (!any && fd >= 0) {
117 /* if no range is encoded in the pack file this is
118 * intended to mean that the whole file shall be
121 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
122 log_warning("posix_fadvise() failed: %m");
133 static int replay(const char *root) {
137 char *pack_fn = NULL;
139 bool on_ssd, ready = false;
145 block_bump_request_nr(root);
147 if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
152 pack = fopen(pack_fn, "re");
155 log_debug("No pack file found.");
157 log_error("Failed to open pack file: %m");
164 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
166 if ((inotify_fd = open_inotify()) < 0) {
171 if (!(fgets(line, sizeof(line), pack))) {
172 log_error("Premature end of pack file.");
179 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
180 log_debug("Pack file host or version type mismatch.");
184 if ((c = getc(pack)) == EOF) {
185 log_debug("Premature end of pack file.");
190 /* We do not retest SSD here, so that we can start replaying
191 * before udev is up.*/
193 log_debug("On SSD: %s", yes_no(on_ssd));
196 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
198 /* We are not using RT here, since we'd starve IO that
199 we didn't record (which is for example blkid, since
200 its disk accesses go directly to the block device and
201 are thus not visible in fallocate) to death. However,
202 we do ask for an IO prio that is slightly higher than
203 the default (which is BE. 4) */
204 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);
206 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
207 log_warning("Failed to set IDLE IO priority class: %m");
209 sd_notify(0, "STATUS=Replaying readahead data");
211 log_debug("Replaying...");
213 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
214 log_debug("Got termination request");
218 while (!feof(pack) && !ferror(pack)) {
219 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
223 if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
224 if (errno != EINTR && errno != EAGAIN) {
225 log_error("Failed to read inotify event: %m");
230 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
235 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
236 log_debug("Got termination request");
240 step = sizeof(struct inotify_event) + e->len;
241 assert(step <= (size_t) n);
243 e = (struct inotify_event*) ((uint8_t*) e + step);
248 if ((k = unpack_file(pack)) < 0) {
254 /* We delay the ready notification until we
255 * queued at least one read */
256 sd_notify(0, "READY=1");
263 sd_notify(0, "READY=1");
266 log_error("Failed to read pack file.");
277 safe_close(inotify_fd);
284 int main_replay(const char *root) {
290 log_info("Disabling readahead replay due to low memory.");
294 shared = shared_get();
298 shared->replay = getpid();
299 __sync_synchronize();
301 if (replay(root) < 0)