]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/readahead/readahead-replay.c
readahead: modernizations
[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 49static int unpack_file(FILE *pack) {
a8c73b86 50 _cleanup_close_ int fd = -1;
22be093f 51 char fn[PATH_MAX];
22be093f
LP
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) {
1c981ff2 66 if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP)
a78899f5
LP
67 log_warning("open(%s) failed: %m", fn);
68
03e334a1
LP
69 } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0)
70 fd = safe_close(fd);
22be093f 71
189455ab
LP
72 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
73 log_error("Premature end of pack file.");
a8c73b86 74 return -EIO;
189455ab
LP
75 }
76
77 if (fd >= 0) {
78 /* If the inode changed the file got deleted, so just
79 * ignore this entry */
03e334a1
LP
80 if (st.st_ino != (uint64_t) inode)
81 fd = safe_close(fd);
189455ab
LP
82 }
83
22be093f
LP
84 for (;;) {
85 uint32_t b, c;
86
87 if (fread(&b, sizeof(b), 1, pack) != 1 ||
88 fread(&c, sizeof(c), 1, pack) != 1) {
89 log_error("Premature end of pack file.");
a8c73b86 90 return -EIO;
22be093f
LP
91 }
92
93 if (b == 0 && c == 0)
94 break;
95
96 if (c <= b) {
97 log_error("Invalid pack file.");
a8c73b86 98 return -EIO;
22be093f
LP
99 }
100
101 log_debug("%s: page %u to %u", fn, b, c);
102
103 any = true;
104
a8c73b86 105 if (fd >= 0) {
37f85e66 106 if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
6e66797a 107 log_warning("posix_fadvise() failed: %m");
a8c73b86 108 return -errno;
22be093f 109 }
a8c73b86 110 }
22be093f
LP
111 }
112
113 if (!any && fd >= 0) {
114 /* if no range is encoded in the pack file this is
115 * intended to mean that the whole file shall be
116 * read */
117
6e66797a
HH
118 if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
119 log_warning("posix_fadvise() failed: %m");
a8c73b86 120 return -errno;
22be093f
LP
121 }
122 }
123
a8c73b86 124 return 0;
22be093f
LP
125}
126
127static int replay(const char *root) {
a8c73b86
LP
128 _cleanup_close_ int inotify_fd = -1;
129 _cleanup_free_ char *pack_fn = NULL;
130 _cleanup_fclose_ FILE *pack = NULL;
902a339c 131 bool on_ssd, ready = false;
a8c73b86
LP
132 char line[LINE_MAX];
133 int prio, c;
22be093f
LP
134
135 assert(root);
136
6de338a2 137 block_bump_request_nr(root);
75a010e0 138
a8c73b86
LP
139 if (asprintf(&pack_fn, "%s/.readahead", root) < 0)
140 return log_oom();
22be093f 141
ebfb7506
LP
142 pack = fopen(pack_fn, "re");
143 if (!pack) {
a8c73b86 144 if (errno == ENOENT) {
22be093f 145 log_debug("No pack file found.");
a8c73b86 146 return 0;
22be093f
LP
147 }
148
a8c73b86
LP
149 log_error("Failed to open pack file: %m");
150 return -errno;
22be093f
LP
151 }
152
bdb0e14d
LP
153 posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);
154
a8c73b86
LP
155 inotify_fd = open_inotify();
156 if (inotify_fd < 0)
157 return inotify_fd;
6624768c 158
a8c73b86 159 if (!fgets(line, sizeof(line), pack)) {
22be093f 160 log_error("Premature end of pack file.");
a8c73b86 161 return -EIO;
22be093f
LP
162 }
163
164 char_array_0(line);
165
cae544bc 166 if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
189455ab 167 log_debug("Pack file host or version type mismatch.");
a8c73b86 168 goto done;
22be093f
LP
169 }
170
a8c73b86
LP
171 c = getc(pack);
172 if (c == EOF) {
22be093f 173 log_debug("Premature end of pack file.");
a8c73b86 174 return -EIO;
22be093f
LP
175 }
176
177 /* We do not retest SSD here, so that we can start replaying
178 * before udev is up.*/
179 on_ssd = c == 'S';
180 log_debug("On SSD: %s", yes_no(on_ssd));
181
182 if (on_ssd)
183 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
184 else
05aa9edd
LP
185 /* We are not using RT here, since we'd starve IO that
186 we didn't record (which is for example blkid, since
187 its disk accesses go directly to the block device and
188 are thus not visible in fallocate) to death. However,
189 we do ask for an IO prio that is slightly higher than
190 the default (which is BE. 4) */
191 prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);
22be093f
LP
192
193 if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
194 log_warning("Failed to set IDLE IO priority class: %m");
195
902a339c 196 sd_notify(0, "STATUS=Replaying readahead data");
22be093f
LP
197
198 log_debug("Replaying...");
199
2b583ce6 200 if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
6624768c
LP
201 log_debug("Got termination request");
202 goto done;
203 }
204
22be093f 205 while (!feof(pack) && !ferror(pack)) {
6624768c 206 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
22be093f 207 int k;
6624768c
LP
208 ssize_t n;
209
a8c73b86
LP
210 n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer));
211 if (n < 0) {
6624768c
LP
212 if (errno != EINTR && errno != EAGAIN) {
213 log_error("Failed to read inotify event: %m");
a8c73b86 214 return -errno;
6624768c
LP
215 }
216 } else {
217 struct inotify_event *e = (struct inotify_event*) inotify_buffer;
218
219 while (n > 0) {
220 size_t step;
221
222 if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
223 log_debug("Got termination request");
224 goto done;
225 }
226
227 step = sizeof(struct inotify_event) + e->len;
228 assert(step <= (size_t) n);
229
230 e = (struct inotify_event*) ((uint8_t*) e + step);
231 n -= step;
232 }
233 }
22be093f 234
a8c73b86
LP
235 k = unpack_file(pack);
236 if (k < 0)
237 return k;
902a339c
LP
238
239 if (!ready) {
240 /* We delay the ready notification until we
241 * queued at least one read */
242 sd_notify(0, "READY=1");
243 ready = true;
244 }
22be093f
LP
245 }
246
6624768c 247done:
22be093f
LP
248 if (ferror(pack)) {
249 log_error("Failed to read pack file.");
a8c73b86 250 return -EIO;
22be093f
LP
251 }
252
a8c73b86
LP
253 if (!ready)
254 sd_notify(0, "READY=1");
22be093f 255
a8c73b86
LP
256 log_debug("Done.");
257 return 0;
22be093f
LP
258}
259
87ce22cc 260int main_replay(const char *root) {
8260358d 261
87ce22cc
LP
262 if (!root)
263 root = "/";
2b590e13 264
41a598e2
LP
265 if (!enough_ram()) {
266 log_info("Disabling readahead replay due to low memory.");
87ce22cc 267 return EXIT_SUCCESS;
41a598e2
LP
268 }
269
3b2d5b02
LP
270 shared = shared_get();
271 if (!shared)
87ce22cc 272 return EXIT_FAILURE;
d9c7a87b
LP
273
274 shared->replay = getpid();
275 __sync_synchronize();
276
2b590e13 277 if (replay(root) < 0)
87ce22cc 278 return EXIT_FAILURE;
22be093f 279
87ce22cc 280 return EXIT_SUCCESS;
22be093f 281}