Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 17 May 2014 11:58:26 -0400
From:      Allan Jude <freebsd@allanjude.com>
To:        roberto@freebsd.org, freebsd-sysinstall@freebsd.org
Subject:   patch to bsdinstall to support BSD partitions
Message-ID:  <53778722.9000608@allanjude.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------020100060009040503090208
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

On some Lenovo machines, booting ZFS off MBR partitions does not work

On the Lenovo X61s that we were able to test on at the BSDCan Hackers
Lounge, we were able to get them to boot properly using a BSD
partitioning scheme instead.


The attached patch makes the following changes:

Add support for BSD partition type

Moved the write of the MBR boot sector to the end of the process to
avoid it being nuked by the pedantic zpool labelclear commands

Change the MBR code to not always create 2 zpools when using MBR. The
user only wants 2 pools (1 unencrypted to boot, and one encrypted for
data) in the case where they enable encryption. Due to the simplicity of
the code in previous versions of bsdinstall, two pools were used to
avoid a problem with the order of the creation of the partitions to
ensure that there was a partition at the front of the drive for the boot
code, and that the swap partition was the 2nd partition (BSD partition 'b')

Some style cleanup to make the flow of the MBR section more

fix an syntax error introduced in the previous patch where a newline was
not escaped

Write the zfsboot code to the two different places require for MBR and
BSD. Write the larger section first because writing the first sector
first seems to make the BSD partition disappear and appear as an empty
MBR (No idea why this was happening, reproduced on two Lenovo laptops)

Resolve variable reuse by renaming 'disksize' in second card to
'usablesize' to avoid disksize being disksize less swap+boot size

Sponsored By: ScaleEngine Inc.

--------------020100060009040503090208
Content-Type: text/x-patch;
 name="zfsboot.bsd_partition_v2.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="zfsboot.bsd_partition_v2.patch"

Index: usr.sbin/bsdinstall/scripts/zfsboot
===================================================================
--- usr.sbin/bsdinstall/scripts/zfsboot	(revision 266146)
+++ usr.sbin/bsdinstall/scripts/zfsboot	(working copy)
@@ -77,17 +77,17 @@
 
 #
 # Create a separate boot pool?
-# NB: Automatically set when using geli(8) or MBR
+# NB: Automatically set when using geli(8)
 #
 : ${ZFSBOOT_BOOT_POOL=}
 
 #
-# Default name for boot pool when enabled (e.g., geli(8) or MBR)
+# Default name for boot pool when enabled (e.g., geli(8))
 #
 : ${ZFSBOOT_BOOT_POOL_NAME:=bootpool}
 
 #
-# Default size for boot pool when enabled (e.g., geli(8) or MBR)
+# Default size for boot pool when enabled (e.g., geli(8))
 #
 : ${ZFSBOOT_BOOT_POOL_SIZE:=2g}
 
@@ -253,7 +253,7 @@
 msg_null_poolname="NULL poolname"
 msg_ok="OK"
 msg_partition_scheme="Partition Scheme"
-msg_partition_scheme_help="Toggle between GPT and MBR partitioning schemes"
+msg_partition_scheme_help="Toggle between GPT, MBR, and BSD partitioning schemes"
 msg_please_enter_a_name_for_your_zpool="Please enter a name for your zpool:"
 msg_please_enter_amount_of_swap_space="Please enter amount of swap space (SI-Unit suffixes\nrecommended; e.g., \`2g' for 2 Gigabytes):"
 msg_please_select_one_or_more_disks="Please select one or more disks to create a zpool:"
@@ -721,7 +721,7 @@
 
 	# Check for unknown partition scheme before proceeding further
 	case "$ZFSBOOT_PARTITION_SCHEME" in
-	""|MBR|GPT) : known good ;;
+	""|MBR|GPT|BSD) : known good ;;
 	*)
 		f_dprintf "$funcname: %s is an unsupported partition scheme" \
 		          "$ZFSBOOT_PARTITION_SCHEME"
@@ -777,7 +777,7 @@
 		[ ${swapsize:-0} -gt 0 ] && targetpart=p3
 
 		#
-		# Prepare boot pool if enabled (e.g., for geli(8))
+		# 3. Prepare boot pool if enabled (e.g., for geli(8))
 		#
 		if [ "$ZFSBOOT_BOOT_POOL" ]; then
 			bootpart=p2 swappart=p3 targetpart=p3
@@ -798,7 +798,7 @@
 		fi
 
 		#
-		# 3. Add freebsd-swap partition labeled `swap#'
+		# 4. Add freebsd-swap partition labeled `swap#'
 		#
 		if [ ${swapsize:-0} -gt 0 ]; then
 			f_eval_catch $funcname gpart \
@@ -811,7 +811,7 @@
 		fi
 
 		#
-		# 4. Add freebsd-zfs partition labeled `zfs#' for zroot
+		# 5. Add freebsd-zfs partition labeled `zfs#' for zroot
 		#
 		f_eval_catch $funcname gpart "$GPART_ADD_LABEL" \
 		             zfs$index freebsd-zfs $disk || return $FAILURE
@@ -819,6 +819,87 @@
 		                /dev/$disk$targetpart
 		;;
 
+	BSD) f_dprintf "$funcname: Creating BSD layout..."
+		#
+		# 1. Create BSD layout and write boot sector
+		#
+		f_eval_catch $funcname gpart "$GPART_CREATE" bsd $disk ||
+		             return $FAILURE
+
+		bootpart=a swappart=b targetpart=a mbrindex=1
+		#
+		# 2. Prepare boot pool if enabled (e.g., for geli(8))
+		#
+		if [ "$ZFSBOOT_BOOT_POOL" ]; then
+			bootpart=a swappart=b targetpart=d mbrindex=4
+			#
+			# 3. Create an unencrypted boot pool
+			#
+			f_eval_catch $funcname gpart \
+				    "$GPART_ADD_INDEX_WITH_SIZE" 1 \
+				    freebsd-zfs ${bootsize}b $disk ||
+				    return $FAILURE
+			# Pedantically detach bootpart
+			f_eval_catch -d $funcname geli \
+				    "$GELI_DETACH_F" \
+				    /dev/$disk$bootpart
+			# Pedantically nuke any old labels
+			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
+				    /dev/$disk$bootpart
+			#
+			# 4. Add freebsd-swap partition
+			#
+			if [ ${swapsize:-0} -gt 0 ]; then
+				f_eval_catch $funcname gpart \
+					    "$GPART_ADD_INDEX_WITH_SIZE" 2 \
+					    freebsd-swap ${swapsize}b $disk ||
+					    return $FAILURE
+				# Pedantically nuke any old labels on the swap
+				f_eval_catch -d $funcname zpool \
+					    "$ZPOOL_LABELCLEAR_F" \
+					    /dev/$disk$swappart
+			fi
+			#
+			# 5. Add second freebsd-zfs partition for main pool
+			#
+			f_eval_catch $funcname gpart "$GPART_ADD_INDEX" \
+				    $mbrindex freebsd-zfs $disk ||
+				    return $FAILURE
+			# Pedantically detach targetpart
+			f_eval_catch -d $funcname geli \
+				    "$GELI_DETACH_F" \
+				    /dev/$disk$targetpart
+			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
+				    /dev/$disk$targetpart
+		else
+			#
+			# 6. Create and boot off of the main pool
+			#
+			local partsize=$(( $disksize - $swapsize ))
+			f_eval_catch $funcname gpart \
+				    "$GPART_ADD_INDEX_WITH_SIZE" $mbrindex \
+				    freebsd-zfs ${partsize}b $disk ||
+				    return $FAILURE
+			# Pedantically nuke any old labels
+			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
+				    /dev/$disk$bootpart
+			#
+			# 7. There is no partition after this, so autosize swap
+			#
+			if [ ${swapsize:-0} -gt 0 ]; then
+				f_eval_catch $funcname gpart \
+					    "$GPART_ADD_INDEX" 2 \
+					    freebsd-swap $disk ||
+					    return $FAILURE
+				# Pedantically nuke any old labels on the swap
+				f_eval_catch -d $funcname zpool \
+					    "$ZPOOL_LABELCLEAR_F" \
+					    /dev/$disk$swappart
+			fi
+		fi
+
+		;;
+
 	MBR) f_dprintf "$funcname: Creating MBR layout..."
 		#
 		# 1. Create MBR layout (no labels)
@@ -825,8 +906,6 @@
 		#
 		f_eval_catch $funcname gpart "$GPART_CREATE" mbr $disk ||
 		             return $FAILURE
-		f_eval_catch $funcname gpart "$GPART_BOOTCODE" /boot/mbr \
-		             $disk || return $FAILURE
 
 		#
 		# 2. Add freebsd slice with all available space
@@ -847,50 +926,86 @@
 		f_eval_catch $funcname gpart "$GPART_CREATE" BSD ${disk}s1 ||
 		             return $FAILURE
 
-		# NB: zpool will use s1a (no labels)
-		bootpart=s1a swappart=s1b targetpart=s1d mbrindex=4
+		bootpart=s1a swappart=s1b targetpart=s1a mbrindex=1
 
 		#
-		# Always prepare a boot pool on MBR
+		# 4. Prepare boot pool if enabled (e.g., for geli(8))
 		#
-		ZFSBOOT_BOOT_POOL=1
-		f_eval_catch $funcname gpart \
-		             "$GPART_ADD_INDEX_WITH_SIZE" \
-		             1 freebsd-zfs ${bootsize}b ${disk}s1 ||
-		             return $FAILURE
-		# Pedantically nuke any old labels
-		f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
-		                /dev/$disk$bootpart
-		if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
+		if [ "$ZFSBOOT_BOOT_POOL" ]; then
+			bootpart=s1a swappart=s1b targetpart=s1d mbrindex=4
+			#
+			# 5. Create an unencrypted boot pool
+			#
+			f_eval_catch $funcname gpart \
+				    "$GPART_ADD_INDEX_WITH_SIZE" 1 \
+				    freebsd-zfs ${bootsize}b $disk ||
+				    return $FAILURE
+			# Pedantically nuke any old labels
+			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
+				    /dev/$disk$bootpart
 			# Pedantically detach targetpart for later
 			f_eval_catch -d $funcname geli \
-			                "$GELI_DETACH_F" \
-					/dev/$disk$targetpart
-		fi
+				    "$GELI_DETACH_F" \
+				    /dev/$disk$bootpart
+			#
+			# 6. Add freebsd-swap partition
+			#
+			if [ ${swapsize:-0} -gt 0 ]; then
+				f_eval_catch $funcname gpart \
+					    "$GPART_ADD_INDEX_WITH_SIZE" 2 \
+					    freebsd-swap ${swapsize}b \
+					    ${disk}s1 || return $FAILURE
+				# Pedantically nuke any old labels on the swap
+				f_eval_catch -d $funcname zpool \
+					    "$ZPOOL_LABELCLEAR_F" \
+					    /dev/$disk$swappart
+			fi
+			#
+			# 7. Add second freebsd-zfs partition for main pool
+			#
+			f_eval_catch $funcname gpart "$GPART_ADD_INDEX" \
+				     $mbrindex freebsd-zfs ${disk}s1 ||
+				     return $FAILURE
+			# Pedantically detach targetpart
+			f_eval_catch -d $funcname geli \
+				    "$GELI_DETACH_F" \
+				    /dev/$disk$targetpart
+			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
+					/dev/$disk$targetpart # Pedantic
 
-		#
-		# 4. Add freebsd-swap partition
-		#
-		if [ ${swapsize:-0} -gt 0 ]; then
+		else
+			#
+			# 8. Create and boot off of the main pool
+			#
+			local partsize=$(( $disksize - $swapsize ))
 			f_eval_catch $funcname gpart \
-			             "$GPART_ADD_INDEX_WITH_SIZE" 2 \
-			             freebsd-swap ${swapsize}b ${disk}s1 ||
-			             return $FAILURE
-			# Pedantically nuke any old labels on the swap
+				    "$GPART_ADD_INDEX_WITH_SIZE" $mbrindex \
+				    freebsd-zfs ${partsize}b ${disk}s1 ||
+				    return $FAILURE
+			# Pedantically nuke any old labels
 			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
-			                /dev/${disk}s1b
+				    /dev/$disk$bootpart
+			#
+			# 9. There is no partition after this, so autosize swap
+			#
+			if [ ${swapsize:-0} -gt 0 ]; then
+				f_eval_catch $funcname gpart \
+					    "$GPART_ADD_INDEX" 2 \
+					    freebsd-swap ${disk}s1 ||
+					    return $FAILURE
+				# Pedantically nuke any old labels on the swap
+				f_eval_catch -d $funcname zpool \
+					    "$ZPOOL_LABELCLEAR_F" \
+					    /dev/$disk$swappart
+			fi
 		fi
 
 		#
-		# 5. Add freebsd-zfs partition for zroot
+		# 10. Install bootcode
 		#
-		f_eval_catch $funcname gpart "$GPART_ADD_INDEX" \
-			     $mbrindex freebsd-zfs ${disk}s1 || return $FAILURE
-		f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
-				/dev/$disk$targetpart # Pedantic
-		f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
-			     /boot/zfsboot /dev/${disk}s1 count=1 ||
-			     return $FAILURE
+		f_eval_catch $funcname gpart "$GPART_BOOTCODE" /boot/mbr \
+		             $disk || return $FAILURE
+
 		;;
 
 	esac # $ZFSBOOT_PARTITION_SCHEME
@@ -898,6 +1013,7 @@
 	# Update fstab(5)
 	if [ "$isswapmirror" ]; then
 		# This is not the first disk in the mirror, do nothing
+		true
 	elif [ "$ZFSBOOT_SWAP_ENCRYPTION" -a "$ZFSBOOT_SWAP_MIRROR" ]; then
 		f_eval_catch $funcname printf "$PRINTF_FSTAB" \
 		             /dev/mirror/swap.eli none swap sw 0 0 \
@@ -1149,7 +1265,7 @@
 	#
 	f_dprintf "$funcname: Creating root pool..."
 	f_eval_catch $funcname zpool "$ZPOOL_CREATE_WITH_OPTIONS" \
-	             "-o altroot=$BSDINSTALL_CHROOT -O compress=lz4
+	             "-o altroot=$BSDINSTALL_CHROOT -O compress=lz4 \
 	             -m none -f" \
 	             "$zroot_name" "$zroot_vdevtype" "$zroot_vdevs" ||
 	             return $FAILURE
@@ -1230,7 +1346,7 @@
 		fi
 	done
 
-	# MBR boot loader touch-up
+	# write remainder of boot loader for MBR and BSD
 	if [ "$ZFSBOOT_PARTITION_SCHEME" = "MBR" ]; then
 		f_dprintf "$funcname: Updating MBR boot loader on disks..."
 		# Stick the ZFS boot loader in the "convienient hole" after 
@@ -1239,7 +1355,23 @@
 			f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
 			             /boot/zfsboot /dev/$disk$bootpart \
 			             "skip=1 seek=1024" || return $FAILURE
+			f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
+				    /boot/zfsboot /dev/${disk}s1 count=1 ||
+				    return $FAILURE
 		done
+	elif [ "$ZFSBOOT_PARTITION_SCHEME" = "BSD" ]; then
+		f_dprintf "$funcname: Updating BSD boot loader on disks..."
+		# Stick the ZFS boot loader in the "convienient hole" after 
+		# the ZFS internal metadata
+		# Install the first bit last, else odd things happen
+		for disk in $disks; do
+			f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
+			             /boot/zfsboot /dev/$disk$bootpart \
+			             "skip=1 seek=1024" || return $FAILURE
+			f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
+				    /boot/zfsboot /dev/${disk} count=1 ||
+				    return $FAILURE
+		done
 	fi
 
 	# Re-import the ZFS pool(s)
@@ -1426,8 +1558,8 @@
 					$disk $DEVICE_TYPE_DISK device
 				$device get capacity disksize || continue
 				[ ${disksize:-0} -ge 0 ] || disksize=0
-				disksize=$(( $disksize - $minsize ))
-				[ $disksize -lt $minsize ] &&
+				usablesize=$(( $disksize - $minsize ))
+				[ $usablesize -lt $minsize ] &&
 					teeny_disks="$teeny_disks $disk"
 			done
 			if [ "$teeny_disks" ]; then
@@ -1499,9 +1631,11 @@
 		fi
 		;;
 	?" $msg_partition_scheme")
-		# Toggle between GPT and MBR
+		# Toggle between GPT, MBR, and BSD
 		if [ "$ZFSBOOT_PARTITION_SCHEME" = GPT ]; then
 			ZFSBOOT_PARTITION_SCHEME=MBR
+		elif [ "$ZFSBOOT_PARTITION_SCHEME" = MBR ]; then
+			ZFSBOOT_PARTITION_SCHEME=BSD
 		else
 			ZFSBOOT_PARTITION_SCHEME=GPT
 		fi

--------------020100060009040503090208--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?53778722.9000608>