X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/8ad54d9e30ae43754dfc2899691b0bbd31b3753e..0ae79846a8c73fddaca3139f3e1aaf5b0590ac2b:/usr/src/sys/ufs/ffs/ffs_vnops.c diff --git a/usr/src/sys/ufs/ffs/ffs_vnops.c b/usr/src/sys/ufs/ffs/ffs_vnops.c index 1430af9f31..bb4120c694 100644 --- a/usr/src/sys/ufs/ffs/ffs_vnops.c +++ b/usr/src/sys/ufs/ffs/ffs_vnops.c @@ -2,488 +2,241 @@ * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * %sccs.include.redist.c% * - * @(#)ffs_vnops.c 7.23 (Berkeley) %G% + * @(#)ffs_vnops.c 7.93 (Berkeley) %G% */ -#include "param.h" -#include "systm.h" -#include "user.h" -#include "kernel.h" -#include "file.h" -#include "stat.h" -#include "buf.h" -#include "proc.h" -#include "uio.h" -#include "socket.h" -#include "socketvar.h" -#include "conf.h" -#include "mount.h" -#include "vnode.h" -#include "../ufs/inode.h" -#include "../ufs/fs.h" -#include "../ufs/quota.h" - -/* - * Global vfs data structures for ufs - */ - -int ufs_lookup(), - ufs_create(), - ufs_mknod(), - ufs_open(), - ufs_close(), - ufs_access(), - ufs_getattr(), - ufs_setattr(), - ufs_read(), - ufs_write(), - ufs_ioctl(), - ufs_select(), - ufs_mmap(), - ufs_fsync(), - ufs_seek(), - ufs_remove(), - ufs_link(), - ufs_rename(), - ufs_mkdir(), - ufs_rmdir(), - ufs_symlink(), - ufs_readdir(), - ufs_readlink(), - ufs_abortop(), - ufs_inactive(), - ufs_reclaim(), - ufs_lock(), - ufs_unlock(), - ufs_bmap(), - ufs_strategy(); - -struct vnodeops ufs_vnodeops = { - ufs_lookup, - ufs_create, - ufs_mknod, - ufs_open, - ufs_close, - ufs_access, - ufs_getattr, - ufs_setattr, - ufs_read, - ufs_write, - ufs_ioctl, - ufs_select, - ufs_mmap, - ufs_fsync, - ufs_seek, - ufs_remove, - ufs_link, - ufs_rename, - ufs_mkdir, - ufs_rmdir, - ufs_symlink, - ufs_readdir, - ufs_readlink, - ufs_abortop, - ufs_inactive, - ufs_reclaim, - ufs_lock, - ufs_unlock, - ufs_bmap, - ufs_strategy, +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* Global vfs data structures for ufs. */ +int (**ffs_vnodeop_p)(); +struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { + { &vop_default_desc, vn_default_error }, + { &vop_lookup_desc, ufs_lookup }, /* lookup */ + { &vop_create_desc, ufs_create }, /* create */ + { &vop_mknod_desc, ufs_mknod }, /* mknod */ + { &vop_open_desc, ufs_open }, /* open */ + { &vop_close_desc, ufs_close }, /* close */ + { &vop_access_desc, ufs_access }, /* access */ + { &vop_getattr_desc, ufs_getattr }, /* getattr */ + { &vop_setattr_desc, ufs_setattr }, /* setattr */ + { &vop_read_desc, ffs_read }, /* read */ + { &vop_write_desc, ffs_write }, /* write */ + { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ + { &vop_select_desc, ufs_select }, /* select */ + { &vop_mmap_desc, ufs_mmap }, /* mmap */ + { &vop_fsync_desc, ffs_fsync }, /* fsync */ + { &vop_seek_desc, ufs_seek }, /* seek */ + { &vop_remove_desc, ufs_remove }, /* remove */ + { &vop_link_desc, ufs_link }, /* link */ + { &vop_rename_desc, ufs_rename }, /* rename */ + { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ + { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ + { &vop_symlink_desc, ufs_symlink }, /* symlink */ + { &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_reclaim_desc, ufs_reclaim }, /* reclaim */ + { &vop_lock_desc, ufs_lock }, /* lock */ + { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &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_advlock_desc, ufs_advlock }, /* advlock */ + { &vop_blkatoff_desc, ffs_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, ffs_valloc }, /* valloc */ + { &vop_vfree_desc, ffs_vfree }, /* vfree */ + { &vop_truncate_desc, ffs_truncate }, /* truncate */ + { &vop_update_desc, ffs_update }, /* update */ + { &vop_bwrite_desc, vn_bwrite }, + { (struct vnodeop_desc*)NULL, (int(*)())NULL } }; - -int spec_lookup(), - spec_open(), - spec_read(), - spec_write(), - spec_strategy(), - spec_ioctl(), - spec_select(), - spec_close(), - spec_badop(), - spec_nullop(); - -struct vnodeops spec_inodeops = { - spec_lookup, /* lookup */ - spec_badop, /* create */ - spec_badop, /* mknod */ - spec_open, /* open */ - spec_close, /* close */ - ufs_access, /* access */ - ufs_getattr, /* getattr */ - ufs_setattr, /* setattr */ - spec_read, /* read */ - spec_write, /* write */ - spec_ioctl, /* ioctl */ - spec_select, /* select */ - spec_badop, /* mmap */ - spec_nullop, /* fsync */ - spec_badop, /* seek */ - spec_badop, /* remove */ - spec_badop, /* link */ - spec_badop, /* rename */ - spec_badop, /* mkdir */ - spec_badop, /* rmdir */ - spec_badop, /* symlink */ - spec_badop, /* readdir */ - spec_badop, /* readlink */ - spec_badop, /* abortop */ - ufs_inactive, /* inactive */ - ufs_reclaim, /* reclaim */ - ufs_lock, /* lock */ - ufs_unlock, /* unlock */ - spec_badop, /* bmap */ - spec_strategy, /* strategy */ -}; - -enum vtype iftovt_tab[8] = { - VNON, VCHR, VDIR, VBLK, VREG, VLNK, VSOCK, VBAD, +struct vnodeopv_desc ffs_vnodeop_opv_desc = + { &ffs_vnodeop_p, ffs_vnodeop_entries }; + +int (**ffs_specop_p)(); +struct vnodeopv_entry_desc ffs_specop_entries[] = { + { &vop_default_desc, vn_default_error }, + { &vop_lookup_desc, spec_lookup }, /* lookup */ + { &vop_create_desc, spec_create }, /* create */ + { &vop_mknod_desc, spec_mknod }, /* mknod */ + { &vop_open_desc, spec_open }, /* open */ + { &vop_close_desc, ufsspec_close }, /* close */ + { &vop_access_desc, ufs_access }, /* access */ + { &vop_getattr_desc, ufs_getattr }, /* getattr */ + { &vop_setattr_desc, ufs_setattr }, /* setattr */ + { &vop_read_desc, ufsspec_read }, /* read */ + { &vop_write_desc, ufsspec_write }, /* write */ + { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ + { &vop_select_desc, spec_select }, /* select */ + { &vop_mmap_desc, spec_mmap }, /* mmap */ + { &vop_fsync_desc, ffs_fsync }, /* fsync */ + { &vop_seek_desc, spec_seek }, /* seek */ + { &vop_remove_desc, spec_remove }, /* remove */ + { &vop_link_desc, spec_link }, /* link */ + { &vop_rename_desc, spec_rename }, /* rename */ + { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ + { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ + { &vop_symlink_desc, spec_symlink }, /* symlink */ + { &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_reclaim_desc, ufs_reclaim }, /* reclaim */ + { &vop_lock_desc, ufs_lock }, /* lock */ + { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_bmap_desc, spec_bmap }, /* bmap */ + { &vop_strategy_desc, spec_strategy }, /* strategy */ + { &vop_print_desc, ufs_print }, /* print */ + { &vop_islocked_desc, ufs_islocked }, /* islocked */ + { &vop_advlock_desc, spec_advlock }, /* advlock */ + { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, spec_valloc }, /* valloc */ + { &vop_vfree_desc, ffs_vfree }, /* vfree */ + { &vop_truncate_desc, spec_truncate }, /* truncate */ + { &vop_update_desc, ffs_update }, /* update */ + { &vop_bwrite_desc, vn_bwrite }, + { (struct vnodeop_desc*)NULL, (int(*)())NULL } }; -int vttoif_tab[8] = { - 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFMT, +struct vnodeopv_desc ffs_specop_opv_desc = + { &ffs_specop_p, ffs_specop_entries }; + +#ifdef FIFO +int (**ffs_fifoop_p)(); +struct vnodeopv_entry_desc ffs_fifoop_entries[] = { + { &vop_default_desc, vn_default_error }, + { &vop_lookup_desc, fifo_lookup }, /* lookup */ + { &vop_create_desc, fifo_create }, /* create */ + { &vop_mknod_desc, fifo_mknod }, /* mknod */ + { &vop_open_desc, fifo_open }, /* open */ + { &vop_close_desc, ufsfifo_close }, /* close */ + { &vop_access_desc, ufs_access }, /* access */ + { &vop_getattr_desc, ufs_getattr }, /* getattr */ + { &vop_setattr_desc, ufs_setattr }, /* setattr */ + { &vop_read_desc, ufsfifo_read }, /* read */ + { &vop_write_desc, ufsfifo_write }, /* write */ + { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ + { &vop_select_desc, fifo_select }, /* select */ + { &vop_mmap_desc, fifo_mmap }, /* mmap */ + { &vop_fsync_desc, ffs_fsync }, /* fsync */ + { &vop_seek_desc, fifo_seek }, /* seek */ + { &vop_remove_desc, fifo_remove }, /* remove */ + { &vop_link_desc, fifo_link }, /* link */ + { &vop_rename_desc, fifo_rename }, /* rename */ + { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ + { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ + { &vop_symlink_desc, fifo_symlink }, /* symlink */ + { &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_reclaim_desc, ufs_reclaim }, /* reclaim */ + { &vop_lock_desc, ufs_lock }, /* lock */ + { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_bmap_desc, fifo_bmap }, /* bmap */ + { &vop_strategy_desc, fifo_strategy }, /* strategy */ + { &vop_print_desc, ufs_print }, /* print */ + { &vop_islocked_desc, ufs_islocked }, /* islocked */ + { &vop_advlock_desc, fifo_advlock }, /* advlock */ + { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, fifo_valloc }, /* valloc */ + { &vop_vfree_desc, ffs_vfree }, /* vfree */ + { &vop_truncate_desc, fifo_truncate }, /* truncate */ + { &vop_update_desc, ffs_update }, /* update */ + { &vop_bwrite_desc, vn_bwrite }, + { (struct vnodeop_desc*)NULL, (int(*)())NULL } }; +struct vnodeopv_desc ffs_fifoop_opv_desc = + { &ffs_fifoop_p, ffs_fifoop_entries }; +#endif /* FIFO */ -/* - * Create a regular file - */ -ufs_create(ndp, vap) - struct nameidata *ndp; - struct vattr *vap; -{ - struct inode *ip; - int error; - - if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) - return (error); - ndp->ni_vp = ITOV(ip); - return (0); -} - -/* - * Mknod vnode call - */ -/* ARGSUSED */ -ufs_mknod(ndp, vap, cred) - struct nameidata *ndp; - struct ucred *cred; - struct vattr *vap; -{ - register struct vnode *vp; - struct inode *ip; - int error; - - if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) - return (error); - vp = ITOV(ip); - if (vap->va_rdev) { - /* - * Want to be able to use this to make badblock - * inodes, so don't truncate the dev number. - */ - ip->i_rdev = vap->va_rdev; - ip->i_flag |= IACC|IUPD|ICHG; - } - /* - * Remove inode so that it will be reloaded by iget and - * checked to see if it is an alias of an existing entry - * in the inode cache. - */ - iput(ip); - vp->v_type = VNON; - vgone(vp); - return (0); -} - -/* - * Open called. - * - * Nothing to do. - */ -/* ARGSUSED */ -ufs_open(vp, mode, cred) - struct vnode *vp; - int mode; - struct ucred *cred; -{ - - return (0); -} - -/* - * Close called - * - * Update the times on the inode. - */ -/* ARGSUSED */ -ufs_close(vp, fflag, cred) - struct vnode *vp; - int fflag; - struct ucred *cred; -{ - register struct inode *ip = VTOI(vp); - - if (vp->v_count > 1 && !(ip->i_flag & ILOCKED)) - ITIMES(ip, &time, &time); - return (0); -} - -ufs_access(vp, mode, cred) - struct vnode *vp; - int mode; - struct ucred *cred; -{ - - return (iaccess(VTOI(vp), mode, cred)); -} - -/* ARGSUSED */ -ufs_getattr(vp, vap, cred) - struct vnode *vp; - register struct vattr *vap; - struct ucred *cred; -{ - register struct inode *ip = VTOI(vp); - - ITIMES(ip, &time, &time); - /* - * Copy from inode table - */ - vap->va_fsid = ip->i_dev; - vap->va_fileid = ip->i_number; - vap->va_mode = ip->i_mode & ~IFMT; - vap->va_nlink = ip->i_nlink; - vap->va_uid = ip->i_uid; - vap->va_gid = ip->i_gid; - vap->va_rdev = (dev_t)ip->i_rdev; - vap->va_size = ip->i_din.di_qsize.val[0]; - vap->va_size1 = ip->i_din.di_qsize.val[1]; - vap->va_atime.tv_sec = ip->i_atime; - vap->va_atime.tv_usec = 0; - vap->va_mtime.tv_sec = ip->i_mtime; - vap->va_mtime.tv_usec = 0; - vap->va_ctime.tv_sec = ip->i_ctime; - vap->va_ctime.tv_usec = 0; - vap->va_flags = ip->i_flags; - vap->va_gen = ip->i_gen; - /* this doesn't belong here */ - if (vp->v_type == VBLK) - vap->va_blocksize = BLKDEV_IOSIZE; - else if (vp->v_type == VCHR) - vap->va_blocksize = MAXBSIZE; - else - vap->va_blocksize = ip->i_fs->fs_bsize; - vap->va_bytes = dbtob(ip->i_blocks); - vap->va_bytes1 = -1; - vap->va_type = vp->v_type; - return (0); -} - -/* - * Set attribute vnode op. called from several syscalls - */ -ufs_setattr(vp, vap, cred) - register struct vnode *vp; - register struct vattr *vap; - register struct ucred *cred; -{ - register struct inode *ip = VTOI(vp); - int error = 0; - - /* - * Check for unsetable attributes. - */ - if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || - (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || - (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || - ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { - return (EINVAL); - } - /* - * Go through the fields and update iff not VNOVAL. - */ - if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) - if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) - return (error); - if (vap->va_size != VNOVAL) { - if (vp->v_type == VDIR) - return (EISDIR); - if (error = itrunc(ip, vap->va_size)) - return (error); - } - if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { - if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &u.u_acflag))) - return (error); - if (vap->va_atime.tv_sec != VNOVAL) - ip->i_flag |= IACC; - if (vap->va_mtime.tv_sec != VNOVAL) - ip->i_flag |= IUPD; - ip->i_flag |= ICHG; - if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) - return (error); - } - if (vap->va_mode != (u_short)VNOVAL) - error = chmod1(vp, (int)vap->va_mode, cred); - if (vap->va_flags != VNOVAL) { - if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &u.u_acflag))) - return (error); - if (cred->cr_uid == 0) { - ip->i_flags = vap->va_flags; - } else { - ip->i_flags &= 0xffff0000; - ip->i_flags |= (vap->va_flags & 0xffff); - } - ip->i_flag |= ICHG; - } - return (error); -} - -/* - * Change the mode on a file. - * Inode must be locked before calling. - */ -chmod1(vp, mode, cred) - register struct vnode *vp; - register int mode; - struct ucred *cred; -{ - register struct inode *ip = VTOI(vp); - int error; - - if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &u.u_acflag))) - return (error); - ip->i_mode &= ~07777; - if (cred->cr_uid) { - if (vp->v_type != VDIR) - mode &= ~ISVTX; - if (!groupmember(ip->i_gid, cred)) - mode &= ~ISGID; - } - ip->i_mode |= mode & 07777; - ip->i_flag |= ICHG; - if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) - xrele(vp); - return (0); -} - -/* - * Perform chown operation on inode ip; - * inode must be locked prior to call. - */ -chown1(vp, uid, gid, cred) - register struct vnode *vp; - uid_t uid; - gid_t gid; - struct ucred *cred; -{ - register struct inode *ip = VTOI(vp); -#ifdef QUOTA - register long change; -#endif - int error; - - if (uid == (u_short)VNOVAL) - uid = ip->i_uid; - if (gid == (u_short)VNOVAL) - gid = ip->i_gid; - /* - * If we don't own the file, are trying to change the owner - * of the file, or are not a member of the target group, - * the caller must be superuser or the call fails. - */ - if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || - !groupmember((gid_t)gid, cred)) && - (error = suser(cred, &u.u_acflag))) - return (error); -#ifdef QUOTA - if (ip->i_uid == uid) /* this just speeds things a little */ - change = 0; - else - change = ip->i_blocks; - (void) chkdq(ip, -change, 1); - (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); - dqrele(ip->i_dquot); -#endif - if (ip->i_uid != uid && cred->cr_uid != 0) - ip->i_mode &= ~ISUID; - if (ip->i_gid != gid && cred->cr_uid != 0) - ip->i_mode &= ~ISGID; - ip->i_uid = uid; - ip->i_gid = gid; - ip->i_flag |= ICHG; -#ifdef QUOTA - ip->i_dquot = inoquota(ip); - (void) chkdq(ip, change, 1); - (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1); - return (u.u_error); /* should == 0 ALWAYS !! */ -#else - return (0); -#endif -} /* * Vnode op for reading. */ /* ARGSUSED */ -ufs_read(vp, uio, ioflag, cred) - struct vnode *vp; - register struct uio *uio; - int ioflag; - struct ucred *cred; +ffs_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; { + register struct vnode *vp = ap->a_vp; register struct inode *ip = VTOI(vp); + register struct uio *uio = ap->a_uio; register struct fs *fs; struct buf *bp; daddr_t lbn, bn, rablock; - int size, rasize, diff, error = 0; - long n, on, type; + off_t diff; + int rasize, error = 0; + long size, n, on; +#ifdef DIAGNOSTIC + int type; if (uio->uio_rw != UIO_READ) - panic("ufs_read mode"); + panic("ffs_read mode"); type = ip->i_mode & IFMT; if (type != IFDIR && type != IFREG && type != IFLNK) - panic("ufs_read type"); + panic("ffs_read type"); + if (type == IFLNK && (int)ip->i_size < vp->v_mount->mnt_maxsymlinklen) + panic("read short symlink"); +#endif if (uio->uio_resid == 0) return (0); - if (uio->uio_offset < 0) - return (EINVAL); - ip->i_flag |= IACC; fs = ip->i_fs; + if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize) + return (EFBIG); + ip->i_flag |= IACC; 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); if (diff < n) n = diff; - if (error = bmap(ip, lbn, &bn, &rablock, &rasize)) - return (error); size = blksize(fs, ip, lbn); - if ((long)bn < 0) { - bp = geteblk(size); - clrbuf(bp); - } else if (ip->i_lastr + 1 == lbn) - error = breada(ip->i_devvp, bn, size, rablock, rasize, - NOCRED, &bp); - else - error = bread(ip->i_devvp, bn, size, NOCRED, &bp); - ip->i_lastr = lbn; - n = MIN(n, size - bp->b_resid); + rablock = lbn + 1; + if (vp->v_lastr + 1 == lbn && + lblktosize(fs, rablock) < ip->i_size) { + rasize = blksize(fs, ip, rablock); + error = breadn(vp, lbn, size, &rablock, + &rasize, 1, NOCRED, &bp); + } else + error = bread(vp, lbn, size, NOCRED, &bp); + vp->v_lastr = lbn; + n = min(n, size - bp->b_resid); if (error) { brelse(bp); return (error); @@ -499,22 +252,31 @@ ufs_read(vp, uio, ioflag, cred) /* * Vnode op for writing. */ -ufs_write(vp, uio, ioflag, cred) - register struct vnode *vp; - struct uio *uio; - int ioflag; - struct ucred *cred; +ffs_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; { + register struct vnode *vp = ap->a_vp; + register struct uio *uio = ap->a_uio; register struct inode *ip = VTOI(vp); register struct fs *fs; + struct proc *p = uio->uio_procp; + int ioflag = ap->a_ioflag; + struct timeval tv; struct buf *bp; daddr_t lbn, bn; - u_long osize; - int i, n, on, flags; - int count, size, resid, error = 0; + off_t osize; + int n, on, flags; + int size, resid, error = 0; +#ifdef DIAGNOSTIC if (uio->uio_rw != UIO_WRITE) - panic("ufs_write mode"); + panic("ffs_write mode"); +#endif switch (vp->v_type) { case VREG: if (ioflag & IO_APPEND) @@ -525,54 +287,51 @@ ufs_write(vp, uio, ioflag, cred) case VDIR: if ((ioflag & IO_SYNC) == 0) - panic("ufs_write nonsync dir write"); + panic("ffs_write nonsync dir write"); break; default: - panic("ufs_write type"); + panic("ffs_write type"); } - if (uio->uio_offset < 0) - return (EINVAL); if (uio->uio_resid == 0) return (0); + fs = ip->i_fs; + 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 * file servers have no limits, i don't think it matters */ - if (vp->v_type == VREG && + if (vp->v_type == VREG && p && uio->uio_offset + uio->uio_resid > - u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { - psignal(u.u_procp, SIGXFSZ); + p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + psignal(p, SIGXFSZ); return (EFBIG); } resid = uio->uio_resid; osize = ip->i_size; - fs = ip->i_fs; + flags = 0; + if (ioflag & IO_SYNC) + flags = B_SYNC; 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; + flags |= B_CLRBUF; else - flags = 0; - if (error = balloc(ip, lbn, (int)(on + n), &bn, flags)) + flags &= ~B_CLRBUF; + if (error = ffs_balloc(ip, lbn, on + n, ap->a_cred, &bp, flags)) break; - if (uio->uio_offset + n > ip->i_size) + bn = bp->b_blkno; + if (uio->uio_offset + n > ip->i_size) { ip->i_size = uio->uio_offset + n; - size = blksize(fs, ip, lbn); - count = howmany(size, CLBYTES); - for (i = 0; i < count; i++) - munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); - if (n == fs->fs_bsize) - bp = getblk(ip->i_devvp, bn, size); - else - error = bread(ip->i_devvp, bn, size, NOCRED, &bp); - n = MIN(n, size - bp->b_resid); - if (error) { - brelse(bp); - break; + vnode_pager_setsize(vp, (u_long)ip->i_size); } + size = blksize(fs, ip, lbn); + (void) vnode_pager_uncache(vp); + n = min(n, size - bp->b_resid); error = uiomove(bp->b_un.b_addr + on, n, uio); if (ioflag & IO_SYNC) (void) bwrite(bp); @@ -582,779 +341,134 @@ ufs_write(vp, uio, ioflag, cred) } else bdwrite(bp); ip->i_flag |= IUPD|ICHG; - if (cred->cr_uid != 0) + if (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)) { - (void) itrunc(ip, osize); + (void)VOP_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred, + uio->uio_procp); uio->uio_offset -= resid - uio->uio_resid; uio->uio_resid = resid; } + if (!error && (ioflag & IO_SYNC)) { + tv = time; + error = VOP_UPDATE(vp, &tv, &tv, 1); + } return (error); } -/* ARGSUSED */ -ufs_ioctl(vp, com, data, fflag, cred) - struct vnode *vp; - int com; - caddr_t data; - int fflag; - struct ucred *cred; -{ - - return (ENOTTY); -} - -/* ARGSUSED */ -ufs_select(vp, which, cred) - struct vnode *vp; - int which; - struct ucred *cred; -{ - - return (1); /* XXX */ -} - -/* - * Mmap a file - * - * NB Currently unsupported. - */ -/* ARGSUSED */ -ufs_mmap(vp, fflags, cred) - struct vnode *vp; - int fflags; - struct ucred *cred; -{ - - return (EINVAL); -} - /* * Synch an open file. */ /* ARGSUSED */ -ufs_fsync(vp, fflags, cred, waitfor) - struct vnode *vp; - int fflags; - struct ucred *cred; - int waitfor; +int +ffs_fsync(ap) + struct vop_fsync_args /* { + struct vnode *a_vp; + struct ucred *a_cred; + int a_waitfor; + struct proc *a_p; + } */ *ap; { + register struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); - - if (fflags&FWRITE) - ip->i_flag |= ICHG; - return (syncip(ip, waitfor)); -} - -/* - * Seek on a file - * - * Nothing to do, so just return. - */ -/* ARGSUSED */ -ufs_seek(vp, oldoff, newoff, cred) - struct vnode *vp; - off_t oldoff, newoff; - struct ucred *cred; -{ - - return (0); -} - -/* - * ufs remove - * Hard to avoid races here, especially - * in unlinking directories. - */ -ufs_remove(ndp) - struct nameidata *ndp; -{ - register struct inode *ip, *dp; - int error; - - ip = VTOI(ndp->ni_vp); - dp = VTOI(ndp->ni_dvp); - error = dirremove(ndp); - if (!error) { - ip->i_nlink--; - ip->i_flag |= ICHG; - } - if (dp == ip) - vrele(ITOV(ip)); - else - iput(ip); - iput(dp); - return (error); -} - -/* - * link vnode call - */ -ufs_link(vp, ndp) - register struct vnode *vp; - register struct nameidata *ndp; -{ - register struct inode *ip = VTOI(vp); - int error; - - if (ndp->ni_dvp != vp) - ILOCK(ip); - if (ip->i_nlink == LINK_MAX - 1) { - error = EMLINK; - goto out; - } - ip->i_nlink++; - ip->i_flag |= ICHG; - error = iupdat(ip, &time, &time, 1); - if (!error) - error = direnter(ip, ndp); -out: - if (ndp->ni_dvp != vp) - IUNLOCK(ip); - if (error) { - ip->i_nlink--; - ip->i_flag |= ICHG; - } - return (error); -} - -/* - * Rename system call. - * rename("foo", "bar"); - * is essentially - * unlink("bar"); - * link("foo", "bar"); - * unlink("foo"); - * but ``atomically''. Can't do full commit without saving state in the - * inode on disk which isn't feasible at this time. Best we can do is - * always guarantee the target exists. - * - * Basic algorithm is: - * - * 1) Bump link count on source while we're linking it to the - * target. This also ensure the inode won't be deleted out - * from underneath us while we work (it may be truncated by - * a concurrent `trunc' or `open' for creation). - * 2) Link source to destination. If destination already exists, - * delete it first. - * 3) Unlink source reference to inode if still around. If a - * directory was moved and the parent of the destination - * is different from the source, patch the ".." entry in the - * directory. - */ -ufs_rename(fndp, tndp) - register struct nameidata *fndp, *tndp; -{ - register struct inode *ip, *xp, *dp; - struct dirtemplate dirbuf; - int doingdirectory = 0, oldparent = 0, newparent = 0; - int error = 0; - - dp = VTOI(fndp->ni_dvp); - ip = VTOI(fndp->ni_vp); - ILOCK(ip); - if ((ip->i_mode&IFMT) == IFDIR) { - register struct direct *d = &fndp->ni_dent; - - /* - * Avoid ".", "..", and aliases of "." for obvious reasons. - */ - if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || - fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { - IUNLOCK(ip); - ufs_abortop(fndp); - ufs_abortop(tndp); - return (EINVAL); - } - ip->i_flag |= IRENAME; - oldparent = dp->i_number; - doingdirectory++; - } - vrele(fndp->ni_dvp); - - /* - * 1) Bump link count while we're moving stuff - * around. If we crash somewhere before - * completing our work, the link count - * may be wrong, but correctable. - */ - ip->i_nlink++; - ip->i_flag |= ICHG; - error = iupdat(ip, &time, &time, 1); - IUNLOCK(ip); + register struct buf *bp; + struct timeval tv; + struct buf *nbp; + int s; /* - * When the target exists, both the directory - * and target vnodes are returned locked. + * Flush all dirty buffers associated with a vnode. */ - dp = VTOI(tndp->ni_dvp); - xp = NULL; - if (tndp->ni_vp) - xp = VTOI(tndp->ni_vp); - /* - * If ".." must be changed (ie the directory gets a new - * parent) then the source directory must not be in the - * directory heirarchy above the target, as this would - * orphan everything below the source directory. Also - * the user must have write permission in the source so - * as to be able to change "..". We must repeat the call - * to namei, as the parent directory is unlocked by the - * call to checkpath(). - */ - if (oldparent != dp->i_number) - newparent = dp->i_number; - if (doingdirectory && newparent) { - if (error = iaccess(ip, IWRITE, tndp->ni_cred)) - goto bad; - tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; - do { - dp = VTOI(tndp->ni_dvp); - if (xp != NULL) - iput(xp); - if (error = checkpath(ip, dp, tndp->ni_cred)) - goto out; - if (error = namei(tndp)) - goto out; - xp = NULL; - if (tndp->ni_vp) - xp = VTOI(tndp->ni_vp); - } while (dp != VTOI(tndp->ni_dvp)); - } - /* - * 2) If target doesn't exist, link the target - * to the source and unlink the source. - * Otherwise, rewrite the target directory - * entry to reference the source inode and - * expunge the original entry's existence. - */ - if (xp == NULL) { - if (dp->i_dev != ip->i_dev) - panic("rename: EXDEV"); - /* - * Account for ".." in new directory. - * When source and destination have the same - * parent we don't fool with the link count. - */ - if (doingdirectory && newparent) { - dp->i_nlink++; - dp->i_flag |= ICHG; - error = iupdat(dp, &time, &time, 1); - } - if (error = direnter(ip, tndp)) - goto out; - } else { - if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) - panic("rename: EXDEV"); - /* - * Short circuit rename(foo, foo). - */ - if (xp->i_number == ip->i_number) - panic("rename: same file"); - /* - * If the parent directory is "sticky", then the user must - * own the parent directory, or the destination of the rename, - * otherwise the destination may not be changed (except by - * root). This implements append-only directories. - */ - if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && - tndp->ni_cred->cr_uid != dp->i_uid && - xp->i_uid != tndp->ni_cred->cr_uid) { - error = EPERM; - goto bad; - } - /* - * Target must be empty if a directory - * and have no links to it. - * Also, insure source and target are - * compatible (both directories, or both - * not directories). - */ - if ((xp->i_mode&IFMT) == IFDIR) { - if (!dirempty(xp, dp->i_number, tndp->ni_cred) || - xp->i_nlink > 2) { - error = ENOTEMPTY; - goto bad; - } - if (!doingdirectory) { - error = ENOTDIR; - goto bad; - } - cache_purge(ITOV(dp)); - } else if (doingdirectory) { - error = EISDIR; - goto bad; - } - if (error = dirrewrite(dp, ip, tndp)) - goto bad; - vput(ITOV(dp)); +loop: + s = splbio(); + for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { + nbp = bp->b_blockf; + if ((bp->b_flags & B_BUSY)) + continue; + if ((bp->b_flags & B_DELWRI) == 0) + panic("ffs_fsync: not dirty"); + bremfree(bp); + bp->b_flags |= B_BUSY; + splx(s); /* - * Adjust the link count of the target to - * reflect the dirrewrite above. If this is - * a directory it is empty and there are - * no links to it, so we can squash the inode and - * any space associated with it. We disallowed - * renaming over top of a directory with links to - * it above, as the remaining link would point to - * a directory without "." or ".." entries. + * Wait for I/O associated with indirect blocks to complete, + * since there is no way to quickly wait for them below. */ - xp->i_nlink--; - if (doingdirectory) { - if (--xp->i_nlink != 0) - panic("rename: linked directory"); - error = itrunc(xp, (u_long)0); - } - xp->i_flag |= ICHG; - iput(xp); - xp = NULL; - } - - /* - * 3) Unlink the source. - */ - fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; - (void)namei(fndp); - if (fndp->ni_vp != NULL) { - xp = VTOI(fndp->ni_vp); - dp = VTOI(fndp->ni_dvp); - } else { - if (fndp->ni_dvp != NULL) - vput(fndp->ni_dvp); - xp = NULL; - dp = NULL; + if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) + (void) bawrite(bp); + else + (void) bwrite(bp); + goto loop; } - /* - * Ensure that the directory entry still exists and has not - * changed while the new name has been entered. If the source is - * a file then the entry may have been unlinked or renamed. In - * either case there is no further work to be done. If the source - * is a directory then it cannot have been rmdir'ed; its link - * count of three would cause a rmdir to fail with ENOTEMPTY. - * The IRENAME flag ensures that it cannot be moved by another - * rename. - */ - if (xp != ip) { - if (doingdirectory) - panic("rename: lost dir entry"); - } else { - /* - * If the source is a directory with a - * new parent, the link count of the old - * parent directory must be decremented - * and ".." set to point to the new parent. - */ - if (doingdirectory && newparent) { - dp->i_nlink--; - dp->i_flag |= ICHG; - error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, - sizeof (struct dirtemplate), (off_t)0, - UIO_SYSSPACE, IO_NODELOCKED, - tndp->ni_cred, (int *)0); - if (error == 0) { - if (dirbuf.dotdot_namlen != 2 || - dirbuf.dotdot_name[0] != '.' || - dirbuf.dotdot_name[1] != '.') { - dirbad(xp, 12, "rename: mangled dir"); - } else { - dirbuf.dotdot_ino = newparent; - (void) vn_rdwr(UIO_WRITE, ITOV(xp), - (caddr_t)&dirbuf, - sizeof (struct dirtemplate), - (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED|IO_SYNC, - tndp->ni_cred, (int *)0); - cache_purge(ITOV(dp)); - } - } + if (ap->a_waitfor == MNT_WAIT) { + while (vp->v_numoutput) { + vp->v_flag |= VBWAIT; + sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); } - error = dirremove(fndp); - if (!error) { - xp->i_nlink--; - xp->i_flag |= ICHG; +#ifdef DIAGNOSTIC + if (vp->v_dirtyblkhd) { + vprint("ffs_fsync: dirty", vp); + goto loop; } - xp->i_flag &= ~IRENAME; - } - if (dp) - vput(ITOV(dp)); - if (xp) - vput(ITOV(xp)); - vrele(ITOV(ip)); - return (error); - -bad: - if (xp) - vput(ITOV(xp)); - vput(ITOV(dp)); -out: - ip->i_nlink--; - ip->i_flag |= ICHG; - vrele(ITOV(ip)); - return (error); -} - -/* - * A virgin directory (no blushing please). - */ -struct dirtemplate mastertemplate = { - 0, 12, 1, ".", - 0, DIRBLKSIZ - 12, 2, ".." -}; - -/* - * Mkdir system call - */ -ufs_mkdir(ndp, vap) - struct nameidata *ndp; - struct vattr *vap; -{ - register struct inode *ip, *dp; - struct inode *tip; - struct vnode *dvp; - struct dirtemplate dirtemplate; - int error; - int dmode; - - dvp = ndp->ni_dvp; - dp = VTOI(dvp); - dmode = vap->va_mode&0777; - dmode |= IFDIR; - /* - * Must simulate part of maknode here - * in order to acquire the inode, but - * not have it entered in the parent - * directory. The entry is made later - * after writing "." and ".." entries out. - */ - error = ialloc(dp, dirpref(dp->i_fs), dmode, &tip); - if (error) { - iput(dp); - return (error); - } - ip = tip; -#ifdef QUOTA - if (ip->i_dquot != NODQUOT) - panic("mkdir: dquot"); -#endif - ip->i_flag |= IACC|IUPD|ICHG; - ip->i_mode = dmode; - ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ - ip->i_nlink = 2; - ip->i_uid = ndp->ni_cred->cr_uid; - ip->i_gid = dp->i_gid; -#ifdef QUOTA - ip->i_dquot = inoquota(ip); #endif - error = iupdat(ip, &time, &time, 1); - - /* - * Bump link count in parent directory - * to reflect work done below. Should - * be done before reference is created - * so reparation is possible if we crash. - */ - dp->i_nlink++; - dp->i_flag |= ICHG; - error = iupdat(dp, &time, &time, 1); - - /* - * Initialize directory with "." - * and ".." from static template. - */ - dirtemplate = mastertemplate; - dirtemplate.dot_ino = ip->i_number; - dirtemplate.dotdot_ino = dp->i_number; - error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, - sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); - if (error) { - dp->i_nlink--; - dp->i_flag |= ICHG; - goto bad; - } - if (DIRBLKSIZ > dp->i_fs->fs_fsize) - panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ - else - ip->i_size = DIRBLKSIZ; - /* - * Directory all set up, now - * install the entry for it in - * the parent directory. - */ - error = direnter(ip, ndp); - dp = NULL; - if (error) { - ndp->ni_nameiop = LOOKUP | NOCACHE; - error = namei(ndp); - if (!error) { - dp = VTOI(ndp->ni_vp); - dp->i_nlink--; - dp->i_flag |= ICHG; - } } -bad: - /* - * No need to do an explicit itrunc here, - * vrele will do this for us because we set - * the link count to 0. - */ - if (error) { - ip->i_nlink = 0; - ip->i_flag |= ICHG; - iput(ip); - } else - ndp->ni_vp = ITOV(ip); - if (dp) - iput(dp); - return (error); + splx(s); + tv = time; + return (VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT)); } /* - * Rmdir system call. + * Last reference to an inode, write the inode out and if necessary, + * truncate and deallocate the file. */ -ufs_rmdir(ndp) - register struct nameidata *ndp; -{ - register struct inode *ip, *dp; - int error = 0; - - ip = VTOI(ndp->ni_vp); - dp = VTOI(ndp->ni_dvp); - /* - * No rmdir "." please. - */ - if (dp == ip) { - vrele(ITOV(dp)); - iput(ip); - return (EINVAL); - } - /* - * Verify the directory is empty (and valid). - * (Rmdir ".." won't be valid since - * ".." will contain a reference to - * the current directory and thus be - * non-empty.) - */ - if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { - error = ENOTEMPTY; - goto out; - } - /* - * Delete reference to directory before purging - * inode. If we crash in between, the directory - * will be reattached to lost+found, - */ - if (error = dirremove(ndp)) - goto out; - dp->i_nlink--; - dp->i_flag |= ICHG; - cache_purge(ITOV(dp)); - iput(dp); - ndp->ni_dvp = NULL; - /* - * Truncate inode. The only stuff left - * in the directory is "." and "..". The - * "." reference is inconsequential since - * we're quashing it. The ".." reference - * has already been adjusted above. We've - * removed the "." reference and the reference - * in the parent directory, but there may be - * other hard links so decrement by 2 and - * worry about them later. - */ - ip->i_nlink -= 2; - error = itrunc(ip, (u_long)0); - cache_purge(ITOV(ip)); -out: - if (ndp->ni_dvp) - iput(dp); - iput(ip); - return (error); -} - -/* - * symlink -- make a symbolic link - */ -ufs_symlink(ndp, vap, target) - struct nameidata *ndp; - struct vattr *vap; - char *target; -{ - struct inode *ip; - int error; - - error = maknode(IFLNK | vap->va_mode, ndp, &ip); - if (error) - return (error); - error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, - UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); - iput(ip); - return (error); -} - -/* - * Vnode op for read and write - */ -ufs_readdir(vp, uio, cred) - struct vnode *vp; - register struct uio *uio; - struct ucred *cred; -{ - int count, lost, error; - - count = uio->uio_resid; - count &= ~(DIRBLKSIZ - 1); - lost = uio->uio_resid - count; - if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) - return (EINVAL); - uio->uio_resid = count; - uio->uio_iov->iov_len = count; - error = ufs_read(vp, uio, 0, cred); - uio->uio_resid += lost; - return (error); -} - -/* - * Return target name of a symbolic link - */ -ufs_readlink(vp, uiop, cred) - struct vnode *vp; - struct uio *uiop; - struct ucred *cred; -{ - - return (ufs_read(vp, uiop, 0, cred)); -} - -/* - * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually - * done. Iff ni_vp/ni_dvp not null and locked, unlock. - */ -ufs_abortop(ndp) - register struct nameidata *ndp; -{ - register struct inode *ip; - - if (ndp->ni_vp) { - ip = VTOI(ndp->ni_vp); - if (ip->i_flag & ILOCKED) - IUNLOCK(ip); - vrele(ndp->ni_vp); - } - if (ndp->ni_dvp) { - ip = VTOI(ndp->ni_dvp); - if (ip->i_flag & ILOCKED) - IUNLOCK(ip); - vrele(ndp->ni_dvp); - } - return; -} - -ufs_lock(vp) - struct vnode *vp; -{ - register struct inode *ip = VTOI(vp); - - ILOCK(ip); - return (0); -} - -ufs_unlock(vp) - struct vnode *vp; +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 (!(ip->i_flag & ILOCKED)) - panic("ufs_unlock NOT LOCKED"); - IUNLOCK(ip); - return (0); -} - -/* - * Get access to bmap - */ -ufs_bmap(vp, bn, vpp, bnp) - struct vnode *vp; - daddr_t bn; - struct vnode **vpp; - daddr_t *bnp; -{ - struct inode *ip = VTOI(vp); + if (prtactive && vp->v_usecount != 0) + vprint("ffs_inactive: pushing active", vp); - if (vpp != NULL) - *vpp = ip->i_devvp; - if (bnp == NULL) + /* Get rid of inodes related to stale file handles. */ + if (ip->i_mode == 0) { + if ((vp->v_flag & VXLOCK) == 0) + vgone(vp); return (0); - return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0)); -} - -/* - * Just call the device strategy routine - */ -ufs_strategy(bp) - register struct buf *bp; -{ - (*bdevsw[major(bp->b_dev)].d_strategy)(bp); - return (0); -} - -/* - * Make a new file. - */ -maknode(mode, ndp, ipp) - int mode; - register struct nameidata *ndp; - struct inode **ipp; -{ - register struct inode *ip; - struct inode *tip; - register struct inode *pdir = VTOI(ndp->ni_dvp); - ino_t ipref; - int error; - - *ipp = 0; - if ((mode & IFMT) == IFDIR) - ipref = dirpref(pdir->i_fs); - else - ipref = pdir->i_number; - error = ialloc(pdir, ipref, mode, &tip); - if (error) { - iput(pdir); - return (error); } - ip = tip; -#ifdef QUOTA - if (ip->i_dquot != NODQUOT) - panic("maknode: dquot"); -#endif - ip->i_flag |= IACC|IUPD|ICHG; - if ((mode & IFMT) == 0) - mode |= IFREG; - ip->i_mode = mode; - ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ - ip->i_nlink = 1; - ip->i_uid = ndp->ni_cred->cr_uid; - ip->i_gid = pdir->i_gid; - if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && - suser(ndp->ni_cred, NULL)) - ip->i_mode &= ~ISGID; + + error = 0; + ILOCK(ip); + if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { #ifdef QUOTA - ip->i_dquot = inoquota(ip); + 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; /* - * Make sure inode goes to disk before directory entry. + * If we are done with the inode, reclaim it + * so that it can be reused immediately. */ - if ((error = iupdat(ip, &time, &time, 1)) || - (error = direnter(ip, ndp))) { - /* - * Write error occurred trying to update the inode - * or the directory so must deallocate the inode. - */ - ip->i_nlink = 0; - ip->i_flag |= ICHG; - iput(ip); - return (error); - } - *ipp = ip; - return (0); + if (vp->v_usecount == 0 && ip->i_mode == 0) + vgone(vp); + return (error); }