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