Implement fine-grained locking for UFS quotas.

Each struct dquot gets dq_lock mutex to protect dq_flags and to interlock
with DQ_LOCK. qhash, dqfreelist and dq.dq_cnt are protected by global
dqhlock mutex.

i_dquot array for inode is protected by lockmgr' vnode lock, corresponding
assert added to the dqget(). Access to struct ufsmount quota-related fields
(um_quotas and um_qflags) is protected by um_lock.

Tested by:	Peter Holm
Reviewed by:	tegge
Approved by:	re (kensmith)

This work were not possible without enormous amount of help given by
Tor Egge and Peter Holm. Tor reviewed each version of patch, pointed out
numerous errors and provided invaluable suggestions. Peter did tireless
testing of the patch as it was developed.
This commit is contained in:
Konstantin Belousov 2007-03-14 08:54:08 +00:00
parent df0f953ae2
commit 088ffd2086
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167543
3 changed files with 494 additions and 143 deletions

View File

@ -1103,8 +1103,6 @@ ffs_flushfiles(mp, flags, td)
if (error)
return (error);
for (i = 0; i < MAXQUOTAS; i++) {
if (ump->um_quotas[i] == NULLVP)
continue;
quotaoff(td, mp, i);
}
/*

View File

@ -113,15 +113,18 @@ struct dqblk {
* filesystem. There is one allocated for each quota that exists on any
* filesystem for the current user or group. A cache is kept of recently
* used entries.
* (h) protected by dqhlock
*/
struct dquot {
LIST_ENTRY(dquot) dq_hash; /* hash list */
TAILQ_ENTRY(dquot) dq_freelist; /* free list */
LIST_ENTRY(dquot) dq_hash; /* (h) hash list */
TAILQ_ENTRY(dquot) dq_freelist; /* (h) free list */
struct mtx dq_lock; /* lock for concurrency */
u_int16_t dq_flags; /* flags, see below */
u_int16_t dq_type; /* quota type of this dquot */
u_int32_t dq_cnt; /* count of active references */
u_int32_t dq_cnt; /* (h) count of active references */
u_int32_t dq_id; /* identifier this applies to */
struct ufsmount *dq_ump; /* filesystem that this is taken from */
struct ufsmount *dq_ump; /* (h) filesystem that this is
taken from */
struct dqblk dq_dqb; /* actual usage & quotas */
};
/*
@ -167,6 +170,23 @@ struct dquot {
#define DQREF(dq) (dq)->dq_cnt++
#endif
#define DQI_LOCK(dq) mtx_lock(&(dq)->dq_lock)
#define DQI_UNLOCK(dq) mtx_unlock(&(dq)->dq_lock)
#define DQI_WAIT(dq, prio, msg) do { \
while ((dq)->dq_flags & DQ_LOCK) { \
(dq)->dq_flags |= DQ_WANT; \
(void) msleep((dq), \
&(dq)->dq_lock, (prio), (msg), 0); \
} \
} while (0)
#define DQI_WAKEUP(dq) do { \
if ((dq)->dq_flags & DQ_WANT) \
wakeup((dq)); \
(dq)->dq_flags &= ~(DQ_WANT|DQ_LOCK); \
} while (0)
struct inode;
struct mount;
struct thread;

File diff suppressed because it is too large Load Diff