Date: Fri, 28 Feb 2003 22:40:08 -0800 (PST) From: Ed.Alley.wea@llnl.gov To: freebsd-bugs@FreeBSD.org Subject: kern/47982: Minix file-system offered Message-ID: <200303010640.h216e8GL073020@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:30:31 -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(×tr, 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 = ∈
+ 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?200303010640.h216e8GL073020>
