chiark / gitweb /
units: use OOMScoreAdjust= in the unit files to set OOM score adjust
[elogind.git] / src / readahead / readahead-collect.c
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
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.
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
16   Lesser General Public License for more details.
17
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/>.
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>
35 #include <linux/fanotify.h>
36 #include <sys/signalfd.h>
37 #include <sys/poll.h>
38 #include <sys/mman.h>
39 #include <linux/fs.h>
40 #include <linux/fiemap.h>
41 #include <sys/ioctl.h>
42 #include <sys/vfs.h>
43 #include <getopt.h>
44 #include <sys/inotify.h>
45
46 #include <systemd/sd-daemon.h>
47
48 #include "missing.h"
49 #include "util.h"
50 #include "set.h"
51 #include "ioprio.h"
52 #include "readahead-common.h"
53 #include "virt.h"
54
55 /* fixme:
56  *
57  * - detect ssd on btrfs/lvm...
58  * - read ahead directories
59  * - gzip?
60  * - remount rw?
61  * - handle files where nothing is in mincore
62  * - does ioprio_set work with fadvise()?
63  */
64
65 static unsigned arg_files_max = 16*1024;
66 static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
67 static usec_t arg_timeout = 2*USEC_PER_MINUTE;
68
69 static ReadaheadShared *shared = NULL;
70
71 /* Avoid collisions with the NULL pointer */
72 #define SECTOR_TO_PTR(s) ULONG_TO_PTR((s)+1)
73 #define PTR_TO_SECTOR(p) (PTR_TO_ULONG(p)-1)
74
75 static int btrfs_defrag(int fd) {
76         struct btrfs_ioctl_vol_args data;
77
78         zero(data);
79         data.fd = fd;
80
81         return ioctl(fd, BTRFS_IOC_DEFRAG, &data);
82 }
83
84 static int pack_file(FILE *pack, const char *fn, bool on_btrfs) {
85         struct stat st;
86         void *start = MAP_FAILED;
87         uint8_t *vec;
88         uint32_t b, c;
89         size_t l, pages;
90         bool mapped;
91         int r = 0, fd = -1, k;
92
93         assert(pack);
94         assert(fn);
95
96         if ((fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW)) < 0) {
97
98                 if (errno == ENOENT)
99                         return 0;
100
101                 if (errno == EPERM || errno == EACCES)
102                         return 0;
103
104                 log_warning("open(%s) failed: %m", fn);
105                 r = -errno;
106                 goto finish;
107         }
108
109         if ((k = file_verify(fd, fn, arg_file_size_max, &st)) <= 0) {
110                 r = k;
111                 goto finish;
112         }
113
114         if (on_btrfs)
115                 btrfs_defrag(fd);
116
117         l = PAGE_ALIGN(st.st_size);
118         if ((start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
119                 log_warning("mmap(%s) failed: %m", fn);
120                 r = -errno;
121                 goto finish;
122         }
123
124         pages = l / page_size();
125
126         vec = alloca(pages);
127         memset(vec, 0, pages);
128         if (mincore(start, l, vec) < 0) {
129                 log_warning("mincore(%s) failed: %m", fn);
130                 r = -errno;
131                 goto finish;
132         }
133
134         fputs(fn, pack);
135         fputc('\n', pack);
136
137         mapped = false;
138         for (c = 0; c < pages; c++) {
139                 bool new_mapped = !!(vec[c] & 1);
140
141                 if (!mapped && new_mapped)
142                         b = c;
143                 else if (mapped && !new_mapped) {
144                         fwrite(&b, sizeof(b), 1, pack);
145                         fwrite(&c, sizeof(c), 1, pack);
146
147                         log_debug("%s: page %u to %u", fn, b, c);
148                 }
149
150                 mapped = new_mapped;
151         }
152
153         /* We don't write any range data if we should read the entire file */
154         if (mapped && b > 0) {
155                 fwrite(&b, sizeof(b), 1, pack);
156                 fwrite(&c, sizeof(c), 1, pack);
157
158                 log_debug("%s: page %u to %u", fn, b, c);
159         }
160
161         /* End marker */
162         b = 0;
163         fwrite(&b, sizeof(b), 1, pack);
164         fwrite(&b, sizeof(b), 1, pack);
165
166 finish:
167         if (start != MAP_FAILED)
168                 munmap(start, l);
169
170         if (fd >= 0)
171                 close_nointr_nofail(fd);
172
173         return r;
174 }
175
176 static unsigned long fd_first_block(int fd) {
177         struct {
178                 struct fiemap fiemap;
179                 struct fiemap_extent extent;
180         } data;
181
182         zero(data);
183         data.fiemap.fm_length = ~0ULL;
184         data.fiemap.fm_extent_count = 1;
185
186         if (ioctl(fd, FS_IOC_FIEMAP, &data) < 0)
187                 return 0;
188
189         if (data.fiemap.fm_mapped_extents <= 0)
190                 return 0;
191
192         if (data.fiemap.fm_extents[0].fe_flags & FIEMAP_EXTENT_UNKNOWN)
193                 return 0;
194
195         return (unsigned long) data.fiemap.fm_extents[0].fe_physical;
196 }
197
198 struct item {
199         const char *path;
200         unsigned long block;
201 };
202
203 static int qsort_compare(const void *a, const void *b) {
204         const struct item *i, *j;
205
206         i = a;
207         j = b;
208
209         if (i->block < j->block)
210                 return -1;
211         if (i->block > j->block)
212                 return 1;
213
214         return strcmp(i->path, j->path);
215 }
216
217 static int collect(const char *root) {
218         enum {
219                 FD_FANOTIFY,  /* Get the actual fs events */
220                 FD_SIGNAL,
221                 FD_INOTIFY,   /* We get notifications to quit early via this fd */
222                 _FD_MAX
223         };
224         struct pollfd pollfd[_FD_MAX];
225         int fanotify_fd = -1, signal_fd = -1, inotify_fd = -1, r = 0;
226         pid_t my_pid;
227         Hashmap *files = NULL;
228         Iterator i;
229         char *p, *q;
230         sigset_t mask;
231         FILE *pack = NULL;
232         char *pack_fn_new = NULL, *pack_fn = NULL;
233         bool on_ssd, on_btrfs;
234         struct statfs sfs;
235         usec_t not_after;
236         uint64_t previous_block_readahead;
237         bool previous_block_readahead_set = false;
238
239         assert(root);
240
241         if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
242                 log_error("Out of memory");
243                 r = -ENOMEM;
244                 goto finish;
245         }
246
247         /* If there's no pack file yet we lower the kernel readahead
248          * so that mincore() is accurate. If there is a pack file
249          * already we assume it is accurate enough so that kernel
250          * readahead is never triggered. */
251         previous_block_readahead_set =
252                 access(pack_fn, F_OK) < 0 &&
253                 block_get_readahead(root, &previous_block_readahead) >= 0 &&
254                 block_set_readahead(root, 8*1024) >= 0;
255
256         if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0)
257                 log_warning("Failed to set IDLE IO priority class: %m");
258
259         assert_se(sigemptyset(&mask) == 0);
260         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
261         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
262
263         if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
264                 log_error("signalfd(): %m");
265                 r = -errno;
266                 goto finish;
267         }
268
269         if (!(files = hashmap_new(string_hash_func, string_compare_func))) {
270                 log_error("Failed to allocate set.");
271                 r = -ENOMEM;
272                 goto finish;
273         }
274
275         if ((fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME)) < 0)  {
276                 log_error("Failed to create fanotify object: %m");
277                 r = -errno;
278                 goto finish;
279         }
280
281         if (fanotify_mark(fanotify_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_OPEN, AT_FDCWD, root) < 0) {
282                 log_error("Failed to mark %s: %m", root);
283                 r = -errno;
284                 goto finish;
285         }
286
287         if ((inotify_fd = open_inotify()) < 0) {
288                 r = inotify_fd;
289                 goto finish;
290         }
291
292         not_after = now(CLOCK_MONOTONIC) + arg_timeout;
293
294         my_pid = getpid();
295
296         zero(pollfd);
297         pollfd[FD_FANOTIFY].fd = fanotify_fd;
298         pollfd[FD_FANOTIFY].events = POLLIN;
299         pollfd[FD_SIGNAL].fd = signal_fd;
300         pollfd[FD_SIGNAL].events = POLLIN;
301         pollfd[FD_INOTIFY].fd = inotify_fd;
302         pollfd[FD_INOTIFY].events = POLLIN;
303
304         sd_notify(0,
305                   "READY=1\n"
306                   "STATUS=Collecting readahead data");
307
308         log_debug("Collecting...");
309
310         if (access("/run/systemd/readahead/cancel", F_OK) >= 0) {
311                 log_debug("Collection canceled");
312                 r = -ECANCELED;
313                 goto finish;
314         }
315
316         if (access("/run/systemd/readahead/done", F_OK) >= 0) {
317                 log_debug("Got termination request");
318                 goto done;
319         }
320
321         for (;;) {
322                 union {
323                         struct fanotify_event_metadata metadata;
324                         char buffer[4096];
325                 } data;
326                 ssize_t n;
327                 struct fanotify_event_metadata *m;
328                 usec_t t;
329                 int h;
330
331                 if (hashmap_size(files) > arg_files_max) {
332                         log_debug("Reached maximum number of read ahead files, ending collection.");
333                         break;
334                 }
335
336                 t = now(CLOCK_MONOTONIC);
337                 if (t >= not_after) {
338                         log_debug("Reached maximum collection time, ending collection.");
339                         break;
340                 }
341
342                 if ((h = poll(pollfd, _FD_MAX, (int) ((not_after - t) / USEC_PER_MSEC))) < 0) {
343
344                         if (errno == EINTR)
345                                 continue;
346
347                         log_error("poll(): %m");
348                         r = -errno;
349                         goto finish;
350                 }
351
352                 if (h == 0) {
353                         log_debug("Reached maximum collection time, ending collection.");
354                         break;
355                 }
356
357                 if (pollfd[FD_SIGNAL].revents) {
358                         log_debug("Got signal.");
359                         break;
360                 }
361
362                 if (pollfd[FD_INOTIFY].revents) {
363                         uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
364                         struct inotify_event *e;
365
366                         if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
367                                 if (errno == EINTR || errno == EAGAIN)
368                                         continue;
369
370                                 log_error("Failed to read inotify event: %m");
371                                 r = -errno;
372                                 goto finish;
373                         }
374
375                         e = (struct inotify_event*) inotify_buffer;
376                         while (n > 0) {
377                                 size_t step;
378
379                                 if ((e->mask & IN_CREATE) && streq(e->name, "cancel")) {
380                                         log_debug("Collection canceled");
381                                         r = -ECANCELED;
382                                         goto finish;
383                                 }
384
385                                 if ((e->mask & IN_CREATE) && streq(e->name, "done")) {
386                                         log_debug("Got termination request");
387                                         goto done;
388                                 }
389
390                                 step = sizeof(struct inotify_event) + e->len;
391                                 assert(step <= (size_t) n);
392
393                                 e = (struct inotify_event*) ((uint8_t*) e + step);
394                                 n -= step;
395                         }
396                 }
397
398                 if ((n = read(fanotify_fd, &data, sizeof(data))) < 0) {
399
400                         if (errno == EINTR || errno == EAGAIN)
401                                 continue;
402
403                         /* fanotify sometimes returns EACCES on read()
404                          * where it shouldn't. For now let's just
405                          * ignore it here (which is safe), but
406                          * eventually this should be
407                          * dropped when the kernel is fixed.
408                          *
409                          * https://bugzilla.redhat.com/show_bug.cgi?id=707577 */
410                         if (errno == EACCES)
411                                 continue;
412
413                         log_error("Failed to read event: %m");
414                         r = -errno;
415                         goto finish;
416                 }
417
418                 for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) {
419                         char fn[PATH_MAX];
420                         int k;
421
422                         if (m->fd < 0)
423                                 goto next_iteration;
424
425                         if (m->pid == my_pid)
426                                 goto next_iteration;
427
428                         __sync_synchronize();
429                         if (m->pid == shared->replay)
430                                 goto next_iteration;
431
432                         snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd);
433                         char_array_0(fn);
434
435                         if ((k = readlink_malloc(fn, &p)) >= 0) {
436                                 if (startswith(p, "/tmp") ||
437                                     endswith(p, " (deleted)") ||
438                                     hashmap_get(files, p))
439                                         /* Not interesting, or
440                                          * already read */
441                                         free(p);
442                                 else {
443                                         unsigned long ul;
444
445                                         ul = fd_first_block(m->fd);
446
447                                         if ((k = hashmap_put(files, p, SECTOR_TO_PTR(ul))) < 0) {
448                                                 log_warning("set_put() failed: %s", strerror(-k));
449                                                 free(p);
450                                         }
451                                 }
452
453                         } else
454                                 log_warning("readlink(%s) failed: %s", fn, strerror(-k));
455
456                 next_iteration:
457                         if (m->fd)
458                                 close_nointr_nofail(m->fd);
459                 }
460         }
461
462 done:
463         if (fanotify_fd >= 0) {
464                 close_nointr_nofail(fanotify_fd);
465                 fanotify_fd = -1;
466         }
467
468         log_debug("Writing Pack File...");
469
470         on_ssd = fs_on_ssd(root) > 0;
471         log_debug("On SSD: %s", yes_no(on_ssd));
472
473         on_btrfs = statfs(root, &sfs) >= 0 && (long) sfs.f_type == (long) BTRFS_SUPER_MAGIC;
474         log_debug("On btrfs: %s", yes_no(on_btrfs));
475
476         if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) {
477                 log_error("Out of memory");
478                 r = -ENOMEM;
479                 goto finish;
480         }
481
482         if (!(pack = fopen(pack_fn_new, "we"))) {
483                 log_error("Failed to open pack file: %m");
484                 r = -errno;
485                 goto finish;
486         }
487
488         fputs(CANONICAL_HOST "\n", pack);
489         putc(on_ssd ? 'S' : 'R', pack);
490
491         if (on_ssd || on_btrfs) {
492
493                 /* On SSD or on btrfs, just write things out in the
494                  * order the files were accessed. */
495
496                 HASHMAP_FOREACH_KEY(q, p, files, i)
497                         pack_file(pack, p, on_btrfs);
498         } else {
499                 struct item *ordered, *j;
500                 unsigned k, n;
501
502                 /* On rotating media, order things by the block
503                  * numbers */
504
505                 log_debug("Ordering...");
506
507                 n = hashmap_size(files);
508                 if (!(ordered = new(struct item, n))) {
509                         log_error("Out of memory");
510                         r = -ENOMEM;
511                         goto finish;
512                 }
513
514                 j = ordered;
515                 HASHMAP_FOREACH_KEY(q, p, files, i) {
516                         j->path = p;
517                         j->block = PTR_TO_SECTOR(q);
518                         j++;
519                 }
520
521                 assert(ordered + n == j);
522
523                 qsort(ordered, n, sizeof(struct item), qsort_compare);
524
525                 for (k = 0; k < n; k++)
526                         pack_file(pack, ordered[k].path, on_btrfs);
527
528                 free(ordered);
529         }
530
531         log_debug("Finalizing...");
532
533         fflush(pack);
534
535         if (ferror(pack)) {
536                 log_error("Failed to write pack file.");
537                 r = -EIO;
538                 goto finish;
539         }
540
541         if (rename(pack_fn_new, pack_fn) < 0) {
542                 log_error("Failed to rename readahead file: %m");
543                 r = -errno;
544                 goto finish;
545         }
546
547         fclose(pack);
548         pack = NULL;
549
550         log_debug("Done.");
551
552 finish:
553         if (fanotify_fd >= 0)
554                 close_nointr_nofail(fanotify_fd);
555
556         if (signal_fd >= 0)
557                 close_nointr_nofail(signal_fd);
558
559         if (inotify_fd >= 0)
560                 close_nointr_nofail(inotify_fd);
561
562         if (pack) {
563                 fclose(pack);
564                 unlink(pack_fn_new);
565         }
566         free(pack_fn_new);
567         free(pack_fn);
568
569         while ((p = hashmap_steal_first_key(files)))
570                 free(p);
571
572         hashmap_free(files);
573
574         if (previous_block_readahead_set) {
575                 uint64_t bytes;
576
577                 /* Restore the original kernel readahead setting if we
578                  * changed it, and nobody has overwritten it since
579                  * yet. */
580                 if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024)
581                         block_set_readahead(root, previous_block_readahead);
582         }
583
584         return r;
585 }
586
587 static int help(void) {
588
589         printf("%s [OPTIONS...] [DIRECTORY]\n\n"
590                "Collect read-ahead data on early boot.\n\n"
591                "  -h --help                 Show this help\n"
592                "     --max-files=INT        Maximum number of files to read ahead\n"
593                "     --max-file-size=BYTES  Maximum size of files to read ahead\n"
594                "     --timeout=USEC         Maximum time to spend collecting data\n",
595                program_invocation_short_name);
596
597         return 0;
598 }
599
600 static int parse_argv(int argc, char *argv[]) {
601
602         enum {
603                 ARG_FILES_MAX = 0x100,
604                 ARG_FILE_SIZE_MAX,
605                 ARG_TIMEOUT
606         };
607
608         static const struct option options[] = {
609                 { "help",          no_argument,       NULL, 'h'                },
610                 { "files-max",     required_argument, NULL, ARG_FILES_MAX      },
611                 { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX  },
612                 { "timeout",       required_argument, NULL, ARG_TIMEOUT        },
613                 { NULL,            0,                 NULL, 0                  }
614         };
615
616         int c;
617
618         assert(argc >= 0);
619         assert(argv);
620
621         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
622
623                 switch (c) {
624
625                 case 'h':
626                         help();
627                         return 0;
628
629                 case ARG_FILES_MAX:
630                         if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) {
631                                 log_error("Failed to parse maximum number of files %s.", optarg);
632                                 return -EINVAL;
633                         }
634                         break;
635
636                 case ARG_FILE_SIZE_MAX: {
637                         unsigned long long ull;
638
639                         if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
640                                 log_error("Failed to parse maximum file size %s.", optarg);
641                                 return -EINVAL;
642                         }
643
644                         arg_file_size_max = (off_t) ull;
645                         break;
646                 }
647
648                 case ARG_TIMEOUT:
649                         if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
650                                 log_error("Failed to parse timeout %s.", optarg);
651                                 return -EINVAL;
652                         }
653
654                         break;
655
656                 case '?':
657                         return -EINVAL;
658
659                 default:
660                         log_error("Unknown option code %c", c);
661                         return -EINVAL;
662                 }
663         }
664
665         if (optind != argc &&
666             optind != argc-1) {
667                 help();
668                 return -EINVAL;
669         }
670
671         return 1;
672 }
673
674 int main(int argc, char *argv[]) {
675         int r;
676         const char *root;
677
678         log_set_target(LOG_TARGET_AUTO);
679         log_parse_environment();
680         log_open();
681
682         umask(0022);
683
684         r = parse_argv(argc, argv);
685         if (r <= 0)
686                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
687
688         root = optind < argc ? argv[optind] : "/";
689
690         /* Skip this step on read-only media. Note that we check the
691          * underlying block device here, not he read-only flag of the
692          * file system on top, since that one is most likely mounted
693          * read-only anyway at boot, even if the underlying block
694          * device is theoretically writable. */
695         if (fs_on_read_only(root) > 0) {
696                 log_info("Disabling readahead collector due to read-only media.");
697                 return 0;
698         }
699
700         if (!enough_ram()) {
701                 log_info("Disabling readahead collector due to low memory.");
702                 return 0;
703         }
704
705         shared = shared_get();
706         if (!shared)
707                 return 1;
708
709         shared->collect = getpid();
710         __sync_synchronize();
711
712         if (collect(root) < 0)
713                 return 1;
714
715         return 0;
716 }