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)
68 log_warning("open(%s) failed: %m", fn);
70 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) {
71 close_nointr_nofail(fd);
75 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
76 log_error("Premature end of pack file.");
82 /* If the inode changed the file got deleted, so just
83 * ignore this entry */
84 if (st.st_ino != (uint64_t) inode) {
85 close_nointr_nofail(fd);
93 if (fread(&b, sizeof(b), 1, pack) != 1 ||
94 fread(&c, sizeof(c), 1, pack) != 1) {
95 log_error("Premature end of pack file.");
100 if (b == 0 && c == 0)
104 log_error("Invalid pack file.");
109 log_debug("%s: page %u to %u", fn, b, c);
114 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
115 log_warning("posix_fadvise() failed: %m");
120 if (!any && fd >= 0) {
121 /* if no range is encoded in the pack file this is
122 * intended to mean that the whole file shall be
125 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
126 log_warning("posix_fadvise() failed: %m");
133 close_nointr_nofail(fd);
138 static int replay(const char *root) {
142 char *pack_fn = NULL;
144 bool on_ssd, ready = false;
150 block_bump_request_nr(root);
152 if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
153 log_error("Out of memory");
158 pack = fopen(pack_fn, "re");
161 log_debug("No pack file found.");
163 log_error("Failed to open pack file: %m");
170 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
172 if ((inotify_fd = open_inotify()) < 0) {
177 if (!(fgets(line, sizeof(line), pack))) {
178 log_error("Premature end of pack file.");
185 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
186 log_debug("Pack file host or version type mismatch.");
190 if ((c = getc(pack)) == EOF) {
191 log_debug("Premature end of pack file.");
196 /* We do not retest SSD here, so that we can start replaying
197 * before udev is up.*/
199 log_debug("On SSD: %s", yes_no(on_ssd));
202 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
204 /* We are not using RT here, since we'd starve IO that
205 we didn't record (which is for example blkid, since
206 its disk accesses go directly to the block device and
207 are thus not visible in fallocate) to death. However,
208 we do ask for an IO prio that is slightly higher than
209 the default (which is BE. 4) */
210 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);
212 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
213 log_warning("Failed to set IDLE IO priority class: %m");
215 sd_notify(0, "STATUS=Replaying readahead data");
217 log_debug("Replaying...");
219 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
220 log_debug("Got termination request");
224 while (!feof(pack) && !ferror(pack)) {
225 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
229 if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
230 if (errno != EINTR && errno != EAGAIN) {
231 log_error("Failed to read inotify event: %m");
236 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
241 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
242 log_debug("Got termination request");
246 step = sizeof(struct inotify_event) + e->len;
247 assert(step <= (size_t) n);
249 e = (struct inotify_event*) ((uint8_t*) e + step);
254 if ((k = unpack_file(pack)) < 0) {
260 /* We delay the ready notification until we
261 * queued at least one read */
262 sd_notify(0, "READY=1");
269 sd_notify(0, "READY=1");
272 log_error("Failed to read pack file.");
284 close_nointr_nofail(inotify_fd);
291 int main_replay(const char *root) {
297 log_info("Disabling readahead replay due to low memory.");
301 shared = shared_get();
305 shared->replay = getpid();
306 __sync_synchronize();
308 if (replay(root) < 0)