summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2000-10-14 03:02:30 +0000
committeradrian <adrian@FreeBSD.org>2000-10-14 03:02:30 +0000
commit0458054c4e405cc6f262b0fb171dc3d049bc7513 (patch)
tree5d8132a94f833d46795e30aa5296a893b2e5637c
parentee143d47ad6c41a3590bdb5ed28c7bd5bf6ffff8 (diff)
downloadFreeBSD-src-0458054c4e405cc6f262b0fb171dc3d049bc7513.zip
FreeBSD-src-0458054c4e405cc6f262b0fb171dc3d049bc7513.tar.gz
Initial commit of IFS - a inode-namespaced FFS. Here is a short
description: How it works: -- Basically ifs is a copy of ffs, overriding some vfs/vnops. (Yes, hack.) I didn't see the need in duplicating all of sys/ufs/ffs to get this off the ground. File creation is done through a special file - 'newfile' . When newfile is called, the system allocates and returns an inode. Note that newfile is done in a cloning fashion: fd = open("newfile", O_CREAT|O_RDWR, 0644); fstat(fd, &st); printf("new file is %d\n", (int)st.st_ino); Once you have created a file, you can open() and unlink() it by its returned inode number retrieved from the stat call, ie: fd = open("5", O_RDWR); The creation permissions depend entirely if you have write access to the root directory of the filesystem. To get the list of currently allocated inodes, VOP_READDIR has been added which returns a directory listing of those currently allocated. -- What this entails: * patching conf/files and conf/options to include IFS as a new compile option (and since ifs depends upon FFS, include the FFS routines) * An entry in i386/conf/NOTES indicating IFS exists and where to go for an explanation * Unstaticize a couple of routines in src/sys/ufs/ffs/ which the IFS routines require (ffs_mount() and ffs_reload()) * a new bunch of routines in src/sys/ufs/ifs/ which implement the IFS routines. IFS replaces some of the vfsops, and a handful of vnops - most notably are VFS_VGET(), VOP_LOOKUP(), VOP_UNLINK() and VOP_READDIR(). Any other directory operation is marked as invalid. What this results in: * an IFS partition's create permissions are controlled by the perm/ownership of the root mount point, just like a normal directory * Each inode has perm and ownership too * IFS does *NOT* mean an FFS partition can be opened per inode. This is a completely seperate filesystem here * Softupdates doesn't work with IFS, and really I don't think it needs it. Besides, fsck's are FAST. (Try it :-) * Inodes 0 and 1 aren't allocatable because they are special (dump/swap IIRC). Inode 2 isn't allocatable since UFS/FFS locks all inodes in the system against this particular inode, and unravelling THAT code isn't trivial. Therefore, useful inodes start at 3. Enjoy, and feedback is definitely appreciated!
-rw-r--r--sys/conf/NOTES3
-rw-r--r--sys/conf/files12
-rw-r--r--sys/conf/options1
-rw-r--r--sys/i386/conf/NOTES3
-rw-r--r--sys/ufs/ffs/ffs_extern.h2
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c8
-rw-r--r--sys/ufs/ffs/ffs_vnops.c4
-rw-r--r--sys/ufs/ifs/README109
-rw-r--r--sys/ufs/ifs/ifs_extern.h84
-rw-r--r--sys/ufs/ifs/ifs_lookup.c254
-rw-r--r--sys/ufs/ifs/ifs_subr.c120
-rw-r--r--sys/ufs/ifs/ifs_vfsops.c279
-rw-r--r--sys/ufs/ifs/ifs_vnops.c473
13 files changed, 1345 insertions, 7 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 7702d03..f965941 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -665,6 +665,9 @@ options NFS_ROOT #NFS usable as root device
# This code is still experimental (e.g. doesn't handle disk slices well).
# Also, 'options MFS' is currently incompatible with DEVFS.
options DEVFS #devices filesystem
+# This code enables IFS, an FFS which exports inodes as the namespace.
+# You can find details in src/sys/ufs/ifs/README .
+options IFS
# Soft updates is a technique for improving file system speed and
# making abrupt shutdown less risky.
diff --git a/sys/conf/files b/sys/conf/files
index 9aab791..cb32e8d 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -973,22 +973,30 @@ posix4/ksched.c optional _kposix_priority_scheduling
posix4/p1003_1b.c standard
posix4/posix4_mib.c standard
ufs/ffs/ffs_alloc.c optional ffs
+ufs/ffs/ffs_alloc.c optional ifs
ufs/ffs/ffs_alloc.c optional mfs
ufs/ffs/ffs_balloc.c optional ffs
+ufs/ffs/ffs_balloc.c optional ifs
ufs/ffs/ffs_balloc.c optional mfs
ufs/ffs/ffs_inode.c optional ffs
+ufs/ffs/ffs_inode.c optional ifs
ufs/ffs/ffs_inode.c optional mfs
ufs/ffs/ffs_snapshot.c optional ffs
+ufs/ffs/ffs_snapshot.c optional ifs
ufs/ffs/ffs_snapshot.c optional mfs
ufs/ffs/ffs_softdep.c optional softupdates
ufs/ffs/ffs_softdep_stub.c standard
ufs/ffs/ffs_subr.c optional ffs
+ufs/ffs/ffs_subr.c optional ifs
ufs/ffs/ffs_subr.c optional mfs
ufs/ffs/ffs_tables.c optional ffs
+ufs/ffs/ffs_tables.c optional ifs
ufs/ffs/ffs_tables.c optional mfs
ufs/ffs/ffs_vfsops.c optional ffs
+ufs/ffs/ffs_vfsops.c optional ifs
ufs/ffs/ffs_vfsops.c optional mfs
ufs/ffs/ffs_vnops.c optional ffs
+ufs/ffs/ffs_vnops.c optional ifs
ufs/ffs/ffs_vnops.c optional mfs
ufs/mfs/mfs_vfsops.c optional mfs
ufs/mfs/mfs_vnops.c optional mfs
@@ -997,6 +1005,10 @@ ufs/ufs/ufs_extattr.c standard
ufs/ufs/ufs_ihash.c standard
ufs/ufs/ufs_inode.c standard
ufs/ufs/ufs_lookup.c standard
+ufs/ifs/ifs_lookup.c optional ifs
+ufs/ifs/ifs_vfsops.c optional ifs
+ufs/ifs/ifs_vnops.c optional ifs
+ufs/ifs/ifs_subr.c optional ifs
ufs/ufs/ufs_quota.c standard
ufs/ufs/ufs_vfsops.c standard
ufs/ufs/ufs_vnops.c standard
diff --git a/sys/conf/options b/sys/conf/options
index a2a0bfc..5402290 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -122,6 +122,7 @@ NTFS opt_dontuse.h
CODA
CD9660
FFS
+IFS
NFS
NWFS
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 7702d03..f965941 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -665,6 +665,9 @@ options NFS_ROOT #NFS usable as root device
# This code is still experimental (e.g. doesn't handle disk slices well).
# Also, 'options MFS' is currently incompatible with DEVFS.
options DEVFS #devices filesystem
+# This code enables IFS, an FFS which exports inodes as the namespace.
+# You can find details in src/sys/ufs/ifs/README .
+options IFS
# Soft updates is a technique for improving file system speed and
# making abrupt shutdown less risky.
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index 1d52ec7..e5ef387 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -87,6 +87,8 @@ int ffs_isfreeblock __P((struct fs *, unsigned char *, ufs_daddr_t));
int ffs_mountfs __P((struct vnode *, struct mount *, struct proc *,
struct malloc_type *));
int ffs_mountroot __P((void));
+int ffs_mount __P((struct mount *, char *, caddr_t, struct nameidata *,
+ struct proc *));
int ffs_reallocblks __P((struct vop_reallocblks_args *));
int ffs_realloccg __P((struct inode *,
ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **));
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 80610a3..fd3fd5d 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -68,10 +68,8 @@
static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part");
static int ffs_sbupdate __P((struct ufsmount *, int));
-static int ffs_reload __P((struct mount *,struct ucred *,struct proc *));
+int ffs_reload __P((struct mount *,struct ucred *,struct proc *));
static int ffs_oldfscompat __P((struct fs *));
-static int ffs_mount __P((struct mount *, char *, caddr_t,
- struct nameidata *, struct proc *));
static int ffs_init __P((struct vfsconf *));
static struct vfsops ufs_vfsops = {
@@ -134,7 +132,7 @@ VFS_SET(ufs_vfsops, ufs, 0);
* system call will fail with EFAULT in copyinstr in
* namei() if it is a genuine NULL from the user.
*/
-static int
+int
ffs_mount(mp, path, data, ndp, p)
struct mount *mp; /* mount struct pointer*/
char *path; /* path to mount point*/
@@ -359,7 +357,7 @@ ffs_mount(mp, path, data, ndp, p)
* 5) invalidate all cached file data.
* 6) re-read inode data for all active vnodes.
*/
-static int
+int
ffs_reload(mp, cred, p)
register struct mount *mp;
struct ucred *cred;
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index b9a83f5..bc26dd4 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -65,7 +65,7 @@
#include <ufs/ffs/fs.h>
#include <ufs/ffs/ffs_extern.h>
-static int ffs_fsync __P((struct vop_fsync_args *));
+int ffs_fsync __P((struct vop_fsync_args *));
static int ffs_getpages __P((struct vop_getpages_args *));
static int ffs_putpages __P((struct vop_putpages_args *));
static int ffs_read __P((struct vop_read_args *));
@@ -128,7 +128,7 @@ VNODEOP_SET(ffs_fifoop_opv_desc);
* Synch an open file.
*/
/* ARGSUSED */
-static int
+int
ffs_fsync(ap)
struct vop_fsync_args /* {
struct vnode *a_vp;
diff --git a/sys/ufs/ifs/README b/sys/ufs/ifs/README
new file mode 100644
index 0000000..cf66c70
--- /dev/null
+++ b/sys/ufs/ifs/README
@@ -0,0 +1,109 @@
+
+$FreeBSD$
+
+ifs- inode filesystem
+--
+
+
+ifs is the beginning of a little experiment - to remove the namespace
+from ffs. FFS is a good generic filesystem, however in high volume
+activities today (eg web, mail, cache, news) one thing causes a rather
+huge resource drain - the namespace.
+
+Having to maintain the directory structures means wasting a lot of
+disk IO and/or memory. Since most applications these days have their
+own database containing object->ufs namespace mappings, we can effectively
+bypass namespace together and talk instead to just inodes.
+
+This is a big big hack(1), but its also a start. It should speed up news
+servers and cache servers quite a bit - since the time spent in open()
+and unlink() is drastically reduced - however, it is nowhere near
+optimal. We'll cover that shortly.
+
+(1) not hack as evil and ugly, hack as in non-optimal solution. The
+ optimal solution hasn't quite presented itself yet. :-)
+
+
+
+How it works:
+--
+
+Basically ifs is a copy of ffs, overriding some vfs/vnops. (Yes, hack.)
+I didn't see the need in duplicating all of sys/ufs/ffs to get this
+off the ground.
+
+File creation is done through a special file - 'newfile' . When newfile
+is called, the system allocates and returns an inode. Note that newfile
+is done in a cloning fashion:
+
+fd = open("newfile", O_CREAT|O_RDWR, 0644);
+fstat(fd, &st);
+
+printf("new file is %d\n", (int)st.st_ino);
+
+Once you have created a file, you can open() and unlink() it by its returned
+inode number retrieved from the stat call, ie:
+
+fd = open("5", O_RDWR);
+
+The creation permissions depend entirely if you have write access to the
+root directory of the filesystem.
+
+
+Why its nowhere near optimal
+--
+
+When doing file allocation in FFS, it tries to reduce the disk seeks by
+allocating new files inside the cylinder group of the parent directory, if
+possible. In this scheme, we've had to drop that. Files are allocated
+sequentially, filling up cylinder groups as we go along. Its not very optimal,
+more research will have to be done into how cylinder group locality can be
+bought back into this. (It entirely depends upon the benefits here..)
+
+Allowing create by inode number requires quite a bit of code rewrite, and in
+the test applications here I didn't need it. Maybe in the next phase I might
+look at allowing create by inode number, feedback, please.
+
+SOFTUPDATES will *NOT* work here - especially in unlink() where I've just
+taken a large axe to it. I've tried to keep as much of the softupdates call
+stubs in as much as possible, but I haven't looked at the softupdates code.
+My reasoning was that because there's no directory metadata anymore,
+softupdates isn't as important. Besides, fsck's are so damn quick ..
+
+Extras
+--
+
+I've taken the liberty of applying a large axe to bits of fsck - stripping out
+namespace checks. As far as I can *TELL*, its close, however, I'd like it if
+someone fsck clued poked me back on what I missed.
+
+There's also a modified copy of mount that will mount a fs type 'ifs'. Again,
+its just the normal mount with s/"ufs"/"ifs"/g, async/noatime/etc mount
+options work just as normal.
+
+I haven't supplied an ifs 'newfs' - use FFS newfs to create a blank drive.
+That creates the root directory, which you still do DEFINITELY need.
+However, ifs updates on the drive will not update directory entries in '.'.
+There is a 1:1 mapping between the inode numbers in open()/stat() and the
+inodes on disk. You don't get access to inodes 0-2. They don't show up
+in a readdir. I'll work on making 2 avaliable, but since the current ufs/ffs
+code assumes things are locked against the root inode which is 2 ..
+
+You can find these utilities in src/sbin/mount_ifs and src/sbin/fsck_ifs .
+Yes, this means that you can tie in ifs partitions in your bootup
+sequence.
+
+TODO:
+--
+
+* Implement cookies for NFS
+
+ (Realise that this is a huge hack which uses the existing UFS/FFS code.
+ Therefore its nowhere near as optimal as it could be, and things aren't
+ as easy to add as one might think. Especially 'fake' files. :-)
+
+
+
+--
+Adrian Chadd
+<adrianFreeBSD.org>
diff --git a/sys/ufs/ifs/ifs_extern.h b/sys/ufs/ifs/ifs_extern.h
new file mode 100644
index 0000000..f8fe866
--- /dev/null
+++ b/sys/ufs/ifs/ifs_extern.h
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95
+ * $FreeBSD$
+ */
+
+#ifndef _UFS_IFS_EXTERN_H
+#define _UFS_IFS_EXTERN_H
+
+/*
+ * Sysctl values for the fast filesystem.
+ */
+#define IFS_REALLOCBLKS 3 /* block reallocation enabled */
+#define IFS_ASYNCFREE 4 /* asynchronous block freeing enabled */
+#define IFS_MAXID 5 /* number of valid ffs ids */
+
+
+/* Return vals from ifs_isinodealloc */
+#define IFS_INODE_ISALLOC 1
+#define IFS_INODE_NOALLOC 0
+#define IFS_INODE_EMPTYCG -1
+
+#define IFS_NAMES { \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "doreallocblks", CTLTYPE_INT }, \
+ { "doasyncfree", CTLTYPE_INT }, \
+}
+
+struct buf;
+struct fid;
+struct fs;
+struct inode;
+struct malloc_type;
+struct mount;
+struct proc;
+struct sockaddr;
+struct statfs;
+struct ucred;
+struct vnode;
+struct vop_balloc_args;
+struct vop_bmap_args;
+struct vop_fsync_args;
+struct vop_reallocblks_args;
+
+extern vop_t **ifs_vnodeop_p;
+extern vop_t **ifs_specop_p;
+extern vop_t **ifs_fifoop_p;
+
+int ifs_lookup(struct vop_lookup_args *);
+int ifs_isinodealloc(struct inode *, ufs_daddr_t);
+
+#endif /* !_UFS_IFS_EXTERN_H */
diff --git a/sys/ufs/ifs/ifs_lookup.c b/sys/ufs/ifs/ifs_lookup.c
new file mode 100644
index 0000000..47c7f11
--- /dev/null
+++ b/sys/ufs/ifs/ifs_lookup.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 1999, 2000
+ * Adrian Chadd <adrian@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95
+ * $FreeBSD$
+ */
+
+#include <machine/limits.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/namei.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/ufs_extern.h>
+#include <ufs/ffs/fs.h>
+
+#include <ufs/ifs/ifs_extern.h>
+
+/* true if old FS format...*/
+#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
+
+/* Define if you want my debug printfs inside ifs_lookup() */
+#undef DEBUG_IFS_LOOKUP
+
+
+#ifdef DEBUG_IFS_LOOKUP
+static char *
+getnameiopstr(int nameiop)
+{
+ switch (nameiop) {
+ case LOOKUP:
+ return "LOOKUP";
+ break;
+ case CREATE:
+ return "CREATE";
+ break;
+ case DELETE:
+ return "DELETE";
+ break;
+ case RENAME:
+ return "RENAME";
+ break;
+ default:
+ return "unknown";
+ break;
+ }
+}
+#endif
+
+/*
+ * Convert a path to an inode.
+ *
+ * This is HIGHLY simplified - we just take the path fragment given to us,
+ * attempt to convert it to an inode, and return the inode if we can.
+ * No permission checking is done here, that is done further up in the
+ * VFS call layers.
+ */
+int
+ifs_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct vnode *vdp; /* vnode for directory being searched */
+ struct inode *dp; /* inode for directory being searched */
+ struct vnode *pdp; /* saved dp during symlink work */
+ struct vnode *tdp; /* returned by VFS_VGET */
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct ucred *cred = cnp->cn_cred;
+ struct mount *mp = ap->a_dvp->v_mount;
+ struct fs *fs = VFSTOUFS(mp)->um_fs;
+ int flags = cnp->cn_flags;
+ int nameiop = cnp->cn_nameiop;
+ int error, lockparent, wantparent;
+ struct proc *p = cnp->cn_proc;
+ ufs_daddr_t inodenum;
+ char *endp;
+
+ *vpp = NULL;
+ lockparent = flags & LOCKPARENT;
+ wantparent = flags & (LOCKPARENT|WANTPARENT);
+ vdp = ap->a_dvp;
+ dp = VTOI(vdp);
+ pdp = vdp;
+ /*
+ * Firstly, we are NOT dealing with RENAME, at all
+ */
+ if (nameiop == RENAME) {
+ *vpp = NULL;
+#ifdef DEBUG_IFS_LOOKUP
+ printf("ifs_lookup(): Denying RENAME nameiop\n");
+#endif
+ return (EPERM);
+ }
+ /* Deal with the '.' directory */
+ /* VOP_UNLOCK(vdp, 0, p); */
+ if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
+ /* We don't unlock the parent dir since the're the same */
+ *vpp = vdp;
+ VREF(vdp);
+ /* vn_lock(vdp, LK_SHARED | LK_RETRY, p); */
+ return (0);
+ }
+ /*
+ * 'newfile' is considered something special .. read below why
+ * we're returning NULL
+ */
+ if ((cnp->cn_namelen) == 7 && (strncmp(cnp->cn_nameptr, "newfile", 7) == 0)) {
+ if (nameiop == CREATE) {
+ /* Check for write permissions in . */
+ error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
+ if (error)
+ return (error);
+ *vpp = NULL;
+ if (!lockparent || !(flags & ISLASTCN))
+ VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= SAVENAME;
+ return (EJUSTRETURN);
+ } else {
+ *vpp = NULL;
+#ifdef DEBUG_IFS_LOOKUP
+ printf("ifs_lookup(): Denying !CREATE on 'newfile'\n");
+#endif
+ return (EPERM);
+ }
+ }
+ /* Grab the hex inode number */
+ inodenum = strtouq(cnp->cn_nameptr, &endp, 0);
+ /* Sanity Check */
+ if (endp != (cnp->cn_nameptr + cnp->cn_namelen)) {
+ *vpp = NULL;
+ return (ENOENT);
+ }
+ /*
+ * error check here - inodes 0-2 are considered 'special' even here
+ * so we will hide it from the user.
+ */
+ if (inodenum <= 2) {
+#ifdef DEBUG_IFS_LOOKUP
+ printf("ifs_lookup(): Access to disk inode '%d' denied\n",
+ (int)inodenum);
+#endif
+ return EPERM;
+ }
+ /* Check we haven't overflowed the number of inodes in the fs */
+ if (inodenum > (fs->fs_ncg * fs->fs_ipg)) {
+#ifdef DEBUG_IFS_LOOKUP
+ printf("ifs_lookup(): disk inode '%d' is outside the disk\n"),
+ (int)inodenum);
+#endif
+ return EINVAL;
+ }
+ /*
+ * The next bit of code grabs the inode, checks to see whether
+ * we're allowed to do our nameiop on it. The only one we need
+ * to check here is CREATE - only allow create on an inode
+ * that exists.
+ *
+ * Comment for VFS-newbies:
+ * read vn_open() - you'll learn that if you return a name here,
+ * it assumes you don't need to call VOP_CREATE. Bad juju as
+ * you now have a vnode that isn't tagged with the right type,
+ * and it'll panic in the VOP_READ/VOP_WRITE routines..
+ */
+ /*
+ * If we get here and its a CREATE, then return EPERM if the inode
+ * doesn't exist.
+ */
+ if ((nameiop == CREATE) &&
+ (ifs_isinodealloc(VTOI(vdp), inodenum) != IFS_INODE_ISALLOC)) {
+#ifdef DEBUG_IFS_LOOKUP
+ printf("ifs_lookup(): CREATE on inode %d which doesn't exist\n",
+ (int)inodenum);
+#endif
+ return EPERM;
+#ifdef DEBUG_IFS_LOOKUP
+ } else if (nameiop == CREATE) {
+ /* It does exist, allow CREATE */
+ printf("ifs_lookup(): CREATE on inode %d which exists\n",
+ (int)inodenum);
+ }
+#else
+ }
+#endif
+ /*
+ * Make sure that the inode exists if we're trying to delete or
+ * modify
+ */
+ if ((nameiop == LOOKUP || nameiop == DELETE) &&
+ ifs_isinodealloc(VTOI(vdp), inodenum) != IFS_INODE_ISALLOC) {
+ /* it doesn't exist */
+#ifdef DEBUG_IFS_LOOKUP
+ printf("ifs_lookup(): Inode %d isn't allocated\n", inodenum);
+#endif
+ return ENOENT;
+ }
+ /* Now, we can get the vnode */
+ error = VFS_VGET(vdp->v_mount, (long)inodenum, &tdp);
+ if (error)
+ return (error);
+ if (!lockparent || !(flags & ISLASTCN))
+ VOP_UNLOCK(pdp, 0, p);
+ *vpp = tdp;
+ return (0);
+}
+
diff --git a/sys/ufs/ifs/ifs_subr.c b/sys/ufs/ifs/ifs_subr.c
new file mode 100644
index 0000000..b1c213b
--- /dev/null
+++ b/sys/ufs/ifs/ifs_subr.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1999, 2000
+ * Adrian Chadd <adrian@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+
+#include <machine/limits.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufs_extern.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
+#include <ufs/ifs/ifs_extern.h>
+
+
+/*
+ * Check whether the given inode number is free.
+ *
+ * This routine is a chunk of ffs_nodealloccg - we aren't
+ * allocating here. We also check whether there will be
+ * any other inodes in the cylinder group, and if not,
+ * we return -1.
+ */
+int
+ifs_isinodealloc(struct inode *ip, ufs_daddr_t ino)
+{
+ struct fs *fs;
+ struct cg *cgp;
+ struct buf *bp;
+ int error;
+ int cg;
+ int retval = 0;
+
+ /* Grab the filesystem info and cylinder group */
+ fs = ip->i_fs;
+ cg = ino_to_cg(fs, ino);
+ /* Read in the cylinder group inode allocation bitmap .. */
+ error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+ (int)fs->fs_cgsize, NOCRED, &bp);
+ if (error) {
+ retval = IFS_INODE_NOALLOC;
+ goto end;
+ }
+ cgp = (struct cg *)bp->b_data;
+ if (!cg_chkmagic(cgp)) {
+ retval = IFS_INODE_NOALLOC;
+ goto end;
+ }
+ ino %= fs->fs_ipg;
+ /*
+ * Check whether we have any inodes in this cg, or whether the
+ * inode is allocated
+ */
+ if (!isclr(cg_inosused(cgp), ino))
+ retval = IFS_INODE_ISALLOC; /* it is allocated */
+ else if (cgp->cg_niblk == cgp->cg_cs.cs_nifree)
+ retval = IFS_INODE_EMPTYCG; /* empty cg */
+ else
+ retval = IFS_INODE_NOALLOC; /* its not allocated */
+end:
+ /* Close the buffer and return */
+ brelse(bp);
+ return (retval);
+}
+
diff --git a/sys/ufs/ifs/ifs_vfsops.c b/sys/ufs/ifs/ifs_vfsops.c
new file mode 100644
index 0000000..e607d54
--- /dev/null
+++ b/sys/ufs/ifs/ifs_vfsops.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1999, 2000
+ * Adrian Chadd <adrian@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95
+ * $FreeBSD$
+ */
+
+
+#include "opt_ffs.h"
+#include "opt_quota.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/disklabel.h>
+#include <sys/malloc.h>
+
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufs_extern.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
+#include <ufs/ifs/ifs_extern.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+
+
+static MALLOC_DEFINE(M_IFSNODE, "IFS node", "IFS vnode private part");
+
+static int ifs_init (struct vfsconf *);
+static int ifs_mount (struct mount *, char *, caddr_t,
+ struct nameidata *, struct proc *);
+extern int ifs_vget (struct mount *, ino_t, struct vnode **);
+
+
+
+static struct vfsops ifs_vfsops = {
+ ifs_mount,
+ ufs_start,
+ ffs_unmount,
+ ufs_root,
+ ufs_quotactl,
+ ffs_statfs,
+ ffs_sync,
+ ifs_vget,
+ ffs_fhtovp,
+ ufs_check_export,
+ ffs_vptofh,
+ ifs_init,
+ vfs_stduninit,
+ vfs_stdextattrctl,
+};
+
+VFS_SET(ifs_vfsops, ifs, 0);
+
+/*
+ * Initialize the filesystem; just use ufs_init.
+ */
+static int
+ifs_init(vfsp)
+ struct vfsconf *vfsp;
+{
+ return (ufs_init(vfsp));
+}
+
+/*
+ * ifs_mount
+ *
+ * A simple wrapper around ffs_mount - IFS filesystems right now can't
+ * deal with softupdates so we make sure the user isn't trying to use it.
+ */
+static int
+ifs_mount(mp, path, data, ndp, p)
+ struct mount *mp;
+ char *path;
+ caddr_t data;
+ struct nameidata *ndp;
+ struct proc *p;
+{
+ /* Clear the softdep flag */
+ mp->mnt_flag &= ~MNT_SOFTDEP;
+ return (ffs_mount(mp, path, data, ndp, p));
+}
+
+
+
+/*
+ * Look up a IFS dinode number to find its incore vnode, otherwise read it
+ * in from disk. If it is in core, wait for the lock bit to clear, then
+ * return the inode locked. Detection and handling of mount points must be
+ * done by the calling routine.
+ */
+static int ifs_inode_hash_lock;
+
+int
+ifs_vget(mp, ino, vpp)
+ struct mount *mp;
+ ino_t ino;
+ struct vnode **vpp;
+{
+ struct fs *fs;
+ struct inode *ip;
+ struct ufsmount *ump;
+ struct buf *bp;
+ struct vnode *vp;
+ dev_t dev;
+ int error;
+
+ ump = VFSTOUFS(mp);
+ dev = ump->um_dev;
+restart:
+ if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
+ return (0);
+ }
+
+ /*
+ * Lock out the creation of new entries in the FFS hash table in
+ * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
+ * may occur!
+ */
+ if (ifs_inode_hash_lock) {
+ while (ifs_inode_hash_lock) {
+ ifs_inode_hash_lock = -1;
+ tsleep(&ifs_inode_hash_lock, PVM, "ifsvgt", 0);
+ }
+ goto restart;
+ }
+ ifs_inode_hash_lock = 1;
+
+ /*
+ * If this MALLOC() is performed after the getnewvnode()
+ * it might block, leaving a vnode with a NULL v_data to be
+ * found by ffs_sync() if a sync happens to fire right then,
+ * which will cause a panic because ffs_sync() blindly
+ * dereferences vp->v_data (as well it should).
+ */
+ MALLOC(ip, struct inode *, sizeof(struct inode),
+ ump->um_malloctype, M_WAITOK);
+
+ /* Allocate a new vnode/inode. */
+ error = getnewvnode(VT_UFS, mp, ifs_vnodeop_p, &vp);
+ if (error) {
+ if (ifs_inode_hash_lock < 0)
+ wakeup(&ifs_inode_hash_lock);
+ ifs_inode_hash_lock = 0;
+ *vpp = NULL;
+ FREE(ip, ump->um_malloctype);
+ return (error);
+ }
+ bzero((caddr_t)ip, sizeof(struct inode));
+ /*
+ * IFS supports lock sharing in the stack of vnodes
+ */
+ vp->v_vnlock = &vp->v_lock;
+ lockinit(vp->v_vnlock, PINOD, "inode", 0, LK_CANRECURSE);
+ vp->v_data = ip;
+ ip->i_vnode = vp;
+ ip->i_fs = fs = ump->um_fs;
+ ip->i_dev = dev;
+ ip->i_number = ino;
+#ifdef QUOTA
+ {
+ int i;
+ for (i = 0; i < MAXQUOTAS; i++)
+ ip->i_dquot[i] = NODQUOT;
+ }
+#endif
+ /*
+ * Put it onto its hash chain and lock it so that other requests for
+ * this inode will block if they arrive while we are sleeping waiting
+ * for old data structures to be purged or for the contents of the
+ * disk portion of this inode to be read.
+ */
+ ufs_ihashins(ip);
+
+ if (ifs_inode_hash_lock < 0)
+ wakeup(&ifs_inode_hash_lock);
+ ifs_inode_hash_lock = 0;
+
+ /* Read in the disk contents for the inode, copy into the inode. */
+ error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
+ (int)fs->fs_bsize, NOCRED, &bp);
+ if (error) {
+ /*
+ * The inode does not contain anything useful, so it would
+ * be misleading to leave it on its hash chain. With mode
+ * still zero, it will be unlinked and returned to the free
+ * list by vput().
+ */
+ brelse(bp);
+ vput(vp);
+ *vpp = NULL;
+ return (error);
+ }
+ ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
+ if (DOINGSOFTDEP(vp))
+ softdep_load_inodeblock(ip);
+ else
+ ip->i_effnlink = ip->i_nlink;
+ bqrelse(bp);
+
+ /*
+ * Initialize the vnode from the inode, check for aliases.
+ * Note that the underlying vnode may have changed.
+ */
+ error = ufs_vinit(mp, ifs_specop_p, ifs_fifoop_p, &vp);
+ if (error) {
+ vput(vp);
+ *vpp = NULL;
+ return (error);
+ }
+ /*
+ * Finish inode initialization now that aliasing has been resolved.
+ */
+ ip->i_devvp = ump->um_devvp;
+ VREF(ip->i_devvp);
+ /*
+ * Set up a generation number for this inode if it does not
+ * already have one. This should only happen on old filesystems.
+ */
+ if (ip->i_gen == 0) {
+ ip->i_gen = random() / 2 + 1;
+ if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
+ ip->i_flag |= IN_MODIFIED;
+ }
+ /*
+ * Ensure that uid and gid are correct. This is a temporary
+ * fix until fsck has been changed to do the update.
+ */
+ if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
+ ip->i_uid = ip->i_din.di_ouid; /* XXX */
+ ip->i_gid = ip->i_din.di_ogid; /* XXX */
+ } /* XXX */
+
+ *vpp = vp;
+ return (0);
+}
diff --git a/sys/ufs/ifs/ifs_vnops.c b/sys/ufs/ifs/ifs_vnops.c
new file mode 100644
index 0000000..658b633
--- /dev/null
+++ b/sys/ufs/ifs/ifs_vnops.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 1999, 2000
+ * Adrian Chadd <adrian@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+#include <sys/poll.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+
+#include <machine/limits.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/ufs_extern.h>
+#include <ufs/ufs/dir.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
+
+#include <ufs/ifs/ifs_extern.h>
+
+/* IFS debugging */
+#undef DEBUG_IFS_READDIR
+
+/* Declare our trampling into the FFS code */
+extern int ffs_fsync (struct vop_fsync_args *);
+static int ffs_getpages(struct vop_getpages_args *);
+static int ffs_putpages(struct vop_putpages_args *);
+static int ffs_read(struct vop_read_args *);
+static int ffs_write(struct vop_write_args *);
+
+static int ifs_noop(struct vop_generic_args *);
+static int ifs_getattr(struct vop_getattr_args *);
+static int ifs_create(struct vop_create_args *);
+static int ifs_makeinode(int mode, struct vnode *, struct vnode **,
+ struct componentname *);
+static int ifs_remove(struct vop_remove_args *);
+static int ifs_readdir(struct vop_readdir_args *);
+static int ifs_dirremove(struct vnode *, struct inode *, int, int);
+
+
+
+/* Global vfs data structures for ifs. */
+vop_t **ifs_vnodeop_p;
+static struct vnodeopv_entry_desc ifs_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) ufs_vnoperate },
+ { &vop_fsync_desc, (vop_t *) ffs_fsync },
+ { &vop_getpages_desc, (vop_t *) ffs_getpages },
+ { &vop_putpages_desc, (vop_t *) ffs_putpages },
+ { &vop_read_desc, (vop_t *) ffs_read },
+ { &vop_balloc_desc, (vop_t *) ffs_balloc },
+ { &vop_reallocblks_desc, (vop_t *) ffs_reallocblks },
+ { &vop_write_desc, (vop_t *) ffs_write },
+
+ { &vop_lookup_desc, (vop_t *) ifs_lookup },
+ { &vop_getattr_desc, (vop_t *) ifs_getattr },
+ { &vop_create_desc, (vop_t *) ifs_create },
+ { &vop_remove_desc, (vop_t *) ifs_remove },
+ { &vop_readdir_desc, (vop_t *) ifs_readdir },
+
+/* NULL operations for ifs */
+ { &vop_cachedlookup_desc, (vop_t *) ifs_noop },
+ { &vop_mkdir_desc, (vop_t *) ifs_noop },
+ { &vop_mknod_desc, (vop_t *) ifs_noop },
+ { &vop_readlink_desc, (vop_t *) ifs_noop },
+ { &vop_rename_desc, (vop_t *) ifs_noop },
+ { &vop_rmdir_desc, (vop_t *) ifs_noop },
+ { &vop_symlink_desc, (vop_t *) ifs_noop },
+ { &vop_link_desc, (vop_t *) ifs_noop },
+ { &vop_whiteout_desc, (vop_t *) ifs_noop },
+
+ { NULL, NULL }
+};
+static struct vnodeopv_desc ifs_vnodeop_opv_desc =
+ { &ifs_vnodeop_p, ifs_vnodeop_entries };
+
+vop_t **ifs_specop_p;
+static struct vnodeopv_entry_desc ifs_specop_entries[] = {
+ { &vop_default_desc, (vop_t *) ufs_vnoperatespec },
+ { &vop_fsync_desc, (vop_t *) ffs_fsync },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc ifs_specop_opv_desc =
+ { &ifs_specop_p, ifs_specop_entries };
+
+vop_t **ifs_fifoop_p;
+static struct vnodeopv_entry_desc ifs_fifoop_entries[] = {
+ { &vop_default_desc, (vop_t *) ufs_vnoperatefifo },
+ { &vop_fsync_desc, (vop_t *) ffs_fsync },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc ifs_fifoop_opv_desc =
+ { &ifs_fifoop_p, ifs_fifoop_entries };
+
+VNODEOP_SET(ifs_vnodeop_opv_desc);
+VNODEOP_SET(ifs_specop_opv_desc);
+VNODEOP_SET(ifs_fifoop_opv_desc);
+
+#include <ufs/ufs/ufs_readwrite.c>
+
+
+static int
+ifs_noop(ap)
+ struct vop_generic_args *ap;
+{
+ return EOPNOTSUPP;
+}
+
+
+/* ARGSUSED */
+static int
+ifs_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct inode *ip = VTOI(vp);
+ register struct vattr *vap = ap->a_vap;
+
+ ufs_itimes(vp);
+ /*
+ * Copy from inode table
+ */
+ vap->va_fsid = dev2udev(ip->i_dev);
+ vap->va_fileid = ip->i_number;
+ vap->va_mode = ip->i_mode & ~IFMT;
+ vap->va_nlink = VFSTOUFS(vp->v_mount)->um_i_effnlink_valid ?
+ ip->i_effnlink : ip->i_nlink;
+ vap->va_uid = ip->i_uid;
+ vap->va_gid = ip->i_gid;
+ vap->va_rdev = ip->i_rdev;
+ vap->va_size = ip->i_din.di_size;
+ vap->va_atime.tv_sec = ip->i_atime;
+ vap->va_atime.tv_nsec = ip->i_atimensec;
+ vap->va_mtime.tv_sec = ip->i_mtime;
+ vap->va_mtime.tv_nsec = ip->i_mtimensec;
+ vap->va_ctime.tv_sec = ip->i_ctime;
+ vap->va_ctime.tv_nsec = ip->i_ctimensec;
+ vap->va_flags = ip->i_flags;
+ vap->va_gen = ip->i_gen;
+ vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
+ vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
+ vap->va_type = IFTOVT(ip->i_mode);
+ vap->va_filerev = ip->i_modrev;
+ return (0);
+}
+
+
+/*
+ * Create a regular file
+ */
+int
+ifs_create(ap)
+ struct vop_create_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ int error;
+
+ error =
+ ifs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
+ ap->a_dvp, ap->a_vpp, ap->a_cnp);
+ if (error)
+ return (error);
+ VN_POLLEVENT(ap->a_dvp, POLLWRITE);
+ return (0);
+}
+
+
+/*
+ * Allocate a new inode.
+ */
+int
+ifs_makeinode(mode, dvp, vpp, cnp)
+ int mode;
+ struct vnode *dvp;
+ struct vnode **vpp;
+ struct componentname *cnp;
+{
+ register struct inode *ip, *pdir;
+ struct vnode *tvp;
+ int error;
+
+ pdir = VTOI(dvp);
+#ifdef DIAGNOSTIC
+ if ((cnp->cn_flags & HASBUF) == 0)
+ panic("ifs_makeinode: no name");
+#endif
+ *vpp = NULL;
+ if ((mode & IFMT) == 0)
+ mode |= IFREG;
+ error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
+ if (error) {
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+ }
+ ip = VTOI(tvp);
+ ip->i_gid = pdir->i_gid;
+ ip->i_uid = cnp->cn_cred->cr_uid;
+#ifdef QUOTA
+ if ((error = getinoquota(ip)) ||
+ (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
+ UFS_VFREE(tvp, ip->i_number, mode);
+ vput(tvp);
+ return (error);
+ }
+#endif
+ ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
+ ip->i_mode = mode;
+ tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
+ ip->i_effnlink = 1;
+ ip->i_nlink = 1;
+ if (DOINGSOFTDEP(tvp))
+ softdep_change_linkcnt(ip);
+ if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
+ suser_xxx(cnp->cn_cred, 0, 0))
+ ip->i_mode &= ~ISGID;
+
+ if (cnp->cn_flags & ISWHITEOUT)
+ ip->i_flags |= UF_OPAQUE;
+
+ /*
+ * Make sure inode goes to disk before directory entry.
+ */
+ error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) | DOINGASYNC(tvp)));
+ if (error)
+ 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_effnlink = 0;
+ ip->i_nlink = 0;
+ ip->i_flag |= IN_CHANGE;
+ if (DOINGSOFTDEP(tvp))
+ softdep_change_linkcnt(ip);
+ vput(tvp);
+ return (error);
+}
+
+
+int
+ifs_remove(ap)
+ struct vop_remove_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct inode *ip;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+ int error;
+
+ ip = VTOI(vp);
+ if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
+ (VTOI(dvp)->i_flags & APPEND)) {
+ error = EPERM;
+ goto out;
+ }
+ error = ifs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
+ VN_POLLEVENT(vp, POLLNLINK);
+out:
+ return (error);
+}
+
+
+/*
+ * highly cutdown ufs_dirremove, since we're not updating
+ * any directory entries. :-)
+ */
+static int
+ifs_dirremove(struct vnode *dvp, struct inode *ip, int flags, int isrmdir)
+{
+ int error;
+
+ if (ip) {
+ ip->i_effnlink--;
+ ip->i_flag |= IN_CHANGE;
+ ip->i_nlink--;
+ error = 0;
+ } else
+ error = ENOENT;
+ return (error);
+}
+
+
+/*
+ * ifs_readdir
+ *
+ * Do the directory listing, representing the allocated inodes
+ * making up this filesystem.
+ *
+ */
+
+static int
+ifs_readdir(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;
+ } */ *ap;
+{
+ int inodenum;
+ struct dirent *dent, *lastdp = NULL;
+ struct dirent *tmpdp;
+ char *dirbuf;
+ struct inode *ip = VTOI(ap->a_vp); /* To get the mount info later */
+ struct mount *mp = ap->a_vp->v_mount;
+ struct fs *fs = VFSTOUFS(mp)->um_fs;
+ int maxnuminode = fs->fs_ncg * fs->fs_ipg;
+ int error = 0;
+ int count;
+ int dircount = 0;
+ int copylen = 0;
+ char iret;
+
+ /*
+ * Get the offset, which represents the inode we're going to
+ * start from
+ */
+ inodenum = ap->a_uio->uio_offset;
+#ifdef DEBUG_IFS_READDIR
+ printf("ifs_readdir: starting with inode %d\n", inodenum);
+#endif
+ if (inodenum < 0)
+ return EINVAL;
+ /*
+ * Next, get the buffer size, round it down to a dirent, and
+ * figure out how many allocated inodes we need to match
+ */
+ count = ap->a_uio->uio_resid;
+ /*
+ * Next, create a dirbuf to fill with directory entries
+ */
+ MALLOC(tmpdp, struct dirent *, sizeof (struct dirent), M_TEMP, M_WAITOK);
+ MALLOC(dirbuf, char *, count, M_TEMP, M_WAITOK);
+ dent = (struct dirent *)dirbuf;
+ /* now, keep reading until we run out of inodes */
+ while (inodenum <= maxnuminode) {
+ /* Get bitmap info and see if we bother with this cg */
+ iret = ifs_isinodealloc(ip, inodenum);
+ if (iret == IFS_INODE_EMPTYCG) {
+ /* Skip this CG */
+ /* Next cg please */
+ inodenum -= inodenum % fs->fs_ipg;
+ inodenum += fs->fs_ipg;
+ continue;
+ }
+ /* Allocated and not special? */
+ if ((inodenum > 2) && iret == IFS_INODE_ISALLOC) {
+ /* Create a new entry */
+ sprintf(tmpdp->d_name, "%d", inodenum);
+ tmpdp->d_fileno = inodenum;
+ tmpdp->d_type = DT_REG;
+ tmpdp->d_namlen = strlen(tmpdp->d_name);
+ tmpdp->d_reclen = DIRECTSIZ(tmpdp->d_namlen);
+ /* Make sure we have enough space for this entry */
+ if (tmpdp->d_reclen > count)
+ break;
+ /* Copy it to the given buffer */
+ bcopy(tmpdp, dent, tmpdp->d_reclen);
+ /* Decrement the count */
+ count -= dent->d_reclen;
+ copylen += dent->d_reclen;
+ lastdp = dent;
+ /* Increment the offset pointer */
+ dent = (struct dirent *)((char *)dent + dent->d_reclen);
+ dircount++;
+ }
+ /* Increment the inode number we are checking */
+ inodenum++;
+ }
+ /* End */
+#ifdef DEBUG_IFS_READDIR
+ printf("ifs_readdir: copied %d directories\n", dircount);
+#endif
+ /*
+ * Get the last dent updated, and make the record d_reclen last the whole
+ * buffer.
+ */
+ if (lastdp != NULL) {
+ /* Update the length of the last entry */
+ lastdp->d_reclen += count;
+ }
+ /* Copy the data out */
+#ifdef DEBUG_IFS_READDIR
+ printf("ifs_readdir: copied %d bytes\n", copylen);
+#endif
+ error = uiomove(dirbuf, copylen, ap->a_uio);
+ /* Free memory we've used */
+ FREE(dirbuf, M_TEMP);
+ FREE(tmpdp, M_TEMP);
+ /* Set uio_offset to the last inode number */
+ ap->a_uio->uio_offset = inodenum;
+ /* Handle EOF/eofflag */
+ if ((inodenum >= maxnuminode) && (ap->a_eofflag != NULL)) {
+ *ap->a_eofflag = 1;
+#ifdef DEBUG_IFS_READDIR
+ printf("ifs_readdir: setting EOF flag\n");
+#endif
+ }
+#ifdef DEBUG_IFS_READDIR
+ printf("ifs_readdir: new offset: %d\n", inodenum);
+#endif
+ return error;
+}
+
OpenPOWER on IntegriCloud