* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)ffs_vnops.c 7.66 (Berkeley) %G%
#include <sys/resourcevar.h>
#include <ufs/ufs/lockf.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ffs/ffs_extern.h>
/* Global vfs data structures for ufs. */
struct vnodeops ffs_vnodeops
= {
ufs_getattr
, /* getattr */
ufs_setattr
, /* setattr */
ufs_symlink
, /* symlink */
ufs_readdir
, /* readdir */
ufs_readlink
, /* readlink */
ufs_abortop
, /* abortop */
ffs_inactive
, /* inactive */
ufs_reclaim
, /* reclaim */
ufs_strategy
, /* strategy */
ufs_islocked
, /* islocked */
ufs_advlock
, /* advlock */
ffs_blkatoff
, /* blkatoff */
ffs_truncate
, /* truncate */
struct vnodeops ffs_specops
= {
spec_lookup
, /* lookup */
spec_create
, /* create */
ufsspec_close
, /* close */
ufs_getattr
, /* getattr */
ufs_setattr
, /* setattr */
ufsspec_write
, /* write */
spec_select
, /* select */
spec_remove
, /* remove */
spec_rename
, /* rename */
spec_symlink
, /* symlink */
spec_readdir
, /* readdir */
spec_readlink
, /* readlink */
spec_abortop
, /* abortop */
ffs_inactive
, /* inactive */
ufs_reclaim
, /* reclaim */
spec_strategy
, /* strategy */
ufs_islocked
, /* islocked */
spec_advlock
, /* advlock */
spec_blkatoff
, /* blkatoff */
spec_valloc
, /* valloc */
spec_truncate
, /* truncate */
struct vnodeops ffs_fifoops
= {
fifo_lookup
, /* lookup */
fifo_create
, /* create */
ufsfifo_close
, /* close */
ufs_getattr
, /* getattr */
ufs_setattr
, /* setattr */
ufsfifo_write
, /* write */
fifo_select
, /* select */
fifo_remove
, /* remove */
fifo_rename
, /* rename */
fifo_symlink
, /* symlink */
fifo_readdir
, /* readdir */
fifo_readlink
, /* readlink */
fifo_abortop
, /* abortop */
ffs_inactive
, /* inactive */
ufs_reclaim
, /* reclaim */
fifo_strategy
, /* strategy */
ufs_islocked
, /* islocked */
fifo_advlock
, /* advlock */
fifo_blkatoff
, /* blkatoff */
fifo_valloc
, /* valloc */
fifo_truncate
, /* truncate */
int maknode
__P((int, struct nameidata
*, struct inode
**));
ffs_read(vp
, uio
, ioflag
, cred
)
register struct uio
*uio
;
register struct inode
*ip
= VTOI(vp
);
daddr_t lbn
, bn
, rablock
;
int size
, diff
, error
= 0;
if (uio
->uio_rw
!= UIO_READ
)
type
= ip
->i_mode
& IFMT
;
if (type
!= IFDIR
&& type
!= IFREG
&& type
!= IFLNK
)
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
;
size
= blksize(fs
, ip
, lbn
);
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
);
error
= bread(ITOV(ip
), lbn
, size
, NOCRED
, &bp
);
n
= MIN(n
, size
- bp
->b_resid
);
error
= uiomove(bp
->b_un
.b_addr
+ on
, (int)n
, uio
);
if (n
+ on
== fs
->fs_bsize
|| uio
->uio_offset
== ip
->i_size
)
} while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
ffs_write(vp
, uio
, ioflag
, cred
)
register struct vnode
*vp
;
struct proc
*p
= uio
->uio_procp
;
register struct inode
*ip
= VTOI(vp
);
int size
, resid
, error
= 0;
if (uio
->uio_rw
!= UIO_WRITE
)
uio
->uio_offset
= ip
->i_size
;
if ((ioflag
& IO_SYNC
) == 0)
panic("ffs_write nonsync dir write");
* 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
) {
lbn
= lblkno(fs
, uio
->uio_offset
);
on
= blkoff(fs
, uio
->uio_offset
);
n
= MIN((unsigned)(fs
->fs_bsize
- on
), uio
->uio_resid
);
if (error
= ffs_balloc(ip
, lbn
, (int)(on
+ n
), &bp
, flags
))
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
);
else if (n
+ on
== fs
->fs_bsize
) {
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
;
if (!error
&& (ioflag
& IO_SYNC
))
error
= ffs_update(vp
, &time
, &time
, 1);
ffs_fsync(vp
, fflags
, cred
, waitfor
, p
)
struct inode
*ip
= VTOI(vp
);
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.
register struct inode
*ip
;
if (prtactive
&& vp
->v_usecount
!= 0)
vprint("ffs_inactive: pushing active", vp
);
/* Get rid of inodes related to stale file handles. */
if ((vp
->v_flag
& VXLOCK
) == 0)
if (ip
->i_nlink
<= 0 && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
(void)chkiq(ip
, -1, NOCRED
, 0);
error
= ffs_truncate(vp
, (u_long
)0, 0);
ffs_vfree(vp
, ip
->i_number
, mode
);
if (ip
->i_flag
&(IUPD
|IACC
|ICHG
|IMOD
))
ffs_update(vp
, &time
, &time
, 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)