Giant-less UFS with quotas for FreeBSD

As of 23-02-2006, FreeBSD marks ufs filesystems as not needing Giant, unless quotas support is compiled into the kernel. Proposed patch against 7-CURRENT aims to properly lock quota code and adds MNTK_MPSAFE flag to ufs mounts unconditionally.

Locking strategy

The following places were identified as needed to be properly locked:

One global mutex (dqhlock) is used to protect dqhash, dqfreelist and dq_cnt, because they all manage busy/free/lookup operations for dquot'as.

Also, each dquot got individual mutex dq_lock to protect dq_flags. I.e., to safely access and manipulate dquot, the protocol shall be followed, where the operation starts by acquiring dq_lock mutex ownership. Then, thread shall wait in msleep(9) until DQ_LOCK flag is cleared by current owner. After that it is allowed to perform quick manipulations with dquot while dq_lock is held, or, if sleeping is possible, DQ_LOCK flag shall be set and mutex freed. For example,

	mtx_lock(&(dq->dq_lock));
	while (dq->dq_flags & DQ_LOCK) {
		dq->dq_flags |= DQ_WANT;
		(void) msleep(dq, &(dq->dq_lock), PINOD+1, "chkdq1", 0);
	}
	/* do something */
	dq->dq_flags |= DQ_MOD;
	mtx_unlock(&(dq->dq_lock));

To protect ufsmount data, um_lock mutex is used.

inode' i_dquot array is protected by lockmgr' vnode lock. As consequence, getinoquota(9) shall be called with exclusive lock on the vnode (except the case of NULLVP). The only caller that did not follow this (new) rule I found was ufs_access(), that could call getinoquota() with only shared lock held. I request upgrade of the vnode lock in ufs_access() before calling getinoquota() and downgrade lock after, if appropriate.

Patch

$Id: index-quotagiant.html,v 1.21 2006/06/06 09:47:07 kostik Exp $