Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Feb 2003 22:50:13 -0800 (PST)
From:      Ed Alley <wea@llnl.gov>
To:        freebsd-bugs@FreeBSD.org
Subject:   kern/47982: Minix file-system offered
Message-ID:  <200303010650.h216oDkW075038@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/47982; it has been noted by GNATS.

From: Ed Alley <wea@llnl.gov>
To: FreeBSD-gnats-submit@freebsd.org
Cc: wea@llnl.gov
Subject: kern/47982: Minix file-system offered
Date: Fri, 28 Feb 2003 22:42:58 -0800 (PST)

 >Submitter-Id:	current-users
 >Originator:	Ed Alley
 >Organization:	Lawrence Livermore National Laboratory
 >Confidential:	no
 >Synopsis:	kern/47982: Minix file-system offered
 >Severity:	non-critical
 >Priority:	low
 >Category:	kern
 >Class:		update
 >Release:	FreeBSD 4.6.2-RELEASE i386
 >Environment:
 System: FreeBSD jordan.llnl.gov FreeBSD 4.6.2-RELEASE #0: i386
 
 >Description:
 	RE: PR kern/47982
 
 	This is an update of my previous submission. The previous
 	submitted patch should be discarded. I have added
 	inode hashing, and the ability to operate with data
 	zone sizes that can contain a power of two number of
 	contiguous data blocks. This is supposed to make disk reads
 	a little more efficient in Minix lore, but I put it in for
 	compatability reasons.
 
 	I have also fixed some bugs that either corrupted the FS or
 	in one case caused a random page-fault. This was traced to
 	the root inode pointer getting trashed when its vnode was
 	released and re-assigned through the vnode cache process.
 
 	Other bugs occured during renameing of files and directories
 	after a remove has been performed. (Boy! VOPS_RENAME(9) is
 	sure a subtle routine; I worked a long time on that one and
 	am still not 100% sure about it.)
 	
 >How-To-Repeat:
 	Not applicable
 >Fix:
 	Rather than submit one huge patch on /usr/src, I have submitted
 	two patches: one for /usr/src/sbin, and one for /usr/src/sys.
 	The patches are demarked by the line:
 
 	8><------------------------------------------------- Cut here
 
 	The sources have been diffed against FreeBSD 4.6.2.
 
 	To apply the /sbin patch:
 
 		cd /usr/src
 		patch -p0 < sbin.patch
 
 	To apply the /kernel patch:
 
 		cd /usr/src
 		patch -p0 < sys.patch
 
 				Ed Alley <wea@llnl.gov>
 
 
 	        FOLLOWING is the SBIN PATCH:
 8><------------------------------------------------- Cut here
 diff -ruN sbin.orig/Makefile sbin/Makefile
 --- sbin.orig/Makefile	Mon Mar 18 00:40:00 2002
 +++ sbin/Makefile	Fri Feb 28 13:44:16 2003
 @@ -78,7 +78,7 @@
  	vinum
  
  .if ${MACHINE_ARCH} == i386
 -SUBDIR+=	kget mount_nwfs mount_smbfs
 +SUBDIR+=	kget mount_nwfs mount_smbfs mount_minix newfs_minix
  .endif
  
  .if exists(${.CURDIR}/${MACHINE})
 diff -ruN sbin.orig/mount_minix/Makefile sbin/mount_minix/Makefile
 --- sbin.orig/mount_minix/Makefile	Wed Dec 31 16:00:00 1969
 +++ sbin/mount_minix/Makefile	Fri Feb 28 13:54:39 2003
 @@ -0,0 +1,10 @@
 +
 +PROG=	mount_minixfs
 +SRCS=	mount_minixfs.c getmntopts.c
 +MAN=	mount_minixfs.8
 +
 +MOUNT=	${.CURDIR}/../mount
 +CFLAGS+= -I${MOUNT}
 +.PATH:	${MOUNT}
 +
 +.include <bsd.prog.mk>
 diff -ruN sbin.orig/mount_minix/bsd-copyright sbin/mount_minix/bsd-copyright
 --- sbin.orig/mount_minix/bsd-copyright	Wed Dec 31 16:00:00 1969
 +++ sbin/mount_minix/bsd-copyright	Fri Feb 28 13:50:57 2003
 @@ -0,0 +1,25 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 diff -ruN sbin.orig/mount_minix/mount_minixfs.8 sbin/mount_minix/mount_minixfs.8
 --- sbin.orig/mount_minix/mount_minixfs.8	Wed Dec 31 16:00:00 1969
 +++ sbin/mount_minix/mount_minixfs.8	Fri Feb 28 13:55:27 2003
 @@ -0,0 +1,44 @@
 +
 +.Dd November 5, 2002
 +.Dt MOUNT_MINIXFS 8
 +.Os
 +.Sh NAME
 +.Nm mount_minixfs
 +.Nd mount a minixfs file system
 +.Sh SYNOPSIS
 +.Nm
 +.Op Fl o Ar options
 +.Ar special
 +.Ar node
 +.Sh DESCRIPTION
 +The
 +.Nm
 +command attaches a minixfs file system
 +.Ar special
 +device on to the file system tree at the point
 +.Ar node .
 +.Pp
 +This command is normally executed by
 +.Xr mount 8
 +at boot time.
 +.Pp
 +The options are as follows:
 +.Bl -tag -width indent
 +.It Fl o
 +Options are specified with a
 +.Fl o
 +flag followed by a comma separated string of options.
 +See the
 +.Xr mount 8
 +man page for possible options and their meanings.
 +.El
 +.Sh SEE ALSO
 +.Xr mount 2 ,
 +.Xr unmount 2 ,
 +.Xr fstab 5 ,
 +.Xr mount 8
 +.Sh HISTORY
 +The
 +.Nm
 +function first appeared in
 +.Fx 4.6 .
 diff -ruN sbin.orig/mount_minix/mount_minixfs.c sbin/mount_minix/mount_minixfs.c
 --- sbin.orig/mount_minix/mount_minixfs.c	Wed Dec 31 16:00:00 1969
 +++ sbin/mount_minix/mount_minixfs.c	Fri Feb 28 13:52:40 2003
 @@ -0,0 +1,118 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include <sys/param.h>
 +#include <sys/mount.h>
 +
 +#include <err.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <sysexits.h>
 +#include <unistd.h>
 +
 +#include <ufs/ufs/ufsmount.h>
 +
 +#include "mntopts.h"
 +
 +struct mntopt mopts[] = {
 +	MOPT_STDOPTS,
 +	MOPT_FORCE,
 +	MOPT_SYNC,
 +	MOPT_UPDATE,
 +	{ NULL }
 +};
 +
 +static void	usage __P((void)) __dead2;
 +
 +int
 +main(argc, argv)
 +	int argc;
 +	char *argv[];
 +{
 +	struct ufs_args args;
 +	int ch, mntflags;
 +	char *fs_name, *options, mntpath[MAXPATHLEN];
 +	struct vfsconf vfc;
 +	int error;
 +
 +	options = NULL;
 +	mntflags = 0;
 +	while ((ch = getopt(argc, argv, "o:")) != -1)
 +		switch (ch) {
 +		case 'o':
 +			getmntopts(optarg, mopts, &mntflags, 0);
 +			break;
 +		case '?':
 +		default:
 +			usage();
 +		}
 +	argc -= optind;
 +	argv += optind;
 +
 +	if (argc != 2)
 +		usage();
 +
 +        args.fspec = argv[0];	/* the name of the device file */
 +	fs_name = argv[1];	/* the mount point */
 +
 +	/*
 +	 * Resolve the mountpoint with realpath(3) and remove unnecessary
 +	 * slashes from the devicename if there are any.
 +	 */
 +	(void)checkpath(fs_name, mntpath);
 +	(void)rmslashes(args.fspec, args.fspec);
 +
 +#define DEFAULT_ROOTUID	-2
 +	args.export.ex_root = DEFAULT_ROOTUID;
 +	if (mntflags & MNT_RDONLY)
 +		args.export.ex_flags = MNT_EXRDONLY;
 +	else
 +		args.export.ex_flags = 0;
 +
 +	error = getvfsbyname("minixfs", &vfc);
 +	if (error && vfsisloadable("minixfs")) {
 +		if (vfsload("minixfs")) {
 +			err(EX_OSERR, "vfsload(minixfs)");
 +		}
 +		endvfsent();	/* flush cache */
 +		error = getvfsbyname("minixfs", &vfc);
 +	}
 +	if (error)
 +		errx(EX_OSERR, "minixfs filesystem is not available");
 +
 +	if (mount(vfc.vfc_name, mntpath, mntflags, &args) < 0)
 +		err(EX_OSERR, "%s", args.fspec);
 +	exit(0);
 +}
 +
 +void
 +usage()
 +{
 +	(void)fprintf(stderr,
 +		"usage: mount_minixfs [-o options] special node\n");
 +	exit(EX_USAGE);
 +}
 diff -ruN sbin.orig/newfs_minix/Makefile sbin/newfs_minix/Makefile
 --- sbin.orig/newfs_minix/Makefile	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/Makefile	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,32 @@
 +#  Copyright (c) 2003 Ed Alley: wea@llnl.gov
 +#  All rights reserved.
 +# 
 +#  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 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 AUTHOR 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.
 +
 +PROG=	newfs_minix
 +SRCS=   main.c super.c blockio.c inodeio.c zoneio.c dirio.c misc.c
 +MAN=	newfs_minix.8
 +
 +LINKS= ${BINDIR}/newfs_minix ${BINDIR}/mount_minixfs
 +MLINKS= newfs_minix.8 mount_minixfs.8
 +
 +.include <bsd.prog.mk>
 diff -ruN sbin.orig/newfs_minix/blockio.c sbin/newfs_minix/blockio.c
 --- sbin.orig/newfs_minix/blockio.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/blockio.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,76 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include "mkfs.h"
 +
 +#include <string.h>
 +
 +void
 +insert_bit(block_t block, int bit)
 +{
 +	/* Inserts a bit in a bitmap */
 +     
 +	int w, s;
 +	short buf[BLOCK_SIZE / sizeof(short)];
 +
 +	get_block(block, (char*)buf);
 +  
 +	w = bit / (8 * sizeof(short));
 +	s = bit % (8 * sizeof(short));
 +  
 +	buf[w] |= (1 << s);
 +  
 +	put_block(block, (char*)buf);
 +}
 +
 +int
 +read_bit(block_t block, int bit)
 +{
 +	/* Returns a bit in a bitmap */
 +     
 +	int w, s;
 +	short buf[BLOCK_SIZE/sizeof(short)];
 +
 +	get_block(block, (char *)buf);
 +     
 +	w = bit / (8 * sizeof(short));
 +	s = bit % (8 * sizeof(short));
 +
 +	return ((int)((buf[w] >> s) & 0x1));
 +}
 +
 +void
 +get_block (block_t block, char *buf)
 +{
 +	bcopy (zone[block].store, buf, BLOCK_SIZE);
 +}
 +
 +void
 +put_block (block_t block, char *buf)
 +{
 +	bcopy (buf, zone[block].store, BLOCK_SIZE);
 +     
 +}
 diff -ruN sbin.orig/newfs_minix/bsd-copyright sbin/newfs_minix/bsd-copyright
 --- sbin.orig/newfs_minix/bsd-copyright	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/bsd-copyright	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,25 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 diff -ruN sbin.orig/newfs_minix/dirio.c sbin/newfs_minix/dirio.c
 --- sbin.orig/newfs_minix/dirio.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/dirio.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,125 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/*
 + * The following code was slightly modified from Minix's mkfs.c with permission.
 + */
 +
 +#include "mkfs.h"
 +
 +void rootdir(mino_t inode)
 +{
 +	/*
 +	  Get a zone for the root directory and
 +	  add the two entries for '.' and '..'
 +	  The length of a single directory entry is
 +	  16 bytes; hence, 32 for two directories.
 +	*/
 +
 +	add_zone(inode, alloc_zone(), 32L, current_time);
 +
 +	/*
 +	  Add the directory entries for the root directory.
 +	  (note that the parent and child inodes are the same)
 +	*/
 +
 +	enter_dir(inode, ".", inode);
 +	enter_dir(inode, "..", inode);
 +
 +	/* increment the link counts */
 +
 +	incr_link(inode);
 +	incr_link(inode);
 +}
 +
 +
 +void
 +incr_link(mino_t n)
 +{
 +	/* Increment the link count to inode n */
 +	
 +	int off;
 +	block_t b;
 +	inode_t inode2[V2_INODES_PER_BLOCK];
 +
 +	b = ((n - 1) / inodes_per_block) + inode_offset;
 +	off = (n - 1) % inodes_per_block;
 +
 +	get_block(b, (char *) inode2);
 +	inode2[off].i_nlinks++;
 +	put_block(b, (char *) inode2);
 +}
 +
 +void
 +enter_dir(mino_t parent, char *name, mino_t child)
 +{
 +	/* Enter child in parent directory */
 +	/* Works for dir > 1 block and zone > block */
 +     
 +	int i, j, k, l, off;
 +	block_t b;
 +	zone_t z;
 +	char *p1, *p2;
 +	struct direct dir_entry[NR_DIR_ENTRIES];
 +	inode_t ino2[V2_INODES_PER_BLOCK];
 +	int nr_dzones;
 +
 +	b = ((parent - 1) / inodes_per_block) + inode_offset;
 +	off = (parent - 1) % inodes_per_block;
 +
 +	get_block(b, (char *) ino2);
 +	nr_dzones = V2_NR_DZONES;
 +  
 +	for (k = 0; k < nr_dzones; k++) {
 +		z = ino2[off].i_zone[k];
 +		if (z == 0) {
 +			z = alloc_zone();
 +			ino2[off].i_zone[k] = z;
 +		}
 +		for (l = 0; l < zone_size; l++) {
 +			get_block((z << zone_shift) + l, (char *) dir_entry);
 +			for (i = 0; i < NR_DIR_ENTRIES; i++) {
 +				if (dir_entry[i].d_ino == 0) {
 +					dir_entry[i].d_ino = child;
 +					p1 = name;
 +					p2 = dir_entry[i].d_name;
 +					j = 14;
 +					while (j--) {
 +						*p2++ = *p1;
 +						if (*p1 != 0) p1++;
 +					}
 +					put_block((z << zone_shift) + l, (char *) dir_entry);
 +					put_block(b, (char *) ino2);
 +					return;
 +				}
 +			}
 +		}
 +	}
 +
 +	printf("Directory-inode %d beyond direct blocks.  Could not enter %s\n",
 +	    parent, name);
 +	exit(1);
 +}
 diff -ruN sbin.orig/newfs_minix/inodeio.c sbin/newfs_minix/inodeio.c
 --- sbin.orig/newfs_minix/inodeio.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/inodeio.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,85 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include "mkfs.h"
 +
 +/*
 +  Returns a free inode number and marks it active
 +*/
 +
 +mino_t
 +get_inode(void)
 +{
 +	mino_t num;
 +	block_t inodemap;
 +	int bit;
 +
 +	/* loop over inodes */
 +
 +	for (num=1; num<nrinodes; num++) {
 +		inodemap = (num/BITS_PER_BLOCK) + INODE_MAP;
 +		bit = num % BITS_PER_BLOCK;
 +		if (read_bit(inodemap, bit) == 0) {
 +			insert_bit(inodemap, bit);
 +			return num;
 +		}
 +	}
 +
 +	printf("No inodes available!\n");
 +	exit(1);
 +}
 +
 +/*
 +  Get an inode, set its mode, usr and group ids.
 +*/
 +
 +mino_t
 +alloc_inode (int mode, int usrid, int grpid)
 +{
 +	mino_t num;
 +	int off;
 +	block_t b;
 +	inode_t inode2[V2_INODES_PER_BLOCK];
 +
 +	/* Get a free inode and mark it active */
 +  
 +	num = get_inode();
 +
 +	/* Get the inode block and its offset within the block */
 +  
 +	b   = ((num - 1) / inodes_per_block) + inode_offset;
 +	off = (num - 1) % inodes_per_block;
 +
 +	/* Set the mode, usr and group ids for this inode */
 +
 +	get_block(b, (char *) inode2);
 +	inode2[off].i_mode = mode;
 +	inode2[off].i_uid = usrid;
 +	inode2[off].i_gid = grpid;
 +	put_block(b, (char *) inode2);
 +  
 +	return (num);
 +}
 diff -ruN sbin.orig/newfs_minix/main.c sbin/newfs_minix/main.c
 --- sbin.orig/newfs_minix/main.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/main.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,242 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/* Some of this code was lifted from the Minix source with permission. */
 +
 +#include "mkfs.h"
 +
 +#include <string.h>
 +#include <stdlib.h>
 +#include <ctype.h>
 +
 +int zone_size, zone_map, zone_shift;
 +int zoff;
 +int inodes_per_block;
 +int inode_offset;
 +int nrblocks, nrnodes;
 +long current_time;
 +zone_t nrzones;
 +unsigned int nrinodes;
 +Zone_t *zone;
 +char zero[BLOCK_SIZE];
 +
 +#define MAX_BLOCKS (1024L * 1024)
 +#define MAX_INODES ((unsigned) 65535)
 +
 +void super(super_block_t*, zone_t, mino_t);
 +void usage(int,char*);
 +
 +int
 +main(int argc, char **argv)
 +{
 +	int c, i, s, fdo, no_output;
 +	super_block_t sp[1];
 +	struct timeval timestr;
 +	int mode;
 +	char *ch, *fname = (char*)NULL;
 +	char defname[] = {"flimage"};
 +
 +	/* The following default values are for a 1440K floppy fs */
 +     
 +	nrblocks = 1440;
 +	nrinodes = 0;
 +	zone_shift = 0;
 +	no_output = 0;
 +
 +	while(1) {
 +		if ((s = getopt(argc, argv, ":hNi:b:s:")) == -1) {
 +			fname = argv[optind++];
 +			break;
 +		}
 +		switch (s) {
 +		case 'h':
 +			usage(0,(char*)NULL);
 +			break;
 +		case 'i':
 +			ch = optarg;
 +			for (i=0; i<strlen(ch); i++) {
 +				c = ch[i];
 +				if (!isdigit(c))
 +					usage(1,"Bad digit for nrinodes");
 +			}
 +			nrinodes = atoi(optarg);
 +			break;
 +		case 'b':
 +			ch = optarg;
 +			for (i=0; i<strlen(ch); i++) {
 +				c = ch[i];
 +				if (!isdigit(c))
 +					usage(1,"Bad digit for nrblocks");
 +			}
 +			nrblocks  = atoi(optarg);
 +			break;
 +		case 's':
 +			ch = optarg;
 +			for (i=0; i<strlen(ch); i++) {
 +				c = ch[i];
 +				if (!isdigit(c))
 +					usage(1,"Bad digit for zoneshift");
 +			}
 +			zone_shift  = atoi(optarg);
 +			break;
 +		case 'N':
 +			no_output = 1;
 +			break;
 +		case '?':
 +			usage(1,"Unknown option");
 +			break;
 +		case ':':
 +			usage(1,"Missing argument");
 +			break;
 +		default:
 +			usage(1,"Huh?");
 +			break;
 +		}
 +	}
 +
 +	inodes_per_block = V2_INODES_PER_BLOCK;
 +
 +	if (nrblocks < 5)
 +		usage(1, "nrblocks is too small");
 +
 +	if (nrblocks > MAX_BLOCKS)
 +		usage(1, "nrblocks greater than (1024 X 1024)");
 +
 +	if (nrinodes == 0) {
 +		/* The default for inodes is 3 blocks per inode, rounded up
 +		 * to fill an inode block.  Above 20M, the average files are
 +		 * sure to be larger because it is hard to fill up 20M with
 +		 * tiny files, so reduce the default number of inodes.  This
 +		 * default can always be overridden by using the -i option.
 +		 */
 +		nrinodes = nrblocks / 3;
 +		if (nrblocks >= 20000) nrinodes  = nrblocks / 4;
 +		if (nrblocks >= 40000) nrinodes  = nrblocks / 5;
 +		if (nrblocks >= 60000) nrinodes  = nrblocks / 6;
 +		if (nrblocks >= 80000) nrinodes  = nrblocks / 7;
 +		if (nrblocks >= 100000) nrinodes = nrblocks / 8;
 +		nrinodes += inodes_per_block - 1;
 +		nrinodes = nrinodes / inodes_per_block * inodes_per_block;
 +		if (nrinodes > MAX_INODES) nrinodes = MAX_INODES;
 +	}
 +
 +	if (nrinodes < 1)
 +		usage(1, "Inode count too small");
 +
 +	if (nrinodes > MAX_INODES)
 +		usage(1, "Inode count too large");
 +
 +	if (fname == NULL && !no_output) {
 +		usage(1, "No special file provided");
 +	}
 +
 +	zone_size = BLOCK_SIZE << zone_shift;
 +	nrzones = nrblocks >> zone_shift;
 +	if ((nrzones << zone_shift) < nrblocks)
 +		nrzones++;
 +
 +	printf("block size = 1024 bytes\n");
 +	printf("zone  size = %d bytes\n",(int)zone_size);
 +	printf("number of blocks = %d\n",(int)nrblocks);
 +	printf("number of zones  = %d\n",(int)nrzones);
 +	printf("zone shift = %d\n",(int)zone_shift);
 +
 +	zone = (Zone_t*)malloc(nrzones*zone_size);
 +
 +	bzero((char*)zone, nrzones*zone_size);
 +     
 +	gettimeofday(&timestr, NULL);
 +	current_time = timestr.tv_sec;  /* UNIX time in seconds */
 +
 +	/* Set up a block of zeros */
 +
 +	bzero(zero, BLOCK_SIZE);
 +
 +	/* Set up the superblock */
 +
 +	super(sp, nrzones, nrinodes);
 +
 +	/* The superblock goes into block[1]. */
 +     
 +	zone[1].sp = sp[0];
 +
 +	zone_map = INODE_MAP + sp->s_imap_blocks;
 +	zone_size  = 1 << zone_shift;         /* Re-define zone_size */
 +	zoff = sp->s_firstdatazone - 1;
 +
 +	insert_bit(INODE_MAP, 0);   /* inode zero is not used but must be allocated */
 +	insert_bit(zone_map,  0);   /* bit zero must always be allocated in zone map */
 +
 +	/*
 +	  Set the mode and rwx bits for the root directory
 +	*/
 +
 +	mode = 040755;  /* drwxr_xr_x */
 +
 +	rootdir(alloc_inode(mode, getuid(), getgid()));
 +
 +	if (!no_output) {
 +
 +		if ((fdo = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0644)) == -1) {
 +			printf("Can't open file: %s; Quitting!\n",fname);
 +			exit(1);
 +		}
 +
 +		/* Write out the blocks */
 +	
 +		for (i=0; i<nrblocks; i++)
 +			write(fdo, &(zone[i]), BLOCK_SIZE);
 +
 +		close(fdo);
 +	}
 +     
 +	exit (0);
 +}
 +
 +void
 +usage(int err, char *mess)
 +{
 +	if (mess != NULL)
 +		printf("\n     %s!\n",mess);
 +
 +	printf("\n");
 +	printf("usage: newfs_minix [-hN] [-i inodes] [-b blocks] [-s shift] special\n");
 +	printf("\n");
 +	printf("   -h,       gives this help message\n");
 +	printf("   -N        no special file is written\n");
 +	printf("   -i inodes is the number of inodes\n");
 +	printf("   -b blocks is the number of blocks\n");
 +	printf("   -s shift  is log2(blocks/zone)\n");
 +	printf("\n");
 +	printf("\"special\" is either a special file or a regular file.\n");
 +	printf("\n");
 +	printf(" If \"special\" is omitted, then this help message will be printed.\n");
 +	printf(" If \"inodes\" is omitted then the number is calculated\n");
 +	printf(" If \"blocks\" is omitted then 1440 is used\n");
 +	printf("\n");
 +
 +	exit(err);
 +}
 diff -ruN sbin.orig/newfs_minix/misc.c sbin/newfs_minix/misc.c
 --- sbin.orig/newfs_minix/misc.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/misc.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,67 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley; wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include "mkfs.h"
 +
 +/*
 + * Below was lifted directly from the Minix source with permission.
 + */
 +
 +/*
 + * The next routine is copied from Minix's fsck.c and mkfs.c...  (Re)define some
 + * things for consistency.  Some things should be done better.  The shifts
 + * should be replaced by multiplications and divisions by MAP_BITS_PER_BLOCK
 + * since log2 of this is too painful to get right.
 + */
 +
 +/* Convert from bit count to a block count. The usual expression
 + *
 + *	(nr_bits + (1 << BITMAPSHIFT) - 1) >> BITMAPSHIFT
 + *
 + * doesn't work because of overflow.
 + *
 + * Other overflow bugs, such as the expression for N_ILIST overflowing when
 + * s_inodes is just over INODES_PER_BLOCK less than the maximum+1, are not
 + * fixed yet, because that number of inodes is silly.
 + */
 +
 +/* The above comment doesn't all apply now bit_t is ulong.  Overflow is now
 + * unlikely, but negative bit counts are now possible (though unlikely)
 + * and give silly results.
 + */
 +
 +int
 +bitmapsize(bit_t nr_bits)
 +{
 +	int nr_blocks;
 +
 +	nr_blocks = (int) (nr_bits >> BITMAPSHIFT);
 +  
 +	if (((bit_t) nr_blocks << BITMAPSHIFT) < nr_bits)
 +		++nr_blocks;
 +  
 +	return nr_blocks;
 +}
 diff -ruN sbin.orig/newfs_minix/mkfs.h sbin/newfs_minix/mkfs.h
 --- sbin.orig/newfs_minix/mkfs.h	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/mkfs.h	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,178 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 + /***************************************************************************
 + *                                                                          *
 + *                           Minix File System                              *
 + *                                                                          *
 + *   The guide for these sources comes from Andrew Tannenbaum's MINIX       *
 + *   source which can be gotten from the official MINIX home page:          *
 + *                http://www.cs.vu.nl/~ast/minix.html                       *
 + *   Some of the names have been changed to avoid conflicts with FBSD. ;)   *
 + *                                                                          *
 + *   For further information there is also the book:                        *
 + *      Tannenbaum and Woodhull,                                            *
 + *          "Operating Systems Design and Implememtation", 2nd ed, 1997     *
 + *                  from Prentice Hall, New Jersey                          *
 + *                                                                          *
 + ****************************************************************************/
 +
 +#include <sys/types.h>
 +#include <sys/time.h>
 +#include <sys/uio.h>
 +
 +#include <fcntl.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <unistd.h>
 +
 +/*
 + * In the definitions that follow, a zone is a block.
 + * There exists the possiblity that a zone can be
 + * a power of two larger than a block; that is the
 + * function of the variable s_log_zone_size in the
 + * super block which represents the shift needed
 + * to go from blocks to zones and back again.
 + */
 +
 +#define BLOCK_SIZE 1024       /* # bytes in a disk block */
 +
 +#define BITS_PER_BLOCK 8192   /* 8*BLOCK_SIZE */
 +#define BITMAPSHIFT 13        /* log2(BITS_PER_BLOCK) */
 +
 +#define INODE_MAP 2           /* position of first inode bitmap */
 +
 +#define V2_NR_DZONES 7
 +#define V2_NR_TZONES 10
 +#define NR_INODES 64
 +#define V2_INODE_SIZE 64    /* sizeof(inode_t) */
 +#define V2_ZONE_NUM_SIZE 4  /* sizeof(zone_t) = 32 bits */
 +#define V2_INODES_PER_BLOCK (BLOCK_SIZE/V2_INODE_SIZE)
 +#define V2_INDIRECTS   (BLOCK_SIZE/V2_ZONE_NUM_SIZE)  /* # zones/indir block */
 +
 +/* The type of sizeof may be (unsigned) long.  Use the following macro for
 + * taking the sizes of small objects so that there are no surprises like
 + * (small) long constants being passed to routines expecting an int.
 + */
 +
 +#define usizeof(t) ((unsigned) sizeof(t))
 +
 +/* Types used in disk, inode, etc. data structures. */
 +typedef unsigned short mino_t; 	   /* i-node number */
 +typedef unsigned short mmode_t;	   /* file type and permissions bits */
 +typedef unsigned long  moff_t;	   /* offset within a file */
 +typedef unsigned short zone1_t;	   /* zone number for V1 file systems */
 +typedef unsigned long  zone_t;	   /* zone number */
 +typedef unsigned long  block_t;	   /* block number */
 +typedef unsigned long  bit_t;      /* bit number in a bitmap */
 +typedef unsigned short bitchunk_t; /* a collection of bits from a bitmap */
 +typedef long           mtime_t;    /* time in sec since 1 Jan 1970 0000 GMT */
 +
 +/* File system types. */
 +#define SUPER_MAGIC   0x137F	/* magic number contained in super-block */
 +#define SUPER_REV     0x7F13	/* magic # when 68000 disk read on PC or vv */
 +#define SUPER_V2      0x2468	/* magic # for V2 file systems */
 +#define SUPER_V2_REV  0x6824	/* V2 magic written on PC, read on 68K or vv */
 +
 +/* Directory layout */
 +#define DIRBLKSIZ 512
 +#define DIRSIZ    14
 +
 +struct direct {
 +	mino_t d_ino;           /*  2 */
 +	char d_name[DIRSIZ];    /* 14 */
 +};
 +
 +#define DIR_ENTRY_SIZE usizeof(struct direct)
 +#define NR_DIR_ENTRIES (BLOCK_SIZE/DIR_ENTRY_SIZE)
 +
 +/* Structure of the superblock on disk */
 +
 +typedef struct {
 +	mino_t s_ninodes;		/* # usable inodes on the minor device */
 +	zone1_t  s_nzones;		/* total device size, including bit maps etc */
 +	short s_imap_blocks;		/* # of blocks used by inode bit map */
 +	short s_zmap_blocks;		/* # of blocks used by zone bit map */
 +	zone1_t s_firstdatazone;	/* number of first data zone */
 +	short s_log_zone_size;	        /* log2 of blocks/zone */
 +	moff_t s_max_size;		/* maximum file size on this device */
 +	short s_magic;		        /* magic number to recognize super-blocks */
 +	short s_pad;			/* try to avoid compiler-dependent padding */
 +	zone_t s_zones;	        	/* number of zones (replaces s_nzones in V2) */
 +	char pad[1000];                 /* pad the block to 1024 bytes */
 +} super_block_t;
 +
 +/* Structure of an inode on disk. length = 64 bytes. */
 +
 +typedef struct {
 +	mmode_t  i_mode;		/* file type, protection, etc. 2 */
 +	short i_nlinks;		        /* how many links to this file 2 */
 +	short i_uid;		        /* user id of the file's owner 2 */
 +	short i_gid;	        	/* group number                2 */
 +	moff_t i_size;	       	        /* current file size in bytes  4 */
 +	mtime_t i_atime;		/* time of last access (V2 only) 4 */
 +	mtime_t i_mtime;		/* when was file data last changed 4 */
 +	mtime_t i_ctime;		/* when was inode itself changed (V2 only) 4 */
 +	zone_t i_zone[V2_NR_TZONES];	/* zone numbers for direct, ind, and dbl ind 40 */
 +} inode_t;
 +
 +/* A zone can be inodes, a bootblock, a superblock or data */
 +/* This definition really defines the possible structure of a block */
 +
 +typedef union {
 +	inode_t inode[16];
 +	super_block_t sp;
 +	struct boot_block_s {
 +		char bootblock[294];
 +		char pad[730];
 +	} boot_block;
 +	char store[1024];
 +} Zone_t;
 +
 +void insert_bit (block_t, int);
 +int read_bit (block_t, int);
 +mino_t get_inode(void);
 +void get_block (block_t, char*);
 +void put_block (block_t, char*);
 +void rootdir(mino_t);
 +zone_t alloc_zone(void);
 +mino_t alloc_inode(int , int, int);
 +void add_zone(mino_t, zone_t, long, long);
 +void incr_link(mino_t);
 +void enter_dir(mino_t, char*, mino_t);
 +
 +/* These variable are defined in main and used throughout */
 +
 +extern Zone_t *zone;
 +extern int zone_size, zone_map, zone_shift;
 +extern int zoff;
 +extern char zero[BLOCK_SIZE];
 +extern int inodes_per_block;
 +extern int inode_offset;
 +extern int nrblocks, nrnodes;
 +extern long current_time;
 +extern zone_t nrzones;
 +extern unsigned int nrinodes;
 diff -ruN sbin.orig/newfs_minix/newfs_minix.8 sbin/newfs_minix/newfs_minix.8
 --- sbin.orig/newfs_minix/newfs_minix.8	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/newfs_minix.8	Fri Feb 28 13:56:11 2003
 @@ -0,0 +1,59 @@
 +
 +.Dd February 28, 2003
 +.Dt NEWFS_MINIX 8
 +.Os
 +.Sh NAME
 +.Nm newfs_minix
 +.Nd construct a new Minix file system
 +.Sh SYNOPSIS
 +.Nm
 +.Op Fl N
 +.Op Fl b Ar number-of-blocks
 +.Op Fl i Ar number-of-inodes
 +.Op Fl s Ar zone-shift
 +.Ar special
 +.Sh DESCRIPTION
 +The
 +.Nm
 +utility is used to initialize and clear the Minix
 +filesystem on device
 +.Ar special.
 +(We often refer to the
 +.Dq special file
 +as the
 +.Dq disk ,
 +although the special file need not be a physical disk.
 +In fact, it need not even be special.)
 +Without options
 +.Nm
 +will make a file system that will fit on a 1.44MB
 +floppy disk, however,
 +.Nm
 +has some options to allow the defaults to be selectively overridden.
 +.Pp
 +The following options define the general layout policies:
 +.Bl -tag -width indent
 +.It Fl b Ar number-of-blocks
 +The total number of blocks of 1024 bytes each that the FS will contain.
 +If this option is not provided then 1440 blocks are chosen.
 +.It Fl i Ar number-of-inodes
 +The number of inode in the FS. If this option is not provided then
 +the number of inodes will be calculated to be roughly 1/3 of the
 +number of blocks.
 +.It Fl s Ar zone-shift
 +The log2 of the number of blocks/zone. The FS can be designed to be
 +made up of data zones that contain a power of two contiguous blocks
 +in them. The default for this parameter is zero.
 +.It Fl N
 +Cause the file system parameters to be printed out
 +without really creating the file system.
 +.Sh SEE ALSO
 +.Xr mount 8 ,
 +.Xr mount_minixfs 8
 +.Sh AUTHOR
 +.An Ed Alley <wea@llnl.gov>
 +.Sh HISTORY
 +The
 +.Nm
 +command first appeared in
 +.Bx 4.6.2  .
 diff -ruN sbin.orig/newfs_minix/super.c sbin/newfs_minix/super.c
 --- sbin.orig/newfs_minix/super.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/super.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,106 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/* The following code was lifted and modified from the minix source with permission. */
 +
 +#include "mkfs.h"
 +
 +int bitmapsize(bit_t);
 +
 +void
 +super(super_block_t *sp, zone_t nzones, mino_t ninodes)
 +{
 +	zone_t maxsize;
 +	zone_t fstblk, fstzon;
 +	short impsize, zmpsize;
 +	int i, inoblks;
 +     
 +	/*
 +	  The maximum file size is the cube of the number of indirects
 +	  plus the square of the number of indirects plus the number of
 +	  indirects plus the number of direct entries in the inode times
 +	  the number of bytes in a zone. This can be a very large number,
 +	  (more than 32 bits of addressing can manage).
 +	*/
 +
 +	/* With triple indirects just put the 2GB limit as the max size */
 +     
 +	maxsize = ~(1 << 31);  /* All bits are ones except the sign bit */
 +     
 +	/* maxsize is then (2^31 - 1) = 2,147,483,647 bytes */
 +     
 +	/*
 +	  bitmapsize() returns the number of blocks in a bitmap
 +	*/
 +     
 +	impsize = bitmapsize((bit_t) (1 + ninodes));
 +	zmpsize = bitmapsize((bit_t) nzones);
 +
 +	printf("blocks in imap = %d\n",impsize);
 +	printf("blocks in zmap = %d\n",zmpsize);
 +
 +	/*
 +	  The number of blocks to the beginning of the inodes
 +	*/
 +
 +	inode_offset = impsize + zmpsize + 2;
 +
 +	printf("inode offset = %d\n", inode_offset);
 +
 +	/* The number blocks that contain inodes */
 +     
 +	inoblks = (ninodes + inodes_per_block - 1)/inodes_per_block;
 +
 +	printf("inode blocks = %d\n",inoblks);
 +
 +	/*
 +	  The number of blocks to the beginning of the data
 +	  gives the location of the first data zone.
 +	*/
 +
 +	fstblk = inode_offset + inoblks;    /* Number of 1K blocks */
 +	fstzon = (fstblk + (1 << zone_shift) - 1) >> zone_shift;
 +
 +	printf("first data zone  = %d\n",(int)fstzon);
 +	printf("first data block = %d\n",(int)(fstzon << zone_shift));
 +
 +	/*
 +	  Construct the V2 superblock
 +	*/
 +     
 +	sp->s_ninodes = ninodes;      /* # of inodes */
 +	sp->s_nzones = 0;             /* Not used in V1; forces errors in V2 */
 +	sp->s_imap_blocks = impsize;  /* # of blocks used by inode bit map */
 +	sp->s_zmap_blocks = zmpsize;  /* # of blocks used by zone  bit map */
 +	sp->s_firstdatazone = fstzon; /* index of the first data zone */
 +	sp->s_log_zone_size = zone_shift; /* log2(blocks/zone) */
 +	sp->s_max_size = maxsize;     /* Maximum file system size */
 +	sp->s_magic = SUPER_V2;       /* Indicates a V2 filesystem */
 +	sp->s_pad = 0;                /* Just padding */
 +	sp->s_zones = nzones;         /* # of zones */
 +	for (i=0; i<1000; i++)        /* Pad the rest of the block with zeros */
 +		sp->pad[i] = '\0';
 +}
 diff -ruN sbin.orig/newfs_minix/zoneio.c sbin/newfs_minix/zoneio.c
 --- sbin.orig/newfs_minix/zoneio.c	Wed Dec 31 16:00:00 1969
 +++ sbin/newfs_minix/zoneio.c	Fri Feb 28 13:44:15 2003
 @@ -0,0 +1,127 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/*
 + * The code below was lifted from Minix's mkfs.c with permission.
 + */
 +
 +#include "mkfs.h"
 +
 +/*
 + * Returns a free zone/block number and marks it active
 + */
 +
 +zone_t
 +get_zone(void)
 +{
 +	zone_t num;
 +	block_t znodemap;
 +	int bit;
 +
 +	/* loop over zones */
 +
 +	for (num=1; num<nrzones; num++) {
 +		znodemap = (num/BITS_PER_BLOCK) + zone_map;
 +		bit      = num % BITS_PER_BLOCK;
 +		if (read_bit(znodemap,bit) == 0) {
 +			insert_bit(znodemap, bit);
 +			return (num+zoff);
 +		}
 +	}
 +
 +	printf("No data blocks available!\n");
 +	exit(1);
 +}
 +
 +/*
 +  Returns the absolute zone number of a new zone
 +*/
 +
 +zone_t
 +alloc_zone(void)
 +{
 +	/* Allocate a new zone */
 +	/* Works for zone > block */
 +     
 +	block_t b;
 +	int i;
 +	zone_t z;
 +
 +	/* Get a free zone/block and mark it active */
 +  
 +	z = get_zone();
 +  
 +	b = z << zone_shift;
 +  
 +	for (i = 0; i < zone_size; i++)
 +		put_block(b + i, zero);	/* give an empty zone */
 +     
 +	return z;  /* Returns the absolute zone number in the file */
 +}
 +
 +void
 +add_zone(mino_t n, zone_t z, long bytes, long cur_time)
 +{
 +	/* Add zone z to inode n. The file has grown by 'bytes' bytes. */
 +
 +	int off, i;
 +	block_t b;
 +	zone_t indir;
 +	zone_t blk[V2_INDIRECTS];
 +	inode_t *p;
 +	inode_t inode[V2_INODES_PER_BLOCK];
 +
 +	b = ((n - 1) / V2_INODES_PER_BLOCK) + inode_offset;
 +	off = (n - 1) % V2_INODES_PER_BLOCK;
 +  
 +	get_block(b, (char *) inode);
 +	p = &inode[off];
 +	p->i_size += bytes;
 +	p->i_mtime = cur_time;
 +	for (i = 0; i < V2_NR_DZONES; i++)
 +		if (p->i_zone[i] == 0) {
 +			p->i_zone[i] = z;
 +			put_block(b, (char *) inode);
 +			return;
 +		}
 +	put_block(b, (char *) inode);
 +
 +  /* File has grown beyond a small file. */
 +
 +	if (p->i_zone[V2_NR_DZONES] == 0) p->i_zone[V2_NR_DZONES] = alloc_zone();
 +	indir = p->i_zone[V2_NR_DZONES];
 +	put_block(b, (char *) inode);
 +	b = indir << zone_shift;
 +	get_block(b, (char *) blk);
 +	for (i = 0; i < V2_INDIRECTS; i++)
 +		if (blk[i] == 0) {
 +			blk[i] = z;
 +			put_block(b, (char *) blk);
 +			return;
 +		}
 +	printf("File has grown beyond single indirect");
 +	exit(1);
 +}
 8><------------------------------------------------- Cut here
 
 
 	        FOLLOWING is the SYS PATCH:
 8><------------------------------------------------- Cut here
 diff -ruN sys.orig/fs/minixfs/README sys/fs/minixfs/README
 --- sys.orig/fs/minixfs/README	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/README	Fri Feb 28 16:02:15 2003
 @@ -0,0 +1,40 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +This is the Minix FS. It was developed on FreeBSD-4.6.x.
 +
 +The fs should be located in: "/usr/src/sys/fs/minixfs". There are two other source
 +files located in /usr/src/sbin/: mount_minixfs(8) is located in the directory:
 +"mount_minix"; and newfs_minix(8) is located in the directory: newfs_minix. The first
 +source is needed to mount the FS and the second one will make the FS. The include file:
 +vnode.h in "/usr/src/sys/sys" is modified in the enum vtagtype statement to include
 +VT_MINIXFS after the last entry (which at this writing is: VT_SMBFS). The Makefile for
 +the Minix FS is located in: "/usr/src/sys/modules/minixfs". The Makefile for sbin must
 +be modified to compile minix_mountfs.c and newfs_minix.c. The Makefile for the modules
 +must be modified to compile the Minix FS module. I modified the i386 sections of these
 +Makefiles because the FS only works on the i386 platform.
 +
 +					Ed
 diff -ruN sys.orig/fs/minixfs/TODO sys/fs/minixfs/TODO
 --- sys.orig/fs/minixfs/TODO	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/TODO	Fri Feb 28 16:28:01 2003
 @@ -0,0 +1,69 @@
 +To do list:       (Not necessarily in order of importance)
 +
 +	1. Modify to allow zone sizes larger than one block.
 +		As of now: zone size = block size = 1024 bytes.
 +		The routine: minix_bmapfs() shows a beginning
 +		in that direction. There is an issue of whether
 +		to save the zone fragments after reading, in case
 +		another block is desired within a previously read
 +		zone. I realize that these issues have already
 +		been delt with in ufs and ext2fs and that these 
 +		algorithms should be understood before writing one
 +		for Minix.
 +			(DONE 030213 by Ed Alley)
 +
 +	2. Fix ip hashing.
 +		As of now I get a panic (page fault from memory manager)
 +		after a dismount then subsequent remount; the panic
 +		occurs when I first reference the file system after
 +		the remount, for example, by executing ls(1) within
 +		the file system. Because of this I have disabled ip hashing
 +		in this source until I can figure out what is going wrong.
 +			(DONE 030228 by Ed Alley)
 +
 +	3. Clean up redundant metadata writes.
 +		This involves reducing the number of 'minix_update()' calls
 +		to a minimum when metadata changes occur; I took a very
 +		conservative approach in building this fs and did not
 +		even consider trying to design it with asynchronous updates
 +		of metadata; as a consequence, there are undoubtably too
 +		many update() calls.
 +
 +	4. Make more routines static.
 +		Need to reduce the number of routines with prototypes
 +		lacking the "static" designation to reduce the number
 +		of minix functions with global names.
 +
 +	5. Write a minix_fsck routine.
 +		Probably not necessary, because Minix already has one
 +		operating on its side of the fence. But it might be
 +		fun nonetheless. :)
 +
 +	6. Make modifications for other platforms.
 +		As of now the Minix fs only works on the i386 platform.
 +	        This might be tricky if endian issues are involved.
 +
 +	7. Write a newfs_minix routine.
 +			(DONE 030210 by Ed Alley)
 +
 +	8. Page fault if module is loaded for days!
 +		I don't understand this one. It seems that
 +		the module will page fault if it is loaded
 +		for days even after being unmounted. If a
 +		fs is mounted, then a page fault will occur.
 +		This can be eliminated by unloading the
 +		module after the last fs is unmounted.
 +			(DONE 020220 by Ed Alley)
 +
 +	9. Clean up the directory manipulating routines:
 +	        Come up with a way to keep track of holes,
 +	  	so we don't have to search the directory
 +	 	each time we need to put an entry in.
 +	        Also, fix up the way that the directory
 +	        size is determined: right now we just count
 +	        the entries until the last is found.
 +	        Fix up the way directories are truncated
 +	        when they are shortened: right now we just
 +	        copy out the existing entries, clean the
 +	        directory out and then reload it with the
 +	        saved entries.
 diff -ruN sys.orig/fs/minixfs/bsd-copyright sys/fs/minixfs/bsd-copyright
 --- sys.orig/fs/minixfs/bsd-copyright	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/bsd-copyright	Fri Feb 28 13:46:38 2003
 @@ -0,0 +1,25 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 diff -ruN sys.orig/fs/minixfs/minix.h sys/fs/minixfs/minix.h
 --- sys.orig/fs/minixfs/minix.h	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix.h	Fri Feb 28 21:07:27 2003
 @@ -0,0 +1,373 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/****************************************************************************
 + *                                                                          *
 + *                  Minix File System include file                          *
 + *                                                                          *
 + *   The guide for this include file comes from Andrew Tannenbaum's MINIX   *
 + *   source which can be gotten from the official MINIX home page:          *
 + *                http://www.cs.vu.nl/~ast/minix.html                       *
 + *   Some of the names have been changed to avoid conflicts with FBSD. ;)   *
 + *                                                                          *
 + *   For further information there is also the book:                        *
 + *      Tannenbaum and Woodhull,                                            *
 + *          "Operating Systems Design and Implememtation", 2nd ed, 1997     *
 + *                  from Prentice Hall, New Jersey                          *
 + *                                                                          *
 + ****************************************************************************/
 +
 +#ifndef _SYS_PARAM_H_
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/kernel.h>
 +#include <sys/proc.h>
 +#include <sys/lock.h>
 +#include <sys/vnode.h>
 +#include <sys/mount.h>
 +#include <sys/conf.h>
 +#include <sys/buf.h>
 +#endif
 +
 +#ifndef _SYS_MALLOC_H_
 +#include <sys/malloc.h>
 +#endif
 +
 +#define MINIXFS_VERSION 2     /* Version 2 Minix file system */
 +                              /* Block size = 1024 bytes. */
 +
 +/* Some maximum sizes */
 +
 +#define MINIX_NAME_MAX  14   /* Max size of a file name */
 +#define MINIX_LINK_MAX 127   /* Max links of a file */
 +#define MINIX_PATH_MAX 255   /* Maximum path length */
 +#define MINIX_PIPE_BUF 512   /* Maximum size of atomic pipe writes */
 +
 +/* Block size defines */
 +
 +#define NO_BLOCK 0            /* Flag indicating no block available */
 +#define NO_ZONE  0            /* Flag indicating no zone available */
 +#define BLOCK_SIZE 1024       /* # bytes in a disk block */
 +#define BITCHUNK_SIZE 2       /* # bytes in a bitchunk */
 +#define BITMAP_CHUNKS 512     /* # bitmap chunks in a disk block */
 +#define BITCHUNK_BITS 16      /* # bits in a bitchunk */
 +#define BITS_PER_BLOCK 8192   /* # bits in a block 8*BLOCK_SIZE */
 +#define BITMAPSHIFT 13        /* log2(BITS_PER_BLOCK) */
 +
 +/* Inode defines */
 +
 +#define ROOT_INO 1            /* Minix uses inode 1 for the root inode */
 +#define NO_INODE 0            /* Inode number to return if none found */
 +#define V2_INODE_SIZE 64      /* size of inode in bytes */
 +#define V2_INODES_PER_BLOCK (BLOCK_SIZE/V2_INODE_SIZE) /* # of inodes per block */
 +#define INODE_MAP 2           /* position of first inode bitmap in file */
 +#define V2_NR_DBLOCKS 7       /* # of direct block pointers in inode */
 +#define V2_NR_TBLOCKS 10      /* # of block pointers: direct+single+double+triple */
 +#define V2_NR_INDIRECTS 256   /* # of indirect pointers in a block */
 +#define INDIRECT_SHIFT 8      /* log2(V2_NR_INDIRECTS) */
 +
 +/* These next defines count the number of addressable blocks */
 +
 +#define NR_DIRECT     V2_NR_DBLOCKS
 +#define NR_SINDIRECT  V2_NR_INDIRECTS
 +#define NR_DINDIRECT (V2_NR_INDIRECTS*NR_SINDIRECT)
 +#define NR_TINDIRECT (V2_NR_INDIRECTS*NR_DINDIRECT)
 +
 +#define TOT_DIRECT     NR_DIRECT
 +#define TOT_SINDIRECT (TOT_DIRECT    + NR_SINDIRECT)
 +#define TOT_DINDIRECT (TOT_SINDIRECT + NR_DINDIRECT)
 +#define TOT_TINDIRECT (TOT_DINDIRECT + NR_TINDIRECT)
 +
 +/* Minix flag bits for i_mode in the dinode. */
 +
 +#define I_TYPE          0170000	/* this field gives inode type */
 +#define I_SOCK          0140000 /* UNIX domain socket */
 +#define I_LINK          0120000 /* 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 ALL_MODES       0006777	/* 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 */
 +
 +/* Block defines */
 +
 +#define V2_BLOCK_NUM_SIZE 4  /* size of block address in bytes */
 +#define V2_INDIRECTS   (BLOCK_SIZE/V2_BLOCK_NUM_SIZE)  /* # blocks per indir block */
 +
 +/* File system types. (Only SUPER_V2 is recognized in this implementation */
 +
 +#define SUPER_MAGIC   0x137F	/* magic number contained in super-block */
 +#define SUPER_REV     0x7F13	/* magic # when 68000 disk read on PC or vv */
 +#define SUPER_V2      0x2468	/* magic # for V2 file systems */
 +#define SUPER_V2_REV  0x6824	/* V2 magic written on PC, read on 68K or vv */
 +
 +/* The type of sizeof may be (unsigned) long.  Use the following macro for
 + * taking the sizes of small objects so that there are no surprises like
 + * (small) long constants being passed to routines expecting an int.
 + */
 +
 +#define usizeof(t) ((unsigned) sizeof(t))
 +
 +/* Types used in disk, inode, etc. data structures. */
 +
 +typedef u_int16_t   mino_t;     /* Minix i-node number is 16 bits */
 +typedef u_int32_t   block_t;    /* block number */
 +typedef u_int32_t   bit_t;      /* bit number in a bitmap */
 +typedef u_int16_t   bitchunk_t; /* a collection of bits from a bitmap */
 +typedef long        mtime_t;    /* time in sec since 1 Jan 1970 0000 GMT */
 +
 +/* Directory layout (Minix only allows 14 characters in a file name) */
 +
 +struct minix_direct {
 +	u_int16_t d_ino;                /*  2 */
 +	char d_name[MINIX_NAME_MAX];    /* 14 */
 +};
 +
 +struct minix_dirtemplate {   /* 32 bytes */
 +	u_int16_t    dot_ino;
 +	char         dot_name[MINIX_NAME_MAX];
 +	u_int16_t    dotdot_ino;
 +	char         dotdot_name[MINIX_NAME_MAX];
 +};
 +
 +#define DIR_ENTRY_SIZE usizeof(struct minix_direct) /* size of dir entry in bytes = 16 */
 +#define NR_DIR_ENTRIES (BLOCK_SIZE/DIR_ENTRY_SIZE) /* # of dirs/block = 64 */
 +#define MAX_DIR_ENTRIES ((V2_NR_DBLOCKS + V2_NR_INDIRECTS) * NR_DIR_ENTRIES)
 +
 +#define MINIX_LINK_MAX 127 /* Maximum number of file links */
 +#define MINIX_MAXSYMLINKLEN (4*V2_NR_TBLOCKS)  /* Max chars in a short symlink */
 +#define MINIX_MAXSYMLINK BLOCK_SIZE          /* Max chars in a long symlink  */
 +
 +/* Structure of an inode on disk. length = 64 bytes. */
 +
 +struct minix_dinode {
 +	u_int16_t i_mode;     /* file type, protection, etc. 2b */
 +	int16_t i_nlinks;     /* how many links to this file 2b */
 +	int16_t i_uid;	      /* user id of the file's owner 2b */
 +	int16_t i_gid;	      /* group number                2b */
 +	u_int32_t i_size;     /* current file size in bytes  4b */
 +	int32_t i_atime;      /* time of last access (V2 only) 4b */
 +	int32_t i_mtime;      /* when was file data last changed 4b */
 +	int32_t i_ctime;      /* when was inode itself changed (V2 only) 4b */
 +	u_int32_t i_block[V2_NR_TBLOCKS]; /* direct,+ 1,2,3 indirect 40b */
 +};
 +
 +/* Structure of an in-core inode. */
 +
 +struct minix_inode {
 +        struct lock i_lock;             /* Inode lock. Must be first. */
 +	LIST_ENTRY(minix_inode) i_hash; /* Hash chain */
 +	struct minixmount *i_mmp;
 +	struct vnode *i_vnode;          /* Vnode associated with this inode */
 +	mode_t    i_mode;               /* BSD style mode of file */
 +	u_int32_t i_flag;               /* flags */
 +	u_int32_t i_blocks;             /* Total number of blocks in file */
 +	dev_t     i_dev;                /* specinfo for device associated with this inode */
 +	ino_t     i_number;             /* The identity of this inode */
 +	ino_t     i_parent;             /* The parent inode */
 +	int       i_count;              /* Reference count */
 +	int       i_entry;              /* Directory entry number from namei */
 +	int       i_noent;              /* First no entry number if a directory */
 +	struct minix_super_block *i_su; /* Super block */
 +	struct minix_dinode i_dino;     /* The on-disk inode */
 +};
 +
 +/* Some useful defines */
 +
 +#define i_nlink i_dino.i_nlinks
 +#define i_zone i_dino.i_block
 +#define i_shortlink i_dino.i_block
 +#define i_rdev i_dino.i_block[0]
 +
 +#define ino_to_byte(fs,ino) ((fs->s_firstinode + (ino-1)/V2_INODES_PER_BLOCK)*BLOCK_SIZE)
 +#define blk_to_byte(blk) ((blk)*BLOCK_SIZE)
 +#define byte_to_blkn(byte) ((u_daddr_t)((byte) >> DEV_BSHIFT))
 +#define ino_off(ino) (((ino-1) % V2_INODES_PER_BLOCK) * V2_INODE_SIZE)
 +#define VTOMI(vp) ((struct minix_inode*)(vp)->v_data)
 +
 +/* These flags are kept in i_flag. (some are not recognized by Minix) */
 +#define	IN_ACCESS	0x0001		/* Access time update request. */
 +#define	IN_CHANGE	0x0002		/* Inode change time update request. */
 +#define	IN_UPDATE	0x0004		/* Modification time update request. */
 +#define	IN_MODIFIED	0x0008		/* Inode has been modified. */
 +#define	IN_RENAME	0x0010		/* Inode is being renamed. */
 +#define	IN_SHLOCK	0x0020		/* File has shared lock. */
 +#define	IN_EXLOCK	0x0040		/* File has exclusive lock. */
 +#define	IN_HASHED	0x0080		/* Inode is on hash list */
 +#define	IN_LAZYMOD	0x0100		/* Modified, but don't write yet. */
 +
 +/* These are the BSD-type mode bits present in the incore inode */
 +
 +/* File permissions. */
 +#define	IEXEC		0000100		/* Executable. */
 +#define	IWRITE		0000200		/* Writeable. */
 +#define	IREAD		0000400		/* Readable. */
 +#define	ISVTX		0001000		/* Sticky bit. */
 +#define	ISGID		0002000		/* Set-gid. */
 +#define	ISUID		0004000		/* Set-uid. */
 +
 +/* File types. */
 +#define	IFMT		0170000		/* Mask of file type. */
 +#define	IFIFO		0010000		/* Named pipe (fifo). */
 +#define	IFCHR		0020000		/* Character device. */
 +#define	IFDIR		0040000		/* Directory file. */
 +#define	IFBLK		0060000		/* Block device. */
 +#define	IFREG		0100000		/* Regular file. */
 +#define	IFLNK		0120000		/* Symbolic link. */
 +#define	IFSOCK		0140000		/* UNIX domain socket. */
 +#define	IFWHT		0160000		/* Whiteout. */
 +
 +#define LSUPER_V2  BLOCK_SIZE        /* Byte location of V2 super block on disk */
 +#define LSV2BLOCK ((u_daddr_t)(LSUPER_V2/DEV_BSIZE)) /* Record count on device */
 +
 +/* Structure of the superblock length on disk is 24b */
 +
 +struct minix_super_block {
 +	u_short s_ninodes;	 /* # usable inodes on the minor device 2b */
 +	u_short s_nzones;	 /* number of V1 fs zones 2b */
 +	short s_imap_blocks;	 /* # of blocks used by inode bit map 2b */
 +	short s_zmap_blocks;	 /* # of blocks used by zone bit map 2b */
 +	u_short s_firstdatazone; /* number of first data zone 2b */
 +	short s_zshift;	         /* log2 of blocks/zone 2b */
 +	u_long s_max_size;	 /* maximum file size on this device 4b */
 +	short s_magic;		 /* magic number 2b */
 +	short s_pad;		 /* pad it to a 4-byte boundary 2b */
 +	u_long s_zones;		 /* number of V2 fs zones 4b */
 +	
 +	/* The rest of the structure belongs to the in-core superblock */
 +
 +	struct vnode *s_devvp;   /* Vnode of device mounted on */
 +	struct minix_inode *s_root;   /* Inode for root dir of mounted file system */
 +	ino_t s_imnton;          /* UFS inode number mounted on */
 +	u_int16_t *s_ibmap;      /* Inode bit-map */
 +	u_int16_t *s_zbmap;      /* Zone bit-map */
 +	u_int32_t imap_lock;     /* Inode bit-map lock variable */
 +	u_int32_t zmap_lock;     /* Zone bit-map lock variable */
 +	dev_t s_dev;             /* Specinfo of device of mounted filesystem */
 +	int s_rdonly;            /* Read only flag */
 +	int s_version;           /* Version number of file system */
 +	int s_firstinode;        /* Block no of first inode */
 +	int s_zoff;              /* Data block offset = s_firstdatazone - 1. */
 +	int s_bsize;             /* Block size */
 +	int s_zsize;             /* Zone size */
 +};
 +
 +/* A block can be inodes, directories, a bootblock, a superblock or ... */
 +
 +union minix_block {
 +	struct minix_dinode dinode[16];   /* 16 dinodes */
 +	struct minix_super_block sp;      /*  1 superblock + space */
 +	struct boot_block_s {             /*  1 bootblock + space */
 +		char bootblock[294];
 +		char pad[730];
 +	} boot_block;
 +	struct minix_direct dir[64];      /*   64 directories */
 +	u_int32_t ind[256];               /*  256 indirect blocks */
 +	u_int16_t bitchunk[512];          /*  512 bitchunks */
 +	u_int8_t  data[1024];             /* 1024 bytes */
 +};
 +
 +#define MBLOCK(bp) ((union minix_block*)((bp)->b_data))
 +
 +struct minixmount {
 +	struct minix_super_block *mnx_su;            /* Superblock */
 +	struct mount             *mnx_mp;            /* VFS mount structure */
 +	struct vnode             *mnx_devvp;         /* Device vnode mounted on */
 +	dev_t                     mnx_dev;           /* Specinfo of device */
 +	struct malloc_type       *mnx_malloctype;
 +};
 +
 +/* Inode hash routines */
 +
 +void minix_ihashinit(void);
 +void minix_ihashuninit(void);
 +struct vnode *minix_ihashlookup(dev_t, ino_t);
 +struct vnode *minix_ihashget(dev_t, ino_t);
 +void minix_ihashins(struct minix_inode *);
 +void minix_ihashrem(struct minix_inode *);
 +
 +/* Support routine prototypes */
 +
 +int minix_vinit(struct mount*, vop_t**, vop_t**, struct vnode**);
 +int minix_vget(struct mount*, ino_t, struct vnode**);
 +int minix_vfree(struct vnode*, ino_t, int);
 +int minix_getblk(struct vnode*,block_t,struct buf**);
 +int minix_putblk(struct buf*);
 +void minix_freeblk(struct buf*);
 +int minix_valloc(struct vnode*,int,struct ucred*, struct vnode**);
 +int minix_balloc(struct vnode*,u_daddr_t,struct buf**);
 +int minix_blkatoff(struct vnode*,off_t,char**,struct buf**);
 +int minix_zalloc(struct minix_super_block*,u_daddr_t*,u_daddr_t*);
 +int minix_dzalloc(struct minix_super_block*,u_daddr_t);
 +int minix_makeinode(int,struct vnode*,struct vnode**,struct componentname*);
 +int minix_addzone(struct minix_inode*,u_daddr_t,u_daddr_t);
 +int minix_ialloc(struct minix_super_block*,int*);
 +int minix_dialloc(struct minix_super_block*,int);
 +int minix_update(struct vnode*);
 +void minix_itimes(struct vnode*);
 +int minix_truncate(struct vnode*,off_t,int,struct ucred*,struct proc*);
 +int minix_iget(struct vnode*,struct minix_super_block*,
 +               mino_t,struct minix_inode*);
 +int minix_iput(struct minix_inode*);
 +void minix_wipe_dinode(struct minix_dinode*);
 +int minix_dinode_access(struct minix_dinode*,int,
 +          struct ucred*,struct minix_super_block*);
 +int minix_free_inode_count(struct minix_super_block*);
 +int minix_free_zone_count(struct minix_super_block*);
 +int minix_next_free_inode(struct minix_super_block*);
 +int minix_next_free_zone(struct minix_super_block*);
 +int minix_bmapfs(struct vnode*,u_daddr_t,u_daddr_t*,int*);
 +int minix_get_vtype(struct minix_inode*);
 +int minix_num_blocks(u_int16_t, u_int32_t, short);
 +void minix_get_lock(u_int32_t*);
 +void minix_free_lock(u_int32_t*);
 +void minix_makedirentry(struct minix_inode*,struct componentname*,
 +                        struct minix_direct*);
 +int minix_direnter(struct vnode*,struct vnode*,struct minix_direct*,
 +                   struct componentname*);
 +int minix_dirremove(struct vnode*);
 +int minix_dirempty(struct minix_inode*,ino_t,struct ucred*);
 +int minix_dirrewrite(struct minix_inode*,struct minix_inode*,ino_t,int);
 +int minix_checkpath(struct minix_inode*,struct minix_inode*,struct ucred*);
 +
 +/* VOP pointers */
 +
 +extern vop_t **minix_vnodeop_p;
 +extern vop_t **minix_specop_p;
 +extern vop_t **minix_fifoop_p;
 +
 +/* Misc declarations */
 +
 +MALLOC_DECLARE(M_MINIXMNT);
 +MALLOC_DECLARE(M_MINIXNOD);
 diff -ruN sys.orig/fs/minixfs/minix_alock.s sys/fs/minixfs/minix_alock.s
 --- sys.orig/fs/minixfs/minix_alock.s	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_alock.s	Fri Feb 28 13:46:38 2003
 @@ -0,0 +1,63 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 + /*************************************************************
 + *                                                           *
 + *   OK so we have another TSL lock routine.                 *
 + *                                                           *
 + *   C-Prototype:   (long) _alock(long*);                    *
 + *                                                           *
 + *   I am not spin waiting here because I want the choice    *
 + *   of either spin waiting or giving up the processor.      *
 + *   This we can do by putting the call to this routine      *
 + *   in the argument of a while loop. The loop can either    *
 + *   spin or call a cpu giveup routine until the lock is     *
 + *   obtained:	                                             *
 + *               while (_minix_alock(&lock_var)) {           *
 + *    		    tsleep(&loc_var);                        *
 + *               }                                           *
 + *							     *
 + *  See the file: minix_locks.c, for the implementation.     *
 + *                                                           *
 + *************************************************************/
 +
 +.globl _minix_alock
 +.align 16
 +_minix_alock:
 +	pushl %ebp
 +	movl  %esp, %ebp
 +
 +	pushl %ecx
 +
 +	movl  8(%ebp), %ecx
 +	movl  $1,  %eax
 +
 +	lock xchg (%ecx), %eax
 +
 +	popl %ecx
 +
 +	popl  %ebp
 +	ret
 diff -ruN sys.orig/fs/minixfs/minix_bio.c sys/fs/minixfs/minix_bio.c
 --- sys.orig/fs/minixfs/minix_bio.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_bio.c	Fri Feb 28 21:27:15 2003
 @@ -0,0 +1,732 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/kernel.h>
 +#include <sys/vnode.h>
 +#include <sys/malloc.h>
 +#include <sys/module.h>
 +#include <sys/buf.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +int  minix_read_zbit(struct minix_super_block*,u_int32_t);
 +void minix_write_zbit(struct minix_super_block*,u_int32_t);
 +void minix_delete_zbit(struct minix_super_block*,u_int32_t);
 +
 +/*
 + * Allocate new blocks from lbof0+1 to lbof1.
 + * If lbof0 doesn't exist, then allocate it first.
 + */
 +int
 +minix_balloc(struct vnode *vp, u_daddr_t lbof1, struct buf **bpp)
 +{
 +	struct buf *bp;
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	u_daddr_t lbof0, lbn, pbn, lb, zone, boff, z0, z1, bsize;
 +	int error;
 +
 +	*bpp = NULL;
 +
 +	if (dip->i_size == 0) {  /* No zones so create a new one */
 +		zone = 0;
 +		if ((error = minix_zalloc(sp, &lbn, &pbn)) != 0)
 +			return error;
 +		if ((error = minix_addzone(ip, zone, lbn >> sp->s_zshift)) != 0)
 +			return error;
 +		if ((error = bread(devvp, pbn, sp->s_zsize, NOCRED, &bp)) != 0)
 +			return error;
 +		bzero(bp->b_data, (size_t)sp->s_zsize);
 +		bwrite(bp);
 +	}
 +
 +	if (dip->i_size > 0)
 +		lbof0 = (dip->i_size - 1)/BLOCK_SIZE;
 +	else
 +		lbof0 = 0;
 +
 +	z0 = lbof0 >> sp->s_zshift;
 +	z1 = lbof1 >> sp->s_zshift;
 +
 +	if (z1 <= z0) {  /* Zone already exists! just return the block */
 +		if ((error = minix_bmapfs(vp, lbof1, &pbn, NULL)) != 0)
 +			return error;
 +		if ((error = bread(devvp, pbn, BLOCK_SIZE, NOCRED, &bp)) != 0)
 +			return error;
 +		bzero(bp->b_data, (size_t)BLOCK_SIZE);
 +		*bpp = bp;
 +		return 0;
 +	}
 +
 +	/* The new zone extends beyond the file */
 +
 +	/* Allocate all the blocks between lbof0 and lbof1 and zero them out */
 +
 +	for (lb=lbof0+1; lb<lbof1; lb++) {
 +		zone = lb >> sp->s_zshift;
 +		boff = lb - (zone << sp->s_zshift);
 +		if (boff > 0) { /* Zone already exixts */
 +			bsize = BLOCK_SIZE;
 +			if ((error = minix_bmapfs(vp, lb, &pbn, NULL)) != 0)
 +				return error;
 +		} else {
 +			bsize = sp->s_zsize;
 +			if ((error = minix_zalloc(sp, &lbn, &pbn)) != 0)
 +				return error;
 +			if ((error = minix_addzone(ip, zone, lbn >> sp->s_zshift)) != 0) /* add the new zone to inode */
 +				return error;	
 +		}
 +		if ((error = bread(devvp, pbn, bsize, NOCRED, &bp)) != 0)
 +			return error;
 +		bzero(bp->b_data, (size_t)bsize);
 +		bwrite(bp);
 +	}
 +	/* Finally allocate lbof1, the required new block */
 +
 +	zone = lbof1 >> sp->s_zshift;
 +	boff = lbof1 - (zone << sp->s_zshift);
 +	if (boff > 0) {   /* Zone already exists, just get the block */
 +		bsize = BLOCK_SIZE;
 +		if ((error = minix_bmapfs(vp, lbof1, &pbn, NULL)) != 0)
 +			return error;
 +	} else {
 +		bsize = sp->s_zsize;
 +		if ((error = minix_zalloc(sp, &lbn, &pbn)) != 0)
 +			return error;
 +		if ((error = minix_addzone(ip, zone, lbn >> sp->s_zshift)) != 0) /* add the new zone to inode */
 +			return error;
 +	}
 +	if ((error = bread(devvp, pbn, bsize, NOCRED, &bp)) != 0)
 +		return error;
 +	bzero(bp->b_data, (size_t)bsize);
 +
 +	*bpp = bp;
 +	return 0;
 +
 +}
 +/*
 + * Returns the block number of the next free zone and sets
 + * the corresponding bit in the zone bitmap.
 + */
 +int
 +minix_zalloc(struct minix_super_block *sp, u_daddr_t *lblkp, u_daddr_t *pblkp)
 +{
 +	int ic, error;
 +	u_daddr_t zone, bblk;
 +	daddr_t off;
 +	struct buf *bp;
 +	struct vnode *devvp = sp->s_devvp;
 +	union minix_block *mbp;
 +	u_daddr_t pbn = 0, pzn = 0;
 +	u_int16_t *buf = sp->s_zbmap;
 +
 +	*lblkp = 0;
 +	*pblkp = 0;
 +
 +	minix_get_lock(&sp->zmap_lock);
 +
 +	if ((zone = minix_next_free_zone(sp)) == NO_ZONE) {
 +		minix_free_lock(&sp->zmap_lock);
 +		return ENOSPC;
 +	}
 +
 +	minix_write_zbit(sp, zone);
 +
 +	ic = zone >> 4;                 /* Chunk that bit resides in */
 +	bblk = zone / BITS_PER_BLOCK;   /* Block that bit is in */
 +	off  = zone % BITS_PER_BLOCK;   /* Bit offset in block */
 +	off >>= 4;                      /* Chunk offset in block */
 +	bblk += 2 + sp->s_imap_blocks;  /* Adjust for offset in file  */
 +
 +	bp = NULL;
 +	if ((error = minix_getblk(devvp, bblk, &bp)) != 0) {
 +		if (bp != NULL)
 +			brelse(bp);
 +		minix_delete_zbit(sp, zone);
 +		minix_free_lock(&sp->zmap_lock);
 +		return error;
 +	}
 +
 +	mbp = MBLOCK(bp);
 +	mbp->bitchunk[off] = buf[ic];
 +
 +	if ((error = minix_putblk(bp)) != 0) {
 +		minix_delete_zbit(sp, zone);
 +		if (bp != NULL) {
 +		     bp->b_flags |= B_INVAL;
 +		     brelse(bp);
 +		}
 +		minix_free_lock(&sp->zmap_lock);
 +		return error;
 +	}
 +
 +	minix_free_lock(&sp->zmap_lock);
 +
 +	pzn = zone + sp->s_zoff;    /* Physical zone number */
 +	pbn = pzn << sp->s_zshift;  /* Physical block number */
 +	
 +	*lblkp = pbn;
 +	*pblkp = byte_to_blkn(blk_to_byte(pbn)); /* Suitable for bread */
 +
 +	return 0;
 +}
 +/*
 + * Deallocates a zone if the last block in it is released.
 + */
 +int
 +minix_dzalloc(struct minix_super_block *sp, u_daddr_t zone)
 +{
 +        int ic, error;
 +	u_daddr_t bblk;
 +	daddr_t off;
 +	struct buf *bp;
 +	struct vnode *devvp = sp->s_devvp;
 +	u_int16_t *buf = sp->s_zbmap;
 +	union minix_block *mbp;
 +
 +	minix_get_lock(&sp->zmap_lock);
 +
 +	zone -= sp->s_zoff;              /* Convert to bit offset */
 +
 +	if (minix_read_zbit(sp, zone))
 +		minix_delete_zbit(sp, zone);
 +	else {
 +		minix_free_lock(&sp->zmap_lock);
 +		return 0;
 +	}
 +	
 +	ic = zone >> 4;                 /* Chunk that bit resides in */
 +	bblk = zone / BITS_PER_BLOCK;   /* Block that bit is in */
 +	off  = zone % BITS_PER_BLOCK;   /* Bit offset in block */
 +	off >>= 4;                      /* Chunk offset in block */
 +	bblk += 2 + sp->s_imap_blocks;  /* Adjust for offset in file  */
 +
 +	bp = NULL;
 +	if ((error = minix_getblk(devvp, bblk, &bp)) != 0) {
 +		if (bp != NULL) {
 +			bp->b_flags |= B_INVAL;
 +			brelse(bp);
 +		}
 +	        minix_write_zbit(sp, zone);
 +		minix_free_lock(&sp->zmap_lock);
 +		return error;
 +	}
 +
 +	mbp = MBLOCK(bp);
 +	mbp->bitchunk[off] = buf[ic];
 +
 +	if ((error = minix_putblk(bp)) != 0) {
 +		minix_write_zbit(sp, zone);
 +		if (bp != NULL) {
 +			bp->b_flags |= B_INVAL;
 +			brelse(bp);
 +		}
 +		minix_free_lock(&sp->zmap_lock);
 +		return error;
 +	}
 +
 +	minix_free_lock(&sp->zmap_lock);
 +	
 +	return 0;
 +}
 +/*
 + * Add a zone to the end of a file. "zone" is the logical zone
 + * offset in the file and pbn is the physical zone offset in the
 + * file system. It is the responsibility of the calling
 + * routine to guarantee that the next zone to add is at the
 + * logical end of the file. This routine returns EIO otherwise.
 + */
 +int
 +minix_addzone(struct minix_inode *ip, u_daddr_t zone, u_daddr_t pbn)
 +{
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	union minix_block *mbp;
 +	struct buf *bp;
 +	u_daddr_t pind;
 +	u_daddr_t id0, id1, id2, id3, off, blk;
 +	int error, indirect = 0;
 +
 +	pind = zone + 1;
 +
 +	if (pind > TOT_DIRECT)
 +		indirect++;
 +	if (pind > TOT_SINDIRECT)
 +		indirect++;
 +	if (pind > TOT_DINDIRECT)
 +		indirect++;
 +	if (pind > TOT_TINDIRECT)
 +		indirect++;
 +
 +	switch (indirect) {
 +	case 0:
 +		if (dip->i_block[zone] != 0)
 +			return EIO;
 +		dip->i_block[zone] = pbn;
 +		break;
 +	case 3:
 +		off = zone - TOT_DINDIRECT;
 +		id2 = off >> INDIRECT_SHIFT;
 +		id3 = id2 >> INDIRECT_SHIFT;
 +		id2 = id2 %  V2_NR_INDIRECTS;
 +		id1 = off %  V2_NR_INDIRECTS;
 +		if (dip->i_block[V2_NR_DBLOCKS+2] == 0) {
 +			/* Generate a triple indirect block */
 +			if ((error = minix_zalloc(sp, &blk, &pind)) != 0)
 +				return error;
 +			if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +				return error;
 +			bzero(bp->b_data, BLOCK_SIZE);
 +			id0 = blk >> sp->s_zshift;
 +			dip->i_block[V2_NR_DBLOCKS+2] = id0;
 +			bwrite(bp);
 +		} else
 +			id0 = dip->i_block[V2_NR_DBLOCKS+2];
 +
 +		blk = id0 << sp->s_zshift;
 +		if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +			return error;
 +		mbp = MBLOCK(bp);
 +		id0 = mbp->ind[id3];
 +		if (id0 == 0) {
 +			/* Generate a double indirect block */
 +			if ((error = minix_zalloc(sp, &blk, &pind)) != 0)
 +				return error;
 +			id0 = blk >> sp->s_zshift;
 +			mbp->ind[id3] = id0;
 +			bwrite(bp);
 +			if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +				return error;
 +			bzero(bp->b_data, BLOCK_SIZE);
 +			bwrite(bp);
 +		} else
 +			bqrelse(bp);
 +		goto rind2;
 +		break;
 +	case 2:
 +		off = zone - TOT_SINDIRECT;
 +		id2 = off >> INDIRECT_SHIFT;
 +		id1 = off % V2_NR_INDIRECTS;
 +		if (dip->i_block[V2_NR_DBLOCKS+1] == 0) {
 +			/* Generate double indirect block */
 +			if ((error = minix_zalloc(sp, &blk, &pind)) != 0)
 +				return error;
 +			if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +				return error;
 +			bzero(bp->b_data, BLOCK_SIZE);
 +			id0 = blk >> sp->s_zshift;
 +			dip->i_block[V2_NR_DBLOCKS+1] = id0;
 +			bwrite(bp);
 +		} else
 +			id0 = dip->i_block[V2_NR_DBLOCKS+1];
 +	rind2:
 +		blk = id0 << sp->s_zshift;
 +		if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +			return error;
 +		mbp = MBLOCK(bp);
 +		id0 = mbp->ind[id2];
 +		if (id0 == 0) {
 +			/* Generate a single indirect block */
 +			if ((error = minix_zalloc(sp, &blk, &pind)) != 0)
 +				return error;
 +			id0 = blk >> sp->s_zshift;
 +			mbp->ind[id2] = id0;
 +			bwrite(bp);
 +			if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +				return error;
 +			bzero(bp->b_data, BLOCK_SIZE);
 +			bwrite(bp);
 +		} else
 +			bqrelse(bp);
 +		goto rind1;
 +		break;
 +	case 1:
 +		id1 = zone - TOT_DIRECT;
 +		if (dip->i_block[V2_NR_DBLOCKS] == 0) {
 +			/* Generate a single indirect block */
 +			if ((error = minix_zalloc(sp, &blk, &pind)) != 0)
 +				return error;
 +			id0 = blk >> sp->s_zshift;
 +			if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +				return error;
 +			bzero(bp->b_data, BLOCK_SIZE);
 +			dip->i_block[V2_NR_DBLOCKS] = id0;
 +			bwrite(bp);
 +		} else
 +			id0 = dip->i_block[V2_NR_DBLOCKS];
 +	rind1:
 +		blk = id0 << sp->s_zshift;
 +		if ((error = minix_getblk(devvp, blk, &bp)) != 0)
 +			return error;
 +		mbp = MBLOCK(bp);
 +		mbp->ind[id1] = pbn;
 +		bwrite(bp);
 +		break;
 +	default:
 +		printf("minix_addzone: too large: zone = %d\n",(int)zone);
 +		return ENOSPC;
 +	}
 +
 +	ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +
 +	return 0;
 +}
 +/*
 + *  bmap returns the buffer block offset given the logical block offset.
 + *  The offset returned is converted to buffer block units with DEV_BSHIFT.
 + */
 +int
 +minix_bmapfs(struct vnode *vp,        /* vnode of file */
 +	     u_daddr_t lbk,           /* logical block number */
 +             u_daddr_t *pbk,          /* returned physical block number */
 +             int *runp)               /* number of dev chunks to add */
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	union minix_block *mbp;
 +	struct buf *bp;
 +
 +	int ndb   = TOT_DIRECT;
 +	int nsidb = TOT_SINDIRECT;
 +	int ndidb = TOT_DINDIRECT;
 +	int ntidb = TOT_TINDIRECT;
 +     
 +	int ndbpb;
 +	u_daddr_t id, idp, id0=0, id1, id2, id3, blk;
 +	daddr_t offset;
 +	int error, indirect = 0;
 +
 +	if (runp != NULL) {
 +		ndbpb = BLOCK_SIZE >> DEV_BSHIFT; /* buffer blocks per minix block */
 +		if (ndbpb > 0)
 +		     *runp = ndbpb - 1;
 +		else
 +		     *runp = 0;
 +	}
 +
 +	id = lbk >> sp->s_zshift;            /* index by zones */
 +	offset = lbk - (id << sp->s_zshift); /* Block offset in zone */
 +	
 +	idp = id + 1;
 +
 +	if (idp > ndb)
 +		indirect++;
 +	if (idp > nsidb)
 +		indirect++;
 +	if (idp > ndidb)
 +		indirect++;
 +	if (idp > ntidb)
 +		indirect++;
 +
 +	*pbk = 0;
 +	switch (indirect) {
 +	case 0:                /* Direct */
 +		if ((*pbk = (dip->i_block[id] << sp->s_zshift)) == 0)
 +			return EFAULT;
 +		*pbk += offset;
 +		*pbk = ((*pbk)*BLOCK_SIZE) >> DEV_BSHIFT;
 +		return 0;
 +	case 3:                /* Triple indirect */
 +		if ((blk = (dip->i_block[V2_NR_DBLOCKS+2] << sp->s_zshift)) == 0)
 +			return EFAULT;
 +		if ((error = minix_getblk(devvp,blk,&bp)) != 0) {
 +			brelse(bp);
 +			return error;
 +		}
 +		mbp = MBLOCK(bp);
 +		id -= ndidb;
 +		id3 = (id >> INDIRECT_SHIFT) >> INDIRECT_SHIFT;
 +		id2 = (id >> INDIRECT_SHIFT) % V2_NR_INDIRECTS;
 +		id1 = id % V2_NR_INDIRECTS;
 +		id0 = mbp->ind[id3];
 +		bqrelse(bp);
 +		goto rind2;
 +	case 2:                /* Double indirect */
 +		id  -= nsidb;
 +		id2 = id >> INDIRECT_SHIFT;
 +		id1 = id % V2_NR_INDIRECTS;
 +		id0 = dip->i_block[V2_NR_DBLOCKS+1];
 +	rind2:
 +		if ((blk = (id0 << sp->s_zshift)) == 0)
 +			return EFAULT;
 +		if ((error = minix_getblk(devvp,blk,&bp)) != 0) {
 +			brelse(bp);
 +			return error;
 +		}
 +		mbp = MBLOCK(bp);
 +		id0 = mbp->ind[id2];
 +		bqrelse(bp);
 +		goto rind1;
 +	case 1:                /* Single indirect */
 +		id1 = id - ndb;
 +		id0 = dip->i_block[V2_NR_DBLOCKS];
 +	rind1:
 +		if ((blk = (id0 << sp->s_zshift)) == 0)
 +			return EFAULT;
 +		if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +			return error;
 +		mbp = MBLOCK(bp);
 +		if ((*pbk = (mbp->ind[id1] << sp->s_zshift)) == 0) {
 +			brelse(bp);
 +			return EFAULT;
 +		}
 +		bqrelse(bp);
 +		*pbk += offset;
 +		*pbk = ((*pbk)*BLOCK_SIZE) >> DEV_BSHIFT;
 +		return 0;
 +	default:
 +		return ENOSPC;
 +	}
 +
 +	/* NOTREACHED */
 +}
 +/*
 + * Returns a logical block in a buffer
 + */
 +int
 +minix_getblk(struct vnode *devvp, block_t blk, struct buf **bpp)
 +{
 +	u_daddr_t offset;
 +	int error;
 +
 +	offset = (u_daddr_t)byte_to_blkn(blk_to_byte(blk));
 +	if ((error = bread(devvp, offset, BLOCK_SIZE, NOCRED, bpp)) != 0)
 +		return error;
 +	return 0;
 +}
 +/*
 + * Writes the buffer to disk
 + */
 +int
 +minix_putblk(struct buf *bp)
 +{
 +	bp->b_flags &= ~B_ASYNC;
 +	return bwrite(bp);
 +}
 +/*
 + * Releases the buffer block from any connection with the minixfs
 + */
 +void
 +minix_freeblk(struct buf *bp) {
 +	bp->b_flags |= B_FREEBUF;
 +	brelse(bp);
 +}
 +/*
 + * Return buffer with the contents of block "offset" from the beginning of
 + * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
 + * remaining space in the directory.
 + */
 +int
 +minix_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
 +{
 +	struct buf *bp;
 +	u_daddr_t lbn, pbn;
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct vnode *devvp = ip->i_su->s_devvp;
 +	int error;
 +	
 +	lbn = ((u_daddr_t)offset) / BLOCK_SIZE;
 +
 +        if ((error = minix_bmapfs(vp, lbn, &pbn, (int*)NULL)) != 0)
 +		return error;
 +
 +	*bpp = NULL;
 +	bp   = NULL;
 +	if ((error = bread(devvp, pbn, BLOCK_SIZE, NOCRED, &bp)) != 0) {
 +		if (bp != NULL)
 +			brelse(bp);
 +		return error;
 +	}
 +	if (res != NULL)
 +		*res = (char *)bp->b_data + (int)(offset % BLOCK_SIZE);
 +	*bpp = bp;
 +	return 0;
 +}
 +/*
 + * The next few routines read or alter the in-core
 + * zone bitmaps. Any locking that is required is
 + * assumed to occur in the calling programs.
 + */
 +
 +/*
 + * Return the number of free zones
 + */
 +int
 +minix_free_zone_count(struct minix_super_block *sp)
 +{
 +     short nbits[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
 +     u_int16_t *bits = sp->s_zbmap;
 +     int b1,b2,b3,b4,j,n;
 +     int sum;
 +
 +     sum = sp->s_zones - sp->s_firstdatazone + 1;
 +
 +     n = ((sum-1)>>4) + 1;
 +     for (j=0; j<n; j++) {
 +	     b4 = (bits[j] >> 12) & 0xf;
 +	     b3 = (bits[j] >>  8) & 0xf;
 +	     b2 = (bits[j] >>  4) & 0xf;
 +	     b1 =  bits[j]        & 0xf;
 +	     sum -= (nbits[b1] + nbits[b2] +
 +		     nbits[b3] + nbits[b4]);
 +     }
 +     return(sum < 0 ? 0 : sum+1); /* Add one to counter bit zero in the bitmap */
 +}
 +/*
 + * Returns the next free zone
 + */
 +int
 +minix_next_free_zone(struct minix_super_block *sp)
 +{
 +	int i, n, s, nb;
 +	u_int16_t *buf = sp->s_zbmap;
 +	register int bit;
 +
 +	nb = sp->s_zones - sp->s_firstdatazone + 1;
 +	n = nb >> 4;
 +	if ((nb % 16) > 0)
 +		n += 1;
 +
 +	/* Look for a hole in a chunk, then */
 +	/* search the chunk for the bit */
 +
 +	for (i=0; i<n; i++)
 +		if (buf[i] != 0xffff)
 +			for (s=0; s<16; s++)
 +				if (!((buf[i] >> s) & 1)) {
 +					bit = s + (i << 4);
 +					return((bit < nb) ? bit : NO_ZONE);
 +				}
 +	return NO_ZONE;
 +}
 +/*
 + * Read a bit from the in-core data block bitmap
 + */
 +int
 +minix_read_zbit(struct minix_super_block *sp, u_int32_t bit)
 +{
 +	u_int16_t *buf = sp->s_zbmap;     
 +	int w, s;
 +     
 +	w = bit >> 4;
 +	s = bit % 16;
 +
 +	return ((int)((buf[w] >> s) & 0x1));
 +}
 +/*
 + * Write a bit into the in-core data block bitmap
 + */
 +void
 +minix_write_zbit(struct minix_super_block *sp, u_int32_t bit)
 +{
 +	u_int16_t *buf = sp->s_zbmap; 
 +	int w, s;
 +
 +	w = bit >> 4;
 +	s = bit % 16;
 +  
 +	buf[w] |= (1 << s);
 +}
 +/*
 + * Delete a bit in the in-core data block bitmap
 + */
 +void
 +minix_delete_zbit(struct minix_super_block *sp, u_int32_t bit)
 +{
 +	u_int16_t *buf = sp->s_zbmap;
 +	int w, s;
 +  
 +	w = bit >> 4;
 +	s = bit % 16;
 +  
 +	buf[w] &= ~(1 << s);
 +}
 +/*
 + * Figures out the number of data blocks in a file,
 + * including the indirect blocks, given the size
 + * of the file.
 + */
 +int
 +minix_num_blocks(u_int16_t mode, u_int32_t size, short zshift)
 +{
 +     int nindirects, indirect = 0;
 +     int nzones, nblocks = 1;
 +
 +     switch (mode & I_TYPE) {         
 +     case I_LINK:
 +	  if (size < MINIX_MAXSYMLINKLEN)
 +	       return 0;   /* No data blocks for a short symlink */
 +	  return 1;        /* One data block for a long symlink */
 +     case I_REGULAR:
 +	  break;
 +     default:     /* This includes Sock,B_Spec,C_Spec, and Fifo. */
 +	  return 0;
 +     }
 +     if (size == 0)
 +	  return 0;
 +     /*
 +      * nblocks set initially to one above. Add the extra blocks below.
 +      */
 +     nblocks += (size - 1) / BLOCK_SIZE;
 +     nzones = nblocks >> zshift;
 +     if (nblocks > (nzones << zshift))
 +	  nzones += 1;
 +
 +     /* Figure out whether we have indirect blocks */
 +
 +     if (nzones > TOT_DIRECT)
 +	  indirect++;         /* Single indirect */
 +
 +     if (nzones > TOT_SINDIRECT)
 +	  indirect++;         /* Double indirect */
 +
 +     if (nzones > TOT_DINDIRECT)
 +	  indirect++;         /* Triple indirect */
 +	  
 +     switch (indirect) {
 +     case 0:
 +	  return nblocks;
 +     case 1:
 +	  return (nblocks + 1);  /* One for the indirect */
 +     case 2:
 +	  nindirects = (nblocks - TOT_SINDIRECT - 1)/V2_NR_INDIRECTS;
 +	  return (nblocks + nindirects + 2);
 +     case 3:
 +	  nindirects = (nblocks - TOT_DINDIRECT - 1) / V2_NR_INDIRECTS;
 +	  nindirects += nindirects / V2_NR_INDIRECTS;  /* Number of extra doubles */
 +	  return (nblocks + nindirects + V2_NR_INDIRECTS + 2);	  
 +     default:
 +	  break;
 +     }
 +     return 0;  /* NOTREACHED */
 +}
 diff -ruN sys.orig/fs/minixfs/minix_ihash.c sys/fs/minixfs/minix_ihash.c
 --- sys.orig/fs/minixfs/minix_ihash.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_ihash.c	Fri Feb 28 13:46:38 2003
 @@ -0,0 +1,165 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/*
 + * This code was lifted from FreeBSD and modified for Minix.
 + */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/kernel.h>
 +#include <sys/lock.h>
 +#include <sys/vnode.h>
 +#include <sys/malloc.h>
 +#include <sys/proc.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +static MALLOC_DEFINE(M_MNXIHASH, "MINIX ihash", "MINIX Inode hash tables");
 +/*
 + * Structures associated with inode cacheing.
 + */
 +static LIST_HEAD(mnxihashhead, minix_inode) *mnxihashtb;
 +static u_long	minix_ihash;		/* size of hash table - 1 */
 +#define	MNXINOHSH(device, inum)	(&mnxihashtb[(minor(device) + (inum)) & minix_ihash])
 +#ifndef NULL_SIMPLELOCKS
 +static struct simplelock minix_ihash_slock;
 +#endif
 +
 +/*
 + * Initialize inode hash table.
 + */
 +void
 +minix_ihashinit(void)
 +{
 +	mnxihashtb = hashinit(desiredvnodes, M_MNXIHASH, &minix_ihash);
 +	simple_lock_init(&minix_ihash_slock);
 +}
 +/*
 + * Free the inode hash table
 + */
 +void
 +minix_ihashuninit(void)
 +{
 +     if (mnxihashtb) {
 +	  free(mnxihashtb, M_MNXIHASH);
 +	  mnxihashtb = NULL;
 +     }
 +}
 +/*
 + * Use the device/inum pair to find the incore inode, and return a pointer
 + * to it. If it is in core, return it, even if it is locked.
 + */
 +struct vnode *
 +minix_ihashlookup(dev_t dev, ino_t inum)
 +{
 +	struct minix_inode *ip;
 +
 +	simple_lock(&minix_ihash_slock);
 +	for (ip = MNXINOHSH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next)
 +		if (inum == ip->i_number && dev == ip->i_dev)
 +			break;
 +	simple_unlock(&minix_ihash_slock);
 +
 +	if (ip) {
 +		ip->i_vnode->v_type = minix_get_vtype(ip);
 +		return (ip->i_vnode);
 +	}
 +	
 +	return (NULLVP);
 +}
 +
 +/*
 + * Use the device/inum pair to find the incore inode, and return a pointer
 + * to it. If it is in core, but locked, wait for it.
 + */
 +struct vnode *
 +minix_ihashget(dev_t dev, ino_t inum)
 +{
 +	struct proc *p = curproc;	/* XXX */
 +	struct minix_inode *ip;
 +	struct vnode *vp;
 +
 +loop:
 +	simple_lock(&minix_ihash_slock);
 +	for (ip = MNXINOHSH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) {
 +		if (inum == ip->i_number && dev == ip->i_dev) {
 +			vp = ip->i_vnode;
 +			simple_lock(&vp->v_interlock);
 +			simple_unlock(&minix_ihash_slock);
 +			if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))
 +				goto loop;
 +			vp->v_type = minix_get_vtype(ip);
 +			return (vp);
 +		}
 +	}
 +	simple_unlock(&minix_ihash_slock);
 +
 +	return (NULLVP);
 +}
 +
 +/*
 + * Insert the inode into the hash table, and return it locked.
 + */
 +void
 +minix_ihashins(struct minix_inode *ip)
 +{
 +	struct proc *p = curproc;		/* XXX */
 +	struct mnxihashhead *ipp;
 +
 +	if (1)
 +	     return;
 +
 +	/* lock the inode, then put it on the appropriate hash list */
 +	lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p);
 +
 +	simple_lock(&minix_ihash_slock);
 +	ipp = MNXINOHSH(ip->i_dev, ip->i_number);
 +	LIST_INSERT_HEAD(ipp, ip, i_hash);
 +	ip->i_flag |= IN_HASHED;
 +	simple_unlock(&minix_ihash_slock);
 +}
 +
 +/*
 + * Remove the inode from the hash table.
 + */
 +void
 +minix_ihashrem(struct minix_inode *ip)
 +{
 +     if (1)
 +	  return;
 +     
 +	simple_lock(&minix_ihash_slock);
 +	if (ip->i_flag & IN_HASHED) {
 +		ip->i_flag &= ~IN_HASHED;
 +		LIST_REMOVE(ip, i_hash);
 +#ifdef DIAGNOSTIC
 +		ip->i_hash.le_next = NULL;
 +		ip->i_hash.le_prev = NULL;
 +#endif
 +	}
 +	simple_unlock(&minix_ihash_slock);
 +}
 diff -ruN sys.orig/fs/minixfs/minix_inode.c sys/fs/minixfs/minix_inode.c
 --- sys.orig/fs/minixfs/minix_inode.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_inode.c	Fri Feb 28 21:21:42 2003
 @@ -0,0 +1,757 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/proc.h>
 +#include <sys/kernel.h>
 +#include <sys/sysctl.h>
 +#include <sys/vnode.h>
 +#include <sys/lock.h>
 +#include <sys/time.h>
 +#include <sys/malloc.h>
 +#include <sys/namei.h>
 +#include <sys/mount.h>
 +#include <sys/stat.h>
 +#include <sys/buf.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +int  minix_read_ibit(struct minix_super_block*,int);
 +void minix_write_ibit(struct minix_super_block*,int);
 +void minix_delete_ibit(struct minix_super_block*,int);
 +static int minix_truncatefs(struct minix_inode*,u_daddr_t,u_daddr_t);
 +
 +int
 +minix_makeinode(int mode, struct vnode *dvp,
 +                struct vnode **vpp, struct componentname *cnp)
 +{
 +	struct minix_inode *dip, *ip;
 +	struct vnode *tvp;
 +	struct minix_direct newdir;
 +	int error;
 +
 +	dip = VTOMI(dvp);
 +	*vpp = NULL;
 +	
 +	if ((mode & IFMT) == 0)
 +		mode |= IFREG;
 +
 +	if ((error = minix_valloc(dvp, mode, cnp->cn_cred, &tvp)) != 0)
 +		return error;
 +
 +	ip = VTOMI(tvp);
 +	ip->i_dino.i_gid = dip->i_dino.i_gid;
 +	
 +	/*
 +	 * If we are not the owner of the directory,
 +	 * and we are hacking owners here, (only do this where told to)
 +	 * and we are not giving it TO root, (would subvert quotas)
 +	 * then go ahead and give it to the other user.
 +	 * Note that this drops off the execute bits for security.
 +	 */
 +	if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
 +	    (dip->i_dino.i_mode & ISUID) &&
 +	    (dip->i_dino.i_uid != cnp->cn_cred->cr_uid) && dip->i_dino.i_uid) {
 +		ip->i_dino.i_uid = dip->i_dino.i_uid;
 +		mode &= ~07111;
 +	} else
 +		ip->i_dino.i_uid = cnp->cn_cred->cr_uid;
 +
 +	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 +	ip->i_mode = mode;
 +	ip->i_dino.i_mode = mode;
 +	tvp->v_type = minix_get_vtype(ip); /* Rest init'd in getnewvnode(). */
 +	ip->i_nlink = 1;
 +
 +	if ((ip->i_mode & ISGID) && !groupmember(ip->i_dino.i_gid, cnp->cn_cred) &&
 +	    suser_xxx(cnp->cn_cred, 0, 0))
 +		ip->i_mode &= ~ISGID;
 +	/*
 +	 * Make sure inode goes to disk before directory entry.
 +	 */
 +	if ((error = minix_update(tvp)) != 0)
 +		goto bad;
 +	
 +	minix_makedirentry(ip, cnp, &newdir);
 +	
 +	if ((error = minix_direnter(dvp, tvp, &newdir, cnp)) != 0)
 +		goto bad;
 +	
 +	*vpp = tvp;
 +
 +	return 0;
 +bad:
 +	/*
 +	 * Write error occurred trying to update the inode
 +	 * or the directory so must deallocate the inode.
 +	 */
 +	ip->i_nlink = 0;
 +	ip->i_flag |= IN_CHANGE;
 +	vput(tvp);
 +	return error;
 +}
 +/*
 + * Truncate the inode to at most length size, freeing the
 + * disk blocks.
 + */
 +int
 +minix_truncate(struct vnode *vp,
 +               off_t length,
 +               int flags,
 +               struct ucred *cred,
 +               struct proc  *p)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	u_daddr_t lbn0, lbn1, len32;
 +	int error;
 +
 +	if (length > ~(1 << 31))   /* 32-bit offsets only! */
 +		return EFBIG;
 +
 +	len32 = (u_daddr_t)length;
 +
 +	/* Data in a short symlink is stored in the inode */
 +
 +	if (vp->v_type == VLNK && 
 +	    dip->i_size < vp->v_mount->mnt_maxsymlinklen) {
 +		bzero((char*)ip->i_shortlink, MINIX_MAXSYMLINKLEN);
 +		dip->i_size = 0;
 +		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +		return minix_update(vp);
 +	}
 +	if (dip->i_size <= len32) {
 +	     ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +	     return minix_update(vp);
 +	}
 +
 +	/* lbn1 is the last zone in the file */
 +
 +	lbn1 = (dip->i_size - 1)/sp->s_zsize;
 +
 +	/* lbn0 is the first zone to eliminate */
 +	
 +	if (len32 > 0)
 +		lbn0 = (len32 - 1)/sp->s_zsize + 1;
 +	else
 +		lbn0 = 0;    /* Eliminate all zones */
 +
 +	if (lbn0 > lbn1)     /* Silly but check anyway */
 +		return EIO;
 +
 +	/* truncatefs will eliminate all zones from lbn0 to EOF */
 +
 +	if ((error = minix_truncatefs(ip, lbn0, len32)) != 0)
 +		return error;
 +	
 +	dip->i_size  = len32;               /* The new length of the file */
 +	ip->i_blocks = minix_num_blocks(ip->i_mode, len32, sp->s_zshift);
 +	
 +	ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +	
 +	return minix_update(vp);
 +}
 +/*
 + * Frees all zones from the logical offset lbn to the end of the file.
 + */
 +static int
 +minix_truncatefs(struct minix_inode *ip, u_daddr_t lbn, u_daddr_t length)
 +{
 +	struct buf *bp;
 +	union minix_block *mbp;
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	u_daddr_t lb0, lb, off = 0;
 +	u_daddr_t blk, id0, id1, id2, id3, zone;
 +	int error, indirect;
 +	int delete1, delete2, delete3;
 +
 +	if (dip->i_size == 0)
 +		return 0;
 +
 +	lb = lb0 = (dip->i_size - 1)/sp->s_zsize;
 +	
 +	if (lb < lbn)
 +		return EIO;
 +	
 +	do {
 +		delete1  = 0;
 +		delete2  = 0;
 +		delete3  = 0;
 +		indirect = 0;
 +		if (lb >= TOT_DIRECT)
 +			indirect++;
 +		if (lb >= TOT_SINDIRECT)
 +			indirect++;
 +		if (lb >= TOT_DINDIRECT)
 +			indirect++;
 +		if (lb >= TOT_TINDIRECT)
 +			indirect++;
 +
 +		switch (indirect) {
 +		case 0:
 +			if ((error = minix_dzalloc(sp, dip->i_block[lb])) != 0)
 +				return error;
 +			dip->i_block[lb] = 0;
 +			break;
 +		case 3:
 +			off = lb - TOT_DINDIRECT;
 +			id2 = off >> INDIRECT_SHIFT;
 +			id3 = id2 >> INDIRECT_SHIFT;
 +			id2 = id2 % V2_NR_INDIRECTS;
 +			id1 = off % V2_NR_INDIRECTS;
 +			if (id1 == 0) {
 +				delete1 = 1;
 +				if (id2 == 0) {
 +					delete2 = 1;
 +					if (id3 == 0)
 +						delete3 = 1;
 +				}
 +			}
 +			blk = dip->i_block[V2_NR_DBLOCKS+2] << sp->s_zshift;
 +			if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +				return 0;
 +			mbp = MBLOCK(bp);
 +			id0 = mbp->ind[id3];
 +			if (delete3) {
 +				zone = dip->i_block[V2_NR_DBLOCKS+2];
 +				dip->i_block[V2_NR_DBLOCKS+2] = 0;
 +				if ((error = minix_dzalloc(sp, zone)) != 0)
 +					return error;
 +				brelse(bp);
 +			} else {
 +				if (delete2) {
 +					mbp->ind[id3] = 0;
 +					bwrite(bp);
 +				} else
 +					bqrelse(bp);
 +			}
 +			goto rind2;
 +		case 2:
 +			off = lb - TOT_SINDIRECT;
 +			id2 = off >> INDIRECT_SHIFT;
 +			id1 = off % V2_NR_INDIRECTS;
 +			if (id1 == 0) {
 +				delete1 = 1;
 +				if (id2 == 0)
 +					delete2 = 1;
 +			}
 +			id0 = dip->i_block[V2_NR_DBLOCKS+1];
 +			if (delete2)
 +				dip->i_block[V2_NR_DBLOCKS+1] = 0;
 +		rind2:
 +			blk = id0 << sp->s_zshift;
 +			if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +				return error;
 +			if (delete2) {
 +				if ((error = minix_dzalloc(sp,id0)) != 0)
 +					return error;
 +			}
 +			mbp = MBLOCK(bp);
 +			id0 = mbp->ind[id2];
 +			if (delete2)
 +				brelse(bp);
 +			else {
 +				if (delete1) {
 +					mbp->ind[id2] = 0;
 +					bwrite(bp); 
 +				} else
 +					bqrelse(bp);
 +			}
 +			goto rind1;
 +		case 1:
 +			id1 = lb - TOT_DIRECT;
 +			if (id1 == 0)
 +				delete1 = 1;
 +			id0 = dip->i_block[V2_NR_DBLOCKS];
 +			if (delete1)
 +				dip->i_block[V2_NR_DBLOCKS] = 0;
 +		rind1:
 +			blk = id0 << sp->s_zshift;
 +			if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			if ((error = minix_dzalloc(sp, mbp->ind[id1])) != 0)
 +				return error;
 +			if (delete1) {
 +				if ((error = minix_dzalloc(sp, id0)) != 0)
 +					return error;
 +				brelse(bp);
 +			} else {
 +				mbp->ind[id1] = 0;
 +				bwrite(bp);
 +			}
 +			break;
 +		default:
 +			return EIO;
 +		}
 +
 +	} while (lbn < lb--);
 +	
 +	return 0;
 +}
 +/*
 + * Update the access, modified, and inode change times as specified by the
 + * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.  Write the inode
 + * to disk if the IN_MODIFIED flag is set (it may be set initially, or by
 + * the timestamp update).
 + */
 +int
 +minix_update(struct vnode *vp)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +
 +	minix_itimes(vp);
 +	
 +	if ((ip->i_flag & IN_MODIFIED) == 0)
 +		return 0;
 +	
 +	ip->i_flag &= ~(IN_MODIFIED);
 +	
 +	if (vp->v_mount->mnt_flag & MNT_RDONLY)
 +		return 0;
 +
 +	return minix_iput(ip);
 +}
 +
 +void
 +minix_itimes(struct vnode *vp)
 +{
 +     	struct minix_inode *ip = VTOMI(vp);
 +	struct timespec ts;
 +	
 +	if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
 +		return;
 +
 +	if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 +		vfs_timestamp(&ts);
 +		if (ip->i_flag & IN_ACCESS) {
 +			ip->i_dino.i_atime = ts.tv_sec;
 +		}
 +		if (ip->i_flag & IN_UPDATE) {
 +			ip->i_dino.i_mtime = ts.tv_sec;
 +		}
 +		if (ip->i_flag & IN_CHANGE) {
 +			ip->i_dino.i_ctime = ts.tv_sec;
 +		}
 +		ip->i_flag |= IN_MODIFIED;
 +	}
 +	ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
 +}
 +/*
 + * The following access routine was lifted from the UFS code.
 + */
 +int
 +minix_dinode_access(struct minix_dinode *dip, int mode,
 +                    struct ucred *cred, struct minix_super_block *sp)
 +{
 +	int i,mask;
 +	gid_t *gp;
 +	
 +        /*
 +	 * Disallow write attempts on read-only file systems;
 +	 * unless the file is a socket, fifo, or a block or
 +	 * character device resident on the file system.
 +	 */
 +	
 +	if (mode & VWRITE) {
 +		switch ((dip->i_mode) & I_TYPE) {
 +		case I_DIRECTORY:
 +		case I_LINK:
 +		case I_REGULAR:
 +			if (sp->s_rdonly != 0)
 +				return EROFS;
 +			break;
 +		}
 +	}
 +
 +        /* No immutable bit in minix */
 +
 +        /* user id 0 always gets access. */
 +	
 +	if (cred->cr_uid == 0)
 +		return 0;
 +
 +	mask = 0;
 +
 +        /* check the owner. */
 +	
 +	if (cred->cr_uid == dip->i_uid) {
 +		if (mode & VEXEC)
 +			mask |= S_IXUSR;
 +		if (mode & VREAD)
 +			mask |= S_IRUSR;
 +		if (mode & VWRITE)
 +			mask |= S_IWUSR;
 +		return ((dip->i_mode & mask) == mask ? 0 : EACCES);
 +	}
 +
 +        /* check the groups. */
 +	
 +	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
 +		if (dip->i_gid == *gp) {
 +			if (mode & VEXEC)
 +				mask |= S_IXGRP;
 +			if (mode & VREAD)
 +				mask |= S_IRGRP;
 +			if (mode & VWRITE)
 +				mask |= S_IWGRP;
 +			return ((dip->i_mode & mask) == mask ? 0 : EACCES);
 +		}
 +
 +        /* check everyone else. */
 +	
 +	if (mode & VEXEC)
 +		mask |= S_IXOTH;
 +	if (mode & VREAD)
 +		mask |= S_IROTH;
 +	if (mode & VWRITE)
 +		mask |= S_IWOTH;
 +	return ((dip->i_mode & mask) == mask ? 0 : EACCES);	
 +}
 +
 +/* Clean up the inode associated with the vnode before freeing it */
 +
 +/*
 + * Free an inode; put it back into the block that it belongs
 + * and then free the block. Update the superblock if necessary.
 + */
 +
 +int
 +minix_vfree(struct vnode *vp, ino_t ino, int mode)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +
 +        return minix_dialloc(ip->i_su, ino);
 +}
 +/*
 + * Get a minix inode with no vnode attached. Routine
 + * assumes that space for the inode, pointed to by ip,
 + * is supplied by the caller. Also notice that there
 + * is no vnode involved here, so the elements i_vnode
 + * and i_mmp are set to NULL and i_parent = 0;
 + */
 +int
 +minix_iget(struct vnode *devvp, struct minix_super_block *sp,
 +           mino_t ino, struct minix_inode *ip)
 +{
 +     struct buf *bp;
 +     block_t blk;
 +     union minix_block *mbp;
 +     int error;
 +     u_daddr_t off;
 +
 +     bzero((caddr_t)ip, sizeof(struct minix_inode));
 +     blk = (block_t)ino_to_byte(sp,ino)/BLOCK_SIZE;
 +     
 +     bp = NULL;
 +     if ((error = minix_getblk(devvp,blk,&bp)) != 0) {
 +	     if (bp != NULL)
 +		     brelse(bp);
 +	     return error;
 +     }
 +
 +     mbp = MBLOCK(bp);
 +     off = (ino-1) % V2_INODES_PER_BLOCK;
 +     ip->i_dino = mbp->dinode[off];
 +     
 +     bqrelse(bp);
 +
 +     ip->i_number = ino;
 +     ip->i_parent = 0;
 +     ip->i_su = sp;
 +     ip->i_vnode = NULL;
 +     ip->i_mode = ip->i_dino.i_mode;
 +     ip->i_mmp = NULL;
 +     ip->i_dev = devvp->v_rdev;
 +     ip->i_flag = 0;
 +     
 +     return 0;
 +}
 +/*
 + * Write an inode; assumes that the caller will
 + * release the space pointed to by ip when finished.
 + */
 +int
 +minix_iput(struct minix_inode *ip)
 +{
 +	struct vnode *devvp;
 +	struct buf *bp;
 +	union minix_block *mbp;
 +	mino_t ino;
 +	block_t blk;
 +	u_daddr_t off;
 +	int error;
 +
 +	devvp = ip->i_su->s_devvp;
 +	ino = ip->i_number;
 +	blk = (block_t)ino_to_byte(ip->i_su,ino)/BLOCK_SIZE;
 +
 +	bp = NULL;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0) {
 +		if (bp != NULL)
 +			brelse(bp);
 +		return error;
 +	}
 +
 +	mbp = MBLOCK(bp);
 +	off = (ino-1) % V2_INODES_PER_BLOCK;
 +	mbp->dinode[off] = ip->i_dino;
 +	
 +	return minix_putblk(bp);
 +}
 +/*
 + * Returns the next free inode number, sets the bitmap
 + * to active, writes the bitmap to disk, and cleans
 + * the on disk dinode.
 + */
 +int
 +minix_ialloc(struct minix_super_block *sp, int *inop)
 +{
 +	int ino, ic, blk, off, error;
 +	u_int16_t *buf = sp->s_ibmap;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	struct minix_inode in;
 +	union minix_block *mbp;
 +
 +	*inop = 0;
 +
 +	minix_get_lock(&sp->imap_lock);
 +	
 +	if ((ino = minix_next_free_inode(sp)) == NO_INODE) {
 +		minix_free_lock(&sp->imap_lock);
 +		printf("minix_next_free_inode: returned zero inode\n");
 +		return ENOSPC;
 +	}
 +
 +	minix_write_ibit(sp, ino);
 +
 +	ic  = ino >> 4;                   /* Chunk that bit resides in */
 +	blk = ino / BITS_PER_BLOCK;       /* Block that bit is in */
 +	off = ino % BITS_PER_BLOCK;       /* Bit offset in block */
 +	off >>= 4;                        /* Chunk offset in block */
 +	blk += 2;                         /* Adjust for offset in file */
 +
 +	bp = NULL;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0) {
 +		if (bp != NULL)
 +			brelse(bp);
 +		minix_delete_ibit(sp, ino);
 +		minix_free_lock(&sp->imap_lock);
 +		return error;
 +	}
 +
 +	mbp = MBLOCK(bp);
 +	mbp->bitchunk[off] = buf[ic];
 +
 +	if ((error = minix_putblk(bp)) != 0) {
 +		minix_delete_ibit(sp,ino);
 +		if (bp != NULL) {
 +			bp->b_flags |= B_INVAL;
 +			brelse(bp);
 +		}
 +		minix_free_lock(&sp->imap_lock);
 +		return error;
 +	}
 +
 +	if ((error = minix_iget(devvp,sp,ino,&in)) != 0) {
 +		minix_free_lock(&sp->imap_lock);
 +		minix_dialloc(sp, ino);
 +		return error;
 +	}
 +
 +	minix_wipe_dinode(&(in.i_dino));
 +
 +	if ((error = minix_iput(&in)) != 0) {
 +		minix_free_lock(&sp->imap_lock);
 +		minix_dialloc(sp,ino);
 +		return error;
 +	}
 +
 +	minix_free_lock(&sp->imap_lock);
 +
 +	*inop = ino;
 +
 +	return 0;
 +}
 +int
 +minix_dialloc(struct minix_super_block *sp, int ino)
 +{
 +	int blk, ic, off, error;
 +	u_int16_t *buf = sp->s_ibmap;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	union minix_block *mbp;
 +
 +	minix_get_lock(&sp->imap_lock);
 +
 +	if (minix_read_ibit(sp, ino))
 +		minix_delete_ibit(sp, ino);
 +	else {
 +		minix_free_lock(&sp->imap_lock);
 +		return 0;
 +	}
 +
 +	ic  = ino >> 4;                   /* Chunk that bit resides in */
 +	blk = ino / BITS_PER_BLOCK;       /* Block that bit is in */
 +	off = ino % BITS_PER_BLOCK;       /* Bit offset in block */
 +	off >>= 4;                        /* Chunk offset in block */
 +	blk += 2;                         /* Adjust for offset in file */
 +
 +	bp = NULL;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0) {
 +		if (bp != NULL)
 +			brelse(bp);
 +		minix_write_ibit(sp, ino);
 +		minix_free_lock(&sp->imap_lock);
 +		return error;
 +	}
 +
 +	mbp = MBLOCK(bp);
 +	mbp->bitchunk[off] = buf[ic];
 +
 +	if ((error = minix_putblk(bp)) != 0) {
 +		minix_write_ibit(sp,ino);
 +		if (bp != NULL) {
 +			bp->b_flags |= B_INVAL;
 +			brelse(bp);
 +		}
 +		minix_free_lock(&sp->imap_lock);
 +		return error;
 +	}
 +
 +	minix_free_lock(&sp->imap_lock);
 +	
 +	return 0;
 +}
 +/*
 + * The next few routines manipulate/read the inode bitmaps.
 + * Any locking that is needed is assumed to occur in the
 + * calling programs.
 + */
 +/*
 + * Counts the number of free inodes
 + */
 +int
 +minix_free_inode_count(struct minix_super_block *sp)
 +{
 +     short nbits[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
 +     u_int16_t *bits = sp->s_ibmap;
 +     int b1,b2,b3,b4,j,n;
 +     int sum;
 +
 +     sum = sp->s_ninodes;
 +
 +     n = ((sp->s_ninodes-1)>>4);
 +     for (j=0; j<n; j++) {
 +	     b4 = (bits[j] >> 12) & 0xf;
 +	     b3 = (bits[j] >>  8) & 0xf;
 +	     b2 = (bits[j] >>  4) & 0xf;
 +	     b1 =  bits[j]        & 0xf;
 +	     sum -= (nbits[b1] + nbits[b2] +
 +		     nbits[b3] + nbits[b4]);
 +     }
 +     return(sum < 0 ? 0 : sum+1); /* Add one to counter bit zero in the bitmap */
 +}
 +/*
 + * Return the next free inode from the inode bitmap (very simple)
 + */
 +int
 +minix_next_free_inode(struct minix_super_block *sp)
 +{
 +	int i, n, s;
 +	u_int16_t *buf = sp->s_ibmap;
 +	register int bit;
 +
 +	n = sp->s_ninodes >> 4;
 +	if ((sp->s_ninodes % 16) > 0)
 +		n += 1;
 +
 +	/* Look for a hole in a chunk, then */
 +	/* search the chunk for the bit */
 +	
 +	for (i=0; i<n; i++)
 +		if (buf[i] != 0xffff)
 +			for (s=0; s<16; s++)
 +				if (!((buf[i] >> s) & 1)) {
 +					bit = s + (i << 4);
 +					return((bit < sp->s_ninodes) ? bit : NO_INODE);
 +				}
 +	return NO_INODE;
 +}
 +/*
 + * Read a bit from the in-core inode bitmap
 + * note log2(16) = 4
 + */
 +int
 +minix_read_ibit(struct minix_super_block *sp, int bit)
 +{
 +	u_int16_t *buf = sp->s_ibmap;     
 +	int w, s;
 +     
 +	w = bit >> 4;
 +	s = bit % 16;
 +
 +	return ((int)((buf[w] >> s) & 0x1));
 +}
 +/*
 + * Write a bit into the in-core inode bitmap
 + */
 +void
 +minix_write_ibit(struct minix_super_block *sp, int bit)
 +{
 +	u_int16_t *buf = sp->s_ibmap; 
 +	int w, s;
 +  
 +	w = bit >> 4;
 +	s = bit % 16;
 +  
 +	buf[w] |= (1 << s);
 +}
 +/*
 + * Delete a bit in the in-core inode bitmap
 + */
 +void
 +minix_delete_ibit(struct minix_super_block *sp, int bit)
 +{
 +	u_int16_t *buf = sp->s_ibmap;
 +	int w, s;
 +  
 +	w = bit >> 4;
 +	s = bit % 16;
 +  
 +	buf[w] &= ~(1 << s);
 +}
 +
 +void
 +minix_wipe_dinode(struct minix_dinode *dip)
 +{
 +      bzero((char*)dip, sizeof(struct minix_dinode));
 +}
 diff -ruN sys.orig/fs/minixfs/minix_locks.c sys/fs/minixfs/minix_locks.c
 --- sys.orig/fs/minixfs/minix_locks.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_locks.c	Fri Feb 28 13:46:38 2003
 @@ -0,0 +1,52 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/kernel.h>
 +#include <sys/buf.h>
 +#include <sys/lock.h>
 +#include <sys/malloc.h>
 +#include <sys/mount.h>
 +#include <sys/vnode.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +u_int32_t _minix_alock(u_int32_t*);
 +
 +void
 +minix_get_lock(u_int32_t *lock)
 +{
 +     while(_minix_alock(lock))
 +	  tsleep(lock, PINOD, "Mnxlck", 0);
 +}
 +
 +void
 +minix_free_lock(u_int32_t *lock)
 +{
 +	*lock = 0l;
 +	wakeup(lock);
 +}
 diff -ruN sys.orig/fs/minixfs/minix_lookup.c sys/fs/minixfs/minix_lookup.c
 --- sys.orig/fs/minixfs/minix_lookup.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_lookup.c	Fri Feb 28 21:28:31 2003
 @@ -0,0 +1,1273 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/* Much of the code below follows FreeBSD's ufs implementation */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/proc.h>
 +#include <sys/ucred.h>
 +#include <sys/kernel.h>
 +#include <sys/vnode.h>
 +#include <sys/lock.h>
 +#include <sys/malloc.h>
 +#include <sys/mount.h>
 +#include <sys/namei.h>
 +#include <sys/buf.h>
 +
 +#include <vm/vm.h>
 +#include <vm/vm_extern.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +struct minix_namei_args {
 +	struct vnode *a_devvp;
 +	struct minix_super_block *a_sp;
 +	struct ucred *a_cred;
 +	struct proc *a_pp;
 +};
 +
 +int minix_lookup(struct vop_cachedlookup_args*);
 +
 +static int minix_namei(struct minix_namei_args*,char*,ino_t*,ino_t*,int*);
 +static int minix_newdirent(struct vnode*);
 +static int minix_dirsize(struct vnode*, u_long*);
 +static int minix_dircount(struct vnode*, u_long*);
 +static int minix_dirmove(struct vnode*, struct minix_direct*, u_long);
 +static int minix_dirclean(struct vnode*);
 +static int minix_dircleanup(struct vnode*);
 +static char *minix_strtok(char*, char*);
 +static char *minix_strtok_r(char*, char*, char**);
 +
 +ino_t root_inode, current_inode;  /* For communication with minix_namei(). */
 +
 +int
 +minix_lookup(struct vop_cachedlookup_args *ap)
 +     	/*
 +       struct vop_cachedlookup_args
 +         {
 +	     struct vnode *a_dvp;
 +	     struct vnode **a_vpp;
 +	     struct componentname *a_cnp;
 +         } *ap;
 +     */
 +{
 +    struct vnode *dvp = ap->a_dvp;
 +    struct vnode **vpp = ap->a_vpp;
 +    struct componentname *cnp = ap->a_cnp;
 +    struct vnode *vp = NULL;
 +    int error, isdot, entry;
 +    u_long flags, islastcn, lockparent, nameiop, wantparent;
 +    struct proc *pp;
 +    struct mount *mp;
 +    struct ucred *cred;
 +    struct minix_inode *dip;       /* minix inode for directory being searched */
 +    struct minix_inode *ip;        /* target inode */
 +    struct minixmount  *mmp;       /* minix mount information */
 +    struct minix_super_block *msp;
 +    struct minix_namei_args nia;
 +    ino_t mdino;                  /* minix initial directory inode number */
 +    ino_t mino, pino;             /* minix target inode number and parent */
 +    char path[PATH_MAX+1];
 +
 +    nameiop = cnp->cn_nameiop;
 +    flags   = cnp->cn_flags;
 +    lockparent = flags & LOCKPARENT;
 +    islastcn   = flags & ISLASTCN;
 +    wantparent = flags & (LOCKPARENT|WANTPARENT);
 +
 +    pp   = cnp->cn_proc;
 +    cred = pp->p_cred->pc_ucred;
 +    dip  = VTOMI(dvp);
 +    mmp  = dip->i_mmp;
 +    mp   = mmp->mnx_mp;
 +    msp  = mmp->mnx_su;
 +
 +    root_inode    = (ino_t)msp->s_root->i_number;
 +    current_inode = (ino_t)dip->i_number;
 +
 +    mdino = current_inode;
 +
 +    isdot = ((cnp->cn_namelen) == 1 && (cnp->cn_nameptr[0] == '.'));
 +    
 +    if (mdino == 0)
 +	    return ERANGE;
 +    /*
 +     * Check accessibility of directory.
 +     */
 +    if (dvp->v_type != VDIR)
 +	return ENOTDIR;
 +
 +    if ((error = VOP_ACCESS(dvp, VEXEC, cred, pp)) != 0)
 +	return error;
 +
 +    if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
 +	(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == CREATE ||
 +	 cnp->cn_nameiop == RENAME))
 +	    return EROFS;
 +
 +    /*
 +     * Search dvp for the component cnp->cn_nameptr.
 +     */
 +    nia.a_devvp = mmp->mnx_devvp;
 +    nia.a_sp    = mmp->mnx_su;
 +    nia.a_cred  = cred;
 +    nia.a_pp    = pp;
 +
 +    /* We assume that the pathlength has been checked earlier */
 +
 +    bzero(path, PATH_MAX+1);
 +    bcopy(cnp->cn_nameptr, path, cnp->cn_namelen);
 +    
 +    error = minix_namei(&nia, path, &mino, &pino, &entry);
 +
 +    if (error != 0) {
 +
 +	 if (error != ENOENT)
 +		 return error;
 +
 +	 if ((nameiop == CREATE || nameiop == RENAME)
 +	              && islastcn && wantparent
 +	              && dip->i_dino.i_nlinks != 0) {
 +	    /*
 +	     * Check for write access on directory.
 +	     */
 +	      if((error = VOP_ACCESS(dvp, VWRITE, cred, pp)) != 0)
 +		      return error;
 +	    /*
 +	     * Possibly record the position of a slot in the directory
 +	     * large enough for the new component name.  This can be
 +	     * recorded in the vnode private data for dvp.
 +	     * Set the SAVENAME flag to hold onto the pathname for use
 +	     * later in VOP_CREATE or VOP_RENAME.
 +	     */
 +	      
 +	      dip->i_entry = entry;
 +		
 +	      cnp->cn_flags |= SAVENAME;
 +	      if (!lockparent)
 +		      /*
 +		       * Note that the extra data recorded above is only
 +		       * useful if lockparent is specified.
 +		       */
 +		      VOP_UNLOCK(dvp, 0, pp);
 +
 +	      return EJUSTRETURN;
 +	}
 +
 +	/*
 +	 * Consider inserting name into cache.
 +	 */
 +	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
 +	    cache_enter(dvp, NULL, cnp);
 +
 +	return ENOENT;
 +    } else {
 +	/*
 +	 * If deleting, and at end of pathname, return parameters
 +	 * which can be used to remove file.  If the wantparent flag
 +	 * isn't set, we return only the directory, otherwise we go on
 +	 * and lock the inode, being careful with ".".
 +	 */
 +	if (nameiop == DELETE && islastcn) {
 +	    /*
 +	     * Check for write access on directory.
 +	     */
 +		if ((error = VOP_ACCESS(dvp, VWRITE, cred, pp)) != 0)
 +			return error;
 +		
 +		dip->i_entry = entry;
 +
 +		if (mino == dip->i_number || isdot) {
 +			VREF(dvp);
 +			*vpp = dvp;
 +			return 0;
 +		}
 +
 +		if ((error = VFS_VGET(dvp->v_mount, mino, &vp)) != 0)
 +			return error;
 +
 +		ip = VTOMI(vp);
 +		ip->i_parent = pino;         /* Record the parent inode */
 +	    
 +/*          Minix does not support the concept of a sticky bit (:<)!
 +	    
 +	    if (directory is sticky
 +	        && cred->cr_uid != 0
 +		&& cred->cr_uid != owner of dvp
 +		&& owner of vp != cred->cr_uid) {
 +		vput(vp);
 +		return EPERM;
 +	    }
 +*/
 +		*vpp = vp;
 +		if (!lockparent)
 +			VOP_UNLOCK(dvp, 0, pp);
 +
 +		return 0;
 +	}
 +	/*
 +	 * If rewriting (RENAME), return the inode and the
 +	 * information required to rewrite the present directory
 +	 * Must get inode of directory entry to verify it's a
 +	 * regular file, or empty directory.
 +	 */
 +	if (nameiop == RENAME && wantparent && islastcn) {
 +	    error = VOP_ACCESS(dvp, VWRITE, cred, pp);
 +	    if (error)
 +		return (error);
 +
 +	    dip->i_entry = entry;
 +
 +	    /*
 +	     * Check for "."
 +	     */
 +	    if (mino == dip->i_number || isdot)
 +		return EISDIR;
 +
 +	    error = VFS_VGET(dvp->v_mount, mino, &vp);
 +	    if (error)
 +		return error;
 +	    *vpp = vp;
 +	    /*
 +	     * Save the name for use in VOP_RENAME later.
 +	     */
 +	    cnp->cn_flags |= SAVENAME;
 +	    if (!lockparent)
 +		VOP_UNLOCK(dvp, 0, pp);
 +
 +	    return 0;
 +	}
 +
 +	/*
 +	 * Step through the translation in the name.  We do not `vput' the
 +	 * directory because we may need it again if a symbolic link
 +	 * is relative to the current directory.  Instead we save it
 +	 * unlocked as "pdp".  We must get the target inode before unlocking
 +	 * the directory to insure that the inode will not be removed
 +	 * before we get it.  We prevent deadlock by always fetching
 +	 * inodes from the root, moving down the directory tree. Thus
 +	 * when following backward pointers ".." we must unlock the
 +	 * parent directory before getting the requested directory.
 +	 * There is a potential race condition here if both the current
 +	 * and parent directories are removed before the VFS_VGET for the
 +	 * inode associated with ".." returns.  We hope that this occurs
 +	 * infrequently since we cannot avoid this race condition without
 +	 * implementing a sophisticated deadlock detection algorithm.
 +	 * Note also that this simple deadlock detection scheme will not
 +	 * work if the file system has any hard links other than ".."
 +	 * that point backwards in the directory structure.
 +	 */
 +	if (flags & ISDOTDOT) {
 +	    VOP_UNLOCK(dvp, 0, pp);	/* race to get the inode */
 +	    error = VFS_VGET(dvp->v_mount, mino, &vp);
 +	    if (error) {
 +		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, pp);
 +		return (error);
 +	    }
 +	    if (lockparent && islastcn) {
 +		error = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, pp);
 +		if (error) {
 +		    vput(vp);
 +		    return error;
 +		}
 +	    }
 +	    *vpp = vp;
 +	} else if (mino == dip->i_number || isdot) {
 +	    VREF(dvp);	/* we want ourself, ie "." */
 +	    *vpp = dvp;
 +	} else {
 +	    error = VFS_VGET(dvp->v_mount, mino, &vp);
 +	    if (error)
 +		return (error);
 +	    if (!lockparent || !islastcn)
 +		VOP_UNLOCK(dvp, 0, pp);
 +	    *vpp = vp;
 +	}
 +
 +	/*
 +	 * Insert name into cache if appropriate.
 +	 */
 +	if (cnp->cn_flags & MAKEENTRY)
 +	    cache_enter(dvp, *vpp, cnp);
 +	return (0);
 +    }
 +}
 +
 +/***********************************************************************
 + *                                                                     *
 + *   namei() parses the directory path and returns the inode number    *
 + *   of the last token in the path. If there is no path then the       *
 + *   current inode number is returned. If the path leads to no inode   *
 + *   then zero is returned and ENOENT is returned as an error.         *
 + *                                     by Ed Alley 021006              *
 + *                                                                     *
 + ***********************************************************************/
 +
 +static int
 +minix_namei(struct minix_namei_args *ap, char *path, ino_t *ino, ino_t *pino, int *entp)
 +{
 +	struct vnode *devvp = ap->a_devvp;
 +	struct minix_super_block *sp = ap->a_sp;
 +	struct ucred *cred = ap->a_cred;
 +	struct buf *bp;
 +	struct minix_inode *ip, in;
 +	struct minix_dinode *dip;
 +	int i, ib, id, j, error, len, entry = 0;
 +	char ppath[256], *pname;
 +	struct minix_direct dir[NR_DIR_ENTRIES];
 +	unsigned long ind1[V2_INDIRECTS], blk;
 +	ino_t inum, inuml;
 +
 +	*ino = 0;
 +	*pino = 0;
 +	*entp = -1;
 +
 +	if ((len = strlen(path)) > 255)
 +		return ENAMETOOLONG;
 +
 +	if (path == NULL) {
 +		*ino = current_inode;
 +		return ENOENT;
 +	}
 +
 +	bzero(ppath, 256);
 +     
 +	if (path[0] == '/')
 +		inum = root_inode;
 +	else
 +		inum = current_inode;
 +
 +	strncpy(ppath, path, len+1);
 +
 +	if (ppath[0] == '\0') {
 +		*ino = inum;
 +		return 0;
 +	}
 +
 +	/* Get the current directory */
 +     
 +	if ((error = minix_iget(devvp,sp,(mino_t)inum,&in)) != 0)
 +		return error;
 +
 +	ip  = &in;
 +	dip = &(in.i_dino);    /* the dinode of current directory */
 +
 +	pname = NULL;
 +	pname = minix_strtok(ppath, "/");
 +	inuml = inum;
 +
 +	ip->i_noent = -1;
 +	ip->i_entry = -1;
 +     
 +	while(pname != NULL) {
 +
 +		ip->i_noent = -1;
 +		ip->i_entry = -1;
 +	  
 +		if (!(ip->i_mode & IFDIR))
 +			return ENOTDIR;
 +
 +		if (minix_dinode_access(dip,VEXEC,cred,sp) != 0)
 +			return EACCES;
 +
 +		/* Search directory */
 +
 +		entry = 0;
 +		for (i=0; i<V2_NR_DBLOCKS; i++) {
 +			if (dip->i_block[i] == 0) {
 +				if (ip->i_noent < 0)
 +					ip->i_noent = entry;
 +				return ENOENT;
 +			}
 +			ib  = 1 << sp->s_zshift;
 +			blk = dip->i_block[i] << sp->s_zshift;
 +			while(ib--) {
 +				if((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +					return error;
 +				bcopy(bp->b_data, dir, BLOCK_SIZE);
 +				bqrelse(bp);
 +				for (j=0; j<NR_DIR_ENTRIES; j++) {
 +					if (dir[j].d_ino == 0) {
 +						if (ip->i_noent < 0)
 +							ip->i_noent = entry;
 +						entry++;
 +						continue;
 +					}
 +					if (!strncmp(pname, dir[j].d_name,MINIX_NAME_MAX)) {
 +						ip->i_entry = entry;
 +						goto gotj;
 +					}
 +					entry++;
 +				}
 +		        }
 +		}
 +	  
 +		if (dip->i_block[V2_NR_DBLOCKS] == 0) {
 +			if (ip->i_noent < 0)
 +				ip->i_noent = entry;
 +			return ENOENT;
 +		}
 +		blk = dip->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +		if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +			return error;
 +		bcopy(bp->b_data, ind1, BLOCK_SIZE);
 +		bqrelse(bp);
 +		for (id=0; id<V2_NR_INDIRECTS; id++) {
 +			if (ind1[id] == 0) {
 +				if (ip->i_noent < 0)
 +					ip->i_noent = entry;
 +				return ENOENT;
 +			}
 +			ib  = 1 << sp->s_zshift;
 +			blk = ind1[id] << sp->s_zshift;
 +			while(ib--) {
 +				if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +					return error;
 +				bcopy(bp->b_data, dir, BLOCK_SIZE);
 +				bqrelse(bp);
 +				for (j=0; j<NR_DIR_ENTRIES; j++) {
 +					if (dir[j].d_ino == 0) {
 +						if (ip->i_noent < 0)
 +							ip->i_noent = entry;
 +						entry++;
 +						continue;
 +					}
 +					if (!strncmp(pname, dir[j].d_name,MINIX_NAME_MAX)) {
 +					        ip->i_entry = entry;
 +						goto gotj;
 +					}
 +					entry++;
 +				}
 +			}
 +		}
 +
 +		/*
 +		 * Dropped through:
 +		 *      Could not find an entry: return "no entry".
 +		 */
 +		
 +		if (ip->i_noent < 0)
 +			ip->i_noent = entry;
 +
 +		*ino  = 0;
 +		*pino = inuml;
 +		*entp = -1;
 +		
 +		return ENOENT;		
 +		
 +	gotj:
 +		/*
 +		 * Found an entry; get the inode and look for another token.
 +		 */
 +		inuml = inum;
 +		if (!strcmp(dir[j].d_name,"..") && inum == root_inode)
 +			inum = root_inode;
 +		else
 +			inum  = dir[j].d_ino;
 +
 +		if ((error = minix_iget(devvp,sp,(mino_t)inum,ip)) != 0)
 +			return error;
 +
 +		pname = minix_strtok((char*)NULL, "/");
 +	}
 +	
 +	/*
 +	 * Return the inode for the entry found, and related information.
 +	 */
 +	
 +	*ino  = inum;
 +	*pino = inuml;
 +	*entp = entry;
 +     
 +	return 0;
 +}
 +/*
 + * Construct a new directory entry after a call to namei, using the
 + * parameters that it left in the componentname argument cnp. The
 + * argument ip is the inode to which the new directory entry will refer.
 + */
 +void
 +minix_makedirentry(ip, cnp, newdirp)
 +	struct minix_inode *ip;
 +	struct componentname *cnp;
 +	struct minix_direct *newdirp;
 +{
 +	int namelen;
 +	bzero(newdirp->d_name, MINIX_NAME_MAX);
 +	
 +	newdirp->d_ino = (short)ip->i_number;
 +	
 +        namelen = strlen(cnp->cn_nameptr);
 +	if (namelen > MINIX_NAME_MAX)
 +	     namelen = MINIX_NAME_MAX;
 +	bcopy(cnp->cn_nameptr, newdirp->d_name, namelen);
 +}
 +/*
 + * Write a directory entry after a call to namei, using the parameters
 + * that it left in nameidata. The argument dirp is the new directory
 + * entry contents. Dvp is a pointer to the directory to be written,
 + * which was left locked by namei. Remaining parameter: dp->i_noent
 + * was left by namei and indicates the entry into the directory list
 + * where a new entry may be placed.
 + */
 +int
 +minix_direnter(dvp, tvp, dirp, cnp)
 +	struct vnode *dvp;
 +	struct vnode *tvp;
 +	struct minix_direct *dirp;
 +	struct componentname *cnp;
 +{
 +	struct ucred *cr;
 +	struct proc *p;
 +	int newentrysize, newent;
 +	u_int32_t bln, off, newsize;
 +	off_t offset;
 +	struct minix_inode *ip = VTOMI(dvp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_direct *ep;
 +	struct iovec aiov;
 +	struct uio auio;
 +	struct buf *bp;
 +	char *dirbuf;
 +	int error;
 +
 +	p  = curproc;
 +	cr = p->p_ucred;
 +
 +	newentrysize = DIR_ENTRY_SIZE;
 +
 +	if ((error = minix_newdirent(dvp)) != 0)
 +		return error;
 +	if (ip->i_noent < 0 && ip->i_entry < 0)
 +		return ENOSPC;
 +	
 +	if (ip->i_noent < 0 && ip->i_entry >= 0) { /* No Entries Available */
 +		if (!(ip->i_entry < MAX_DIR_ENTRIES))
 +			return ENOSPC;
 +		bln = ip->i_entry / NR_DIR_ENTRIES;
 +		auio.uio_offset = bln*BLOCK_SIZE;
 +		auio.uio_resid  = newentrysize;
 +		aiov.iov_len    = newentrysize;
 +		aiov.iov_base   = (caddr_t)dirp;
 +		auio.uio_iov    = &aiov;
 +		auio.uio_iovcnt = 1;
 +		auio.uio_rw     = UIO_WRITE;
 +		auio.uio_segflg = UIO_SYSSPACE;
 +		auio.uio_procp  = (struct proc*)0;
 +		error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
 +		ip->i_flag |= IN_CHANGE;
 +		return error;
 +	}
 +
 +	if (ip->i_noent >= 0)
 +		newent = ip->i_noent;
 +	else
 +		newent = ip->i_entry;
 +
 +	bln = newent / NR_DIR_ENTRIES;
 +	off = newent % NR_DIR_ENTRIES;
 +	offset = (off_t)(bln*BLOCK_SIZE + off*newentrysize);
 +
 +	if ((error = minix_blkatoff(dvp, offset, &dirbuf, &bp)) != 0)
 +		return error;
 +	ep = (struct minix_direct*)dirbuf;
 +	*ep = *dirp;
 +	bwrite(bp);
 +
 +	newsize = (u_int32_t)offset + newentrysize;
 +	if (newsize > dip->i_size)
 +	     dip->i_size = newsize;
 +	ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +	return minix_update(dvp);
 +}
 +static int
 +minix_dircleanup(struct vnode *dvp)
 +{
 +	struct minix_inode *ip = VTOMI(dvp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	u_daddr_t bln;
 +	u_long newsize;
 +	int error;
 +
 +	if ((error = minix_dirsize(dvp, &newsize)) != 0)
 +		return error;
 +
 +	bln = minix_num_blocks(ip->i_mode, (u_int32_t)newsize, sp->s_zshift);
 +
 +	if (ip->i_blocks > bln)
 +		if ((error = minix_truncate(dvp, (off_t)newsize, IO_SYNC, NOCRED, NULL)) != 0)
 +		     return error;
 +	
 +	if (bln > ip->i_blocks)
 +	     vnode_pager_setsize(dvp, (vm_ooffset_t)(bln*BLOCK_SIZE));
 +
 +	ip->i_blocks = bln;
 +	dip->i_size  = newsize;
 +
 +	return 0;
 +}
 +/*
 + * Removes an entry from a directory.
 + * NOTE: Will not remove . or .. but returns ENOENT
 + *       in that case.
 + */
 +int
 +minix_dirremove(struct vnode *dvp)
 +{
 +     struct buf *bp;
 +     struct minix_inode *dip = VTOMI(dvp);
 +     struct minix_dinode *dinp = &(dip->i_dino);
 +     union minix_block *mbp;
 +     struct minix_direct *dirp;
 +     struct minix_super_block *sp = dip->i_su;
 +     struct vnode *devvp = sp->s_devvp;
 +     u_daddr_t ind, bln, off, dsiz;
 +     u_daddr_t blks, blkc, zone, boff;
 +     u_long count, size;
 +     int entry, error;
 +
 +     /*
 +      * Entries 0 and 1 are '.' and '..' respectively.
 +      */
 +
 +     if ((entry = dip->i_entry) < 2)
 +	     return ENOENT;
 +     
 +     bln = entry / NR_DIR_ENTRIES;
 +     off = entry % NR_DIR_ENTRIES;
 +     zone = bln >> sp->s_zshift;
 +     boff = bln - (zone << sp->s_zshift);
 +
 +     if (zone < V2_NR_DBLOCKS) {
 +	  zone = dinp->i_block[zone];
 +	  bln  = (zone << sp->s_zshift) + boff;
 +	  if ((error = minix_getblk(devvp,bln,&bp)) != 0)
 +	       return error;
 +	  mbp = MBLOCK(bp);
 +	  mbp->dir[off].d_ino = 0;
 +	  bwrite(bp);
 +     } else {
 +	  zone -= V2_NR_DBLOCKS;
 +	  bln = dinp->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +	  if ((error = minix_getblk(devvp,bln,&bp)) != 0)
 +	       return error;
 +	  mbp = MBLOCK(bp);
 +	  ind = mbp->ind[zone];
 +	  bqrelse(bp);
 +	  bln = (ind << sp->s_zshift) + boff;
 +	  if ((error = minix_getblk(devvp,bln,&bp)) != 0)
 +	       return error;
 +	  mbp = MBLOCK(bp);
 +	  mbp->dir[off].d_ino = 0;
 +	  bwrite(bp);
 +     }
 +
 +     if ((error = minix_dirsize(dvp, &size)) != 0)
 +	     return error;
 +     if ((error = minix_dircount(dvp, &count)) != 0)
 +	     return error;
 +
 +     blks = size / BLOCK_SIZE;
 +     blkc = count / NR_DIR_ENTRIES;
 +
 +     if (blkc < blks && count > 2) {
 +	     dsiz = BLOCK_SIZE*(blkc+1);
 +	     dirp = (struct minix_direct*)malloc(dsiz, M_MINIXNOD, M_WAITOK);
 +	     bzero((char*)dirp, dsiz);
 +	     if ((error = minix_dirmove(dvp, dirp, count)) != 0)
 +		     return error;
 +	     if ((error = minix_dirclean(dvp)) != 0)
 +		     return error;
 +	     for (ind=2; ind<count; ind++)
 +		     if ((error = minix_direnter(dvp, NULL, &(dirp[ind]), NULL)) != 0)
 +			     return error;
 +
 +	     free(dirp, M_MINIXNOD);
 +
 +	     cache_purge(dvp);
 +
 +	     return 0;
 +     }
 +     
 +     return minix_dircleanup(dvp);
 +}
 +/*
 + * Find an empty directory entry if it wasn't previously
 + * found by minix_namei(); place it in ip->i_noent.
 + * Routine returns empty entry number in ip->i_noent
 + * and zero as the error number. If no entry, because
 + * the available space is full, then the routine returns
 + * the next entry number and 0 as an error.
 + * Finally ENOSPC is returned if we are out of free entries.
 + *
 + * Need to improve this by getting an idea of the
 + * size of the search, so we don't have to search through
 + * the entire space as we do here.
 + */
 +static int
 +minix_newdirent(struct vnode *vp)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	struct minix_direct dir[NR_DIR_ENTRIES];
 +	unsigned long ind1[V2_INDIRECTS];
 +	u_int32_t blk;
 +	int ib, id, iz, error, entry = 0;
 +
 +	for (iz=0; iz<V2_NR_DBLOCKS; iz++) {
 +		if (dip->i_block[iz] == 0) {
 +			ip->i_noent = -1;
 +			ip->i_entry = entry;
 +			return 0;
 +		}
 +		blk = dip->i_block[iz] << sp->s_zshift;
 +		ib = 1 << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			bcopy(bp->b_data, dir, BLOCK_SIZE);
 +			bqrelse(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				if (dir[id].d_ino == 0) {
 +					ip->i_noent = entry;
 +					ip->i_entry = -1;
 +					return 0;
 +				}
 +				entry++;
 +			}
 +		}
 +	}
 +
 +	if (dip->i_block[V2_NR_DBLOCKS] == 0) {
 +	     ip->i_noent = -1;
 +	     ip->i_entry = entry;
 +	     return 0;
 +	}
 +
 +	blk = dip->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +		return error;
 +	bcopy(bp->b_data, ind1, BLOCK_SIZE);
 +	bqrelse(bp);
 +	
 +	for (iz=0; iz<V2_NR_INDIRECTS; iz++) {
 +		if (ind1[iz] == 0) {
 +			ip->i_noent = -1;
 +			ip->i_entry = entry;
 +			return 0;
 +		}
 +		ib = 1 << sp->s_zshift;
 +		blk = ind1[iz] << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			bcopy(bp->b_data, dir, BLOCK_SIZE);
 +			bqrelse(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				if (dir[id].d_ino == 0) {
 +					ip->i_noent = entry;
 +					ip->i_entry = -1;
 +					return 0;
 +				}
 +				entry++;
 +			}
 +		}
 +	}
 +	ip->i_noent = -1;
 +	ip->i_entry = -1;
 +	return ENOSPC;
 +}
 +
 +/*
 + * The size of a directory corresponds to the index+1 of the
 + * last entry (including all null entries between) times
 + * the size of a directory entry in bytes.
 + */
 +static int
 +minix_dirsize(struct vnode *vp, u_long *last)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	unsigned long ind1[V2_INDIRECTS];
 +	union minix_block *mbp;
 +	int ib, id, iz, error;
 +	u_int32_t blk;
 +	u_long count = 0;
 +
 +	*last = count;
 +	for (iz=0; iz<V2_NR_DBLOCKS; iz++) {
 +		if (dip->i_block[iz] == 0)
 +			return 0;
 +		ib = 1 << sp->s_zshift;
 +		blk = dip->i_block[iz] << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				count += DIR_ENTRY_SIZE;
 +				if (mbp->dir[id].d_ino > 0)
 +					*last = count;
 +			}
 +			bqrelse(bp);
 +		}
 +	}
 +
 +	if (dip->i_block[V2_NR_DBLOCKS] == 0)
 +	     return 0;
 +
 +	blk = dip->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +		return error;
 +	bcopy(bp->b_data, ind1, BLOCK_SIZE);
 +	bqrelse(bp);
 +	
 +	for (iz=0; iz<V2_NR_INDIRECTS; iz++) {
 +		if (ind1[iz] == 0)
 +			return 0;
 +		ib = 1 << sp->s_zshift;
 +		blk = ind1[iz] << sp->s_zshift;
 +		while (ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				count += DIR_ENTRY_SIZE;
 +				if (mbp->dir[id].d_ino > 0)
 +					*last = count;
 +			}
 +			bqrelse(bp);
 +		}
 +	}
 +	return 0;	
 +}
 +
 +/*
 + * Count the number of entries in a directory
 + */
 +static int
 +minix_dircount(struct vnode *dvp, unsigned long *count)
 +{
 +     	struct minix_inode *ip = VTOMI(dvp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	u_int32_t ind1[V2_INDIRECTS];
 +	u_int32_t blk;
 +	union minix_block *mbp;
 +	int ib, id, iz, error;
 +
 +	*count = 0;
 +	for (iz=0; iz<V2_NR_DBLOCKS; iz++) {
 +		if (dip->i_block[iz] == 0)
 +			return 0;
 +		ib = 1 << sp->s_zshift;
 +		blk = dip->i_block[iz] << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				if (mbp->dir[id].d_ino > 0)
 +					(*count) += 1;
 +			}
 +			bqrelse(bp);
 +		}
 +	}
 +
 +	if (dip->i_block[V2_NR_DBLOCKS] == 0)
 +		return 0;
 +
 +	blk = dip->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +		return error;
 +	bcopy(bp->b_data, ind1, BLOCK_SIZE);
 +	bqrelse(bp);
 +	
 +	for (iz=0; iz<V2_NR_INDIRECTS; iz++) {
 +		if (ind1[iz] == 0)
 +			return 0;
 +		ib = 1 << sp->s_zshift;
 +		blk = ind1[iz] << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				if (mbp->dir[id].d_ino > 0)
 +					(*count) += 1;
 +			}
 +			bqrelse(bp);
 +		}
 +	}
 +	return 0;
 +}
 +
 +static int
 +minix_dirmove(struct vnode *dvp, struct minix_direct *dirp, unsigned long count)
 +{
 +     	struct minix_inode *ip = VTOMI(dvp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	u_int32_t ind1[V2_INDIRECTS];
 +	u_int32_t blk;
 +	unsigned long idc;
 +	union minix_block *mbp;
 +	int ib, id, iz, error;
 +
 +	if (count < 2)
 +	     return EIO;
 +
 +	idc = 0;
 +	for (iz=0; iz<V2_NR_DBLOCKS; iz++) {
 +		if (dip->i_block[iz] == 0)
 +			return 0;
 +		ib = 1 << sp->s_zshift;
 +		blk = dip->i_block[iz] << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				if (mbp->dir[id].d_ino > 0) {
 +					dirp[idc].d_ino = mbp->dir[id].d_ino;
 +					strncpy(dirp[idc].d_name, mbp->dir[id].d_name, MINIX_NAME_MAX);
 +					if (++idc == count) {
 +					     bqrelse(bp);
 +					     return 0;
 +					}
 +				}
 +			}
 +			bqrelse(bp);
 +		}
 +	}
 +
 +	if (dip->i_block[V2_NR_DBLOCKS] == 0)
 +		return 0;
 +
 +	blk = dip->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +		return error;
 +	bcopy(bp->b_data, ind1, BLOCK_SIZE);
 +	bqrelse(bp);
 +	
 +	for (iz=0; iz<V2_NR_INDIRECTS; iz++) {
 +		if (ind1[iz] == 0)
 +			return 0;
 +		ib = 1 << sp->s_zshift;
 +		blk = ind1[iz] << sp->s_zshift;
 +		while(ib--) {
 +			if ((error = minix_getblk(devvp,blk++,&bp)) != 0)
 +				return error;
 +			mbp = MBLOCK(bp);
 +			for (id=0; id<NR_DIR_ENTRIES; id++) {
 +				if (mbp->dir[id].d_ino > 0) {
 +					dirp[idc].d_ino = mbp->dir[id].d_ino;
 +					strncpy(dirp[idc].d_name, mbp->dir[id].d_name, MINIX_NAME_MAX);
 +					if (++idc == count) {
 +						bqrelse(bp);
 +						return 0;
 +					}
 +				}
 +			}
 +			bqrelse(bp);
 +		}
 +	}
 +	return 0;	
 +}
 +/*
 + * Clean everything out of a directory except '.' and '..'.
 + */
 +static int
 +minix_dirclean(struct vnode *dvp)
 +{
 +     	struct minix_inode *ip = VTOMI(dvp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	struct buf *bp;
 +	u_int32_t ind1[V2_INDIRECTS];
 +	u_int32_t blk;
 +	union minix_block *mbp;
 +	int ib, ib0, id, iz, error;
 +
 +	if (dip->i_block[0] == 0) /* This zone must always exist */
 +		return EIO;
 +
 +	ip->i_blocks = 1 << sp->s_zshift;
 +	dip->i_size = 2*DIR_ENTRY_SIZE;
 +
 +	blk = dip->i_block[0] << sp->s_zshift;
 +	ib  = ip->i_blocks;
 +	ib0 = ib - 1;
 +
 +	while(ib--) {
 +		if ((error = minix_getblk(devvp,blk++, &bp)) != 0)
 +			return error;
 +		mbp = MBLOCK(bp);
 +		for (id=(ib==ib0)?2:0; id<NR_DIR_ENTRIES; id++)
 +			mbp->dir[id].d_ino = 0;
 +		bwrite(bp);
 +	}
 +
 +	for (iz=1; iz<V2_NR_DBLOCKS; iz++) {
 +		if (dip->i_block[iz] == 0)
 +			return 0;
 +		if ((error = minix_dzalloc(sp, dip->i_block[iz])) != 0)
 +			return error;
 +		dip->i_block[iz] = 0;
 +	}
 +
 +	if (dip->i_block[V2_NR_DBLOCKS] == 0)
 +		return 0;
 +
 +	blk = dip->i_block[V2_NR_DBLOCKS] << sp->s_zshift;
 +	if ((error = minix_getblk(devvp,blk,&bp)) != 0)
 +		return error;
 +	bcopy(bp->b_data, ind1, BLOCK_SIZE);
 +	brelse(bp);
 +
 +	if ((error = minix_dzalloc(sp, dip->i_block[V2_NR_DBLOCKS])) != 0)
 +	     return 0;
 +	dip->i_block[V2_NR_DBLOCKS] = 0;
 +
 +	for (iz=0; iz<V2_NR_INDIRECTS; iz++) {
 +		if (ind1[iz] == 0)
 +			return 0;
 +		if ((error = minix_dzalloc(sp, ind1[iz])) != 0)
 +			return error;
 +	}
 +	return 0;	
 +}
 +/*
 + * Returns non-zero if the directory is empty, zero otherwise.
 + */
 +int
 +minix_dirempty(struct minix_inode *ip, ino_t parentino, struct ucred *cred)
 +{
 +	off_t off;
 +	struct minix_direct dbuf;
 +	struct minix_direct *dp = (struct minix_direct*)&dbuf;
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	int error, count, namelen;
 +	int mindirsiz = sizeof(struct minix_direct);
 +
 +	for (off=0; off<(off_t)dip->i_size; off+=mindirsiz) {
 +		error = vn_rdwr(UIO_READ,ip->i_vnode,(caddr_t)dp,
 +		    mindirsiz, off, UIO_SYSSPACE, IO_NODELOCKED,
 +		    cred, &count, (struct proc*)0);
 +		if (error || count !=0)
 +			return 0;
 +		if (dp->d_ino == 0)
 +			continue;
 +		namelen = strlen(dp->d_name);
 +		if (namelen > 2)
 +			return 0;
 +		if (dp->d_name[0] != '.')
 +			return 0;
 +		if (namelen == 1 && dp->d_ino == ip->i_number)
 +			continue;
 +		if (dp->d_name[1] == '.' && dp->d_ino == parentino)
 +			continue;
 +		return 0;
 +	}
 +	return 1;
 +}
 +/*
 + * Check if source directory is in the path of the target directory.
 + * Target is supplied locked, source is unlocked.
 + * The target is always vput before returning.
 + */
 +int
 +minix_checkpath(struct minix_inode *source, struct minix_inode *target,
 +                struct ucred *cred)
 +{
 +	struct vnode *vp;
 +	struct minix_dirtemplate dirbuf;
 +	int error, rootino;
 +
 +	vp = target->i_vnode;
 +	if (target->i_number == source->i_number) {
 +		error = EEXIST;
 +		goto out;
 +	}
 +	rootino = ROOT_INO;
 +	error = 0;
 +	if (target->i_number == rootino)
 +		goto out;
 +
 +	/*
 +	 * Start at target and move to root, checking as we go.
 +	 */
 +	for (;;) {
 +		if (vp->v_type != VDIR) {
 +			error = ENOTDIR;
 +			break;
 +		}
 +		error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
 +		    sizeof(struct minix_dirtemplate), (off_t)0, UIO_SYSSPACE,
 +		    IO_NODELOCKED, cred, (int*)0, (struct proc*)0);
 +		if (error != 0)
 +			break;
 +		if (dirbuf.dotdot_name[0] != '.' ||
 +		    dirbuf.dotdot_name[1] != '.') {
 +			error = ENOTDIR;
 +			break;
 +		}
 +		if (dirbuf.dotdot_ino == source->i_number) {
 +			error = EINVAL;
 +			break;
 +		}
 +		if (dirbuf.dotdot_ino == rootino) /* Check until root */
 +			break;
 +		vput(vp);
 +		error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp);
 +		if (error) {
 +			vp = NULL;
 +			break;
 +		}
 +	}
 +out:
 +	if (vp != NULL)
 +		vput(vp);
 +	return error;
 +}
 +/*
 + * Rewrite an existing directory entry to point
 + * to the inode supplied. NOTE: This only works
 + * for the first block.
 + */
 +int
 +minix_dirrewrite(struct minix_inode *dp, struct minix_inode *ip,
 +                 ino_t ino, int entry)
 +{
 +	struct buf *bp;
 +	union minix_block *mbp;
 +	int off, error;
 +	off_t offset;
 +	u_daddr_t bln;
 +
 +	bln = entry / NR_DIR_ENTRIES;
 +	off = entry % NR_DIR_ENTRIES;
 +
 +	offset = (off_t)(bln*BLOCK_SIZE);
 +
 +	if ((error = minix_blkatoff(dp->i_vnode, offset, NULL, &bp)) != 0)
 +	     return error;
 +
 +	mbp = MBLOCK(bp);
 +	mbp->dir[off].d_ino = ino;
 +	
 +	ip->i_nlink--;
 +	ip->i_flag |= IN_CHANGE;
 +	dp->i_flag |= IN_CHANGE | IN_UPDATE;
 +	
 +	return bwrite(bp);
 +}
 +/*
 + *  The following was taken from FreeBSD's libc strtok.c and
 + *  slightly modified to use to parse the path in minix_namei().
 + */
 +static char *
 +minix_strtok_r(char *s, char *delim, char **last)
 +{
 +    char *spanp;
 +    int c, sc;
 +    char *tok;
 +
 +    if (s == NULL && (s = *last) == NULL)
 +    {
 +	return NULL;
 +    }
 +
 +    /*
 +     * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
 +     */
 +cont:
 +    c = *s++;
 +    for (spanp = (char *)delim; (sc = *spanp++) != 0; )
 +    {
 +	if (c == sc)
 +	{
 +	    goto cont;
 +	}
 +    }
 +
 +    if (c == 0)		/* no non-delimiter characters */
 +    {
 +	*last = NULL;
 +	return NULL;
 +    }
 +    tok = s - 1;
 +
 +    /*
 +     * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
 +     * Note that delim must have one NUL; we stop if we see that, too.
 +     */
 +    for (;;)
 +    {
 +	c = *s++;
 +	spanp = (char *)delim;
 +	do
 +	{
 +	    if ((sc = *spanp++) == c)
 +	    {
 +		if (c == 0)
 +		{
 +		    s = NULL;
 +		}
 +		else
 +		{
 +		    char *w = s - 1;
 +		    *w = '\0';
 +		}
 +		*last = s;
 +		return tok;
 +	    }
 +	}
 +	while (sc != 0);
 +    }
 +    /* NOTREACHED */
 +}
 +
 +static char *
 +minix_strtok(char *s, char *delim)
 +{
 +	static char *last = NULL;
 +
 +	return minix_strtok_r(s, delim, &last);
 +}
 diff -ruN sys.orig/fs/minixfs/minix_subr.c sys/fs/minixfs/minix_subr.c
 --- sys.orig/fs/minixfs/minix_subr.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_subr.c	Fri Feb 28 21:04:32 2003
 @@ -0,0 +1,262 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/proc.h>
 +#include <sys/kernel.h>
 +#include <sys/sysctl.h>
 +#include <sys/vnode.h>
 +#include <sys/mount.h>
 +#include <sys/buf.h>
 +#include <sys/lock.h>
 +#include <sys/malloc.h>
 +#include <sys/stat.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +int minix_to_dirent_type(struct minix_inode*);
 +int minix_chown(struct vnode*,uid_t,gid_t,struct ucred*,struct proc*);
 +int minix_chmod(struct vnode*,int,struct ucred*,struct proc*);
 +
 +/*
 + * Allocate a new inode in the file system and
 + * return its vnode.
 + */
 +int
 +minix_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp)
 +{
 +	struct minix_inode *pip = VTOMI(pvp);
 +	struct minix_super_block *sp = pip->i_su;
 +	struct mount *mp = pip->i_mmp->mnx_mp;
 +	struct minix_inode *ip;
 +	struct minix_dinode *dip;
 +	int ino, error;
 +	
 +	if ((error = minix_ialloc(sp, &ino)) != 0)
 +		return error;
 +
 +	if ((error = minix_vget(mp, ino, vpp)) != 0) {
 +		(void)minix_dialloc(sp, ino);
 +		return error;
 +	}
 +
 +	ip = VTOMI(*vpp);
 +	ip->i_parent = pip->i_number;
 +	ip->i_count  = 1;
 +	ip->i_blocks = 0;
 +	ip->i_mode = mode;
 +	ip->i_flag = IN_MODIFIED;
 +	ip->i_su = sp;
 +	
 +	dip = &(ip->i_dino);
 +	dip->i_mode = mode;        /* XXX Check this! */
 +	dip->i_size = 0;
 +	dip->i_nlinks = 1;
 +	dip->i_uid = cred->cr_uid;
 +	dip->i_gid = pip->i_dino.i_gid;
 +
 +	(*vpp)->v_type = minix_get_vtype(ip);
 +	
 +	return 0;
 +}
 +/*
 + * Initialize the vnode associated with a new inode, handle aliased
 + * vnodes.
 + */
 +int
 +minix_vinit(struct mount *mntp, vop_t **specops,
 +    vop_t **fifoops, struct vnode **vpp)
 +{
 +	struct vnode *vp;
 +	struct minix_inode *ip;
 +	struct minix_dinode *dip;
 +	int maj, min;
 +
 +	vp = *vpp;
 +	ip = VTOMI(vp);
 +	dip = &(ip->i_dino);
 +	
 +	switch(vp->v_type) {
 +	case VCHR:
 +	case VBLK:
 +		vp->v_op = specops;
 +		maj = (dip->i_block[0] >> 8) & 0xff;
 +		min =  dip->i_block[0] & 0xff;
 +		addaliasu(vp, dev2udev(makedev(maj,min)));
 +		break;
 +	case VFIFO:
 +		vp->v_op = fifoops;
 +		break;
 +	default:
 +		break;
 +	}
 +	
 +	if (ip->i_number == ROOT_INO)
 +		vp->v_flag |= VROOT;
 +
 +	*vpp = vp;
 +	
 +	return 0;
 +}
 +/*
 + * Perform chown operation on inode ip;
 + * inode must be locked prior to call.
 + * Modified from ufs; PRISON_ROOT is not recognize by
 + * Minix at this time, so is a no-op.
 + */
 +int
 +minix_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
 +   struct proc *p)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	uid_t ouid;
 +	gid_t ogid;
 +	int error = 0;
 +
 +	if (uid == (uid_t)VNOVAL)
 +		uid = dip->i_uid;
 +	if (gid == (gid_t)VNOVAL)
 +		gid = dip->i_gid;
 +	/*
 +	 * If we don't own the file, are trying to change the owner
 +	 * of the file, or are not a member of the target group,
 +	 * the caller must be superuser or the call fails.
 +	 */
 +	if ((cred->cr_uid != dip->i_uid || uid != dip->i_uid ||
 +	    (gid != dip->i_gid && !groupmember((gid_t)gid, cred))) &&
 +	    (error = suser_xxx(cred, p, PRISON_ROOT)))
 +		return (error);
 +	ogid = dip->i_gid;
 +	ouid = dip->i_uid;
 +
 +	dip->i_gid = gid;
 +	dip->i_uid = uid;
 +
 +	ip->i_flag |= IN_CHANGE;
 +	if (cred->cr_uid != 0 && (ouid != uid || ogid != gid))
 +		ip->i_mode &= ~(ISUID | ISGID);	
 +	
 +	return 0;
 +}
 +/*
 + * Change the mode on a file.
 + * Inode must be locked before calling.
 + * Modified from ufs; there are some options that are
 + * not recognized by minix at this time: PRISON_ROOT, S_ISTXT.
 + */
 +int
 +minix_chmod(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
 +{
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	int error;
 +
 +     	if (cred->cr_uid != dip->i_uid) {
 +		error = suser_xxx(cred, p, PRISON_ROOT);
 +		if (error)
 +			return (error);
 +	}
 +	if (cred->cr_uid) {
 +		if (vp->v_type != VDIR && (mode & S_ISTXT))
 +			return (EFTYPE);
 +		if (!groupmember(dip->i_gid, cred) && (mode & ISGID))
 +			return (EPERM);
 +	}
 +	ip->i_mode &= ~ALLPERMS;
 +	ip->i_mode |= (mode & ALLPERMS);
 +	dip->i_mode = ip->i_mode;
 +	ip->i_flag |= IN_CHANGE;
 +	return 0;
 +}
 +
 +#include <sys/dirent.h>
 +
 +int
 +minix_to_dirent_type(struct minix_inode *ip)
 +{
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	int f_type;
 +
 +	switch(dip->i_mode & I_TYPE) {
 +	case I_NAMED_PIPE:
 +		f_type = DT_FIFO;
 +		break;
 +	case I_CHAR_SPECIAL:
 +		f_type = DT_CHR;
 +		break;
 +	case I_DIRECTORY:
 +		f_type = DT_DIR;
 +		break;
 +	case I_BLOCK_SPECIAL:
 +		f_type = DT_BLK;
 +		break;
 +	case I_REGULAR:
 +		f_type = DT_REG;
 +		break;
 +	case I_LINK:
 +		f_type = DT_LNK;
 +		break;
 +	case I_SOCK:
 +		f_type = DT_SOCK;
 +		break;
 +	default:
 +		f_type = DT_UNKNOWN;
 +		break;
 +	}
 +
 +	return f_type;
 +}
 +
 +/* Returns ufs vnode type given a minix inode */
 +
 +int
 +minix_get_vtype(struct minix_inode *ip)
 +{
 +	switch (ip->i_mode & I_TYPE) {
 +	case I_DIRECTORY:
 +		return VDIR;
 +	case I_REGULAR:
 +		return VREG;
 +	case I_BLOCK_SPECIAL:
 +		return VBLK;
 +	case I_CHAR_SPECIAL:
 +		return VCHR;
 +	case I_NAMED_PIPE:
 +		return VFIFO;
 +	case I_LINK:
 +		return VLNK;
 +	case I_SOCK:
 +		return VSOCK;
 +	default:
 +	     /*
 +		return VNON;
 +	     */
 +	     break;
 +	}
 +	return VBAD;
 +}
 diff -ruN sys.orig/fs/minixfs/minix_ufs.c sys/fs/minixfs/minix_ufs.c
 --- sys.orig/fs/minixfs/minix_ufs.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_ufs.c	Fri Feb 28 13:46:38 2003
 @@ -0,0 +1,60 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +
 +/*
 + * This little bit of code needs to be separate from the rest of
 + * the Minix code because of name conflicts between minix.h and
 + * the ufs include files.
 + */
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/proc.h>
 +#include <sys/kernel.h>
 +#include <sys/mount.h>
 +#include <sys/vnode.h>
 +
 +#include <ufs/ufs/quota.h>
 +#include <ufs/ufs/inode.h>
 +
 +ino_t ufs_parent_ino(struct mount*);
 +ino_t ufs_vnode_ino(struct vnode*);
 +
 +ino_t
 +ufs_parent_ino(struct mount *mp)
 +{
 +     struct vnode *vp = mp->mnt_vnodecovered;
 +     struct inode *ip = (struct inode*)vp->v_data;
 +
 +     return (ino_t)ip->i_number;
 +}
 +
 +ino_t
 +ufs_vnode_ino(struct vnode *vp)
 +{
 +     struct inode *ip = (struct inode*)vp->v_data;
 +
 +     return (ino_t)ip->i_number;
 +}
 diff -ruN sys.orig/fs/minixfs/minix_vfsops.c sys/fs/minixfs/minix_vfsops.c
 --- sys.orig/fs/minixfs/minix_vfsops.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_vfsops.c	Fri Feb 28 20:07:19 2003
 @@ -0,0 +1,716 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +/*
 + * This file is modelel after both the ufs and ext2fs code.
 + */
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/proc.h>
 +#include <sys/kernel.h>
 +#include <sys/sysctl.h>
 +#include <sys/lock.h>
 +#include <sys/conf.h>
 +#include <sys/vnode.h>
 +#include <sys/mount.h>
 +#include <sys/namei.h>
 +#include <sys/disklabel.h>
 +#include <sys/fcntl.h>
 +#include <sys/stat.h>
 +#include <sys/malloc.h>
 +#include <sys/module.h>
 +#include <sys/buf.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +/* Various locks used throughout */
 +
 +int minix_inode_hash_lock;
 +
 +static int minix_mount(struct mount*, char*, caddr_t,
 +    struct nameidata*, struct proc*);
 +static int minix_unmount(struct mount*, int, struct proc*);
 +static int minix_root(struct mount*, struct vnode**);
 +static int minix_statfs(struct mount*, struct statfs*, struct proc*);
 +static int minix_sync(struct mount*, int, struct ucred*, struct proc*);
 +static int minix_start(struct mount*, int, struct proc*);
 +static int minix_init(struct vfsconf*);
 +static int minix_uninit(struct vfsconf*);
 +ino_t ufs_parent_ino(struct mount*);
 +ino_t ufs_vnode_ino(struct vnode*);
 +
 +struct minix_args {
 +	char               *fspec;
 +	struct export_args export;
 +};
 +
 +MALLOC_DEFINE(M_MINIXMNT, "Minixfs mount", "Minixfs mount structure");
 +MALLOC_DEFINE(M_MINIXNOD, "Minixfs node", "Minixfs vnode");
 +
 +static int
 +minix_mount(struct mount *mp, char *path, caddr_t data,
 +    struct nameidata *ndp, struct proc *p)
 +{
 +	struct minix_args args;
 +	struct minixmount *mmp = NULL;
 +	struct vnode *devvp, *vproot;
 +	struct buf *bp;
 +	struct minix_super_block *es;
 +	struct ucred *cred = p->p_ucred;
 +	int error = 0, ronly = 0, size;
 +	u_daddr_t iblkn, zblkn;
 +	long isize, ssize, zsize;
 +	mode_t accessmode;
 +
 +	if (p->p_ucred->cr_uid != 0)
 +		return EACCES;
 +
 +	if (mp->mnt_flag & MNT_UPDATE)
 +		return EOPNOTSUPP;
 +
 +	/* no asynchronous updates and no soft updates */
 +
 +	mp->mnt_flag &= ~(MNT_ASYNC | MNT_SOFTDEP);
 +	
 +	/***  FORCE READ-ONLY FOR DEBUGGING  ***/
 +/*
 +	mp->mnt_flag |= MNT_RDONLY;
 +*/
 +	/***  FORCE NODEV and NOEXEC for safety ***/
 +
 +	mp->mnt_flag |= (MNT_NODEV | MNT_NOEXEC);
 +	
 +	error = copyin(data, (caddr_t)&args, sizeof(struct minix_args));
 +	if (error)
 +		return error;
 +
 +	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
 +	ndp->ni_vp = NULL;
 +	if ((error = namei(ndp)) != 0)
 +		return error;	
 +	NDFREE(ndp, NDF_ONLY_PNBUF);
 +
 +	if (ndp->ni_vp != NULL)
 +		devvp = ndp->ni_vp;
 +	else {
 +		printf("devvp is NULL!\n");
 +		return ENXIO;
 +	}
 +	
 +	if (!vn_isdisk(devvp, &error)) {
 +		printf("vn_isdisk error = %d\n",error);
 +		goto out;
 +	}
 +
 +	if (vcount(devvp) < 1) {
 +		printf("devvp: vcount < 1!\n");
 +		return ENXIO;
 +	}
 +
 +	/*
 +	 * Disallow multiple mounts of the same device.
 +	 * Disallow mounting of a device that is currently in use
 +	 * (except for root, which might share swap device for miniroot).
 +	 * Flush out any old buffers remaining from a previous use.
 +	 */
 +
 +	if ((error = vfs_mountedon(devvp)) != 0) {
 +		printf("vfs_mountedon error\n");
 +		goto out;
 +	}
 +	
 +	if (vcount(devvp) > 1 && devvp != rootvp) {
 +		printf("vcount error\n");
 +		error = EBUSY;
 +		goto out;
 +	}
 +
 +	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
 +	error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
 +	VOP_UNLOCK(devvp, 0, p);
 +
 +	if (error) {
 +		printf("vinvalbuf error\n");
 +		goto out;
 +	}
 +
 +	/*
 +	 * If mount by non-root, then verify that the user has
 +	 * the necessary permissions on the device.
 +	 */
 +	if (cred->cr_uid != 0) {
 +		accessmode = VREAD;
 +		if ((mp->mnt_flag & MNT_RDONLY) == 0)
 +			accessmode |= VWRITE;
 +		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
 +		if ((error = VOP_ACCESS(devvp, accessmode, cred, p)) != 0) {
 +			vput(devvp);
 +			return (error);
 +		}
 +		VOP_UNLOCK(devvp, 0, p);
 +	}
 +
 +	/*
 +	 * Only VMIO the backing device if the backing device is a real
 +	 * block device.  This excludes the original MFS implementation.
 +	 * Note that it is optional that the backing device be VMIOed.  This
 +	 * increases the opportunity for metadata caching.
 +	 */
 +	if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) {
 +		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
 +		vfs_object_create(devvp, p, p->p_ucred);
 +		simple_lock(&devvp->v_interlock);
 +		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
 +	}
 +	
 +	/*********************************/
 +
 +	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
 +	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
 +	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
 +	VOP_UNLOCK(devvp, 0, p);
 +	
 +	if (error) {
 +		printf("VOP_OPEN error\n");
 +		goto out;
 +	}
 +
 +	if (devvp->v_rdev->si_iosize_max != 0)
 +		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
 +	if (mp->mnt_iosize_max > MAXPHYS)
 +		mp->mnt_iosize_max = MAXPHYS;
 +
 +	bp  = NULL;
 +	if ((error = bread(devvp, LSV2BLOCK, BLOCK_SIZE, NOCRED, &bp)) != 0) {
 +		printf("bread error reading superblock: %d\n",error);
 +		goto out;
 +	}
 +	
 +	es = (struct minix_super_block *)bp->b_data;
 +
 +	if (es->s_magic != SUPER_V2) {
 +		printf("Invalid super block = 0x%x\n",es->s_magic);
 +		error = EINVAL;
 +		goto out;
 +	}
 +
 +	if ((mmp = malloc(sizeof(struct minixmount), M_MINIXMNT, M_WAITOK)) == NULL) {
 +		error = ENOMEM;
 +		goto out;
 +	}
 +	bzero(mmp, sizeof(struct minixmount));
 +
 +	mp->mnt_data = (qaddr_t)mmp;
 +
 +	/* The superblock gets stored in mmp */
 +	
 +	if ((mmp->mnx_su = malloc(sizeof(struct minix_super_block),
 +	    M_MINIXMNT, M_WAITOK)) == NULL) {
 +		error = ENOMEM;
 +		goto out;
 +	}
 +	
 +	bcopy(es, mmp->mnx_su, sizeof(struct minix_super_block));
 +	
 +	brelse(bp);
 +	bp = NULL;
 +
 +	/* Reset es to point to the stored super block */
 +
 +	es = mmp->mnx_su;
 +
 +	/* Fill the in-core super with stuff */
 +	
 +	es->s_firstinode = 2 + es->s_imap_blocks + es->s_zmap_blocks;
 +	es->s_zoff = es->s_firstdatazone - 1;
 +	es->s_version = 2;
 +	es->s_dev = devvp->v_rdev;
 +	es->s_devvp = devvp;
 +	es->s_rdonly = ronly;
 +	es->s_bsize = BLOCK_SIZE;
 +	es->s_zsize = BLOCK_SIZE << es->s_zshift;
 +	es->s_imnton = ufs_parent_ino(mp);
 +	es->s_max_size = ((es->s_zones - es->s_zoff) << es->s_zshift)*BLOCK_SIZE;
 +
 +	isize = blk_to_byte(es->s_imap_blocks);
 +	zsize = blk_to_byte(es->s_zmap_blocks);
 +	iblkn = byte_to_blkn(blk_to_byte(2));
 +	zblkn = byte_to_blkn(blk_to_byte(es->s_imap_blocks + 2));
 +
 +	/* Load the bitmaps into the in-core super */
 +
 +	es->s_ibmap = (u_int16_t*)malloc(isize, M_MINIXMNT, M_WAITOK);
 +	if (es->s_ibmap == NULL) {
 +		error = ENOMEM;
 +		goto out;
 +	}
 +	es->s_zbmap = (u_int16_t*)malloc(zsize, M_MINIXMNT, M_WAITOK);
 +	if (es->s_zbmap == NULL) {
 +		error = ENOMEM;
 +		free(es->s_ibmap, M_MINIXMNT);
 +		goto out;
 +	}
 +	bzero(es->s_ibmap, isize);
 +	bzero(es->s_zbmap, zsize);
 +	es->imap_lock = 0l;
 +	es->zmap_lock = 0l;
 +
 +	if ((error = bread(devvp, iblkn, isize, NOCRED, &bp)) != 0) {
 +		printf("bread error reading inode bitmap\n");
 +		free(es->s_ibmap, M_MINIXMNT);
 +		free(es->s_zbmap, M_MINIXMNT);
 +		goto out;
 +	}
 +	bcopy((caddr_t)bp->b_data, es->s_ibmap, isize);
 +	brelse(bp);
 +	bp = NULL;
 +
 +	if ((error = bread(devvp, zblkn, zsize, NOCRED, &bp)) != 0) {
 +		printf("bread error reading block bitmap\n");
 +		free(es->s_ibmap, M_MINIXMNT);
 +		free(es->s_zbmap, M_MINIXMNT);
 +		goto out;
 +	}
 +	bcopy((caddr_t)bp->b_data, es->s_zbmap, zsize);
 +	brelse(bp);
 +	bp = NULL;
 +
 +	/* Finish filling mmp */
 +
 +	mmp->mnx_devvp = devvp;
 +	mmp->mnx_dev   = devvp->v_rdev;
 +	mmp->mnx_mp    = mp;
 +       	mmp->mnx_malloctype = M_MINIXNOD;
 +
 +	/* Complete the mount */
 +
 +	mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(devvp->v_rdev);
 +	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
 +	mp->mnt_maxsymlinklen = MINIX_MAXSYMLINKLEN; /* Max short symlink */
 +	mp->mnt_flag |= MNT_LOCAL;
 +	
 +	devvp->v_specmountpoint = mp;
 +
 +	/**************/
 +
 +	/* Save "last mounted on" info for mount point (NULL pad)*/
 +	copyinstr(	path,				/* mount point*/
 +	    mp->mnt_stat.f_mntonname,	                /* save area*/
 +	    MNAMELEN - 1,			        /* max size*/
 +	    &size);				        /* real size*/
 +	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
 +
 +	/* Save "mounted from" info for mount point (NULL pad)*/
 +	copyinstr(	args.fspec,			/* device name*/
 +	    mp->mnt_stat.f_mntfromname,	                /* save area*/
 +	    MNAMELEN - 1,			        /* max size*/
 +	    &size);				        /* real size*/
 +	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
 +
 +	mp->mnt_stat.f_type = mp->mnt_vfc->vfc_typenum;
 +	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
 +	mp->mnt_stat.f_flags = mp->mnt_flag;
 +
 +	minix_statfs(mp, &mp->mnt_stat, p);
 +
 +	/* minix_root increments usecount as well as locks the vnode */
 +
 +	es->s_root = (struct minix_inode*)NULL;
 +	
 +	if ((error = minix_root(mp, &vproot)) != 0) {
 +		free(es->s_ibmap, M_MINIXMNT);
 +		free(es->s_zbmap, M_MINIXMNT);
 +		goto out;
 +	}
 +
 +	ssize = sizeof(struct minix_inode);
 +
 +	es->s_root = (struct minix_inode*)malloc(ssize, M_MINIXMNT, M_WAITOK);
 +	if (es->s_root == NULL) {
 +	     free(es->s_ibmap, M_MINIXMNT);
 +	     free(es->s_zbmap, M_MINIXMNT);
 +	     goto out;
 +	}
 +	bcopy((char*)vproot->v_data, es->s_root, ssize);
 +	vput(vproot);
 +	
 +	es->s_root->i_parent = es->s_imnton;
 +
 +	return 0;
 +
 +out:
 +	devvp->v_specmountpoint = NULL;
 +	if (bp)
 +		brelse(bp);
 +	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
 +	if (vcount(devvp) > 0)
 +	     vrele(devvp);
 +	if (mmp) {
 +	     	if (mmp->mnx_su)
 +			free(mmp->mnx_su, M_MINIXMNT);
 +		free(mmp, M_MINIXMNT);
 +	}
 +	
 +	mp->mnt_data = (qaddr_t)0;
 +		
 +	return error;
 +}
 +
 +static int
 +minix_unmount(struct mount *mp, int mntflags, struct proc *p)
 +{
 +	struct minixmount *mmp = (struct minixmount*)(mp->mnt_data);
 +	struct minix_inode *rip = mmp->mnx_su->s_root;
 +	struct vnode *devvp;
 +	int error, ronly, flags;
 +
 +	flags = 0;
 +	if (mntflags & MNT_FORCE)
 +	     flags |= FORCECLOSE;
 +
 +	/* Flush all the vnodes associated with mp. */
 +	
 +	if ((error = vflush(mp, 0, flags)) != 0)
 +	     return error;
 +
 +	cache_purgevfs(mp);
 +
 +	devvp = mmp->mnx_devvp;
 +
 +	/* Sync up metadata */
 +
 +	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
 +	error = VOP_FSYNC(devvp, p->p_ucred, MNT_WAIT, p);
 +	VOP_UNLOCK(devvp, 0, p);
 +
 +	minix_ihashrem(rip);
 +
 +	devvp->v_specmountpoint = NULL;
 +	vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, 0);
 +	ronly =(mp->mnt_flag & MNT_RDONLY) != 0;
 +	error = VOP_CLOSE(devvp,ronly ? FREAD : FREAD|FWRITE,NOCRED,p);
 +	vrele(devvp);
 +
 +	free(mmp->mnx_su->s_ibmap, M_MINIXMNT);
 +	free(mmp->mnx_su->s_zbmap, M_MINIXMNT);
 +	if (mmp->mnx_su->s_root)
 +	     free(mmp->mnx_su->s_root, M_MINIXMNT);
 +	free(mmp->mnx_su, M_MINIXMNT);
 +	free(mmp, M_MINIXMNT);
 +	mp->mnt_data = (qaddr_t)0;
 +	mp->mnt_flag &= ~MNT_LOCAL;
 +	
 +	return error;
 +}
 +
 +static int
 +minix_root(struct mount *mp, struct vnode **vpp)
 +{
 +	return minix_vget(mp, (ino_t)ROOT_INO, vpp);
 +}
 +
 +static int
 +minix_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
 +{
 +	struct minixmount *mmp;
 +	struct minix_super_block *sp;
 +	size_t size;
 +
 +	mmp = (struct minixmount*)(mp->mnt_data);
 +	sp  = mmp->mnx_su;
 +	
 +	sbp->f_bsize  = BLOCK_SIZE;
 +	sbp->f_iosize = BLOCK_SIZE;
 +	sbp->f_blocks = (sp->s_zones - sp->s_zoff) << sp->s_zshift;
 +	sbp->f_bfree  = (minix_free_zone_count(sp) << sp->s_zshift);
 +	sbp->f_ffree  = minix_free_inode_count(sp);
 +	sbp->f_files  = sp->s_ninodes;
 +	sbp->f_bavail = sbp->f_bfree;
 +	copystr("minixfs", sbp->f_fstypename,8, &size);
 +
 +	if (sbp != &mp->mnt_stat) {
 +		sbp->f_type  = mp->mnt_vfc->vfc_typenum;
 +		sbp->f_owner = mp->mnt_stat.f_owner;
 +		sbp->f_flags = mp->mnt_flag;
 +		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
 +		    (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
 +		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
 +		    (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
 +	}
 +	
 +	return 0;
 +}
 +/*
 + * Convert an inode number into a locked vnode.
 + */
 +int
 +minix_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
 +{
 +	struct minix_super_block *su;
 +	struct minix_inode *ip;
 +	struct minixmount *mmp;
 +	struct vnode *vp;
 +	dev_t dev;
 +	int error;
 +
 +	*vpp = NULL;
 +	mmp  = (struct minixmount*)(mp->mnt_data);
 +	dev  = mmp->mnx_dev;
 +	su   = mmp->mnx_su;
 +
 +	/* Look for the vnode in the hash table first */
 +	
 +restart:
 +	if ((*vpp = minix_ihashget(dev, ino)) != NULL) {
 +
 +		vp = *vpp;
 +		ip = VTOMI(vp);
 +
 +		(void)minix_vinit(mp, minix_specop_p, minix_fifoop_p, vpp);
 +
 +		if (ino == ROOT_INO)
 +			vp->v_flag |= VROOT;
 +		
 +		return 0;
 +	}
 +	
 +	if (minix_inode_hash_lock) {
 +		while (minix_inode_hash_lock) {
 +			minix_inode_hash_lock = -1;
 +			tsleep(&minix_inode_hash_lock, PVM, "mnxfsgt", 0);
 +		}
 +		goto restart;
 +	}
 +	minix_inode_hash_lock = 1;
 +
 +	/* Not in the hash table; so make a new vnode/inode pair. */
 +
 +	MALLOC(ip, struct minix_inode*,sizeof(struct minix_inode),
 +	    M_MINIXNOD, M_WAITOK);
 +	
 +	if ((error = minix_iget(mmp->mnx_devvp, su, (mino_t)ino, ip)) != 0) {
 +		FREE(ip, M_MINIXNOD);
 +		*vpp = NULL;
 +		return error;
 +	}
 +
 +	/* Allocate a new vnode */
 +	
 +	error = getnewvnode(VT_MINIXFS, mp, minix_vnodeop_p, &vp);
 +     	if (error) {
 +		if (minix_inode_hash_lock < 0)
 +			wakeup(&minix_inode_hash_lock);
 +		minix_inode_hash_lock = 0;
 +		*vpp = NULL;
 +		FREE(ip, M_MINIXNOD);
 +		return (error);
 +	}
 +
 +	vp->v_data = ip;     /* connect vnode to inode */
 +
 +	/* Set up lock sharing in the stack of vnodes */
 +	
 +	lockinit(&ip->i_lock, PINOD, "minix_inode", VLKTIMEOUT, LK_CANRECURSE);
 +	vp->v_vnlock = &ip->i_lock;
 +
 +	/* Load up the inode with info */
 +	
 +	ip->i_vnode = vp;
 +	ip->i_dev = dev;       /* Specinfo pointer */
 +	ip->i_su  = su;
 +	ip->i_number = ino;
 +	ip->i_parent = 0;      /* Don't know this yet */
 +	ip->i_mmp    = mmp;
 +	ip->i_flag   = 0;
 +	ip->i_mode = ip->i_dino.i_mode;
 +	ip->i_blocks = minix_num_blocks(ip->i_mode, ip->i_dino.i_size, su->s_zshift);
 +	ip->i_count = 1;
 +	ip->i_entry = 0;
 +	ip->i_noent = 0;
 +
 +	/* Put the inode into the hash table */
 +	
 +	minix_ihashins(ip);   /* This leads to panics after remounts! */
 +
 +	/* We just lock the inode here and forget about hashing for now. */
 +
 +	lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, curproc);
 +
 +	if (minix_inode_hash_lock < 0)
 +		wakeup(&minix_inode_hash_lock);
 +	
 +	minix_inode_hash_lock = 0;
 +
 +	/* Put more good stuff into the vnode */
 +
 +	vp->v_type = minix_get_vtype(ip);
 +
 +	if (ino == ROOT_INO) {
 +	     vp->v_flag |= VROOT;
 +	     ip->i_flag |= VROOT;
 +	}
 +	
 +	error = minix_vinit(mp, minix_specop_p, minix_fifoop_p, &vp);
 +	if (error) {
 +	        minix_ihashrem(ip);
 +		FREE(ip, M_MINIXNOD);
 +		vput(vp);
 +		*vpp = NULL;
 +		return error;
 +	}
 +
 +	/* Reference the device vnode */
 +	
 +	VREF(su->s_devvp);
 +  
 +	*vpp = vp;
 +     
 +	return 0;
 +}
 +
 +static int
 +minix_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p)
 +{
 +	struct vnode *vp, *nvp;
 +	struct minix_inode *ip;
 +	struct minixmount *mmp;
 +	struct minix_super_block *su;
 +	int error, allerror = 0;
 +
 +	mmp = (struct minixmount*)(mp->mnt_data);
 +        su = mmp->mnx_su;
 +
 +	/*
 +	 *  Write back each (modified) inode.
 +	 */
 +	simple_lock(&mntvnode_slock);
 +loop:
 +	for(vp=TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
 +		if (vp->v_mount != mp)
 +			goto loop;
 +		nvp = TAILQ_NEXT(vp, v_nmntvnodes);
 +		ip = vp->v_data;
 +		if (vp->v_type == VNON || ((ip->i_flag *
 +		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
 +		    TAILQ_EMPTY(&vp->v_dirtyblkhd)))
 +			continue;
 +		if (vp->v_type != VCHR) {
 +						simple_unlock(&mntvnode_slock);
 +			error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT, p);
 +			if (error) {
 +				simple_lock(&mntvnode_slock);
 +				if (error == ENOENT)
 +					goto loop;
 +			} else {
 +				if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
 +					allerror = error;
 +				VOP_UNLOCK(vp, 0, p);
 +				vrele(vp);
 +				simple_lock(&mntvnode_slock);
 +			}
 +			
 +		} else {
 +                        /*
 +			 * We must reference the vp to prevent it from
 +			 * getting ripped out from under UFS_UPDATE, since
 +			 * we are not holding a vnode lock.  XXX why aren't
 +			 * we holding a vnode lock?
 +			 */
 +			VREF(vp);
 +			simple_unlock(&mntvnode_slock);
 +                        minix_update(vp);
 +			vrele(vp);
 +			simple_lock(&mntvnode_slock);
 +		}
 +		if (TAILQ_NEXT(vp, v_nmntvnodes) != nvp)
 +			goto loop;
 +	}
 +	simple_unlock(&mntvnode_slock);
 +	/*
 +	 * Force stale file system control information to be flushed.
 +	 */
 +	if (waitfor != MNT_LAZY) {
 +		if (mmp->mnx_mp->mnt_flag & MNT_SOFTDEP)
 +			waitfor = MNT_NOWAIT;
 +		vn_lock(mmp->mnx_devvp, LK_EXCLUSIVE | LK_RETRY, p);
 +		if ((error = VOP_FSYNC(mmp->mnx_devvp, cred, waitfor, p)) != 0)
 +			allerror = error;
 +		VOP_UNLOCK(mmp->mnx_devvp, 0, p);
 +	}
 +	return 0;
 +}
 +
 +static int
 +minix_start(struct mount *mp, int flags, struct proc *p)
 +{
 +	return 0;
 +}
 +
 +/*
 + *  minix_init is called by kld when the minixfs is loaded.
 + */
 +static int
 +minix_init(struct vfsconf *vfsp)
 +{
 +	static int done = 0;
 +
 +	if (done == 1)
 +		return 0;
 +
 +	minix_inode_hash_lock = 0;
 +	minix_ihashinit();
 +	done = 1;
 +     
 +	return 0;
 +}
 +
 +/*
 + *  minix_uninit is called by kld when the minixfs is unloaded.
 + */
 +static int
 +minix_uninit(struct vfsconf *vfsp)
 +{
 +	minix_ihashuninit();
 +	return 0;
 +}
 +
 +static struct vfsops minixfs_vfsops = {
 +	minix_mount,
 +	minix_start,
 +	minix_unmount,
 +	minix_root,
 +	vfs_stdquotactl,
 +	minix_statfs,
 +	minix_sync,
 +	minix_vget,
 +	vfs_stdfhtovp,
 +	vfs_stdcheckexp,
 +	vfs_stdvptofh,
 +	minix_init,
 +	minix_uninit,
 +	vfs_stdextattrctl,
 +};
 +
 +VFS_SET(minixfs_vfsops, minixfs, 0);
 diff -ruN sys.orig/fs/minixfs/minix_vnops.c sys/fs/minixfs/minix_vnops.c
 --- sys.orig/fs/minixfs/minix_vnops.c	Wed Dec 31 16:00:00 1969
 +++ sys/fs/minixfs/minix_vnops.c	Fri Feb 28 20:24:43 2003
 @@ -0,0 +1,1722 @@
 +/*-
 + * Copyright (c) 2003 Ed Alley: wea@llnl.gov
 + * All rights reserved.
 + *
 + * 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 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 AUTHOR 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.
 + */
 +/*
 + * This file has borrowed heavily from FreeBSD's ufs and ext2fs
 + * implementations.
 + */
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/proc.h>
 +#include <sys/kernel.h>
 +#include <sys/sysctl.h>
 +#include <sys/vnode.h>
 +#include <sys/lock.h>
 +#include <sys/malloc.h>
 +#include <sys/mount.h>
 +#include <sys/stat.h>
 +#include <sys/dirent.h>
 +#include <sys/fcntl.h>
 +#include <sys/buf.h>
 +#include <sys/namei.h>
 +#include <sys/unistd.h>
 +
 +#include <vm/vm.h>
 +#include <vm/vm_extern.h>
 +#include <vm/vm_zone.h>
 +#include <vm/vnode_pager.h>
 +
 +#include <miscfs/fifofs/fifo.h>
 +
 +#include <fs/minixfs/minix.h>
 +
 +int minix_lookup(struct vop_cachedlookup_args*);
 +int minix_to_dirent_type(struct minix_inode*);
 +int minix_chown(struct vnode*,uid_t,gid_t,struct ucred*,struct proc*);
 +int minix_chmod(struct vnode*,int,struct ucred*,struct proc*);
 +
 +static int minix_fsync(struct vop_fsync_args*);
 +static int minix_inactive(struct vop_inactive_args*);
 +static int minix_reclaim(struct vop_reclaim_args*);
 +static int minix_readdir(struct vop_readdir_args*);
 +static int minix_readlink(struct vop_readlink_args*);
 +static int minix_symlink(struct vop_symlink_args*);
 +static int minix_open(struct vop_open_args*);
 +static int minix_close(struct vop_close_args*);
 +static int minix_create(struct vop_create_args*);
 +static int minix_remove(struct vop_remove_args*);
 +static int minix_link(struct vop_link_args*);
 +static int minix_mkdir(struct vop_mkdir_args*);
 +static int minix_rmdir(struct vop_rmdir_args*);
 +static int minix_read(struct vop_read_args*);
 +static int minix_write(struct vop_write_args*);
 +static int minix_bmap(struct vop_bmap_args*);
 +static int minix_getpages(struct vop_getpages_args*);
 +static int minix_putpages(struct vop_putpages_args*);
 +static int minix_access(struct vop_access_args*);
 +static int minix_getattr(struct vop_getattr_args*);
 +static int minix_rename(struct vop_rename_args*);
 +static int minix_setattr(struct vop_setattr_args*);
 +static int minix_mknod(struct vop_mknod_args*);
 +static int minixfifo_read(struct vop_read_args*);
 +static int minixfifo_write(struct vop_write_args*);
 +static int minixfifo_close(struct vop_close_args*);
 +static int minix_pathconf(struct vop_pathconf_args*);
 +
 +#define PRINTD(x) printf(x);
 +#undef PRINTD(x)
 +#define PRINTD(x)
 +
 +#undef MINIX_DEBUG
 +
 +vop_t **minix_vnodeop_p;
 +static struct vnodeopv_entry_desc minix_vnodeop_entries[] = {
 +	{ &vop_default_desc,		(vop_t *) vop_defaultop },
 +	{ &vop_cachedlookup_desc,       (vop_t *) minix_lookup },
 +	{ &vop_lookup_desc,             (vop_t *) vfs_cache_lookup },
 +	{ &vop_fsync_desc,		(vop_t *) minix_fsync },
 +	{ &vop_inactive_desc,		(vop_t *) minix_inactive },
 +	{ &vop_reclaim_desc,            (vop_t *) minix_reclaim },
 +	{ &vop_read_desc,		(vop_t *) minix_read },
 +	{ &vop_readdir_desc,		(vop_t *) minix_readdir },
 +	{ &vop_readlink_desc,           (vop_t *) minix_readlink },
 +	{ &vop_symlink_desc,            (vop_t *) minix_symlink },
 +	{ &vop_bmap_desc,               (vop_t *) minix_bmap },
 +	{ &vop_write_desc,		(vop_t *) minix_write },
 +	{ &vop_access_desc,             (vop_t *) minix_access },
 +	{ &vop_getattr_desc,            (vop_t *) minix_getattr },
 +	{ &vop_setattr_desc,            (vop_t *) minix_setattr },
 +        { &vop_open_desc,               (vop_t *) minix_open },
 +	{ &vop_close_desc,              (vop_t *) minix_close },
 +	{ &vop_create_desc,             (vop_t *) minix_create },
 +	{ &vop_remove_desc,             (vop_t *) minix_remove },
 +	{ &vop_link_desc,		(vop_t *) minix_link },
 +	{ &vop_mkdir_desc,              (vop_t *) minix_mkdir },
 +	{ &vop_rmdir_desc,              (vop_t *) minix_rmdir },
 +	{ &vop_rename_desc,		(vop_t *) minix_rename },
 +	{ &vop_mknod_desc,		(vop_t *) minix_mknod },
 +	{ &vop_pathconf_desc,           (vop_t *) minix_pathconf },
 +	{ &vop_islocked_desc,           (vop_t *) vop_stdislocked },
 +	{ &vop_lock_desc,               (vop_t *) vop_stdlock },
 +	{ &vop_poll_desc,               (vop_t *) vop_stdpoll },
 +	{ &vop_unlock_desc,             (vop_t *) vop_stdunlock },
 +	{ &vop_getpages_desc,		(vop_t *) minix_getpages },
 +	{ &vop_putpages_desc,		(vop_t *) minix_putpages },
 +	{ NULL, NULL }
 +};
 +
 +static struct vnodeopv_desc minix_vnodeop_opv_desc =
 +{ &minix_vnodeop_p, minix_vnodeop_entries };
 +
 +/* We do not implement read or write of device files for safety */
 +
 +vop_t **minix_specop_p;
 +static struct vnodeopv_entry_desc minix_specop_entries[] = {
 +     { &vop_default_desc,              (vop_t *) vop_defaultop },
 +     { &vop_fsync_desc,                (vop_t *) minix_fsync },
 +     { &vop_inactive_desc,             (vop_t *) minix_inactive },
 +     { &vop_reclaim_desc,              (vop_t *) minix_reclaim },
 +     { &vop_access_desc,               (vop_t *) minix_access },
 +     { &vop_getattr_desc,              (vop_t *) minix_getattr },
 +     { &vop_islocked_desc,             (vop_t *) vop_stdislocked },
 +     { &vop_lock_desc,                 (vop_t *) vop_stdlock },
 +     { &vop_unlock_desc,               (vop_t *) vop_stdunlock },
 +     { NULL, NULL}
 +};
 +static struct vnodeopv_desc minix_specop_opv_desc =
 +  { &minix_specop_p, minix_specop_entries };
 +
 +vop_t **minix_fifoop_p;
 +static struct vnodeopv_entry_desc minix_fifoop_entries[] = {
 +     { &vop_default_desc,              (vop_t *) fifo_vnoperate },
 +     { &vop_fsync_desc,                (vop_t *) minix_fsync },
 +     { &vop_inactive_desc,             (vop_t *) minix_inactive },
 +     { &vop_reclaim_desc,              (vop_t *) minix_reclaim },
 +     { &vop_access_desc,               (vop_t *) minix_access },
 +     { &vop_getattr_desc,              (vop_t *) minix_getattr },
 +     { &vop_setattr_desc,              (vop_t *) minix_setattr },
 +     { &vop_read_desc,                 (vop_t *) minixfifo_read },
 +     { &vop_write_desc,                (vop_t *) minixfifo_write },
 +     { &vop_close_desc,                (vop_t *) minixfifo_close },
 +     { &vop_islocked_desc,             (vop_t *) vop_stdislocked },
 +     { &vop_lock_desc,                 (vop_t *) vop_stdlock },
 +     { &vop_unlock_desc,               (vop_t *) vop_stdunlock },     
 +     { NULL, NULL }
 +};
 +
 +static struct vnodeopv_desc minix_fifoop_opv_desc =
 +  { &minix_fifoop_p, minix_fifoop_entries };
 +
 +VNODEOP_SET(minix_vnodeop_opv_desc);
 +VNODEOP_SET(minix_specop_opv_desc);
 +VNODEOP_SET(minix_fifoop_opv_desc);
 +
 +/*
 + * Called by vput(), vrele(), if usecount drops to zero.
 + * Also called by vclean() if use count has
 + * dropped to zero.
 + * This routine should clean release buffers associated
 + * with the vnode/inode back to the buffer cache,
 + * however, the vnode maintains its association with
 + * the filesystem.
 + */
 +
 +/*
 + * Vnode usecount has dropped to zero; write or delete it.
 + * The node is locked when inactive is called, and is
 + * unlocked by inactive before it returns.
 + * Typically called from vrele, vput, vclean.
 + */
 +
 +static int
 +minix_inactive(struct vop_inactive_args *ap)
 +     /*
 +       struct vop_inactive_args {
 +          struct vnodeop_desc *a_desc;
 +	  struct vnode *a_vp;
 +	  struct proc  *a_p;
 +	  }
 +     */
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct proc *p = ap->a_p;
 +	int mode, error = 0;
 +     
 +	PRINTD("Entering: minix_inactive\n")
 +
 +	if (ip->i_mode == 0)
 +		goto out;
 +
 +	if (ip->i_nlink <= 0) {
 +		error = minix_truncate(vp, (off_t)0, IO_SYNC, NOCRED, p);
 +		ip->i_dev = 0;
 +		mode = ip->i_mode;
 +		ip->i_mode = 0;
 +		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +		minix_vfree(vp, ip->i_number, mode);
 +	}
 +	if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))
 +		minix_update(vp);
 +out:
 +	VOP_UNLOCK(vp, 0, p);
 +	/*
 +	 * If we are done with the inode, reclaim it
 +	 * so that it can be reused immediately.
 +	 */
 +	if (ip->i_mode == 0)
 +		vrecycle(vp, (struct simplelock *)0, p);
 +	
 +	return error;
 +}
 +
 +/*
 + * Called by vclean() after the buffers associated with the
 + * vnode have been released. VOP_INACTIVE is called if the
 + * usercount is zero to clean out the vnode.
 + * This routine actually frees the inode associated with
 + * the vnode to disassociate it from the file system.
 + */
 +static int
 +minix_reclaim(struct vop_reclaim_args *ap)
 +     /*
 +       struct vop_reclaim_args {
 +             struct vnodeop_desc *a_desc;
 +	     struct vnode *a_vp;
 +	     struct proc *a_p;
 +	     };
 +     */
 +{
 +     struct vnode *vp = ap->a_vp;
 +     struct minix_inode *ip = VTOMI(vp);
 +     struct minix_super_block *sp = ip->i_su;
 +
 +     minix_ihashrem(ip);
 +     cache_purge(vp);
 +     vrele(sp->s_devvp);
 +
 +     FREE(ip, M_MINIXNOD); /* release inode space */
 +     vp->v_data = 0;
 +     
 +     return 0;
 +}
 +
 +static int
 +minix_fsync(struct vop_fsync_args *ap)
 +    /*
 +	  struct vop_fsync_args {
 +	          struct vnode *a_vp;
 +		  struct ucred *a_cred;
 +		  int a_waitfor;
 +		  struct proc *a_p;
 +	 };
 +    */
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct buf *bp, *nbp;
 +	int s;
 +
 +loop:
 +	s = splbio();
 +	for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
 +		nbp = TAILQ_NEXT(bp, b_vnbufs);
 +/*
 + * Ignore buffers that are already being written.
 + */
 +		if (bp->b_flags & B_WRITEINPROG)
 +			continue;
 +/*
 + * Make sure the buffer is dirty.
 + */
 +		if ((bp->b_flags & B_DELWRI) == 0)
 +			panic("minix_fsync: not dirty");
 +
 +		vfs_bio_awrite(bp);
 +		splx(s);
 +		goto loop;
 +	}
 +	splx(s);
 +
 +	if (ap->a_waitfor == MNT_WAIT) {
 +		s = splbio();
 +		while (vp->v_numoutput) {
 +			vp->v_flag |= VBWAIT;
 +			tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "mnxfsn",0);
 +		}
 +		splx(s);
 +#ifdef DIAGNOSTIC
 +		if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
 +			vprint("minix_fsync: dirty", vp);
 +			goto loop;
 +		}
 +#endif
 +	}
 +	splx(s);
 +
 +	ip->i_flag |= IN_UPDATE;
 +	return minix_update(vp);
 +}
 +
 +static int
 +minix_access(struct vop_access_args *ap)
 +/*
 +  struct vop_access_args {
 +          struct vnode *a_vp;
 +	  int a_mode;
 +	  struct ucred *a_cred;
 +	  struct proc *a_p;
 +	  };
 +*/
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct ucred *cred = ap->a_cred;
 +	int mode = ap->a_mode;
 +	
 +	struct minix_dinode *dip;
 +	struct minix_inode  *ip;
 +
 +	ip  = VTOMI(vp);
 +	dip = &ip->i_dino;
 +
 +	return minix_dinode_access(dip, mode, cred, ip->i_su);
 +}
 +
 +static int
 +minix_getattr(struct vop_getattr_args *ap)
 +     /*
 +       struct vop_getattr_args {
 +               struct vnode *a_vp;
 +	       struct vattr *a_vap;
 +	       struct ucred *a_cred;
 +	       struct proc  *a_p;
 +	       }
 +     */
 +{
 +     struct vnode *vp = ap->a_vp;
 +     struct minix_inode *ip = VTOMI(vp);
 +     struct vattr *vap = ap->a_vap;
 +     struct minix_dinode *dip = &(ip->i_dino);
 +     
 +     minix_itimes(vp);
 +
 +     vap->va_fsid = dev2udev(ip->i_dev);
 +     vap->va_fileid = ip->i_number;
 +     vap->va_mode = ip->i_mode & ALL_MODES;  /* Minix and ufs agree here */
 +     vap->va_nlink = dip->i_nlinks;
 +     vap->va_uid   = dip->i_uid;
 +     vap->va_gid   = dip->i_gid;
 +     vap->va_rdev  = dip->i_block[0];
 +     vap->va_size  = dip->i_size;
 +     vap->va_atime.tv_sec = dip->i_atime;
 +     vap->va_atime.tv_nsec = (dip->i_atime)*1000000000;
 +     vap->va_mtime.tv_sec = dip->i_mtime;
 +     vap->va_mtime.tv_nsec = (dip->i_mtime)*1000000000;
 +     vap->va_ctime.tv_sec = dip->i_ctime;
 +     vap->va_ctime.tv_nsec = (dip->i_ctime)*1000000000;
 +     vap->va_flags = 0;                  /* Minix has no chflags command */
 +     vap->va_gen   = 0;                  /* I don't know what this is */
 +     vap->va_blocksize = BLOCK_SIZE;
 +     vap->va_bytes = ((dip->i_size + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1)) +
 +	              BLOCK_SIZE;
 +     vap->va_filerev = 0;                     /* NFS is not relevant yet */
 +/*     vap->va_type = minix_get_vtype(ip); */
 +     vap->va_type = IFTOVT(ip->i_mode);      /* IFTOVT() also works for minix */
 +
 +     return 0;
 +}
 +
 +static int
 +minix_setattr(struct vop_setattr_args *ap)
 +	/*
 +       struct vop_setattr_args {
 +               struct vnode *a_vp;
 +	       struct vattr *a_vap;
 +	       struct ucred *a_cred;
 +	       struct proc  *a_p;
 +	       }
 +     */
 +{
 +	struct vattr *vap = ap->a_vap;
 +	struct vnode *vp = ap->a_vp;
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct ucred *cred = ap->a_cred;
 +	struct proc *p = ap->a_p;
 +	int error;
 +	/*
 +	 * Check for unsettable attributes.
 +	 */
 +	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
 +	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
 +	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
 +	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
 +		return EINVAL;
 +	}
 +	
 +	/* Minix doesn't have chflags capability */
 +	
 +	if (vap->va_flags != VNOVAL)
 +		printf("minix_setattr: FLAGS NOT SET\n");
 +	/*
 +	 * Go through the fields and update iff not VNOVAL.
 +	 */
 +	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
 +		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 +			return EROFS;
 +		if ((error = minix_chown(vp, vap->va_uid, vap->va_gid, cred, p)) != 0)
 +			return error;
 +	}
 +	if (vap->va_size != VNOVAL) {
 +		/*
 +		 * Disallow write attempts on read-only file systems;
 +		 * unless the file is a socket, fifo, or a block or
 +		 * character device resident on the file system.
 +		 */
 +		switch (vp->v_type) {
 +		case VDIR:
 +			return EISDIR;
 +		case VLNK:
 +		case VREG:
 +			if (vp->v_mount->mnt_flag & MNT_RDONLY)
 +				return EROFS;
 +			break;
 +		default:
 +			break;
 +		}
 +		if ((error = minix_truncate(vp, vap->va_size, IO_SYNC, cred, p)) != 0)
 +			return error;
 +	}
 +	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
 +		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 +			return EROFS;
 +		if (cred->cr_uid != dip->i_uid &&
 +		    (error = suser_xxx(cred, p, PRISON_ROOT)) &&
 +		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
 +			(error = VOP_ACCESS(vp, VWRITE, cred, p))))
 +			return error;
 +		if (vap->va_atime.tv_sec != VNOVAL)
 +			ip->i_flag |= IN_ACCESS;
 +		if (vap->va_mtime.tv_sec != VNOVAL)
 +			ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +		minix_itimes(vp);
 +		if (vap->va_atime.tv_sec != VNOVAL) {
 +			dip->i_atime = vap->va_atime.tv_sec;
 +		}
 +		if (vap->va_mtime.tv_sec != VNOVAL) {
 +			dip->i_mtime = vap->va_mtime.tv_sec;
 +		}
 +		if ((error = minix_update(vp)) != 0)
 +			return error;
 +	}
 +	error = 0;
 +	if (vap->va_mode != (mode_t)VNOVAL) {
 +		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 +			return EROFS;
 +		error = minix_chmod(vp, (int)vap->va_mode, cred, p);
 +	}
 +
 +	return error;
 +}
 +
 +static int
 +minix_readdir(struct vop_readdir_args *ap)
 +     /*
 +        struct vop_readdir_args {
 +                struct vnode *a_vp;
 +                struct uio *a_uio;
 +                struct ucred *a_cred;
 +		int *a_eofflag;
 +		int *ncookies;
 +		u_long **a_cookies;
 +        };
 +     */
 +{
 +        struct uio *uio = ap->a_uio;
 +        int count, lost, error, err;
 +	struct vnode *vp = ap->a_vp;
 +	struct vnode *devvp;
 +	struct minix_inode in, *ip = VTOMI(vp);
 +	struct minix_super_block *sp;
 +	struct mount *mp = vp->v_mount;
 +	struct minixmount *mmp;
 +
 +	struct minix_direct *edp, *dp;
 +	int ncookies;
 +	struct dirent dstdp;
 +	struct uio auio;
 +	struct iovec aiov;
 +	caddr_t dirbuf;
 +	int DIRBLKSIZ = BLOCK_SIZE;
 +	int smdsize = sizeof(struct minix_direct);
 +	int readcnt;
 +	off_t startoffset = uio->uio_offset;
 +
 +	mmp = (struct minixmount*)mp->mnt_data;
 +	sp  = mmp->mnx_su;
 +	devvp = mmp->mnx_devvp;
 +
 +	count = uio->uio_resid;
 +	/*
 +         * Make sure we don't return partial entries.
 +	 */
 +	if (count <= ((uio->uio_offset + count) & (DIRBLKSIZ -1)))
 +		return EINVAL;
 +	count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
 +	lost   = uio->uio_resid - count;
 +	uio->uio_resid = count;
 +	uio->uio_iov->iov_len = count;
 +        
 +	auio = *uio;
 +	auio.uio_iov = &aiov;
 +	auio.uio_iovcnt = 1;
 +	auio.uio_resid = count;
 +	auio.uio_segflg = UIO_SYSSPACE;
 +	aiov.iov_len = count;
 +	MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
 +	aiov.iov_base = dirbuf;
 +	if ((error = VOP_READ(vp, &auio, 0, ap->a_cred)) == 0) {
 +		readcnt = count - auio.uio_resid;
 +		edp = (struct minix_direct *)&dirbuf[readcnt];
 +		ncookies = 0;
 +		bzero(&dstdp, offsetof(struct dirent, d_name));
 +		for (dp = (struct minix_direct *)dirbuf; 
 +		    !error && uio->uio_resid > 0 && dp < edp; ) {
 +			/*
 +			 * Minix directory entries:
 +			 * - the name is NUL-terminated except for max length name.
 +			 * - no file type and no namelength.
 +			 * - so we get the file type from the inode
 +			 * - and the namelength from strlen().
 +			 * - The record size for each entry is calculated
 +			 * - from GENERIC_DIRSIZ().
 +			 */
 +			bzero(dstdp.d_name, MAXNAMLEN+1);
 +			if (dp->d_ino > 0) {
 +				dstdp.d_fileno = dp->d_ino;
 +				if ((err = minix_iget(devvp,sp,dp->d_ino,&in)) != 0)
 +				     return err;
 +				dstdp.d_type = minix_to_dirent_type(&in);
 +				strncpy(dstdp.d_name, dp->d_name, MINIX_NAME_MAX);
 +				dstdp.d_name[MINIX_NAME_MAX] = '\0';
 +				dstdp.d_namlen = strlen(dstdp.d_name);
 +				dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
 +			} else {
 +				dstdp.d_fileno = 0;
 +				dstdp.d_type   = DT_UNKNOWN;
 +				dstdp.d_namlen = 0;
 +				dstdp.d_name[0] = '\0';
 +				dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
 +			}
 +
 +			if(dstdp.d_reclen <= uio->uio_resid) {
 +				if (dstdp.d_fileno > 0) /* Only move entries that are valid */
 +					error = uiomove((caddr_t)&dstdp, dstdp.d_reclen, uio);
 +				else {  /* Invalid entry so go to the next entry */
 +					error = 0;
 +				}
 +				if (!error)
 +					ncookies++;
 +			} else
 +				break;
 +			
 +			dp++;
 +		}
 +		/* we need to correct uio_offset */
 +		uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;
 +
 +		if (!error && ap->a_ncookies != NULL) {
 +			u_long *cookiep, *cookies, *ecookies;
 +			off_t off;
 +
 +			if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
 +				panic("minix_readdir: unexpected uio from NFS server");
 +			MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
 +			       M_WAITOK);
 +			off = startoffset;
 +			for (dp = (struct minix_direct *)dirbuf,
 +			     cookiep = cookies, ecookies = cookies + ncookies;
 +			     cookiep < ecookies;
 +			     dp = (struct minix_direct *)((caddr_t) dp + smdsize)) {
 +				off += smdsize;
 +				*cookiep++ = (u_long) off;
 +			}
 +			*ap->a_ncookies = ncookies;
 +			*ap->a_cookies = cookies;
 +		}
 +	}
 +	FREE(dirbuf, M_TEMP);
 +	uio->uio_resid += lost;
 +	if (ap->a_eofflag)
 +		*ap->a_eofflag = ip->i_dino.i_size <= uio->uio_offset;
 +        return error;
 +}
 +/*
 + * Make a symbolic link; follows ufs treatment.
 + *
 + * Symbolic links are not supported in Minix 2.0
 + * but are useful in FreeBSD for amoung other things
 + * running Emacs on a file in the Minixfs. :)
 + */
 +static int
 +minix_symlink(struct vop_symlink_args *ap)
 +     /*
 +       	struct vop_symlink_args {
 +		struct vnode *a_dvp;
 +		struct vnode **a_vpp;
 +		struct componentname *a_cnp;
 +		struct vattr *a_vap;
 +		char *a_target;
 +		};
 +     */
 +{
 +	struct vnode *vp, **vpp = ap->a_vpp;
 +	struct minix_inode *ip;
 +	int len, error;
 +
 +	error = minix_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
 +	    vpp, ap->a_cnp);
 +	if (error)
 +		return error;
 +
 +	vp = *vpp;
 +	len = strlen(ap->a_target);
 +	if (len > MINIX_MAXSYMLINK)
 +	     return ENAMETOOLONG;
 +	if (len < vp->v_mount->mnt_maxsymlinklen) {
 +		ip = VTOMI(vp);
 +		bzero((char*)ip->i_shortlink, MINIX_MAXSYMLINKLEN);
 +		bcopy(ap->a_target, (char*)ip->i_shortlink, len);
 +		ip->i_dino.i_size = len;
 +		ip->i_blocks = 0;
 +		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +	} else
 +		error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
 +		    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int*)0,
 +		    (struct proc*)0);
 +	if (error)
 +		vput(vp);
 +	
 +        cache_purge(ap->a_dvp);
 +	return minix_update(vp);
 +}
 +/*
 + * Read a symbolic link; follows ufs treatment
 + */
 +static int
 +minix_readlink(struct vop_readlink_args *ap)
 +	/*
 +	  struct vop_reaklink_args {
 +	          struct vnode *a_vp;
 +		  struct uio   *a_uio;
 +		  struct ucred *a_cred;
 +		  };
 +	*/
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct minix_inode *ip = (struct minix_inode*)vp->v_data;
 +	int isize;
 +
 +	isize = ip->i_dino.i_size;
 +	if (isize < vp->v_mount->mnt_maxsymlinklen) {
 +		uiomove((char*)ip->i_shortlink, isize, ap->a_uio);
 +		return 0;
 +	}
 +	return VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
 +}
 +
 +static int
 +minix_bmap(struct vop_bmap_args *ap)
 +     /*
 +       struct vop_bmap_args {
 +               struct vnode *a_vp;
 +	       struct daddr_t a_bn;
 +	       struct vnode **a_vpp;
 +	       struct daddr_t *a_bnp;
 +	       int *a_runp;
 +	       int *a_runb;
 +	};
 +     */
 +{
 +	struct minixmount *mmp;
 +     
 +	if (ap->a_vpp != NULL) {
 +		mmp = (struct minixmount*)(ap->a_vp->v_mount->mnt_data);
 +		*ap->a_vpp = mmp->mnx_devvp;
 +	}
 +	if (ap->a_bnp == NULL)
 +		return 0;
 +
 +	if (ap->a_runb != NULL)  /* No cluster reads */
 +		*ap->a_runb = 0;
 +
 +	return minix_bmapfs(ap->a_vp, ap->a_bn, ap->a_bnp, ap->a_runp);
 +}
 +static int
 +minix_open(struct vop_open_args *ap)
 +{
 +	return 0;
 +}
 +static int
 +minix_close(struct vop_close_args *ap)
 +{
 +	struct vnode *vp = ap->a_vp;
 +	
 +	simple_lock(&vp->v_interlock);
 +	if (vp->v_usecount > 1)
 +		minix_itimes(vp);
 +	simple_unlock(&vp->v_interlock);
 +	
 +	return 0;
 +}
 +/*
 + * Vnode op for reading.
 + */
 +static int
 +minix_read(struct vop_read_args *ap)
 +	/*
 +	struct vop_read_args {
 +		struct vnode *a_vp;
 +		struct uio *a_uio;
 +		int a_ioflag;
 +		struct ucred *a_cred;
 +	}
 +     */
 +{
 +	struct vnode  *vp  = ap->a_vp;
 +	struct uio   *uio  = ap->a_uio;
 +
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +
 +	struct buf *bp;
 +	off_t bytesinfile;
 +	u_daddr_t lbn, pbn;
 +	long size, xfersize, blkoffset;
 +	int error, orig_resid;
 +
 +	size = BLOCK_SIZE;
 +
 +	orig_resid = uio->uio_resid;
 +	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
 +		bytesinfile = (off_t)dip->i_size - uio->uio_offset;
 +		if (bytesinfile <= 0)
 +			break;
 +
 +		lbn = uio->uio_offset / size;
 +		blkoffset = uio->uio_offset - lbn * size;
 +
 +		xfersize = size - blkoffset;
 +		if (uio->uio_resid < xfersize)
 +			xfersize = uio->uio_resid;
 +		if (bytesinfile < xfersize)
 +			xfersize = bytesinfile;
 +		
 +		if ((error = VOP_BMAP(vp, lbn, NULL, &pbn, NULL, NULL)) != 0)
 +			return error;
 +
 +		if (pbn < 0)
 +		     return EIO;
 +		
 +		if ((error = bread(devvp, pbn, size, NOCRED, &bp)) != 0) {
 +			brelse(bp);
 +			bp = NULL;
 +			break;
 +		}
 +
 +		/*
 +		 * We should only get non-zero b_resid when an I/O error
 +		 * has occurred, which should cause us to break above.
 +		 * However, if the short read did not cause an error,
 +		 * then we want to ensure that we do not uiomove bad
 +		 * or uninitialized data.
 +		 */
 +		size -= bp->b_resid;
 +		if (size < xfersize) {
 +			if (size == 0)
 +				break;
 +			xfersize = size;
 +		}
 +		
 +		error = uiomove((char *)bp->b_data+blkoffset, (int)xfersize, uio);
 +		if (error)
 +			break;
 +
 +		bqrelse(bp);
 +	}
 +	if (bp != NULL)
 +		bqrelse(bp);
 +	
 +	if (orig_resid > 0 && (error == 0 || uio->uio_resid != orig_resid) &&
 +	    (vp->v_mount->mnt_flag & MNT_NOATIME) == 0) {
 +		ip->i_flag |= IN_ACCESS;
 +		(void)minix_update(vp);
 +	}
 +
 +	return error;
 +}
 +/*
 + * Vnode op for writing.
 + */
 +static int
 +minix_write(struct vop_write_args *ap)
 +	/*
 +	struct vop_write_args {
 +		struct vnode *a_vp;
 +		struct uio *a_uio;
 +		int a_ioflag;
 +		struct ucred *a_cred;
 +	}
 +     */
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct uio  *uio = ap->a_uio;
 +	struct ucred *cred = ap->a_cred;
 +	int ioflag = ap->a_ioflag;
 +	struct buf *bp;
 +	struct minix_inode *ip = VTOMI(vp);
 +	struct minix_dinode *dip = &(ip->i_dino);
 +	struct minix_super_block *sp = ip->i_su;
 +	struct vnode *devvp = sp->s_devvp;
 +	u_daddr_t lbn, pbn;
 +	off_t osize;
 +	long size, resid, blkoffset, xfersize = 0;
 +	int flags, error;
 +	
 +	osize = (off_t)dip->i_size;
 +	size = BLOCK_SIZE;
 +	resid = uio->uio_resid;
 +	
 +	if (ioflag & IO_SYNC)
 +		flags = B_SYNC;
 +	else
 +		flags = 0;
 +
 +	for (error = 0; uio->uio_resid > 0;) {
 +	     lbn = uio->uio_offset/size;
 +	     blkoffset = uio->uio_offset - lbn*size;
 +
 +	     xfersize = size - blkoffset;
 +	     if (uio->uio_resid < xfersize)
 +		  xfersize = uio->uio_resid;
 +
 +	     flags |= B_CLRBUF;    /* All the time */
 +
 +	     if (uio->uio_offset + xfersize > dip->i_size) {
 +		  vnode_pager_setsize(vp, (vm_ooffset_t)(uio->uio_offset + xfersize));
 +		  if ((error = minix_balloc(vp, lbn, &bp)) != 0)
 +		       break;
 +	     } else {
 +		  if ((error = minix_bmapfs(vp, lbn, &pbn, NULL)) != 0)
 +		       break;
 +		  if ((error = bread(devvp, pbn, BLOCK_SIZE, NOCRED, &bp)) != 0)
 +		       break;
 +	     }
 +
 +	     if (uio->uio_offset + xfersize > dip->i_size) {
 +		  dip->i_size = uio->uio_offset + xfersize;
 +		  ip->i_blocks = minix_num_blocks(ip->i_mode, dip->i_size, sp->s_zshift);
 +	     }
 +
 +	     error = uiomove((char*)bp->b_data+blkoffset, (int)xfersize, uio);
 +
 +	     if (ioflag & IO_VMIO)
 +		  bp->b_flags |= B_RELBUF;
 +
 +	     if (ioflag & IO_SYNC)
 +		  bwrite(bp);
 +	     else if (xfersize + blkoffset == BLOCK_SIZE)
 +		  bawrite(bp);
 +	     else
 +		  bdwrite(bp);
 +
 +	     if (error || xfersize == 0)
 +		  break;
 +	}
 +    
 +	if (error) {
 +	     if (ioflag & IO_UNIT) {
 +		  (void)minix_truncate(vp,osize,ioflag & IO_SYNC, cred, uio->uio_procp);
 +		  uio->uio_offset -= resid - uio->uio_resid;
 +		  uio->uio_resid = resid;
 +	     } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
 +		  (void)minix_update(vp);
 +	     }
 +	}
 +	/*
 +	 * If we successfully wrote any data, and we are not the superuser
 +	 * we clear the setuid and setgid bits as a precaution against
 +	 * tampering.
 +	 */
 +	if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
 +		ip->i_mode &= ~(ISUID | ISGID);
 +	
 +	if (xfersize > 0 && error == 0) {
 +		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +		(void)minix_update(vp);
 +	}
 +	
 +	return error;
 +}
 +
 +static int
 +minix_create(struct vop_create_args *ap)
 +{
 +	struct componentname *cnp = ap->a_cnp;
 +	int mode;
 +
 +	if (strlen(cnp->cn_nameptr) > MINIX_NAME_MAX)
 +		return ENAMETOOLONG;
 +	
 +	mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
 +	
 +	return minix_makeinode(mode,ap->a_dvp, ap->a_vpp, cnp);
 +}
 +/*
 + * Just remove the directory entry and decrease the link count
 + * of the file, after a call to minix_namei().
 + */
 +static int
 +minix_remove(struct vop_remove_args *ap)
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct vnode *dvp = ap->a_dvp;
 +	struct minix_inode *ip = VTOMI(vp);
 +	int error;
 +	int prtrmv = 0;
 +	
 +	if ((error = minix_dirremove(dvp)) == 0) {
 +	     ip->i_nlink--;
 +	     ip->i_flag |= IN_CHANGE;
 +	}
 +
 +	if (error)
 +	     return error;
 +
 +	if (prtrmv) {
 +		vprint("remove: parent directory",dvp);
 +		vprint("remove: source file",vp);
 +	}
 +	
 +	return minix_update(dvp);
 +}
 +/*
 + * Add a link in a directory
 + */
 +static int
 +minix_link(struct vop_link_args *ap)
 +	/*
 +       struct vop_link_args {
 +               struct vnode *a_tdvp;
 +	       struct vnode *a_vp;
 +	       struct componentname *a_cnp;
 +	       };
 +     */
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct vnode *tdvp = ap->a_tdvp;
 +	struct componentname *cnp = ap->a_cnp;
 +	struct proc *p = cnp->cn_proc;
 +	struct minix_inode *ip;
 +	struct minix_direct newdir;
 +	int error;
 +
 +	if (tdvp->v_mount != vp->v_mount)
 +		return EXDEV;
 +
 +	if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p)))
 +		return error;
 +
 +	ip = VTOMI(vp);
 +	if (ip->i_nlink >= MINIX_LINK_MAX) {
 +		error = EMLINK;
 +		goto out;
 +	}
 +	ip->i_nlink++;
 +	ip->i_flag |= IN_CHANGE;
 +	if ((error = minix_update(vp)) == 0) {
 +		minix_makedirentry(ip, cnp, &newdir);
 +		if ((error = minix_direnter(tdvp, vp, &newdir, cnp)) != 0) {
 +			ip->i_nlink--;
 +			ip->i_flag |= IN_CHANGE;
 +			(void)minix_update(vp);
 +		}
 +	}
 +out:
 +	if (tdvp != vp)
 +		VOP_UNLOCK(vp, 0, p);
 +     
 +	return error;
 +}
 +/*
 + * Mkdir system call.
 + */
 +static int
 +minix_mkdir(struct vop_mkdir_args *ap)
 +     /*
 +       	struct vop_mkdir_args {
 +		struct vnode *a_dvp;
 +		struct vnode **a_vpp;
 +		struct componentname *a_cnp;
 +		struct vattr *a_vap;
 +	};
 +     */
 +{
 +	struct vnode *dvp = ap->a_dvp;
 +	struct vattr *vap = ap->a_vap;
 +	struct componentname *cnp = ap->a_cnp;
 +	struct minix_inode *dp = VTOMI(dvp);
 +	struct vnode *tvp;
 +	struct minix_inode *ip = NULL;
 +	struct minix_dinode *dip;
 +	struct minix_super_block *sp;
 +	struct buf *bp;
 +	struct minix_dirtemplate dirtemplate, *dtp;
 +	struct minix_direct newdir;
 +	int error, dmode;
 +	struct minix_dirtemplate mastertemplate = {
 +	     0, ".",
 +	     0, ".."
 +	};
 +
 +	if (dp->i_nlink >= MINIX_LINK_MAX) {
 +		error = EMLINK;
 +		goto out;
 +	}
 +	dmode = vap->va_mode &0777;
 +	dmode |= IFDIR;
 +	
 +	if ((error = minix_valloc(dvp, dmode, cnp->cn_cred, &tvp)) != 0)
 +		goto out;
 +	
 +	ip  = (struct minix_inode*)tvp->v_data;
 +	sp  = ip->i_su;
 +	dip = &(ip->i_dino);
 +	ip->i_dino.i_gid = dp->i_dino.i_gid;
 +	ip->i_dino.i_uid = cnp->cn_cred->cr_uid;
 +	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 +	ip->i_mode = dmode;
 +	ip->i_dino.i_mode = dmode;
 +	tvp->v_type = VDIR;
 +	ip->i_nlink = 2;
 +	/*
 +	 * Bump link count in parent directory to reflect work done below.
 +	 * Should be done before reference is created so cleanup is
 +	 * possible if we crash.
 +	 */
 +	dp->i_nlink++;
 +	dp->i_flag |= IN_CHANGE;
 +	if ((error = minix_update(tvp)) != 0)
 +		goto bad;
 +	/*
 +	 * Initialize directory with "." and ".." from static template.
 +	 */
 +	dtp = &mastertemplate;
 +	dirtemplate = *dtp;
 +	dirtemplate.dot_ino = ip->i_number;
 +	dirtemplate.dotdot_ino = dp->i_number;
 +	if ((error = minix_balloc(tvp, (u_daddr_t)0, &bp)) != 0)
 +		goto bad;
 +	dip->i_size = sizeof(dirtemplate);
 +	ip->i_blocks = 1 << sp->s_zshift;
 +	ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +	vnode_pager_setsize(tvp, (vm_ooffset_t)BLOCK_SIZE);
 +	bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof(dirtemplate));
 +
 +	if ((error = minix_update(tvp)) != 0) {
 +		(void)bwrite(bp);
 +		goto bad;
 +	}
 +	/*
 +	 * Directory set up, now install its entry in the parent directory.
 +	 *
 +	 * If we are not doing soft dependencies, then we must write out the
 +	 * buffer containing the new directory body before entering the new 
 +	 * name in the parent. If we are doing soft dependencies, then the
 +	 * buffer containing the new directory body will be passed to and
 +	 * released in the soft dependency code after the code has attached
 +	 * an appropriate ordering dependency to the buffer which ensures that
 +	 * the buffer is written before the new name is written in the parent.
 +	 */
 +	if ((error = bwrite(bp)) != 0)
 +		goto bad;
 +	
 +	minix_makedirentry(ip, cnp, &newdir);
 +	error = minix_direnter(dvp, tvp, &newdir, cnp);
 +bad:
 +	if (error == 0) {
 +		*ap->a_vpp = tvp;
 +	} else {
 +		dp->i_nlink--;
 +		dp->i_flag |= IN_CHANGE;
 +		/*
 +		 * No need to do an explicit VOP_TRUNCATE here, vrele will
 +		 * do this for us because we set the link count to 0.
 +		 */
 +		ip->i_nlink = 0;
 +		ip->i_flag |= IN_CHANGE;
 +		vput(tvp);
 +	}
 +out:
 +	return error;
 +}
 +/*
 + * Rmdir system call
 + */
 +static int
 +minix_rmdir(struct vop_rmdir_args *ap)
 +    /*
 +	struct vop_rmdir_args {
 +	   struct vnode *a_dvp;
 +	   struct vnode *a_vp;
 +	   struct componentname *a_cnp;
 +	};
 +    */
 +{
 +	struct vnode *vp = ap->a_vp;
 +	struct vnode *dvp = ap->a_dvp;
 +	struct componentname *cnp = ap->a_cnp;
 +	struct proc *p = cnp->cn_proc;
 +	struct minix_inode *ip, *dp;
 +	int error, ioflag = IO_SYNC;
 +	int prmdir = 0;
 +
 +	ip = VTOMI(vp);
 +	dp = VTOMI(dvp);
 +
 +	/*
 +	 * Do not remove a directory that is in the process of being renamed.
 +	 * Verify the directory is empty (and valid). Rmdir ".." will not be
 +	 * valid since ".." will contain a reference to the current directory
 +	 * and thus be non-empty. Do not allow the removal of mounted on
 +	 * directories (this can happen when an NFS exported filesystem
 +	 * tries to remove a locally mounted on directory).
 +	 */
 +	error = 0;
 +	if (ip->i_flag & IN_RENAME) {
 +		error = EINVAL;
 +		goto out;
 +	}
 +	if (ip->i_nlink > 2 ||
 +	    !minix_dirempty(ip, dp->i_number, cnp->cn_cred)) {
 +		error = ENOTEMPTY;
 +		goto out;
 +	}
 +	if (vp->v_mountedhere != 0) {
 +		error = EINVAL;
 +		goto out;
 +	}
 +	/*
 +	 * Delete reference to directory before purging
 +	 * inode.  If we crash in between, the directory
 +	 * will be reattached to lost+found,
 +	 */
 +	if ((error = minix_dirremove(dvp)) != 0)
 +		goto out;
 +	dp->i_nlink--;
 +	dp->i_flag |= IN_CHANGE;
 +	cache_purge(dvp);
 +	VOP_UNLOCK(dvp, 0, p);
 +	(void)minix_update(dvp);
 +	/*
 +	 * Truncate inode. The only stuff left in the directory is "." and
 +	 * "..". The "." reference is inconsequential since we are quashing
 +	 * it.
 +	 */
 +	ip->i_nlink -= 2;
 +	ip->i_flag |= IN_CHANGE;
 +	error = minix_truncate(vp, (off_t)0, ioflag, cnp->cn_cred, p);
 +	cache_purge(vp);
 +	vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
 +out:
 +	if (prmdir) {
 +		vprint("rmdir: parent directory",dvp);
 +		vprint("rmdir: source directory",vp);
 +	}
 +	return error;
 +}
 +/*
 + * mknod system call
 + */
 +static int
 +minix_mknod(struct vop_mknod_args *ap)
 +     /*
 +     	struct vop_mknod_args {
 +		struct vnode *a_dvp;
 +		struct vnode **a_vpp;
 +		struct componentname *a_cnp;
 +		struct vattr *a_vap;
 +	};
 +     */
 +{
 +	struct vnode **vpp = ap->a_vpp;
 +	struct vattr  *vap = ap->a_vap;
 +	struct minix_inode *ip;
 +	ino_t ino;
 +	int error;
 +
 +	error = minix_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
 +	    ap->a_dvp, vpp, ap->a_cnp);
 +	if (error)
 +		return error;
 +	ip = VTOMI(*vpp);
 +	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 +	if (vap->va_rdev != VNOVAL)
 +		ip->i_rdev = vap->va_rdev;
 +	/*
 +	 * Remove inode, then reload it through VFS_VGET so it is
 +	 * checked to see if it is an alias of an existing entry in
 +	 * the inode cache.
 +	 */
 +	vput(*vpp);
 +	(*vpp)->v_type = VNON;
 +	ino = ip->i_number;	/* Save this before vgone() invalidates ip. */
 +	vgone(*vpp);
 +	if ((error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp)) != 0) {
 +		*vpp = NULL;
 +		return error;
 +	}
 +	return minix_update(*vpp);
 +}
 +/*
 + * Rename system call. Follows FreeBSD's ufs.
 + * 	rename("foo", "bar");
 + * is essentially
 + *	unlink("bar");
 + *	link("foo", "bar");
 + *	unlink("foo");
 + * but ``atomically''.  Can't do full commit without saving state in the
 + * inode on disk which isn't feasible at this time.  Best we can do is
 + * always guarantee the target exists.
 + *
 + * Basic algorithm is:
 + *
 + * 1) Bump link count on source while we're linking it to the
 + *    target.  This also ensures the inode won't be deleted out
 + *    from underneath us while we work (it may be truncated by
 + *    a concurrent `trunc' or `open' for creation).
 + * 2) Link source to destination.  If destination already exists,
 + *    delete it first.
 + * 3) Unlink source reference to inode if still around. If a
 + *    directory was moved and the parent of the destination
 + *    is different from the source, patch the ".." entry in the
 + *    directory.
 + */
 +static int
 +minix_rename(struct vop_rename_args *ap)
 +    /*
 +	struct vop_rename_args {
 +        struct vnode *ap_fdvp;
 +	struct vnode *ap_fvp;
 +	struct componentname *ap_fcnp;
 +	struct vnode *ap_tdvp;
 +	struct vnode *ap_tvp;
 +	struct componentname *ap_tcnp;
 +	  };
 +    */
 +{
 +        /*
 +	 * fdvp is the old parent directory
 +	 * fvp  is the file to be renamed
 +	 * fcnp is the path info about the current file: fvp
 +	 * tdvp is the new parent directory
 +	 * tvp  is the new 'target' file name (if it exists)
 +	 * tcnp is the path info about the file's new name
 +	 */
 +     	struct vnode *tvp = ap->a_tvp;
 +	register struct vnode *tdvp = ap->a_tdvp;
 +	struct vnode *fvp = ap->a_fvp;
 +	struct vnode *fdvp = ap->a_fdvp;
 +	struct componentname *tcnp = ap->a_tcnp;
 +	struct componentname *fcnp = ap->a_fcnp;
 +	struct proc *p = fcnp->cn_proc;
 +	struct minix_inode *ip, *xp, *dp;
 +	struct minix_direct newdir;
 +	int doingdirectory = 0, oldparent = 0, newparent = 0;
 +	int entry, error = 0, ioflag = IO_SYNC;
 +
 +	/*
 +	 * Check for cross-device rename.
 +	 */
 +	if ((fvp->v_mount != tdvp->v_mount) ||
 +	    (tvp && (fvp->v_mount != tvp->v_mount))) {
 +		error = EXDEV;
 +	abortit:
 +		if (tdvp == tvp)
 +			vrele(tdvp);
 +		else
 +			vput(tdvp);
 +		if (tvp)
 +			vput(tvp);
 +		vrele(fdvp);
 +		vrele(fvp);
 +		return error;
 +	}
 +        /*
 +	 * Check if just deleting a link name.
 +	 */
 +	if (fvp == tvp) {
 +		if (fvp->v_type == VDIR) {
 +			error = ENOENT;
 +			goto abortit;
 +		}
 +
 +		/*
 +		 * Release destination.
 +		 */
 +		vput(tdvp);
 +		vput(tvp);
 +                /*
 +		 * Delete source.  Pretty bizarre stuff.
 +		 */
 +		vrele(fdvp);
 +		vrele(fvp);
 +		fcnp->cn_flags &= ~MODMASK;
 +		fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
 +		fcnp->cn_nameiop = DELETE;
 +		VREF(fdvp);
 +		error = relookup(fdvp, &fvp, fcnp);
 +		if (error == 0)
 +			vrele(fdvp);
 +		if (fvp == NULL)
 +			return ENOENT;
 +		error = VOP_REMOVE(fdvp, fvp, fcnp);
 +		if (fdvp == fvp)
 +			vrele(fdvp);
 +		else
 +			vput(fdvp);
 +		if (fvp != NULL)
 +			vput(fvp);
 +		return error;
 +	}
 +	
 +	if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
 +		goto abortit;
 +
 +	dp = VTOMI(fdvp);   /* From directory */
 +	ip = VTOMI(fvp);    /* From inode */
 +
 +	if (ip->i_nlink >= MINIX_LINK_MAX) {
 +		VOP_UNLOCK(fvp, 0, p);
 +		error = EMLINK;
 +		goto abortit;
 +	}
 +
 +	if ((ip->i_mode & IFMT) == IFDIR) {
 +		/*
 +		 * Avoid ".", "..", and aliases of "." for obvious reasons.
 +		 */
 +		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
 +		    || dp->i_number == ip->i_number
 +		    || ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)) {
 +			VOP_UNLOCK(fvp, 0, p);
 +			error = EINVAL;
 +			goto abortit;
 +		}
 +		ip->i_flag |= IN_RENAME;
 +		oldparent = dp->i_number;
 +		doingdirectory = 1;
 +	}
 +	vrele(fdvp);
 +
 +	/*
 +	 * When the target exists, both the directory
 +	 * and target vnodes are returned locked.
 +	 */
 +
 +	dp = VTOMI(tdvp);   /* dp is now the target directory */
 +	xp = NULL;       
 +	if (tvp)
 +		xp = VTOMI(tvp); /* xp is now the target file name */
 +	
 +	/*
 +	 * Bump link count on fvp while we are moving stuff around.  If we
 +	 * crash before completing the work, the link count may be wrong
 +	 * but correctable.
 +	 */
 +	ip->i_nlink++;
 +	ip->i_flag |= IN_CHANGE;
 +	if ((error = minix_update(fvp)) != 0) {
 +		VOP_UNLOCK(fvp, 0, p);
 +		goto bad;
 +	}
 +
 +        /*
 +	 * If ".." must be changed (ie the directory gets a new
 +	 * parent) then the source directory must not be in the
 +	 * directory hierarchy above the target, as this would
 +	 * orphan everything below the source directory. Also
 +	 * the user must have write permission in the source so
 +	 * as to be able to change "..".
 +	 */
 +	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
 +	VOP_UNLOCK(fvp, 0, p);
 +	if (oldparent != dp->i_number)
 +		newparent = dp->i_number;
 +	if (doingdirectory && newparent) {
 +		if (error)	/* write access check above */
 +			goto bad;
 +		if (xp != NULL)
 +			vput(tvp);
 +		if ((error = minix_checkpath(ip, dp, tcnp->cn_cred)) != 0)
 +			goto out;
 +		VREF(tdvp);
 +		error = relookup(tdvp, &tvp, tcnp);
 +		if (error)
 +			goto out;
 +		vrele(tdvp);
 +		dp = VTOMI(tdvp);
 +		xp = NULL;
 +		if (tvp)
 +			xp = VTOMI(tvp);
 +	}
 +
 +/*
 + * If the target doesn't exist, link the target to the source and
 + * unlink the source.  Otherwise, rewrite the target directory to
 + * reference the source and remove the original entry.
 + */
 +	if (xp == NULL) {
 +		if (dp->i_dev != ip->i_dev)
 +			panic("minix_rename: EXDEV");
 +		/*
 +		 * Account for ".." in new directory.
 +		 * When source and destination have the same
 +		 * parent we don't fool with the link count.
 +		 */
 +		if (doingdirectory && newparent) {
 +			if ((nlink_t)dp->i_nlink >= MINIX_LINK_MAX) {
 +				error = EMLINK;
 +				goto bad;
 +			}
 +			dp->i_nlink++;
 +			dp->i_flag |= IN_CHANGE;
 +			if ((error = minix_update(tdvp)) != 0)
 +				goto bad;
 +		}
 +		minix_makedirentry(ip, tcnp, &newdir);
 +		error = minix_direnter(tdvp, NULL, &newdir, tcnp);
 +		
 +		if (error) {
 +			if (doingdirectory && newparent) {
 +				dp->i_nlink--;
 +				dp->i_flag |= IN_CHANGE;
 +				(void)minix_update(tdvp);
 +			}
 +			goto bad;
 +		}
 +		vput(tdvp);
 +	} else {
 +		
 +		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
 +			panic("minix_rename: EXDEV");
 +		/*
 +		 * Target must be empty if a directory and have no links
 +		 * to it. Also, ensure source and target are compatible
 +		 * (both directories, or both not directories).
 +		 */
 +		if ((xp->i_mode&IFMT) == IFDIR) {
 +			if ((xp->i_nlink > 2) ||
 +			    !minix_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
 +				error = ENOTEMPTY;
 +				goto bad;
 +			}
 +			if (!doingdirectory) {
 +				error = ENOTDIR;
 +				goto bad;
 +			}
 +			/*
 +			 * Update name cache since directory is going away.
 +			 */
 +			cache_purge(tdvp);
 +			
 +		} else if (doingdirectory) {
 +			error = EISDIR;
 +			goto bad;
 +		}
 +
 +		/*
 +		 * Change name tcnp in tdvp to point at fvp.
 +		 */
 +
 +		if ((entry = dp->i_entry) < 2) {
 +		     printf("rename: i_entry < 2\n");
 +		     error = EIO;
 +		     goto bad;
 +		}
 +		  
 +		if ((error = minix_dirrewrite(dp, xp, ip->i_number, entry)) != 0)
 +			goto bad;
 +
 +		/*
 +		 * If the target directory is in same directory as the source
 +		 * directory, decrement the link count on the parent of the
 +		 * target directory.  This accounts for the fact that a
 +		 * directory links back to its parent with ..
 +		 */
 +		
 +		if (doingdirectory) {
 +		     if (!newparent) {
 +			  /* Decrement the link count of tdvp */
 +			  dp->i_nlink--;
 +			  dp->i_flag |= IN_CHANGE;
 +		     }
 +		     xp->i_nlink--;
 +		     xp->i_flag |= IN_CHANGE;
 +		     if (--xp->i_nlink != 0)
 +			     panic("minix_rename: linked directory");
 +		     if ((error = minix_truncate(tvp, (off_t)0, ioflag,
 +			tcnp->cn_cred, tcnp->cn_proc)) != 0)
 +			  goto bad;
 +		}
 +		
 +		vput(tdvp);
 +		vput(tvp);
 +		xp = NULL;
 +	}
 +/*
 + * Unlink the source.  If a directory was moved to a new parent,
 + * update its ".." entry.  Gobs of ugly UFS code omitted here.
 + */
 +	fcnp->cn_flags &= ~MODMASK;
 +	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
 +	VREF(fdvp);
 +	error = relookup(fdvp, &fvp, fcnp); /* Relookup gets a new vnode/inode */
 +	if (error == 0)
 +		vrele(fdvp);
 +	if (fvp != NULL) {
 +		xp = VTOMI(fvp);
 +		dp = VTOMI(fdvp);
 +	} else {
 +		/*
 +		 * From name has disappeared.
 +		 */
 +		if (doingdirectory)
 +			panic("minix_rename: lost dir entry");
 +		vrele(ap->a_fvp);
 +		return (0);
 +	}
 +/*
 + * Ensure that the directory entry still exists and has not
 + * changed while the new name has been entered. If the source is
 + * a file then the entry may have been unlinked or renamed. In
 + * either case there is no further work to be done. If the source
 + * is a directory then it cannot have been rmdir'ed; the IN_RENAME
 + * flag ensures that it cannot be moved by another rename or removed
 + * by a rmdir.
 + */
 +	if (xp->i_number != ip->i_number) { /* Need to compare inode numbers here */
 +		if (doingdirectory)
 +			panic("minix_rename: lost dir entry");
 +	} else {
 +		/*
 +		 * If the source is a directory with a
 +		 * new parent, the link count of the old
 +		 * parent directory must be decremented
 +		 * and ".." set to point to the new parent.
 +		 */
 +		if (doingdirectory && newparent) {
 +			entry = 1;  /* entry #1 is '..' in a Minix directory */
 +			minix_dirrewrite(xp, dp, newparent, entry);
 +			cache_purge(fdvp);
 +		}
 +		if((error = minix_dirremove(fdvp)) != 0)
 +		     printf("minix_dirremove: error = %d\n",error);
 +		if (!error) {
 +			cache_purge(fvp);
 +			ip->i_nlink--;
 +			ip->i_flag |=  IN_CHANGE;
 +			ip->i_flag &= ~IN_RENAME;
 +			(void)minix_update(fvp);
 +			dp->i_flag |= IN_CHANGE | IN_UPDATE;
 +			(void)minix_update(fdvp);
 +		}
 +	}
 +	if (dp)
 +		vput(dp->i_vnode);
 +	if (xp)
 +		vput(xp->i_vnode);
 +	vrele(ap->a_fvp);
 +	return error;
 +
 +bad:
 +	if (xp)
 +	     vput(xp->i_vnode);
 +	if (dp)
 +	     vput(dp->i_vnode);
 +out:
 +	if (doingdirectory)
 +	     ip->i_flag &= ~IN_RENAME;
 +	if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
 +	     ip->i_nlink--;
 +	     ip->i_flag |= IN_CHANGE;
 +	     ip->i_flag &= ~IN_RENAME;
 +	     (void)minix_update(fvp);
 +	     vput(fvp);
 +	} else
 +	     vrele(fvp);
 +
 +	return error;
 +}
 +/*
 + * Return POSIX pathconf information applicable to minix filesystems.
 + */
 +static int
 +minix_pathconf(ap)
 +	struct vop_pathconf_args /* {
 +		struct vnode *a_vp;
 +		int a_name;
 +		int *a_retval;
 +	} */ *ap;
 +{
 +	switch (ap->a_name) {
 +	case _PC_LINK_MAX:
 +		*ap->a_retval = MINIX_LINK_MAX;
 +		return (0);
 +	case _PC_NAME_MAX:
 +		*ap->a_retval = MINIX_NAME_MAX;
 +		return (0);
 +	case _PC_PATH_MAX:
 +		*ap->a_retval = MINIX_PATH_MAX;
 +		return (0);
 +	case _PC_PIPE_BUF:
 +		*ap->a_retval = MINIX_PIPE_BUF;
 +		return (0);
 +	case _PC_CHOWN_RESTRICTED:
 +		*ap->a_retval = 1;
 +		return (0);
 +	case _PC_NO_TRUNC:
 +		*ap->a_retval = 1;
 +		return (0);
 +	default:
 +		return (EINVAL);
 +	}
 +	/* NOTREACHED */
 +}
 +/* The fifo calls below follow ufs's fifofs */
 +/*
 + * Update the times on the inode for the fifo then close
 + */
 +static int
 +minixfifo_close(struct vop_close_args *ap)
 +{
 +	struct vnode *vp = ap->a_vp;
 +
 +	simple_lock(&vp->v_interlock);
 +	if (vp->v_usecount > 1)
 +		minix_itimes(vp);
 +	simple_unlock(&vp->v_interlock);
 +	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
 +}
 +/*
 + * Read wrapper for fifos.
 + */
 +static int
 +minixfifo_read(struct vop_read_args *ap)
 +{
 +	int error, resid;
 +	struct uio *uio = ap->a_uio;
 +	struct vnode *vp = ap->a_vp;
 +	struct minix_inode *ip = VTOMI(vp);
 +
 +	resid = uio->uio_resid;
 +	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap);
 +	if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0 &&
 +	    ip != NULL && (uio->uio_resid != resid ||
 +		(error == 0 && resid != 0)))
 +		ip->i_flag |= IN_ACCESS;
 +	return error;
 +}
 +/*
 + * Write wrapper for fifos.
 + */
 +static int
 +minixfifo_write(struct vop_write_args *ap)
 +{
 +	int error, resid;
 +	struct uio *uio = ap->a_uio;
 +	struct vnode *vp = ap->a_vp;
 +	struct minix_inode *ip = VTOMI(vp);
 +
 +	resid = uio->uio_resid;
 +	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap);
 +	if (ip != NULL && (uio->uio_resid != resid ||(error == 0 && resid != 0)))
 +		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 +	return error;
 +}
 +static int
 +minix_getpages(struct vop_getpages_args *ap)
 +{
 +	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
 +		ap->a_reqpage);
 +}
 +static int
 +minix_putpages(struct vop_putpages_args *ap)
 +{
 +	return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
 +		ap->a_sync, ap->a_rtvals);
 +}
 diff -ruN sys.orig/modules/Makefile sys/modules/Makefile
 --- sys.orig/modules/Makefile	Sat May  4 01:23:52 2002
 +++ sys/modules/Makefile	Fri Feb 28 13:46:46 2003
 @@ -102,6 +102,7 @@
  	gnufpu \
  	ibcs2 \
  	linprocfs \
 +	minixfs \
  	mly \
  	ncv \
  	nsp \
 diff -ruN sys.orig/modules/minixfs/Makefile sys/modules/minixfs/Makefile
 --- sys.orig/modules/minixfs/Makefile	Wed Dec 31 16:00:00 1969
 +++ sys/modules/minixfs/Makefile	Fri Feb 28 13:46:44 2003
 @@ -0,0 +1,11 @@
 +# $FreeBSD: src/sys/modules/minixfs/Makefile,v 1.10 021105 Ed Exp $
 +
 +.PATH:	${.CURDIR}/../../fs/minixfs
 +KMOD=	minixfs
 +SRCS=	vnode_if.h \
 +	minix_subr.c minix_vfsops.c minix_vnops.c minix_lookup.c \
 +	minix_bio.c minix_inode.c minix_ufs.c minix_locks.c \
 +	minix_ihash.c minix_alock.s
 +NOMAN=
 +
 +.include <bsd.kmod.mk>
 diff -ruN sys.orig/sys/vnode.h sys/sys/vnode.h
 --- sys.orig/sys/vnode.h	Mon Dec 24 17:44:44 2001
 +++ sys/sys/vnode.h	Fri Feb 28 13:46:55 2003
 @@ -65,7 +65,7 @@
  	VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_PC, VT_LFS, VT_LOFS, VT_FDESC,
  	VT_PORTAL, VT_NULL, VT_UMAP, VT_KERNFS, VT_PROCFS, VT_AFS, VT_ISOFS,
  	VT_UNION, VT_MSDOSFS, VT_TFS, VT_VFS, VT_CODA, VT_NTFS,
 -	VT_HPFS, VT_NWFS, VT_SMBFS
 +	VT_HPFS, VT_NWFS, VT_SMBFS, VT_MINIXFS
  };
  
  /*

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200303010650.h216oDkW075038>