[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#688336: os-probe: subvol: patches to provide bootloaders with all the subvolume info.



Hello,
  This is the result of several days working the issues and analysing
each aspect.  These patches include only what is necessary to support
subvol.  Care has been taken to future proof by preparing for other
filesystems, currently this only works with btrfs.  These patches have
been split, solving four main goals.

1. Scan btrfs filesystems only once, regardless of how many devices they span.
2. Report to the bootloader the existence of OS lurking on subvolumes.
3. Add option to linux-boot-prober for subvolume and output
appropriate rootoptions.
4. Tell bootloader about boot filesystems on a subvolume.

1 is simple and can be applied with no changes to the bootloader.

2 extends the output of os-prober to support subvolumes. Existing
bootloaders should ignore these records as the key was changed from
linux to linux-subvol and the device is listed as device@subvolid.

3 requires the bootloader to be patched to support the above
linux-subvol records.  It should be a noop for bootloaders that don't
pass a subvolid as the second parameter to linux-boot-prober.

4 I would hold off on, it requires the bootloader to support
subvolumes and I think it's ok to restrict the boot device to
non-subvolumes until such support is added.
From c37c722edba11566ce4bd73e80120b56a37dfa37 Mon Sep 17 00:00:00 2001
From: Michael Mestnik <cheako+github_com@mikemestnik.net>
Date: Mon, 5 Jun 2017 11:08:42 -0500
Subject: [PATCH 4/4] Pass subvol data for /boot to bootloadter(s)

---
 common.sh                                   | 36 +++++++++++++++++++++++++++++
 linux-boot-prober                           |  6 +++--
 linux-boot-probes/mounted/common/40grub2    |  3 ++-
 linux-boot-probes/mounted/common/90fallback |  5 ++--
 linux-boot-probes/mounted/powerpc/40yaboot  |  3 ++-
 linux-boot-probes/mounted/sparc/50silo      |  3 ++-
 linux-boot-probes/mounted/x86/40grub        |  3 ++-
 linux-boot-probes/mounted/x86/50lilo        |  3 ++-
 8 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/common.sh b/common.sh
index 1001c74..ff278c3 100644
--- a/common.sh
+++ b/common.sh
@@ -253,6 +253,42 @@ linux_mount_boot () {
 			shift
 			set -- "$(mapdevfs "$tmppart")" "$@"
 
+			if bootsubvolid="$(echo "$4" | grep -o 'subvolid=[0-9][0-9]*')"; then
+				bootsubvolid="$(echo "$bootsubvolid" | cut -d= -f2-)"
+				if mount -o "subvolid=$bootsubvolid" "$1" "$tmpmnt/boot"; then
+					if [ "$bootsubvolid" = "$(get_default_subvolid "$tmpmnt/boot")" ]; then
+						mountboot="$1 1"
+						return
+					else
+						mountboot="$1 1 $bootsubvolid"
+						return
+					fi
+				else
+					debug "failed to subvolid-mount $1 onto $tmpmnt/boot"
+					mountboot="$1 0 $bootsubvolid"
+					return
+				fi
+			else
+				if bootsubvol="$(echo "$4" | grep -o 'subvol=[^,]*')"; then
+					bootsubvol="$(echo "$bootsubvol" | cut -d= -f2-)"
+					bootsubvol="${bootsubvol#/}"
+					if mount -o "subvol=${bootsubvol:=/}" "$1" "$tmpmnt/boot"; then
+						bootsubvolid="$(grep "^/dev/" /proc/mounts | parse_proc_mounts | grep " $tmpmnt/boot " | cut -d ' ' -f 4)"
+						if [ "$bootsubvolid" = "$(get_default_subvolid "$tmpmnt/boot")" ]; then
+							mountboot="$1 1"
+							return
+						else
+							mountboot="$1 1 ${bootsubvolid:-@$bootsubvol}"
+							return
+						fi
+					else
+						debug "failed to subvol-mount $1 onto $tmpmnt/boot"
+						mountboot="$1 0 @$bootsubvol"
+						return
+					fi
+				fi
+			fi
+
 			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")"
diff --git a/linux-boot-prober b/linux-boot-prober
index c53f05d..ba1a0bf 100755
--- a/linux-boot-prober
+++ b/linux-boot-prober
@@ -36,19 +36,21 @@ else
 	mpoint="$(unescape_mount "$mpoint")"
 	if [ "$mpoint" != "/target/boot" ] && [ "$mpoint" != "/target" ] && [ "$mpoint" != "/" ]; then
 		type=$(echo "$mrecord" | head -n1 | cut -d " " -f 3)
-		if ! grep -q " $mpoint/boot " "$OS_PROBER_TMP/mounted-map"; then
+		if ! bootrecord="$(grep -q " $mpoint/boot " "$OS_PROBER_TMP/mounted-map")"; then
 			linux_mount_boot "$partition" "$mpoint"
 			set -- $mountboot
 			bootpart="$1"
 			bootmounted="$2"
+			bootsubvolid="$3"
 		else
 			bootpart="$partition"
 			bootmounted=0
+			bootsubvolid="$(echo "$bootrecord" | head -n1 | cut -d ' ' -f 4)"
 		fi
 		for test in /usr/lib/linux-boot-probes/mounted/*; do
 			if [ -f $test ] && [ -x $test ]; then
 				debug "running $test on mounted $partition"
-				if $test "$partition" "$bootpart" "$mpoint" "$type" "$subvolid"; then
+				if $test "$partition" "$bootpart" "$mpoint" "$type" "$subvolid" "$bootsubvolid"; then
 					debug "$test succeeded"
 					break
 				fi
diff --git a/linux-boot-probes/mounted/common/40grub2 b/linux-boot-probes/mounted/common/40grub2
index 9d0b48c..06b8744 100755
--- a/linux-boot-probes/mounted/common/40grub2
+++ b/linux-boot-probes/mounted/common/40grub2
@@ -7,6 +7,7 @@ bootpart="$2"
 mpoint="$3"
 type="$4"
 subvolid="$5"
+bootsubvolid="$6"
 
 found_item=0
 
@@ -14,7 +15,7 @@ entry_result () {
 	if [ "$ignore_item" = 0 ] && \
 	   [ -n "$kernel" ] && \
 	   [ -e "$mpoint/$kernel" ]; then
-		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
+		result "$rootpart:$bootpart${bootsubvolid:+@$bootsubvolid}:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 		found_item=1
 	fi
 	kernel=""
diff --git a/linux-boot-probes/mounted/common/90fallback b/linux-boot-probes/mounted/common/90fallback
index da0d22d..7a5b001 100755
--- a/linux-boot-probes/mounted/common/90fallback
+++ b/linux-boot-probes/mounted/common/90fallback
@@ -9,6 +9,7 @@ bootpart="$2"
 mpoint="$3"
 type="$4"
 subvolid="$5"
+bootsubvolid="$6"
 
 mappedpartition=$(mapdevfs "$partition" 2>/dev/null) || mappedpartition="$partition"
 
@@ -39,13 +40,13 @@ for kernpat in /vmlinuz /vmlinux /boot/vmlinuz /boot/vmlinux "/boot/vmlinuz*" \
 			for initrd in $(eval ls "$initrdname" "$initrdname1" "$initrdname2" "$initrdname3" "$initrdname4" 2>/dev/null); do
 				if [ "$initrd" != "$kernfile" ] && [ -f "$initrd" ] && [ ! -L "$initrd" ]; then
 					initrd=$(echo "$initrd" | sed "s!^$mpoint!!")
-					result "$partition:$kernbootpart::$kernbasefile:$initrd:root=$mappedpartition${subvolid:+ rootflags=subvolid=$subvolid}"
+					result "$partition:$kernbootpart${bootsubvolid:+@$bootsubvolid}::$kernbasefile:$initrd:root=$mappedpartition${subvolid:+ rootflags=subvolid=$subvolid}"
 					exitcode=0
 					foundinitrd=1
 				fi
 			done
 			if [ "$foundinitrd" = 0 ]; then
-				result "$partition:$kernbootpart::$kernbasefile::root=$mappedpartition${subvolid:+ rootflags=subvolid=$subvolid}"
+				result "$partition:$kernbootpart${bootsubvolid:+@$bootsubvolid}::$kernbasefile::root=$mappedpartition${subvolid:+ rootflags=subvolid=$subvolid}"
 				exitcode=0
 			fi
 		fi
diff --git a/linux-boot-probes/mounted/powerpc/40yaboot b/linux-boot-probes/mounted/powerpc/40yaboot
index 44ca0bc..05f4c82 100755
--- a/linux-boot-probes/mounted/powerpc/40yaboot
+++ b/linux-boot-probes/mounted/powerpc/40yaboot
@@ -7,6 +7,7 @@ bootpart="$2"
 mpoint="$3"
 type="$4"
 subvolid="$5"
+bootsubvolid="$6"
 
 found_item=0
 
@@ -37,7 +38,7 @@ recordstanza () {
 			parameters="root=$rootdev $parameters"
 		fi
 		parameters="${parameters% }"
-		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
+		result "$rootpart:$bootpart${bootsubvolid:+@$bootsubvolid}:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 		found_item=1
 
 		title=
diff --git a/linux-boot-probes/mounted/sparc/50silo b/linux-boot-probes/mounted/sparc/50silo
index da6579b..71098e1 100755
--- a/linux-boot-probes/mounted/sparc/50silo
+++ b/linux-boot-probes/mounted/sparc/50silo
@@ -7,6 +7,7 @@ bootpart="$2"
 mpoint="$3"
 type="$4"
 subvolid="$5"
+bootsubvolid="$6"
 
 found_item=0
 
@@ -38,7 +39,7 @@ recordstanza () {
 					parameters="root=$rootdev $parameters"
 				fi
 				parameters="${parameters% }"
-				result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
+				result "$rootpart:$bootpart${bootsubvolid:+@$bootsubvolid}:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 				found_item=1
 			else
 				debug "cannot find $initrd, not recording"
diff --git a/linux-boot-probes/mounted/x86/40grub b/linux-boot-probes/mounted/x86/40grub
index 4e2eaf1..3cd2839 100755
--- a/linux-boot-probes/mounted/x86/40grub
+++ b/linux-boot-probes/mounted/x86/40grub
@@ -7,6 +7,7 @@ bootpart="$2"
 mpoint="$3"
 type="$4"
 subvolid="$5"
+bootsubvolid="$6"
 
 found_item=0
 
@@ -14,7 +15,7 @@ entry_result () {
 	if [ "$ignore_item" = 0 ] && \
 	   [ -n "$kernel" ] && \
 	   [ -e "$mpoint/$kernel" ]; then
-		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
+		result "$rootpart:$bootpart${bootsubvolid:+@$bootsubvolid}:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 		found_item=1
 	fi
 	kernel=""
diff --git a/linux-boot-probes/mounted/x86/50lilo b/linux-boot-probes/mounted/x86/50lilo
index d0f3c1d..6918a1b 100755
--- a/linux-boot-probes/mounted/x86/50lilo
+++ b/linux-boot-probes/mounted/x86/50lilo
@@ -7,6 +7,7 @@ bootpart="$2"
 mpoint="$3"
 type="$4"
 subvolid="$5"
+bootsubvolid="$6"
 
 found_item=0
 
@@ -49,7 +50,7 @@ recordstanza () {
 				parameters="root=$rootdev $parameters"
 			fi
 			parameters="${parameters% }"
-			result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
+			result "$rootpart:$bootpart${bootsubvolid:+@$bootsubvolid}:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 			found_item=1
 		else
 			debug "cannot find $kernel or $initrd, not recording"
-- 
2.11.0

From deebe39945932c055acc0be9153e6d3f8dd73608 Mon Sep 17 00:00:00 2001
From: Michael Mestnik <cheako+github_com@mikemestnik.net>
Date: Tue, 6 Jun 2017 21:42:19 -0500
Subject: [PATCH 3/4] Handle subvol during boot probe

---
 common.sh                                   |  5 +++--
 linux-boot-prober                           | 16 +++++++++-------
 linux-boot-probes/mounted/common/40grub2    |  3 ++-
 linux-boot-probes/mounted/common/90fallback |  5 +++--
 linux-boot-probes/mounted/powerpc/40yaboot  |  3 ++-
 linux-boot-probes/mounted/sparc/50silo      |  3 ++-
 linux-boot-probes/mounted/x86/40grub        |  3 ++-
 linux-boot-probes/mounted/x86/50lilo        |  3 ++-
 8 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/common.sh b/common.sh
index d486cec..1001c74 100644
--- a/common.sh
+++ b/common.sh
@@ -151,7 +151,8 @@ parse_proc_mounts () {
 		set -f
 		set -- $line
 		set +f
-		printf '%s %s %s\n' "$(mapdevfs "$1")" "$2" "$3"
+		printf '%s %s %s %s\n' "$(mapdevfs "$1")" "$2" "$3" "$(
+		echo "$4" | grep -o 'subvolid=[0-9][0-9]*' | cut -d= -f2)"
 	done
 }
 
@@ -165,7 +166,7 @@ parsefstab () {
 				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
diff --git a/linux-boot-prober b/linux-boot-prober
index e32dc84..c53f05d 100755
--- a/linux-boot-prober
+++ b/linux-boot-prober
@@ -9,6 +9,7 @@ require_tmpdir
 grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true
 
 partition="$1"
+subvolid="$2"
 
 if [ -z "$partition" ]; then
 	echo "usage: linux-boot-prober partition" >&2
@@ -20,25 +21,26 @@ if ! mapped="$(mapdevfs "$partition")"; then
 	continue
 fi
 
-if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map"; then
+if ! mrecord="$(grep "^$mapped [^ ]* [^ ]* $subvolid" "$OS_PROBER_TMP/mounted-map")"; then
 	for test in /usr/lib/linux-boot-probes/*; do
 		debug "running $test"
 		if [ -x $test ] && [ -f $test ]; then
-			if $test "$partition"; then
+			if $test "$partition" "$subvolid"; then
 				debug "linux detected by $test"
 				break
 			fi
 		fi
 	done
 else
-	mpoint=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 2)
+	mpoint=$(echo "$mrecord" | head -n1 | cut -d " " -f 2)
 	mpoint="$(unescape_mount "$mpoint")"
 	if [ "$mpoint" != "/target/boot" ] && [ "$mpoint" != "/target" ] && [ "$mpoint" != "/" ]; then
-		type=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 3)
+		type=$(echo "$mrecord" | head -n1 | cut -d " " -f 3)
 		if ! grep -q " $mpoint/boot " "$OS_PROBER_TMP/mounted-map"; then
 			linux_mount_boot "$partition" "$mpoint"
-			bootpart="${mountboot%% *}"
-			bootmounted="${mountboot#* }"
+			set -- $mountboot
+			bootpart="$1"
+			bootmounted="$2"
 		else
 			bootpart="$partition"
 			bootmounted=0
@@ -46,7 +48,7 @@ else
 		for test in /usr/lib/linux-boot-probes/mounted/*; do
 			if [ -f $test ] && [ -x $test ]; then
 				debug "running $test on mounted $partition"
-				if $test "$partition" "$bootpart" "$mpoint" "$type"; then
+				if $test "$partition" "$bootpart" "$mpoint" "$type" "$subvolid"; then
 					debug "$test succeeded"
 					break
 				fi
diff --git a/linux-boot-probes/mounted/common/40grub2 b/linux-boot-probes/mounted/common/40grub2
index 885614e..9d0b48c 100755
--- a/linux-boot-probes/mounted/common/40grub2
+++ b/linux-boot-probes/mounted/common/40grub2
@@ -6,6 +6,7 @@ partition="$1"
 bootpart="$2"
 mpoint="$3"
 type="$4"
+subvolid="$5"
 
 found_item=0
 
@@ -13,7 +14,7 @@ entry_result () {
 	if [ "$ignore_item" = 0 ] && \
 	   [ -n "$kernel" ] && \
 	   [ -e "$mpoint/$kernel" ]; then
-		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 		found_item=1
 	fi
 	kernel=""
diff --git a/linux-boot-probes/mounted/common/90fallback b/linux-boot-probes/mounted/common/90fallback
index 9ff78e1..da0d22d 100755
--- a/linux-boot-probes/mounted/common/90fallback
+++ b/linux-boot-probes/mounted/common/90fallback
@@ -8,6 +8,7 @@ partition="$1"
 bootpart="$2"
 mpoint="$3"
 type="$4"
+subvolid="$5"
 
 mappedpartition=$(mapdevfs "$partition" 2>/dev/null) || mappedpartition="$partition"
 
@@ -38,13 +39,13 @@ for kernpat in /vmlinuz /vmlinux /boot/vmlinuz /boot/vmlinux "/boot/vmlinuz*" \
 			for initrd in $(eval ls "$initrdname" "$initrdname1" "$initrdname2" "$initrdname3" "$initrdname4" 2>/dev/null); do
 				if [ "$initrd" != "$kernfile" ] && [ -f "$initrd" ] && [ ! -L "$initrd" ]; then
 					initrd=$(echo "$initrd" | sed "s!^$mpoint!!")
-					result "$partition:$kernbootpart::$kernbasefile:$initrd:root=$mappedpartition"
+					result "$partition:$kernbootpart::$kernbasefile:$initrd:root=$mappedpartition${subvolid:+ rootflags=subvolid=$subvolid}"
 					exitcode=0
 					foundinitrd=1
 				fi
 			done
 			if [ "$foundinitrd" = 0 ]; then
-				result "$partition:$kernbootpart::$kernbasefile::root=$mappedpartition"
+				result "$partition:$kernbootpart::$kernbasefile::root=$mappedpartition${subvolid:+ rootflags=subvolid=$subvolid}"
 				exitcode=0
 			fi
 		fi
diff --git a/linux-boot-probes/mounted/powerpc/40yaboot b/linux-boot-probes/mounted/powerpc/40yaboot
index 764621c..44ca0bc 100755
--- a/linux-boot-probes/mounted/powerpc/40yaboot
+++ b/linux-boot-probes/mounted/powerpc/40yaboot
@@ -6,6 +6,7 @@ partition="$1"
 bootpart="$2"
 mpoint="$3"
 type="$4"
+subvolid="$5"
 
 found_item=0
 
@@ -36,7 +37,7 @@ recordstanza () {
 			parameters="root=$rootdev $parameters"
 		fi
 		parameters="${parameters% }"
-		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 		found_item=1
 
 		title=
diff --git a/linux-boot-probes/mounted/sparc/50silo b/linux-boot-probes/mounted/sparc/50silo
index bb5c41c..da6579b 100755
--- a/linux-boot-probes/mounted/sparc/50silo
+++ b/linux-boot-probes/mounted/sparc/50silo
@@ -6,6 +6,7 @@ partition="$1"
 bootpart="$2"
 mpoint="$3"
 type="$4"
+subvolid="$5"
 
 found_item=0
 
@@ -37,7 +38,7 @@ recordstanza () {
 					parameters="root=$rootdev $parameters"
 				fi
 				parameters="${parameters% }"
-				result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+				result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 				found_item=1
 			else
 				debug "cannot find $initrd, not recording"
diff --git a/linux-boot-probes/mounted/x86/40grub b/linux-boot-probes/mounted/x86/40grub
index 08f6605..4e2eaf1 100755
--- a/linux-boot-probes/mounted/x86/40grub
+++ b/linux-boot-probes/mounted/x86/40grub
@@ -6,6 +6,7 @@ partition="$1"
 bootpart="$2"
 mpoint="$3"
 type="$4"
+subvolid="$5"
 
 found_item=0
 
@@ -13,7 +14,7 @@ entry_result () {
 	if [ "$ignore_item" = 0 ] && \
 	   [ -n "$kernel" ] && \
 	   [ -e "$mpoint/$kernel" ]; then
-		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+		result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 		found_item=1
 	fi
 	kernel=""
diff --git a/linux-boot-probes/mounted/x86/50lilo b/linux-boot-probes/mounted/x86/50lilo
index a011b56..d0f3c1d 100755
--- a/linux-boot-probes/mounted/x86/50lilo
+++ b/linux-boot-probes/mounted/x86/50lilo
@@ -6,6 +6,7 @@ partition="$1"
 bootpart="$2"
 mpoint="$3"
 type="$4"
+subvolid="$5"
 
 found_item=0
 
@@ -48,7 +49,7 @@ recordstanza () {
 				parameters="root=$rootdev $parameters"
 			fi
 			parameters="${parameters% }"
-			result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+			result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters${subvolid:+ rootflags=subvolid=$subvolid}"
 			found_item=1
 		else
 			debug "cannot find $kernel or $initrd, not recording"
-- 
2.11.0

From f455d764d91296a03a008c2091e9cb2bc2b0f140 Mon Sep 17 00:00:00 2001
From: Michael Mestnik <cheako+github_com@mikemestnik.net>
Date: Sun, 4 Jun 2017 20:42:11 -0500
Subject: [PATCH 2/4] Iterate over and insert, subvol, into output

---
 common.sh                               |  5 ++++
 debian/os-prober.prerm                  | 34 +++++++++++++++++++++
 os-prober                               | 52 +++++++++++++++++++++++++++++++++
 os-probes/mounted/common/40lsb          |  3 +-
 os-probes/mounted/common/90linux-distro |  3 +-
 5 files changed, 95 insertions(+), 2 deletions(-)
 create mode 100644 debian/os-prober.prerm

diff --git a/common.sh b/common.sh
index e1646d4..d486cec 100644
--- a/common.sh
+++ b/common.sh
@@ -204,6 +204,11 @@ find_uuid () {
 	fi
 }
 
+get_default_subvolid () {
+	btrfs subvolume get-default "$1" 2>/dev/null |
+	cut -d ' ' -f 2 | head -n1
+}
+
 # Sets $mountboot as output variables.  This is very messy, but POSIX shell
 # isn't really up to the task of doing it more cleanly.
 linux_mount_boot () {
diff --git a/debian/os-prober.prerm b/debian/os-prober.prerm
new file mode 100644
index 0000000..957d6ef
--- /dev/null
+++ b/debian/os-prober.prerm
@@ -0,0 +1,34 @@
+#!/bin/sh
+# prerm script for os-prober
+#
+# see: dh_installdeb(1)
+
+set -e
+
+case "$1" in
+  remove)
+    # Cleanup script temp files/folders
+    # in case of crash and user uninstalls.
+    # The last thing we want is for our pkg
+    # to generate even more errors on it's
+    # way out.
+    tmpmnt=/var/lib/os-prober/mnt
+    umount "$tmpmnt" 2>/dev/null || true
+    rmdir "$tmpmnt" 2>/dev/null || true
+  ;;
+
+  upgrade|deconfigure|failed-upgrade)
+  ;;
+
+  *)
+    echo "prerm called with unknown argument \`$1'" >&2
+    exit 1
+  ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/os-prober b/os-prober
index 0373afb..0225f3a 100755
--- a/os-prober
+++ b/os-prober
@@ -168,6 +168,58 @@ for partition in $(partitions); do
 		continue
 	fi
 
+	# Scan btrfs subvol(s)
+	type=$(fs_type $mapped)
+	if [ "$type" = "btrfs" ] && type btrfs >/dev/null 2>&1; then
+		tmpmnt=/var/lib/os-prober/mnt
+		if [ ! -d "$tmpmnt" ]; then
+			mkdir "$tmpmnt"
+		fi
+		# any fs supporting subvol has no fear of multi-mount
+		mount $mapped "$tmpmnt"
+		# 5 is special for btrfs and not listed as a subvol
+		subvols=$(echo 5; btrfs subvolume list "$tmpmnt" | cut -d ' ' -f 2)
+		rosubvols=$(btrfs subvolume list -r "$tmpmnt" | cut -d ' ' -f 2)
+		sssubvols=$(btrfs subvolume list -s "$tmpmnt" | cut -d ' ' -f 2)
+		defaultsv=$(get_default_subvolid "$tmpmnt")
+		umount "$tmpmnt"
+		for subvol in $subvols; do
+			if echo "$rosubvols" | grep -q -x "$subvol"; then
+				continue
+			fi
+			if echo "$sssubvols" | grep -q -x "$subvol"; then
+				continue
+			fi
+			if [ "$defaultsv" = "$subvol" ]; then
+				mount $mapped "$tmpmnt"
+				for test in /usr/lib/os-probes/mounted/*; do
+					if [ -f "$test" ] && [ -x "$test" ]; then
+						debug "running $test on $mapped default subvol "
+						if "$test" "$mapped" "$tmpmnt" "$type"; then
+							debug "os detected by $test"
+							break
+						fi
+					fi
+				done
+				umount "$tmpmnt"
+				continue
+			fi
+			mount -o "subvolid=$subvol" $mapped "$tmpmnt"
+			for test in /usr/lib/os-probes/mounted/*; do
+				if [ -f "$test" ] && [ -x "$test" ]; then
+					debug "running $test on $mapped subvolid $subvol"
+					if "$test" "$mapped" "$tmpmnt" "$type" "$subvol"; then
+						debug "os detected by $test"
+						break
+					fi
+				fi
+			done
+			umount "$tmpmnt"
+		done
+		rmdir "$tmpmnt"
+		continue
+	fi
+
 	if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
 		for test in /usr/lib/os-probes/*; do
 			if [ -f "$test" ] && [ -x "$test" ]; then
diff --git a/os-probes/mounted/common/40lsb b/os-probes/mounted/common/40lsb
index ce8d4e1..da58b8f 100755
--- a/os-probes/mounted/common/40lsb
+++ b/os-probes/mounted/common/40lsb
@@ -7,6 +7,7 @@ set -e
 partition="$1"
 dir="$2"
 type="$3"
+subvolid="$4"
 
 lsb_field () {
 	file="$1"
@@ -44,5 +45,5 @@ if [ -z "$short" ]; then
 fi
 
 label="$(count_next_label "$short")"
-result "$partition:$long:$label:linux"
+result "$partition${subvolid:+@$subvolid}:$long:$label:linux${subvolid:+-subvolid}"
 exit 0
diff --git a/os-probes/mounted/common/90linux-distro b/os-probes/mounted/common/90linux-distro
index badfbb1..adba52d 100755
--- a/os-probes/mounted/common/90linux-distro
+++ b/os-probes/mounted/common/90linux-distro
@@ -7,6 +7,7 @@ set -e
 partition="$1"
 dir="$2"
 type="$3"
+subvolid="$4"
 
 # 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
@@ -143,7 +144,7 @@ if (ls "$dir"/lib*/ld*.so* && [ -d "$dir/boot" ] || ls "$dir"/usr/lib*/ld*.so*)
 	fi
 	
         label="$(count_next_label "$short")"
-	result "$partition:$long:$label:linux"
+	result "$partition${subvolid:+@$subvolid}:$long:$label:linux${subvolid:+-subvolid}"
 	exit 0
 else
 	exit 1
-- 
2.11.0

From 2a411006671ab5add32d5c83b30672e8412cd74b Mon Sep 17 00:00:00 2001
From: Michael Mestnik <cheako+github_com@mikemestnik.net>
Date: Sun, 4 Jun 2017 15:21:54 -0500
Subject: [PATCH 1/4] Squelch btrfs devices with duplicate uuid

Warn if type is not btrfs
---
 os-prober | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/os-prober b/os-prober
index a48863e..0373afb 100755
--- a/os-prober
+++ b/os-prober
@@ -30,6 +30,25 @@ on_sataraid () {
 }
 
 partitions () {
+	_partitions "$@" |
+	while read part; do
+		uuid=$(blkid -o value -s UUID $part)
+		type=$(fs_type $part)
+		if [ "$uuid" ]; then
+			if echo "$vols" | grep -q "$uuid $type"; then
+				if [ "$type" = "btrfs" ]; then
+					continue
+				else
+					warn "Duplicate UUID unexpected on $part"
+				fi
+			fi
+			vols="$vols $uuid $type"
+		fi
+		echo $part
+	done
+}
+
+_partitions () {
 	os_name="$(uname -s)"
 	# Exclude partitions that have whole_disk sysfs attribute set.
 	if [ -d /sys/block ]; then
-- 
2.11.0


Reply to: