summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-12-08 11:04:17 +0000
committerkib <kib@FreeBSD.org>2008-12-08 11:04:17 +0000
commit01085e085d51e1ee61dcba260fad1e95ee8a4e99 (patch)
treebc3515b769d3b5646ab79908bdbc1b1e8798167f /sys/ufs
parent4495ba28679e6469e05b130ac1d5dbd4f5cfeae2 (diff)
downloadFreeBSD-src-01085e085d51e1ee61dcba260fad1e95ee8a4e99.zip
FreeBSD-src-01085e085d51e1ee61dcba260fad1e95ee8a4e99.tar.gz
The dqrele() function syncs the dq, then acquires the dqh lock, and then
does final drop of the the dq reference to put it onto the free list. There is a possibility that the dq would be found by another thread after sync and before the dqh lock is acquired. If that other thread drops the dq before we have taken the dqh lock, the dirty dq is put on the free list. Recheck the DQ_MOD after the dqh lock is relocked. Repeat dqsync() if the dq is dirty. This ensures that up to date dq is written in the quota file and fixes assertion in dqget(). Reported and tested by: Frode Nordahl <frode nordahl net> MFC after: 3 days
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ufs/ufs_quota.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c
index 5f068c0..2db0444 100644
--- a/sys/ufs/ufs/ufs_quota.c
+++ b/sys/ufs/ufs/ufs_quota.c
@@ -1262,7 +1262,7 @@ dqrele(struct vnode *vp, struct dquot *dq)
return;
}
DQH_UNLOCK();
-
+sync:
(void) dqsync(vp, dq);
DQH_LOCK();
@@ -1271,6 +1271,18 @@ dqrele(struct vnode *vp, struct dquot *dq)
DQH_UNLOCK();
return;
}
+
+ /*
+ * The dq may become dirty after it is synced but before it is
+ * put to the free list. Checking the DQ_MOD there without
+ * locking dq should be safe since no other references to the
+ * dq exist.
+ */
+ if ((dq->dq_flags & DQ_MOD) != 0) {
+ dq->dq_cnt++;
+ DQH_UNLOCK();
+ goto sync;
+ }
TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
DQH_UNLOCK();
}
OpenPOWER on IntegriCloud