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

Bug#652459: initramfs-tools: [patch] Please support mounting of /usr in the initramfs



On Wed, Dec 28, 2011 at 04:15:41PM +0000, Roger Leigh wrote:
> On Sun, Dec 18, 2011 at 03:38:20AM +0100, Marco d'Itri wrote:
> > On Dec 17, Roger Leigh <rleigh@debian.org> wrote:
> > 
> > > 1) Generation of /etc/fstab in the initramfs, including the rootfs
> > >    and all the filesystems desired to be mounted
> > This is highly suboptimal, because it suddenly makes the initramfs not
> > generic anymore.
> > The initramfs should:
> > - mount / as usual
> > - look at the rootfs fstab
> > - mount /usr using the information from the rootfs fstab
> 
> The attached patch does this.
> 
> Note that the patch isn't complete; it won't mount an LVM VG because
> it lacks the LV activation performed for the root in
> "scripts/local-top/lvm2".  I haven't included this in the patch
> because I'm not sure of the best approach to take here.
> 
> Maybe it would make sense to make the existing scripts a bit more
> generic, to permit setup of devices other than $ROOT?  Maybe if the
> scripts were idempotent, they could be invoked multiple times (once
> per device)?
> 
> I didn't want to do this without discussing it with you, so hope the
> patch is useful as a basis for a complete solution.
> 
> Regarding mounting of /etc; I think this would be useful in a number
> of uncommon situations.  I'll look at (separately) implementing an
> --etc/etc= option similar to the existing root options which would
> permit this to work, and keep the initramfs generic at the same time.
> As for /usr above, having the ability to generically activate devices
> other than $ROOT would also be useful here.

I have worked on improving my original patchset over the last couple
of weeks.  This completely generalises the boot logic so that you
can now mount arbitrary filesystems in the initramfs.  It's all
split up into discrete logical changes so that you can see the
intent of each and easily amend them or elide them as required.

With all the patches applied, /usr will be automatically mounted if
it is present in the /etc/fstab on the rootfs.  This works for both
local and nfs.  I've not tested LVM, but standard UUIDs work fine.
You can also mount /etc so that this can be independently mounted;
obviously this can't use the fstab, so it's done using an equivalent
set of command-line options as for the rootfs.  This is a separate
patch so it can be easily dropped.

If anything is unclear, please just ask.

Changes which might need making: inclusion of modules in the
initramfs needed to mount usr (or etc).

I hope this is all reasonable.


Regards,
Roger

-- 
  .''`.  Roger Leigh
 : :' :  Debian GNU/Linux             http://people.debian.org/~rleigh/
 `. `'   Printing on GNU/Linux?       http://gutenprint.sourceforge.net/
   `-    GPG Public Key: 0x25BFB848   Please GPG sign your mail.
From f1685f82df05215918ff6d7780991ee11fb2d307 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 19:37:13 +0100
Subject: [PATCH 01/12] local: Add local_top, local_premount and local_bottom

---
 scripts/local |   41 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/scripts/local b/scripts/local
index 521e69a..f79a335 100644
--- a/scripts/local
+++ b/scripts/local
@@ -1,11 +1,38 @@
 # Local filesystem mounting			-*- shell-script -*-
 
-pre_mountroot()
+local_top()
 {
-	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top"
-	run_scripts /scripts/local-top
-	[ "$quiet" != "y" ] && log_end_msg
+	if [ "${local_top_used}" != "yes" ]; then
+		[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top"
+		run_scripts /scripts/local-top
+		[ "$quiet" != "y" ] && log_end_msg
+	fi
+	local_top_used=yes
+}
+
+local_premount()
+{
+	if [ "${local_premount_used}" != "yes" ]; then
+		[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
+		run_scripts /scripts/local-premount
+		[ "$quiet" != "y" ] && log_end_msg
+	fi
+	local_premount_used=yes
+}
 
+local_bottom()
+{
+	if [ "${local_premount_used}" = "yes" ] || [ "${local_top_used}" = "yes" ]; then
+		[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
+		run_scripts /scripts/local-bottom
+		[ "$quiet" != "y" ] && log_end_msg
+	fi
+	local_premount_used=no
+	local_top_used=no
+}
+
+pre_mountroot()
+{
 	wait_for_udev 10
 
 	# Load ubi with the correct MTD partition and return since fstype
@@ -76,6 +103,8 @@ pre_mountroot()
 
 mountroot()
 {
+	local_top
+
 	pre_mountroot
 
 	# Get the root filesystem type if not set
@@ -85,9 +114,7 @@ mountroot()
 		FSTYPE=${ROOTFSTYPE}
 	fi
 
-	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
-	run_scripts /scripts/local-premount
-	[ "$quiet" != "y" ] && log_end_msg
+        local_premount
 
 	if [ "${readonly}" = "y" ]; then
 		roflag=-r
-- 
1.7.10.4

From d5ce57e833cf415f32bc27fe84fba5703985cbd0 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 19:40:08 +0100
Subject: [PATCH 02/12] nfs: Add nfs_top, nfs_premount and nfs_bottom

---
 scripts/nfs |   43 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/scripts/nfs b/scripts/nfs
index 6fa0c43..1927b7b 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -4,6 +4,37 @@
 
 retry_nr=0
 
+nfs_top()
+{
+	if [ "${nfs_top_used}" != "yes" ]; then
+		[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-top"
+		run_scripts /scripts/nfs-top
+		[ "$quiet" != "y" ] && log_end_msg
+	fi
+	nfs_top_used=yes
+}
+
+nfs_premount()
+{
+	if [ "${nfs_premount_used}" != "yes" ]; then
+		[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-premount"
+		run_scripts /scripts/nfs-premount
+		[ "$quiet" != "y" ] && log_end_msg
+	fi
+	nfs_premount_used=yes
+}
+
+nfs_bottom()
+{
+	if [ "${nfs_premount_used}" = "yes" ] || [ "${nfs_top_used}" = "yes" ]; then
+		[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-bottom"
+		run_scripts /scripts/nfs-bottom
+		[ "$quiet" != "y" ] && log_end_msg
+	fi
+	nfs_premount_used=no
+	nfs_top_used=no
+}
+
 # parse nfs bootargs and mount nfs
 do_nfsmount()
 {
@@ -35,9 +66,7 @@ do_nfsmount()
 		NFSOPTS="-o retrans=10"
 	fi
 
-	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-premount"
-	run_scripts /scripts/nfs-premount
-	[ "$quiet" != "y" ] && log_end_msg
+	nfs_premount
 
 	if [ ${readonly} = y ]; then
 		roflag="-o ro"
@@ -51,9 +80,7 @@ do_nfsmount()
 # NFS root mounting
 mountroot()
 {
-	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-top"
-	run_scripts /scripts/nfs-top
-	[ "$quiet" != "y" ] && log_end_msg
+	nfs_top
 
 	modprobe nfs
 	# For DHCP
@@ -74,7 +101,5 @@ mountroot()
 		[ "$quiet" != "y" ] && log_end_msg
 	done
 
-	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-bottom"
-	run_scripts /scripts/nfs-bottom
-	[ "$quiet" != "y" ] && log_end_msg
+	nfs_bottom
 }
-- 
1.7.10.4

From 3b187e24a1c6eb3d88a4e8ec4d0c8ffa4ffa287a Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 20:05:12 +0100
Subject: [PATCH 03/12] nfs: Move retry_nr to site of use and rename to
 nfs_retry_count

---
 scripts/nfs |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/scripts/nfs b/scripts/nfs
index 1927b7b..2368aee 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -2,8 +2,6 @@
 
 # FIXME This needs error checking
 
-retry_nr=0
-
 nfs_top()
 {
 	if [ "${nfs_top_used}" != "yes" ]; then
@@ -93,11 +91,12 @@ mountroot()
 
 	# loop until nfsmount succeeds
 	do_nfsmount
-	while [ ${retry_nr} -lt ${delay} ] && [ ! -e ${rootmnt}${init} ]; do
+	nfs_retry_count=0
+	while [ ${nfs_retry_count} -lt ${delay} ] && [ ! -e ${rootmnt}${init} ]; do
 		[ "$quiet" != "y" ] && log_begin_msg "Retrying nfs mount"
 		/bin/sleep 1
 		do_nfsmount
-		retry_nr=$(( ${retry_nr} + 1 ))
+		nfs_retry_count=$(( ${nfs_retry_count} + 1 ))
 		[ "$quiet" != "y" ] && log_end_msg
 	done
 
-- 
1.7.10.4

From 873cafaff905dcce9c3c255589dbfd383beebea4 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 19:32:06 +0100
Subject: [PATCH 04/12] functions: Add read_fstab_entry

Based upon the initscript equivalent.
---
 scripts/functions |   30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/scripts/functions b/scripts/functions
index e150d06..d07cc8b 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -424,3 +424,33 @@ wait_for_udev()
 	command -v udevadm >/dev/null 2>&1 || return 0
 	udevadm settle ${1:+--timeout=$1}
 }
+
+# Find a specific fstab entry
+# $1=mountpoint
+# $2=fstype (optional)
+# returns 0 on success, 1 on failure (not found or no fstab)
+read_fstab_entry() {
+	# Not found by default.
+	found=1
+
+	for file in ${rootmnt}/etc/fstab; do
+		if [ -f "$file" ]; then
+			while read MNT_FSNAME MNT_DIR MNT_TYPE MNT_OPTS MNT_FREQ MNT_PASS MNT_JUNK; do
+				case "$MNT_FSNAME" in
+				  ""|\#*)
+					continue;
+					;;
+				esac
+				if [ "$MNT_DIR" = "$1" ]; then
+					if [ -n "$2" ]; then
+						[ "$MNT_TYPE" = "$2" ] || continue;
+					fi
+					found=0
+					break 2
+				fi
+			done < "$file"
+		fi
+	done
+
+	return $found
+}
-- 
1.7.10.4

From 732878bb95f76285f347717b7dc14e8fe0904e62 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 23:27:02 +0100
Subject: [PATCH 05/12] functions: Add resolve_device function

This is generalising the root-specific functionality in init.
---
 init              |   40 +++++-----------------------------------
 scripts/functions |   40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 35 deletions(-)

diff --git a/init b/init
index cb832ff..c3571d3 100755
--- a/init
+++ b/init
@@ -70,41 +70,11 @@ for x in $(cat /proc/cmdline); do
 		;;
 	root=*)
 		ROOT=${x#root=}
-		case $ROOT in
-		LABEL=*)
-			ROOT="${ROOT#LABEL=}"
-
-			# support any / in LABEL= path (escape to \x2f)
-			case "${ROOT}" in
-			*/*)
-			if command -v sed >/dev/null 2>&1; then
-				ROOT="$(echo ${ROOT} | sed 's,/,\\x2f,g')"
-			else
-				if [ "${ROOT}" != "${ROOT#/}" ]; then
-					ROOT="\x2f${ROOT#/}"
-				fi
-				if [ "${ROOT}" != "${ROOT%/}" ]; then
-					ROOT="${ROOT%/}\x2f"
-				fi
-				IFS='/'
-				newroot=
-				for s in $ROOT; do
-					newroot="${newroot:+${newroot}\\x2f}${s}"
-				done
-				unset IFS
-				ROOT="${newroot}"
-			fi
-			esac
-			ROOT="/dev/disk/by-label/${ROOT}"
-			;;
-		UUID=*)
-			ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"
-			;;
-		/dev/nfs)
-			[ -z "${BOOT}" ] && BOOT=nfs
-			;;
-		esac
-		;;
+		ROOT=$(resolve_device "$ROOT")
+		if [ -z "${BOOT}" ] && [ "$ROOT" = "/dev/nfs" ]; then
+			BOOT=nfs
+		fi
+                ;;
 	rootflags=*)
 		ROOTFLAGS="-o ${x#rootflags=}"
 		;;
diff --git a/scripts/functions b/scripts/functions
index d07cc8b..bd3f427 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -454,3 +454,43 @@ read_fstab_entry() {
 
 	return $found
 }
+
+# Resolve device node from a name.  This expands any LABEL or UUID.
+# $1=name
+# Resolved name is echoed.
+resolve_device() {
+	DEV="$1"
+
+	case $DEV in
+	LABEL=*)
+		DEV="${DEV#LABEL=}"
+
+		# support any / in LABEL= path (escape to \x2f)
+		case "${DEV}" in
+		*/*)
+		if command -v sed >/dev/null 2>&1; then
+			DEV="$(echo ${DEV} | sed 's,/,\\x2f,g')"
+		else
+			if [ "${DEV}" != "${DEV#/}" ]; then
+				DEV="\x2f${DEV#/}"
+			fi
+			if [ "${DEV}" != "${DEV%/}" ]; then
+				DEV="${DEV%/}\x2f"
+			fi
+			IFS='/'
+			newroot=
+			for s in $DEV; do
+				newroot="${newroot:+${newroot}\\x2f}${s}"
+			done
+			unset IFS
+			DEV="${newroot}"
+		fi
+		esac
+		DEV="/dev/disk/by-label/${DEV}"
+		;;
+	UUID=*)
+		DEV="/dev/disk/by-uuid/${DEV#UUID=}"
+		;;
+	esac
+	echo "$DEV"
+}
-- 
1.7.10.4

From 2b20f3b174554c160233a79bfc879c4f0876b6cf Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 23:48:52 +0100
Subject: [PATCH 06/12] Add functions to mount filesystems from /etc/fstab

---
 scripts/functions |   16 ++++++++++++++++
 scripts/local     |   23 +++++++++++++++++++++++
 scripts/nfs       |   39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+)

diff --git a/scripts/functions b/scripts/functions
index bd3f427..44a0a32 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -494,3 +494,19 @@ resolve_device() {
 	esac
 	echo "$DEV"
 }
+
+# Mount a file system.  We parse the information from the fstab.  This
+# should be overridden by any boot script which can mount arbitrary
+# filesystems such as /usr.  This default implementation delegates to
+# local or nfs based upon the filesystem type.
+# $1=mountpoint mount location
+mountfs()
+{
+	type=local
+	read_fstab_entry "$1"
+	if [ "${MNT_TYPE}" = "nfs" ] || [ "${MNT_TYPE}" = "nfs4" ]; then
+		type=nfs
+	fi
+
+	${type}_mount_fs "$1"
+}
diff --git a/scripts/local b/scripts/local
index f79a335..e1da5c7 100644
--- a/scripts/local
+++ b/scripts/local
@@ -137,3 +137,26 @@ mountroot()
 	run_scripts /scripts/local-bottom
 	[ "$quiet" != "y" ] && log_end_msg
 }
+
+local_mount_fs()
+{
+	read_fstab_entry "$1"
+	MNT_FSNAME=$(resolve_device "$MNT_FSNAME")
+
+	local_device_setup "$MNT_FSNAME" "$1"
+
+	local_premount
+
+	if [ "${readonly}" = "y" ]; then
+		roflag=-r
+	else
+		roflag=-w
+	fi
+
+	# FIXME This has no error checking
+	modprobe "${MNT_TYPE}"
+
+	# FIXME This has no error checking
+	# Mount filesystem
+	mount ${roflag} -t "${MNT_TYPE}" -o "${MNT_OPTS}" "$MNT_FSNAME" "${rootmnt}${MNT_DIR}"
+}
diff --git a/scripts/nfs b/scripts/nfs
index 2368aee..37d655d 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -102,3 +102,42 @@ mountroot()
 
 	nfs_bottom
 }
+
+nfs_mount_fs_impl()
+{
+	configure_networking
+
+	if [ -z "${NFSOPTS}" ]; then
+		NFSOPTS="-o retrans=10"
+	fi
+
+	nfs_premount
+
+	if [ ${readonly} = y ]; then
+		roflag="-o ro"
+	else
+		roflag="-o rw"
+	fi
+
+	read_fstab_entry "$1"
+
+	nfsmount ${roflag} ${NFSOPTS} -o "${MNT_OPTS}" "$MNT_FSNAME" "${rootmnt}${MNT_DIR}"
+}
+
+nfs_mount_fs()
+{
+	nfs_top
+
+	modprobe nfs
+	# For DHCP
+	modprobe af_packet
+
+	wait_for_udev 10
+
+	# Default delay is around 180s
+	delay=${ROOTDELAY:-180}
+
+	# Don't loop here; we can't sanely check if it worked like for
+	# the rootfs or /etc.
+	nfs_mount_fs_impl "$1"
+}
-- 
1.7.10.4

From 4d0245817ab1b940e0abba74f57fd29fd52ba21a Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 21:48:24 +0100
Subject: [PATCH 07/12] scripts: Add overridable indirect functions

---
 scripts/functions |   28 ++++++++++++++++++++++++++++
 scripts/local     |   25 ++++++++++++++++++++++++-
 scripts/nfs       |   25 ++++++++++++++++++++++++-
 3 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/scripts/functions b/scripts/functions
index 44a0a32..f3e2eff 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -510,3 +510,31 @@ mountfs()
 
 	${type}_mount_fs "$1"
 }
+
+# Mount the root file system.  It should be overridden by all
+# boot scripts.
+mountroot()
+{
+	:
+}
+
+# Run /scripts/${boot}-top.  This should be overridden by all boot
+# scripts.
+mount_top()
+{
+	:
+}
+
+# Run /scripts/${boot}-premount.  This should be overridden by all boot
+# scripts.
+mount_premount()
+{
+	:
+}
+
+# Run /scripts/${boot}-bottom.  This should be overridden by all boot
+# scripts.
+mount_bottom()
+{
+	:
+}
diff --git a/scripts/local b/scripts/local
index e1da5c7..0c61ca3 100644
--- a/scripts/local
+++ b/scripts/local
@@ -101,7 +101,7 @@ pre_mountroot()
 	done
 }
 
-mountroot()
+local_mount_root()
 {
 	local_top
 
@@ -160,3 +160,26 @@ local_mount_fs()
 	# Mount filesystem
 	mount ${roflag} -t "${MNT_TYPE}" -o "${MNT_OPTS}" "$MNT_FSNAME" "${rootmnt}${MNT_DIR}"
 }
+
+mountroot()
+{
+	local_mount_root
+}
+
+mount_top()
+{
+	# Note, also called directly in case it's overridden.
+	local_top
+}
+
+mount_premount()
+{
+	# Note, also called directly in case it's overridden.
+	local_premount
+}
+
+mount_bottom()
+{
+	# Note, also called directly in case it's overridden.
+	local_bottom
+}
diff --git a/scripts/nfs b/scripts/nfs
index 37d655d..d443455 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -76,7 +76,7 @@ do_nfsmount()
 }
 
 # NFS root mounting
-mountroot()
+nfs_mount_root()
 {
 	nfs_top
 
@@ -141,3 +141,26 @@ nfs_mount_fs()
 	# the rootfs or /etc.
 	nfs_mount_fs_impl "$1"
 }
+
+mountroot()
+{
+	nfs_mount_root
+}
+
+mount_top()
+{
+	# Note, also called directly in case it's overridden.
+	nfs_top
+}
+
+mount_premount()
+{
+	# Note, also called directly in case it's overridden.
+	nfs_premount
+}
+
+mount_bottom()
+{
+	# Note, also called directly in case it's overridden.
+	nfs_bottom
+}
-- 
1.7.10.4

From 2c1257d40cbafeabdcf2192bb730b1508546fbe0 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Fri, 10 May 2013 22:43:00 +0100
Subject: [PATCH 08/12] init: Use generic mount functions, and mount /usr

---
 init        |   17 +++++++++++++++++
 scripts/nfs |    2 --
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/init b/init
index c3571d3..529011d 100755
--- a/init
+++ b/init
@@ -187,12 +187,29 @@ run_scripts /scripts/init-premount
 
 maybe_break mount
 log_begin_msg "Mounting root file system"
+# Always load local and nfs (since these might be needed for /etc or
+# /usr, irrespective of the boot script used to mount the rootfs).
+. /scripts/local
+. /scripts/nfs
 . /scripts/${BOOT}
 parse_numeric ${ROOT}
 maybe_break mountroot
+mount_top
+mount_premount
 mountroot
 log_end_msg
 
+if read_fstab_entry /usr; then
+	log_begin_msg "Mounting /usr file system"
+	mountfs /usr
+	log_end_msg
+fi
+
+# Mount cleanup
+mount_bottom
+nfs_bottom
+local_bottom
+
 maybe_break bottom
 [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"
 run_scripts /scripts/init-bottom
diff --git a/scripts/nfs b/scripts/nfs
index d443455..b27c6dc 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -99,8 +99,6 @@ nfs_mount_root()
 		nfs_retry_count=$(( ${nfs_retry_count} + 1 ))
 		[ "$quiet" != "y" ] && log_end_msg
 	done
-
-	nfs_bottom
 }
 
 nfs_mount_fs_impl()
-- 
1.7.10.4

From 77913d2858de4c8ae2fd20dd2a8d4131868bc554 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 20:01:51 +0100
Subject: [PATCH 09/12] local: Generalise local device setup

---
 scripts/local |   44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/scripts/local b/scripts/local
index 0c61ca3..da80d06 100644
--- a/scripts/local
+++ b/scripts/local
@@ -31,7 +31,9 @@ local_bottom()
 	local_top_used=no
 }
 
-pre_mountroot()
+# $1=device to mount
+# $2=optionname (for root and etc)
+local_device_setup()
 {
 	wait_for_udev 10
 
@@ -44,21 +46,21 @@ pre_mountroot()
 
 	# Don't wait for a root device that doesn't have a corresponding
 	# device in /dev (ie, mtd0)
-	if [ "${ROOT#/dev}" = "${ROOT}" ]; then
+	if [ "${1#/dev}" = "$1" ]; then
 		return
 	fi
 
 	# If the root device hasn't shown up yet, give it a little while
 	# to deal with removable devices
-	if [ ! -e "${ROOT}" ] || ! $(get_fstype "${ROOT}" >/dev/null); then
-		log_begin_msg "Waiting for root file system"
+	if [ ! -e "$1" ] || ! $(get_fstype "$1" >/dev/null); then
+		log_begin_msg "Waiting for $2 file system"
 
 		# Default delay is 30s
 		slumber=${ROOTDELAY:-30}
 
 		slumber=$(( ${slumber} * 10 ))
-		while [ ! -e "${ROOT}" ] \
-		|| ! $(get_fstype "${ROOT}" >/dev/null); do
+		while [ ! -e "$1" ] \
+		|| ! $(get_fstype "$1" >/dev/null); do
 			/bin/sleep 0.1
 			slumber=$(( ${slumber} - 1 ))
 			[ ${slumber} -gt 0 ] || break
@@ -72,40 +74,42 @@ pre_mountroot()
 	fi
 
 	# We've given up, but we'll let the user fix matters if they can
-	while [ ! -e "${ROOT}" ]; do
+	while [ ! -e "$1" ]; do
 		# give hint about renamed root
-		case "${ROOT}" in
+		case "$1" in
 		/dev/hd*)
-			suffix="${ROOT#/dev/hd}"
+			suffix="${1#/dev/hd}"
 			major="${suffix%[[:digit:]]}"
 			major="${major%[[:digit:]]}"
 			if [ -d "/sys/block/sd${major}" ]; then
-				echo "WARNING bootdevice may be renamed. Try root=/dev/sd${suffix}"
+				echo "WARNING bootdevice may be renamed. Try $2=/dev/sd${suffix}"
 			fi
 			;;
 		/dev/sd*)
-			suffix="${ROOT#/dev/sd}"
+			suffix="${1#/dev/sd}"
 			major="${suffix%[[:digit:]]}"
 			major="${major%[[:digit:]]}"
 			if [ -d "/sys/block/hd${major}" ]; then
-				echo "WARNING bootdevice may be renamed. Try root=/dev/hd${suffix}"
+				echo "WARNING bootdevice may be renamed. Try $2=/dev/hd${suffix}"
 			fi
 			;;
 		esac
-		echo "Gave up waiting for root device.  Common problems:"
+		echo "Gave up waiting for $2 device.  Common problems:"
 		echo " - Boot args (cat /proc/cmdline)"
 		echo "   - Check rootdelay= (did the system wait long enough?)"
-		echo "   - Check root= (did the system wait for the right device?)"
+	        # Only applies to root= and etc=:
+		if [ "${2#/}" = "$2" ]; then
+			echo "   - Check $2= (did the system wait for the right device?)"
+		fi
 		echo " - Missing modules (cat /proc/modules; ls /dev)"
-		panic "ALERT!  ${ROOT} does not exist.  Dropping to a shell!"
+		panic "ALERT!  $1 does not exist.  Dropping to a shell!"
 	done
 }
 
 local_mount_root()
 {
 	local_top
-
-	pre_mountroot
+	local_device_setup "${ROOT}" root
 
 	# Get the root filesystem type if not set
 	if [ -z "${ROOTFSTYPE}" ]; then
@@ -114,7 +118,7 @@ local_mount_root()
 		FSTYPE=${ROOTFSTYPE}
 	fi
 
-        local_premount
+	local_premount
 
 	if [ "${readonly}" = "y" ]; then
 		roflag=-r
@@ -132,10 +136,6 @@ local_mount_root()
 	else
 		mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
 	fi
-
-	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
-	run_scripts /scripts/local-bottom
-	[ "$quiet" != "y" ] && log_end_msg
 }
 
 local_mount_fs()
-- 
1.7.10.4

From d22ee084110e88d650c291258ce9fa74502b6811 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 20:08:56 +0100
Subject: [PATCH 10/12] nfs: Rename do_nfsmount to nfs_mount_root_impl

---
 scripts/nfs |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/scripts/nfs b/scripts/nfs
index b27c6dc..7955e00 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -34,9 +34,8 @@ nfs_bottom()
 }
 
 # parse nfs bootargs and mount nfs
-do_nfsmount()
+nfs_mount_root_impl()
 {
-
 	configure_networking
 
 	# get nfs root from dhcp
@@ -90,12 +89,12 @@ nfs_mount_root()
 	delay=${ROOTDELAY:-180}
 
 	# loop until nfsmount succeeds
-	do_nfsmount
+	nfs_mount_root_impl
 	nfs_retry_count=0
 	while [ ${nfs_retry_count} -lt ${delay} ] && [ ! -e ${rootmnt}${init} ]; do
 		[ "$quiet" != "y" ] && log_begin_msg "Retrying nfs mount"
 		/bin/sleep 1
-		do_nfsmount
+		nfs_mount_root_impl
 		nfs_retry_count=$(( ${nfs_retry_count} + 1 ))
 		[ "$quiet" != "y" ] && log_end_msg
 	done
-- 
1.7.10.4

From 6f101687fa9730921111f5dc7a421fa81b2c95c5 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Wed, 8 May 2013 21:01:28 +0100
Subject: [PATCH 11/12] Add support for mounting /etc

This duplicates the logic for mounting the rootfs.
---
 init              |   35 ++++++++++++++++++++++++++++++++
 initramfs-tools.8 |   18 +++++++++++++++++
 scripts/functions |   13 ++++++++++++
 scripts/local     |   31 +++++++++++++++++++++++++++++
 scripts/nfs       |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+)

diff --git a/init b/init
index 529011d..8057f79 100755
--- a/init
+++ b/init
@@ -40,6 +40,10 @@ export ROOT=
 export ROOTDELAY=
 export ROOTFLAGS=
 export ROOTFSTYPE=
+export ETC=
+export ETCDELAY=
+export ETCFLAGS=
+export ETCFSTYPE=
 export IP=
 export BOOT=
 export BOOTIF=
@@ -89,9 +93,30 @@ for x in $(cat /proc/cmdline); do
 			;;
 		esac
 		;;
+	etc=*)
+		ETC=${x#etc=}
+		ETC=$(resolve_device "$ETC")
+                ;;
+	etcflags=*)
+		ETCFLAGS="-o ${x#etcflags=}"
+		;;
+	etcfstype=*)
+		ETCFSTYPE="${x#etcfstype=}"
+		;;
+	etcdelay=*)
+		ETCDELAY="${x#etcdelay=}"
+		case ${ETCDELAY} in
+		*[![:digit:].]*)
+			ETCDELAY=
+			;;
+		esac
+		;;
 	nfsroot=*)
 		NFSROOT="${x#nfsroot=}"
 		;;
+	nfsetc=*)
+		NFSETC="${x#nfsetc=}"
+		;;
 	ip=*)
 		IP="${x#ip=}"
 		;;
@@ -199,6 +224,12 @@ mount_premount
 mountroot
 log_end_msg
 
+if [ -n "${ETC}" ]; then
+	log_begin_msg "Mounting /etc file system"
+	mountetc
+	log_end_msg
+fi
+
 if read_fstab_entry /usr; then
 	log_begin_msg "Mounting /usr file system"
 	mountfs /usr
@@ -289,6 +320,10 @@ unset ROOTFLAGS
 unset ROOTFSTYPE
 unset ROOTDELAY
 unset ROOT
+unset ETCFLAGS
+unset ETCFSTYPE
+unset ETCDELAY
+unset ETC
 unset IP
 unset BOOT
 unset BOOTIF
diff --git a/initramfs-tools.8 b/initramfs-tools.8
index 375e5c1..9dd20ce 100644
--- a/initramfs-tools.8
+++ b/initramfs-tools.8
@@ -42,6 +42,24 @@ The default is 180 seconds.
 set the file system mount option string.
 
 .TP
+\fB\fI etc= "<path to blockdevice>"
+the device node to mount as the etc file system.
+The recommended usage is to specify the UUID as followed "etc=UUID=xxx".
+
+.TP
+\fB\fI etcfstype
+set the etc file system type.
+
+.TP
+\fB\fI etcdelay
+set delay in seconds. Determines how long mountetc waits for etc to appear.
+The default is 180 seconds.
+
+.TP
+\fB\fI etcflags
+set the file system mount option string.
+
+.TP
 \fB\fI nfsroot
 can be either "auto" to try to get the relevant information from DHCP or a
 string of the form NFSSERVER:NFSPATH or NFSSERVER:NFSPATH:NFSOPTS.
diff --git a/scripts/functions b/scripts/functions
index f3e2eff..6354573 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -518,6 +518,19 @@ mountroot()
 	:
 }
 
+# Mount the etc file system.    It should be overridden by any
+# boot script which can mount /etc.
+# Mount the etc file system.
+mountetc()
+{
+	type=local
+	if [ "$ETC" = "/dev/nfs" ]; then
+		type=nfs
+	fi
+
+	${type}_mount_etc
+}
+
 # Run /scripts/${boot}-top.  This should be overridden by all boot
 # scripts.
 mount_top()
diff --git a/scripts/local b/scripts/local
index da80d06..3299232 100644
--- a/scripts/local
+++ b/scripts/local
@@ -138,6 +138,37 @@ local_mount_root()
 	fi
 }
 
+local_mount_etc()
+{
+	local_device_setup "${ETC}" etc
+
+	# Get the etc filesystem type if not set
+	if [ -z "${ETCFSTYPE}" ]; then
+		FSTYPE=$(get_fstype "${ETC}")
+	else
+		FSTYPE=${ETCFSTYPE}
+	fi
+
+	local_premount
+
+	if [ "${readonly}" = "y" ]; then
+		roflag=-r
+	else
+		roflag=-w
+	fi
+
+	# FIXME This has no error checking
+	modprobe ${FSTYPE}
+
+	# FIXME This has no error checking
+	# Mount etc
+	if [ "${FSTYPE}" != "unknown" ]; then
+		mount ${roflag} -t ${FSTYPE} ${ETCFLAGS} ${ETC} ${rootmnt}/etc
+	else
+		mount ${roflag} ${ETCFLAGS} ${ETC} ${rootmnt}/etc
+	fi
+}
+
 local_mount_fs()
 {
 	read_fstab_entry "$1"
diff --git a/scripts/nfs b/scripts/nfs
index 7955e00..ba3b108 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -100,6 +100,63 @@ nfs_mount_root()
 	done
 }
 
+# parse nfs bootargs and mount nfs
+nfs_mount_etc_impl()
+{
+	configure_networking
+
+	if [ -n "${NFSETC}" ]; then
+		# nfs options are an optional arg
+		if [ "${NFSETC#*,}" != "${NFSETC}" ]; then
+			NFSOPTS="-o ${NFSETC#*,}"
+		fi
+		NFSETC=${NFSETC%%,*}
+		if [ "${NFSETC#*:}" = "$NFSETC" ]; then
+			NFSETC=${ETCSERVER}:${NFSETC}
+		fi
+	fi
+
+	if [ -z "${NFSOPTS}" ]; then
+		NFSOPTS="-o retrans=10"
+	fi
+
+	nfs_premount
+
+	if [ ${readonly} = y ]; then
+		roflag="-o ro"
+	else
+		roflag="-o rw"
+	fi
+
+	nfsmount -o nolock ${roflag} ${NFSOPTS} ${NFSETC} ${rootmnt}/etc
+}
+
+# NFS etc mounting
+nfs_mount_etc()
+{
+	nfs_top
+
+	modprobe nfs
+	# For DHCP
+	modprobe af_packet
+
+	wait_for_udev 10
+
+	# Default delay is around 180s
+	delay=${ETCDELAY:-180}
+
+	# loop until nfsmount succeeds
+	nfs_mount_etc_impl
+	retry_nr=0
+	while [ ${retry_nr} -lt ${delay} ] && [ ! -e ${rootmnt}/etc/fstab ]; do
+		[ "$quiet" != "y" ] && log_begin_msg "Retrying nfs mount"
+		/bin/sleep 1
+		nfs_mount_etc_impl
+		retry_nr=$(( ${retry_nr} + 1 ))
+		[ "$quiet" != "y" ] && log_end_msg
+	done
+}
+
 nfs_mount_fs_impl()
 {
 	configure_networking
-- 
1.7.10.4

From cdac7a367cbae508ba4b71a0c1d7e10baa7dfbf1 Mon Sep 17 00:00:00 2001
From: Roger Leigh <Roger Leigh rleigh@debian.org>
Date: Sat, 11 May 2013 19:50:57 +0100
Subject: [PATCH 12/12] debian: Document /usr and /etc mount changes and close
 #652459

---
 debian/changelog |   33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index b75596c..df01f9d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,36 @@
+initramfs-tools (0.112+usrmount1) UNRELEASED; urgency=low
+
+  [ Roger Leigh ]
+  * Generalise logic used for mounting the rootfs:
+    - The existing logic was only intended for mounting the root
+      filesystem; this logic has been refactored to support the
+      mounting of multiple filesystems
+    - Add a read_fstab_entry function to parse /etc/fstab on the
+      mounted rootfs
+    - Add resolve_device function which generalises the existing
+      support for resolving LABEL= and UUID= strings to the
+      corresponding device node
+    - Add general mount_top, mount_premount and mount_bottom functions,
+      with boot-script-specific variants for the local and nfs scripts;
+      other boot scripts should override them if needed; the local and
+      nfs scripts show how to use these to redirect to a specific
+      implementation
+    - Add general mountfs function to mount a filesystem from the
+      /etc/fstab on the mounted rootfs.  This works for both local and
+      nfs mounts; other boot scripts may override it to provide more
+      specialised functionality
+    - Add general mountetc function to mount /etc; this works for both
+      local and nfs /etc; other boot scripts may override it to provide
+      more specialised functionality
+    - The local and nfs bottom scripts are run on demand if used; this
+      does not interfere with alternative boot scripts being used,
+      which will run first
+  * Mount /usr if present in the /etc/fstab on the mounted rootfs
+    (Closes: #652459)
+  * Mount /etc if specified on the kernel command-line
+
+ -- Roger Leigh <rleigh@debian.org>  Sat, 11 May 2013 19:35:04 +0100
+
 initramfs-tools (0.112) unstable; urgency=low
 
   * Add myself to Uploaders
-- 
1.7.10.4

Attachment: signature.asc
Description: Digital signature


Reply to: