X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Freadahead-collect.c;h=6705615d11e7267028c48476f68e5269537c8643;hb=408b85df83ad5711eeb959dd657b967447892c56;hp=93a04521f3fb82a7dd9d3385f36ff18fe14f1525;hpb=22be093ffb403a1c474037939ca9b88b1ee39f77;p=elogind.git diff --git a/src/readahead-collect.c b/src/readahead-collect.c index 93a04521f..6705615d1 100644 --- a/src/readahead-collect.c +++ b/src/readahead-collect.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "missing.h" #include "util.h" @@ -47,15 +48,31 @@ #include "ioprio.h" #include "readahead-common.h" -/* - fixme: +#define MINCORE_VEC_SIZE (READAHEAD_FILE_SIZE_MAX/PAGE_SIZE) +#define TIMEOUT_USEC (2*USEC_PER_MINUTE) + +/* fixme: + * + * - detect ssd on btrfs/lvm... + * - read ahead directories + * - sd_readahead_cancel + * - gzip? + * - oom adjust + * - remount rw + * - are filenames from anotify normalized regards /../ and // and /./? + * - does ioprio_set work with fadvise()? + */ + +static int btrfs_defrag(int fd) { + struct btrfs_ioctl_vol_args data; - - BTRFS_IOC_DEFRAG -*/ + zero(data); + data.fd = fd; -#define MINCORE_VEC_SIZE (READAHEAD_FILE_SIZE_MAX/PAGE_SIZE) + return ioctl(fd, BTRFS_IOC_DEFRAG, &data); +} -static int pack_file(FILE *pack, const char *fn) { +static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { struct stat st; void *start = MAP_FAILED; uint8_t vec[MINCORE_VEC_SIZE]; @@ -78,6 +95,9 @@ static int pack_file(FILE *pack, const char *fn) { goto finish; } + if (on_btrfs) + btrfs_defrag(fd); + l = PAGE_ALIGN(st.st_size); if ((start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { log_warning("mmap(%s) failed: %m", fn); @@ -97,7 +117,7 @@ static int pack_file(FILE *pack, const char *fn) { pages = l / PAGE_SIZE; mapped = false; for (c = 0; c < pages; c++) { - bool new_mapped = (vec[c] & 1); + bool new_mapped = !!(vec[c] & 1); if (!mapped && new_mapped) b = c; @@ -190,7 +210,9 @@ static int collect(const char *root) { sigset_t mask; FILE *pack = NULL; char *pack_fn_new = NULL, *pack_fn = NULL; - bool on_ssd; + bool on_ssd, on_btrfs; + struct statfs sfs; + usec_t not_after; assert(root); @@ -213,7 +235,7 @@ static int collect(const char *root) { goto finish; } - if ((fanotify_fd = fanotify_init(FAN_CLOEXEC, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME)) < 0) { + if ((fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME)) < 0) { log_error("Failed to create fanotify object: %m"); r = -errno; goto finish; @@ -225,6 +247,8 @@ static int collect(const char *root) { goto finish; } + not_after = now(CLOCK_MONOTONIC) + TIMEOUT_USEC; + my_pid = getpid(); zero(pollfd); @@ -246,8 +270,21 @@ static int collect(const char *root) { } data; ssize_t n; struct fanotify_event_metadata *m; + usec_t t; + int h; + + if (hashmap_size(files) > READAHEAD_FILES_MAX) { + log_debug("Reached maximum number of read ahead files, ending collection."); + break; + } + + t = now(CLOCK_MONOTONIC); + if (t >= not_after) { + log_debug("Reached maximum collection time, ending collection."); + break; + } - if (poll(pollfd, _FD_MAX, -1) < 0) { + if ((h = poll(pollfd, _FD_MAX, (int) ((not_after - t) / USEC_PER_MSEC))) < 0) { if (errno == EINTR) continue; @@ -260,6 +297,11 @@ static int collect(const char *root) { if (pollfd[FD_SIGNAL].revents != 0) break; + if (h == 0) { + log_debug("Reached maximum collection time, ending collection."); + break; + } + if ((n = read(fanotify_fd, &data, sizeof(data))) < 0) { if (errno == EINTR || errno == EAGAIN) @@ -270,8 +312,7 @@ static int collect(const char *root) { goto finish; } - m = &data.metadata; - while (FAN_EVENT_OK(m, n)) { + for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) { if (m->pid != my_pid && m->fd >= 0) { char fn[PATH_MAX]; @@ -291,10 +332,7 @@ static int collect(const char *root) { ul = fd_first_block(m->fd); if ((k = hashmap_put(files, p, ULONG_TO_PTR(ul))) < 0) { - - if (k != -EEXIST) - log_warning("set_put() failed: %s", strerror(-k)); - + log_warning("set_put() failed: %s", strerror(-k)); free(p); } } @@ -305,10 +343,7 @@ static int collect(const char *root) { if (m->fd) close_nointr_nofail(m->fd); - - m = FAN_EVENT_NEXT(m, n); } - } if (fanotify_fd >= 0) { @@ -321,6 +356,9 @@ static int collect(const char *root) { on_ssd = fs_on_ssd(root); log_debug("On SSD: %s", yes_no(on_ssd)); + on_btrfs = statfs(root, &sfs) >= 0 && sfs.f_type == BTRFS_SUPER_MAGIC; + log_debug("On btrfs: %s", yes_no(on_btrfs)); + asprintf(&pack_fn, "%s/.readahead", root); asprintf(&pack_fn_new, "%s/.readahead.new", root); @@ -339,13 +377,13 @@ static int collect(const char *root) { fputs(CANONICAL_HOST "\n", pack); putc(on_ssd ? 'S' : 'R', pack); - if (on_ssd) { + if (on_ssd || on_btrfs) { - /* On SSD, just write things out in the order the - * files where accessed */ + /* On SSD or on btrfs, just write things out in the + * order the files were accessed. */ HASHMAP_FOREACH_KEY(q, p, files, i) - pack_file(pack, p); + pack_file(pack, p, on_btrfs); } else { struct item *ordered, *j; unsigned k, n; @@ -374,7 +412,7 @@ static int collect(const char *root) { qsort(ordered, n, sizeof(struct item), qsort_compare); for (k = 0; k < n; k++) - pack_file(pack, ordered[k].path); + pack_file(pack, ordered[k].path, on_btrfs); free(ordered); } @@ -424,13 +462,17 @@ finish: } int main(int argc, char *argv[]) { - /* log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); */ + + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); log_parse_environment(); log_open(); - log_set_max_level(LOG_DEBUG); + if (!enough_ram()) { + log_info("Disabling readahead collector due to low memory."); + return 0; + } - if (collect("/") < 0) + if (collect(argc >= 2 ? argv[1] : "/") < 0) return 1; return 0;