Never inline init_symbol_arrays, to avoid conflicting stack garbage.
[ksplice.git] / ksplice-create.in
blob0bb9f68539cd83c3dadb30727660d986af8cd3e6
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 @exclude_match;
31 my $standalone;
32 my ($prebuild, $skip_prebuild) = (0, 0);
33 my @patch_opt = "-p1";
34 GetOptions(@common_options,
35 "id=s" => \$kid,
36 "patch=s" => \$patchfile,
37 "description=s" => \$description,
38 "diffext=s" => \$diffext,
39 "git=s" => \$git,
40 "prebuild" => \$prebuild,
41 "series!" => \$series,
42 "build-modules!" => \$build_modules,
43 "only-targets=s" => \@only_targets,
44 "extra-match=s" => \@extra_match,
45 "exclude-match=s" => \@exclude_match,
46 "standalone!" => \$standalone,
47 "skip-prebuild" => \$skip_prebuild,
48 "jobs|j:i" => \$jobs,
49 "config=s" => \$orig_config_dir,
50 "patch-opt=s" => \@patch_opt) or pod2usage(1);
52 pod2usage(1) if($help || scalar(@ARGV) != 1);
53 my $actions = (defined $patchfile) + (defined $diffext) + (defined $git) + $prebuild;
54 pod2usage(1) if($actions != 1);
56 my $have_Git = eval { require Git };
57 $have_Git or die $@ if defined $git;
59 my ($linuxtree) = (abs_path($ARGV[0]));
61 if(!defined $orig_config_dir) {
62 $orig_config_dir = "$linuxtree/ksplice";
64 else {
65 $orig_config_dir = abs_path($orig_config_dir);
66 if($orig_config_dir =~ $linuxtree) {
67 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
70 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
71 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
73 if(! -e "$orig_config_dir/System.map") {
74 die "Failed to find System.map file in ORIG_CONFIG directory";
77 my $kernel_headers_dir = "$orig_config_dir/build";
78 $kernel_headers_dir = $linuxtree unless(-d $kernel_headers_dir);
80 my @kbuild_flags = ();
81 if(-e "$orig_config_dir/flags") {
82 open(FLAGS, '<', "$orig_config_dir/flags") or die;
83 local $/;
84 @kbuild_flags = shellwords(scalar <FLAGS>);
85 close(FLAGS);
88 $ENV{KSPLICE_VERBOSE} = $Verbose::level;
89 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
91 my @chars = ('a'..'z', 0..9);
92 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
93 my $ksplice = "ksplice-$kid";
94 $ENV{KSPLICE_KID} = $kid;
96 # Some versions of Fedora have System.map files whose symbol addresses disagree
97 # with the running kernel by a constant address offset. Here, Ksplice notes the
98 # System.map address for printk so that it can later compare this address against
99 # the kernel's address for printk. This comparison helps Ksplice work around
100 # this Fedora problem, and this comparison also helps Ksplice detect whether
101 # the user has provided an incorrect System.map file.
102 my $map_printk = runstr("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
104 print "Starting kernel builds (this process might take a long time)...\n"
105 if($Verbose::level >= 0);
107 $patchfile = abs_path($patchfile) if(defined $patchfile);
109 my $origdir = getcwd();
110 chdir($linuxtree);
112 my $git_rev;
113 my $git_repo;
114 if (defined $git) {
115 $git_repo = Git->repository();
116 ($git_rev) = $git_repo->command(qw(rev-parse --verify), $git);
117 } else {
118 $git_repo = eval { Git->repository() };
121 my @make = ("make", "-rR");
122 if(defined $jobs) {
123 push @make, "-j$jobs";
124 } elsif(defined $ENV{CONCURRENCY_LEVEL}) {
125 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
128 if($Verbose::level >= 2) {
129 push @make, "V=1";
130 } elsif($Verbose::level < 0) {
131 push @make, "-s";
134 $ENV{PATH} = "$datadir:$ENV{PATH}";
135 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
137 push(@make_ksplice, "KSPLICE_BUILD_MODULES=1") if ($build_modules);
138 if(-e "include/config/kernel.release") {
139 push(@make_ksplice, "-o", "include/config/kernel.release");
142 my @revert_flags = ("KSPLICE_MODE=revert");
143 push(@revert_flags, "KSPLICE_SERIES=y") if ($series);
145 sub git_have_ksplice_pre {
146 return $git_repo->command(qw(for-each-ref refs/ksplice/pre)) ne '';
149 if(-e "$orig_config_dir/.config" && !-e "$linuxtree/.config") {
150 copy("$orig_config_dir/.config", "$linuxtree/.config");
151 utime((stat("$orig_config_dir/.config"))[8, 9],
152 "$linuxtree/.config");
155 sub revert_orig() {
156 for(split(/\0/, runstr(qw(find -name *.KSPLICE_presrc -print0)))) {
157 my ($file) = m/^(.*)\.KSPLICE_presrc$/;
158 if ($series) {
159 unlink($_);
160 } else {
161 rename($_, $file);
164 if (defined $git_repo && git_have_ksplice_pre) {
165 if ($series) {
166 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: freeze", qw(refs/ksplice/pre HEAD refs/ksplice/pre));
167 } else {
168 $git_repo->command_noisy(qw(update-index --refresh));
169 $git_repo->command_noisy(qw(read-tree -m --trivial -u refs/ksplice/pre));
170 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: revert", qw(HEAD refs/ksplice/pre HEAD));
173 runval(@make_ksplice, @revert_flags);
175 revert_orig();
177 if (defined $git_repo && !git_have_ksplice_pre) {
178 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: snap", qw(refs/ksplice/pre HEAD), '');
181 if(!$skip_prebuild) {
182 if(-e "$orig_config_dir/.config") {
183 copy("$orig_config_dir/.config", "$linuxtree/.config");
184 utime((stat("$orig_config_dir/.config"))[8, 9],
185 "$linuxtree/.config");
187 my @snap_flags = ("KSPLICE_MODE=snap");
188 runval_raw(@make_ksplice, @snap_flags) == 0 or
189 die "Aborting: Prebuild failed";
190 sleep(1);
192 exit(0) if($prebuild);
194 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
195 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
196 $patchfile = "$tmpdir/patch";
198 if(defined $diffext) {
199 open(PATCH, '>', $patchfile) or die;
200 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
201 my ($file) = /^(.*)\Q$diffext\E/ or die;
202 print PATCH runstr("diff", "-u", "--", $file, $_);
204 close(PATCH) or die;
205 @patch_opt = ("-p0");
208 my $kmodsrc = "$tmpdir/kmodsrc";
209 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
210 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
212 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
214 if (!defined($standalone)) {
215 $standalone = (!-e "$linuxtree/.config" || runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
217 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
219 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");
221 runval(@make_kmodsrc);
222 runval(@make_kmodsrc_install);
224 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
226 if (defined $git) {
227 $git_repo->command_noisy(qw(update-index --refresh));
228 $git_repo->command_noisy(qw(read-tree -m --trivial -u), $git_rev);
229 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: diff", "HEAD", $git_rev);
231 open(PATCH, '>', $patchfile) or die;
232 if ($git_repo->command(qw(rev-parse --verify HEAD^)) eq
233 $git_repo->command(qw(rev-parse --verify refs/ksplice/pre))) {
234 print PATCH scalar($git_repo->command(qw(log -1 HEAD --))), "\n";
236 print PATCH scalar($git_repo->command(qw(diff-tree -p refs/ksplice/pre HEAD --)));
237 close(PATCH) or die;
238 } else {
239 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_presrc");
242 my @diff_flags = ("KSPLICE_MODE=diff");
243 push @diff_flags, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
244 push @diff_flags, "KSPLICE_EXCLUDE_MATCH=@exclude_match" if (@exclude_match);
245 push @diff_flags, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
246 if(runval_raw(@make_ksplice, @diff_flags) != 0) {
247 revert_orig() if(defined($diffext));
248 die "Aborting: Applying the patch appears to break the kernel build";
251 sub copy_debug {
252 my ($file) = @_;
253 my ($dir, $base) = (dirname($file), basename($file));
254 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
255 copy($file, "$tmpdir/objects/$file");
256 my $cmdfile = "$dir/.$base.cmd";
257 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
260 mkdir("$tmpdir/objects");
261 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
262 next if (basename($_) =~ m/^(?:vmlinux|vmlinux\.o|\.tmp_vmlinux[0-9]+|\.tmp_kallsyms[0-9]+.o)\.KSPLICE_pre$/);
263 copy_debug($_);
264 copy_debug($1) if (m/^(.*)\.KSPLICE_pre(?:src)?$/);
267 my @modulepaths = ();
268 my @modules = ();
269 foreach(glob("$kmodsrc/*.mod.KSPLICE")) {
270 open MOD, '<', $_;
271 chomp(my $mod = <MOD>);
272 close MOD;
273 push @modulepaths, "$mod.ko" if (basename($mod) ne "vmlinux");
274 push @modules, basename($mod);
277 if(!@modules) {
278 revert_orig() if(defined($diffext));
279 print STDERR "No changes detected.\n";
280 exit(66);
283 if ($build_modules) {
284 mkdir("$tmpdir/modules");
285 runval(@make_ksplice, "KSPLICE_MODE=modinst", "MODLIB=$tmpdir/modules", "INSTALL_MOD_STRIP=1", "modules=@modulepaths");
288 revert_orig() if(defined($diffext));
290 runval(@make_kmodsrc, "KSPLICE_MODULES=@modules", "KSPLICE_SKIP_CORE=1");
291 runval(@make_kmodsrc_install, "KSPLICE_MODULES=@modules", "KSPLICE_SKIP_CORE=1");
293 chdir($tmpdir);
294 mkdir($ksplice);
295 move($patchfile, $ksplice);
296 if ($description) {
297 write_file("$ksplice/description", "$description\n");
299 write_file("$ksplice/api-version", "KSPLICE_API_VERSION\n");
300 write_file("$ksplice/timestamp", time() . "\n");
301 runval_outfile("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
302 open(CONTENTS, ">", "$ksplice/contents");
303 foreach my $mod (@modules) {
304 (my $target = $mod) =~ s/-/_/g;
305 my $mid = "${kid}_$target";
306 my $module = "ksplice-$mid";
307 rename("$tmpdir/ksplice-modules/extra/$module-new.ko", "$ksplice/$module-new.ko");
308 print CONTENTS "new_code $target ksplice_$mid $module-new.ko\n";
309 rename("$tmpdir/ksplice-modules/extra/$module-old.ko", "$ksplice/$module-old.ko");
310 print CONTENTS "old_code $target ksplice_$mid $module-old.ko\n";
312 if ($standalone) {
313 rename("$tmpdir/ksplice-modules/extra/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
314 print CONTENTS "core ksplice_$kid ksplice-$kid.ko\n";
316 if ($build_modules) {
317 foreach my $mod (@modulepaths) {
318 (my $target = basename($mod)) =~ s/-/_/g;
319 print CONTENTS "target $target $mod\n";
323 mkdir("$ksplice/debug");
324 rename("objects", "$ksplice/debug/objects");
325 rename("modules", "$ksplice/modules") if ($build_modules);
326 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
328 close(CONTENTS);
329 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
330 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
331 print "Ksplice update tarball written to $ksplice.tar.gz\n";
332 exit(0);
334 =head1 NAME
336 ksplice-create - Create a set of kernel modules for a rebootless kernel update
338 =head1 SYNOPSIS
340 B<ksplice-create> [I<OPTIONS>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
342 B<ksplice-create> [I<OPTIONS>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
344 B<ksplice-create> [I<OPTIONS>] B<--git=>I<COMMIT> I<KERNEL_SOURCE>
346 B<ksplice-create> [I<OPTIONS>] B<--prebuild> I<KERNEL_SOURCE>
348 =head1 DESCRIPTION
350 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
351 will apply a user-specified source code patch to the running binary kernel.
353 Before you use B<ksplice-create> on a patch, you should confirm that the
354 desired source code change does not make any semantic changes to kernel data
355 structures--that is, changes that would require existing instances of kernel
356 data structures to be transformed (e.g., a patch that adds a field to a global
357 data structure would require the existing data structures to change). If you
358 use Ksplice on a patch that changes data structure semantics, Ksplice will not
359 detect the problem and you could experience kernel problems as a result.
361 The to-be-applied source code patch can be specified by providing a L<patch(1)>
362 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
363 (B<--diffext=>I<EXTENSION>).
365 If a file extension is specified, then the desired source code patch will be
366 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
367 whose names end with the extra extension I<EXTENSION> against the corresponding
368 files without the extra extension. Only the new files containing the extra
369 extension in their filenames should be modified.
371 Here is an example of using a file extension to specify a patch:
373 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
374 [edit sys.c.prctl_fixed to include the desired changes]
375 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
377 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
378 original source code. If your Linux distribution applies patches to the Linux
379 kernel during the kernel build process, then those patches must be applied to
380 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
381 directory. B<ksplice-create> will not modify the source code in the
382 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
383 directory tree.
385 I<ORIG_CONFIG> can be used to specify the directory containing the
386 to-be-updated kernel's original F<.config> file and original F<System.map> file
387 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
388 I<KERNEL_SOURCE>B</ksplice>.
390 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
391 close to the compiler and assembler originally used to build the running kernel
392 as possible. If the current compiler and linker are too different from the
393 original compiler and linker, B<ksplice-apply> will abort when applying the
394 update.
396 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
397 containing the desired Ksplice update modules. This tarball will be created in
398 the current directory, and it can be manipulated using the other Ksplice
399 utilities, such as B<ksplice-apply>.
401 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
402 directory, it must build that kernel from scratch, which is much slower than
403 the rest of the update-creation process. B<--prebuild> can be used to perform
404 this initial kernel build without providing a source code patch.
406 In order to patch a function that has previously been patched by Ksplice, the
407 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
408 contains the source for the currently running kernel, including any patches
409 that have previously been applied by Ksplice.
411 =head1 OPTIONS
413 =over 8
415 =item B<--patch=>I<PATCH_FILE>
417 Builds a Ksplice update out of the given L<patch(1)> file I<PATCH_FILE>.
419 =item B<--diffext=>I<EXTENSION>
421 Builds a Ksplice update using the modified source files with names ending in
422 I<EXTENSION>. The patch will be determined by comparing all of the files in the
423 I<KERNEL_SOURCE> directory tree whose names end with the extra extension
424 I<EXTENSION> against the corresponding files without the extra extension.
426 =item B<--git>=I<COMMIT>
428 Builds a Ksplice update using the commit I<COMMIT> in the Git working tree
429 I<KERNEL_SOURCE>. The original state corresponding to the running kernel is
430 remembered in the Git ref B<refs/ksplice/pre>, which will be created from the
431 current B<HEAD> if it does not yet exist (and can be changed using the
432 B<--series> option). Therefore, the source code change to be applied
433 corresponds to the output of B<git diff ksplice/pre> I<COMMIT>.
435 =item B<--prebuild>
437 Compiles the original source code that will be needed to build future Ksplice
438 updates. If any Ksplice updates have previously been built in the
439 I<KERNEL_SOURCE> tree, the source files in the tree are reverted to their
440 original state.
442 =item B<--series>
444 Specifies that the current state of the I<KERNEL_SOURCE> tree should be used as
445 the original source that corresponds to the running kernel. If a Ksplice update
446 has recently been built in the I<KERNEL_SOURCE> tree, this option specifies that
447 the Ksplice update being built should be applied after the previous update in
448 series. This option can be used with B<--prebuild> to forget the previous
449 original state and perform no other action.
451 =item B<--build-modules>
453 For a patch that includes changes to kernel modules, in addition to building a
454 hot update that can be applied to the running kernel, this option will cause
455 B<ksplice-create> to generate a set of new modules based on the updated source
456 code. These modules can be used to replace the kernel modules stored on disk,
457 where they can later be loaded normally after part of the hot update has been
458 applied using L<ksplice-apply(1)> B<--partial>.
460 =item B<-v>, B<--verbose>
462 Causes B<ksplice-create> to print debugging messages about its progress. Using
463 multiple -v options increases the verbosity. The maximum is 2.
465 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
467 Specifies the number of jobs to run simultaneously while performing kernel
468 builds. B<ksplice-create> also honors the environment variable
469 CONCURRENCY_LEVEL.
471 =item B<--patch-opt=>I<OPTIONS>
473 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
474 B<-p1> is passed to B<patch>. If this option is specified, then only the
475 specified options will be passed to B<patch>. This option can be repeated in
476 order to pass multiple options to B<patch>. This option is ignored when the
477 to-be-applied source code patch is specified using B<--diffext>.
479 =item B<--id=>I<ID>
481 Specifies the unique value that will be used as the identifier of the
482 Ksplice update. This identifier will, for example, appear in the name
483 of the update tarball. By default, a random 8-character ID will be
484 generated.
486 =back
488 =head1 SEE ALSO
490 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
492 =head1 BUGS
494 Please report bugs to <PACKAGE_BUGREPORT>.
496 =head1 AUTHORS
498 Jeff Arnold, Anders Kaseorg, and Tim Abbott
500 =head1 COPYRIGHT
502 Copyright (C) 2007-2009 Ksplice, Inc.
504 This is free software and documentation. You can redistribute and/or modify it
505 under the terms of the GNU General Public License, version 2.
507 =cut