#include <sys/cdefs.h>
#include "opt_quota.h"
#include "opt_ufs.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/lock.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/mutex.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>
#ifdef UFS_DIRHASH
#include <ufs/ufs/dir.h>
#include <ufs/ufs/dirhash.h>
#endif
#ifdef UFS_GJOURNAL
#include <ufs/ufs/gjournal.h>
#endif
int
ufs_need_inactive(struct vop_need_inactive_args *ap)
{
struct vnode *vp;
struct inode *ip;
#ifdef QUOTA
int i;
#endif
vp = ap->a_vp;
ip = VTOI(vp);
if (UFS_RDONLY(ip))
return (0);
if (vn_need_pageq_flush(vp))
return (1);
if (ip->i_mode == 0 || ip->i_nlink <= 0 ||
(ip->i_effnlink == 0 && DOINGSOFTDEP(vp)) ||
(ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED |
IN_UPDATE)) != 0 ||
(ip->i_effnlink <= 0 && (ip->i_size != 0 || (I_IS_UFS2(ip) &&
ip->i_din2->di_extsize != 0))))
return (1);
#ifdef QUOTA
for (i = 0; i < MAXQUOTAS; i++) {
if (ip->i_dquot[i] != NULL)
return (1);
}
#endif
return (0);
}
int
ufs_inactive(
struct vop_inactive_args
*ap)
{
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
mode_t mode;
int error = 0;
off_t isize;
struct mount *mp;
mp = NULL;
if (ip->i_mode == 0)
goto out;
#ifdef UFS_GJOURNAL
ufs_gjournal_close(vp);
#endif
#ifdef QUOTA
qsyncvp(vp);
#endif
if ((ip->i_effnlink == 0 && DOINGSOFTDEP(vp)) ||
(ip->i_nlink <= 0 && !UFS_RDONLY(ip))) {
loop:
if (vn_start_secondary_write(vp, &mp, V_NOWAIT) != 0) {
if (VN_IS_DOOMED(vp)) {
(void) vn_start_secondary_write(vp, &mp,
V_WAIT);
} else {
MNT_ILOCK(mp);
if ((mp->mnt_kern_flag &
(MNTK_SUSPEND2 | MNTK_SUSPENDED)) == 0) {
MNT_IUNLOCK(mp);
goto loop;
}
VI_LOCK(vp);
vp->v_iflag |= VI_OWEINACT;
VI_UNLOCK(vp);
MNT_IUNLOCK(mp);
return (0);
}
}
}
isize = ip->i_size;
if (I_IS_UFS2(ip))
isize += ip->i_din2->di_extsize;
if (ip->i_effnlink <= 0 && isize && !UFS_RDONLY(ip))
error = UFS_TRUNCATE(vp, (off_t)0, IO_EXT | IO_NORMAL, NOCRED);
if (ip->i_nlink <= 0 && ip->i_mode != 0 && !UFS_RDONLY(ip) &&
(vp->v_iflag & VI_OWEINACT) == 0) {
#ifdef QUOTA
if (!getinoquota(ip))
(void)chkiq(ip, -1, NOCRED, FORCE);
#endif
#ifdef UFS_EXTATTR
ufs_extattr_vnode_inactive(vp);
#endif
DIP_SET(ip, i_rdev, 0);
mode = ip->i_mode;
ip->i_mode = 0;
DIP_SET(ip, i_mode, 0);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
if (DOINGSOFTDEP(vp))
softdep_change_linkcnt(ip);
UFS_VFREE(vp, ip->i_number, mode);
}
if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
mp == NULL &&
vn_start_secondary_write(vp, &mp, V_NOWAIT)) {
mp = NULL;
ip->i_flag &= ~IN_ACCESS;
} else {
if (mp == NULL)
(void) vn_start_secondary_write(vp, &mp,
V_WAIT);
UFS_UPDATE(vp, 0);
}
}
out:
if (ip->i_mode == 0 && (vp->v_iflag & VI_OWEINACT) == 0)
vrecycle(vp);
if (mp != NULL)
vn_finished_secondary_write(mp);
return (error);
}
int
ufs_reclaim(
struct vop_reclaim_args
*ap)
{
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
#ifdef QUOTA
int i;
for (i = 0; i < MAXQUOTAS; i++) {
if (ip->i_dquot[i] != NODQUOT) {
dqrele(vp, ip->i_dquot[i]);
ip->i_dquot[i] = NODQUOT;
}
}
#endif
#ifdef UFS_DIRHASH
if (ip->i_dirhash != NULL)
ufsdirhash_free(ip);
#endif
if (ip->i_flag & IN_LAZYMOD)
UFS_INODE_SET_FLAG(ip, IN_MODIFIED);
UFS_UPDATE(vp, 0);
vfs_hash_remove(vp);
VI_LOCK(vp);
vp->v_data = 0;
VI_UNLOCK(vp);
UFS_IFREE(ITOUMP(ip), ip);
return (0);
}