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,

I was trying to add bootxx_minifs3 similar to the bootxx_ext2fs. I
failed to figure out how to use bootxx_ext2fs, because UFS and FAT are
the only filesystems hardcoded in bootxx (pbr.S). Also it seems that a
small ext2 boot partition is not an option for i386, because bootxx
and boot must be on the same partition (and installing bootxx on ext2
kills FS, because 1Kb < ~8Kb). Though commit comment says it can be
done. Could you please explain how to use bootxx_ext2fs?

On Sun, Dec 25, 2011 at 3:34 PM, Izumi Tsutsui 
<tsutsui%ceres.dti.ne.jp@localhost> wrote:
> Hi,
>
> Evgeniy Ivanov wrote:
>
>> Here're patches to implement MINIX File System v3 support in libsa.
>> Support for MFS is added to the boot2 for i386.
>
> Several comments:
>
> - I don't know about MINIX FS v3, but it looks similar to Linux Ext2fs.
>  Is it difficult to share some code among them?

It's also very similar to UFS (seems like Ext2fs is based on that
code). There're some functions which have much in common, but
different either in structure members names (like xxx_stat) or in very
small details. I think sharing such small pieces of code will make
things worse. Probably that's the reason why (IIRC) in Linux ext2,
ext3 and ext4 do not share common code.

> - Do you have any plan to add kernel support for the MINIX FS v3?

No.

>  If not, are changes outside sys/libsa necessary?
>  (common/lib/libutil, libkern/xlat_mbr_fstype.c, sys/disk.h etc.)

It's required by biosdisk modification. Biosdisk itself requires just
one of those, but system build fails without other modifications
(switch doesn't list everything, but adding a proper branch requires
some another changes outside). Also it's nice to show to disklabel
users name of MFS instead of "Unknown".

> - What environment do you test these loaders?
>  Is there any tool to create/check these file system like
>  e2fsprogs for Ext2fs?

To create MFS (sub)partitions and to format I use part and mkfs.mfs
respectively. IIRC it's available in MINIX 3 only, but there is a life
cd.
To check MFS implementation I've inserted a test into boot2: it reads
3 files and calculates md5 sums. The biggest file had all levels of
indirection. Ls was used to check if reads directories correctly.
To multiboot I use an example multiboot kernel from grub's multiboot
specification.

I use VMWare and can share my test virtual disk.

> - There are some "XXX should handle LARGEFILE" comments (that I put
>  for ext2fs REV1 inode), but does MINIX FS have the similar member?
>  It doesn't seem there are extra members in struct mfs_dinode.

Removed odd comments.

> - struct mfs_sblock seems to have many uint16_t and one char members.
>  Probably it's better to put explicit padding and specify __packed
>  to avoid unexpected machine dependent alignment restrictions.

It is the last member in ondisk structure, so machine dependent
alignment after is just fine.

> - in sys/lib/libsa/mfsv3.c:mfsv3_i_bswap()
>  - mdi_zone[] in  is unused? (untesed on big endian?)

Sorry, it's a pasto. I didn't test on big endian.

>  - (int16_t) cast to bswap16() is not necessary?

Fixed.

>  - zone_t is typedef'ed as uint32_t. Shouldn't mdi_zone[] members
>   also be swapped?

Oh, they're swapped in a loop at the end of mfsv3_i_bswap(). That
local mdi_zone[] didn't affect anything.

> - in sys/lib/libsa/mfsv3.c:mfsv3_open()
>  - fsmod and fsmod2 are used to pass module info for bootloaders
>   to load. If currently no kernel support for MINIX FS,
>   fsmod and fsmod2 should be left nothing.

Fixed.

> - Copyright notice seems inconsistent:
>
>>> + * Copyright (c) 2011
>>> + *     Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
>>> + *
>>> + * Author: Evgeniy Ivanov (based on ext2fs.c).
>
> Are you sure that the copyright holder is not you but VU?

Yes, I'm.

>>> + * This code is derived from software contributed to The NetBSD Foundation
>>> + * by Martin Husemann.
>
> Is this still valid statement or just pasto?
>
> + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
>
> Probably not TNF, but the author or copyright holders.

Fixed.


Do I need to send-pr?


-- 
Evgeniy
From 33c4024f3f016a99b0c7aa8f3784bfbc53a7fdf8 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 175a6f6ffd8c59b7e45fe472658c27b9b34e508e 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..ed4b75b
--- /dev/null
+++ b/sys/lib/libsa/minixfs3.c
@@ -0,0 +1,982 @@
+/*     $NetBSD$ */
+
+/*-
+ * Copyright (c) 2011
+ *     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 VRIJE UNIVERSITEIT 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[SBSIZE];
+       size_t buf_size;
+       int rc;
+
+       rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+           SUPER_BLOCK_OFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size);
+       if (rc)
+               return rc;
+
+       if (buf_size != SBSIZE)
+               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);
+
+       for (i = 0; i < V2_NR_TZONES; i++)
+               new->mdi_zone[i] = (zone_t) 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..a6856d4
--- /dev/null
+++ b/sys/lib/libsa/minixfs3.h
@@ -0,0 +1,177 @@
+/*     $NetBSD$ */
+
+/*-
+ * Copyright (c) 2011
+ *     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 VRIJE UNIVERSITEIT 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 bitchunk_t;
+typedef uint32_t zone_t;
+typedef uint16_t zone1_t;
+typedef uint32_t block_t;
+
+#define LOG_MINBSIZE   10
+#define MINBSIZE       (1 << LOG_MINBSIZE)
+
+#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 */
+
+#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 */
+
+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 */
+};
+
+#endif /* MINIX_FS_3_H */
-- 
1.7.3.4

From b4bd212f6522f0fd3e54a1555814def812aed470 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 mfs support.


diff --git a/sys/arch/i386/stand/boot/Makefile.boot 
b/sys/arch/i386/stand/boot/Makefile.boot
index 78b9974..c6b4d7c 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