diff options
author | adrian <adrian@FreeBSD.org> | 2000-10-14 03:02:30 +0000 |
---|---|---|
committer | adrian <adrian@FreeBSD.org> | 2000-10-14 03:02:30 +0000 |
commit | 0458054c4e405cc6f262b0fb171dc3d049bc7513 (patch) | |
tree | 5d8132a94f833d46795e30aa5296a893b2e5637c | |
parent | ee143d47ad6c41a3590bdb5ed28c7bd5bf6ffff8 (diff) | |
download | FreeBSD-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/NOTES | 3 | ||||
-rw-r--r-- | sys/conf/files | 12 | ||||
-rw-r--r-- | sys/conf/options | 1 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 2 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 8 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 4 | ||||
-rw-r--r-- | sys/ufs/ifs/README | 109 | ||||
-rw-r--r-- | sys/ufs/ifs/ifs_extern.h | 84 | ||||
-rw-r--r-- | sys/ufs/ifs/ifs_lookup.c | 254 | ||||
-rw-r--r-- | sys/ufs/ifs/ifs_subr.c | 120 | ||||
-rw-r--r-- | sys/ufs/ifs/ifs_vfsops.c | 279 | ||||
-rw-r--r-- | sys/ufs/ifs/ifs_vnops.c | 473 |
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; +} + |