Some linux distribution simply put the kernel image at /boot/vmlinuz and maybe a backup version as /boot/vmlinuz.old. Same goes for a System.map file.
I prefer to store multiple kernel versions in a hierarchical structure with symlink pointing to the current kernel (which are in turn referenced by grub's menu).
For example, my current kernel is minigen32 (mini since it's my mac mini kernel, gen for gentoo and 32... you can guess :) ).
Under /boot/kernels I have a subdirectory for minigen32 and under that a subdir for each kernel version. I also put another subdir level for local build number, since I might have several builds of the same kernel version.
So I have:
/boot/kernels/minigen32/2.6.32-gentoo-r7/p0
/boot/kernels/minigen32/2.6.32-gentoo-r7/p1
etc., etc.
Each such directory contains the same files. The good 'ol bzImage, System.map and .config.
Then I have symlinks for stable, testing, current, previous etc. pointing to these subdirs, and a simple grub file can be written (kernel /testing/bzImage). When I want to switch kernels I just need to update the symlinks. No need to touch the grub configuration (unless of course I need to change the kernel command line).
Using gentoo's handy eselect utility i've built a module to handle this scheme for me.
$ eselect mykernel list
Available kernel symlink targets:
[1] /boot/kernels/minigen32/2.6.32-gentoo-r7/p0 stable
[2] /boot/kernels/minigen32/2.6.32-gentoo-r7/p1 testing
[3] /boot/kernels/minigen32/2.6.32-gentoo-r7/p2
$ eselect mykernel set testing 3
$ eselect mykernel set testing 2
$ eselect mykernel list
Available kernel symlink targets:
[1] /boot/kernels/minigen32/2.6.32-gentoo-r7/p0
[2] /boot/kernels/minigen32/2.6.32-gentoo-r7/p1 stable
[3] /boot/kernels/minigen32/2.6.32-gentoo-r7/p2 testing
Code for the module (just drop it in ~/.eselect/modules/mykernel.eselect):
DESCRIPTION="Manage the /boot kernel symlinks"
VERSION="0.3"
local BASE_DIR="/boot"
local KERNELS_BASE="$BASE_DIR/kernels"
local TAGS=( stable testing )
# find a list of kernel symlink targets
find_targets() {
local f
for f in $KERNELS_BASE/*/*/p* ; do
#[[ -d ${f} ]] && basename "${f}"
#[[ -d ${f} ]] && echo "${f#${BASE_DIR}/}"
[[ -d ${f} ]] && echo "${f}"
done
}
### show action ###
describe_show() {
echo "Show the current tagged kernels"
}
do_show() {
local TAGS_TO_SHOW=( "${TAGS[@]}" )
has $1 ${TAGS[@]} && TAGS_TO_SHOW=( $1 )
for TAG in ${TAGS_TO_SHOW[@]}
do
my_show $TAG
done
}
my_show() {
local TAG=$1
write_list_start "Current ${TAG} kernel"
if [[ -L $BASE_DIR/${TAG} ]]
then
write_kv_list_entry $BASE_DIR/$(readlink "${BASE_DIR}/${TAG}") ""
else
write_kv_list_entry "(unset)" ""
fi
}
### list action ###
describe_list() {
echo "List Available Kernels in $BASE_DIR"
}
do_list() {
local i j SYMLINKS TAG targets=( $(find_targets) )
write_list_start "Available kernel symlink targets:"
for (( j = 0; j < ${#TAGS[@]}; j++ ))
do
[[ -L $BASE_DIR/${TAGS[$j]} ]] && SYMLINKS[$j]=$BASE_DIR/$(readlink "${BASE_DIR}/${TAGS[$j]}")
done
for (( i = 0; i < ${#targets[@]}; i++ ))
do
local mark=""
for (( j = 0; j < ${#TAGS[@]}; j++ ))
do
if [[ ${targets[${i}]} == ${SYMLINKS[$j]} ]]
then
mark="${mark} $(highlight ${TAGS[$j]})"
fi
done
targets[${i}]="${targets[${i}]} ${mark}"
done
write_numbered_list -m "(none found)" "${targets[@]}"
}
### set action ###
describe_set() {
echo "Tag a kernel"
}
do_set() {
local usage="Usage [${TAGS[@]}] [kernel]" tag=$1 target=$2 symlink
[[ ${#} != 2 ]] && die -q ${usage}
has $tag ${TAGS[@]} || die -q ${usage}
symlink=$BASE_DIR/$tag
if [[ -L "${symlink}" ]] ; then
set_symlink "${target}" "${symlink}" || die -q "Couldn't set a new symlink"
elif [[ -e "${symlink}" ]] ; then
die -q "Target file already exists and is not a symlink: ${symlink}"
else
set_symlink "${target}" "${symlink}" || die -q "Couldn't set a new symlink"
fi
}
set_symlink() {
local target=${1} symlink=${2}
if is_number "${target}" ; then
targets=( $(find_targets) )
target=${targets[$(( ${target} - 1 ))]}
fi
if [[ -z ${target} ]] ; then
die -q "Target \"${1}\" doesn't appear to be valid!"
elif [[ -d "${target}" ]] ; then
local sym_dir=$(dirname ${symlink})
if [[ ! -d ${sym_dir} ]]; then
mkdir -p ${sym_dir} || die -q "Could not create ${my_dir}"
fi
ln -snf "${target#${BASE_DIR}/}" "${symlink}"
else
die -q "Target \"${1}\" doesn't appear to be valid!"
fi
}
Update 3-Jun-2010: Updated eselect module to version 0.3