Subject: port-next68k/11938: NeXT disklabel support
To: None <gnats-bugs@gnats.netbsd.org>
From: None <perseant@hhhh.org>
List: netbsd-bugs
Date: 01/11/2001 14:24:18
>Number:         11938
>Category:       port-next68k
>Synopsis:       NeXT disklabel compatibility support
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    port-next68k-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Thu Jan 11 14:24:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        20010111
>Organization:
------------------------------------------------------------------------
Konrad Schroder          http://www.hitl.washington.edu/people/perseant/
Information Tech & Services   Box 352142 -or- 215 Fluke Hall, Mason Road
Human Interface Technology Lab                  University of Washington
Voice: 206.616.1478   FAX: 206.543.5380          Seattle, WA, 98195, USA
>Environment:
	
System: NetBSD previous.hitl.washington.edu 1.5O NetBSD 1.5O (PREVIOUS) #24: Wed Jan 10 18:34:24 PST 2001 perseant@hammer:/usr/src/sys/arch/next68k/compile/PREVIOUS next68k


>Description:
	The NeXT disklabel code does not currently support reading from a
	NextStep-generated disklabel.  I've stolen the Ultrix compatibility
	code and modified it to the point that (with a trivial tweak to ffs)
	I can mount a NeXT "4.3BSD" ffs from disk.
>How-To-Repeat:
	disklabel sd0
>Fix:

I'm including the ffs patch for completeness, but it's not really something
that is suitable to go into the tree IMO.  (My disk has 512-sectors for real,
but NeXTstep thinks they are 1k sectors, so fs_fsbtodb = 0 instead of 1.
I don't think this is typical.)  I think that the disklabel patch is okay,
assuming that it dtrt for 1k sector disks, which I haven't tested.

Index: next68k/disksubr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/next68k/next68k/disksubr.c,v
retrieving revision 1.5
diff -u -r1.5 disksubr.c
--- next68k/disksubr.c	2000/11/20 08:24:19	1.5
+++ next68k/disksubr.c	2001/01/11 22:05:01
@@ -40,13 +40,22 @@
  *	@(#)ufs_disksubr.c	8.5 (Berkeley) 1/21/94
  */
 
+/* #include "opt_compat_nextstep.h" */
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/buf.h>
+#include <sys/disk.h>
 #include <sys/disklabel.h>
 #include <sys/syslog.h>
 
-#include <sys/disk.h>
+#ifdef COMPAT_NEXTSTEP
+# include <ufs/ufs/dinode.h> /* XXX for fs.h */
+# include <ufs/ffs/fs.h>     /* XXX for SBSIZE */
+
+char	*compat_label __P((dev_t dev, void (*strat) __P((struct buf *bp)),
+	    struct disklabel *lp, struct cpu_disklabel *osdep));
+#endif
 
 #define	b_cylinder	b_resid
 
@@ -101,8 +110,137 @@
 		}
 	}
 	brelse(bp);
+#ifdef COMPAT_NEXTSTEP
+	/*
+	 * If no NetBSD label was found, check for a NextStep label and
+	 * construct tne incore label from the NextStep partition information.
+	 */
+	if (msg != NULL) {
+		msg = compat_label(dev, strat, lp, osdep);
+		if (msg == NULL) {
+			printf("WARNING: using NextStep partition information\n");
+			/* set geometry? */
+		}
+	}
+#endif
+	/* XXX If no label of either type found, generate default label here */
+	return (msg);
+}
+
+#ifdef COMPAT_NEXTSTEP
+/*
+ * Given a buffer bp, try and interpret it as an NextStep disk label,
+ * putting the partition info into a native NetBSD label
+ */
+char *
+compat_label(dev, strat, lp, osdep)
+	dev_t dev;
+	void (*strat) __P((struct buf *bp));
+	struct disklabel *lp;
+	struct cpu_disklabel *osdep;
+{
+	struct cpu_disklabel *cdlp;
+	struct cpu_partition *cpp;
+	struct buf *bp = NULL;
+	char *msg = NULL;
+	int part;
+	int msec;
+
+	bp = geteblk((int)LABELSIZE);
+	bp->b_dev = dev;
+	bp->b_blkno = LABELSECTOR;
+	bp->b_bcount = LABELSIZE;
+	bp->b_flags |= B_READ;
+	bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
+	(*strat)(bp);
+
+	if (biowait(bp)) {
+                msg = "I/O error";
+		goto done;
+	}
+
+	cdlp = (struct cpu_disklabel *)bp->b_data;
+	if (IS_DISKLABEL(cdlp)) {
+		/* XXX KS - check the cksum here */
+#ifdef DEBUG
+		printf("Interpreting NextStep label\n");
+#endif
+		lp->d_magic = cdlp->cd_version;
+		lp->d_npartitions = 0;
+
+#if notyet
+		/* XXX not really, until 1k sectors are really supported */
+		/* XXX and then presumably the disk driver will fix for us */
+		if (cdlp->cd_secsize > lp->d_secsize) {
+			msec = cdlp->cd_secsize / lp->d_secsize;
+			lp->d_secsize = cdlp->cd_secsize;
+			lp->d_nsectors /= msec;
+			lp->d_secpercyl /= msec;
+			lp->d_secperunit /= msec;
+		} else if (cdlp->cd_secsize < lp->d_secsize) {
+			msec = lp->d_secsize / cdlp->cd_secsize;
+			lp->d_secsize = cdlp->cd_secsize;
+			lp->d_nsectors *= msec;
+			lp->d_secpercyl *= msec;
+			lp->d_secperunit *= msec;
+		}
+		msec = 1;
+#else
+		msec = cdlp->cd_secsize / lp->d_secsize;
+#endif
+		/* strncpy(lp->d_packname, cdlp->cd_label, 16); */
+		strncpy(lp->d_packname, "NextStep label", 16);
+		lp->d_rpm = cdlp->cd_rpm;
+		lp->d_interleave = 1;
+		lp->d_flags = 0;
+		lp->d_bbsize = LABELSIZE;
+		lp->d_sbsize = SBSIZE; /* XXX KS */
+		for (part = 0; part < MAXPARTITIONS; part++) {
+			cpp = cdlp->cd_partitions + part;
+			if (cpp->cp_size >= 0 && cpp->cp_offset >= 0) {
+				/* XXX is this the correct use of cd_front? */
+				if (part != RAW_PART && cpp->cp_offset == 0) {
+					cpp->cp_offset = cdlp->cd_front;
+					cpp->cp_size -= cdlp->cd_front;
+				}
+				lp->d_partitions[part].p_size = cpp->cp_size * msec;
+				lp->d_partitions[part].p_offset = cpp->cp_offset * msec;
+				lp->d_partitions[part].p_fsize = cpp->cp_fsize;
+				lp->d_partitions[part].p_frag = cpp->cp_bsize /
+					cpp->cp_fsize;
+				lp->d_partitions[part].p_cpg = cpp->cp_cpg;
+				lp->d_partitions[part].p_fstype =
+					(strncmp(cpp->cp_type, "4.3BSD", 7) == 0) ? FS_BSDFFS : FS_UNUSED;
+#ifdef DEBUG
+				if (cpp->cp_type[0] &&
+				    lp->d_partitions[part].p_fstype == FS_UNUSED)
+					printf(" Interpreting type \"%.9s\" as \"unused\"\n",
+					       cpp->cp_type);
+#endif					
+			} else if (part == RAW_PART) {
+				/* If RAW_PART was empty, make one up */
+				lp->d_partitions[part].p_offset = 0;
+				lp->d_partitions[part].p_size = lp->d_secperunit;
+				lp->d_partitions[part].p_fstype = FS_UNUSED;
+			}
+			lp->d_npartitions++;
+
+#ifdef DEBUG
+			printf(" NextStep label sd%d%c: start %d len %d\n",
+			       DISKUNIT(dev), "abcdefgh"[part],
+			       lp->d_partitions[part].p_offset,
+			       lp->d_partitions[part].p_size);
+#endif
+		}
+	} else {
+		printf("label: %x\n", cdlp->cd_version);
+		msg = ((msg != NULL) ? msg: "no disk label");
+	}
+done:
+	brelse(bp);
 	return (msg);
 }
+#endif /* COMPAT_NEXTSTEP */
 
 /*
  * Check new disk label for sensibility before setting it.
Index: include/disklabel.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/next68k/include/disklabel.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 disklabel.h
--- include/disklabel.h	1998/06/09 07:53:05	1.1.1.1
+++ include/disklabel.h	2001/01/11 22:05:02
@@ -55,46 +55,47 @@
 
 /* The disklabel the way it is on the disk */
 struct cpu_disklabel {
-    int cd_version;		/* label version */
-    int cd_label_blkno;         /* block # of this label */
-    int cd_size;                /* size of media area (sectors) */
-    char cd_label[CPULBLLEN];	/* disk name (label) */
-    u_int cd_flags;		/* flags */
+    int cd_version;		/* 0: label version */
+    int cd_label_blkno;         /* 4: block # of this label */
+    int cd_size;                /* 8: size of media area (sectors) */
+    char cd_label[CPULBLLEN];	/* 12: disk name (label) */
+    u_int cd_flags;		/* 36: flags */
 #define CD_UNINIT	0x80000000 /* label is uninitialized */
-    u_int cd_tag;		/* volume tag */
-    char cd_name[MAXDNMLEN];	/* drive (hardware) name */
-    char cd_type[MAXTYPLEN];	/* drive type */
-    int cd_secsize;		/* # of bytes per sector */
-    int cd_ntracks;		/* # of tracks per cylinder */
-    int cd_nsectors;		/* # of data sectors per track */
-    int cd_ncylinders;          /* # of data cylinders per unit */
-    int cd_rpm;                 /* rotational speed */
-    short cd_front;		/* # of sectors in "front porch" */
-    short cd_back;		/* # of sectors in "back porch" */
-    short cd_ngroups;		/* # of alt groups */
-    short cd_ag_size;		/* alt group size (sectors) */
-    short cd_ag_alts;		/* alternate sectors / alt group */
-    short cd_ag_off;		/* sector offset to first alternate */
-    int cd_boot_blkno[2];	/* boot program locations */
-    char cd_kernel[MAXBFLEN];	/* default kernel name */
-    char cd_hostname[MAXHNLEN];	/* host name (usu. where disk was labeled) */
-    char cd_rootpartition;	/* root partition letter e.g. 'a' */
-    char cd_rwpartition;	/* r/w partition letter e.g. 'b' */
-    struct  cpu_partition {
-	int cp_offset;		/* starting sector */
-	int cp_size;		/* number of sectors in partition */
-	short cp_bsize;		/* block size in bytes */
-	short cp_fsize;		/* filesystem basic fragment size */
-	char cp_opt;		/* optimization type: 's'pace/'t'ime */
-	short cp_cpg;		/* filesystem cylinders per group */
-	short cp_density;	/* bytes per inode density */
-	char cp_minfree;	/* minfree (%) */
-	short cp_reserved;	/* no useful data here */
-	char cp_mountpt[MAXMPTLEN];/* default/standard mount point */
-	char cp_automnt;	/* auto-mount when inserted */
-	char cp_res2;		/* alignment byte */
-	char cp_type[MAXFSTLEN]; /* file system type name */
-    } cd_partitions[MAXPARTITIONS];
+    u_int cd_tag;		/* 40: volume tag */
+    char cd_name[MAXDNMLEN];	/* 44: drive (hardware) name */
+    char cd_type[MAXTYPLEN];	/* 68: drive type */
+    int cd_secsize;		/* 92: # of bytes per sector */
+    int cd_ntracks;		/* 96: # of tracks per cylinder */
+    int cd_nsectors;		/* 100: # of data sectors per track */
+    int cd_ncylinders;          /* 104: # of data cylinders per unit */
+    int cd_rpm;                 /* 108: rotational speed */
+    short cd_front;		/* 112: # of sectors in "front porch" */
+    short cd_back;		/* 114: # of sectors in "back porch" */
+    short cd_ngroups;		/* 116: # of alt groups */
+    short cd_ag_size;		/* 118: alt group size (sectors) */
+    short cd_ag_alts;		/* 120: alternate sectors / alt group */
+    short cd_ag_off;		/* 122: sector offset to first alternate */
+    int cd_boot_blkno[2];	/* 124: boot program locations */
+    char cd_kernel[MAXBFLEN];	/* 132: default kernel name */
+    char cd_hostname[MAXHNLEN];	/* 156: host name (usu. where disk was labeled) */
+    char cd_rootpartition;	/* 188: root partition letter e.g. 'a' */
+    char cd_rwpartition;	/* 189: r/w partition letter e.g. 'b' */
+    struct  cpu_partition {	/* 190, 236, ... */
+	int cp_offset;		    /* 0: starting sector */
+	int cp_size;		    /* 4: number of sectors in partition */
+	short cp_bsize;		    /* 8: block size in bytes */
+	short cp_fsize;		    /* 10: filesystem basic fragment size */
+	char cp_opt;		    /* 12: optimization type: 's'pace/'t'ime */
+        char cp_reserved_0;         /* 13: unused */
+	short cp_cpg;		    /* 14: filesystem cylinders per group */
+	short cp_density;	    /* 16: bytes per inode density */
+	char cp_minfree;	    /* 18: minfree (%) */
+	char cp_reserved_1;	    /* 19: unused */
+	char cp_mountpt[MAXMPTLEN]; /* 20: default/standard mount point */
+	char cp_automnt;	    /* 36: auto-mount when inserted */
+	char cp_type[MAXFSTLEN];    /* 37: file system type name */
+	char cp_reserved_2;	    /* 45: alignment byte */
+    } __attribute__ ((__packed__)) cd_partitions[MAXPARTITIONS];
 
     union {
 	u_short CD_v3_checksum;	/* label version 3 checksum */
@@ -104,6 +105,6 @@
 #define cd_v3_checksum  cd_un.CD_v3_checksum
 #define cd_bad          cd_un.CD_bad
     u_short cd_checksum;	/* label version 1 or 2 checksum */
-};
+} __attribute__ ((__packed__));
 
 #endif /* _MACHINE_DISKLABEL_H_ */

#
# The kludge...
#
Index: ffs_vfsops.c
===================================================================
RCS file: /cvsroot/syssrc/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.75
diff -u -r1.75 ffs_vfsops.c
--- ffs_vfsops.c	2000/12/04 09:37:06	1.75
+++ ffs_vfsops.c	2001/01/11 22:06:03
@@ -112,6 +112,9 @@
 
 struct pool ffs_inode_pool;
 
+static void ffs_sanity_rconv __P((struct fs *));
+static void ffs_sanity_wconv __P((struct fs *));
+
 /*
  * Called by main() when ffs is going to be mounted as root.
  */
@@ -438,6 +441,8 @@
 		free(newfs, M_UFSMNT);
 		return (EIO);		/* XXX needs translation */
 	}
+	ffs_sanity_rconv(newfs);
+
 	/* 
 	 * Copy pointer fields back into superblock before copying in	XXX
 	 * new superblock. These should really be in the ufsmount.	XXX
@@ -624,6 +629,7 @@
 	}
 #endif
 	ffs_oldfscompat(fs);
+	ffs_sanity_rconv(fs);
 
 	if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
 		error = EINVAL;
@@ -1271,6 +1277,7 @@
 	if (mp->um_flags & UFS_NEEDSWAP)
 		ffs_sb_swap(fs, (struct fs*)bp->b_data, 1);
 #endif
+	ffs_sanity_wconv((struct fs *)(bp->b_data));
 
 	fs->fs_flags |= saveflag;
 	fs->fs_nrpos = saved_nrpos; /* XXX */
@@ -1321,4 +1328,33 @@
 	if (!allerror && error)
 		allerror = error;
 	return (allerror);
+}
+
+/*
+ * Check sanity for repairable fields in the superblock.  For now, just
+ * check the block size as compared to the fsbtodb constant.
+ */
+void
+ffs_sanity_rconv(fs)
+	struct fs *fs;
+{
+	int msec;
+
+	msec = dbtofsb(fs, fs->fs_fsize) / dbtob(1);
+	fs->fs_devbsize = 0;
+#ifdef DEBUG
+	printf("ffs_sanity_rconv: changing fsbtodb by factor of %d\n", msec);
+#endif
+	while (msec > 1) {
+		msec /= 2;
+		++fs->fs_fsbtodb;
+		++fs->fs_devbsize;
+	}
+}
+
+void
+ffs_sanity_wconv(fs)
+	struct fs *fs;
+{
+	fs->fs_fsbtodb -= fs->fs_devbsize;
 }
Index: fs.h
===================================================================
RCS file: /cvsroot/syssrc/sys/ufs/ffs/fs.h,v
retrieving revision 1.12
diff -u -r1.12 fs.h
--- fs.h	1999/11/15 18:49:14	1.12
+++ fs.h	2001/01/11 22:06:03
@@ -157,7 +157,7 @@
  */
 struct fs {
 	int32_t	 fs_firstfield;		/* historic file system linked list, */
-	int32_t	 fs_unused_1;		/*     used for incore super blocks */
+	int32_t	 fs_devbsize;		/* original dev_bsize */
 	ufs_daddr_t fs_sblkno;		/* addr of super-block in filesys */
 	ufs_daddr_t fs_cblkno;		/* offset of cyl-block in filesys */
 	ufs_daddr_t fs_iblkno;		/* offset of inode-blocks in filesys */
>Release-Note:
>Audit-Trail:
>Unformatted: