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
22 use lib
'KSPLICE_DATA_DIR';
25 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
28 my $build_modules = 0;
32 my ($prebuild, $skip_prebuild) = (0, 0);
33 my @patch_opt = "-p1";
34 GetOptions
(@common_options,
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,
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";
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/System.map") {
69 die "Failed to find System.map file in ORIG_CONFIG directory";
72 my $kernel_headers_dir = "$orig_config_dir/build";
73 $kernel_headers_dir = $linuxtree unless(-d
$kernel_headers_dir);
75 my @kbuild_flags = ();
76 if(-e
"$orig_config_dir/flags") {
77 open(FLAGS
, '<', "$orig_config_dir/flags") or die;
79 @kbuild_flags = shellwords
(scalar <FLAGS
>);
83 $ENV{KSPLICE_VERBOSE
} = $Verbose::level
;
84 $ENV{KSPLICE_CONFIG_DIR
} = $orig_config_dir;
86 my @chars = ('a'..'z', 0..9);
87 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
88 my $ksplice = "ksplice-$kid";
89 $ENV{KSPLICE_KID
} = $kid;
91 # Some versions of Fedora have System.map files whose symbol addresses disagree
92 # with the running kernel by a constant address offset. Here, Ksplice notes the
93 # System.map address for printk so that it can later compare this address against
94 # the kernel's address for printk. This comparison helps Ksplice work around
95 # this Fedora problem, and this comparison also helps Ksplice detect whether
96 # the user has provided an incorrect System.map file.
97 my $map_printk = runstr
("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
99 print "Starting kernel builds (this process might take a long time)...\n"
100 if($Verbose::level
>= 0);
102 $patchfile = abs_path
($patchfile) if(defined $patchfile);
104 my $origdir = getcwd
();
107 my @make = ("make", "-rR");
109 push @make, "-j$jobs";
110 } elsif(defined $ENV{CONCURRENCY_LEVEL
}) {
111 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
114 if($Verbose::level
>= 2) {
116 } elsif($Verbose::level
< 0) {
120 $ENV{PATH
} = "$datadir:$ENV{PATH}";
121 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
123 push(@make_ksplice, "KSPLICE_BUILD_MODULES=1") if ($build_modules);
124 if(-e
"include/config/kernel.release") {
125 push(@make_ksplice, "-o", "include/config/kernel.release");
128 my @revert_flags = ("KSPLICE_MODE=revert");
129 push(@revert_flags, "KSPLICE_SERIES=y") if ($series);
132 for(split(/\0/, runstr
(qw(find -name *.KSPLICE_presrc -print0)))) {
133 my ($file) = m/^(.*)\.KSPLICE_presrc$/;
140 runval
(@make_ksplice, @revert_flags);
144 if(!$skip_prebuild) {
145 if(-e
"$orig_config_dir/.config") {
146 copy
("$orig_config_dir/.config", "$linuxtree/.config");
147 utime((stat("$orig_config_dir/.config"))[8, 9],
148 "$linuxtree/.config");
150 my @snap_flags = ("KSPLICE_MODE=snap");
151 runval_raw
(@make_ksplice, @snap_flags) == 0 or
152 die "Aborting: Prebuild failed";
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, $_);
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_presrc");
187 my @diff_flags = ("KSPLICE_MODE=diff");
188 push @diff_flags, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
189 push @diff_flags, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
190 if(runval_raw
(@make_ksplice, @diff_flags) != 0) {
191 revert_orig
() if(defined($diffext));
192 die "Aborting: Applying the patch appears to break the kernel build";
197 my ($dir, $base) = (dirname
($file), basename
($file));
198 -d
"$tmpdir/objects/$dir" or mkpath
("$tmpdir/objects/$dir");
199 copy
($file, "$tmpdir/objects/$file");
200 my $cmdfile = "$dir/.$base.cmd";
201 copy
($cmdfile, "$tmpdir/objects/$cmdfile") if(-e
$cmdfile);
204 mkdir("$tmpdir/objects");
205 for (split(/\0/, runstr
(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name
.*.KSPLICE
.cmd
-print0
)))) {
207 copy_debug
($1) if (m/^(.*)\.KSPLICE_pre(?:src)$/);
210 my @modulepaths = ();
212 foreach(glob("$kmodsrc/*.mod.KSPLICE")) {
214 chomp(my $mod = <MOD
>);
216 push @modulepaths, "$mod.ko" if ($mod ne "vmlinux");
217 push @modules, basename
($mod);
221 revert_orig
() if(defined($diffext));
222 die "Aborting: No changes detected";
225 if ($build_modules) {
226 mkdir("$tmpdir/modules");
227 runval
(@make_ksplice, "KSPLICE_MODE=diff", "ksplice_modinst", "MODLIB=$tmpdir/modules", "modules=@modulepaths");
230 revert_orig
() if(defined($diffext));
232 runval
(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
236 move
($patchfile, $ksplice);
238 write_file
("$ksplice/description", "$description\n");
240 write_file
("$ksplice/api-version", "KSPLICE_API_VERSION\n");
241 write_file
("$ksplice/timestamp", time() . "\n");
242 runval_outfile
("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
243 open(CONTENTS
, ">", "$ksplice/contents");
244 foreach my $mod (@modules) {
245 (my $target = $mod) =~ s/-/_/g;
246 my $mid = "${kid}_$target";
247 my $module = "ksplice-$mid";
248 rename("$kmodsrc/$module.ko", "$ksplice/$module.ko");
249 print CONTENTS
"primary $target ksplice_$mid $module.ko\n";
250 rename("$kmodsrc/$module-helper.ko", "$ksplice/$module-helper.ko");
251 print CONTENTS
"helper $target ksplice_$mid $module-helper.ko\n";
254 rename("$kmodsrc/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
255 print CONTENTS
"core ksplice_$kid ksplice-$kid.ko\n";
257 if ($build_modules) {
258 foreach my $mod (@modulepaths) {
259 (my $target = basename
($mod)) =~ s/-/_/g;
260 print CONTENTS
"target $target $mod\n";
264 mkdir("$ksplice/debug");
265 rename("objects", "$ksplice/debug/objects");
266 rename("modules", "$ksplice/modules") if ($build_modules);
267 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
270 runval
("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
271 copy
("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
272 print "Ksplice update tarball written to $ksplice.tar.gz\n";
277 ksplice-create - Create a set of kernel modules for a rebootless kernel update
281 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
283 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
285 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
289 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
290 will apply a user-specified source code patch to the running binary kernel.
292 Before you use B<ksplice-create> on a patch, you should confirm that the
293 desired source code change does not make any semantic changes to kernel data
294 structures--that is, changes that would require existing instances of kernel
295 data structures to be transformed (e.g., a patch that adds a field to a global
296 data structure would require the existing data structures to change). If you
297 use Ksplice on a patch that changes data structure semantics, Ksplice will not
298 detect the problem and you could experience kernel problems as a result.
300 The to-be-applied source code patch can be specified by providing a L<patch(1)>
301 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
302 (B<--diffext=>I<EXTENSION>).
304 If a file extension is specified, then the desired source code patch will be
305 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
306 whose names end with the extra extension I<EXTENSION> against the corresponding
307 files without the extra extension. Only the new files containing the extra
308 extension in their filenames should be modified.
310 Here is an example of using a file extension to specify a patch:
312 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
313 [edit sys.c.prctl_fixed to include the desired changes]
314 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
316 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
317 original source code. If your Linux distribution applies patches to the Linux
318 kernel during the kernel build process, then those patches must be applied to
319 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
320 directory. B<ksplice-create> will not modify the source code in the
321 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
324 I<ORIG_CONFIG> can be used to specify the directory containing the
325 to-be-updated kernel's original F<.config> file and original F<System.map> file
326 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
327 I<KERNEL_SOURCE>B</ksplice>.
329 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
330 close to the compiler and assembler originally used to build the running kernel
331 as possible. If the current compiler and linker are too different from the
332 original compiler and linker, B<ksplice-apply> will abort when applying the
335 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
336 containing the desired Ksplice update modules. This tarball will be created in
337 the current directory, and it can be manipulated using the other Ksplice
338 utilities, such as B<ksplice-apply>.
340 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
341 directory, it must build that kernel from scratch, which is much slower than
342 the rest of the update-creation process. B<--prebuild> can be used to perform
343 this initial kernel build without providing a source code patch.
345 In order to patch a function that has previously been patched by Ksplice, the
346 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
347 contains the source for the currently running kernel, including any patches
348 that have previously been applied by Ksplice.
354 =item B<-v>, B<--verbose>
356 Causes B<ksplice-create> to print debugging messages about its progress. Using
357 multiple -v options increases the verbosity. The maximum is 2.
359 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
361 Specifies the number of jobs to run simultaneously while performing kernel
362 builds. B<ksplice-create> also honors the environment variable
365 =item B<--patch-opt=>I<OPTIONS>
367 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
368 B<-p1> is passed to B<patch>. If this option is specified, then only the
369 specified options will be passed to B<patch>. This option can be repeated in
370 order to pass multiple options to B<patch>. This option is ignored when the
371 to-be-applied source code patch is specified using B<--diffext>.
375 Specifies the unique value that will be used as the identifier of the
376 Ksplice update. This identifier will, for example, appear in the name
377 of the update tarball. By default, a random 8-character ID will be
384 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
388 Please report bugs to <PACKAGE_BUGREPORT>.
392 Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
394 Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
395 Tim Abbott <tabbott@mit.edu>
397 This is free software and documentation. You can redistribute and/or modify it
398 under the terms of the GNU General Public License, version 2.