Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Aug 2010 13:30:23 +0200 (CEST)
From:      Thomas Quinot <thomas@cuivre.fr.eu.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/149803: [patch] loader: set vfs.mount.rootfrom using label
Message-ID:  <20100819113024.13E835197@melamine.cuivre.fr.eu.org>
Resent-Message-ID: <201008191140.o7JBe1IF046386@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         149803
>Category:       kern
>Synopsis:       [patch] loader: set vfs.mount.rootfrom using label
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Aug 19 11:40:00 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Thomas Quinot
>Release:        FreeBSD 8.0-STABLE amd64
>Organization:
>Environment:
System: FreeBSD melamine.cuivre.fr.eu.org 8.0-STABLE FreeBSD 8.0-STABLE #0: Sun Mar 28 14:46:11 CEST 2010 thomas@melamine.cuivre.fr.eu.org:/usr/obj/usr/src/sys/GENERIC amd64


	
>Description:
	The loader code that sets vfs.root.mountfrom currently requires /etc/fstab
	on the root filesystem to contain an appropriate device name. This proposed
	change provides an alternative way of passing the root device from
	loader to kernel, namely by relying on a volume label (in the geom_label
	sense) found on the candidate root device. This allows the root filesystem
	to be mounted even in the absence of a /etc/fstab entry for it if it
	has a supported label (UFS label, UFS unique id, ext2fs label, ISO 9660
	volume name...) It could conceivably be extended to also include support
	for GPT partition labels.

	A typical use case for this feature is a nanoBSD setup with two possible
	boot slices. With this change, you do not need to have a different /etc/fstab
	on the two slices, you can select one slice at boot and the kernel will
	know to mount it using its UFS id.

	The new code is activated when either there's no entry for / in /etc/fstab,
	or when there's one mentioning the special name "/dev/rootdev". I have also
	included a trivial rc.d patch that creates /dev/rootdev as a symlink at boot,
	for consistency.

>How-To-Repeat:
	
>Fix:

Index: etc/rc.d/root
===================================================================
--- etc/rc.d/root	(révision 200035)
+++ etc/rc.d/root	(copie de travail)
@@ -36,6 +36,16 @@
 	if [ -x /sbin/nextboot ]; then
 		/sbin/nextboot -D > /dev/null 2>&1
 	fi
+
+	# Create rootdev link
+	rootmnt=`kenv vfs.root.mountfrom`
+	rootdev=${rootmnt#*:}
+	(
+	cd /dev
+	if [ -e "${rootdev}" ]; then
+		ln -s ${rootdev} rootdev
+	fi
+	)
 }
 
 load_rc_config $name
Index: lib/libstand/ioctl.c
===================================================================
--- lib/libstand/ioctl.c	(révision 200035)
+++ lib/libstand/ioctl.c	(copie de travail)
@@ -64,6 +64,7 @@
 __FBSDID("$FreeBSD$");
 
 #include "stand.h"
+#include "saioctl.h"
 
 int
 ioctl(fd, cmd, arg)
@@ -77,12 +78,31 @@
 		errno = EBADF;
 		return (-1);
 	}
-	if (f->f_flags & F_RAW) {
-		errno = (f->f_dev->dv_ioctl)(f, cmd, arg);
-		if (errno)
-			return (-1);
-		return (0);
+	switch (SAIO_LAYER(cmd)) {
+		case SAIO_DEV:
+			if (f->f_flags & F_RAW)
+				errno = (f->f_dev->dv_ioctl)(f, cmd, arg);
+			else
+				errno = EIO;
+			break;
+		case SAIO_FS:
+			switch (cmd) {
+				case SAIOGFSTYPE:
+					*(const char **)arg = f->f_ops->fs_name;
+					errno = 0;
+					break;
+				case SAIOGFSLABEL:
+					*(const char **)arg = f->f_labeldev;
+					errno = 0;
+					break;
+				default:
+					errno = EINVAL;
+			}
+			break;
+		default:
+			errno = EINVAL;
 	}
-	errno = EIO;
-	return (-1);
+	if (errno)
+		return (-1);
+	return (0);
 }
Index: lib/libstand/ext2fs.c
===================================================================
--- lib/libstand/ext2fs.c	(révision 200035)
+++ lib/libstand/ext2fs.c	(copie de travail)
@@ -386,6 +386,11 @@
 	fs->fs_ipb = fs->fs_bsize / fs->fs_isize;
 	fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1;
 
+	if (fs->fs_fd.fd_volname[0] != '\0') {
+		sprintf(namebuf, "/dev/ext2fs/%s", fs->fs_fd.fd_volname);
+		f->f_labeldev = strdup(namebuf);
+	}
+
 	/*
 	 * we have to load in the "group descriptors" here
 	 */
@@ -794,6 +799,10 @@
 	struct file *fp = (struct file *)f->f_fsdata;
 	int level;
 
+	if (f->f_labeldev != NULL) {
+		free(f->f_labeldev);
+		f->f_labeldev = NULL;
+	}
 	f->f_fsdata = (void *)0;
 	if (fp == (struct file *)0)
 		return (0);
Index: lib/libstand/Makefile
===================================================================
--- lib/libstand/Makefile	(révision 200035)
+++ lib/libstand/Makefile	(copie de travail)
@@ -12,7 +12,7 @@
 LIB=		stand
 NO_PROFILE=
 NO_PIC=
-INCS=		stand.h
+INCS=		stand.h saioctl.h
 MAN=		libstand.3
 
 CFLAGS+= -ffreestanding -Wformat
Index: lib/libstand/ufs.c
===================================================================
--- lib/libstand/ufs.c	(révision 200035)
+++ lib/libstand/ufs.c	(copie de travail)
@@ -538,6 +538,15 @@
 		goto out;
 	}
 	/*
+	 * Find a unique device name.
+	 */
+	if (fs->fs_volname[0] != '\0') {
+		sprintf (namebuf, "/dev/ufs/%s", fs->fs_volname);
+	} else {
+		sprintf (namebuf, "/dev/ufsid/%08x%08x", fs->fs_id[0], fs->fs_id[1]);
+	}
+	f->f_labeldev = strdup(namebuf);
+	/*
 	 * Calculate indirect block levels.
 	 */
 	{
@@ -711,6 +720,8 @@
 	if (fp->f_buf)
 		free(fp->f_buf);
 	free(fp->f_fs);
+	free(f->f_labeldev);
+	f->f_labeldev = NULL;
 	free(fp);
 	return (0);
 }
Index: lib/libstand/open.c
===================================================================
--- lib/libstand/open.c	(révision 200035)
+++ lib/libstand/open.c	(copie de travail)
@@ -123,7 +123,6 @@
 
 	error = ((*file_system[i]).fo_open)(file, f);
 	if (error == 0) {
-	    
 	    f->f_ops = file_system[i];
 	    o_rainit(f);
 	    return (fd);
Index: lib/libstand/saioctl.h
===================================================================
--- lib/libstand/saioctl.h	(révision 200035)
+++ lib/libstand/saioctl.h	(copie de travail)
@@ -33,18 +33,30 @@
  * $FreeBSD$
  */
 
-/* ioctl's -- for disks just now */
-#define	SAIOHDR		(('d'<<8)|1)	/* next i/o includes header */
-#define	SAIOCHECK	(('d'<<8)|2)	/* next i/o checks data */
-#define	SAIOHCHECK	(('d'<<8)|3)	/* next i/o checks header & data */
-#define	SAIONOBAD	(('d'<<8)|4)	/* inhibit bad sector forwarding */
-#define	SAIODOBAD	(('d'<<8)|5)	/* enable bad sector forwarding */
-#define	SAIOECCLIM	(('d'<<8)|6)	/* set limit to ecc correction, bits */
-#define	SAIOECCUNL	(('d'<<8)|7)	/* use standard ecc procedures */
-#define	SAIORETRIES	(('d'<<8)|8)	/* set retry count for unit */
-#define	SAIODEVDATA	(('d'<<8)|9)	/* get pointer to pack label */
-#define	SAIOSSI		(('d'<<8)|10)	/* set skip sector inhibit */
-#define	SAIONOSSI	(('d'<<8)|11)	/* inhibit skip sector handling */
-#define	SAIOSSDEV	(('d'<<8)|12)	/* is device skip sector type? */
-#define	SAIODEBUG	(('d'<<8)|13)	/* enable/disable debugging */
-#define	SAIOGBADINFO	(('d'<<8)|14)	/* get bad-sector table */
+/* ioctl's */
+
+#define SAIO_LAYER(cmd) (cmd & 0xf0000000)
+#define SAIO_DEV (0 << 28)
+#define SAIO_FS  (1 << 28)
+
+/* DEV layer */
+
+#define	SAIOHDR		(SAIO_DEV|('d'<<8)|1)	/* next i/o includes header */
+#define	SAIOCHECK	(SAIO_DEV|('d'<<8)|2)	/* next i/o checks data */
+#define	SAIOHCHECK	(SAIO_DEV|('d'<<8)|3)	/* next i/o checks header & data */
+#define	SAIONOBAD	(SAIO_DEV|('d'<<8)|4)	/* inhibit bad sector forwarding */
+#define	SAIODOBAD	(SAIO_DEV|('d'<<8)|5)	/* enable bad sector forwarding */
+#define	SAIOECCLIM	(SAIO_DEV|('d'<<8)|6)	/* set limit to ecc correction, bits */
+#define	SAIOECCUNL	(SAIO_DEV|('d'<<8)|7)	/* use standard ecc procedures */
+#define	SAIORETRIES	(SAIO_DEV|('d'<<8)|8)	/* set retry count for unit */
+#define	SAIODEVDATA	(SAIO_DEV|('d'<<8)|9)	/* get pointer to pack label */
+#define	SAIOSSI		(SAIO_DEV|('d'<<8)|10)	/* set skip sector inhibit */
+#define	SAIONOSSI	(SAIO_DEV|('d'<<8)|11)	/* inhibit skip sector handling */
+#define	SAIOSSDEV	(SAIO_DEV|('d'<<8)|12)	/* is device skip sector type? */
+#define	SAIODEBUG	(SAIO_DEV|('d'<<8)|13)	/* enable/disable debugging */
+#define	SAIOGBADINFO	(SAIO_DEV|('d'<<8)|14)	/* get bad-sector table */
+
+/* FS layer */
+
+#define SAIOGFSTYPE	(SAIO_FS|('f'<<8)|1)	/* get file system type */
+#define SAIOGFSLABEL	(SAIO_FS|('f'<<8)|2)	/* get unique device name */
Index: lib/libstand/cd9660.c
===================================================================
--- lib/libstand/cd9660.c	(révision 200035)
+++ lib/libstand/cd9660.c	(copie de travail)
@@ -276,6 +276,7 @@
 	struct iso_directory_record rec;
 	struct iso_directory_record *dp = 0;
 	int rc, first, use_rrip, lenskip;
+	char labelbuf[64];
 
 	/* First find the volume descriptor */
 	buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE);
@@ -301,6 +302,9 @@
 	if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
 		goto out;
 
+	sprintf(labelbuf, "/dev/iso9660/%s", vd->volume_id);
+	f->f_labeldev = strdup(labelbuf);
+
 	rec = *(struct iso_directory_record *) vd->root_directory_record;
 	if (*path == '/') path++; /* eat leading '/' */
 
@@ -410,6 +414,8 @@
 {
 	struct file *fp = (struct file *)f->f_fsdata;
 
+	free(f->f_labeldev);
+	f->f_labeldev = NULL;
 	f->f_fsdata = 0;
 	free(fp);
 
Index: lib/libstand/stand.h
===================================================================
--- lib/libstand/stand.h	(révision 200035)
+++ lib/libstand/stand.h	(copie de travail)
@@ -164,6 +164,7 @@
     char		*f_rabuf;	/* readahead buffer pointer */
     size_t		f_ralen;	/* valid data in readahead buffer */
     off_t		f_raoffset;	/* consumer offset in readahead buffer */
+    char		*f_labeldev;	/* unique device name for this file system */
 #define SOPEN_RASIZE	512
 };
 
Index: sys/boot/common/boot.c
===================================================================
--- sys/boot/common/boot.c	(révision 200035)
+++ sys/boot/common/boot.c	(copie de travail)
@@ -32,6 +32,8 @@
  */
 
 #include <stand.h>
+#include <sys/ioctl.h>
+#include <saioctl.h>
 #include <string.h>
 
 #include "bootstrap.h"
@@ -361,11 +363,18 @@
 		cp++;
 	*cp = 0;
 	options = strdup(ep);
-	/* Build the <fstype>:<device> and save it in vfs.root.mountfrom */
-	sprintf(lbuf, "%s:%s", fstyp, dev);
+
+	/* Build the <fstype>:<device> and save it in vfs.root.mountfrom,
+	 * except if dev is special value "/dev/rootdev", in which case
+	 * we rely to the value determined below to provide the proper
+	 * device name.
+	 */
+	if (strcmp (dev, "/dev/rootdev")) {
+		sprintf(lbuf, "%s:%s", fstyp, dev);
+		setenv("vfs.root.mountfrom", lbuf, 0);
+	}
 	free(dev);
 	free(fstyp);
-	setenv("vfs.root.mountfrom", lbuf, 0);
 
 	/* Don't override vfs.root.mountfrom.options if it is already set */
 	if (getenv("vfs.root.mountfrom.options") == NULL) {
@@ -376,6 +385,18 @@
 	error = 0;
 	break;
     }
+
+    if (getenv("vfs.root.mountfrom") == NULL) {
+	/* Try to get device name from on-disk label */
+	if (ioctl(fd, SAIOGFSTYPE, &fstyp) == 0 &&
+	    ioctl(fd, SAIOGFSLABEL, &dev)  == 0)
+	{
+		sprintf(lbuf, "%s:%s", fstyp, dev);
+		setenv("vfs.root.mountfrom", lbuf, 0);
+		error = 0;
+	}
+    }
+
     close(fd);
     return(error);
 }
	


>Release-Note:
>Audit-Trail:
>Unformatted:



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