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) {
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) {
157 pack = fopen(pack_fn, "re");
160 log_debug("No pack file found.");
162 log_error("Failed to open pack file: %m");
169 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
171 if ((inotify_fd = open_inotify()) < 0) {
176 if (!(fgets(line, sizeof(line), pack))) {
177 log_error("Premature end of pack file.");
184 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
185 log_debug("Pack file host or version type mismatch.");
189 if ((c = getc(pack)) == EOF) {
190 log_debug("Premature end of pack file.");
195 /* We do not retest SSD here, so that we can start replaying
196 * before udev is up.*/
198 log_debug("On SSD: %s", yes_no(on_ssd));
201 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
203 /* We are not using RT here, since we'd starve IO that
204 we didn't record (which is for example blkid, since
205 its disk accesses go directly to the block device and
206 are thus not visible in fallocate) to death. However,
207 we do ask for an IO prio that is slightly higher than
208 the default (which is BE. 4) */
209 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);
211 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
212 log_warning("Failed to set IDLE IO priority class: %m");
214 sd_notify(0, "STATUS=Replaying readahead data");
216 log_debug("Replaying...");
218 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
219 log_debug("Got termination request");
223 while (!feof(pack) && !ferror(pack)) {
224 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
228 if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
229 if (errno != EINTR && errno != EAGAIN) {
230 log_error("Failed to read inotify event: %m");
235 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
240 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
241 log_debug("Got termination request");
245 step = sizeof(struct inotify_event) + e->len;
246 assert(step <= (size_t) n);
248 e = (struct inotify_event*) ((uint8_t*) e + step);
253 if ((k = unpack_file(pack)) < 0) {
259 /* We delay the ready notification until we
260 * queued at least one read */
261 sd_notify(0, "READY=1");
268 sd_notify(0, "READY=1");
271 log_error("Failed to read pack file.");
283 close_nointr_nofail(inotify_fd);
290 int main_replay(const char *root) {
296 log_info("Disabling readahead replay due to low memory.");
300 shared = shared_get();
304 shared->replay = getpid();
305 __sync_synchronize();
307 if (replay(root) < 0)