dynamically allocate private part
[unix-history] / usr / src / sys / ufs / ffs / ffs_vnops.c
/*
* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* All rights reserved.
*
* %sccs.include.redist.c%
*
* @(#)ffs_vnops.c 7.66 (Berkeley) %G%
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/resourcevar.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/proc.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 <ufs/ufs/lockf.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ffs/fs.h>
#include <ufs/ffs/ffs_extern.h>
/* Global vfs data structures for ufs. */
struct vnodeops ffs_vnodeops = {
ufs_lookup, /* lookup */
ufs_create, /* create */
ufs_mknod, /* mknod */
ufs_open, /* open */
ufs_close, /* close */
ufs_access, /* access */
ufs_getattr, /* getattr */
ufs_setattr, /* setattr */
ffs_read, /* read */
ffs_write, /* write */
ufs_ioctl, /* ioctl */
ufs_select, /* select */
ufs_mmap, /* mmap */
ffs_fsync, /* fsync */
ufs_seek, /* seek */
ufs_remove, /* remove */
ufs_link, /* link */
ufs_rename, /* rename */
ufs_mkdir, /* mkdir */
ufs_rmdir, /* rmdir */
ufs_symlink, /* symlink */
ufs_readdir, /* readdir */
ufs_readlink, /* readlink */
ufs_abortop, /* abortop */
ffs_inactive, /* inactive */
ufs_reclaim, /* reclaim */
ufs_lock, /* lock */
ufs_unlock, /* unlock */
ffs_bmap, /* bmap */
ufs_strategy, /* strategy */
ufs_print, /* print */
ufs_islocked, /* islocked */
ufs_advlock, /* advlock */
ffs_blkatoff, /* blkatoff */
ffs_vget, /* vget */
ffs_valloc, /* valloc */
ffs_vfree, /* vfree */
ffs_truncate, /* truncate */
ffs_update, /* update */
bwrite, /* bwrite */
};
struct vnodeops ffs_specops = {
spec_lookup, /* lookup */
spec_create, /* create */
spec_mknod, /* mknod */
spec_open, /* open */
ufsspec_close, /* close */
ufs_access, /* access */
ufs_getattr, /* getattr */
ufs_setattr, /* setattr */
ufsspec_read, /* read */
ufsspec_write, /* write */
spec_ioctl, /* ioctl */
spec_select, /* select */
spec_mmap, /* mmap */
spec_fsync, /* fsync */
spec_seek, /* seek */
spec_remove, /* remove */
spec_link, /* link */
spec_rename, /* rename */
spec_mkdir, /* mkdir */
spec_rmdir, /* rmdir */
spec_symlink, /* symlink */
spec_readdir, /* readdir */
spec_readlink, /* readlink */
spec_abortop, /* abortop */
ffs_inactive, /* inactive */
ufs_reclaim, /* reclaim */
ufs_lock, /* lock */
ufs_unlock, /* unlock */
spec_bmap, /* bmap */
spec_strategy, /* strategy */
ufs_print, /* print */
ufs_islocked, /* islocked */
spec_advlock, /* advlock */
spec_blkatoff, /* blkatoff */
spec_vget, /* vget */
spec_valloc, /* valloc */
spec_vfree, /* vfree */
spec_truncate, /* truncate */
ffs_update, /* update */
bwrite, /* bwrite */
};
#ifdef FIFO
struct vnodeops ffs_fifoops = {
fifo_lookup, /* lookup */
fifo_create, /* create */
fifo_mknod, /* mknod */
fifo_open, /* open */
ufsfifo_close, /* close */
ufs_access, /* access */
ufs_getattr, /* getattr */
ufs_setattr, /* setattr */
ufsfifo_read, /* read */
ufsfifo_write, /* write */
fifo_ioctl, /* ioctl */
fifo_select, /* select */
fifo_mmap, /* mmap */
fifo_fsync, /* fsync */
fifo_seek, /* seek */
fifo_remove, /* remove */
fifo_link, /* link */
fifo_rename, /* rename */
fifo_mkdir, /* mkdir */
fifo_rmdir, /* rmdir */
fifo_symlink, /* symlink */
fifo_readdir, /* readdir */
fifo_readlink, /* readlink */
fifo_abortop, /* abortop */
ffs_inactive, /* inactive */
ufs_reclaim, /* reclaim */
ufs_lock, /* lock */
ufs_unlock, /* unlock */
fifo_bmap, /* bmap */
fifo_strategy, /* strategy */
ufs_print, /* print */
ufs_islocked, /* islocked */
fifo_advlock, /* advlock */
fifo_blkatoff, /* blkatoff */
fifo_vget, /* vget */
fifo_valloc, /* valloc */
fifo_vfree, /* vfree */
fifo_truncate, /* truncate */
ffs_update, /* update */
bwrite, /* bwrite */
};
#endif /* FIFO */
int maknode __P((int, struct nameidata *, struct inode **));
/*
* Vnode op for reading.
*/
/* ARGSUSED */
ffs_read(vp, uio, ioflag, cred)
struct vnode *vp;
register struct uio *uio;
int ioflag;
struct ucred *cred;
{
register struct inode *ip = VTOI(vp);
register struct fs *fs;
struct buf *bp;
daddr_t lbn, bn, rablock;
int size, diff, error = 0;
long n, on, type;
#ifdef DIAGNOSTIC
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");
#endif
if (uio->uio_resid == 0)
return (0);
if (uio->uio_offset < 0)
return (EINVAL);
ip->i_flag |= IACC;
fs = ip->i_fs;
do {
lbn = lblkno(fs, uio->uio_offset);
on = blkoff(fs, uio->uio_offset);
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;
size = blksize(fs, ip, lbn);
rablock = lbn + 1;
if (vp->v_lastr + 1 == lbn &&
lblktosize(fs, rablock) < ip->i_size)
error = breada(ITOV(ip), lbn, size, rablock,
blksize(fs, ip, rablock), NOCRED, &bp);
else
error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
vp->v_lastr = lbn;
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 (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);
return (error);
}
/*
* Vnode op for writing.
*/
ffs_write(vp, uio, ioflag, cred)
register struct vnode *vp;
struct uio *uio;
int ioflag;
struct ucred *cred;
{
struct proc *p = uio->uio_procp;
register struct inode *ip = VTOI(vp);
register struct fs *fs;
struct buf *bp;
daddr_t lbn, bn;
u_long osize;
int n, on, flags;
int size, resid, error = 0;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_WRITE)
panic("ffs_write mode");
#endif
switch (vp->v_type) {
case VREG:
if (ioflag & IO_APPEND)
uio->uio_offset = ip->i_size;
/* fall through */
case VLNK:
break;
case VDIR:
if ((ioflag & IO_SYNC) == 0)
panic("ffs_write nonsync dir write");
break;
default:
panic("ffs_write type");
}
if (uio->uio_offset < 0)
return (EINVAL);
if (uio->uio_resid == 0)
return (0);
/*
* 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 && p &&
uio->uio_offset + uio->uio_resid >
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);
if (n < fs->fs_bsize)
flags |= B_CLRBUF;
else
flags &= ~B_CLRBUF;
if (error = ffs_balloc(ip, lbn, (int)(on + n), &bp, flags))
break;
bn = bp->b_blkno;
if (uio->uio_offset + n > ip->i_size) {
ip->i_size = uio->uio_offset + n;
vnode_pager_setsize(vp, 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);
else if (n + on == fs->fs_bsize) {
bp->b_flags |= B_AGE;
bawrite(bp);
} else
bdwrite(bp);
ip->i_flag |= IUPD|ICHG;
if (cred->cr_uid != 0)
ip->i_mode &= ~(ISUID|ISGID);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
if (error && (ioflag & IO_UNIT)) {
(void)ffs_truncate(vp, osize, ioflag & IO_SYNC);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
}
if (!error && (ioflag & IO_SYNC))
error = ffs_update(vp, &time, &time, 1);
return (error);
}
/*
* Synch an open file.
*/
/* ARGSUSED */
int
ffs_fsync(vp, fflags, cred, waitfor, p)
struct vnode *vp;
int fflags;
struct ucred *cred;
int waitfor;
struct proc *p;
{
struct inode *ip = VTOI(vp);
if (fflags & FWRITE)
ip->i_flag |= ICHG;
vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
return (ffs_update(vp, &time, &time, waitfor == MNT_WAIT));
}
/*
* Last reference to an inode, write the inode out and if necessary,
* truncate and deallocate the file.
*/
int
ffs_inactive(vp, p)
struct vnode *vp;
struct proc *p;
{
register struct inode *ip;
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. */
ip = VTOI(vp);
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 = ffs_truncate(vp, (u_long)0, 0);
mode = ip->i_mode;
ip->i_mode = 0;
ip->i_rdev = 0;
ip->i_flag |= IUPD|ICHG;
ffs_vfree(vp, ip->i_number, mode);
}
if (ip->i_flag&(IUPD|IACC|ICHG|IMOD))
ffs_update(vp, &time, &time, 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);
}