mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
readahead: merge three binaries into one
since the binaries share much of the same code and we better load only one binary instead of two from disk at early boot let's merge the three readahead binaries into one. This also allows us to drop a lot of duplicated code.
This commit is contained in:
parent
b4bdfefac3
commit
87ce22cc0d
4
.gitignore
vendored
4
.gitignore
vendored
@ -46,8 +46,7 @@
|
||||
/systemd-user-sessions
|
||||
/systemd-shutdown
|
||||
/systemd-tmpfiles
|
||||
/systemd-readahead-collect
|
||||
/systemd-readahead-replay
|
||||
/systemd-readahead
|
||||
/systemd-reply-password
|
||||
/systemd-gnome-ask-password-agent
|
||||
/systemd-ask-password
|
||||
@ -123,4 +122,3 @@ stamp-*
|
||||
/v4l_id
|
||||
/test-libudev
|
||||
/test-udev
|
||||
/systemd-readahead-analyze
|
||||
|
25
Makefile.am
25
Makefile.am
@ -2377,39 +2377,24 @@ endif
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
if ENABLE_READAHEAD
|
||||
systemd_readahead_collect_SOURCES = \
|
||||
systemd_readahead_SOURCES = \
|
||||
src/readahead/readahead.c \
|
||||
src/readahead/readahead-collect.c \
|
||||
src/readahead/readahead-common.c \
|
||||
src/readahead/readahead-common.h
|
||||
|
||||
systemd_readahead_collect_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-daemon.la \
|
||||
libudev.la
|
||||
|
||||
systemd_readahead_replay_SOURCES = \
|
||||
src/readahead/readahead-replay.c \
|
||||
src/readahead/readahead-analyze.c \
|
||||
src/readahead/readahead-common.c \
|
||||
src/readahead/readahead-common.h
|
||||
|
||||
systemd_readahead_replay_LDADD = \
|
||||
systemd_readahead_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-daemon.la \
|
||||
libudev.la
|
||||
|
||||
systemd_readahead_analyze_SOURCES = \
|
||||
src/readahead/readahead-analyze.c \
|
||||
src/readahead/readahead-common.h
|
||||
|
||||
pkginclude_HEADERS += \
|
||||
src/systemd/sd-readahead.h
|
||||
|
||||
rootlibexec_PROGRAMS += \
|
||||
systemd-readahead-collect \
|
||||
systemd-readahead-replay
|
||||
|
||||
bin_PROGRAMS += \
|
||||
systemd-readahead-analyze
|
||||
systemd-readahead
|
||||
|
||||
dist_systemunit_DATA += \
|
||||
units/systemd-readahead-drop.service \
|
||||
|
2
TODO
2
TODO
@ -35,8 +35,6 @@ Features:
|
||||
|
||||
* supprto rd.xxx wherever else makes sense
|
||||
|
||||
* readahead: merge the three tools into one binary
|
||||
|
||||
* systemctl: when stopping a service which has triggres and warning about it actually check the TriggeredBy= deps fields
|
||||
|
||||
* journal: hook up with EFI firmware log, new kmsg logic
|
||||
|
@ -32,8 +32,7 @@
|
||||
|
||||
#include "readahead-common.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main_analyze(const char *pack_path)
|
||||
{
|
||||
char line[1024];
|
||||
char path[PATH_MAX];
|
||||
@ -48,30 +47,28 @@ int main(int argc, char *argv[])
|
||||
struct stat st;
|
||||
int pagesize = getpagesize();
|
||||
|
||||
if (argc != 2)
|
||||
snprintf(path, PATH_MAX, "/.readahead");
|
||||
else
|
||||
snprintf(path, PATH_MAX, "%s", argv[1]);
|
||||
if (!pack_path)
|
||||
pack_path = "/.readahead";
|
||||
|
||||
pack = fopen(path, "r");
|
||||
pack = fopen(pack_path, "r");
|
||||
if (!pack) {
|
||||
fprintf(stderr, "Pack file missing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!(fgets(line, sizeof(line), pack))) {
|
||||
fprintf(stderr, "Pack file corrupt\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!strstr(line, READAHEAD_PACK_FILE_VERSION)) {
|
||||
fprintf(stderr, "Pack file version incompatible with this parser\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if ((a = getc(pack)) == EOF) {
|
||||
fprintf(stderr, "Pack file corrupt\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stdout, " pct sections size: path\n");
|
||||
@ -88,14 +85,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (fread(&inode, sizeof(inode), 1, pack) != 1) {
|
||||
fprintf(stderr, "Pack file corrupt\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (fread(&b, sizeof(b), 1, pack) != 1 ||
|
||||
fread(&c, sizeof(c), 1, pack) != 1) {
|
||||
fprintf(stderr, "Pack file corrupt\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if ((b == 0) && (c == 0))
|
||||
break;
|
||||
@ -137,5 +134,5 @@ int main(int argc, char *argv[])
|
||||
fprintf(stdout, "MISSING: %d\n", missing);
|
||||
fprintf(stdout, "TOTAL: %ld\n", tsize);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -62,10 +62,6 @@
|
||||
* - does ioprio_set work with fadvise()?
|
||||
*/
|
||||
|
||||
static unsigned arg_files_max = 16*1024;
|
||||
static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
|
||||
static usec_t arg_timeout = 2*USEC_PER_MINUTE;
|
||||
|
||||
static ReadaheadShared *shared = NULL;
|
||||
|
||||
/* Avoid collisions with the NULL pointer */
|
||||
@ -592,108 +588,10 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
int main_collect(const char *root) {
|
||||
|
||||
printf("%s [OPTIONS...] [DIRECTORY]\n\n"
|
||||
"Collect read-ahead data on early boot.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --max-files=INT Maximum number of files to read ahead\n"
|
||||
" --max-file-size=BYTES Maximum size of files to read ahead\n"
|
||||
" --timeout=USEC Maximum time to spend collecting data\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_FILES_MAX = 0x100,
|
||||
ARG_FILE_SIZE_MAX,
|
||||
ARG_TIMEOUT
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "files-max", required_argument, NULL, ARG_FILES_MAX },
|
||||
{ "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX },
|
||||
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
|
||||
case ARG_FILES_MAX:
|
||||
if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) {
|
||||
log_error("Failed to parse maximum number of files %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_FILE_SIZE_MAX: {
|
||||
unsigned long long ull;
|
||||
|
||||
if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
|
||||
log_error("Failed to parse maximum file size %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_file_size_max = (off_t) ull;
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_TIMEOUT:
|
||||
if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
|
||||
log_error("Failed to parse timeout %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
log_error("Unknown option code %c", c);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc &&
|
||||
optind != argc-1) {
|
||||
help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
const char *root;
|
||||
|
||||
log_set_target(LOG_TARGET_SAFE);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
|
||||
root = optind < argc ? argv[optind] : "/";
|
||||
if (!root)
|
||||
root = "/";
|
||||
|
||||
/* Skip this step on read-only media. Note that we check the
|
||||
* underlying block device here, not he read-only flag of the
|
||||
@ -702,23 +600,23 @@ int main(int argc, char *argv[]) {
|
||||
* device is theoretically writable. */
|
||||
if (fs_on_read_only(root) > 0) {
|
||||
log_info("Disabling readahead collector due to read-only media.");
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!enough_ram()) {
|
||||
log_info("Disabling readahead collector due to low memory.");
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
shared = shared_get();
|
||||
if (!shared)
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
|
||||
shared->collect = getpid();
|
||||
__sync_synchronize();
|
||||
|
||||
if (collect(root) < 0)
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -26,11 +26,16 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
#define READAHEAD_FILE_SIZE_MAX (10*1024*1024)
|
||||
|
||||
#define READAHEAD_PACK_FILE_VERSION ";VERSION=2\n"
|
||||
|
||||
extern unsigned arg_files_max;
|
||||
extern off_t arg_file_size_max;
|
||||
extern usec_t arg_timeout;
|
||||
|
||||
int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st);
|
||||
|
||||
int fs_on_ssd(const char *p);
|
||||
@ -52,4 +57,8 @@ int block_bump_request_nr(const char *p);
|
||||
int block_get_readahead(const char *p, uint64_t *bytes);
|
||||
int block_set_readahead(const char *p, uint64_t bytes);
|
||||
|
||||
int main_collect(const char *root);
|
||||
int main_replay(const char *root);
|
||||
int main_analyze(const char *pack_path);
|
||||
|
||||
#endif
|
||||
|
@ -44,8 +44,6 @@
|
||||
#include "readahead-common.h"
|
||||
#include "virt.h"
|
||||
|
||||
static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
|
||||
|
||||
static ReadaheadShared *shared = NULL;
|
||||
|
||||
static int unpack_file(FILE *pack) {
|
||||
@ -289,103 +287,25 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
int main_replay(const char *root) {
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...] [DIRECTORY]\n\n"
|
||||
"Replay collected read-ahead data on early boot.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --max-file-size=BYTES Maximum size of files to read ahead\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_FILE_SIZE_MAX
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
|
||||
case ARG_FILE_SIZE_MAX: {
|
||||
unsigned long long ull;
|
||||
|
||||
if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
|
||||
log_error("Failed to parse maximum file size %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_file_size_max = (off_t) ull;
|
||||
break;
|
||||
}
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
log_error("Unknown option code %c", c);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc &&
|
||||
optind != argc-1) {
|
||||
help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char*argv[]) {
|
||||
int r;
|
||||
const char *root;
|
||||
|
||||
log_set_target(LOG_TARGET_SAFE);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
|
||||
root = optind < argc ? argv[optind] : "/";
|
||||
if (!root)
|
||||
root = "/";
|
||||
|
||||
if (!enough_ram()) {
|
||||
log_info("Disabling readahead replay due to low memory.");
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
shared = shared_get();
|
||||
if (!shared)
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
|
||||
shared->replay = getpid();
|
||||
__sync_synchronize();
|
||||
|
||||
if (replay(root) < 0)
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
158
src/readahead/readahead.c
Normal file
158
src/readahead/readahead.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "def.h"
|
||||
#include "readahead-common.h"
|
||||
|
||||
unsigned arg_files_max = 16*1024;
|
||||
off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
|
||||
usec_t arg_timeout = 2*USEC_PER_MINUTE;
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...] collect [DIRECTORY]\n\n"
|
||||
"Collect read-ahead data on early boot.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --max-files=INT Maximum number of files to read ahead\n"
|
||||
" --file-size-max=BYTES Maximum size of files to read ahead\n"
|
||||
" --timeout=USEC Maximum time to spend collecting data\n\n\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
printf("%s [OPTIONS...] replay [DIRECTORY]\n\n"
|
||||
"Replay collected read-ahead data on early boot.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --file-size-max=BYTES Maximum size of files to read ahead\n\n\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
printf("%s [OPTIONS...] analyze [PACK FILE]\n\n"
|
||||
"Analyze collected read-ahead data.\n\n"
|
||||
" -h --help Show this help\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_FILES_MAX = 0x100,
|
||||
ARG_FILE_SIZE_MAX,
|
||||
ARG_TIMEOUT
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "files-max", required_argument, NULL, ARG_FILES_MAX },
|
||||
{ "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX },
|
||||
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
|
||||
case ARG_FILES_MAX:
|
||||
if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) {
|
||||
log_error("Failed to parse maximum number of files %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_FILE_SIZE_MAX: {
|
||||
unsigned long long ull;
|
||||
|
||||
if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
|
||||
log_error("Failed to parse maximum file size %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_file_size_max = (off_t) ull;
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_TIMEOUT:
|
||||
if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
|
||||
log_error("Failed to parse timeout %s.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
log_error("Unknown option code %c", c);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc-1 &&
|
||||
optind != argc-2) {
|
||||
help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
log_set_target(LOG_TARGET_SAFE);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
|
||||
if (streq(argv[optind], "collect"))
|
||||
return main_collect(argv[optind+1]);
|
||||
else if (streq(argv[optind], "replay"))
|
||||
return main_replay(argv[optind+1]);
|
||||
else if (streq(argv[optind], "analyze"))
|
||||
return main_analyze(argv[optind+1]);
|
||||
|
||||
log_error("Unknown verb %s.", argv[optind]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -17,7 +17,7 @@ ConditionVirtualization=no
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=@rootlibexecdir@/systemd-readahead-collect
|
||||
ExecStart=@rootlibexecdir@/systemd-readahead collect
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=null
|
||||
OOMScoreAdjust=1000
|
||||
|
@ -16,7 +16,7 @@ ConditionVirtualization=no
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=@rootlibexecdir@/systemd-readahead-replay
|
||||
ExecStart=@rootlibexecdir@/systemd-readahead replay
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=null
|
||||
OOMScoreAdjust=1000
|
||||
|
Loading…
Reference in New Issue
Block a user