This was found on Fedora 18.
Both os-prober and linux-boot-prober do not support root, boot, or
root+boot on a btrfs subvolume.
The attached patch corrects that. It supplies information such that
grub2, with an additional small patch, will not handle btrfs in
30_os-prober.
I have attached two additional small patches for os-prober which
suppresses debug messages until needed and to fix os-prober to handle
/boot on a separate logical volume.
Gene
diff -uNr os-prober-1.56-orig-1/common.sh os-prober-1.56/common.sh
--- os-prober-1.56-orig-1/common.sh 2013-01-10 08:33:45.200766262 -0500
+++ os-prober-1.56/common.sh 2013-01-10 08:34:43.644058934 -0500
@@ -127,6 +127,7 @@
done
}
+# add forth parameter to pickup btrfs subvol info
parsefstab () {
while read -r line; do
case "$line" in
@@ -137,12 +138,22 @@
set -f
set -- $line
set +f
- printf '%s %s %s\n' "$1" "$2" "$3"
+ printf '%s %s %s %s\n' "$1" "$2" "$3" "$4"
;;
esac
done
}
+#check_btrfs_mounted $bootsv $bootuuid)
+check_btrfs_mounted () {
+ bootsv="$1"
+ bootuuid="$2"
+ bootdev=$(blkid | grep "$bootuuid" | cut -d ':' -f 1)
+ bindfrom=$(grep " btrfs " /proc/self/mountinfo |
+ grep " $bootdev " | grep " /$bootsv " | cut -d ' ' -f 5)
+ printf "%s" "$bindfrom"
+}
+
unescape_mount () {
printf %s "$1" | \
sed 's/\\011/ /g; s/\\012/\n/g; s/\\040/ /g; s/\\134/\\/g'
diff -uNr os-prober-1.56-orig-1/common.sh.orig os-prober-1.56/common.sh.orig
--- os-prober-1.56-orig-1/common.sh.orig 1969-12-31 19:00:00.000000000 -0500
+++ os-prober-1.56/common.sh.orig 2013-01-10 08:34:43.642058924 -0500
@@ -0,0 +1,293 @@
+newns () {
+ [ "$OS_PROBER_NEWNS" ] || exec /usr/lib/newns "$0" "$@"
+}
+
+cleanup_tmpdir=false
+cleanup_ro_partitions=
+cleanup () {
+ local partition
+ for partition in $cleanup_ro_partitions; do
+ blockdev --setrw "$partition"
+ done
+ if $cleanup_tmpdir; then
+ rm -rf "$OS_PROBER_TMP"
+ fi
+}
+
+require_tmpdir() {
+ if [ -z "$OS_PROBER_TMP" ]; then
+ if type mktemp >/dev/null 2>&1; then
+ export OS_PROBER_TMP="$(mktemp -d /tmp/os-prober.XXXXXX)"
+ cleanup_tmpdir=:
+ trap cleanup EXIT HUP INT QUIT TERM
+ else
+ export OS_PROBER_TMP=/tmp
+ fi
+ fi
+}
+
+count_for() {
+ _labelprefix="$1"
+ _result=$(grep "^${_labelprefix} " /var/lib/os-prober/labels 2>/dev/null || true)
+
+ if [ -z "$_result" ]; then
+ return
+ else
+ echo "$_result" | cut -d' ' -f2
+ fi
+}
+
+count_next_label() {
+ require_tmpdir
+
+ _labelprefix="$1"
+ _cfor="$(count_for "${_labelprefix}")"
+
+ if [ -z "$_cfor" ]; then
+ echo "${_labelprefix} 1" >> /var/lib/os-prober/labels
+ else
+ sed "s/^${_labelprefix} ${_cfor}/${_labelprefix} $(($_cfor + 1))/" /var/lib/os-prober/labels > "$OS_PROBER_TMP/os-prober.tmp"
+ mv "$OS_PROBER_TMP/os-prober.tmp" /var/lib/os-prober/labels
+ fi
+
+ echo "${_labelprefix}${_cfor}"
+}
+
+progname=
+cache_progname() {
+ case $progname in
+ '')
+ progname="$(basename "$0")"
+ ;;
+ esac
+}
+
+log() {
+ cache_progname
+ logger -t "$progname" "$@"
+}
+
+error() {
+ log "error: $@"
+}
+
+warn() {
+ log "warning: $@"
+}
+
+debug() {
+ if [ -n "$OS_PROBER_ENABLE_DEBUG" ]; then
+ log "debug: $@"
+ fi
+}
+
+result () {
+ log "result:" "$@"
+ echo "$@"
+}
+
+# shim to make it easier to use os-prober outside d-i
+if ! type mapdevfs >/dev/null 2>&1; then
+ mapdevfs () {
+ readlink -f "$1"
+ }
+fi
+
+item_in_dir () {
+ if [ "$1" = "-q" ]; then
+ q="-q"
+ shift 1
+ else
+ q=""
+ fi
+ [ -d "$2" ] || return 1
+ # find files with any case
+ ls -1 "$2" | grep $q -i "^$1$"
+}
+
+# We can't always tell the filesystem type up front, but if we have the
+# information then we should use it. Note that we can't use block-attr here
+# as it's only available in udebs.
+fs_type () {
+ if (export PATH="/lib/udev:$PATH"; type vol_id) >/dev/null 2>&1; then
+ PATH="/lib/udev:$PATH" vol_id --type "$1" 2>/dev/null
+ elif type blkid >/dev/null 2>&1; then
+ blkid -o value -s TYPE "$1" 2>/dev/null
+ else
+ return 0
+ fi
+}
+
+parse_proc_mounts () {
+ while read -r line; do
+ set -f
+ set -- $line
+ set +f
+ printf '%s %s %s\n' "$(mapdevfs "$1")" "$2" "$3"
+ done
+}
+
+parsefstab () {
+ while read -r line; do
+ case "$line" in
+ "#"*)
+ :
+ ;;
+ *)
+ set -f
+ set -- $line
+ set +f
+ printf '%s %s %s\n' "$1" "$2" "$3"
+ ;;
+ esac
+ done
+}
+
+unescape_mount () {
+ printf %s "$1" | \
+ sed 's/\\011/ /g; s/\\012/\n/g; s/\\040/ /g; s/\\134/\\/g'
+}
+
+ro_partition () {
+ if type blockdev >/dev/null 2>&1 && \
+ [ "$(blockdev --getro "$1")" = 0 ] && \
+ blockdev --setro "$1"; then
+ cleanup_ro_partitions="${cleanup_ro_partitions:+$cleanup_ro_partitions }$1"
+ trap cleanup EXIT HUP INT QUIT TERM
+ fi
+}
+
+find_label () {
+ local output
+ if type blkid >/dev/null 2>&1; then
+ # Hopefully everyone has blkid by now
+ output="$(blkid -o device -t LABEL="$1")" || return 1
+ echo "$output" | head -n1
+ elif [ -h "/dev/disk/by-label/$1" ]; then
+ # Last-ditch fallback
+ readlink -f "/dev/disk/by-label/$1"
+ else
+ return 1
+ fi
+}
+
+find_uuid () {
+ local output
+ if type blkid >/dev/null 2>&1; then
+ # Hopefully everyone has blkid by now
+ output="$(blkid -o device -t UUID="$1")" || return 1
+ echo "$output" | head -n1
+ elif [ -h "/dev/disk/by-uuid/$1" ]; then
+ # Last-ditch fallback
+ readlink -f "/dev/disk/by-uuid/$1"
+ else
+ return 1
+ fi
+}
+
+# Sets $mountboot as output variable. (We do this rather than requiring a
+# subshell so that we can run ro_partition without the cleanup trap firing
+# when the subshell exits.)
+linux_mount_boot () {
+ partition="$1"
+ tmpmnt="$2"
+
+ bootpart=""
+ mounted=""
+ lvboot=""
+ if [ -e "$tmpmnt/etc/fstab" ]; then
+ # Try to mount any /boot partition.
+ bootmnt=$(parsefstab < "$tmpmnt/etc/fstab" | grep " /boot ") || true
+ if [ -n "$bootmnt" ]; then
+ set -f
+ set -- $bootmnt
+ set +f
+ boottomnt=""
+
+ # Try to map labels and UUIDs ourselves if possible,
+ # so that we can check whether they're already
+ # mounted somewhere else.
+ tmppart="$1"
+ if echo "$1" | grep -q "^/dev/mapper/"; then
+ lvboot="$tmppart"
+ elif echo "$1" | grep -q "LABEL="; then
+ label="$(echo "$1" | cut -d = -f 2)"
+ if tmppart="$(find_label "$label")"; then
+ debug "mapped LABEL=$label to $tmppart"
+ else
+ debug "found boot partition LABEL=$label for Linux system on $partition, but cannot map to existing device"
+ mountboot="$partition 0"
+ return
+ fi
+ elif echo "$1" | grep -q "UUID="; then
+ uuid="$(echo "$1" | cut -d = -f 2)"
+ if tmppart="$(find_uuid "$uuid")"; then
+ debug "mapped UUID=$uuid to $tmppart"
+ else
+ debug "found boot partition UUID=$uuid for Linux system on $partition, but cannot map to existing device"
+ mountboot="$partition 0"
+ return
+ fi
+ fi
+ shift
+ set -- "$(mapdevfs "$tmppart")" "$@"
+
+ if grep -q "^$1 " "$OS_PROBER_TMP/mounted-map"; then
+ bindfrom="$(grep "^$1 " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 2)"
+ bindfrom="$(unescape_mount "$bindfrom")"
+ if [ "$bindfrom" != "$tmpmnt/boot" ]; then
+ if mount --bind "$bindfrom" "$tmpmnt/boot"; then
+ mounted=1
+ bootpart="$1"
+ else
+ debug "failed to bind-mount $bindfrom onto $tmpmnt/boot"
+ fi
+ fi
+ fi
+ if [ "$mounted" ]; then
+ :
+ elif [ -e "$1" ]; then
+ bootpart="$1"
+ boottomnt="$1"
+ elif [ -e "$tmpmnt/$1" ]; then
+ bootpart="$1"
+ boottomnt="$tmpmnt/$1"
+ elif [ -e "/target/$1" ]; then
+ bootpart="$1"
+ boottomnt="/target/$1"
+ else
+ bootpart=""
+ fi
+
+ if [ ! "$mounted" ]; then
+ if [ -z "$bootpart" ]; then
+ debug "found boot partition $1 for linux system on $partition, but cannot map to existing device"
+ else
+ debug "found boot partition $bootpart for linux system on $partition"
+ if type grub-mount >/dev/null 2>&1 && \
+ grub-mount "$boottomnt" "$tmpmnt/boot" 2>/dev/null; then
+ mounted=1
+ else
+ ro_partition "$boottomnt"
+ if mount -o ro "$boottomnt" "$tmpmnt/boot" -t "$3"; then
+ mounted=1
+ else
+ error "failed to mount $boottomnt on $tmpmnt/boot"
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ if [ -n "$lvboot" ]; then
+ bootpart="$lvboot"
+ fi
+ if [ -z "$bootpart" ]; then
+ bootpart="$partition"
+ fi
+ if [ -z "$mounted" ]; then
+ mounted=0
+ fi
+
+ mountboot="$bootpart $mounted"
+}
diff -uNr os-prober-1.56-orig-1/linux-boot-prober os-prober-1.56/linux-boot-prober
--- os-prober-1.56-orig-1/linux-boot-prober 2012-03-27 10:39:42.000000000 -0400
+++ os-prober-1.56/linux-boot-prober 2013-01-10 08:34:43.644058934 -0500
@@ -5,16 +5,143 @@
newns "$@"
require_tmpdir
+ERR="n"
+
+tmpmnt=/var/lib/os-prober/mount
+if [ ! -d "$tmpmnt" ]; then
+ mkdir "$tmpmnt"
+fi
+
+mounted=
+bootmnt=
+bootsv=
+bootuuid=
grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true
-partition="$1"
+if [ -z "$1" ]; then
+ ERR=y
+elif [ "$1" = btrfs -a -z "$2" ]; then
+ ERR=y
+elif [ "$1" = btrfs -a -z "$3" ]; then
+ ERR=y
+elif [ "$1" = btrfs ]; then
+ type=btrfs
+ echo "$2" | grep -q "^UUID=" || ERR=y
+ echo "$3" | grep -q "^subvol=" || ERR=y
+ export "$2"
+ export "$3"
+ partition=$(blkid | grep "$UUID" | cut -d ':' -f 1 | tr '\n' ' ' | cut -d ' ' -f 1)
+ debug "btrfs: partition=$partition, UUID=$UUID, subvol=$subvol"
+else
+ partition="$1"
+ type=other
+fi
-if [ -z "$partition" ]; then
+if [ "x$ERR" != xn ]; then
echo "usage: linux-boot-prober partition" >&2
+ echo " linux-boot-prober btrfs UUID=<> subvol=<>" >&2
exit 1
fi
+if [ "$type" = btrfs ]; then
+ # handle all of the btrfs stuff here
+ if [ ! -e "/proc/self/mountinfo" ]; then
+ warn "/proc/self/mountinfo does not exist, exiting"
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ mpoint=$(grep "btrfs" /proc/self/mountinfo | grep " /$subvol " | grep " $partition " | cut -d ' ' -f 5)
+ if [ "$mpoint" = "/" ]; then
+ warn "specifying active root not valid, exiting"
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ if [ "$mpoint" = "$tmpmnt" ]; then
+ warn "btrfs subvol=$subvool, UUID=$UUID, already mounted on $tmpmnt **ERROR**"
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ if [ -z "$mpoint" ]; then
+ # mount the btrfs root
+ if ! mount -o subvol=$subvol -t btrfs -U $UUID "$tmpmnt" 2>/dev/null; then
+ warn "error mounting btrfs subvol=$subvol UUID=$UUID"
+ umount "$tmpmnt/boot" 2>/dev/null
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ else
+ # bind-mount
+ if ! mount -o bind "$mpoint" "$tmpmnt" 2>/dev/null; then
+ warn "error mounting btrfs bindfrom=$mpoint subvol=$subvol UUID=$UUID"
+ umount "$tmpmnt/boot" 2>/dev/null
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ fi
+ debug "mounted btrfs $partition, subvol=$subvol on $tmpmnt"
+ if [ ! -e "$tmpmnt/etc/fstab" ]; then
+ warn "btrfs subvol=$subvol not root"
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ bootmnt=$(parsefstab < "$tmpmnt/etc/fstab" | grep " /boot ") || true
+ if [ -z "$bootmnt" ]; then
+ # /boot is part of the root
+ bootpart="$partition"
+ bootsv="$subvol"
+ elif echo "$bootmnt" | cut -d ' ' -f 3 | grep -q "btrfs"; then
+ # separate btrfs /boot subvolume
+ bootsv=$(echo "$bootmnt" | cut -d ' ' -f 4 | grep "^subvol=" | sed "s/subvol=//" )
+ bootuuid=$(echo "$bootmnt" | cut -d ' ' -f 1 | grep "^UUID=" | sed "s/UUID=//" )
+ debug "mounting btrfs $tmpmnt/boot UUID=$bootuuid subvol=$bootsv"
+ bindfrom=$(check_btrfs_mounted $bootsv $bootuuid)
+ if [ -n "$bindfrom" ]; then
+ # already mounted some place
+ if ! mount -o bind $bindfrom "$tmpmnt/boot" 2>/dev/null; then
+ warn "error bind mounting btrfs boot subvol=$bootsv, from=$bindfrom"
+ umount "$tmpmnt/boot" 2>/dev/null
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ elif ! mount -o subvol=$bootsv -t btrfs -U $bootuuid "$tmpmnt/boot" 2>/dev/null; then
+ warn "error mounting btrfs boot partition subvol=$bootsv, UUID=$bootuuid"
+ umount "$tmpmnt/boot" 2>/dev/null
+ umount "$tmpmnt" 2>/dev/null
+ rmdir "$tmpmnt" 2>/dev/null
+ exit 1
+ fi
+ bootpart=$(grep " btrfs " /proc/self/mountinfo | grep " /$bootsv " | cut -d ' ' -f 10)
+ else
+ # non-btrfs partition or logical volume
+ linux_mount_boot $partition $tmpmnt
+ bootpart="${mountboot%% *}"
+ bootsv=
+ fi
+
+ test="/usr/lib/linux-boot-probes/mounted/40grub2"
+ if [ -f $test ] && [ -x $test ]; then
+ debug "running $test $partition $bootpart $tmpmnt $type $subvol $bootsv"
+ if $test "$partition" "$bootpart" "$tmpmnt" "$type" "$subvol" "$bootsv"; then
+ debug "$test succeeded"
+ fi
+ fi
+ umount "$tmpmnt/boot" 2>/dev/null || true
+ if ! umount "$tmpmnt" 2>/dev/null; then
+ warn "problem umount $tmpmnt"
+ fi
+ rmdir "$tmpmnt" 2>/dev/null || true
+
+ exit 0
+fi
+
if ! mapped="$(mapdevfs "$partition")"; then
log "Device '$partition' does not exist; skipping"
continue
@@ -22,8 +149,8 @@
if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map"; then
for test in /usr/lib/linux-boot-probes/*; do
- debug "running $test"
if [ -x $test ] && [ -f $test ]; then
+ debug "running $test"
if $test "$partition"; then
debug "linux detected by $test"
break
diff -uNr os-prober-1.56-orig-1/linux-boot-probes/mounted/common/40grub2 os-prober-1.56/linux-boot-probes/mounted/common/40grub2
--- os-prober-1.56-orig-1/linux-boot-probes/mounted/common/40grub2 2012-09-17 13:32:52.000000000 -0400
+++ os-prober-1.56/linux-boot-probes/mounted/common/40grub2 2013-01-10 08:34:43.644058934 -0500
@@ -2,17 +2,27 @@
. /usr/share/os-prober/common.sh
set -e
+# add support for btrfs with no separate /boot
+# that is, rootsv = bootsv
partition="$1"
bootpart="$2"
mpoint="$3"
type="$4"
+rootsv="$5"
+bootsv="$6"
found_item=0
entry_result () {
+ if [ "x$type" = "xbtrfs" -a "$rootsv" = "$bootsv" ]; then
+ # trim off the leading subvol
+ kernelfile=$(echo "$kernel" | cut -d '/' -f 2- | cut -d '/' -f 2-)
+ else
+ kernelfile=$kernel
+ fi
if [ "$ignore_item" = 0 ] && \
[ -n "$kernel" ] && \
- [ -e "$mpoint/$kernel" ]; then
+ [ -e "$mpoint/$kernelfile" ]; then
result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
found_item=1
fi
diff -uNr os-prober-1.56-orig-1/os-prober os-prober-1.56/os-prober
--- os-prober-1.56-orig-1/os-prober 2013-01-10 08:33:45.193766227 -0500
+++ os-prober-1.56/os-prober 2013-01-10 08:34:43.645058939 -0500
@@ -64,9 +64,12 @@
# Also detect OSes on LVM volumes (assumes LVM is active)
if type lvs >/dev/null 2>&1; then
- echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name |
+ echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name 2>/dev/null |
sed "s|-|--|g;s|^[[:space:]]*\(.*\):\(.*\)$|/dev/mapper/\1-\2|")"
fi
+
+ # now lets make sure we got all of the btrfs partitions and disks
+ blkid | grep btrfs | cut -d ':' -f 1
}
parse_proc_swaps () {
@@ -124,6 +127,8 @@
grep "^md" /proc/mdstat | cut -d: -f2- | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true
fi
+: >"$OS_PROBER_TMP/btrfs-vols"
+
for partition in $(partitions); do
if ! mapped="$(mapdevfs "$partition")"; then
log "Device '$partition' does not exist; skipping"
@@ -142,7 +147,26 @@
continue
fi
- if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
+ # do btrfs processing here; both mounted and unmounted will
+ # be handled by 50mounted-tests so we can do a subvol only once.
+ type=$(blkid -o value -s TYPE $mapped)
+ if [ "$type" = btrfs ]; then
+ uuid=$(blkid -o value -s UUID $mapped)
+ if grep -q "^$uuid" "$OS_PROBER_TMP/btrfs-vols" ; then
+ continue
+ fi
+ debug "btrfs volume uuid=$uuid partition=$partition"
+ echo "$uuid" >>"$OS_PROBER_TMP/btrfs-vols"
+ test="/usr/lib/os-probes/50mounted-tests"
+ if [ -f "$test" ] && [ -x "$test" ]; then
+ debug "running $test on btrfs $partition"
+ if "$test" btrfs "$uuid" "$partition"; then
+ debug "os detected by $test"
+ continue
+ fi
+ fi
+
+ elif ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
for test in /usr/lib/os-probes/*; do
if [ -f "$test" ] && [ -x "$test" ]; then
debug "running $test on $partition"
diff -uNr os-prober-1.56-orig-1/os-probes/common/50mounted-tests os-prober-1.56/os-probes/common/50mounted-tests
--- os-prober-1.56-orig-1/os-probes/common/50mounted-tests 2012-09-17 11:08:12.000000000 -0400
+++ os-prober-1.56/os-probes/common/50mounted-tests 2013-01-10 08:34:43.645058939 -0500
@@ -1,20 +1,36 @@
#!/bin/sh
# Sub-tests that require a mounted partition.
set -e
-partition="$1"
. /usr/share/os-prober/common.sh
-types="$(fs_type "$partition")" || types=NOT-DETECTED
+if [ "x$1" = xbtrfs ]; then
+ types=btrfs
+ if [ -z "$2" -o -z "$3" ]; then
+ debug "missing btrfs parameters, exiting"
+ exit 1
+ fi
+ UUID="$2"
+ BTRFSDEV="$3"
+else
+ partition="$1"
+ types="$(fs_type "$partition")" || types=NOT-DETECTED
+fi
+
if [ "$types" = NOT-DETECTED ]; then
debug "$1 type not recognised; skipping"
- exit 0
+ exit 1
+elif [ "x$types" = "x" ]; then
+ exit 1
+elif [ "$types" = LVM2_member ]; then
+ debug "skipping LVM2 Volume Group on $partition"
+ exit 1
elif [ "$types" = swap ]; then
debug "$1 is a swap partition; skipping"
- exit 0
+ exit 1
elif [ "$types" = crypto_LUKS ]; then
debug "$1 is a LUKS partition; skipping"
- exit 0
+ exit 1
elif [ "$types" = ntfs ]; then
if type ntfs-3g >/dev/null 2>&1; then
types='ntfs-3g ntfs'
@@ -23,7 +39,7 @@
if type cryptsetup >/dev/null 2>&1 && \
cryptsetup luksDump "$partition" >/dev/null 2>&1; then
debug "$1 is a LUKS partition; skipping"
- exit 0
+ exit 1
fi
for type in $(grep -v nodev /proc/filesystems); do
# hfsplus filesystems are mountable as hfs. Try hfs last so
@@ -46,6 +62,76 @@
fi
mounted=
+
+# all btrfs processing here. Handle both unmounted and
+# mounted subvolumes.
+if [ "$types" = btrfs ]; then
+ partition="$BTRFSDEV"
+ debug "begin btrfs processing for $UUID"
+ # note that the btrfs volume must not be mounted ro
+ if mount -t btrfs -U "$UUID" "$tmpmnt" 2>/dev/null; then
+ debug "btrfs volume $UUID mounted"
+ else
+ warn "cannot mount btrfs volume $UUID, exiting"
+ rmdir "$tmpmnt" || true
+ exit 1
+ fi
+ # besides regular subvols, get ro and snapshot so thet can be excluded
+ subvols=$(btrfs subvolume list "$tmpmnt" | cut -d ' ' -f 9)
+ rosubvols=$(btrfs subvolume list -r "$tmpmnt" | cut -d ' ' -f 9)
+ sssubvols=$(btrfs subvolume list -s "$tmpmnt" | cut -d ' ' -f 9)
+ if ! umount "$tmpmnt"; then
+ warn "failed to umount btrfs volume on $tmpmnt"
+ rmdir "$tmpmnt" || true
+ exit 1
+ fi
+ if [ -z "$subvols" ]; then
+ debug "no subvols found on btrfs volume $UUID"
+ exit 1
+ fi
+ found=
+ for subvol in $subvols; do
+ debug "begin btrfs processing for $UUID subvol=$subvol"
+ if echo "$rosubvols" | grep -q -x "$subvol"; then
+ continue
+ fi
+ if echo "$sssubvols" | grep -q -x "$subvol"; then
+ continue
+ fi
+ mounted=
+ mpoint="$(grep btrfs /proc/self/mountinfo | grep "$partition " | grep "/$subvol " | cut -d ' ' -f 5)"
+ if [ -n "$mpoint" ]; then
+ if [ "x$mpoint" = "x/" ]; then
+ continue # this is the root for the running system
+ fi
+ mounted=1
+ else
+ # again, do not mount btrfs ro
+ mount -t btrfs -o subvol="$subvol" -U "$UUID" "$tmpmnt"
+ mpoint="$tmpmnt"
+ fi
+ test="/usr/lib/os-probes/mounted/90linux-distro"
+ if [ -f "$test" ] && [ -x "$test" ]; then
+ debug "running subtest $test"
+ if "$test" "$partition" "$mpoint" btrfs "UUID=$UUID" "subvol=$subvol"; then
+ debug "os found by subtest $test on subvol $subvol"
+ found=1
+ fi
+ fi
+ if [ -z "$mounted" ]; then
+ if ! umount "$tmpmnt"; then
+ warn "failed to umount $tmpmnt"
+ fi
+ fi
+ done
+ rmdir "$tmpmnt" || true
+ if [ "$found" ]; then
+ exit 0
+ else
+ exit 1
+ fi
+fi
+
if type grub-mount >/dev/null 2>&1 && \
type grub-probe >/dev/null 2>&1 && \
grub-mount "$partition" "$tmpmnt" 2>/dev/null; then
diff -uNr os-prober-1.56-orig-1/os-probes/mounted/common/90linux-distro os-prober-1.56/os-probes/mounted/common/90linux-distro
--- os-prober-1.56-orig-1/os-probes/mounted/common/90linux-distro 2013-01-10 08:33:45.197766247 -0500
+++ os-prober-1.56/os-probes/mounted/common/90linux-distro 2013-01-10 08:34:43.645058939 -0500
@@ -7,6 +7,8 @@
partition="$1"
dir="$2"
type="$3"
+uuid="$4"
+subvol="$5"
# This test is inaccurate, but given separate / and /boot partitions and the
# fact that only some architectures have ld-linux.so, I can't see anything
@@ -128,7 +130,11 @@
fi
label="$(count_next_label "$short")"
- result "$partition:$long:$label:linux"
+ if [ "x$type" = "xbtrfs" -a "x$uuid" != "x" -a "x$subvol" != "x" ]; then
+ result "$partition:$long:$label:linux:$type:$uuid:$subvol"
+ else
+ result "$partition:$long:$label:linux"
+ fi
exit 0
else
exit 1
diff -uNr os-prober-1.56-orig-1/README.btrfs os-prober-1.56/README.btrfs
--- os-prober-1.56-orig-1/README.btrfs 1969-12-31 19:00:00.000000000 -0500
+++ os-prober-1.56/README.btrfs 2013-01-10 08:34:43.645058939 -0500
@@ -0,0 +1,15 @@
+BTRFS is a new filesystem which combines the filesystem with logical volume
+management (subvolumes). For further information, see:
+ https://btrfs.wiki.kernel.org/index.php/Main_Page
+ https://btrfs.wiki.kernel.org/index.php/FAQ
+
+In order to support BTRFS, a number of changes were necessary to os-prober,
+os-probes/common/50mounted-tests, os-probes/mounted/common/90linux-distro,
+linux-boot-prober, and linux-boot-probes/common/50mounted-tests.
+
+The biggest impact will be to grub2 where there is additional information
+output by os-prober and where, if a BTRFS subvolume is being used for root,
+the parameters for linux-boot-prober have changed.
+
+Sun 30 Dec 2012 11:49:52 AM EST Gene Czarcinski <g...@czarc.net>
+
diff -ur os-prober-1.56-orig/common.sh os-prober-1.56/common.sh
--- os-prober-1.56-orig/common.sh 2012-12-26 13:53:55.962187097 -0500
+++ os-prober-1.56/common.sh 2013-01-10 08:25:14.843206268 -0500
@@ -76,7 +76,9 @@
}
debug() {
- log "debug: $@"
+ if [ -n "$OS_PROBER_ENABLE_DEBUG" ]; then
+ log "debug: $@"
+ fi
}
result () {
diff -ur os-prober-1.56-orig-0/common.sh os-prober-1.56/common.sh
--- os-prober-1.56-orig-0/common.sh 2013-01-10 08:28:43.867255779 -0500
+++ os-prober-1.56/common.sh 2013-01-10 08:29:27.173473026 -0500
@@ -194,6 +194,7 @@
bootpart=""
mounted=""
+ lvboot=""
if [ -e "$tmpmnt/etc/fstab" ]; then
# Try to mount any /boot partition.
bootmnt=$(parsefstab < "$tmpmnt/etc/fstab" | grep " /boot ") || true
@@ -207,7 +208,9 @@
# so that we can check whether they're already
# mounted somewhere else.
tmppart="$1"
- if echo "$1" | grep -q "LABEL="; then
+ if echo "$1" | grep -q "^/dev/mapper/"; then
+ lvboot="$tmppart"
+ elif echo "$1" | grep -q "LABEL="; then
label="$(echo "$1" | cut -d = -f 2)"
if tmppart="$(find_label "$label")"; then
debug "mapped LABEL=$label to $tmppart"
@@ -276,6 +279,9 @@
fi
fi
fi
+ if [ -n "$lvboot" ]; then
+ bootpart="$lvboot"
+ fi
if [ -z "$bootpart" ]; then
bootpart="$partition"
fi
Only in os-prober-1.56: common.sh.orig
>From 9049389abd37ab8251d4bfcb3ee73012221e7546 Mon Sep 17 00:00:00 2001
From: Fedora Ninjas <grub2-ow...@fedoraproject.org>
Date: Thu, 10 Jan 2013 08:57:28 -0500
Subject: [PATCH] Add btrfs support for root and boot on a subvolume
This patch adds support for having root ("/") and or /boot
being on a btrfs subvolume. It also supports no separate
/boot.
This requires an updated os-prober package which also provides
btrfs support for both os-prober and linux-boot-prober.
---
util/grub.d/30_os-prober.in | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
index bcc6c25..be989ac 100644
--- a/util/grub.d/30_os-prober.in
+++ b/util/grub.d/30_os-prober.in
@@ -112,6 +112,11 @@ for OS in ${OSPROBED} ; do
LONGNAME="`echo ${OS} | cut -d ':' -f 2 | tr '^' ' '`"
LABEL="`echo ${OS} | cut -d ':' -f 3 | tr '^' ' '`"
BOOT="`echo ${OS} | cut -d ':' -f 4`"
+ BTRFS="`echo ${OS} | cut -d ':' -f 5`"
+ if [ "x$BTRFS" = "xbtrfs" ]; then
+ BTRFSuuid="`echo ${OS} | cut -d ':' -f 6`"
+ BTRFSsubvol="`echo ${OS} | cut -d ':' -f 7`"
+ fi
if [ -z "${LONGNAME}" ] ; then
LONGNAME="${LABEL}"
@@ -145,7 +150,11 @@ EOF
EOF
;;
linux)
- LINUXPROBED="`linux-boot-prober ${DEVICE} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`"
+ if [ "x$BTRFS" = "xbtrfs" ]; then
+ LINUXPROBED="`linux-boot-prober btrfs ${BTRFSuuid} ${BTRFSsubvol} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`"
+ else
+ LINUXPROBED="`linux-boot-prober ${DEVICE} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`"
+ fi
prepare_boot_cache=
boot_device_id=
is_first_entry=true
--
1.8.1