diff options
Diffstat (limited to 'fs/gfs2/quota.c')
-rw-r--r-- | fs/gfs2/quota.c | 42 |
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, | |||
222 | static void qd_hold(struct gfs2_quota_data *qd) | 223 | static 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 | ||
229 | static void qd_put(struct gfs2_quota_data *qd) | 230 | static 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 | ||
239 | static int slot_get(struct gfs2_quota_data *qd) | 246 | static 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 |