tech-kern archive

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

Re: patch: MFSv3 support (libsa) for boot2 (i386)



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 <david%l8s.co.uk@localhost> 
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: david%l8s.co.uk@localhost



-- 
Evgeniy
From 7d7f2b29751ceccfc1addce299cb5131e9f7b1e8 Mon Sep 17 00:00:00 2001
From: Evgeniy Ivanov <lolkaantimat%gmail.com@localhost>
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 <lolkaantimat%gmail.com@localhost>
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.Distribution%CS.CMU.EDU@localhost
+ *  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 <lolkaantimat%gmail.com@localhost>
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



Home | Main Index | Thread Index | Old Index