4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / sys / ufs / ffs / ffs_vnops.c
index ab7f471..64fcc51 100644 (file)
@@ -1,10 +1,10 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ffs_vnops.c 7.88 (Berkeley) %G%
+ *     @(#)ffs_vnops.c 8.1 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
 #include <sys/conf.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/conf.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
-#include <sys/specdev.h>
-#include <sys/fifo.h>
 #include <sys/malloc.h>
 
 #include <vm/vm.h>
 
 #include <sys/malloc.h>
 
 #include <vm/vm.h>
 
+#include <miscfs/specfs/specdev.h>
+#include <miscfs/fifofs/fifo.h>
+
 #include <ufs/ufs/lockf.h>
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/lockf.h>
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
@@ -61,14 +62,15 @@ struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
        { &vop_readdir_desc, ufs_readdir },             /* readdir */
        { &vop_readlink_desc, ufs_readlink },           /* readlink */
        { &vop_abortop_desc, ufs_abortop },             /* abortop */
        { &vop_readdir_desc, ufs_readdir },             /* readdir */
        { &vop_readlink_desc, ufs_readlink },           /* readlink */
        { &vop_abortop_desc, ufs_abortop },             /* abortop */
-       { &vop_inactive_desc, ffs_inactive },           /* inactive */
+       { &vop_inactive_desc, ufs_inactive },           /* inactive */
        { &vop_reclaim_desc, ufs_reclaim },             /* reclaim */
        { &vop_lock_desc, ufs_lock },                   /* lock */
        { &vop_unlock_desc, ufs_unlock },               /* unlock */
        { &vop_reclaim_desc, ufs_reclaim },             /* reclaim */
        { &vop_lock_desc, ufs_lock },                   /* lock */
        { &vop_unlock_desc, ufs_unlock },               /* unlock */
-       { &vop_bmap_desc, ffs_bmap },                   /* bmap */
+       { &vop_bmap_desc, ufs_bmap },                   /* bmap */
        { &vop_strategy_desc, ufs_strategy },           /* strategy */
        { &vop_print_desc, ufs_print },                 /* print */
        { &vop_islocked_desc, ufs_islocked },           /* islocked */
        { &vop_strategy_desc, ufs_strategy },           /* strategy */
        { &vop_print_desc, ufs_print },                 /* print */
        { &vop_islocked_desc, ufs_islocked },           /* islocked */
+       { &vop_pathconf_desc, ufs_pathconf },           /* pathconf */
        { &vop_advlock_desc, ufs_advlock },             /* advlock */
        { &vop_blkatoff_desc, ffs_blkatoff },           /* blkatoff */
        { &vop_valloc_desc, ffs_valloc },               /* valloc */
        { &vop_advlock_desc, ufs_advlock },             /* advlock */
        { &vop_blkatoff_desc, ffs_blkatoff },           /* blkatoff */
        { &vop_valloc_desc, ffs_valloc },               /* valloc */
@@ -108,7 +110,7 @@ struct vnodeopv_entry_desc ffs_specop_entries[] = {
        { &vop_readdir_desc, spec_readdir },            /* readdir */
        { &vop_readlink_desc, spec_readlink },          /* readlink */
        { &vop_abortop_desc, spec_abortop },            /* abortop */
        { &vop_readdir_desc, spec_readdir },            /* readdir */
        { &vop_readlink_desc, spec_readlink },          /* readlink */
        { &vop_abortop_desc, spec_abortop },            /* abortop */
-       { &vop_inactive_desc, ffs_inactive },           /* inactive */
+       { &vop_inactive_desc, ufs_inactive },           /* inactive */
        { &vop_reclaim_desc, ufs_reclaim },             /* reclaim */
        { &vop_lock_desc, ufs_lock },                   /* lock */
        { &vop_unlock_desc, ufs_unlock },               /* unlock */
        { &vop_reclaim_desc, ufs_reclaim },             /* reclaim */
        { &vop_lock_desc, ufs_lock },                   /* lock */
        { &vop_unlock_desc, ufs_unlock },               /* unlock */
@@ -116,6 +118,7 @@ struct vnodeopv_entry_desc ffs_specop_entries[] = {
        { &vop_strategy_desc, spec_strategy },          /* strategy */
        { &vop_print_desc, ufs_print },                 /* print */
        { &vop_islocked_desc, ufs_islocked },           /* islocked */
        { &vop_strategy_desc, spec_strategy },          /* strategy */
        { &vop_print_desc, ufs_print },                 /* print */
        { &vop_islocked_desc, ufs_islocked },           /* islocked */
+       { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
        { &vop_advlock_desc, spec_advlock },            /* advlock */
        { &vop_blkatoff_desc, spec_blkatoff },          /* blkatoff */
        { &vop_valloc_desc, spec_valloc },              /* valloc */
        { &vop_advlock_desc, spec_advlock },            /* advlock */
        { &vop_blkatoff_desc, spec_blkatoff },          /* blkatoff */
        { &vop_valloc_desc, spec_valloc },              /* valloc */
@@ -156,7 +159,7 @@ struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
        { &vop_readdir_desc, fifo_readdir },            /* readdir */
        { &vop_readlink_desc, fifo_readlink },          /* readlink */
        { &vop_abortop_desc, fifo_abortop },            /* abortop */
        { &vop_readdir_desc, fifo_readdir },            /* readdir */
        { &vop_readlink_desc, fifo_readlink },          /* readlink */
        { &vop_abortop_desc, fifo_abortop },            /* abortop */
-       { &vop_inactive_desc, ffs_inactive },           /* inactive */
+       { &vop_inactive_desc, ufs_inactive },           /* inactive */
        { &vop_reclaim_desc, ufs_reclaim },             /* reclaim */
        { &vop_lock_desc, ufs_lock },                   /* lock */
        { &vop_unlock_desc, ufs_unlock },               /* unlock */
        { &vop_reclaim_desc, ufs_reclaim },             /* reclaim */
        { &vop_lock_desc, ufs_lock },                   /* lock */
        { &vop_unlock_desc, ufs_unlock },               /* unlock */
@@ -164,6 +167,7 @@ struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
        { &vop_strategy_desc, fifo_strategy },          /* strategy */
        { &vop_print_desc, ufs_print },                 /* print */
        { &vop_islocked_desc, ufs_islocked },           /* islocked */
        { &vop_strategy_desc, fifo_strategy },          /* strategy */
        { &vop_print_desc, ufs_print },                 /* print */
        { &vop_islocked_desc, ufs_islocked },           /* islocked */
+       { &vop_pathconf_desc, fifo_pathconf },          /* pathconf */
        { &vop_advlock_desc, fifo_advlock },            /* advlock */
        { &vop_blkatoff_desc, fifo_blkatoff },          /* blkatoff */
        { &vop_valloc_desc, fifo_valloc },              /* valloc */
        { &vop_advlock_desc, fifo_advlock },            /* advlock */
        { &vop_blkatoff_desc, fifo_blkatoff },          /* blkatoff */
        { &vop_valloc_desc, fifo_valloc },              /* valloc */
@@ -177,6 +181,14 @@ struct vnodeopv_desc ffs_fifoop_opv_desc =
        { &ffs_fifoop_p, ffs_fifoop_entries };
 #endif /* FIFO */
 
        { &ffs_fifoop_p, ffs_fifoop_entries };
 #endif /* FIFO */
 
+/*
+ * Enabling cluster read/write operations.
+ */
+#include <sys/sysctl.h>
+int doclusterread = 1;
+struct ctldebug debug11 = { "doclusterread", &doclusterread };
+int doclusterwrite = 1;
+struct ctldebug debug12 = { "doclusterwrite", &doclusterwrite };
 
 /*
  * Vnode op for reading.
 
 /*
  * Vnode op for reading.
@@ -197,17 +209,16 @@ ffs_read(ap)
        struct buf *bp;
        daddr_t lbn, bn, rablock;
        off_t diff;
        struct buf *bp;
        daddr_t lbn, bn, rablock;
        off_t diff;
-       int rasize, error = 0;
+       int type, rasize, error = 0;
        long size, n, on;
 
        long size, n, on;
 
+       type = ip->i_mode & IFMT;
 #ifdef DIAGNOSTIC
 #ifdef DIAGNOSTIC
-       int type;
        if (uio->uio_rw != UIO_READ)
                panic("ffs_read mode");
        if (uio->uio_rw != UIO_READ)
                panic("ffs_read mode");
-       type = ip->i_mode & IFMT;
        if (type != IFDIR && type != IFREG && type != IFLNK)
                panic("ffs_read type");
        if (type != IFDIR && type != IFREG && type != IFLNK)
                panic("ffs_read type");
-       if (type == IFLNK && ip->i_size < vp->v_mount->mnt_maxsymlinklen)
+       if (type == IFLNK && (int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
                panic("read short symlink");
 #endif
        if (uio->uio_resid == 0)
                panic("read short symlink");
 #endif
        if (uio->uio_resid == 0)
@@ -219,7 +230,7 @@ ffs_read(ap)
        do {
                lbn = lblkno(fs, uio->uio_offset);
                on = blkoff(fs, uio->uio_offset);
        do {
                lbn = lblkno(fs, uio->uio_offset);
                on = blkoff(fs, uio->uio_offset);
-               n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
+               n = min((unsigned)(fs->fs_bsize - on), uio->uio_resid);
                diff = ip->i_size - uio->uio_offset;
                if (diff <= 0)
                        return (0);
                diff = ip->i_size - uio->uio_offset;
                if (diff <= 0)
                        return (0);
@@ -227,7 +238,10 @@ ffs_read(ap)
                        n = diff;
                size = blksize(fs, ip, lbn);
                rablock = lbn + 1;
                        n = diff;
                size = blksize(fs, ip, lbn);
                rablock = lbn + 1;
-               if (vp->v_lastr + 1 == lbn &&
+               if (doclusterread && lblktosize(fs, rablock) <= ip->i_size) {
+                       error = cluster_read(vp, ip->i_size, lbn, size,
+                           NOCRED, &bp);
+               } else if (vp->v_lastr + 1 == lbn &&
                    lblktosize(fs, rablock) < ip->i_size) {
                        rasize = blksize(fs, ip, rablock);
                        error = breadn(vp, lbn, size, &rablock,
                    lblktosize(fs, rablock) < ip->i_size) {
                        rasize = blksize(fs, ip, rablock);
                        error = breadn(vp, lbn, size, &rablock,
@@ -235,13 +249,14 @@ ffs_read(ap)
                } else
                        error = bread(vp, lbn, size, NOCRED, &bp);
                vp->v_lastr = lbn;
                } else
                        error = bread(vp, lbn, size, NOCRED, &bp);
                vp->v_lastr = lbn;
-               n = MIN(n, size - bp->b_resid);
+               n = min(n, size - bp->b_resid);
                if (error) {
                        brelse(bp);
                        return (error);
                }
                error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
                if (error) {
                        brelse(bp);
                        return (error);
                }
                error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
-               if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
+               if (type == IFREG &&
+                   (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size))
                        bp->b_flags |= B_AGE;
                brelse(bp);
        } while (error == 0 && uio->uio_resid > 0 && n != 0);
                        bp->b_flags |= B_AGE;
                brelse(bp);
        } while (error == 0 && uio->uio_resid > 0 && n != 0);
@@ -280,6 +295,8 @@ ffs_write(ap)
        case VREG:
                if (ioflag & IO_APPEND)
                        uio->uio_offset = ip->i_size;
        case VREG:
                if (ioflag & IO_APPEND)
                        uio->uio_offset = ip->i_size;
+               if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
+                       return (EPERM);
                /* fall through */
        case VLNK:
                break;
                /* fall through */
        case VLNK:
                break;
@@ -295,7 +312,8 @@ ffs_write(ap)
        if (uio->uio_resid == 0)
                return (0);
        fs = ip->i_fs;
        if (uio->uio_resid == 0)
                return (0);
        fs = ip->i_fs;
-       if (uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
+       if (uio->uio_offset < 0 ||
+           (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
                return (EFBIG);
        /*
         * Maybe this should be above the vnode op call, but so long as
                return (EFBIG);
        /*
         * Maybe this should be above the vnode op call, but so long as
@@ -315,7 +333,7 @@ ffs_write(ap)
        do {
                lbn = lblkno(fs, uio->uio_offset);
                on = blkoff(fs, uio->uio_offset);
        do {
                lbn = lblkno(fs, uio->uio_offset);
                on = blkoff(fs, uio->uio_offset);
-               n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
+               n = min((unsigned)(fs->fs_bsize - on), uio->uio_resid);
                if (n < fs->fs_bsize)
                        flags |= B_CLRBUF;
                else
                if (n < fs->fs_bsize)
                        flags |= B_CLRBUF;
                else
@@ -329,17 +347,21 @@ ffs_write(ap)
                }
                size = blksize(fs, ip, lbn);
                (void) vnode_pager_uncache(vp);
                }
                size = blksize(fs, ip, lbn);
                (void) vnode_pager_uncache(vp);
-               n = MIN(n, size - bp->b_resid);
+               n = min(n, size - bp->b_resid);
                error = uiomove(bp->b_un.b_addr + on, n, uio);
                if (ioflag & IO_SYNC)
                        (void) bwrite(bp);
                else if (n + on == fs->fs_bsize) {
                error = uiomove(bp->b_un.b_addr + on, n, uio);
                if (ioflag & IO_SYNC)
                        (void) bwrite(bp);
                else if (n + on == fs->fs_bsize) {
-                       bp->b_flags |= B_AGE;
-                       bawrite(bp);
+                       if (doclusterwrite) {
+                               cluster_write(bp, ip->i_size);
+                       } else {
+                               bp->b_flags |= B_AGE;
+                               bawrite(bp);
+                       }
                } else
                        bdwrite(bp);
                ip->i_flag |= IUPD|ICHG;
                } else
                        bdwrite(bp);
                ip->i_flag |= IUPD|ICHG;
-               if (ap->a_cred->cr_uid != 0)
+               if (ap->a_cred && ap->a_cred->cr_uid != 0)
                        ip->i_mode &= ~(ISUID|ISGID);
        } while (error == 0 && uio->uio_resid > 0 && n != 0);
        if (error && (ioflag & IO_UNIT)) {
                        ip->i_mode &= ~(ISUID|ISGID);
        } while (error == 0 && uio->uio_resid > 0 && n != 0);
        if (error && (ioflag & IO_UNIT)) {
@@ -380,8 +402,8 @@ ffs_fsync(ap)
         */
 loop:
        s = splbio();
         */
 loop:
        s = splbio();
-       for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
-               nbp = bp->b_blockf;
+       for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
+               nbp = bp->b_vnbufs.qe_next;
                if ((bp->b_flags & B_BUSY))
                        continue;
                if ((bp->b_flags & B_DELWRI) == 0)
                if ((bp->b_flags & B_BUSY))
                        continue;
                if ((bp->b_flags & B_DELWRI) == 0)
@@ -405,7 +427,7 @@ loop:
                        sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
                }
 #ifdef DIAGNOSTIC
                        sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
                }
 #ifdef DIAGNOSTIC
-               if (vp->v_dirtyblkhd) {
+               if (vp->v_dirtyblkhd.le_next) {
                        vprint("ffs_fsync: dirty", vp);
                        goto loop;
                }
                        vprint("ffs_fsync: dirty", vp);
                        goto loop;
                }
@@ -416,57 +438,3 @@ loop:
        return (VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT));
 }
 
        return (VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT));
 }
 
-/*
- * Last reference to an inode, write the inode out and if necessary,
- * truncate and deallocate the file.
- */
-int
-ffs_inactive(ap)
-       struct vop_inactive_args /* {
-               struct vnode *a_vp;
-       } */ *ap;
-{
-       register struct vnode *vp = ap->a_vp;
-       register struct inode *ip = VTOI(vp);
-       struct timeval tv;
-       int mode, error;
-       extern int prtactive;
-
-       if (prtactive && vp->v_usecount != 0)
-               vprint("ffs_inactive: pushing active", vp);
-
-       /* Get rid of inodes related to stale file handles. */
-       if (ip->i_mode == 0) {
-               if ((vp->v_flag & VXLOCK) == 0)
-                       vgone(vp);
-               return (0);
-       }
-
-       error = 0;
-       ILOCK(ip);
-       if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
-#ifdef QUOTA
-               if (!getinoquota(ip))
-                       (void)chkiq(ip, -1, NOCRED, 0);
-#endif
-               error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, NULL);
-               mode = ip->i_mode;
-               ip->i_mode = 0;
-               ip->i_rdev = 0;
-               ip->i_flag |= IUPD|ICHG;
-               VOP_VFREE(vp, ip->i_number, mode);
-       }
-       if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) {
-               tv = time;
-               VOP_UPDATE(vp, &tv, &tv, 0);
-       }
-       IUNLOCK(ip);
-       ip->i_flag = 0;
-       /*
-        * If we are done with the inode, reclaim it
-        * so that it can be reused immediately.
-        */
-       if (vp->v_usecount == 0 && ip->i_mode == 0)
-               vgone(vp);
-       return (error);
-}