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>