Example #1
0
/*
 * Reclaim an inode so that it can be used for other purposes.
 *
 * ufs_reclaim(struct vnode *a_vp)
 */
int
ufs_reclaim(struct vop_reclaim_args *ap)
{
	struct inode *ip;
	struct vnode *vp = ap->a_vp;
	struct ufsmount *ump;
#ifdef QUOTA
	int i;
#endif

	ump = VFSTOUFS(vp->v_mount);

	if (prtactive && VREFCNT(vp) > 1)
		vprint("ufs_reclaim: pushing active", vp);
	ip = VTOI(vp);

	/*
	 * Lazy updates.
	 */
	if (ip) {
		if (ip->i_flag & IN_LAZYMOD) {
			ip->i_flag |= IN_MODIFIED;
			ffs_update(vp, 0);
		}
	}
#ifdef INVARIANTS
	if (ip && (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))) {
		kprintf("WARNING: INODE %ld flags %08x: modified inode being released!\n", (long)ip->i_number, (int)ip->i_flag);
		ip->i_flag |= IN_MODIFIED;
		ffs_update(vp, 0);
	}
#endif
	/*
	 * Remove the inode from its hash chain and purge namecache
	 * data associated with the vnode.
	 */
	vp->v_data = NULL;
	if (ip) {
		ufs_ihashrem(ump, ip);
		if (ip->i_devvp) {
			vrele(ip->i_devvp);
			ip->i_devvp = 0;
		}
#ifdef QUOTA
		for (i = 0; i < MAXQUOTAS; i++) {
			if (ip->i_dquot[i] != NODQUOT) {
				ufs_dqrele(vp, ip->i_dquot[i]);
				ip->i_dquot[i] = NODQUOT;
			}
		}
#endif
#ifdef UFS_DIRHASH
		if (ip->i_dirhash != NULL)
			ufsdirhash_free(ip);
#endif
		kfree(ip, VFSTOUFS(vp->v_mount)->um_malloctype);
	}
	return (0);
}
Example #2
0
/*
 * Q_SETQUOTA - assign an entire dqblk structure.
 */
int
ufs_setquota(struct mount *mp, u_long id, int type, caddr_t addr)
{
	struct ufs_dquot *dq;
	struct ufs_dquot *ndq;
	struct ufsmount *ump = VFSTOUFS(mp);
	struct ufs_dqblk newlim;
	int error;

	error = copyin(addr, (caddr_t)&newlim, sizeof (struct ufs_dqblk));
	if (error)
		return (error);
	error = ufs_dqget(NULLVP, id, ump, type, &ndq);
	if (error)
		return (error);
	dq = ndq;
	while (dq->dq_flags & DQ_LOCK) {
		dq->dq_flags |= DQ_WANT;
		(void) tsleep((caddr_t)dq, 0, "setqta", 0);
	}
	/*
	 * Copy all but the current values.
	 * Reset time limit if previously had no soft limit or were
	 * under it, but now have a soft limit and are over it.
	 */
	newlim.dqb_curblocks = dq->dq_curblocks;
	newlim.dqb_curinodes = dq->dq_curinodes;
	if (dq->dq_id != 0) {
		newlim.dqb_btime = dq->dq_btime;
		newlim.dqb_itime = dq->dq_itime;
	}
	if (newlim.dqb_bsoftlimit &&
	    dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
	    (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
		newlim.dqb_btime = time_second + ump->um_btime[type];
	if (newlim.dqb_isoftlimit &&
	    dq->dq_curinodes >= newlim.dqb_isoftlimit &&
	    (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
		newlim.dqb_itime = time_second + ump->um_itime[type];
	dq->dq_dqb = newlim;
	if (dq->dq_curblocks < dq->dq_bsoftlimit)
		dq->dq_flags &= ~DQ_BLKS;
	if (dq->dq_curinodes < dq->dq_isoftlimit)
		dq->dq_flags &= ~DQ_INODS;
	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
		dq->dq_flags |= DQ_FAKE;
	else
		dq->dq_flags &= ~DQ_FAKE;
	dq->dq_flags |= DQ_MOD;
	ufs_dqrele(NULLVP, dq);
	return (0);
}
Example #3
0
/*
 * Q_GETQUOTA - return current values in a dqblk structure.
 */
int
ufs_getquota(struct mount *mp, u_long id, int type, caddr_t addr)
{
	struct ufs_dquot *dq;
	int error;

	error = ufs_dqget(NULLVP, id, VFSTOUFS(mp), type, &dq);
	if (error)
		return (error);
	error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct ufs_dqblk));
	ufs_dqrele(NULLVP, dq);
	return (error);
}
Example #4
0
static int
ufs_quotaoff_scan(struct mount *mp, struct vnode *vp, void *data)
{
	struct scaninfo *info = data;
	struct ufs_dquot *dq;
	struct inode *ip;

	if (vp->v_type == VNON) {
		return(0);
	}
	ip = VTOI(vp);
	dq = ip->i_dquot[info->type];
	ip->i_dquot[info->type] = NODQUOT;
	ufs_dqrele(vp, dq);
	return(0);
}
Example #5
0
/*
 * Q_SETUSE - set current inode and block usage.
 */
int
ufs_setuse(struct mount *mp, u_long id, int type, caddr_t addr)
{
	struct ufs_dquot *dq;
	struct ufsmount *ump = VFSTOUFS(mp);
	struct ufs_dquot *ndq;
	struct ufs_dqblk usage;
	int error;

	error = copyin(addr, (caddr_t)&usage, sizeof (struct ufs_dqblk));
	if (error)
		return (error);
	error = ufs_dqget(NULLVP, id, ump, type, &ndq);
	if (error)
		return (error);
	dq = ndq;
	while (dq->dq_flags & DQ_LOCK) {
		dq->dq_flags |= DQ_WANT;
		(void) tsleep((caddr_t)dq, 0, "setuse", 0);
	}
	/*
	 * Reset time limit if have a soft limit and were
	 * previously under it, but are now over it.
	 */
	if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
	    usage.dqb_curblocks >= dq->dq_bsoftlimit)
		dq->dq_btime = time_second + ump->um_btime[type];
	if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
	    usage.dqb_curinodes >= dq->dq_isoftlimit)
		dq->dq_itime = time_second + ump->um_itime[type];
	dq->dq_curblocks = usage.dqb_curblocks;
	dq->dq_curinodes = usage.dqb_curinodes;
	if (dq->dq_curblocks < dq->dq_bsoftlimit)
		dq->dq_flags &= ~DQ_BLKS;
	if (dq->dq_curinodes < dq->dq_isoftlimit)
		dq->dq_flags &= ~DQ_INODS;
	dq->dq_flags |= DQ_MOD;
	ufs_dqrele(NULLVP, dq);
	return (0);
}
Example #6
0
/*
 * Obtain a dquot structure for the specified identifier and quota file
 * reading the information from the file if necessary.
 */
static int
ufs_dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
      struct ufs_dquot **dqp)
{
	struct ufs_dquot *dq;
	struct ufs_dqhash *dqh;
	struct vnode *dqvp;
	struct iovec aiov;
	struct uio auio;
	int error;

	dqvp = ump->um_quotas[type];
	if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
		*dqp = NODQUOT;
		return (EINVAL);
	}
	/*
	 * Check the cache first.
	 */
	dqh = DQHASH(dqvp, id);
	LIST_FOREACH(dq, dqh, dq_hash) {
		if (dq->dq_id != id ||
		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
			continue;
		/*
		 * Cache hit with no references.  Take
		 * the structure off the free list.
		 */
		if (dq->dq_cnt == 0)
			TAILQ_REMOVE(&ufs_dqfreelist, dq, dq_freelist);
		DQREF(dq);
		*dqp = dq;
		return (0);
	}
	/*
	 * Not in cache, allocate a new one.
	 */
	if (TAILQ_EMPTY(&ufs_dqfreelist) && ufs_numdquot < MAXQUOTAS * desiredvnodes)
		ufs_desireddquot += DQUOTINC;
	if (ufs_numdquot < ufs_desireddquot) {
		dq = (struct ufs_dquot *)
			kmalloc(sizeof *dq, M_DQUOT, M_WAITOK | M_ZERO);
		ufs_numdquot++;
	} else {
		if ((dq = TAILQ_FIRST(&ufs_dqfreelist)) == NULL) {
			tablefull("dquot");
			*dqp = NODQUOT;
			return (EUSERS);
		}
		if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
			panic("dqget: free dquot isn't");
		TAILQ_REMOVE(&ufs_dqfreelist, dq, dq_freelist);
		if (dq->dq_ump != NULL)
			LIST_REMOVE(dq, dq_hash);
	}
	/*
	 * Initialize the contents of the dquot structure.
	 */
	if (vp != dqvp)
		vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
	LIST_INSERT_HEAD(dqh, dq, dq_hash);
	DQREF(dq);
	dq->dq_flags = DQ_LOCK;
	dq->dq_id = id;
	dq->dq_ump = ump;
	dq->dq_type = type;
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	aiov.iov_base = (caddr_t)&dq->dq_dqb;
	aiov.iov_len = sizeof (struct ufs_dqblk);
	auio.uio_resid = sizeof (struct ufs_dqblk);
	auio.uio_offset = (off_t)(id * sizeof (struct ufs_dqblk));
	auio.uio_segflg = UIO_SYSSPACE;
	auio.uio_rw = UIO_READ;
	auio.uio_td = NULL;
	error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
	if (auio.uio_resid == sizeof(struct ufs_dqblk) && error == 0)
		bzero((caddr_t)&dq->dq_dqb, sizeof(struct ufs_dqblk));
	if (vp != dqvp)
		vn_unlock(dqvp);
	if (dq->dq_flags & DQ_WANT)
		wakeup((caddr_t)dq);
	dq->dq_flags = 0;
	/*
	 * I/O error in reading quota file, release
	 * quota structure and reflect problem to caller.
	 */
	if (error) {
		LIST_REMOVE(dq, dq_hash);
		ufs_dqrele(vp, dq);
		*dqp = NODQUOT;
		return (error);
	}
	/*
	 * Check for no limit to enforce.
	 * Initialize time values if necessary.
	 */
	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
		dq->dq_flags |= DQ_FAKE;
	if (dq->dq_id != 0) {
		if (dq->dq_btime == 0)
			dq->dq_btime = time_second + ump->um_btime[type];
		if (dq->dq_itime == 0)
			dq->dq_itime = time_second + ump->um_itime[type];
	}
	*dqp = dq;
	return (0);
}
Example #7
0
int
ufs_quotaon(struct ucred *cred, struct mount *mp, int type, caddr_t fname)
{
	struct ufsmount *ump = VFSTOUFS(mp);
	struct vnode *vp, **vpp;
	struct ufs_dquot *dq;
	int error;
	struct nlookupdata nd;
	struct scaninfo scaninfo;

	vpp = &ump->um_quotas[type];
	error = nlookup_init(&nd, fname, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
	if (error == 0)
		error = vn_open(&nd, NULL, FREAD|FWRITE, 0);
	if (error == 0 && nd.nl_open_vp->v_type != VREG)
		error = EACCES;
	if (error) {
		nlookup_done(&nd);
		return (error);
	}
	vp = nd.nl_open_vp;
	nd.nl_open_vp = NULL;
	nlookup_done(&nd);

	vn_unlock(vp);
	if (*vpp != vp)
		ufs_quotaoff(mp, type);
	ump->um_qflags[type] |= QTF_OPENING;
	mp->mnt_flag |= MNT_QUOTA;
	vsetflags(vp, VSYSTEM);
	*vpp = vp;
	/* XXX release duplicate vp if *vpp == vp? */
	/*
	 * Save the credential of the process that turned on quotas.
	 * Set up the time limits for this quota.
	 */
	ump->um_cred[type] = crhold(cred);
	ump->um_btime[type] = MAX_DQ_TIME;
	ump->um_itime[type] = MAX_IQ_TIME;
	if (ufs_dqget(NULLVP, 0, ump, type, &dq) == 0) {
		if (dq->dq_btime > 0)
			ump->um_btime[type] = dq->dq_btime;
		if (dq->dq_itime > 0)
			ump->um_itime[type] = dq->dq_itime;
		ufs_dqrele(NULLVP, dq);
	}
	/*
	 * Search vnodes associated with this mount point,
	 * adding references to quota file being opened.
	 * NB: only need to add dquot's for inodes being modified.
	 */
	scaninfo.rescan = 1;
	while (scaninfo.rescan) {
		scaninfo.rescan = 0;
		error = vmntvnodescan(mp, VMSC_GETVP,
					NULL, ufs_quotaon_scan, &scaninfo);
		if (error)
			break;
	}
	ump->um_qflags[type] &= ~QTF_OPENING;
	if (error)
		ufs_quotaoff(mp, type);
	return (error);
}