]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/readahead/readahead-replay.c
use "Out of memory." consistantly (or with "\n")
[thirdparty/systemd.git] / src / readahead / readahead-replay.c
CommitLineData
22be093f
LP
1/*-*- 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
5430f7f2
LP
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
22be093f
LP
11 (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
5430f7f2 16 Lesser General Public License for more details.
22be093f 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
22be093f
LP
19 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>
8260358d 35#include <getopt.h>
6624768c 36#include <sys/inotify.h>
22be093f 37
81527be1
LP
38#include <systemd/sd-daemon.h>
39
22be093f
LP
40#include "missing.h"
41#include "util.h"
42#include "set.h"
22be093f
LP
43#include "ioprio.h"
44#include "readahead-common.h"
b52aae1d 45#include "virt.h"
22be093f 46
d9c7a87b
LP
47static ReadaheadShared *shared = NULL;
48
22be093f
LP
49static int unpack_file(FILE *pack) {
50 char fn[PATH_MAX];
51 int r = 0, fd = -1;
52 bool any = false;
53 struct stat st;
189455ab 54 uint64_t inode;
22be093f
LP
55
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
189455ab
LP
64 fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW);
65 if (fd < 0) {
a78899f5 66
a76fad09 67 if (errno != ENOENT && errno != EPERM && errno != EACCES)
a78899f5
LP
68 log_warning("open(%s) failed: %m", fn);
69
70 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) {
22be093f
LP
71 close_nointr_nofail(fd);
72 fd = -1;
73 }
74
189455ab
LP
75 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
76 log_error("Premature end of pack file.");
77 r = -EIO;
78 goto finish;
79 }
80
81 if (fd >= 0) {
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);
86 fd = -1;
87 }
88 }
89
22be093f
LP
90 for (;;) {
91 uint32_t b, c;
92
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.");
96 r = -EIO;
97 goto finish;
98 }
99
100 if (b == 0 && c == 0)
101 break;
102
103 if (c <= b) {
104 log_error("Invalid pack file.");
105 r = -EIO;
106 goto finish;
107 }
108
109 log_debug("%s: page %u to %u", fn, b, c);
110
111 any = true;
112
113 if (fd >= 0)
37f85e66 114 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
6e66797a 115 log_warning("posix_fadvise() failed: %m");
22be093f
LP
116 goto finish;
117 }
118 }
119
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
123 * read */
124
6e66797a
HH
125 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
126 log_warning("posix_fadvise() failed: %m");
22be093f
LP
127 goto finish;
128 }
129 }
130
131finish:
132 if (fd >= 0)
133 close_nointr_nofail(fd);
134
135 return r;
136}
137
138static int replay(const char *root) {
858209c5 139 FILE *pack = NULL;
22be093f
LP
140 char line[LINE_MAX];
141 int r = 0;
da19d5c1
LP
142 char *pack_fn = NULL;
143 int c;
902a339c 144 bool on_ssd, ready = false;
22be093f 145 int prio;
6624768c 146 int inotify_fd = -1;
22be093f
LP
147
148 assert(root);
149
6de338a2 150 block_bump_request_nr(root);
75a010e0 151
22be093f 152 if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
669241a0 153 log_error("Out of memory.");
22be093f
LP
154 r = -ENOMEM;
155 goto finish;
156 }
157
ebfb7506
LP
158 pack = fopen(pack_fn, "re");
159 if (!pack) {
a78899f5 160 if (errno == ENOENT)
22be093f
LP
161 log_debug("No pack file found.");
162 else {
163 log_error("Failed to open pack file: %m");
164 r = -errno;
165 }
166
167 goto finish;
168 }
169
bdb0e14d
LP
170 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
171
6624768c
LP
172 if ((inotify_fd = open_inotify()) < 0) {
173 r = inotify_fd;
174 goto finish;
175 }
176
22be093f
LP
177 if (!(fgets(line, sizeof(line), pack))) {
178 log_error("Premature end of pack file.");
179 r = -EIO;
180 goto finish;
181 }
182
183 char_array_0(line);
184
cae544bc 185 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
189455ab 186 log_debug("Pack file host or version type mismatch.");
22be093f
LP
187 goto finish;
188 }
189
190 if ((c = getc(pack)) == EOF) {
191 log_debug("Premature end of pack file.");
192 r = -EIO;
193 goto finish;
194 }
195
196 /* We do not retest SSD here, so that we can start replaying
197 * before udev is up.*/
198 on_ssd = c == 'S';
199 log_debug("On SSD: %s", yes_no(on_ssd));
200
201 if (on_ssd)
202 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
203 else
05aa9edd
LP
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);
22be093f
LP
211
212 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
213 log_warning("Failed to set IDLE IO priority class: %m");
214
902a339c 215 sd_notify(0, "STATUS=Replaying readahead data");
22be093f
LP
216
217 log_debug("Replaying...");
218
2b583ce6 219 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
6624768c
LP
220 log_debug("Got termination request");
221 goto done;
222 }
223
22be093f 224 while (!feof(pack) && !ferror(pack)) {
6624768c 225 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
22be093f 226 int k;
6624768c
LP
227 ssize_t n;
228
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");
232 r = -errno;
233 goto finish;
234 }
235 } else {
236 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
237
238 while (n > 0) {
239 size_t step;
240
241 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
242 log_debug("Got termination request");
243 goto done;
244 }
245
246 step = sizeof(struct inotify_event) + e->len;
247 assert(step <= (size_t) n);
248
249 e = (struct inotify_event*) ((uint8_t*) e + step);
250 n -= step;
251 }
252 }
22be093f
LP
253
254 if ((k = unpack_file(pack)) < 0) {
255 r = k;
256 goto finish;
257 }
902a339c
LP
258
259 if (!ready) {
260 /* We delay the ready notification until we
261 * queued at least one read */
262 sd_notify(0, "READY=1");
263 ready = true;
264 }
22be093f
LP
265 }
266
6624768c 267done:
902a339c
LP
268 if (!ready)
269 sd_notify(0, "READY=1");
270
22be093f
LP
271 if (ferror(pack)) {
272 log_error("Failed to read pack file.");
273 r = -EIO;
274 goto finish;
275 }
276
277 log_debug("Done.");
278
279finish:
280 if (pack)
281 fclose(pack);
282
6624768c
LP
283 if (inotify_fd >= 0)
284 close_nointr_nofail(inotify_fd);
285
22be093f
LP
286 free(pack_fn);
287
288 return r;
289}
290
87ce22cc 291int main_replay(const char *root) {
8260358d 292
87ce22cc
LP
293 if (!root)
294 root = "/";
2b590e13 295
41a598e2
LP
296 if (!enough_ram()) {
297 log_info("Disabling readahead replay due to low memory.");
87ce22cc 298 return EXIT_SUCCESS;
41a598e2
LP
299 }
300
3b2d5b02
LP
301 shared = shared_get();
302 if (!shared)
87ce22cc 303 return EXIT_FAILURE;
d9c7a87b
LP
304
305 shared->replay = getpid();
306 __sync_synchronize();
307
2b590e13 308 if (replay(root) < 0)
87ce22cc 309 return EXIT_FAILURE;
22be093f 310
87ce22cc 311 return EXIT_SUCCESS;
22be093f 312}