Never inline map_trampoline_pages, to avoid conflicting stack garbage.
[ksplice.git] / ksplice-create.in
blob891f7d0675fc8fc32ecea5fab9f5b4b5c2b8994a
1 #!/usr/bin/perl
3 # Copyright (C) 2007-2009 Ksplice, Inc.
4 # Authors: Jeff Arnold, Anders Kaseorg, Tim Abbott
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License, version 2.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 # 02110-1301, USA.
19 use strict;
20 use warnings;
21 use lib 'KSPLICE_DATA_DIR';
22 use Ksplice;
24 my ($patchfile, $diffext, $git, $orig_config_dir, $jobs, $kid);
25 my $description;
26 my $series = 0;
27 my $build_modules = 0;
28 my @only_targets;
29 my @extra_match;
30 my $standalone;
31 my ($prebuild, $skip_prebuild) = (0, 0);
32 my @patch_opt = "-p1";
33 GetOptions(@common_options,
34 "id=s" => \$kid,
35 "patch=s" => \$patchfile,
36 "description=s" => \$description,
37 "diffext=s" => \$diffext,
38 "git=s" => \$git,
39 "prebuild" => \$prebuild,
40 "series!" => \$series,
41 "build-modules!" => \$build_modules,
42 "only-targets=s" => \@only_targets,
43 "extra-match=s" => \@extra_match,
44 "standalone!" => \$standalone,
45 "skip-prebuild" => \$skip_prebuild,
46 "jobs|j:i" => \$jobs,
47 "config=s" => \$orig_config_dir,
48 "patch-opt=s" => \@patch_opt) or pod2usage(1);
50 pod2usage(1) if($help || scalar(@ARGV) != 1);
51 my $actions = (defined $patchfile) + (defined $diffext) + (defined $git) + $prebuild;
52 pod2usage(1) if($actions != 1);
54 my $have_Git = eval { require Git };
55 $have_Git or die $@ if defined $git;
57 my ($linuxtree) = (abs_path($ARGV[0]));
59 if(!defined $orig_config_dir) {
60 $orig_config_dir = "$linuxtree/ksplice";
62 else {
63 $orig_config_dir = abs_path($orig_config_dir);
64 if($orig_config_dir =~ $linuxtree) {
65 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
68 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
69 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
71 if(! -e "$orig_config_dir/System.map") {
72 die "Failed to find System.map file in ORIG_CONFIG directory";
75 my $kernel_headers_dir = "$orig_config_dir/build";
76 $kernel_headers_dir = $linuxtree unless(-d $kernel_headers_dir);
78 my @kbuild_flags = ();
79 if(-e "$orig_config_dir/flags") {
80 open(FLAGS, '<', "$orig_config_dir/flags") or die;
81 local $/;
82 @kbuild_flags = shellwords(scalar <FLAGS>);
83 close(FLAGS);
86 $ENV{KSPLICE_VERBOSE} = $Verbose::level;
87 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
89 my @chars = ('a'..'z', 0..9);
90 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
91 my $ksplice = "ksplice-$kid";
92 $ENV{KSPLICE_KID} = $kid;
94 # Some versions of Fedora have System.map files whose symbol addresses disagree
95 # with the running kernel by a constant address offset. Here, Ksplice notes the
96 # System.map address for printk so that it can later compare this address against
97 # the kernel's address for printk. This comparison helps Ksplice work around
98 # this Fedora problem, and this comparison also helps Ksplice detect whether
99 # the user has provided an incorrect System.map file.
100 my $map_printk = runstr("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
102 print "Starting kernel builds (this process might take a long time)...\n"
103 if($Verbose::level >= 0);
105 $patchfile = abs_path($patchfile) if(defined $patchfile);
107 my $origdir = getcwd();
108 chdir($linuxtree);
110 my $git_rev;
111 my $git_repo;
112 if (defined $git) {
113 $git_repo = Git->repository();
114 ($git_rev) = $git_repo->command(qw(rev-parse --verify), $git);
115 } else {
116 $git_repo = eval { Git->repository() };
119 my @make = ("make", "-rR");
120 if(defined $jobs) {
121 push @make, "-j$jobs";
122 } elsif(defined $ENV{CONCURRENCY_LEVEL}) {
123 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
126 if($Verbose::level >= 2) {
127 push @make, "V=1";
128 } elsif($Verbose::level < 0) {
129 push @make, "-s";
132 $ENV{PATH} = "$datadir:$ENV{PATH}";
133 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
135 push(@make_ksplice, "KSPLICE_BUILD_MODULES=1") if ($build_modules);
136 if(-e "include/config/kernel.release") {
137 push(@make_ksplice, "-o", "include/config/kernel.release");
140 my @revert_flags = ("KSPLICE_MODE=revert");
141 push(@revert_flags, "KSPLICE_SERIES=y") if ($series);
143 sub git_have_ksplice_pre {
144 return $git_repo->command(qw(for-each-ref refs/ksplice/pre)) ne '';
147 if(-e "$orig_config_dir/.config" && !-e "$linuxtree/.config") {
148 copy("$orig_config_dir/.config", "$linuxtree/.config");
149 utime((stat("$orig_config_dir/.config"))[8, 9],
150 "$linuxtree/.config");
153 sub revert_orig() {
154 for(split(/\0/, runstr(qw(find -name *.KSPLICE_presrc -print0)))) {
155 my ($file) = m/^(.*)\.KSPLICE_presrc$/;
156 if ($series) {
157 unlink($_);
158 } else {
159 rename($_, $file);
162 if (defined $git_repo && git_have_ksplice_pre) {
163 if ($series) {
164 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: freeze", qw(refs/ksplice/pre HEAD refs/ksplice/pre));
165 } else {
166 $git_repo->command_noisy(qw(update-index --refresh));
167 $git_repo->command_noisy(qw(read-tree -m --trivial -u refs/ksplice/pre));
168 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: revert", qw(HEAD refs/ksplice/pre HEAD));
171 runval(@make_ksplice, @revert_flags);
173 revert_orig();
175 if (defined $git_repo && !git_have_ksplice_pre) {
176 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: snap", qw(refs/ksplice/pre HEAD), '');
179 if(!$skip_prebuild) {
180 if(-e "$orig_config_dir/.config") {
181 copy("$orig_config_dir/.config", "$linuxtree/.config");
182 utime((stat("$orig_config_dir/.config"))[8, 9],
183 "$linuxtree/.config");
185 my @snap_flags = ("KSPLICE_MODE=snap");
186 runval_raw(@make_ksplice, @snap_flags) == 0 or
187 die "Aborting: Prebuild failed";
188 sleep(1);
190 exit(0) if($prebuild);
192 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
193 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
194 $patchfile = "$tmpdir/patch";
196 if(defined $diffext) {
197 open(PATCH, '>', $patchfile) or die;
198 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
199 my ($file) = /^(.*)\Q$diffext\E/ or die;
200 print PATCH runstr("diff", "-u", "--", $file, $_);
202 close(PATCH) or die;
203 @patch_opt = ("-p0");
206 my $kmodsrc = "$tmpdir/kmodsrc";
207 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
208 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
210 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
212 if (!defined($standalone)) {
213 $standalone = (!-e "$linuxtree/.config" || runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
215 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
217 my @make_kmodsrc_install = (@make_kmodsrc, qw(modules_install --old-file=_modinst_post --old-file=_emodinst_post), "MAKE=make --old-file=_modinst_post --old-file=_emodinst_post", "INSTALL_MOD_STRIP=1", "MODLIB=$tmpdir/ksplice-modules");
219 runval(@make_kmodsrc);
220 runval(@make_kmodsrc_install);
222 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
224 if (defined $git) {
225 $git_repo->command_noisy(qw(update-index --refresh));
226 $git_repo->command_noisy(qw(read-tree -m --trivial -u), $git_rev);
227 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: diff", "HEAD", $git_rev);
229 open(PATCH, '>', $patchfile) or die;
230 if ($git_repo->command(qw(rev-parse --verify HEAD^)) eq
231 $git_repo->command(qw(rev-parse --verify refs/ksplice/pre))) {
232 print PATCH scalar($git_repo->command(qw(log -1 HEAD --))), "\n";
234 print PATCH scalar($git_repo->command(qw(diff-tree -p refs/ksplice/pre HEAD --)));
235 close(PATCH) or die;
236 } else {
237 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_presrc");
240 my @diff_flags = ("KSPLICE_MODE=diff");
241 push @diff_flags, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
242 push @diff_flags, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
243 if(runval_raw(@make_ksplice, @diff_flags) != 0) {
244 revert_orig() if(defined($diffext));
245 die "Aborting: Applying the patch appears to break the kernel build";
248 sub copy_debug {
249 my ($file) = @_;
250 my ($dir, $base) = (dirname($file), basename($file));
251 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
252 copy($file, "$tmpdir/objects/$file");
253 my $cmdfile = "$dir/.$base.cmd";
254 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
257 mkdir("$tmpdir/objects");
258 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
259 next if (basename($_) =~ m/^(?:vmlinux|vmlinux\.o|\.tmp_vmlinux[0-9]+|\.tmp_kallsyms[0-9]+.o)\.KSPLICE_pre$/);
260 copy_debug($_);
261 copy_debug($1) if (m/^(.*)\.KSPLICE_pre(?:src)?$/);
264 my @modulepaths = ();
265 my @modules = ();
266 foreach(glob("$kmodsrc/*.mod.KSPLICE")) {
267 open MOD, '<', $_;
268 chomp(my $mod = <MOD>);
269 close MOD;
270 push @modulepaths, "$mod.ko" if (basename($mod) ne "vmlinux");
271 push @modules, basename($mod);
274 if(!@modules) {
275 revert_orig() if(defined($diffext));
276 print STDERR "No changes detected.\n";
277 exit(66);
280 if ($build_modules) {
281 mkdir("$tmpdir/modules");
282 runval(@make_ksplice, "KSPLICE_MODE=modinst", "MODLIB=$tmpdir/modules", "INSTALL_MOD_STRIP=1", "modules=@modulepaths");
285 revert_orig() if(defined($diffext));
287 runval(@make_kmodsrc, "KSPLICE_MODULES=@modules", "KSPLICE_SKIP_CORE=1");
288 runval(@make_kmodsrc_install, "KSPLICE_MODULES=@modules", "KSPLICE_SKIP_CORE=1");
290 chdir($tmpdir);
291 mkdir($ksplice);
292 move($patchfile, $ksplice);
293 if ($description) {
294 write_file("$ksplice/description", "$description\n");
296 write_file("$ksplice/api-version", "KSPLICE_API_VERSION\n");
297 write_file("$ksplice/timestamp", time() . "\n");
298 runval_outfile("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
299 open(CONTENTS, ">", "$ksplice/contents");
300 foreach my $mod (@modules) {
301 (my $target = $mod) =~ s/-/_/g;
302 my $mid = "${kid}_$target";
303 my $module = "ksplice-$mid";
304 rename("$tmpdir/ksplice-modules/extra/$module-new.ko", "$ksplice/$module-new.ko");
305 print CONTENTS "new_code $target ksplice_$mid $module-new.ko\n";
306 rename("$tmpdir/ksplice-modules/extra/$module-old.ko", "$ksplice/$module-old.ko");
307 print CONTENTS "old_code $target ksplice_$mid $module-old.ko\n";
309 if ($standalone) {
310 rename("$tmpdir/ksplice-modules/extra/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
311 print CONTENTS "core ksplice_$kid ksplice-$kid.ko\n";
313 if ($build_modules) {
314 foreach my $mod (@modulepaths) {
315 (my $target = basename($mod)) =~ s/-/_/g;
316 print CONTENTS "target $target $mod\n";
320 mkdir("$ksplice/debug");
321 rename("objects", "$ksplice/debug/objects");
322 rename("modules", "$ksplice/modules") if ($build_modules);
323 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
325 close(CONTENTS);
326 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
327 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
328 print "Ksplice update tarball written to $ksplice.tar.gz\n";
329 exit(0);
331 =head1 NAME
333 ksplice-create - Create a set of kernel modules for a rebootless kernel update
335 =head1 SYNOPSIS
337 B<ksplice-create> [I<OPTIONS>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
339 B<ksplice-create> [I<OPTIONS>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
341 B<ksplice-create> [I<OPTIONS>] B<--git=>I<COMMIT> I<KERNEL_SOURCE>
343 B<ksplice-create> [I<OPTIONS>] B<--prebuild> I<KERNEL_SOURCE>
345 =head1 DESCRIPTION
347 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
348 will apply a user-specified source code patch to the running binary kernel.
350 Before you use B<ksplice-create> on a patch, you should confirm that the
351 desired source code change does not make any semantic changes to kernel data
352 structures--that is, changes that would require existing instances of kernel
353 data structures to be transformed (e.g., a patch that adds a field to a global
354 data structure would require the existing data structures to change). If you
355 use Ksplice on a patch that changes data structure semantics, Ksplice will not
356 detect the problem and you could experience kernel problems as a result.
358 The to-be-applied source code patch can be specified by providing a L<patch(1)>
359 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
360 (B<--diffext=>I<EXTENSION>).
362 If a file extension is specified, then the desired source code patch will be
363 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
364 whose names end with the extra extension I<EXTENSION> against the corresponding
365 files without the extra extension. Only the new files containing the extra
366 extension in their filenames should be modified.
368 Here is an example of using a file extension to specify a patch:
370 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
371 [edit sys.c.prctl_fixed to include the desired changes]
372 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
374 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
375 original source code. If your Linux distribution applies patches to the Linux
376 kernel during the kernel build process, then those patches must be applied to
377 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
378 directory. B<ksplice-create> will not modify the source code in the
379 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
380 directory tree.
382 I<ORIG_CONFIG> can be used to specify the directory containing the
383 to-be-updated kernel's original F<.config> file and original F<System.map> file
384 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
385 I<KERNEL_SOURCE>B</ksplice>.
387 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
388 close to the compiler and assembler originally used to build the running kernel
389 as possible. If the current compiler and linker are too different from the
390 original compiler and linker, B<ksplice-apply> will abort when applying the
391 update.
393 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
394 containing the desired Ksplice update modules. This tarball will be created in
395 the current directory, and it can be manipulated using the other Ksplice
396 utilities, such as B<ksplice-apply>.
398 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
399 directory, it must build that kernel from scratch, which is much slower than
400 the rest of the update-creation process. B<--prebuild> can be used to perform
401 this initial kernel build without providing a source code patch.
403 In order to patch a function that has previously been patched by Ksplice, the
404 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
405 contains the source for the currently running kernel, including any patches
406 that have previously been applied by Ksplice.
408 =head1 OPTIONS
410 =over 8
412 =item B<--patch=>I<PATCH_FILE>
414 Builds a Ksplice update out of the given L<patch(1)> file I<PATCH_FILE>.
416 =item B<--diffext=>I<EXTENSION>
418 Builds a Ksplice update using the modified source files with names ending in
419 I<EXTENSION>. The patch will be determined by comparing all of the files in the
420 I<KERNEL_SOURCE> directory tree whose names end with the extra extension
421 I<EXTENSION> against the corresponding files without the extra extension.
423 =item B<--git>=I<COMMIT>
425 Builds a Ksplice update using the commit I<COMMIT> in the Git working tree
426 I<KERNEL_SOURCE>. The original state corresponding to the running kernel is
427 remembered in the Git ref B<refs/ksplice/pre>, which will be created from the
428 current B<HEAD> if it does not yet exist (and can be changed using the
429 B<--series> option). Therefore, the source code change to be applied
430 corresponds to the output of B<git diff ksplice/pre> I<COMMIT>.
432 =item B<--prebuild>
434 Compiles the original source code that will be needed to build future Ksplice
435 updates. If any Ksplice updates have previously been built in the
436 I<KERNEL_SOURCE> tree, the source files in the tree are reverted to their
437 original state.
439 =item B<--series>
441 Specifies that the current state of the I<KERNEL_SOURCE> tree should be used as
442 the original source that corresponds to the running kernel. If a Ksplice update
443 has recently been built in the I<KERNEL_SOURCE> tree, this option specifies that
444 the Ksplice update being built should be applied after the previous update in
445 series. This option can be used with B<--prebuild> to forget the previous
446 original state and perform no other action.
448 =item B<--build-modules>
450 For a patch that includes changes to kernel modules, in addition to building a
451 hot update that can be applied to the running kernel, this option will cause
452 B<ksplice-create> to generate a set of new modules based on the updated source
453 code. These modules can be used to replace the kernel modules stored on disk,
454 where they can later be loaded normally after part of the hot update has been
455 applied using L<ksplice-apply(1)> B<--partial>.
457 =item B<-v>, B<--verbose>
459 Causes B<ksplice-create> to print debugging messages about its progress. Using
460 multiple -v options increases the verbosity. The maximum is 2.
462 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
464 Specifies the number of jobs to run simultaneously while performing kernel
465 builds. B<ksplice-create> also honors the environment variable
466 CONCURRENCY_LEVEL.
468 =item B<--patch-opt=>I<OPTIONS>
470 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
471 B<-p1> is passed to B<patch>. If this option is specified, then only the
472 specified options will be passed to B<patch>. This option can be repeated in
473 order to pass multiple options to B<patch>. This option is ignored when the
474 to-be-applied source code patch is specified using B<--diffext>.
476 =item B<--id=>I<ID>
478 Specifies the unique value that will be used as the identifier of the
479 Ksplice update. This identifier will, for example, appear in the name
480 of the update tarball. By default, a random 8-character ID will be
481 generated.
483 =back
485 =head1 SEE ALSO
487 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
489 =head1 BUGS
491 Please report bugs to <PACKAGE_BUGREPORT>.
493 =head1 AUTHORS
495 Jeff Arnold, Anders Kaseorg, and Tim Abbott
497 =head1 COPYRIGHT
499 Copyright (C) 2007-2009 Ksplice, Inc.
501 This is free software and documentation. You can redistribute and/or modify it
502 under the terms of the GNU General Public License, version 2.
504 =cut