summaryrefslogtreecommitdiffstats
path: root/sys/ufs
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 /sys/ufs
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!
Diffstat (limited to 'sys/ufs')
-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
9 files changed, 1326 insertions, 7 deletions
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