Document the ksplice-create --build-modules option.
[ksplice.git] / ksplice-create.in
blob6f30eb937aeb76532fd445cb6f1735fc3facd2ff
1 #!/usr/bin/perl
3 # Copyright (C) 2007-2008 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 sub revert_orig() {
148 for(split(/\0/, runstr(qw(find -name *.KSPLICE_presrc -print0)))) {
149 my ($file) = m/^(.*)\.KSPLICE_presrc$/;
150 if ($series) {
151 unlink($_);
152 } else {
153 rename($_, $file);
156 if (defined $git_repo && git_have_ksplice_pre) {
157 if ($series) {
158 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: freeze", qw(refs/ksplice/pre HEAD refs/ksplice/pre));
159 } else {
160 $git_repo->command_noisy(qw(update-index --refresh));
161 $git_repo->command_noisy(qw(read-tree -m --trivial -u refs/ksplice/pre));
162 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: revert", qw(HEAD refs/ksplice/pre HEAD));
165 runval(@make_ksplice, @revert_flags);
167 revert_orig();
169 if (defined $git_repo && !git_have_ksplice_pre) {
170 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: snap", qw(refs/ksplice/pre HEAD), '');
173 if(!$skip_prebuild) {
174 if(-e "$orig_config_dir/.config") {
175 copy("$orig_config_dir/.config", "$linuxtree/.config");
176 utime((stat("$orig_config_dir/.config"))[8, 9],
177 "$linuxtree/.config");
179 my @snap_flags = ("KSPLICE_MODE=snap");
180 runval_raw(@make_ksplice, @snap_flags) == 0 or
181 die "Aborting: Prebuild failed";
182 sleep(1);
184 exit(0) if($prebuild);
186 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
187 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
188 $patchfile = "$tmpdir/patch";
190 if(defined $diffext) {
191 open(PATCH, '>', $patchfile) or die;
192 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
193 my ($file) = /^(.*)\Q$diffext\E/ or die;
194 print PATCH runstr("diff", "-u", "--", $file, $_);
196 close(PATCH) or die;
197 @patch_opt = ("-p0");
200 my $kmodsrc = "$tmpdir/kmodsrc";
201 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
202 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
204 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
206 if (!defined($standalone)) {
207 $standalone = (!-e "$linuxtree/.config" || runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
209 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
211 runval(@make_kmodsrc);
213 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
215 if (defined $git) {
216 $git_repo->command_noisy(qw(update-index --refresh));
217 $git_repo->command_noisy(qw(read-tree -m --trivial -u), $git_rev);
218 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: diff", "HEAD", $git_rev);
220 open(PATCH, '>', $patchfile) or die;
221 if ($git_repo->command(qw(rev-parse --verify HEAD^)) eq
222 $git_repo->command(qw(rev-parse --verify refs/ksplice/pre))) {
223 print PATCH scalar($git_repo->command(qw(log -1 HEAD --))), "\n";
225 print PATCH scalar($git_repo->command(qw(diff-tree -p refs/ksplice/pre HEAD --)));
226 close(PATCH) or die;
227 } else {
228 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_presrc");
231 my @diff_flags = ("KSPLICE_MODE=diff");
232 push @diff_flags, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
233 push @diff_flags, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
234 if(runval_raw(@make_ksplice, @diff_flags) != 0) {
235 revert_orig() if(defined($diffext));
236 die "Aborting: Applying the patch appears to break the kernel build";
239 sub copy_debug {
240 my ($file) = @_;
241 my ($dir, $base) = (dirname($file), basename($file));
242 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
243 copy($file, "$tmpdir/objects/$file");
244 my $cmdfile = "$dir/.$base.cmd";
245 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
248 mkdir("$tmpdir/objects");
249 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
250 next if (basename($_) =~ m/^(?:vmlinux|vmlinux\.o|\.tmp_vmlinux[0-9]+|\.tmp_kallsyms[0-9]+.o)\.KSPLICE_pre$/);
251 copy_debug($_);
252 copy_debug($1) if (m/^(.*)\.KSPLICE_pre(?:src)$/);
255 my @modulepaths = ();
256 my @modules = ();
257 foreach(glob("$kmodsrc/*.mod.KSPLICE")) {
258 open MOD, '<', $_;
259 chomp(my $mod = <MOD>);
260 close MOD;
261 push @modulepaths, "$mod.ko" if (basename($mod) ne "vmlinux");
262 push @modules, basename($mod);
265 if(!@modules) {
266 revert_orig() if(defined($diffext));
267 print STDERR "No changes detected.\n";
268 exit(66);
271 if ($build_modules) {
272 mkdir("$tmpdir/modules");
273 runval(@make_ksplice, "KSPLICE_MODE=modinst", "MODLIB=$tmpdir/modules", "INSTALL_MOD_STRIP=1", "modules=@modulepaths");
276 revert_orig() if(defined($diffext));
278 runval(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
279 runval(@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", "KSPLICE_MODULES=@modules");
281 chdir($tmpdir);
282 mkdir($ksplice);
283 move($patchfile, $ksplice);
284 if ($description) {
285 write_file("$ksplice/description", "$description\n");
287 write_file("$ksplice/api-version", "KSPLICE_API_VERSION\n");
288 write_file("$ksplice/timestamp", time() . "\n");
289 runval_outfile("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
290 open(CONTENTS, ">", "$ksplice/contents");
291 foreach my $mod (@modules) {
292 (my $target = $mod) =~ s/-/_/g;
293 my $mid = "${kid}_$target";
294 my $module = "ksplice-$mid";
295 rename("$tmpdir/ksplice-modules/extra/$module.ko", "$ksplice/$module.ko");
296 print CONTENTS "primary $target ksplice_$mid $module.ko\n";
297 rename("$tmpdir/ksplice-modules/extra/$module-helper.ko", "$ksplice/$module-helper.ko");
298 print CONTENTS "helper $target ksplice_$mid $module-helper.ko\n";
300 if ($standalone) {
301 rename("$tmpdir/ksplice-modules/extra/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
302 print CONTENTS "core ksplice_$kid ksplice-$kid.ko\n";
304 if ($build_modules) {
305 foreach my $mod (@modulepaths) {
306 (my $target = basename($mod)) =~ s/-/_/g;
307 print CONTENTS "target $target $mod\n";
311 mkdir("$ksplice/debug");
312 rename("objects", "$ksplice/debug/objects");
313 rename("modules", "$ksplice/modules") if ($build_modules);
314 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
316 close(CONTENTS);
317 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
318 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
319 print "Ksplice update tarball written to $ksplice.tar.gz\n";
320 exit(0);
322 =head1 NAME
324 ksplice-create - Create a set of kernel modules for a rebootless kernel update
326 =head1 SYNOPSIS
328 B<ksplice-create> [I<OPTIONS>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
330 B<ksplice-create> [I<OPTIONS>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
332 B<ksplice-create> [I<OPTIONS>] B<--git=>I<COMMIT> I<KERNEL_SOURCE>
334 B<ksplice-create> [I<OPTIONS>] B<--prebuild> I<KERNEL_SOURCE>
336 =head1 DESCRIPTION
338 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
339 will apply a user-specified source code patch to the running binary kernel.
341 Before you use B<ksplice-create> on a patch, you should confirm that the
342 desired source code change does not make any semantic changes to kernel data
343 structures--that is, changes that would require existing instances of kernel
344 data structures to be transformed (e.g., a patch that adds a field to a global
345 data structure would require the existing data structures to change). If you
346 use Ksplice on a patch that changes data structure semantics, Ksplice will not
347 detect the problem and you could experience kernel problems as a result.
349 The to-be-applied source code patch can be specified by providing a L<patch(1)>
350 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
351 (B<--diffext=>I<EXTENSION>).
353 If a file extension is specified, then the desired source code patch will be
354 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
355 whose names end with the extra extension I<EXTENSION> against the corresponding
356 files without the extra extension. Only the new files containing the extra
357 extension in their filenames should be modified.
359 Here is an example of using a file extension to specify a patch:
361 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
362 [edit sys.c.prctl_fixed to include the desired changes]
363 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
365 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
366 original source code. If your Linux distribution applies patches to the Linux
367 kernel during the kernel build process, then those patches must be applied to
368 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
369 directory. B<ksplice-create> will not modify the source code in the
370 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
371 directory tree.
373 I<ORIG_CONFIG> can be used to specify the directory containing the
374 to-be-updated kernel's original F<.config> file and original F<System.map> file
375 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
376 I<KERNEL_SOURCE>B</ksplice>.
378 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
379 close to the compiler and assembler originally used to build the running kernel
380 as possible. If the current compiler and linker are too different from the
381 original compiler and linker, B<ksplice-apply> will abort when applying the
382 update.
384 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
385 containing the desired Ksplice update modules. This tarball will be created in
386 the current directory, and it can be manipulated using the other Ksplice
387 utilities, such as B<ksplice-apply>.
389 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
390 directory, it must build that kernel from scratch, which is much slower than
391 the rest of the update-creation process. B<--prebuild> can be used to perform
392 this initial kernel build without providing a source code patch.
394 In order to patch a function that has previously been patched by Ksplice, the
395 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
396 contains the source for the currently running kernel, including any patches
397 that have previously been applied by Ksplice.
399 =head1 OPTIONS
401 =over 8
403 =item B<--patch=>I<PATCH_FILE>
405 Builds a Ksplice update out of the given L<patch(1)> file I<PATCH_FILE>.
407 =item B<--diffext=>I<EXTENSION>
409 Builds a Ksplice update using the modified source files with names ending in
410 I<EXTENSION>. The patch will be determined by comparing all of the files in the
411 I<KERNEL_SOURCE> directory tree whose names end with the extra extension
412 I<EXTENSION> against the corresponding files without the extra extension.
414 =item B<--git>=I<COMMIT>
416 Builds a Ksplice update using the commit I<COMMIT> in the Git working tree
417 I<KERNEL_SOURCE>. The original state corresponding to the running kernel is
418 remembered in the Git ref B<refs/ksplice/pre>, which will be created from the
419 current B<HEAD> if it does not yet exist (and can be changed using the
420 B<--series> option). Therefore, the source code change to be applied
421 corresponds to the output of B<git diff ksplice/pre> I<COMMIT>.
423 =item B<--prebuild>
425 Compiles the original source code that will be needed to build future Ksplice
426 updates. If any Ksplice updates have previously been built in the
427 I<KERNEL_SOURCE> tree, the source files in the tree are reverted to their
428 original state.
430 =item B<--series>
432 Specifies that the current state of the I<KERNEL_SOURCE> tree should be used as
433 the original source that corresponds to the running kernel. If a Ksplice update
434 has recently been built in the I<KERNEL_SOURCE> tree, this option specifies that
435 the Ksplice update being built should be applied after the previous update in
436 series. This option can be used with B<--prebuild> to forget the previous
437 original state and perform no other action.
439 =item B<--build-modules>
441 For a patch that includes changes to kernel modules, in addition to building a
442 hot update that can be applied to the running kernel, this option will cause
443 B<ksplice-create> to generate a set of new modules based on the updated source
444 code. These modules can be used to replace the kernel modules stored on disk,
445 where they can later be loaded normally after part of the hot update has been
446 applied using L<ksplice-apply(1)> B<--partial>.
448 =item B<-v>, B<--verbose>
450 Causes B<ksplice-create> to print debugging messages about its progress. Using
451 multiple -v options increases the verbosity. The maximum is 2.
453 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
455 Specifies the number of jobs to run simultaneously while performing kernel
456 builds. B<ksplice-create> also honors the environment variable
457 CONCURRENCY_LEVEL.
459 =item B<--patch-opt=>I<OPTIONS>
461 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
462 B<-p1> is passed to B<patch>. If this option is specified, then only the
463 specified options will be passed to B<patch>. This option can be repeated in
464 order to pass multiple options to B<patch>. This option is ignored when the
465 to-be-applied source code patch is specified using B<--diffext>.
467 =item B<--id=>I<ID>
469 Specifies the unique value that will be used as the identifier of the
470 Ksplice update. This identifier will, for example, appear in the name
471 of the update tarball. By default, a random 8-character ID will be
472 generated.
474 =back
476 =head1 SEE ALSO
478 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
480 =head1 BUGS
482 Please report bugs to <PACKAGE_BUGREPORT>.
484 =head1 AUTHORS
486 Jeff Arnold, Anders Kaseorg, and Tim Abbott
488 =head1 COPYRIGHT
490 Copyright (C) 2007-2008 Ksplice, Inc.
492 This is free software and documentation. You can redistribute and/or modify it
493 under the terms of the GNU General Public License, version 2.
495 =cut