blob: 8dc194257f07446588a28027456c0191e448ee5b [file] [log] [blame] [raw]
Lennart Poettering22be0932010-09-23 15:01:41 +02001/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
Lennart Poettering5430f7f2012-04-12 00:20:58 +02009 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
Lennart Poettering22be0932010-09-23 15:01:41 +020011 (at your option) any later version.
12
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
Lennart Poettering5430f7f2012-04-12 00:20:58 +020016 Lesser General Public License for more details.
Lennart Poettering22be0932010-09-23 15:01:41 +020017
Lennart Poettering5430f7f2012-04-12 00:20:58 +020018 You should have received a copy of the GNU Lesser General Public License
Lennart Poettering22be0932010-09-23 15:01:41 +020019 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <inttypes.h>
24#include <fcntl.h>
25#include <linux/limits.h>
26#include <stdbool.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/select.h>
31#include <sys/time.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
Lennart Poettering82603582010-09-25 15:39:38 +020035#include <getopt.h>
Lennart Poettering66247682010-09-26 15:50:14 +020036#include <sys/inotify.h>
Lennart Poettering22be0932010-09-23 15:01:41 +020037
Lennart Poettering81527be2012-01-05 16:01:58 +010038#include <systemd/sd-daemon.h>
39
Lennart Poettering22be0932010-09-23 15:01:41 +020040#include "missing.h"
41#include "util.h"
42#include "set.h"
Lennart Poettering22be0932010-09-23 15:01:41 +020043#include "ioprio.h"
44#include "readahead-common.h"
Lennart Poetteringb52aae12011-09-23 17:00:33 +020045#include "virt.h"
Lennart Poettering82603582010-09-25 15:39:38 +020046
Lennart Poetteringd9c7a872010-09-28 21:46:14 +020047static ReadaheadShared *shared = NULL;
48
Lennart Poettering22be0932010-09-23 15:01:41 +020049static int unpack_file(FILE *pack) {
50 char fn[PATH_MAX];
51 int r = 0, fd = -1;
52 bool any = false;
53 struct stat st;
Lennart Poettering189455a2012-05-04 00:34:12 +020054 uint64_t inode;
Lennart Poettering22be0932010-09-23 15:01:41 +020055
56 assert(pack);
57
58 if (!fgets(fn, sizeof(fn), pack))
59 return 0;
60
61 char_array_0(fn);
62 truncate_nl(fn);
63
Lennart Poettering189455a2012-05-04 00:34:12 +020064 fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW);
65 if (fd < 0) {
Lennart Poetteringa78899f2011-01-04 23:42:58 +010066
Lennart Poettering1c981ff2013-01-03 22:37:38 +010067 if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP)
Lennart Poetteringa78899f2011-01-04 23:42:58 +010068 log_warning("open(%s) failed: %m", fn);
69
Lennart Poettering03e334a2014-03-18 19:22:43 +010070 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0)
71 fd = safe_close(fd);
Lennart Poettering189455a2012-05-04 00:34:12 +020072
73 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
74 log_error("Premature end of pack file.");
75 r = -EIO;
76 goto finish;
77 }
78
79 if (fd >= 0) {
80 /* If the inode changed the file got deleted, so just
81 * ignore this entry */
Lennart Poettering03e334a2014-03-18 19:22:43 +010082 if (st.st_ino != (uint64_t) inode)
83 fd = safe_close(fd);
Lennart Poettering22be0932010-09-23 15:01:41 +020084 }
85
86 for (;;) {
87 uint32_t b, c;
88
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.");
92 r = -EIO;
93 goto finish;
94 }
95
96 if (b == 0 && c == 0)
97 break;
98
99 if (c <= b) {
100 log_error("Invalid pack file.");
101 r = -EIO;
102 goto finish;
103 }
104
105 log_debug("%s: page %u to %u", fn, b, c);
106
107 any = true;
108
109 if (fd >= 0)
cee137f85e62011-03-18 10:03:41 +0800110 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
Harald Hoyer6e667972010-09-24 12:54:05 +0200111 log_warning("posix_fadvise() failed: %m");
Lennart Poettering22be0932010-09-23 15:01:41 +0200112 goto finish;
113 }
114 }
115
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
119 * read */
120
Harald Hoyer6e667972010-09-24 12:54:05 +0200121 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
122 log_warning("posix_fadvise() failed: %m");
Lennart Poettering22be0932010-09-23 15:01:41 +0200123 goto finish;
124 }
125 }
126
127finish:
Lennart Poettering03e334a2014-03-18 19:22:43 +0100128 safe_close(fd);
Lennart Poettering22be0932010-09-23 15:01:41 +0200129
130 return r;
131}
132
133static int replay(const char *root) {
Lennart Poettering858209c2010-09-27 03:24:39 +0200134 FILE *pack = NULL;
Lennart Poettering22be0932010-09-23 15:01:41 +0200135 char line[LINE_MAX];
136 int r = 0;
Lennart Poetteringda19d5c2011-03-31 15:35:40 +0200137 char *pack_fn = NULL;
138 int c;
Lennart Poettering902a3392010-09-25 13:47:31 +0200139 bool on_ssd, ready = false;
Lennart Poettering22be0932010-09-23 15:01:41 +0200140 int prio;
Lennart Poettering66247682010-09-26 15:50:14 +0200141 int inotify_fd = -1;
Lennart Poettering22be0932010-09-23 15:01:41 +0200142
143 assert(root);
144
Lennart Poettering6de338a2012-05-04 00:13:20 +0200145 block_bump_request_nr(root);
Lennart Poettering75a010e2010-09-25 14:35:34 +0200146
Lennart Poettering22be0932010-09-23 15:01:41 +0200147 if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
Shawn Landden0d0f0c52012-07-25 14:55:59 -0700148 r = log_oom();
Lennart Poettering22be0932010-09-23 15:01:41 +0200149 goto finish;
150 }
151
Lennart Poetteringebfb7502012-06-22 00:03:25 +0200152 pack = fopen(pack_fn, "re");
153 if (!pack) {
Lennart Poetteringa78899f2011-01-04 23:42:58 +0100154 if (errno == ENOENT)
Lennart Poettering22be0932010-09-23 15:01:41 +0200155 log_debug("No pack file found.");
156 else {
157 log_error("Failed to open pack file: %m");
158 r = -errno;
159 }
160
Lennart Poettering66247682010-09-26 15:50:14 +0200161 goto finish;
162 }
163
Lennart Poetteringbdb0e142010-09-29 03:11:35 +0200164 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
165
Lennart Poettering66247682010-09-26 15:50:14 +0200166 if ((inotify_fd = open_inotify()) < 0) {
167 r = inotify_fd;
Lennart Poettering22be0932010-09-23 15:01:41 +0200168 goto finish;
169 }
170
171 if (!(fgets(line, sizeof(line), pack))) {
172 log_error("Premature end of pack file.");
173 r = -EIO;
174 goto finish;
175 }
176
177 char_array_0(line);
178
Auke Kokcae544b2012-06-05 13:32:20 -0700179 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
Lennart Poettering189455a2012-05-04 00:34:12 +0200180 log_debug("Pack file host or version type mismatch.");
Lennart Poettering22be0932010-09-23 15:01:41 +0200181 goto finish;
182 }
183
184 if ((c = getc(pack)) == EOF) {
185 log_debug("Premature end of pack file.");
186 r = -EIO;
187 goto finish;
188 }
189
190 /* We do not retest SSD here, so that we can start replaying
191 * before udev is up.*/
192 on_ssd = c == 'S';
193 log_debug("On SSD: %s", yes_no(on_ssd));
194
195 if (on_ssd)
196 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
197 else
Lennart Poettering05aa9ed2012-01-21 02:51:13 +0100198 /* 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);
Lennart Poettering22be0932010-09-23 15:01:41 +0200205
206 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
207 log_warning("Failed to set IDLE IO priority class: %m");
208
Lennart Poettering902a3392010-09-25 13:47:31 +0200209 sd_notify(0, "STATUS=Replaying readahead data");
Lennart Poettering22be0932010-09-23 15:01:41 +0200210
211 log_debug("Replaying...");
212
Kay Sievers2b583ce2011-03-25 05:07:20 +0100213 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
Lennart Poettering66247682010-09-26 15:50:14 +0200214 log_debug("Got termination request");
215 goto done;
216 }
217
Lennart Poettering22be0932010-09-23 15:01:41 +0200218 while (!feof(pack) && !ferror(pack)) {
Lennart Poettering66247682010-09-26 15:50:14 +0200219 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
Lennart Poettering22be0932010-09-23 15:01:41 +0200220 int k;
Lennart Poettering66247682010-09-26 15:50:14 +0200221 ssize_t n;
222
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");
226 r = -errno;
227 goto finish;
228 }
229 } else {
230 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
231
232 while (n > 0) {
233 size_t step;
234
235 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
236 log_debug("Got termination request");
237 goto done;
238 }
239
240 step = sizeof(struct inotify_event) + e->len;
241 assert(step <= (size_t) n);
242
243 e = (struct inotify_event*) ((uint8_t*) e + step);
244 n -= step;
245 }
246 }
Lennart Poettering22be0932010-09-23 15:01:41 +0200247
248 if ((k = unpack_file(pack)) < 0) {
249 r = k;
250 goto finish;
251 }
Lennart Poettering902a3392010-09-25 13:47:31 +0200252
253 if (!ready) {
254 /* We delay the ready notification until we
255 * queued at least one read */
256 sd_notify(0, "READY=1");
257 ready = true;
258 }
Lennart Poettering22be0932010-09-23 15:01:41 +0200259 }
260
Lennart Poettering66247682010-09-26 15:50:14 +0200261done:
Lennart Poettering902a3392010-09-25 13:47:31 +0200262 if (!ready)
263 sd_notify(0, "READY=1");
264
Lennart Poettering22be0932010-09-23 15:01:41 +0200265 if (ferror(pack)) {
266 log_error("Failed to read pack file.");
267 r = -EIO;
268 goto finish;
269 }
270
271 log_debug("Done.");
272
273finish:
274 if (pack)
275 fclose(pack);
276
Lennart Poettering03e334a2014-03-18 19:22:43 +0100277 safe_close(inotify_fd);
Lennart Poettering66247682010-09-26 15:50:14 +0200278
Lennart Poettering22be0932010-09-23 15:01:41 +0200279 free(pack_fn);
280
281 return r;
282}
283
Lennart Poettering87ce22c2012-06-21 23:53:20 +0200284int main_replay(const char *root) {
Lennart Poettering82603582010-09-25 15:39:38 +0200285
Lennart Poettering87ce22c2012-06-21 23:53:20 +0200286 if (!root)
287 root = "/";
Lennart Poettering22be0932010-09-23 15:01:41 +0200288
Lennart Poettering41a598e2010-09-25 13:32:54 +0200289 if (!enough_ram()) {
290 log_info("Disabling readahead replay due to low memory.");
Lennart Poettering87ce22c2012-06-21 23:53:20 +0200291 return EXIT_SUCCESS;
Lennart Poettering41a598e2010-09-25 13:32:54 +0200292 }
293
Lennart Poettering3b2d5b02012-04-24 13:12:29 +0200294 shared = shared_get();
295 if (!shared)
Lennart Poettering87ce22c2012-06-21 23:53:20 +0200296 return EXIT_FAILURE;
Lennart Poetteringd9c7a872010-09-28 21:46:14 +0200297
298 shared->replay = getpid();
299 __sync_synchronize();
300
Lennart Poettering2b590e12011-03-03 23:03:26 +0100301 if (replay(root) < 0)
Lennart Poettering87ce22c2012-06-21 23:53:20 +0200302 return EXIT_FAILURE;
Lennart Poettering22be0932010-09-23 15:01:41 +0200303
Lennart Poettering87ce22c2012-06-21 23:53:20 +0200304 return EXIT_SUCCESS;
Lennart Poettering22be0932010-09-23 15:01:41 +0200305}