--- sreadahead-1.0.orig/sreadahead.c +++ sreadahead-1.0/sreadahead.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -41,8 +40,11 @@ #elif defined(__x86_64__) # define HAVE_IO_PRIO # define __NR_ioprio_set 251 +#elif defined(__powerpc__) +# define HAVE_IO_PRIO +# define __NR_ioprio_set 273 #else /* not fatal */ -# warn "Architecture does not support ioprio modification" +# warning "Architecture does not support ioprio modification" #endif #define IOPRIO_WHO_PROCESS 1 #define IOPRIO_CLASS_IDLE 3 @@ -57,6 +59,8 @@ #define MAXFL 128 #define MAXRECS 6 /* reduce nr of fragments to this amount */ +#define DEFAULT_MAX_TIME 15 /* should be enough for every OS to boot */ + /* * By default, the kernel reads ahead for 128kb. This throws off our * measurements since we don't need the extra 128kb for each file. @@ -284,16 +288,22 @@ int i; if (!r) - goto remove; - - memset(record, 0, sizeof(record)); + return 0; file = fopen(r->filename, "r"); if (!file) - goto remove; + return 0; fd = fileno(file); fstat(fd, &statbuf); + /* prevent accidentally reading from a pipe */ + if (!(S_ISREG(statbuf.st_mode))) { + fclose(file); + return 0; + } + + memset(record, 0, sizeof(record)); + mmapptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); mincorebuf = malloc(statbuf.st_size/4096 + 1); @@ -341,7 +351,7 @@ if (rcount > 0) { /* some empty files slip through */ if (record[0].len == 0) - goto remove; + return 0; if (debug) { int tlen = 0; @@ -361,9 +371,6 @@ memcpy(r->data, record, sizeof(r->data)); return 1; } - -remove: - return 0; } static void get_ra_blocks(void) @@ -387,6 +394,7 @@ int ret; FILE *file; char buf[4096]; + struct stat statbuf; /* * at this time during boot we can guarantee that things like @@ -401,25 +409,43 @@ chdir(DEBUGFS_MNT); - file = fopen("tracing/current_tracer", "w"); - if (!file) { - perror("Unable to select tracer\n"); - exit(EXIT_FAILURE); - } - fprintf(file, "open"); - fclose(file); + if (stat("tracing/events/fs/do_sys_open", &statbuf) == 0) { + file = fopen("tracing/events/fs/do_sys_open/enable", "w"); + if (!file) { + perror("unable to enable tracing\n"); + exit(EXIT_FAILURE); + } + fprintf(file, "1"); + fclose(file); - file = fopen("tracing/current_tracer", "r"); - fgets(buf, 4096, file); - fclose(file); - if (strcmp(buf, "open\n") != 0) { - perror("Unable to select open tracer\n"); - exit(EXIT_FAILURE); + file = fopen("tracing/events/fs/do_sys_open/enable", "r"); + fgets(buf, 4096, file); + fclose(file); + if (strcmp(buf, "1\n") != 0) { + perror("enabling tracing failed\n"); + exit(EXIT_FAILURE); + } + } else { + file = fopen("tracing/current_tracer", "w"); + if (!file) { + perror("Unable to select tracer\n"); + exit(EXIT_FAILURE); + } + fprintf(file, "open"); + fclose(file); + + file = fopen("tracing/current_tracer", "r"); + fgets(buf, 4096, file); + fclose(file); + if (strcmp(buf, "open\n") != 0) { + perror("Unable to select open tracer\n"); + exit(EXIT_FAILURE); + } } file = fopen("tracing/tracing_enabled", "w"); if (!file) { - perror("Unable to enable tracing\n"); + perror("unable to enable tracing\n"); exit(EXIT_FAILURE); } fprintf(file, "1"); @@ -429,7 +455,7 @@ fgets(buf, 4096, file); fclose(file); if (strcmp(buf, "1\n") != 0) { - perror("Enabling tracing failed\n"); + perror("enabling tracing failed\n"); exit(EXIT_FAILURE); } @@ -446,6 +472,7 @@ int unmount; int ret; char buf[4096]; + struct stat statbuf; char filename[4096]; FILE *file; struct ra_struct *r; @@ -461,7 +488,7 @@ readahead_set_len(RA_NORMAL); /* - * by now the init process should have mounted debugf on a logical + * by now the init process should have mounted debugfs on a logical * location like /sys/kernel/debug, but if not then we temporarily * re-mount it ourselves */ @@ -473,16 +500,29 @@ exit(EXIT_FAILURE); } chdir(DEBUGFS_MNT); + } else { + chdir(".."); } /* stop tracing */ - file = fopen("tracing/tracing_enabled", "w"); - if (!file) { - perror("Unable to disable tracing\n"); - /* non-fatal */ + if (stat("tracing/events/fs/do_sys_open", &statbuf) == 0) { + file = fopen("tracing/events/fs/do_sys_open/enable", "w"); + if (!file) { + perror("unable to disable tracing\n"); + /* non-fatal */ + } else { + fprintf(file, "0"); + fclose(file); + } } else { - fprintf(file, "0"); - fclose(file); + file = fopen("tracing/tracing_enabled", "w"); + if (!file) { + perror("Unable to disable tracing\n"); + /* non-fatal */ + } else { + fprintf(file, "0"); + fclose(file); + } } file = fopen("tracing/trace", "r"); @@ -592,9 +632,12 @@ static void print_usage(const char *name) { printf("Usage: %s [OPTION...]\n", name); - printf(" -d, --debug Print debug output to stdout\n"); - printf(" -h, --help Show this help message\n"); - printf(" -v, --version Show version information and exit\n"); + printf(" -t N, --time=N Wait for N seconds before creating new\n"); + printf(" pack file (default %d)\n", DEFAULT_MAX_TIME); + printf (" --no-fork Remain in the foreground\n"); + printf(" -d, --debug Print debug output to stdout\n"); + printf(" -h, --help Show this help message\n"); + printf(" -v, --version Show version information and exit\n"); exit(EXIT_SUCCESS); } @@ -610,18 +653,22 @@ FILE *file; int pid = 0; pthread_t one, two, three, four; + int max_time = DEFAULT_MAX_TIME; + int no_fork = 0; while (1) { static struct option opts[] = { { "debug", 0, NULL, 'd' }, { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, + { "time", 1, NULL, 't' }, + { "no-fork", 0, NULL, 129 }, { 0, 0, NULL, 0 } }; int c; int index = 0; - c = getopt_long(argc, argv, "dhv", opts, &index); + c = getopt_long(argc, argv, "dhvt:", opts, &index); if (c == -1) break; switch (c) { @@ -634,6 +681,12 @@ case 'h': print_usage(argv[0]); break; + case 't': + max_time = atoi(optarg); + break; + case 129: + no_fork = 1; + break; default: ; } @@ -644,19 +697,22 @@ /* enable tracing open calls before we fork! */ trace_start(); - if (!fork()) { + if (no_fork || !fork()) { /* child */ - signal(SIGUSR1, trace_stop); - /* - * "" 15 seconds should be enough for everyone to boot"" - * -- Auke Kok, 2009 - */ - sleep(15); + signal(SIGTERM, trace_stop); + if (no_fork) + signal(SIGINT, trace_stop); + if (max_time > 0) + sleep(max_time); + else + pause(); /* * abort if we don't get a signal, so we can stop * the tracing and minimize the trace buffer size */ - signal(SIGUSR1, NULL); + signal(SIGTERM, NULL); + if (no_fork) + signal(SIGINT, NULL); trace_stop(0); } else { return EXIT_SUCCESS; @@ -679,7 +735,8 @@ readahead_set_len(RA_SMALL); - daemon(0,0); + if (!no_fork) + daemon(0,0); pthread_create(&one, NULL, one_thread, NULL); pthread_create(&two, NULL, one_thread, NULL); --- sreadahead-1.0.orig/Makefile +++ sreadahead-1.0/Makefile @@ -1,4 +1,4 @@ -CFLAGS ?= -Os -march=i686 -g +CFLAGS ?= -Os -g PROGS = sreadahead VERSION = "1.0" @@ -14,7 +14,9 @@ install: all mkdir -p $(DESTDIR)/sbin mkdir -p $(DESTDIR)/var/lib/sreadahead/debugfs + mkdir -p $(DESTDIR)/usr/share/man/man1 install -p -m 755 $(PROGS) $(DESTDIR)/sbin + install -p -m 644 sreadahead.8 $(DESTDIR)/usr/share/man/man8 dist: svn export . sreadahead-$(VERSION) --- sreadahead-1.0.orig/README +++ sreadahead-1.0/README @@ -74,7 +74,7 @@ readahead.packed file, and then doing it's work. Sreadahead will generate the pack file after 15 seconds automatically. -If this is too late, one can send sreadahead a SIGUSR1 signal at +If this is too late, one can send sreadahead a TERM signal at any time before this 15 seconds, to make sreadahead immediately stop tracing and create a pack file. --- sreadahead-1.0.orig/sreadahead.8 +++ sreadahead-1.0/sreadahead.8 @@ -0,0 +1,41 @@ +.TH sreadahead 8 "2009-07-20" "" "" +.SH NAME +sreadahead \- a readahead implementation optimized for solid state devices +.SH SYNOPSIS +.B sreadahead +[OPTION]... +.SH DESCRIPTION +.B sreadahead +is a daemon that reads data sequential by use from disk. Sreadahead does this by +retrieving the read order (in timestamp format) from an actual boot sequence and +storing a list of data that was read during that boot sequence in a flat +database. On the next boot this file can be used to load all the data described +in the database into memory and in order of use. +.SH OPTIONS +.TP +.B \-t\fR \fIN\fR, \fB\-\-time\fR=\fIN +make sreadahead stop after N seconds instead of the default 15 seconds, +.I N +may be zero to wait for +.B SIGTERM +.TP +.B \-\-no\-fork +remain in the foreground +.TP +.B \-d\fR, \fB\-\-debug +print debug output to stdout +.TP +.B \-h\fR, \fB\-\-help +show a help message and exit +.TP +.B \-v\fR, \fB\-\-version +show version information and exit +.SH AUTHOR +.PP +sreadahead is written by the Intel Corporation. This manual page was written by +Tobias Klauser for the Debian system (but may be used by +others). +.SH SEE ALSO +.PP +.BR readahead(2), +.BR readahead-list(8) --- sreadahead-1.0.orig/debian/sreadahead.upstart +++ sreadahead-1.0/debian/sreadahead.upstart @@ -0,0 +1,28 @@ +# sreadahead - Read required files in advance +# +# Runs the sreadahead daemon which reads data about files required +# during boot and reads them into the page cache in advance of their +# use. + +description "Read required files in advance" + +start on starting mountall +stop on stopped rc + +# Forks into the background both when reading from disk and when profiling +# (HDD mode won't fork, but that's ok because we'll wait for it in spawned). +expect fork + +# Whenkprofiling, give it three minutes after sending SIGTERM to write out +# the pack file. +kill timeout 180 + +# Don't treat a normal exit after reading finishes as a failure +normal exit 0 + +exec /sbin/sreadahead -t 0 + +# Normally sreadahead will exit on its own when it finishes, unless it's +# profiling - in which case we want to give the system another 30s to +# finish staring the desktop and other things. +pre-stop exec sleep 30 --- sreadahead-1.0.orig/debian/sreadahead.cron.monthly +++ sreadahead-1.0/debian/sreadahead.cron.monthly @@ -0,0 +1,7 @@ +#!/bin/sh +# +# sreadahead's data needs periodic regeneration, this is as easy as +# removing the old data +# + +rm -f /var/lib/sreadahead/pack || true --- sreadahead-1.0.orig/debian/copyright +++ sreadahead-1.0/debian/copyright @@ -0,0 +1,18 @@ +This is the Ubuntu package of sreadahead, the tool for reading required +files in advance during boot. + +Copyright © 2008-2009 Intel Corporation. + +Licence: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program 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 +General Public License for more details. + +On Ubuntu systems, the complete text of the GNU General Public License +can be found in ‘/usr/share/common-licenses/GPL’. --- sreadahead-1.0.orig/debian/sreadahead.postinst +++ sreadahead-1.0/debian/sreadahead.postinst @@ -0,0 +1,44 @@ +#!/bin/sh -e +# This script can be called in the following ways: +# +# After the package was installed: +# configure +# +# After a trigger is activated: +# triggered ... +# +# +# If prerm fails during upgrade or fails on failed upgrade: +# abort-upgrade +# +# If prerm fails during deconfiguration of a package: +# abort-deconfigure in-favour +# removing +# +# If prerm fails during replacement due to conflict: +# abort-remove in-favour + + +case "$1" in + configure) + ;; + + triggered) + # Force a profile + if [ -f /var/lib/sreadahead/pack ]; then + echo "sreadahead will be reprofiled on next reboot" + rm -f /var/lib/sreadahead/pack + fi + ;; + + abort-upgrade|abort-deconfigure|abort-remove) + ;; + + *) + echo "$0 called with unknown argument \`$1'" 1>&2 + exit 1 + ;; +esac + +#DEBHELPER# +exit 0 --- sreadahead-1.0.orig/debian/rules +++ sreadahead-1.0/debian/rules @@ -0,0 +1,81 @@ +#!/usr/bin/make -f +# debian/rules for the sreadahead package. +# Copyright © 2009 Canonical Ltd. +# Author: Scott James Remnant + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export DH_OPTIONS + +CFLAGS = -Wall -g +LDFLAGS = -Wl,-z,relro -Wl,-z,now + +# Disable optimisations if noopt found in $DEB_BUILD_OPTIONS +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 + LDFLAGS += -Wl,-O0 +else + CFLAGS += -Os + LDFLAGS += -Wl,-O1 +endif + + +# Build the package +build: build-stamp +build-stamp: + dh_testdir + + $(MAKE) CFLAGS="$(CFLAGS) $(LDFLAGS)" + touch $@ + +# Install files +install: +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs -v + + $(MAKE) DESTDIR="$(CURDIR)/debian/tmp" install + + +binary: binary-indep binary-arch + +# Build architecture-independent files here. +binary-indep: +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: DH_OPTIONS=-a +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs Changelog + dh_installman + dh_installdocs + dh_installexamples + dh_installcron + dh_install --sourcedir=debian/tmp + dh_installinit --upstart-only --no-start + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_makeshlibs + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + + +# Clean up the mess we made +clean: + dh_testdir + + $(MAKE) clean + dh_clean + + +.PHONY: build install binary-indep binary-arch binary clean --- sreadahead-1.0.orig/debian/sreadahead.manpages +++ sreadahead-1.0/debian/sreadahead.manpages @@ -0,0 +1 @@ +sreadahead.8 --- sreadahead-1.0.orig/debian/sreadahead.triggers +++ sreadahead-1.0/debian/sreadahead.triggers @@ -0,0 +1,2 @@ +interest /etc/init +interest /etc/init.d --- sreadahead-1.0.orig/debian/compat +++ sreadahead-1.0/debian/compat @@ -0,0 +1 @@ +7 --- sreadahead-1.0.orig/debian/changelog +++ sreadahead-1.0/debian/changelog @@ -0,0 +1,52 @@ +sreadahead (1.0-3) karmic; urgency=low + + FFE LP: #427356. + + * debian/rules, debian/sreadahead.install: + - Install Upstart job using dh_installinit + * debian/control: + - Bump build-dependency on debhelper for Upstart-aware dh_installinit + * debian/sreadahead.upstart: + - Start before mounting filesystems. + + -- Scott James Remnant Tue, 15 Sep 2009 03:26:20 +0100 + +sreadahead (1.0-2) karmic; urgency=low + + * Drop our patch to chdir to correct path if debugfs is mounted, + replacing with patch from Upstream Issue #12/SVN -r36. + * Apply patch from Upstream Issue #11/SVN -r38 to avoid reading from + things such as FIFOs. + + * Patch to remove -march=native from default CFLAGS. + * Patch to place manual page in correct section. + * Patch to replace SIGUSR1 stop signal with SIGTERM. + * Rework --no-fork patch. + * Patch to sleep forever with -t 0. + * Patch to use the open() TRACE_EVENT patch included in Ubuntu + kernels. + + * Fix control to not mention being ext3-only. LP: #347477. + * Provide/Conflict/Replace readahead. LP: #349068. + + * Update upstart job to 0.6.0. + * Automatically reprofile if files in /etc/init or /etc/init.d are + updated. + + -- Scott James Remnant Mon, 27 Jul 2009 14:46:32 +0100 + +sreadahead (1.0-1) jaunty; urgency=low + + * Initial package. + + * Apply patch from Upstream SVN -r31 to support -t option. + * Apply patch from Upstream Issue #2 to support PowerPC. + * Apply patch from Upstream Issue #5 to support 2.6.28. + * Add manual page from Upstream Issue #6 and install into section 8. + * Apply patch from Upstream Issue #7 to document -t option. + + * Increase maximum expected boot time to 60s. + * Patch to add --no-fork option to remain in the foreground. + * Patch to chdir to correct path if debugfs is mounted. + + -- Scott James Remnant Fri, 20 Feb 2009 13:15:52 +0000 --- sreadahead-1.0.orig/debian/sreadahead.postrm +++ sreadahead-1.0/debian/sreadahead.postrm @@ -0,0 +1,61 @@ +#!/bin/sh -e +# This script can be called in the following ways: +# +# After the package was removed: +# remove +# +# After the package was purged: +# purge +# +# After the package was upgraded: +# upgrade +# if that fails: +# failed-upgrade +# +# +# After all of the packages files have been replaced: +# disappear +# +# +# If preinst fails during install: +# abort-install +# +# If preinst fails during upgrade of removed package: +# abort-install +# +# If preinst fails during upgrade: +# abort-upgrade + + +# Remove pack file +purge_files() +{ + if [ -f /var/lib/sreadahead/pack ]; then + rm -f /var/lib/sreadahead/pack || true + rmdir /var/lib/sreadahead || true + fi +} + + +case "$1" in + remove) + ;; + + purge) + purge_files + ;; + + upgrade|failed-upgrade|disappear) + ;; + + abort-install|abort-upgrade) + ;; + + *) + echo "$0 called with unknown argument \`$1'" 1>&2 + exit 1 + ;; +esac + +#DEBHELPER# +exit 0 --- sreadahead-1.0.orig/debian/sreadahead.install +++ sreadahead-1.0/debian/sreadahead.install @@ -0,0 +1,2 @@ +/sbin/sreadahead +/var/lib/sreadahead --- sreadahead-1.0.orig/debian/control +++ sreadahead-1.0/debian/control @@ -0,0 +1,24 @@ +Source: sreadahead +Section: admin +Priority: optional +Maintainer: Scott James Remnant +Standards-Version: 3.8.0.0 +Build-Depends: debhelper (>= 7.3.15ubuntu2) +Vcs-Bzr: http://bazaar.launchpad.net/~ubuntu-core-dev/sreadahead/ubuntu + +Package: sreadahead +Architecture: any +Depends: ${shlibs:Depends}, upstart (>= 0.6.0) +Conflicts: readahead +Provides: readahead +Replaces: readahead +Description: Read required files in advance during boot + sreadahead is a daemon that reads data sequential by use from + disk. It does this by retrieving the read order (in timestamp + format) from an actual boot sequence and storing a list of data that + was read during that boot sequence in a flat database. + . + On the next boot this file can be used to load all the data described + in the database into memory and in order of use. + . + sreadahead requires a kernel patch included in the Ubuntu kernel.