Hi,

Here're updated patches. Tested on sparc (build only). Gnats ID is lib/45796.

On Thu, Dec 29, 2011 at 11:20 PM, David Laight <da...@l8s.co.uk> wrote:
> On Thu, Dec 29, 2011 at 07:55:18PM +0100, Antoine LECA wrote:
>>
>> David Laight wrote:
>> > The actual 'pc' boot sequence is:
>> > Stages 1-3 (and maybe 4) are common to all OS.
>> <...>
>> > 3) The pbr code has to determine where it was loaded from, it could:
>> >    a) reread sector zero and look for a partition of the relevant type
>> >    b) have the sector number previously written into the sector data.
>>
>>      c)
>> >    The netbsd bootselect mbr passes the sector number in a register
>> >    (non-standard) and the pbr code scans the partitions looking for
>> >    one that starts in the correct place.
> ...
>> I am not sure whether NetBSD currently uses a or c (or a combination of
>> both); ...
>
> Last time I rewrote it, it reread the mbr and located the partition
> (following the extended/logical partition chain) looking for the
> one that starts in the sector passed in (IIRC) %esi. If not found
> it rescans looking for thr first netbsd partition.
>
> I used %esi because it reduced the number of instructions in the mbr!
> The mbr is a work of art!
>
>        David
>
> --
> David Laight: da...@l8s.co.uk



-- 
Evgeniy
From 7d7f2b29751ceccfc1addce299cb5131e9f7b1e8 Mon Sep 17 00:00:00 2001
From: Evgeniy Ivanov <lolkaanti...@gmail.com>
Date: Mon, 5 Dec 2011 19:44:33 +0400
Subject: [PATCH 1/4] MINIX 3 subpartitions support.

- Read MFS subpartitions, when neccessarly.
- Add MFS to the supported FSes list.

diff --git a/common/lib/libutil/getfstypename.c b/common/lib/libutil/getfstypename.c
index 79ea154..26fe3a3 100644
--- a/common/lib/libutil/getfstypename.c
+++ b/common/lib/libutil/getfstypename.c
@@ -121,6 +121,8 @@ getfstypename(int fstype)
 		return DKW_PTYPE_CGD;
 	case FSMAXTYPES:
 		return DKW_PTYPE_UNKNOWN;
+	case FS_MINIXFS3:
+		return DKW_PTYPE_MINIXFS3;
 	}
 	/* Stupid gcc, should know it is impossible to get here */
 	return DKW_PTYPE_UNKNOWN;
diff --git a/sys/arch/i386/stand/lib/biosdisk.c b/sys/arch/i386/stand/lib/biosdisk.c
index dddfdf9..13701c7 100644
--- a/sys/arch/i386/stand/lib/biosdisk.c
+++ b/sys/arch/i386/stand/lib/biosdisk.c
@@ -404,6 +404,40 @@ check_label(struct biosdisk *d, daddr_t sector)
 }
 
 static int
+read_minix_subp(struct biosdisk *d, struct disklabel* dflt_lbl,
+			int this_ext, daddr_t sector)
+{
+	struct mbr_partition mbr[MBR_PART_COUNT];
+	int i;
+	int typ;
+	struct partition *p;
+
+	if (readsects(&d->ll, sector, 1, d->buf, 0)) {
+#ifdef DISK_DEBUG
+		printf("Error reading MFS sector %d\n", sector);
+#endif
+		return EIO;
+	}
+	if ((uint8_t)d->buf[510] != 0x55 || (uint8_t)d->buf[511] != 0xAA) {
+		return -1;
+	}
+	memcpy(&mbr, ((struct mbr_sector *)d->buf)->mbr_parts, sizeof(mbr));
+	for (i = 0; i < MBR_PART_COUNT; i++) {
+		typ = mbr[i].mbrp_type;
+		if (typ == 0)
+			continue;
+		sector = this_ext + mbr[i].mbrp_start;
+		if (dflt_lbl->d_npartitions >= MAXPARTITIONS)
+			continue;
+		p = &dflt_lbl->d_partitions[dflt_lbl->d_npartitions++];
+		p->p_offset = sector;
+		p->p_size = mbr[i].mbrp_size;
+		p->p_fstype = xlat_mbr_fstype(typ);
+	}
+	return 0;
+}
+
+static int
 read_label(struct biosdisk *d)
 {
 	struct disklabel dflt_lbl;
@@ -452,6 +486,13 @@ read_label(struct biosdisk *d)
 #ifdef DISK_DEBUG
 			printf("ptn type %d in sector %d\n", typ, sector);
 #endif
+                        if (typ == MBR_PTYPE_MINIX_14B) {
+				if (!read_minix_subp(d, &dflt_lbl,
+						   this_ext, sector)) {
+					/* Don't add "container" partition */
+					continue;
+				}
+			}
 			if (typ == MBR_PTYPE_NETBSD) {
 				error = check_label(d, sector);
 				if (error >= 0)
diff --git a/sys/lib/libkern/xlat_mbr_fstype.c b/sys/lib/libkern/xlat_mbr_fstype.c
index 618c55a..4151770 100644
--- a/sys/lib/libkern/xlat_mbr_fstype.c
+++ b/sys/lib/libkern/xlat_mbr_fstype.c
@@ -55,6 +55,7 @@ xlat_mbr_fstype(int mbr_type)
 		{ MBR_PTYPE_LNXSWAP,	FS_SWAP },
 		{ MBR_PTYPE_NETBSD,	FS_BSDFFS },
 		{ MBR_PTYPE_NTFS,	FS_NTFS },
+		{ MBR_PTYPE_MINIX_14B,	FS_MINIXFS3 },
 		{ 0,			FS_OTHER }
 	};
 	const struct ptn_types *pt;
diff --git a/sys/sys/disk.h b/sys/sys/disk.h
index 985f8e7..2c5546a 100644
--- a/sys/sys/disk.h
+++ b/sys/sys/disk.h
@@ -245,6 +245,7 @@ __link_set_add_data(dkwedge_methods, name ## _ddm)
 #define	DKW_PTYPE_EFS		"efs"
 #define	DKW_PTYPE_NILFS		"nilfs"
 #define	DKW_PTYPE_CGD		"cgd"
+#define	DKW_PTYPE_MINIXFS3	"minixfs3"
 
 /*
  * Disk geometry dictionary.
diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h
index ff424ea..69f79c3 100644
--- a/sys/sys/disklabel.h
+++ b/sys/sys/disklabel.h
@@ -357,7 +357,8 @@ x(UDF,     24, "UDF",        NULL,   "udf")   /* UDF */ \
 x(SYSVBFS, 25, "SysVBFS",    NULL,  "sysvbfs")/* System V boot file system */ \
 x(EFS,     26, "EFS",        NULL,   "efs")   /* SGI's Extent Filesystem */ \
 x(NILFS,   27, "NiLFS",      NULL,   "nilfs") /* NTT's NiLFS(2) */ \
-x(CGD,     28, "cgd",	     NULL,   NULL)    /* Cryptographic disk */
+x(CGD,     28, "cgd",	     NULL,   NULL)    /* Cryptographic disk */ \
+x(MINIXFS3,29, "MINIX FSv3", NULL,   NULL)    /* MINIX file system v3 */
 
 
 #ifndef _LOCORE
-- 
1.7.3.4

From 8c1b67f226d95e29a6adac778b4f49a05b286762 Mon Sep 17 00:00:00 2001
From: Evgeniy Ivanov <lolkaanti...@gmail.com>
Date: Sun, 18 Dec 2011 15:04:16 +0400
Subject: [PATCH 2/4] MINIX File System v3 support for libsa.


diff --git a/sys/lib/libsa/Makefile b/sys/lib/libsa/Makefile
index 4d0d951..0eb99a7 100644
--- a/sys/lib/libsa/Makefile
+++ b/sys/lib/libsa/Makefile
@@ -75,6 +75,7 @@ SRCS+=	cd9660.c
 SRCS+=	ustarfs.c
 SRCS+=	dosfs.c
 SRCS+=	ext2fs.c
+SRCS+=	minixfs3.c
 # for historic compatibility ufs == ffsv1
 SRCS+=	ufs.c
 
diff --git a/sys/lib/libsa/minixfs3.c b/sys/lib/libsa/minixfs3.c
new file mode 100644
index 0000000..a722173
--- /dev/null
+++ b/sys/lib/libsa/minixfs3.c
@@ -0,0 +1,991 @@
+/*	$NetBSD$ */
+
+/*-
+ * Copyright (c) 2012
+ *	Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
+ *
+ * Author: Evgeniy Ivanov (based on libsa/ext2fs.c).
+ *
+ * This code is derived from src/sys/lib/libsa/ext2fs.c contributed to 
+ * The NetBSD Foundation, see copyrights below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * Copyright (c) 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: David Golub
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *	Stand-alone file reading package for MFS file system.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef _STANDALONE
+#include <lib/libkern/libkern.h>
+#else
+#include <string.h>
+#endif
+
+#include "stand.h"
+#include "minixfs3.h"
+
+#if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
+#define LIBSA_NO_FS_SYMLINK
+#endif
+
+#if defined(LIBSA_NO_TWIDDLE)
+#define twiddle()
+#endif
+
+typedef uint32_t	ino32_t;
+#ifndef FSBTODB
+#define FSBTODB(fs, indp) fsbtodb(fs, indp)
+#endif
+
+/*
+ * To avoid having a lot of filesystem-block sized buffers lurking (which
+ * could be 32k) we only keep a few entries of the indirect block map.
+ * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
+ * ~13 times pulling in a 6M kernel.
+ * The cache size must be smaller than the smallest filesystem block,
+ * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
+ */
+#define LN2_IND_CACHE_SZ	6
+#define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
+#define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
+
+/*
+ * In-core open file.
+ */
+struct file {
+	off_t		f_seekp;	/* seek pointer */
+	struct mfs_sblock  *f_fs;	/* pointer to super-block */
+	struct mfs_dinode  f_di;	/* copy of on-disk inode */
+	uint		f_nishift;	/* for blocks in indirect block */
+	block_t		f_ind_cache_block;
+	block_t		f_ind_cache[IND_CACHE_SZ];
+
+	char		*f_buf;		/* buffer for data block */
+	size_t		f_buf_size;	/* size of data block */
+	daddr_t		f_buf_blkno;	/* block number of data block */
+};
+
+#if defined(LIBSA_ENABLE_LS_OP)
+
+#define NELEM(x) (sizeof (x) / sizeof(*x))
+
+typedef struct entry_t entry_t;
+struct entry_t {
+	entry_t	*e_next;
+	ino32_t	e_ino;
+	char	e_name[1];
+};
+
+static int
+fn_match(const char *fname, const char *pattern)
+{
+	char fc, pc;
+
+	do {
+		fc = *fname++;
+		pc = *pattern++;
+		if (!fc && !pc)
+			return 1;
+		if (pc == '?' && fc)
+			pc = fc;
+	} while (fc == pc);
+
+	if (pc != '*')
+		return 0;
+	/*
+	 * Too hard (and unnecessary really) too check for "*?name" etc....
+	 * "**" will look for a '*' and "*?" a '?'
+	 */
+	pc = *pattern++;
+	if (!pc)
+		return 1;
+	while ((fname = strchr(fname, pc)))
+		if (fn_match(++fname, pattern))
+			return 1;
+	return 0;
+}
+#endif /* LIBSA_ENABLE_LS_OP */
+
+
+static int read_inode(ino32_t, struct open_file *);
+static int block_map(struct open_file *, block_t, block_t *);
+static int buf_read_file(struct open_file *, char **, size_t *);
+static int search_directory(const char *, int, struct open_file *, ino32_t *);
+static int read_sblock(struct open_file *, struct mfs_sblock *);
+
+/*
+ * Read a new inode into a file structure.
+ */
+static int
+read_inode(ino32_t inumber, struct open_file *f)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	char *buf;
+	size_t rsize;
+	int rc;
+	daddr_t inode_sector;
+	struct mfs_dinode *dip;
+
+	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
+
+	/*
+	 * Read inode and save it.
+	 */
+	buf = fp->f_buf;
+	twiddle();
+	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+	    inode_sector, fs->mfs_block_size, buf, &rsize);
+	if (rc)
+		return rc;
+	if (rsize != fs->mfs_block_size)
+		return EIO;
+
+	dip = (struct mfs_dinode *)(buf +
+	    INODE_SIZE * ino_to_fsbo(fs, inumber));
+	mfs_iload(dip, &fp->f_di);
+
+	/*
+	 * Clear out the old buffers
+	 */
+	fp->f_ind_cache_block = ~0;
+	fp->f_buf_blkno = -1;
+	return rc;
+}
+
+/*
+ * Given an offset in a file, find the disk block number (not zone!)
+ * that contains that block.
+ */
+static int
+block_map(struct open_file *f, block_t file_block, block_t *disk_block_p)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	uint level;
+	block_t ind_cache;
+	block_t ind_block_num;
+	zone_t zone;
+	size_t rsize;
+	int rc;
+	int boff;
+	int scale = fs->mfs_log_zone_size; /* for block-zone conversion */
+	block_t *buf = (void *)fp->f_buf;
+
+	/*
+	 * Index structure of an inode:
+	 *
+	 * mdi_blocks[0..NR_DZONES-1]
+	 *			hold zone numbers for zones
+	 *			0..NR_DZONES-1
+	 *
+	 * mdi_blocks[NR_DZONES+0]
+	 *			block NDADDR+0 is the single indirect block
+	 *			holds zone numbers for zones
+	 *			NR_DZONES .. NR_DZONES + NINDIR(fs)-1
+	 *
+	 * mdi_blocks[NR_DZONES+1]
+	 *			block NDADDR+1 is the double indirect block
+	 *			holds zone numbers for INDEX blocks for zones
+	 *			NR_DZONES + NINDIR(fs) ..
+	 *			NR_TZONES + NINDIR(fs) + NINDIR(fs)**2 - 1
+	 */
+
+	zone = file_block >> scale;
+	boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */
+
+	if (zone < NR_DZONES) {
+		/* Direct zone */
+		zone_t z = fs2h32(fp->f_di.mdi_zone[zone]);
+		if (z == NO_ZONE) {
+			*disk_block_p = NO_BLOCK;
+			return 0;
+		}
+		*disk_block_p = (block_t) ((z << scale) + boff);
+		return 0;
+	}
+
+	zone -= NR_DZONES;
+
+	ind_cache = zone >> LN2_IND_CACHE_SZ;
+	if (ind_cache == fp->f_ind_cache_block) {
+		*disk_block_p =
+		    fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]);
+		return 0;
+	}
+
+	for (level = 0;;) {
+		level += fp->f_nishift;
+
+		if (zone < (block_t)1 << level)
+			break;
+		if (level > NIADDR * fp->f_nishift)
+			/* Zone number too high */
+			return EFBIG;
+		zone -= (block_t)1 << level;
+	}
+
+	ind_block_num =
+	    fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]);
+
+	for (;;) {
+		level -= fp->f_nishift;
+		if (ind_block_num == 0) {
+			*disk_block_p = NO_BLOCK;	/* missing */
+			return 0;
+		}
+
+		twiddle();
+		/*
+		 * If we were feeling brave, we could work out the number
+		 * of the disk sector and read a single disk sector instead
+		 * of a filesystem block.
+		 * However we don't do this very often anyway...
+		 */
+		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+			FSBTODB(fs, ind_block_num), fs->mfs_block_size,
+			buf, &rsize);
+		if (rc)
+			return rc;
+		if (rsize != fs->mfs_block_size)
+			return EIO;
+
+		ind_block_num = fs2h32(buf[zone >> level]);
+		if (level == 0)
+			break;
+		zone &= (1 << level) - 1;
+	}
+
+	/* Save the part of the block that contains this sector */
+	memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK],
+	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
+	fp->f_ind_cache_block = ind_cache;
+
+	zone = (zone_t)ind_block_num;
+	*disk_block_p = (block_t)((zone << scale) + boff);
+	return 0;
+}
+
+/*
+ * Read a portion of a file into an internal buffer.
+ * Return the location in the buffer and the amount in the buffer.
+ */
+static int
+buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	long off;
+	block_t file_block;
+	block_t disk_block;
+	size_t block_size;
+	int rc;
+
+	off = blkoff(fs, fp->f_seekp);
+	file_block = lblkno(fs, fp->f_seekp);
+	block_size = fs->mfs_block_size;
+
+	if (file_block != fp->f_buf_blkno) {
+		rc = block_map(f, file_block, &disk_block);
+		if (rc)
+			return rc;
+
+		if (disk_block == 0) {
+			memset(fp->f_buf, 0, block_size);
+			fp->f_buf_size = block_size;
+		} else {
+			twiddle();
+			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+				FSBTODB(fs, disk_block),
+				block_size, fp->f_buf, &fp->f_buf_size);
+			if (rc)
+				return rc;
+		}
+
+		fp->f_buf_blkno = file_block;
+	}
+
+	/*
+	 * Return address of byte in buffer corresponding to
+	 * offset, and size of remainder of buffer after that
+	 * byte.
+	 */
+	*buf_p = fp->f_buf + off;
+	*size_p = block_size - off;
+
+	/*
+	 * But truncate buffer at end of file.
+	 */
+	if (*size_p > fp->f_di.mdi_size - fp->f_seekp)
+		*size_p = fp->f_di.mdi_size - fp->f_seekp;
+
+	return 0;
+}
+
+/*
+ * Search a directory for a name and return its
+ * inode number.
+ */
+static int
+search_directory(const char *name, int length, struct open_file *f,
+	ino32_t *inumber_p)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	struct mfs_direct *dp;
+	struct mfs_direct *dbuf;
+	size_t buf_size;
+	int namlen;
+	int rc;
+
+	fp->f_seekp = 0;
+
+	while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
+		rc = buf_read_file(f, (char**)&dbuf, &buf_size);
+		if (rc)
+			return rc;
+		if (buf_size == 0)
+			return EIO;
+
+		/* XXX we assume, that buf_read_file reads an fs block and
+		 * doesn't truncate buffer. Currently i_size in MFS doesn't
+		 * the same as size of allocated blocks, it makes buf_read_file
+		 * to truncate buf_size.
+		 */
+		if (buf_size < fs->mfs_block_size)
+			buf_size = fs->mfs_block_size;
+
+		for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
+			char *cp;
+			if (fs2h32(dp->mfsd_ino) == (ino32_t) 0)
+				continue;
+			/* Compute the length of the name */
+			cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
+			if (cp == NULL)
+				namlen = sizeof(dp->mfsd_name);
+			else
+				namlen = cp - (dp->mfsd_name);
+
+			if (namlen == length &&
+			    !memcmp(name, dp->mfsd_name, length)) {
+				/* found entry */
+				*inumber_p = fs2h32(dp->mfsd_ino);
+				return 0;
+			}
+		}
+		fp->f_seekp += buf_size;
+	}
+	return ENOENT;
+}
+
+int
+read_sblock(struct open_file *f, struct mfs_sblock *fs)
+{
+	static uint8_t sbbuf[MINBSIZE];
+	size_t buf_size;
+	int rc;
+
+	/* We must read amount multiple of sector size, hence we can't
+	 * read SBSIZE and read MINBSIZE.
+	 */
+	if (SBSIZE > MINBSIZE)
+		return EINVAL;
+
+	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+	    SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size);
+	if (rc)
+		return rc;
+
+	if (buf_size != MINBSIZE)
+		return EIO;
+
+	mfs_sbload((void *)sbbuf, fs);
+
+	if (fs->mfs_magic != SUPER_MAGIC)
+		return EINVAL;
+	if (fs->mfs_block_size < MINBSIZE)
+		return EINVAL;
+	if ((fs->mfs_block_size % 512) != 0)
+		return EINVAL;
+	if (SBSIZE > fs->mfs_block_size)
+		return EINVAL;
+	if ((fs->mfs_block_size % INODE_SIZE) != 0)
+		return EINVAL;
+
+	/* For even larger disks, a similar problem occurs with s_firstdatazone.
+	 * If the on-disk field contains zero, we assume that the value was too
+	 * large to fit, and compute it on the fly.
+	 */
+	if (fs->mfs_firstdatazone_old == 0) {
+		block_t offset;
+		offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks;
+		offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) /
+				fs->mfs_inodes_per_block;
+
+		fs->mfs_firstdatazone =
+			(offset + (1 << fs->mfs_log_zone_size) - 1) >>
+				fs->mfs_log_zone_size;
+	} else {
+		fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old;
+	}
+
+	if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1
+			|| fs->mfs_ninodes < 1 || fs->mfs_zones < 1
+			|| fs->mfs_firstdatazone <= 4
+			|| fs->mfs_firstdatazone >= fs->mfs_zones
+			|| (unsigned) fs->mfs_log_zone_size > 4)
+		return EINVAL;
+
+	/* compute in-memory mfs_sblock values */
+	fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE;
+
+
+	{
+		int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE;
+		int ln2 = LOG_MINBSIZE;
+
+		for (; mult != 1; ln2++)
+			mult >>= 1;
+
+		fs->mfs_bshift = ln2;
+		/* XXX assume hw bsize = 512 */
+		fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1;
+	}
+
+	fs->mfs_qbmask = fs->mfs_block_size - 1;
+	fs->mfs_bmask = ~fs->mfs_qbmask;
+
+	return 0;
+}
+
+/*
+ * Open a file.
+ */
+__compactcall int
+minixfs3_open(const char *path, struct open_file *f)
+{
+#ifndef LIBSA_FS_SINGLECOMPONENT
+	const char *cp, *ncp;
+	int c;
+#endif
+	ino32_t inumber;
+	struct file *fp;
+	struct mfs_sblock *fs;
+	int rc;
+#ifndef LIBSA_NO_FS_SYMLINK
+	ino32_t parent_inumber;
+	int nlinks = 0;
+	char namebuf[MAXPATHLEN+1];
+	char *buf;
+#endif
+
+	/* allocate file system specific data structure */
+	fp = alloc(sizeof(struct file));
+	memset(fp, 0, sizeof(struct file));
+	f->f_fsdata = (void *)fp;
+
+	/* allocate space and read super block */
+	fs = alloc(sizeof(*fs));
+	memset(fs, 0, sizeof(*fs));
+	fp->f_fs = fs;
+	twiddle();
+
+	rc = read_sblock(f, fs);
+	if (rc)
+		goto out;
+
+	/* alloc a block sized buffer used for all fs transfers */
+	fp->f_buf = alloc(fs->mfs_block_size);
+
+	/*
+	 * Calculate indirect block levels.
+	 */
+	{
+		int32_t mult;
+		int ln2;
+
+		/*
+		 * We note that the number of indirect blocks is always
+		 * a power of 2.  This lets us use shifts and masks instead
+		 * of divide and remainder and avoinds pulling in the
+		 * 64bit division routine into the boot code.
+		 */
+		mult = NINDIR(fs);
+#ifdef DEBUG
+		if (!powerof2(mult)) {
+			/* Hummm was't a power of 2 */
+			rc = EINVAL;
+			goto out;
+		}
+#endif
+		for (ln2 = 0; mult != 1; ln2++)
+			mult >>= 1;
+
+		fp->f_nishift = ln2;
+	}
+
+	inumber = ROOT_INODE;
+	if ((rc = read_inode(inumber, f)) != 0)
+		goto out;
+
+#ifndef LIBSA_FS_SINGLECOMPONENT
+	cp = path;
+	while (*cp) {
+
+		/*
+		 * Remove extra separators
+		 */
+		while (*cp == '/')
+			cp++;
+		if (*cp == '\0')
+			break;
+
+		/*
+		 * Check that current node is a directory.
+		 */
+		if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) {
+			rc = ENOTDIR;
+			goto out;
+		}
+
+		/*
+		 * Get next component of path name.
+		 */
+		ncp = cp;
+		while ((c = *cp) != '\0' && c != '/')
+			cp++;
+
+		/*
+		 * Look up component in current directory.
+		 * Save directory inumber in case we find a
+		 * symbolic link.
+		 */
+#ifndef LIBSA_NO_FS_SYMLINK
+		parent_inumber = inumber;
+#endif
+		rc = search_directory(ncp, cp - ncp, f, &inumber);
+		if (rc)
+			goto out;
+
+		/*
+		 * Open next component.
+		 */
+		if ((rc = read_inode(inumber, f)) != 0)
+			goto out;
+
+#ifndef LIBSA_NO_FS_SYMLINK
+		/*
+		 * Check for symbolic link.
+		 */
+		if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) {
+			int link_len = fp->f_di.mdi_size;
+			int len;
+			size_t buf_size;
+			block_t	disk_block;
+
+			len = strlen(cp);
+
+			if (link_len + len > MAXPATHLEN ||
+			    ++nlinks > MAXSYMLINKS) {
+				rc = ENOENT;
+				goto out;
+			}
+
+			memmove(&namebuf[link_len], cp, len + 1);
+
+			/*
+			 * Read file for symbolic link
+			 */
+			buf = fp->f_buf;
+			rc = block_map(f, (block_t)0, &disk_block);
+			if (rc)
+				goto out;
+
+			twiddle();
+			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
+					F_READ, FSBTODB(fs, disk_block),
+					fs->mfs_block_size, buf, &buf_size);
+			if (rc)
+				goto out;
+
+			memcpy(namebuf, buf, link_len);
+
+			/*
+			 * If relative pathname, restart at parent directory.
+			 * If absolute pathname, restart at root.
+			 */
+			cp = namebuf;
+			if (*cp != '/')
+				inumber = parent_inumber;
+			else
+				inumber = (ino32_t) ROOT_INODE;
+
+			if ((rc = read_inode(inumber, f)) != 0)
+				goto out;
+		}
+#endif	/* !LIBSA_NO_FS_SYMLINK */
+	}
+
+	/*
+	 * Found terminal component.
+	 */
+	rc = 0;
+
+#else /* !LIBSA_FS_SINGLECOMPONENT */
+
+	/* look up component in the current (root) directory */
+	rc = search_directory(path, strlen(path), f, &inumber);
+	if (rc)
+		goto out;
+
+	/* open it */
+	rc = read_inode(inumber, f);
+
+#endif /* !LIBSA_FS_SINGLECOMPONENT */
+
+	fp->f_seekp = 0;		/* reset seek pointer */
+
+out:
+	if (rc)
+		minixfs3_close(f);
+
+	return rc;
+}
+
+__compactcall int
+minixfs3_close(struct open_file *f)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	f->f_fsdata = NULL;
+	if (fp == NULL)
+		return 0;
+
+	if (fp->f_buf)
+		dealloc(fp->f_buf, fp->f_fs->mfs_block_size);
+	dealloc(fp->f_fs, sizeof(*fp->f_fs));
+	dealloc(fp, sizeof(struct file));
+	return 0;
+}
+
+/*
+ * Copy a portion of a file into kernel memory.
+ * Cross block boundaries when necessary.
+ */
+__compactcall int
+minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	size_t csize;
+	char *buf;
+	size_t buf_size;
+	int rc = 0;
+	char *addr = start;
+
+	while (size != 0) {
+		if (fp->f_seekp >= (off_t)fp->f_di.mdi_size)
+			break;
+
+		rc = buf_read_file(f, &buf, &buf_size);
+		if (rc)
+			break;
+
+		csize = size;
+		if (csize > buf_size)
+			csize = buf_size;
+
+		memcpy(addr, buf, csize);
+
+		fp->f_seekp += csize;
+		addr += csize;
+		size -= csize;
+	}
+
+	if (resid)
+		*resid = size;
+	return rc;
+}
+
+/*
+ * Not implemented.
+ */
+#ifndef LIBSA_NO_FS_WRITE
+__compactcall int
+minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+
+	return EROFS;
+}
+#endif /* !LIBSA_NO_FS_WRITE */
+
+#ifndef LIBSA_NO_FS_SEEK
+__compactcall off_t
+minixfs3_seek(struct open_file *f, off_t offset, int where)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	switch (where) {
+	case SEEK_SET:
+		fp->f_seekp = offset;
+		break;
+	case SEEK_CUR:
+		fp->f_seekp += offset;
+		break;
+	case SEEK_END:
+		fp->f_seekp = fp->f_di.mdi_size - offset;
+		break;
+	default:
+		return -1;
+	}
+	return fp->f_seekp;
+}
+#endif /* !LIBSA_NO_FS_SEEK */
+
+__compactcall int
+minixfs3_stat(struct open_file *f, struct stat *sb)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	/* only important stuff */
+	memset(sb, 0, sizeof *sb);
+	sb->st_mode = fp->f_di.mdi_mode;
+	sb->st_uid = fp->f_di.mdi_uid;
+	sb->st_gid = fp->f_di.mdi_gid;
+	sb->st_size = fp->f_di.mdi_size;
+	return 0;
+}
+
+#if defined(LIBSA_ENABLE_LS_OP)
+__compactcall void
+minixfs3_ls(struct open_file *f, const char *pattern)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	struct mfs_direct *dp;
+	struct mfs_direct *dbuf;
+	size_t buf_size;
+	entry_t	*names = 0, *n, **np;
+
+	fp->f_seekp = 0;
+	while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
+		int rc = buf_read_file(f, (char**)&dbuf, &buf_size);
+		if (rc)
+			goto out;
+
+		/* XXX we assume, that buf_read_file reads an fs block and
+		 * doesn't truncate buffer. Currently i_size in MFS doesn't
+		 * the same as size of allocated blocks, it makes buf_read_file
+		 * to truncate buf_size.
+		 */
+		if (buf_size < fs->mfs_block_size)
+			buf_size = fs->mfs_block_size;
+
+		for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
+			char *cp;
+			int namlen;
+
+			if (fs2h32(dp->mfsd_ino) == 0)
+				continue;
+
+			if (pattern && !fn_match(dp->mfsd_name, pattern))
+				continue;
+
+			/* Compute the length of the name,
+			 * We don't use strlen and strcpy, because original MFS
+			 * code doesn't.
+			 */
+			cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
+			if (cp == NULL)
+				namlen = sizeof(dp->mfsd_name);
+			else
+				namlen = cp - (dp->mfsd_name);
+
+			n = alloc(sizeof *n + namlen);
+			if (!n) {
+				printf("%d: %s\n",
+					fs2h32(dp->mfsd_ino), dp->mfsd_name);
+				continue;
+			}
+			n->e_ino = fs2h32(dp->mfsd_ino);
+			strncpy(n->e_name, dp->mfsd_name, namlen);
+			n->e_name[namlen] = '\0';
+			for (np = &names; *np; np = &(*np)->e_next) {
+				if (strcmp(n->e_name, (*np)->e_name) < 0)
+					break;
+			}
+			n->e_next = *np;
+			*np = n;
+		}
+		fp->f_seekp += buf_size;
+	}
+
+	if (names) {
+		entry_t *p_names = names;
+		do {
+			n = p_names;
+			printf("%d: %s\n",
+				n->e_ino, n->e_name);
+			p_names = n->e_next;
+		} while (p_names);
+	} else {
+		printf("not found\n");
+	}
+out:
+	if (names) {
+		do {
+			n = names;
+			names = n->e_next;
+			dealloc(n, 0);
+		} while (names);
+	}
+	return;
+}
+#endif
+
+/*
+ * byte swap functions for big endian machines
+ * (mfs is always little endian)
+ */
+
+/* These functions are only needed if native byte order is not big endian */
+#if BYTE_ORDER == BIG_ENDIAN
+void
+minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new)
+{
+	new->mfs_ninodes	=	bswap32(old->mfs_ninodes);
+	new->mfs_nzones		=	bswap16(old->mfs_nzones);
+	new->mfs_imap_blocks	=	bswap16(old->mfs_imap_blocks);
+	new->mfs_zmap_blocks	=	bswap16(old->mfs_zmap_blocks);
+	new->mfs_firstdatazone_old =	bswap16(old->mfs_firstdatazone_old);
+	new->mfs_log_zone_size	=	bswap16(old->mfs_log_zone_size);
+	new->mfs_max_size	=	bswap32(old->mfs_max_size);
+	new->mfs_zones		=	bswap32(old->mfs_zones);
+	new->mfs_magic		=	bswap16(old->mfs_magic);
+	new->mfs_block_size	=	bswap16(old->mfs_block_size);
+	new->mfs_disk_version	=	old->mfs_disk_version;
+}
+
+void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new)
+{
+	int i;
+
+	new->mdi_mode		=	bswap16(old->mdi_mode);
+	new->mdi_nlinks		=	bswap16(old->mdi_nlinks);
+	new->mdi_uid		=	bswap16(old->mdi_uid);
+	new->mdi_gid		=	bswap16(old->mdi_gid);
+	new->mdi_size		=	bswap32(old->mdi_size);
+	new->mdi_atime		=	bswap32(old->mdi_atime);
+	new->mdi_mtime		=	bswap32(old->mdi_mtime);
+	new->mdi_ctime		=	bswap32(old->mdi_ctime);
+
+	/* We don't swap here, because indirects must be swapped later
+	 * anyway, hence everything is done by block_map().
+	 */
+	for (i = 0; i < NR_TZONES; i++)
+		new->mdi_zone[i] = old->mdi_zone[i];
+}
+#endif
diff --git a/sys/lib/libsa/minixfs3.h b/sys/lib/libsa/minixfs3.h
new file mode 100644
index 0000000..aef8a54
--- /dev/null
+++ b/sys/lib/libsa/minixfs3.h
@@ -0,0 +1,176 @@
+/*	$NetBSD$ */
+
+/*-
+ * Copyright (c) 2012
+ *	Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
+ *
+ * Author: Evgeniy Ivanov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MINIX_FS_3_H
+#define MINIX_FS_3_H
+
+FS_DEF(minixfs3);
+
+typedef uint32_t zone_t;
+typedef uint16_t zone1_t;
+typedef uint32_t block_t;
+
+#define NR_DZONES	7	/* # direct zone numbers in an inode */
+#define NR_TZONES	10	/* total # zone numbers in an inode */
+#define NIADDR		2       /* Indirect addresses in inode */
+
+struct mfs_dinode {
+	uint16_t  mdi_mode;	/* file type, protection, etc. */
+	uint16_t  mdi_nlinks;	/* how many links to this file */
+	int16_t   mdi_uid;	/* user id of the file's owner */
+	uint16_t  mdi_gid;	/* group number */
+	uint32_t  mdi_size;	/* current file size in bytes */
+	uint32_t  mdi_atime;	/* time of last access */
+	uint32_t  mdi_mtime;	/* when was file data last changed */
+	uint32_t  mdi_ctime;	/* when was inode itself changed */
+	zone_t    mdi_zone[NR_TZONES]; /* zone numbers for direct, ind, and
+						dbl ind */
+};
+
+/* Maximum Minix MFS on-disk directory filename.
+ * MFS uses 'struct direct' to write and parse
+ * directory entries, so this can't be changed
+ * without breaking filesystems.
+ */
+#define MFS_DIRSIZ	60
+
+struct mfs_direct {
+	uint32_t  mfsd_ino;
+	char      mfsd_name[MFS_DIRSIZ];
+} __packed;
+
+struct mfs_sblock {
+	uint32_t  mfs_ninodes;		/* # usable inodes on the minor device */
+	zone1_t   mfs_nzones;		/* total device size, including bit maps etc */
+	int16_t   mfs_imap_blocks;	/* # of blocks used by inode bit map */
+	int16_t   mfs_zmap_blocks;	/* # of blocks used by zone bit map */
+	zone1_t   mfs_firstdatazone_old;/* number of first data zone (small) */
+	int16_t   mfs_log_zone_size;	/* log2 of blocks/zone */
+	int16_t   mfs_pad;		/* try to avoid compiler-dependent padding */
+	int32_t   mfs_max_size;		/* maximum file size on this device */
+	zone_t    mfs_zones;		/* number of zones (replaces s_nzones in V2) */
+	int16_t   mfs_magic;		/* magic number to recognize super-blocks */
+	int16_t   mfs_pad2;		/* try to avoid compiler-dependent padding */
+	uint16_t  mfs_block_size;	/* block size in bytes. */
+	char      mfs_disk_version;	/* filesystem format sub-version */
+
+  /* The following items are only used when the super_block is in memory,
+   * mfs_inodes_per_block must be the firs one (see SBSIZE)
+   */
+	unsigned mfs_inodes_per_block;	/* precalculated from magic number */
+	zone_t   mfs_firstdatazone;	/* number of first data zone (big) */
+	int32_t  mfs_bshift;		/* ``lblkno'' calc of logical blkno */
+	int32_t  mfs_bmask;		/* ``blkoff'' calc of blk offsets */
+	int64_t  mfs_qbmask;		/* ~fs_bmask - for use with quad size */
+	int32_t  mfs_fsbtodb;		/* fsbtodb and dbtofsb shift constant */
+};
+
+#define LOG_MINBSIZE	10
+#define MINBSIZE	(1 << LOG_MINBSIZE)
+
+#define SUPER_MAGIC	0x4d5a	/* magic # for MFSv3 file systems */
+
+#define ROOT_INODE	((uint32_t) 1)	/* inode number for root directory */
+#define SUPER_BLOCK_OFF (1024)		/* bytes offset */
+#define START_BLOCK	((block_t) 2)	/* first fs block (not counting SB) */
+
+/* # bytes/dir entry */
+#define DIR_ENTRY_SIZE		sizeof(struct mfs_direct)
+/* # dir entries/blk */
+#define NR_DIR_ENTRIES(fs)	((fs)->mfs_block_size/DIR_ENTRY_SIZE)
+/* mfs_sblock on-disk part size */
+#define SBSIZE			offsetof(struct mfs_sblock, mfs_inodes_per_block)
+
+#define ZONE_NUM_SIZE		sizeof(zone_t) /* # bytes in zone  */
+#define INODE_SIZE		sizeof(struct mfs_dinode) /* bytes in dsk ino */
+/* # zones/indir block */
+#define NINDIR(fs)		((fs)->mfs_block_size/ZONE_NUM_SIZE)
+
+#define NO_ZONE			((zone_t) 0)	/* absence of a zone number */
+#define NO_BLOCK		((block_t) 0)	/* absence of a block number */
+
+/* Turn file system block numbers into disk block addresses */
+#define fsbtodb(fs, b)	((b) << (fs)->mfs_fsbtodb)
+
+#define	ino_to_fsba(fs, x)						\
+	(((x) - 1) / (fs)->mfs_inodes_per_block +			\
+	START_BLOCK + (fs)->mfs_imap_blocks + (fs)->mfs_zmap_blocks)
+#define	ino_to_fsbo(fs, x)	(((x) - 1) % (fs)->mfs_inodes_per_block)
+
+/*
+ * MFS metadatas are stored in little-endian byte order. These macros
+ * helps reading theses metadatas.
+ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#	define fs2h16(x) (x)
+#	define fs2h32(x) (x)
+#	define mfs_sbload(old, new)	\
+		memcpy((new), (old), SBSIZE);
+#	define mfs_iload(old, new)	\
+		memcpy((new),(old),sizeof(struct mfs_dinode))
+#else
+void minixfs3_sb_bswap(struct mfs_sblock *, struct mfs_sblock *);
+void minixfs3_i_bswap(struct mfs_dinode *, struct mfs_dinode *);
+#	define fs2h16(x) bswap16(x)
+#	define fs2h32(x) bswap32(x)
+#	define mfs_sbload(old, new) minixfs3_sb_bswap((old), (new))
+#	define mfs_iload(old, new) minixfs3_i_bswap((old), (new))
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc)		/* calculates (loc % fs->mfs_bsize) */ \
+	((loc) & (fs)->mfs_qbmask)
+#define lblkno(fs, loc)		/* calculates (loc / fs->mfs_bsize) */ \
+	((loc) >> (fs)->mfs_bshift)
+
+/* Flag bits for i_mode in the inode. */
+#define I_TYPE          0170000 /* this field gives inode type */
+#define I_UNIX_SOCKET   0140000 /* unix domain socket */
+#define I_SYMBOLIC_LINK 0120000 /* file is a symbolic link */
+#define I_REGULAR       0100000 /* regular file, not dir or special */
+#define I_BLOCK_SPECIAL 0060000 /* block special file */
+#define I_DIRECTORY     0040000 /* file is a directory */
+#define I_CHAR_SPECIAL  0020000 /* character special file */
+#define I_NAMED_PIPE    0010000 /* named pipe (FIFO) */
+#define I_SET_UID_BIT   0004000 /* set effective uid_t on exec */
+#define I_SET_GID_BIT   0002000 /* set effective gid_t on exec */
+#define I_SET_STCKY_BIT 0001000 /* sticky bit */
+#define ALL_MODES       0007777 /* all bits for user, group and others */
+#define RWX_MODES       0000777 /* mode bits for RWX only */
+#define R_BIT           0000004 /* Rwx protection bit */
+#define W_BIT           0000002 /* rWx protection bit */
+#define X_BIT           0000001 /* rwX protection bit */
+#define I_NOT_ALLOC     0000000 /* this inode is free */
+
+#endif /* MINIX_FS_3_H */
-- 
1.7.3.4

From 9db57a035b7c3c6437467bdaee67b795eaf68a51 Mon Sep 17 00:00:00 2001
From: Evgeniy Ivanov <lolkaanti...@gmail.com>
Date: Sun, 18 Dec 2011 15:54:03 +0400
Subject: [PATCH 3/4] i386 boot2 MINIX FS support.

By default MINIX FS support is disabled.

diff --git a/sys/arch/i386/stand/boot/Makefile.boot b/sys/arch/i386/stand/boot/Makefile.boot
index 78b9974..18b3eb8 100644
--- a/sys/arch/i386/stand/boot/Makefile.boot
+++ b/sys/arch/i386/stand/boot/Makefile.boot
@@ -70,6 +70,7 @@ CPPFLAGS+= -DSUPPORT_CD9660
 CPPFLAGS+= -DSUPPORT_USTARFS
 CPPFLAGS+= -DSUPPORT_DOSFS
 CPPFLAGS+= -DSUPPORT_EXT2FS
+#CPPFLAGS+= -DSUPPORT_MINIXFS3
 CPPFLAGS+= -DPASS_BIOSGEOM
 CPPFLAGS+= -DPASS_MEMMAP
 #CPPFLAGS+= -DBOOTPASSWD
diff --git a/sys/arch/i386/stand/boot/conf.c b/sys/arch/i386/stand/boot/conf.c
index db92a08..fa45ac2 100644
--- a/sys/arch/i386/stand/boot/conf.c
+++ b/sys/arch/i386/stand/boot/conf.c
@@ -36,6 +36,9 @@
 #ifdef SUPPORT_EXT2FS
 #include <lib/libsa/ext2fs.h>
 #endif
+#ifdef SUPPORT_MINIXFS3
+#include <lib/libsa/minixfs3.h>
+#endif
 #ifdef SUPPORT_USTARFS
 #include <lib/libsa/ustarfs.h>
 #endif
@@ -66,6 +69,9 @@ struct fs_ops file_system[] = {
 #ifdef SUPPORT_EXT2FS
 	FS_OPS(ext2fs),
 #endif
+#ifdef SUPPORT_MINIXFS3
+	FS_OPS(minixfs3),
+#endif
 #ifdef SUPPORT_DOSFS
 	FS_OPS(dosfs),
 #endif
-- 
1.7.3.4

Reply via email to