summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/quota.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/quota.c')
-rw-r--r--fs/gfs2/quota.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 4a9726aa191f..ed089118c171 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -50,6 +50,7 @@
50#include <linux/freezer.h> 50#include <linux/freezer.h>
51#include <linux/quota.h> 51#include <linux/quota.h>
52#include <linux/dqblk_xfs.h> 52#include <linux/dqblk_xfs.h>
53#include <linux/lockref.h>
53 54
54#include "gfs2.h" 55#include "gfs2.h"
55#include "incore.h" 56#include "incore.h"
@@ -148,7 +149,8 @@ static int qd_alloc(struct gfs2_sbd *sdp, struct kqid qid,
148 if (!qd) 149 if (!qd)
149 return -ENOMEM; 150 return -ENOMEM;
150 151
151 atomic_set(&qd->qd_count, 1); 152 qd->qd_lockref.count = 1;
153 spin_lock_init(&qd->qd_lockref.lock);
152 qd->qd_id = qid; 154 qd->qd_id = qid;
153 qd->qd_slot = -1; 155 qd->qd_slot = -1;
154 INIT_LIST_HEAD(&qd->qd_reclaim); 156 INIT_LIST_HEAD(&qd->qd_reclaim);
@@ -180,13 +182,12 @@ static int qd_get(struct gfs2_sbd *sdp, struct kqid qid,
180 spin_lock(&qd_lru_lock); 182 spin_lock(&qd_lru_lock);
181 list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { 183 list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
182 if (qid_eq(qd->qd_id, qid)) { 184 if (qid_eq(qd->qd_id, qid)) {
183 if (!atomic_read(&qd->qd_count) && 185 lockref_get(&qd->qd_lockref);
184 !list_empty(&qd->qd_reclaim)) { 186 if (!list_empty(&qd->qd_reclaim)) {
185 /* Remove it from reclaim list */ 187 /* Remove it from reclaim list */
186 list_del_init(&qd->qd_reclaim); 188 list_del_init(&qd->qd_reclaim);
187 atomic_dec(&qd_lru_count); 189 atomic_dec(&qd_lru_count);
188 } 190 }
189 atomic_inc(&qd->qd_count);
190 found = 1; 191 found = 1;
191 break; 192 break;
192 } 193 }
@@ -222,18 +223,24 @@ static int qd_get(struct gfs2_sbd *sdp, struct kqid qid,
222static void qd_hold(struct gfs2_quota_data *qd) 223static void qd_hold(struct gfs2_quota_data *qd)
223{ 224{
224 struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; 225 struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
225 gfs2_assert(sdp, atomic_read(&qd->qd_count)); 226 gfs2_assert(sdp, !__lockref_is_dead(&qd->qd_lockref));
226 atomic_inc(&qd->qd_count); 227 lockref_get(&qd->qd_lockref);
227} 228}
228 229
229static void qd_put(struct gfs2_quota_data *qd) 230static void qd_put(struct gfs2_quota_data *qd)
230{ 231{
231 if (atomic_dec_and_lock(&qd->qd_count, &qd_lru_lock)) { 232 spin_lock(&qd_lru_lock);
233
234 if (!lockref_put_or_lock(&qd->qd_lockref)) {
235
232 /* Add to the reclaim list */ 236 /* Add to the reclaim list */
233 list_add_tail(&qd->qd_reclaim, &qd_lru_list); 237 list_add_tail(&qd->qd_reclaim, &qd_lru_list);
234 atomic_inc(&qd_lru_count); 238 atomic_inc(&qd_lru_count);
235 spin_unlock(&qd_lru_lock); 239
240 spin_unlock(&qd->qd_lockref.lock);
236 } 241 }
242
243 spin_unlock(&qd_lru_lock);
237} 244}
238 245
239static int slot_get(struct gfs2_quota_data *qd) 246static int slot_get(struct gfs2_quota_data *qd)
@@ -394,8 +401,8 @@ static int qd_check_sync(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd,
394 list_move_tail(&qd->qd_list, &sdp->sd_quota_list); 401 list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
395 402
396 set_bit(QDF_LOCKED, &qd->qd_flags); 403 set_bit(QDF_LOCKED, &qd->qd_flags);
397 gfs2_assert_warn(sdp, atomic_read(&qd->qd_count)); 404 gfs2_assert_warn(sdp, !__lockref_is_dead(&qd->qd_lockref));
398 atomic_inc(&qd->qd_count); 405 lockref_get(&qd->qd_lockref);
399 qd->qd_change_sync = qd->qd_change; 406 qd->qd_change_sync = qd->qd_change;
400 gfs2_assert_warn(sdp, qd->qd_slot_count); 407 gfs2_assert_warn(sdp, qd->qd_slot_count);
401 qd->qd_slot_count++; 408 qd->qd_slot_count++;
@@ -1303,15 +1310,22 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
1303 while (!list_empty(head)) { 1310 while (!list_empty(head)) {
1304 qd = list_entry(head->prev, struct gfs2_quota_data, qd_list); 1311 qd = list_entry(head->prev, struct gfs2_quota_data, qd_list);
1305 1312
1306 if (atomic_read(&qd->qd_count) > 1 || 1313 /*
1307 (atomic_read(&qd->qd_count) && 1314 * To be removed in due course... we should be able to
1308 !test_bit(QDF_CHANGE, &qd->qd_flags))) { 1315 * ensure that all refs to the qd have done by this point
1316 * so that this rather odd test is not required
1317 */
1318 spin_lock(&qd->qd_lockref.lock);
1319 if (qd->qd_lockref.count > 1 ||
1320 (qd->qd_lockref.count && !test_bit(QDF_CHANGE, &qd->qd_flags))) {
1321 spin_unlock(&qd->qd_lockref.lock);
1309 list_move(&qd->qd_list, head); 1322 list_move(&qd->qd_list, head);
1310 spin_unlock(&qd_lru_lock); 1323 spin_unlock(&qd_lru_lock);
1311 schedule(); 1324 schedule();
1312 spin_lock(&qd_lru_lock); 1325 spin_lock(&qd_lru_lock);
1313 continue; 1326 continue;
1314 } 1327 }
1328 spin_unlock(&qd->qd_lockref.lock);
1315 1329
1316 list_del(&qd->qd_list); 1330 list_del(&qd->qd_list);
1317 /* Also remove if this qd exists in the reclaim list */ 1331 /* Also remove if this qd exists in the reclaim list */
@@ -1322,7 +1336,7 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
1322 atomic_dec(&sdp->sd_quota_count); 1336 atomic_dec(&sdp->sd_quota_count);
1323 spin_unlock(&qd_lru_lock); 1337 spin_unlock(&qd_lru_lock);
1324 1338
1325 if (!atomic_read(&qd->qd_count)) { 1339 if (!qd->qd_lockref.count) {
1326 gfs2_assert_warn(sdp, !qd->qd_change); 1340 gfs2_assert_warn(sdp, !qd->qd_change);
1327 gfs2_assert_warn(sdp, !qd->qd_slot_count); 1341 gfs2_assert_warn(sdp, !qd->qd_slot_count);
1328 } else 1342 } else