3 # Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License, version 2.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 use Cwd
'abs_path', 'getcwd';
23 use lib
'KSPLICE_DATA_DIR';
26 my ($patchfile, $diffext, $orig_config_dir, $postdir, $jobs);
27 my ($help, $wantversion, $prebuild, $skip_prebuild, $apply, $patch_opt) = (0, 0, 0, 0, 0, "-p1");
28 Getopt
::Long
::Configure
("bundling");
29 GetOptions
("help|?" => \
$help,
30 "version" => \
$wantversion,
31 "verbose|v!" => \
$verbose,
32 "patch=s" => \
$patchfile,
33 "diffext=s" => \
$diffext,
34 "prebuild" => \
$prebuild,
35 "skip-prebuild" => \
$skip_prebuild,
37 "config=s" => \
$orig_config_dir,
39 "postdir=s" => \
$postdir,
40 "patch-opt=s@" => \
$patch_opt) or pod2usage
(1);
46 pod2usage
(1) if($help || scalar(@ARGV) != 1);
47 my $actions = (defined $patchfile) + (defined $diffext) + ($prebuild);
48 pod2usage
(1) if($actions != 1);
50 my ($linuxtree) = (abs_path
($ARGV[0]));
52 my $tmpdir = init_tmpdir
();
53 runval
("cp", "--", $patchfile, "$tmpdir/patch") if(defined $patchfile);
54 $patchfile = "$tmpdir/patch";
56 $patch_opt = "-p0" if(defined $diffext);
57 $patch_opt = join(" ", @
$patch_opt) if(ref $patch_opt);
59 if(!defined $orig_config_dir) {
60 $orig_config_dir = "$linuxtree/ksplice";
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/.config") {
72 die "Failed to find .config file in ORIG_CONFIG directory";
74 if(! -e
"$orig_config_dir/System.map") {
75 die "Failed to find System.map file in ORIG_CONFIG directory";
78 $ENV{KSPLICE_CONFIG_DIR
} = $orig_config_dir;
80 if(!defined $postdir) {
81 $postdir = "$orig_config_dir/post";
83 elsif($postdir =~ $linuxtree) {
84 die "Aborting: User-specified postdir cannot be KERNEL_SOURCE or a subdirectory";
87 runval
("cp", "--", "$orig_config_dir/.config", $linuxtree);
89 my @chars = ('a'..'z', 0..9);
91 for(my $z = 0; $z < 8; $z++) {
92 $kid .= $chars[int(rand(36))];
94 my $ksplice = "ksplice-$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.pl", "system_map_lookup", "printk");
104 print "Starting kernel builds (this process might take a long time)...\n";
106 print "For output during this process, run ksplice-create with the option -v\n";
109 ###################################################################
110 # PHASE 1: Determine which object files are modified by the patch #
111 # - performs the pre and post kernel builds #
112 # - uses objdiff to identify which ELF sections have changed and #
113 # which ELF symbols are entry points to those sections #
114 ###################################################################
116 # We will refer to the object files modified by the patch as the "target object
117 # files", the ELF sections changed by the patch as the "target sections", and
118 # the entry points of those sections as the "target entry points".
120 my $origdir = getcwd
();
122 if(defined $diffext) {
123 runval
("$libexecdir/ksplice-gendiff-reversed >$patchfile . $diffext");
126 my @jlevel = (defined $ENV{CONCURRENCY_LEVEL
} ?
("-j$ENV{CONCURRENCY_LEVEL}") : ());
127 @jlevel = ("-j$jobs") if(defined $jobs);
128 my @make_ksplice = ("make", "-f", "$datadir/Makefile.ksplice", @jlevel);
131 for (split(/\0/, runstr
(qw(find -name *.KSPLICE_pre -print0)))) {
133 rename("$_.KSPLICE_pre", $_);
134 unlink("$_.KSPLICE") if(-e
"$_.KSPLICE");
139 if(!$skip_prebuild &&
140 runval_raw
(@make_ksplice, "KSPLICE_MODE=snap") != 0) {
141 die "Aborting: Prebuild failed";
143 exit(0) if($prebuild);
144 runval
("patch $patch_opt -bz .KSPLICE_pre < $patchfile");
145 if(runval_raw
(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
147 die "Aborting: Applying the patch appears to break the kernel build";
150 runval
("mkdir", "-p", "--", "$tmpdir/collect");
153 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
155 chomp(my $module = <MOD
>);
157 runval
("cp", "$module.o.KSPLICE", "$tmpdir/collect/");
158 runval
("cp", "$module.o.KSPLICE_primary", "$tmpdir/collect/");
159 runval
("cp", "$module.o.KSPLICE_helper", "$tmpdir/collect/");
160 $module =~ s/^.*\///;
161 push @modules, $module;
166 die "Aborting: No changes detected";
171 for my $module (@modules) {
172 runcd
("$tmpdir/collect");
174 ################################################################################
175 # PHASE 3: Combine the target object files and prepare for kernel module build #
176 # - links the many target object files into two "collection" object files #
177 # - saves the reloc info extracted earlier in ELF sect .ksplice.ksplice_relocs #
178 # - uses objmanip's sizelist mode to save the names and sizes of target funcs #
179 # - uses ld-script to aggregate all ELF text sections into .text #
180 # - saves the list of target entry syms in ELF sect .ksplice.ksplice_patches #
181 ################################################################################
184 runval
("cp", "-a", "--", "$datadir/kmodsrc", "kmodsrc-$module");
185 runval
("mv", "collect/$module.o.KSPLICE_primary", "kmodsrc-$module/collection.o.primary");
186 runval
("mv", "collect/$module.o.KSPLICE_helper", "kmodsrc-$module/collection.o.helper");
187 runcd
("kmodsrc-$module");
189 runval
("ld", "--script=ld-script", "-r", "-o", "collection.o.primary.postld", "collection.o.primary");
190 runval
("cp", "collection.o.primary.postld", "collection.o.primary");
191 runval
("ld", "--script=ld-script", "-r", "-o", "collection.o.helper.postld", "collection.o.helper");
192 runval
("cp", "collection.o.helper.postld", "collection.o.helper");
194 ###############################################################################
195 # PHASE 4: Build the kernel modules and create the update tarball #
196 # - builds primary and helper kernel modules #
197 # - uses objmanip's rmsyms mode to remove relocations to non-exported symbols #
198 # - creates a tarball of the primary module and the helper module #
199 ###############################################################################
201 my $kid_m = "${kid}_$module";
203 my $ksplice_m = "ksplice-$kid_m";
204 runval
("make", @jlevel, "modules", "KSPLICE_ID=$kid_m", "map_printk=$map_printk", "KERNELSRC=$linuxtree");
208 runval
("mkdir", $ksplice);
209 runval
("mv", "--", $patchfile, $ksplice);
210 for my $module (@modules) {
211 my $kid_m = "${kid}_$module";
213 my $ksplice_m = "ksplice-$kid_m";
214 runval
("mv", "--", "kmodsrc-$module/$ksplice_m.ko", "kmodsrc-$module/$ksplice_m-helper.ko", $ksplice);
216 runval
("mkdir", "$ksplice/debug");
217 runval
("mv", "collect", "$ksplice/debug");
218 for my $module (@modules) {
219 runval
("mv", "kmodsrc-$module", "$ksplice/debug");
221 runval
("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
222 runval
("cp", "--", "$ksplice.tar.gz", $origdir);
224 runval
("rm", "-rf", "--", "$tmpdir");
226 print "Ksplice update tarball written to $ksplice.tar.gz\n";
229 print "Now running ksplice-apply to apply update...\n";
230 exec("ksplice-apply", $ksplice) || die;
237 ksplice-create - Create a set of kernel modules for a rebootless kernel update
241 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
243 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
245 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
249 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
250 will apply a user-specified source code patch to the running binary kernel.
252 Before you use B<ksplice-create> on a patch, you should confirm that the
253 desired source code change does not make any semantic changes to kernel data
254 structures--that is, changes that would require existing instances of kernel
255 data structures to be transformed (e.g., a patch that adds a field to a global
256 data structure would require the existing data structures to change). If you
257 use Ksplice on a patch that changes data structure semantics, Ksplice will not
258 detect the problem and you could experience kernel problems as a result.
260 The to-be-applied source code patch can be specified by providing a L<patch(1)>
261 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
262 (B<--diffext=>I<EXTENSION>).
264 If a file extension is specified, then the desired source code patch will be
265 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
266 whose names end with the extra extension I<EXTENSION> against the corresponding
267 files without the extra extension. Only the new files containing the extra
268 extension in their filenames should be modified.
270 Here is an example of using a file extension to specify a patch:
272 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
273 [edit sys.c.prctl_fixed to include the desired changes]
274 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
276 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
277 original source code. If your Linux distribution applies patches to the Linux
278 kernel during the kernel build process, then those patches must be applied to
279 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
280 directory. B<ksplice-create> will not modify the source code in the
281 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
284 I<ORIG_CONFIG> can be used to specify the directory containing the
285 to-be-updated kernel's original F<.config> file and original F<System.map> file
286 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
287 I<KERNEL_SOURCE>B</ksplice>.
289 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
290 close to the compiler and assembler originally used to build the running kernel
291 as possible. If the current compiler and linker are too different from the
292 original compiler and linker, B<ksplice-apply> will abort when applying the
295 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
296 containing the desired Ksplice update modules. This tarball will be created in
297 the current directory, and it can be manipulated using the other Ksplice
298 utilities, such as B<ksplice-apply>.
300 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
301 directory, it must build that kernel from scratch, which is much slower than
302 the rest of the update-creation process. B<--prebuild> can be used to perform
303 this initial kernel build (and set up a tentative B<post> directory tree)
304 without providing a source code patch.
306 In order to patch a function that has previously been patched by Ksplice, the
307 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
308 contains the source for the currently running kernel, including any patches
309 that have previously been applied by Ksplice.
315 =item B<-v>, B<--verbose>
317 Prints the commands being executed, the output of the commands being executed,
318 and various other pieces of information.
320 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
322 Specifies the number of jobs to run simultaneously while performing kernel
323 builds. B<ksplice-create> also honors the environment variable
328 Immediately applies the generated update to the running kernel by invoking
331 =item B<--postdir=>I<DIRECTORY>
333 Specifies a directory that is B<dedicated to Ksplice> to be used as the Ksplice
334 I<post> directory. Defaults to I<ORIG_CONFIG>B</post>. If this directory
335 exists, the directory's contents will be removed. If it does not exist, it
338 =item B<--patch-opt=>I<OPTIONS>
340 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
341 B<-p1> is passed to B<patch>. If this option is specified, then only the
342 specified options will be passed to B<patch>. This option can be repeated in
343 order to pass multiple options to B<patch>. This option is ignored when the
344 to-be-applied source code patch is specified using B<--diffext>.
350 Please report bugs to <PACKAGE_BUGREPORT>.
354 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
358 Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>.
360 This is free software and documentation. You can redistribute and/or modify it
361 under the terms of the GNU General Public License, version 2.