chiark / gitweb /
70e0f66eda2b51d5a523796536fcadd34ebfc19e
[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         write_one_line_file("/proc/self/oom_score_adj", "1000");
257
258         if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0)
259                 log_warning("Failed to set IDLE IO priority class: %m");
260
261         assert_se(sigemptyset(&mask) == 0);
262         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
263         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
264
265         if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
266                 log_error("signalfd(): %m");
267                 r = -errno;
268                 goto finish;
269         }
270
271         if (!(files = hashmap_new(string_hash_func, string_compare_func))) {
272                 log_error("Failed to allocate set.");
273                 r = -ENOMEM;
274                 goto finish;
275         }
276
277         if ((fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME)) < 0)  {
278                 log_error("Failed to create fanotify object: %m");
279                 r = -errno;
280                 goto finish;
281         }
282
283         if (fanotify_mark(fanotify_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_OPEN, AT_FDCWD, root) < 0) {
284                 log_error("Failed to mark %s: %m", root);
285                 r = -errno;
286                 goto finish;
287         }
288
289         if ((inotify_fd = open_inotify()) < 0) {
290                 r = inotify_fd;
291                 goto finish;
292         }
293
294         not_after = now(CLOCK_MONOTONIC) + arg_timeout;
295
296         my_pid = getpid();
297
298         zero(pollfd);
299         pollfd[FD_FANOTIFY].fd = fanotify_fd;
300         pollfd[FD_FANOTIFY].events = POLLIN;
301         pollfd[FD_SIGNAL].fd = signal_fd;
302         pollfd[FD_SIGNAL].events = POLLIN;
303         pollfd[FD_INOTIFY].fd = inotify_fd;
304         pollfd[FD_INOTIFY].events = POLLIN;
305
306         sd_notify(0,
307                   "READY=1\n"
308                   "STATUS=Collecting readahead data");
309
310         log_debug("Collecting...");
311
312         if (access("/run/systemd/readahead/cancel", F_OK) >= 0) {
313                 log_debug("Collection canceled");
314                 r = -ECANCELED;
315                 goto finish;
316         }
317
318         if (access("/run/systemd/readahead/done", F_OK) >= 0) {
319                 log_debug("Got termination request");
320                 goto done;
321         }
322
323         for (;;) {
324                 union {
325                         struct fanotify_event_metadata metadata;
326                         char buffer[4096];
327                 } data;
328                 ssize_t n;
329                 struct fanotify_event_metadata *m;
330                 usec_t t;
331                 int h;
332
333                 if (hashmap_size(files) > arg_files_max) {
334                         log_debug("Reached maximum number of read ahead files, ending collection.");
335                         break;
336                 }
337
338                 t = now(CLOCK_MONOTONIC);
339                 if (t >= not_after) {
340                         log_debug("Reached maximum collection time, ending collection.");
341                         break;
342                 }
343
344                 if ((h = poll(pollfd, _FD_MAX, (int) ((not_after - t) / USEC_PER_MSEC))) < 0) {
345
346                         if (errno == EINTR)
347                                 continue;
348
349                         log_error("poll(): %m");
350                         r = -errno;
351                         goto finish;
352                 }
353
354                 if (h == 0) {
355                         log_debug("Reached maximum collection time, ending collection.");
356                         break;
357                 }
358
359                 if (pollfd[FD_SIGNAL].revents) {
360                         log_debug("Got signal.");
361                         break;
362                 }
363
364                 if (pollfd[FD_INOTIFY].revents) {
365                         uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
366                         struct inotify_event *e;
367
368                         if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
369                                 if (errno == EINTR || errno == EAGAIN)
370                                         continue;
371
372                                 log_error("Failed to read inotify event: %m");
373                                 r = -errno;
374                                 goto finish;
375                         }
376
377                         e = (struct inotify_event*) inotify_buffer;
378                         while (n > 0) {
379                                 size_t step;
380
381                                 if ((e->mask & IN_CREATE) && streq(e->name, "cancel")) {
382                                         log_debug("Collection canceled");
383                                         r = -ECANCELED;
384                                         goto finish;
385                                 }
386
387                                 if ((e->mask & IN_CREATE) && streq(e->name, "done")) {
388                                         log_debug("Got termination request");
389                                         goto done;
390                                 }
391
392                                 step = sizeof(struct inotify_event) + e->len;
393                                 assert(step <= (size_t) n);
394
395                                 e = (struct inotify_event*) ((uint8_t*) e + step);
396                                 n -= step;
397                         }
398                 }
399
400                 if ((n = read(fanotify_fd, &data, sizeof(data))) < 0) {
401
402                         if (errno == EINTR || errno == EAGAIN)
403                                 continue;
404
405                         /* fanotify sometimes returns EACCES on read()
406                          * where it shouldn't. For now let's just
407                          * ignore it here (which is safe), but
408                          * eventually this should be
409                          * dropped when the kernel is fixed.
410                          *
411                          * https://bugzilla.redhat.com/show_bug.cgi?id=707577 */
412                         if (errno == EACCES)
413                                 continue;
414
415                         log_error("Failed to read event: %m");
416                         r = -errno;
417                         goto finish;
418                 }
419
420                 for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) {
421                         char fn[PATH_MAX];
422                         int k;
423
424                         if (m->fd < 0)
425                                 goto next_iteration;
426
427                         if (m->pid == my_pid)
428                                 goto next_iteration;
429
430                         __sync_synchronize();
431                         if (m->pid == shared->replay)
432                                 goto next_iteration;
433
434                         snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd);
435                         char_array_0(fn);
436
437                         if ((k = readlink_malloc(fn, &p)) >= 0) {
438                                 if (startswith(p, "/tmp") ||
439                                     endswith(p, " (deleted)") ||
440                                     hashmap_get(files, p))
441                                         /* Not interesting, or
442                                          * already read */
443                                         free(p);
444                                 else {
445                                         unsigned long ul;
446
447                                         ul = fd_first_block(m->fd);
448
449                                         if ((k = hashmap_put(files, p, SECTOR_TO_PTR(ul))) < 0) {
450                                                 log_warning("set_put() failed: %s", strerror(-k));
451                                                 free(p);
452                                         }
453                                 }
454
455                         } else
456                                 log_warning("readlink(%s) failed: %s", fn, strerror(-k));
457
458                 next_iteration:
459                         if (m->fd)
460                                 close_nointr_nofail(m->fd);
461                 }
462         }
463
464 done:
465         if (fanotify_fd >= 0) {
466                 close_nointr_nofail(fanotify_fd);
467                 fanotify_fd = -1;
468         }
469
470         log_debug("Writing Pack File...");
471
472         on_ssd = fs_on_ssd(root) > 0;
473         log_debug("On SSD: %s", yes_no(on_ssd));
474
475         on_btrfs = statfs(root, &sfs) >= 0 && (long) sfs.f_type == (long) BTRFS_SUPER_MAGIC;
476         log_debug("On btrfs: %s", yes_no(on_btrfs));
477
478         if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) {
479                 log_error("Out of memory");
480                 r = -ENOMEM;
481                 goto finish;
482         }
483
484         if (!(pack = fopen(pack_fn_new, "we"))) {
485                 log_error("Failed to open pack file: %m");
486                 r = -errno;
487                 goto finish;
488         }
489
490         fputs(CANONICAL_HOST "\n", pack);
491         putc(on_ssd ? 'S' : 'R', pack);
492
493         if (on_ssd || on_btrfs) {
494
495                 /* On SSD or on btrfs, just write things out in the
496                  * order the files were accessed. */
497
498                 HASHMAP_FOREACH_KEY(q, p, files, i)
499                         pack_file(pack, p, on_btrfs);
500         } else {
501                 struct item *ordered, *j;
502                 unsigned k, n;
503
504                 /* On rotating media, order things by the block
505                  * numbers */
506
507                 log_debug("Ordering...");
508
509                 n = hashmap_size(files);
510                 if (!(ordered = new(struct item, n))) {
511                         log_error("Out of memory");
512                         r = -ENOMEM;
513                         goto finish;
514                 }
515
516                 j = ordered;
517                 HASHMAP_FOREACH_KEY(q, p, files, i) {
518                         j->path = p;
519                         j->block = PTR_TO_SECTOR(q);
520                         j++;
521                 }
522
523                 assert(ordered + n == j);
524
525                 qsort(ordered, n, sizeof(struct item), qsort_compare);
526
527                 for (k = 0; k < n; k++)
528                         pack_file(pack, ordered[k].path, on_btrfs);
529
530                 free(ordered);
531         }
532
533         log_debug("Finalizing...");
534
535         fflush(pack);
536
537         if (ferror(pack)) {
538                 log_error("Failed to write pack file.");
539                 r = -EIO;
540                 goto finish;
541         }
542
543         if (rename(pack_fn_new, pack_fn) < 0) {
544                 log_error("Failed to rename readahead file: %m");
545                 r = -errno;
546                 goto finish;
547         }
548
549         fclose(pack);
550         pack = NULL;
551
552         log_debug("Done.");
553
554 finish:
555         if (fanotify_fd >= 0)
556                 close_nointr_nofail(fanotify_fd);
557
558         if (signal_fd >= 0)
559                 close_nointr_nofail(signal_fd);
560
561         if (inotify_fd >= 0)
562                 close_nointr_nofail(inotify_fd);
563
564         if (pack) {
565                 fclose(pack);
566                 unlink(pack_fn_new);
567         }
568         free(pack_fn_new);
569         free(pack_fn);
570
571         while ((p = hashmap_steal_first_key(files)))
572                 free(p);
573
574         hashmap_free(files);
575
576         if (previous_block_readahead_set) {
577                 uint64_t bytes;
578
579                 /* Restore the original kernel readahead setting if we
580                  * changed it, and nobody has overwritten it since
581                  * yet. */
582                 if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024)
583                         block_set_readahead(root, previous_block_readahead);
584         }
585
586         return r;
587 }
588
589 static int help(void) {
590
591         printf("%s [OPTIONS...] [DIRECTORY]\n\n"
592                "Collect read-ahead data on early boot.\n\n"
593                "  -h --help                 Show this help\n"
594                "     --max-files=INT        Maximum number of files to read ahead\n"
595                "     --max-file-size=BYTES  Maximum size of files to read ahead\n"
596                "     --timeout=USEC         Maximum time to spend collecting data\n",
597                program_invocation_short_name);
598
599         return 0;
600 }
601
602 static int parse_argv(int argc, char *argv[]) {
603
604         enum {
605                 ARG_FILES_MAX = 0x100,
606                 ARG_FILE_SIZE_MAX,
607                 ARG_TIMEOUT
608         };
609
610         static const struct option options[] = {
611                 { "help",          no_argument,       NULL, 'h'                },
612                 { "files-max",     required_argument, NULL, ARG_FILES_MAX      },
613                 { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX  },
614                 { "timeout",       required_argument, NULL, ARG_TIMEOUT        },
615                 { NULL,            0,                 NULL, 0                  }
616         };
617
618         int c;
619
620         assert(argc >= 0);
621         assert(argv);
622
623         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
624
625                 switch (c) {
626
627                 case 'h':
628                         help();
629                         return 0;
630
631                 case ARG_FILES_MAX:
632                         if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) {
633                                 log_error("Failed to parse maximum number of files %s.", optarg);
634                                 return -EINVAL;
635                         }
636                         break;
637
638                 case ARG_FILE_SIZE_MAX: {
639                         unsigned long long ull;
640
641                         if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
642                                 log_error("Failed to parse maximum file size %s.", optarg);
643                                 return -EINVAL;
644                         }
645
646                         arg_file_size_max = (off_t) ull;
647                         break;
648                 }
649
650                 case ARG_TIMEOUT:
651                         if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
652                                 log_error("Failed to parse timeout %s.", optarg);
653                                 return -EINVAL;
654                         }
655
656                         break;
657
658                 case '?':
659                         return -EINVAL;
660
661                 default:
662                         log_error("Unknown option code %c", c);
663                         return -EINVAL;
664                 }
665         }
666
667         if (optind != argc &&
668             optind != argc-1) {
669                 help();
670                 return -EINVAL;
671         }
672
673         return 1;
674 }
675
676 int main(int argc, char *argv[]) {
677         int r;
678         const char *root;
679
680         log_set_target(LOG_TARGET_AUTO);
681         log_parse_environment();
682         log_open();
683
684         umask(0022);
685
686         r = parse_argv(argc, argv);
687         if (r <= 0)
688                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
689
690         root = optind < argc ? argv[optind] : "/";
691
692         /* Skip this step on read-only media. Note that we check the
693          * underlying block device here, not he read-only flag of the
694          * file system on top, since that one is most likely mounted
695          * read-only anyway at boot, even if the underlying block
696          * device is theoretically writable. */
697         if (fs_on_read_only(root) > 0) {
698                 log_info("Disabling readahead collector due to read-only media.");
699                 return 0;
700         }
701
702         if (!enough_ram()) {
703                 log_info("Disabling readahead collector due to low memory.");
704                 return 0;
705         }
706
707         shared = shared_get();
708         if (!shared)
709                 return 1;
710
711         shared->collect = getpid();
712         __sync_synchronize();
713
714         if (collect(root) < 0)
715                 return 1;
716
717         return 0;
718 }