Hi, Here're updated patches. Tested on sparc (build only). Gnats ID is lib/45796.
On Thu, Dec 29, 2011 at 11:20 PM, David Laight <da...@l8s.co.uk> wrote: > On Thu, Dec 29, 2011 at 07:55:18PM +0100, Antoine LECA wrote: >> >> David Laight wrote: >> > The actual 'pc' boot sequence is: >> > Stages 1-3 (and maybe 4) are common to all OS. >> <...> >> > 3) The pbr code has to determine where it was loaded from, it could: >> > a) reread sector zero and look for a partition of the relevant type >> > b) have the sector number previously written into the sector data. >> >> c) >> > The netbsd bootselect mbr passes the sector number in a register >> > (non-standard) and the pbr code scans the partitions looking for >> > one that starts in the correct place. > ... >> I am not sure whether NetBSD currently uses a or c (or a combination of >> both); ... > > Last time I rewrote it, it reread the mbr and located the partition > (following the extended/logical partition chain) looking for the > one that starts in the sector passed in (IIRC) %esi. If not found > it rescans looking for thr first netbsd partition. > > I used %esi because it reduced the number of instructions in the mbr! > The mbr is a work of art! > > David > > -- > David Laight: da...@l8s.co.uk -- Evgeniy
From 7d7f2b29751ceccfc1addce299cb5131e9f7b1e8 Mon Sep 17 00:00:00 2001 From: Evgeniy Ivanov <lolkaanti...@gmail.com> Date: Mon, 5 Dec 2011 19:44:33 +0400 Subject: [PATCH 1/4] MINIX 3 subpartitions support. - Read MFS subpartitions, when neccessarly. - Add MFS to the supported FSes list. diff --git a/common/lib/libutil/getfstypename.c b/common/lib/libutil/getfstypename.c index 79ea154..26fe3a3 100644 --- a/common/lib/libutil/getfstypename.c +++ b/common/lib/libutil/getfstypename.c @@ -121,6 +121,8 @@ getfstypename(int fstype) return DKW_PTYPE_CGD; case FSMAXTYPES: return DKW_PTYPE_UNKNOWN; + case FS_MINIXFS3: + return DKW_PTYPE_MINIXFS3; } /* Stupid gcc, should know it is impossible to get here */ return DKW_PTYPE_UNKNOWN; diff --git a/sys/arch/i386/stand/lib/biosdisk.c b/sys/arch/i386/stand/lib/biosdisk.c index dddfdf9..13701c7 100644 --- a/sys/arch/i386/stand/lib/biosdisk.c +++ b/sys/arch/i386/stand/lib/biosdisk.c @@ -404,6 +404,40 @@ check_label(struct biosdisk *d, daddr_t sector) } static int +read_minix_subp(struct biosdisk *d, struct disklabel* dflt_lbl, + int this_ext, daddr_t sector) +{ + struct mbr_partition mbr[MBR_PART_COUNT]; + int i; + int typ; + struct partition *p; + + if (readsects(&d->ll, sector, 1, d->buf, 0)) { +#ifdef DISK_DEBUG + printf("Error reading MFS sector %d\n", sector); +#endif + return EIO; + } + if ((uint8_t)d->buf[510] != 0x55 || (uint8_t)d->buf[511] != 0xAA) { + return -1; + } + memcpy(&mbr, ((struct mbr_sector *)d->buf)->mbr_parts, sizeof(mbr)); + for (i = 0; i < MBR_PART_COUNT; i++) { + typ = mbr[i].mbrp_type; + if (typ == 0) + continue; + sector = this_ext + mbr[i].mbrp_start; + if (dflt_lbl->d_npartitions >= MAXPARTITIONS) + continue; + p = &dflt_lbl->d_partitions[dflt_lbl->d_npartitions++]; + p->p_offset = sector; + p->p_size = mbr[i].mbrp_size; + p->p_fstype = xlat_mbr_fstype(typ); + } + return 0; +} + +static int read_label(struct biosdisk *d) { struct disklabel dflt_lbl; @@ -452,6 +486,13 @@ read_label(struct biosdisk *d) #ifdef DISK_DEBUG printf("ptn type %d in sector %d\n", typ, sector); #endif + if (typ == MBR_PTYPE_MINIX_14B) { + if (!read_minix_subp(d, &dflt_lbl, + this_ext, sector)) { + /* Don't add "container" partition */ + continue; + } + } if (typ == MBR_PTYPE_NETBSD) { error = check_label(d, sector); if (error >= 0) diff --git a/sys/lib/libkern/xlat_mbr_fstype.c b/sys/lib/libkern/xlat_mbr_fstype.c index 618c55a..4151770 100644 --- a/sys/lib/libkern/xlat_mbr_fstype.c +++ b/sys/lib/libkern/xlat_mbr_fstype.c @@ -55,6 +55,7 @@ xlat_mbr_fstype(int mbr_type) { MBR_PTYPE_LNXSWAP, FS_SWAP }, { MBR_PTYPE_NETBSD, FS_BSDFFS }, { MBR_PTYPE_NTFS, FS_NTFS }, + { MBR_PTYPE_MINIX_14B, FS_MINIXFS3 }, { 0, FS_OTHER } }; const struct ptn_types *pt; diff --git a/sys/sys/disk.h b/sys/sys/disk.h index 985f8e7..2c5546a 100644 --- a/sys/sys/disk.h +++ b/sys/sys/disk.h @@ -245,6 +245,7 @@ __link_set_add_data(dkwedge_methods, name ## _ddm) #define DKW_PTYPE_EFS "efs" #define DKW_PTYPE_NILFS "nilfs" #define DKW_PTYPE_CGD "cgd" +#define DKW_PTYPE_MINIXFS3 "minixfs3" /* * Disk geometry dictionary. diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h index ff424ea..69f79c3 100644 --- a/sys/sys/disklabel.h +++ b/sys/sys/disklabel.h @@ -357,7 +357,8 @@ x(UDF, 24, "UDF", NULL, "udf") /* UDF */ \ x(SYSVBFS, 25, "SysVBFS", NULL, "sysvbfs")/* System V boot file system */ \ x(EFS, 26, "EFS", NULL, "efs") /* SGI's Extent Filesystem */ \ x(NILFS, 27, "NiLFS", NULL, "nilfs") /* NTT's NiLFS(2) */ \ -x(CGD, 28, "cgd", NULL, NULL) /* Cryptographic disk */ +x(CGD, 28, "cgd", NULL, NULL) /* Cryptographic disk */ \ +x(MINIXFS3,29, "MINIX FSv3", NULL, NULL) /* MINIX file system v3 */ #ifndef _LOCORE -- 1.7.3.4
From 8c1b67f226d95e29a6adac778b4f49a05b286762 Mon Sep 17 00:00:00 2001 From: Evgeniy Ivanov <lolkaanti...@gmail.com> Date: Sun, 18 Dec 2011 15:04:16 +0400 Subject: [PATCH 2/4] MINIX File System v3 support for libsa. diff --git a/sys/lib/libsa/Makefile b/sys/lib/libsa/Makefile index 4d0d951..0eb99a7 100644 --- a/sys/lib/libsa/Makefile +++ b/sys/lib/libsa/Makefile @@ -75,6 +75,7 @@ SRCS+= cd9660.c SRCS+= ustarfs.c SRCS+= dosfs.c SRCS+= ext2fs.c +SRCS+= minixfs3.c # for historic compatibility ufs == ffsv1 SRCS+= ufs.c diff --git a/sys/lib/libsa/minixfs3.c b/sys/lib/libsa/minixfs3.c new file mode 100644 index 0000000..a722173 --- /dev/null +++ b/sys/lib/libsa/minixfs3.c @@ -0,0 +1,991 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2012 + * Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved. + * + * Author: Evgeniy Ivanov (based on libsa/ext2fs.c). + * + * This code is derived from src/sys/lib/libsa/ext2fs.c contributed to + * The NetBSD Foundation, see copyrights below. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1997 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or software.distribut...@cs.cmu.edu + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Stand-alone file reading package for MFS file system. + */ + +#include <sys/param.h> +#include <sys/time.h> +#ifdef _STANDALONE +#include <lib/libkern/libkern.h> +#else +#include <string.h> +#endif + +#include "stand.h" +#include "minixfs3.h" + +#if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK) +#define LIBSA_NO_FS_SYMLINK +#endif + +#if defined(LIBSA_NO_TWIDDLE) +#define twiddle() +#endif + +typedef uint32_t ino32_t; +#ifndef FSBTODB +#define FSBTODB(fs, indp) fsbtodb(fs, indp) +#endif + +/* + * To avoid having a lot of filesystem-block sized buffers lurking (which + * could be 32k) we only keep a few entries of the indirect block map. + * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block + * ~13 times pulling in a 6M kernel. + * The cache size must be smaller than the smallest filesystem block, + * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). + */ +#define LN2_IND_CACHE_SZ 6 +#define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) +#define IND_CACHE_MASK (IND_CACHE_SZ - 1) + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + struct mfs_sblock *f_fs; /* pointer to super-block */ + struct mfs_dinode f_di; /* copy of on-disk inode */ + uint f_nishift; /* for blocks in indirect block */ + block_t f_ind_cache_block; + block_t f_ind_cache[IND_CACHE_SZ]; + + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ + daddr_t f_buf_blkno; /* block number of data block */ +}; + +#if defined(LIBSA_ENABLE_LS_OP) + +#define NELEM(x) (sizeof (x) / sizeof(*x)) + +typedef struct entry_t entry_t; +struct entry_t { + entry_t *e_next; + ino32_t e_ino; + char e_name[1]; +}; + +static int +fn_match(const char *fname, const char *pattern) +{ + char fc, pc; + + do { + fc = *fname++; + pc = *pattern++; + if (!fc && !pc) + return 1; + if (pc == '?' && fc) + pc = fc; + } while (fc == pc); + + if (pc != '*') + return 0; + /* + * Too hard (and unnecessary really) too check for "*?name" etc.... + * "**" will look for a '*' and "*?" a '?' + */ + pc = *pattern++; + if (!pc) + return 1; + while ((fname = strchr(fname, pc))) + if (fn_match(++fname, pattern)) + return 1; + return 0; +} +#endif /* LIBSA_ENABLE_LS_OP */ + + +static int read_inode(ino32_t, struct open_file *); +static int block_map(struct open_file *, block_t, block_t *); +static int buf_read_file(struct open_file *, char **, size_t *); +static int search_directory(const char *, int, struct open_file *, ino32_t *); +static int read_sblock(struct open_file *, struct mfs_sblock *); + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(ino32_t inumber, struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct mfs_sblock *fs = fp->f_fs; + char *buf; + size_t rsize; + int rc; + daddr_t inode_sector; + struct mfs_dinode *dip; + + inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); + + /* + * Read inode and save it. + */ + buf = fp->f_buf; + twiddle(); + rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, + inode_sector, fs->mfs_block_size, buf, &rsize); + if (rc) + return rc; + if (rsize != fs->mfs_block_size) + return EIO; + + dip = (struct mfs_dinode *)(buf + + INODE_SIZE * ino_to_fsbo(fs, inumber)); + mfs_iload(dip, &fp->f_di); + + /* + * Clear out the old buffers + */ + fp->f_ind_cache_block = ~0; + fp->f_buf_blkno = -1; + return rc; +} + +/* + * Given an offset in a file, find the disk block number (not zone!) + * that contains that block. + */ +static int +block_map(struct open_file *f, block_t file_block, block_t *disk_block_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct mfs_sblock *fs = fp->f_fs; + uint level; + block_t ind_cache; + block_t ind_block_num; + zone_t zone; + size_t rsize; + int rc; + int boff; + int scale = fs->mfs_log_zone_size; /* for block-zone conversion */ + block_t *buf = (void *)fp->f_buf; + + /* + * Index structure of an inode: + * + * mdi_blocks[0..NR_DZONES-1] + * hold zone numbers for zones + * 0..NR_DZONES-1 + * + * mdi_blocks[NR_DZONES+0] + * block NDADDR+0 is the single indirect block + * holds zone numbers for zones + * NR_DZONES .. NR_DZONES + NINDIR(fs)-1 + * + * mdi_blocks[NR_DZONES+1] + * block NDADDR+1 is the double indirect block + * holds zone numbers for INDEX blocks for zones + * NR_DZONES + NINDIR(fs) .. + * NR_TZONES + NINDIR(fs) + NINDIR(fs)**2 - 1 + */ + + zone = file_block >> scale; + boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */ + + if (zone < NR_DZONES) { + /* Direct zone */ + zone_t z = fs2h32(fp->f_di.mdi_zone[zone]); + if (z == NO_ZONE) { + *disk_block_p = NO_BLOCK; + return 0; + } + *disk_block_p = (block_t) ((z << scale) + boff); + return 0; + } + + zone -= NR_DZONES; + + ind_cache = zone >> LN2_IND_CACHE_SZ; + if (ind_cache == fp->f_ind_cache_block) { + *disk_block_p = + fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]); + return 0; + } + + for (level = 0;;) { + level += fp->f_nishift; + + if (zone < (block_t)1 << level) + break; + if (level > NIADDR * fp->f_nishift) + /* Zone number too high */ + return EFBIG; + zone -= (block_t)1 << level; + } + + ind_block_num = + fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]); + + for (;;) { + level -= fp->f_nishift; + if (ind_block_num == 0) { + *disk_block_p = NO_BLOCK; /* missing */ + return 0; + } + + twiddle(); + /* + * If we were feeling brave, we could work out the number + * of the disk sector and read a single disk sector instead + * of a filesystem block. + * However we don't do this very often anyway... + */ + rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, + FSBTODB(fs, ind_block_num), fs->mfs_block_size, + buf, &rsize); + if (rc) + return rc; + if (rsize != fs->mfs_block_size) + return EIO; + + ind_block_num = fs2h32(buf[zone >> level]); + if (level == 0) + break; + zone &= (1 << level) - 1; + } + + /* Save the part of the block that contains this sector */ + memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK], + IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); + fp->f_ind_cache_block = ind_cache; + + zone = (zone_t)ind_block_num; + *disk_block_p = (block_t)((zone << scale) + boff); + return 0; +} + +/* + * Read a portion of a file into an internal buffer. + * Return the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct mfs_sblock *fs = fp->f_fs; + long off; + block_t file_block; + block_t disk_block; + size_t block_size; + int rc; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = fs->mfs_block_size; + + if (file_block != fp->f_buf_blkno) { + rc = block_map(f, file_block, &disk_block); + if (rc) + return rc; + + if (disk_block == 0) { + memset(fp->f_buf, 0, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(); + rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, + FSBTODB(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return rc; + } + + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > fp->f_di.mdi_size - fp->f_seekp) + *size_p = fp->f_di.mdi_size - fp->f_seekp; + + return 0; +} + +/* + * Search a directory for a name and return its + * inode number. + */ +static int +search_directory(const char *name, int length, struct open_file *f, + ino32_t *inumber_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct mfs_sblock *fs = fp->f_fs; + struct mfs_direct *dp; + struct mfs_direct *dbuf; + size_t buf_size; + int namlen; + int rc; + + fp->f_seekp = 0; + + while (fp->f_seekp < (off_t)fp->f_di.mdi_size) { + rc = buf_read_file(f, (char**)&dbuf, &buf_size); + if (rc) + return rc; + if (buf_size == 0) + return EIO; + + /* XXX we assume, that buf_read_file reads an fs block and + * doesn't truncate buffer. Currently i_size in MFS doesn't + * the same as size of allocated blocks, it makes buf_read_file + * to truncate buf_size. + */ + if (buf_size < fs->mfs_block_size) + buf_size = fs->mfs_block_size; + + for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) { + char *cp; + if (fs2h32(dp->mfsd_ino) == (ino32_t) 0) + continue; + /* Compute the length of the name */ + cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name)); + if (cp == NULL) + namlen = sizeof(dp->mfsd_name); + else + namlen = cp - (dp->mfsd_name); + + if (namlen == length && + !memcmp(name, dp->mfsd_name, length)) { + /* found entry */ + *inumber_p = fs2h32(dp->mfsd_ino); + return 0; + } + } + fp->f_seekp += buf_size; + } + return ENOENT; +} + +int +read_sblock(struct open_file *f, struct mfs_sblock *fs) +{ + static uint8_t sbbuf[MINBSIZE]; + size_t buf_size; + int rc; + + /* We must read amount multiple of sector size, hence we can't + * read SBSIZE and read MINBSIZE. + */ + if (SBSIZE > MINBSIZE) + return EINVAL; + + rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, + SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size); + if (rc) + return rc; + + if (buf_size != MINBSIZE) + return EIO; + + mfs_sbload((void *)sbbuf, fs); + + if (fs->mfs_magic != SUPER_MAGIC) + return EINVAL; + if (fs->mfs_block_size < MINBSIZE) + return EINVAL; + if ((fs->mfs_block_size % 512) != 0) + return EINVAL; + if (SBSIZE > fs->mfs_block_size) + return EINVAL; + if ((fs->mfs_block_size % INODE_SIZE) != 0) + return EINVAL; + + /* For even larger disks, a similar problem occurs with s_firstdatazone. + * If the on-disk field contains zero, we assume that the value was too + * large to fit, and compute it on the fly. + */ + if (fs->mfs_firstdatazone_old == 0) { + block_t offset; + offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks; + offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) / + fs->mfs_inodes_per_block; + + fs->mfs_firstdatazone = + (offset + (1 << fs->mfs_log_zone_size) - 1) >> + fs->mfs_log_zone_size; + } else { + fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old; + } + + if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1 + || fs->mfs_ninodes < 1 || fs->mfs_zones < 1 + || fs->mfs_firstdatazone <= 4 + || fs->mfs_firstdatazone >= fs->mfs_zones + || (unsigned) fs->mfs_log_zone_size > 4) + return EINVAL; + + /* compute in-memory mfs_sblock values */ + fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE; + + + { + int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE; + int ln2 = LOG_MINBSIZE; + + for (; mult != 1; ln2++) + mult >>= 1; + + fs->mfs_bshift = ln2; + /* XXX assume hw bsize = 512 */ + fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1; + } + + fs->mfs_qbmask = fs->mfs_block_size - 1; + fs->mfs_bmask = ~fs->mfs_qbmask; + + return 0; +} + +/* + * Open a file. + */ +__compactcall int +minixfs3_open(const char *path, struct open_file *f) +{ +#ifndef LIBSA_FS_SINGLECOMPONENT + const char *cp, *ncp; + int c; +#endif + ino32_t inumber; + struct file *fp; + struct mfs_sblock *fs; + int rc; +#ifndef LIBSA_NO_FS_SYMLINK + ino32_t parent_inumber; + int nlinks = 0; + char namebuf[MAXPATHLEN+1]; + char *buf; +#endif + + /* allocate file system specific data structure */ + fp = alloc(sizeof(struct file)); + memset(fp, 0, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = alloc(sizeof(*fs)); + memset(fs, 0, sizeof(*fs)); + fp->f_fs = fs; + twiddle(); + + rc = read_sblock(f, fs); + if (rc) + goto out; + + /* alloc a block sized buffer used for all fs transfers */ + fp->f_buf = alloc(fs->mfs_block_size); + + /* + * Calculate indirect block levels. + */ + { + int32_t mult; + int ln2; + + /* + * We note that the number of indirect blocks is always + * a power of 2. This lets us use shifts and masks instead + * of divide and remainder and avoinds pulling in the + * 64bit division routine into the boot code. + */ + mult = NINDIR(fs); +#ifdef DEBUG + if (!powerof2(mult)) { + /* Hummm was't a power of 2 */ + rc = EINVAL; + goto out; + } +#endif + for (ln2 = 0; mult != 1; ln2++) + mult >>= 1; + + fp->f_nishift = ln2; + } + + inumber = ROOT_INODE; + if ((rc = read_inode(inumber, f)) != 0) + goto out; + +#ifndef LIBSA_FS_SINGLECOMPONENT + cp = path; + while (*cp) { + + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) { + rc = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + ncp = cp; + while ((c = *cp) != '\0' && c != '/') + cp++; + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ +#ifndef LIBSA_NO_FS_SYMLINK + parent_inumber = inumber; +#endif + rc = search_directory(ncp, cp - ncp, f, &inumber); + if (rc) + goto out; + + /* + * Open next component. + */ + if ((rc = read_inode(inumber, f)) != 0) + goto out; + +#ifndef LIBSA_NO_FS_SYMLINK + /* + * Check for symbolic link. + */ + if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) { + int link_len = fp->f_di.mdi_size; + int len; + size_t buf_size; + block_t disk_block; + + len = strlen(cp); + + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + rc = ENOENT; + goto out; + } + + memmove(&namebuf[link_len], cp, len + 1); + + /* + * Read file for symbolic link + */ + buf = fp->f_buf; + rc = block_map(f, (block_t)0, &disk_block); + if (rc) + goto out; + + twiddle(); + rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, + F_READ, FSBTODB(fs, disk_block), + fs->mfs_block_size, buf, &buf_size); + if (rc) + goto out; + + memcpy(namebuf, buf, link_len); + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = (ino32_t) ROOT_INODE; + + if ((rc = read_inode(inumber, f)) != 0) + goto out; + } +#endif /* !LIBSA_NO_FS_SYMLINK */ + } + + /* + * Found terminal component. + */ + rc = 0; + +#else /* !LIBSA_FS_SINGLECOMPONENT */ + + /* look up component in the current (root) directory */ + rc = search_directory(path, strlen(path), f, &inumber); + if (rc) + goto out; + + /* open it */ + rc = read_inode(inumber, f); + +#endif /* !LIBSA_FS_SINGLECOMPONENT */ + + fp->f_seekp = 0; /* reset seek pointer */ + +out: + if (rc) + minixfs3_close(f); + + return rc; +} + +__compactcall int +minixfs3_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + f->f_fsdata = NULL; + if (fp == NULL) + return 0; + + if (fp->f_buf) + dealloc(fp->f_buf, fp->f_fs->mfs_block_size); + dealloc(fp->f_fs, sizeof(*fp->f_fs)); + dealloc(fp, sizeof(struct file)); + return 0; +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +__compactcall int +minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize; + char *buf; + size_t buf_size; + int rc = 0; + char *addr = start; + + while (size != 0) { + if (fp->f_seekp >= (off_t)fp->f_di.mdi_size) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + memcpy(addr, buf, csize); + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + + if (resid) + *resid = size; + return rc; +} + +/* + * Not implemented. + */ +#ifndef LIBSA_NO_FS_WRITE +__compactcall int +minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + + return EROFS; +} +#endif /* !LIBSA_NO_FS_WRITE */ + +#ifndef LIBSA_NO_FS_SEEK +__compactcall off_t +minixfs3_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = fp->f_di.mdi_size - offset; + break; + default: + return -1; + } + return fp->f_seekp; +} +#endif /* !LIBSA_NO_FS_SEEK */ + +__compactcall int +minixfs3_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + memset(sb, 0, sizeof *sb); + sb->st_mode = fp->f_di.mdi_mode; + sb->st_uid = fp->f_di.mdi_uid; + sb->st_gid = fp->f_di.mdi_gid; + sb->st_size = fp->f_di.mdi_size; + return 0; +} + +#if defined(LIBSA_ENABLE_LS_OP) +__compactcall void +minixfs3_ls(struct open_file *f, const char *pattern) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct mfs_sblock *fs = fp->f_fs; + struct mfs_direct *dp; + struct mfs_direct *dbuf; + size_t buf_size; + entry_t *names = 0, *n, **np; + + fp->f_seekp = 0; + while (fp->f_seekp < (off_t)fp->f_di.mdi_size) { + int rc = buf_read_file(f, (char**)&dbuf, &buf_size); + if (rc) + goto out; + + /* XXX we assume, that buf_read_file reads an fs block and + * doesn't truncate buffer. Currently i_size in MFS doesn't + * the same as size of allocated blocks, it makes buf_read_file + * to truncate buf_size. + */ + if (buf_size < fs->mfs_block_size) + buf_size = fs->mfs_block_size; + + for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) { + char *cp; + int namlen; + + if (fs2h32(dp->mfsd_ino) == 0) + continue; + + if (pattern && !fn_match(dp->mfsd_name, pattern)) + continue; + + /* Compute the length of the name, + * We don't use strlen and strcpy, because original MFS + * code doesn't. + */ + cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name)); + if (cp == NULL) + namlen = sizeof(dp->mfsd_name); + else + namlen = cp - (dp->mfsd_name); + + n = alloc(sizeof *n + namlen); + if (!n) { + printf("%d: %s\n", + fs2h32(dp->mfsd_ino), dp->mfsd_name); + continue; + } + n->e_ino = fs2h32(dp->mfsd_ino); + strncpy(n->e_name, dp->mfsd_name, namlen); + n->e_name[namlen] = '\0'; + for (np = &names; *np; np = &(*np)->e_next) { + if (strcmp(n->e_name, (*np)->e_name) < 0) + break; + } + n->e_next = *np; + *np = n; + } + fp->f_seekp += buf_size; + } + + if (names) { + entry_t *p_names = names; + do { + n = p_names; + printf("%d: %s\n", + n->e_ino, n->e_name); + p_names = n->e_next; + } while (p_names); + } else { + printf("not found\n"); + } +out: + if (names) { + do { + n = names; + names = n->e_next; + dealloc(n, 0); + } while (names); + } + return; +} +#endif + +/* + * byte swap functions for big endian machines + * (mfs is always little endian) + */ + +/* These functions are only needed if native byte order is not big endian */ +#if BYTE_ORDER == BIG_ENDIAN +void +minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new) +{ + new->mfs_ninodes = bswap32(old->mfs_ninodes); + new->mfs_nzones = bswap16(old->mfs_nzones); + new->mfs_imap_blocks = bswap16(old->mfs_imap_blocks); + new->mfs_zmap_blocks = bswap16(old->mfs_zmap_blocks); + new->mfs_firstdatazone_old = bswap16(old->mfs_firstdatazone_old); + new->mfs_log_zone_size = bswap16(old->mfs_log_zone_size); + new->mfs_max_size = bswap32(old->mfs_max_size); + new->mfs_zones = bswap32(old->mfs_zones); + new->mfs_magic = bswap16(old->mfs_magic); + new->mfs_block_size = bswap16(old->mfs_block_size); + new->mfs_disk_version = old->mfs_disk_version; +} + +void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new) +{ + int i; + + new->mdi_mode = bswap16(old->mdi_mode); + new->mdi_nlinks = bswap16(old->mdi_nlinks); + new->mdi_uid = bswap16(old->mdi_uid); + new->mdi_gid = bswap16(old->mdi_gid); + new->mdi_size = bswap32(old->mdi_size); + new->mdi_atime = bswap32(old->mdi_atime); + new->mdi_mtime = bswap32(old->mdi_mtime); + new->mdi_ctime = bswap32(old->mdi_ctime); + + /* We don't swap here, because indirects must be swapped later + * anyway, hence everything is done by block_map(). + */ + for (i = 0; i < NR_TZONES; i++) + new->mdi_zone[i] = old->mdi_zone[i]; +} +#endif diff --git a/sys/lib/libsa/minixfs3.h b/sys/lib/libsa/minixfs3.h new file mode 100644 index 0000000..aef8a54 --- /dev/null +++ b/sys/lib/libsa/minixfs3.h @@ -0,0 +1,176 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2012 + * Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved. + * + * Author: Evgeniy Ivanov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MINIX_FS_3_H +#define MINIX_FS_3_H + +FS_DEF(minixfs3); + +typedef uint32_t zone_t; +typedef uint16_t zone1_t; +typedef uint32_t block_t; + +#define NR_DZONES 7 /* # direct zone numbers in an inode */ +#define NR_TZONES 10 /* total # zone numbers in an inode */ +#define NIADDR 2 /* Indirect addresses in inode */ + +struct mfs_dinode { + uint16_t mdi_mode; /* file type, protection, etc. */ + uint16_t mdi_nlinks; /* how many links to this file */ + int16_t mdi_uid; /* user id of the file's owner */ + uint16_t mdi_gid; /* group number */ + uint32_t mdi_size; /* current file size in bytes */ + uint32_t mdi_atime; /* time of last access */ + uint32_t mdi_mtime; /* when was file data last changed */ + uint32_t mdi_ctime; /* when was inode itself changed */ + zone_t mdi_zone[NR_TZONES]; /* zone numbers for direct, ind, and + dbl ind */ +}; + +/* Maximum Minix MFS on-disk directory filename. + * MFS uses 'struct direct' to write and parse + * directory entries, so this can't be changed + * without breaking filesystems. + */ +#define MFS_DIRSIZ 60 + +struct mfs_direct { + uint32_t mfsd_ino; + char mfsd_name[MFS_DIRSIZ]; +} __packed; + +struct mfs_sblock { + uint32_t mfs_ninodes; /* # usable inodes on the minor device */ + zone1_t mfs_nzones; /* total device size, including bit maps etc */ + int16_t mfs_imap_blocks; /* # of blocks used by inode bit map */ + int16_t mfs_zmap_blocks; /* # of blocks used by zone bit map */ + zone1_t mfs_firstdatazone_old;/* number of first data zone (small) */ + int16_t mfs_log_zone_size; /* log2 of blocks/zone */ + int16_t mfs_pad; /* try to avoid compiler-dependent padding */ + int32_t mfs_max_size; /* maximum file size on this device */ + zone_t mfs_zones; /* number of zones (replaces s_nzones in V2) */ + int16_t mfs_magic; /* magic number to recognize super-blocks */ + int16_t mfs_pad2; /* try to avoid compiler-dependent padding */ + uint16_t mfs_block_size; /* block size in bytes. */ + char mfs_disk_version; /* filesystem format sub-version */ + + /* The following items are only used when the super_block is in memory, + * mfs_inodes_per_block must be the firs one (see SBSIZE) + */ + unsigned mfs_inodes_per_block; /* precalculated from magic number */ + zone_t mfs_firstdatazone; /* number of first data zone (big) */ + int32_t mfs_bshift; /* ``lblkno'' calc of logical blkno */ + int32_t mfs_bmask; /* ``blkoff'' calc of blk offsets */ + int64_t mfs_qbmask; /* ~fs_bmask - for use with quad size */ + int32_t mfs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ +}; + +#define LOG_MINBSIZE 10 +#define MINBSIZE (1 << LOG_MINBSIZE) + +#define SUPER_MAGIC 0x4d5a /* magic # for MFSv3 file systems */ + +#define ROOT_INODE ((uint32_t) 1) /* inode number for root directory */ +#define SUPER_BLOCK_OFF (1024) /* bytes offset */ +#define START_BLOCK ((block_t) 2) /* first fs block (not counting SB) */ + +/* # bytes/dir entry */ +#define DIR_ENTRY_SIZE sizeof(struct mfs_direct) +/* # dir entries/blk */ +#define NR_DIR_ENTRIES(fs) ((fs)->mfs_block_size/DIR_ENTRY_SIZE) +/* mfs_sblock on-disk part size */ +#define SBSIZE offsetof(struct mfs_sblock, mfs_inodes_per_block) + +#define ZONE_NUM_SIZE sizeof(zone_t) /* # bytes in zone */ +#define INODE_SIZE sizeof(struct mfs_dinode) /* bytes in dsk ino */ +/* # zones/indir block */ +#define NINDIR(fs) ((fs)->mfs_block_size/ZONE_NUM_SIZE) + +#define NO_ZONE ((zone_t) 0) /* absence of a zone number */ +#define NO_BLOCK ((block_t) 0) /* absence of a block number */ + +/* Turn file system block numbers into disk block addresses */ +#define fsbtodb(fs, b) ((b) << (fs)->mfs_fsbtodb) + +#define ino_to_fsba(fs, x) \ + (((x) - 1) / (fs)->mfs_inodes_per_block + \ + START_BLOCK + (fs)->mfs_imap_blocks + (fs)->mfs_zmap_blocks) +#define ino_to_fsbo(fs, x) (((x) - 1) % (fs)->mfs_inodes_per_block) + +/* + * MFS metadatas are stored in little-endian byte order. These macros + * helps reading theses metadatas. + */ +#if BYTE_ORDER == LITTLE_ENDIAN +# define fs2h16(x) (x) +# define fs2h32(x) (x) +# define mfs_sbload(old, new) \ + memcpy((new), (old), SBSIZE); +# define mfs_iload(old, new) \ + memcpy((new),(old),sizeof(struct mfs_dinode)) +#else +void minixfs3_sb_bswap(struct mfs_sblock *, struct mfs_sblock *); +void minixfs3_i_bswap(struct mfs_dinode *, struct mfs_dinode *); +# define fs2h16(x) bswap16(x) +# define fs2h32(x) bswap32(x) +# define mfs_sbload(old, new) minixfs3_sb_bswap((old), (new)) +# define mfs_iload(old, new) minixfs3_i_bswap((old), (new)) +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc) /* calculates (loc % fs->mfs_bsize) */ \ + ((loc) & (fs)->mfs_qbmask) +#define lblkno(fs, loc) /* calculates (loc / fs->mfs_bsize) */ \ + ((loc) >> (fs)->mfs_bshift) + +/* Flag bits for i_mode in the inode. */ +#define I_TYPE 0170000 /* this field gives inode type */ +#define I_UNIX_SOCKET 0140000 /* unix domain socket */ +#define I_SYMBOLIC_LINK 0120000 /* file is a symbolic link */ +#define I_REGULAR 0100000 /* regular file, not dir or special */ +#define I_BLOCK_SPECIAL 0060000 /* block special file */ +#define I_DIRECTORY 0040000 /* file is a directory */ +#define I_CHAR_SPECIAL 0020000 /* character special file */ +#define I_NAMED_PIPE 0010000 /* named pipe (FIFO) */ +#define I_SET_UID_BIT 0004000 /* set effective uid_t on exec */ +#define I_SET_GID_BIT 0002000 /* set effective gid_t on exec */ +#define I_SET_STCKY_BIT 0001000 /* sticky bit */ +#define ALL_MODES 0007777 /* all bits for user, group and others */ +#define RWX_MODES 0000777 /* mode bits for RWX only */ +#define R_BIT 0000004 /* Rwx protection bit */ +#define W_BIT 0000002 /* rWx protection bit */ +#define X_BIT 0000001 /* rwX protection bit */ +#define I_NOT_ALLOC 0000000 /* this inode is free */ + +#endif /* MINIX_FS_3_H */ -- 1.7.3.4
From 9db57a035b7c3c6437467bdaee67b795eaf68a51 Mon Sep 17 00:00:00 2001 From: Evgeniy Ivanov <lolkaanti...@gmail.com> Date: Sun, 18 Dec 2011 15:54:03 +0400 Subject: [PATCH 3/4] i386 boot2 MINIX FS support. By default MINIX FS support is disabled. diff --git a/sys/arch/i386/stand/boot/Makefile.boot b/sys/arch/i386/stand/boot/Makefile.boot index 78b9974..18b3eb8 100644 --- a/sys/arch/i386/stand/boot/Makefile.boot +++ b/sys/arch/i386/stand/boot/Makefile.boot @@ -70,6 +70,7 @@ CPPFLAGS+= -DSUPPORT_CD9660 CPPFLAGS+= -DSUPPORT_USTARFS CPPFLAGS+= -DSUPPORT_DOSFS CPPFLAGS+= -DSUPPORT_EXT2FS +#CPPFLAGS+= -DSUPPORT_MINIXFS3 CPPFLAGS+= -DPASS_BIOSGEOM CPPFLAGS+= -DPASS_MEMMAP #CPPFLAGS+= -DBOOTPASSWD diff --git a/sys/arch/i386/stand/boot/conf.c b/sys/arch/i386/stand/boot/conf.c index db92a08..fa45ac2 100644 --- a/sys/arch/i386/stand/boot/conf.c +++ b/sys/arch/i386/stand/boot/conf.c @@ -36,6 +36,9 @@ #ifdef SUPPORT_EXT2FS #include <lib/libsa/ext2fs.h> #endif +#ifdef SUPPORT_MINIXFS3 +#include <lib/libsa/minixfs3.h> +#endif #ifdef SUPPORT_USTARFS #include <lib/libsa/ustarfs.h> #endif @@ -66,6 +69,9 @@ struct fs_ops file_system[] = { #ifdef SUPPORT_EXT2FS FS_OPS(ext2fs), #endif +#ifdef SUPPORT_MINIXFS3 + FS_OPS(minixfs3), +#endif #ifdef SUPPORT_DOSFS FS_OPS(dosfs), #endif -- 1.7.3.4