Only use COW hooks in diff mode.
[ksplice.git] / ksplice-create.in
blob367f48bcacb028ede1c9f9284ad6c13b6a4f880a
1 #!/usr/bin/perl
3 # Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
4 # Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
5 # Tim Abbott <tabbott@mit.edu>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License, version 2.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
18 # 02110-1301, USA.
20 use strict;
21 use warnings;
22 use lib 'KSPLICE_DATA_DIR';
23 use Ksplice;
25 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
26 my $description;
27 my $series = 0;
28 my $build_modules = 0;
29 my @only_targets;
30 my @extra_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 "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) + ($prebuild);
52 pod2usage(1) if($actions != 1);
54 my ($linuxtree) = (abs_path($ARGV[0]));
56 if(!defined $orig_config_dir) {
57 $orig_config_dir = "$linuxtree/ksplice";
59 else {
60 $orig_config_dir = abs_path($orig_config_dir);
61 if($orig_config_dir =~ $linuxtree) {
62 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
65 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
66 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
68 if(! -e "$orig_config_dir/.config") {
69 die "Failed to find .config file in ORIG_CONFIG directory";
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 @make = ("make", "-rR");
111 if(defined $jobs) {
112 push @make, "-j$jobs";
113 } elsif(defined $ENV{CONCURRENCY_LEVEL}) {
114 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
117 if($Verbose::level >= 2) {
118 push @make, "V=1";
119 } elsif($Verbose::level < 0) {
120 push @make, "-s";
123 $ENV{PATH} = "$datadir:$ENV{PATH}";
124 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
126 push(@make_ksplice, "KSPLICE_BUILD_MODULES=1") if ($build_modules);
128 sub revert_orig() {
129 for(split(/\0/, runstr(qw(find -name *.KSPLICE_* -print0)))) {
130 if(my ($file) = m/^(.*)\.KSPLICE_pre$/) {
131 if ($series) {
132 unlink($_);
133 } else {
134 rename($_, $file);
136 runval("$datadir/ksplice-obj.pl", "snap", "$file.KSPLICE") if(-e "$file.KSPLICE");
137 } elsif(m/\.KSPLICE_(?:primary|helper)$/) {
138 unlink($_) if(-e $_);
142 revert_orig();
144 if(!$skip_prebuild) {
145 copy("$orig_config_dir/.config", "$linuxtree/.config");
146 utime((stat("$orig_config_dir/.config"))[8, 9], "$linuxtree/.config");
147 my @snap_flags = ("KSPLICE_MODE=snap");
148 if(-e "include/config/kernel.release") {
149 push(@snap_flags, "-o", "include/config/kernel.release");
151 runval_raw(@make_ksplice, @snap_flags) == 0 or
152 die "Aborting: Prebuild failed";
153 sleep(1);
155 exit(0) if($prebuild);
157 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
158 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
159 $patchfile = "$tmpdir/patch";
161 if(defined $diffext) {
162 open(PATCH, '>', $patchfile) or die;
163 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
164 my ($file) = /^(.*)\Q$diffext\E/ or die;
165 print PATCH runstr("diff", "-u", "--", $file, $_);
167 close(PATCH) or die;
168 @patch_opt = ("-p0");
171 my $kmodsrc = "$tmpdir/kmodsrc";
172 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
173 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
175 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
177 if (!defined($standalone)) {
178 $standalone = (runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
180 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
182 runval(@make_kmodsrc);
184 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
186 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_pre");
187 push @make_ksplice, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
188 push @make_ksplice, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
189 if(runval_raw(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
190 revert_orig() if(defined($diffext));
191 die "Aborting: Applying the patch appears to break the kernel build";
194 sub copy_debug {
195 my ($file) = @_;
196 my ($dir, $base) = (dirname($file), basename($file));
197 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
198 copy($file, "$tmpdir/objects/$file");
199 my $cmdfile = "$dir/.$base.cmd";
200 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
203 mkdir("$tmpdir/objects");
204 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
205 copy_debug($_);
206 copy_debug($1) if (m/^(.*)\.KSPLICE_pre$/);
209 my @modulepaths = ();
210 my @modules = ();
211 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
212 open MOD, '<', $_;
213 chomp(my $mod = <MOD>);
214 close MOD;
215 foreach my $collect ("$mod.o.KSPLICE", "$mod.o.KSPLICE_primary",
216 "$mod.o.KSPLICE_helper") {
217 copy($collect, "$kmodsrc/" . basename($collect));
219 push @modulepaths, "$mod.ko" if ($mod ne "vmlinux");
220 push @modules, basename($mod);
223 if(!@modules) {
224 revert_orig() if(defined($diffext));
225 die "Aborting: No changes detected";
228 if ($build_modules) {
229 mkdir("$tmpdir/modules");
230 runval(@make_ksplice, "KSPLICE_MODE=diff", "ksplice_modinst", "MODLIB=$tmpdir/modules", "modules=@modulepaths");
233 revert_orig() if(defined($diffext));
235 runval(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
237 chdir($tmpdir);
238 mkdir($ksplice);
239 move($patchfile, $ksplice);
240 if ($description) {
241 write_file("$ksplice/description", "$description\n");
243 write_file("$ksplice/api-version", "KSPLICE_API_VERSION\n");
244 write_file("$ksplice/timestamp", time() . "\n");
245 runval_outfile("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
246 open(CONTENTS, ">", "$ksplice/contents");
247 foreach my $mod (@modules) {
248 (my $target = $mod) =~ s/-/_/g;
249 my $mid = "${kid}_$target";
250 my $module = "ksplice-$mid";
251 rename("$kmodsrc/$module.ko", "$ksplice/$module.ko");
252 print CONTENTS "primary $target ksplice_$mid $module.ko\n";
253 rename("$kmodsrc/$module-helper.ko", "$ksplice/$module-helper.ko");
254 print CONTENTS "helper $target ksplice_$mid $module-helper.ko\n";
256 if ($standalone) {
257 rename("$kmodsrc/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
258 print CONTENTS "core ksplice_$kid ksplice-$kid.ko\n";
260 if ($build_modules) {
261 foreach my $mod (@modulepaths) {
262 (my $target = basename($mod)) =~ s/-/_/g;
263 print CONTENTS "target $target $mod\n";
267 mkdir("$ksplice/debug");
268 rename("objects", "$ksplice/debug/objects");
269 rename("modules", "$ksplice/modules") if ($build_modules);
270 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
272 close(CONTENTS);
273 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
274 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
275 print "Ksplice update tarball written to $ksplice.tar.gz\n";
276 exit(0);
278 =head1 NAME
280 ksplice-create - Create a set of kernel modules for a rebootless kernel update
282 =head1 SYNOPSIS
284 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
286 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
288 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
290 =head1 DESCRIPTION
292 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
293 will apply a user-specified source code patch to the running binary kernel.
295 Before you use B<ksplice-create> on a patch, you should confirm that the
296 desired source code change does not make any semantic changes to kernel data
297 structures--that is, changes that would require existing instances of kernel
298 data structures to be transformed (e.g., a patch that adds a field to a global
299 data structure would require the existing data structures to change). If you
300 use Ksplice on a patch that changes data structure semantics, Ksplice will not
301 detect the problem and you could experience kernel problems as a result.
303 The to-be-applied source code patch can be specified by providing a L<patch(1)>
304 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
305 (B<--diffext=>I<EXTENSION>).
307 If a file extension is specified, then the desired source code patch will be
308 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
309 whose names end with the extra extension I<EXTENSION> against the corresponding
310 files without the extra extension. Only the new files containing the extra
311 extension in their filenames should be modified.
313 Here is an example of using a file extension to specify a patch:
315 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
316 [edit sys.c.prctl_fixed to include the desired changes]
317 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
319 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
320 original source code. If your Linux distribution applies patches to the Linux
321 kernel during the kernel build process, then those patches must be applied to
322 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
323 directory. B<ksplice-create> will not modify the source code in the
324 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
325 directory tree.
327 I<ORIG_CONFIG> can be used to specify the directory containing the
328 to-be-updated kernel's original F<.config> file and original F<System.map> file
329 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
330 I<KERNEL_SOURCE>B</ksplice>.
332 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
333 close to the compiler and assembler originally used to build the running kernel
334 as possible. If the current compiler and linker are too different from the
335 original compiler and linker, B<ksplice-apply> will abort when applying the
336 update.
338 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
339 containing the desired Ksplice update modules. This tarball will be created in
340 the current directory, and it can be manipulated using the other Ksplice
341 utilities, such as B<ksplice-apply>.
343 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
344 directory, it must build that kernel from scratch, which is much slower than
345 the rest of the update-creation process. B<--prebuild> can be used to perform
346 this initial kernel build without providing a source code patch.
348 In order to patch a function that has previously been patched by Ksplice, the
349 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
350 contains the source for the currently running kernel, including any patches
351 that have previously been applied by Ksplice.
353 =head1 OPTIONS
355 =over 8
357 =item B<-v>, B<--verbose>
359 Causes B<ksplice-create> to print debugging messages about its progress. Using
360 multiple -v options increases the verbosity. The maximum is 2.
362 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
364 Specifies the number of jobs to run simultaneously while performing kernel
365 builds. B<ksplice-create> also honors the environment variable
366 CONCURRENCY_LEVEL.
368 =item B<--patch-opt=>I<OPTIONS>
370 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
371 B<-p1> is passed to B<patch>. If this option is specified, then only the
372 specified options will be passed to B<patch>. This option can be repeated in
373 order to pass multiple options to B<patch>. This option is ignored when the
374 to-be-applied source code patch is specified using B<--diffext>.
376 =item B<--id=>I<ID>
378 Specifies the unique value that will be used as the identifier of the
379 Ksplice update. This identifier will, for example, appear in the name
380 of the update tarball. By default, a random 8-character ID will be
381 generated.
383 =back
385 =head1 SEE ALSO
387 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
389 =head1 BUGS
391 Please report bugs to <PACKAGE_BUGREPORT>.
393 =head1 COPYRIGHT
395 Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
397 Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
398 Tim Abbott <tabbott@mit.edu>
400 This is free software and documentation. You can redistribute and/or modify it
401 under the terms of the GNU General Public License, version 2.
403 =cut