diff options
-rw-r--r-- | fs/gfs2/glock.c | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 827136ee794c..f041a89e1ab8 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -174,6 +174,26 @@ static void gfs2_glock_hold(struct gfs2_glock *gl) | |||
174 | } | 174 | } |
175 | 175 | ||
176 | /** | 176 | /** |
177 | * demote_ok - Check to see if it's ok to unlock a glock | ||
178 | * @gl: the glock | ||
179 | * | ||
180 | * Returns: 1 if it's ok | ||
181 | */ | ||
182 | |||
183 | static int demote_ok(const struct gfs2_glock *gl) | ||
184 | { | ||
185 | const struct gfs2_glock_operations *glops = gl->gl_ops; | ||
186 | |||
187 | if (gl->gl_state == LM_ST_UNLOCKED) | ||
188 | return 0; | ||
189 | if (!list_empty(&gl->gl_holders)) | ||
190 | return 0; | ||
191 | if (glops->go_demote_ok) | ||
192 | return glops->go_demote_ok(gl); | ||
193 | return 1; | ||
194 | } | ||
195 | |||
196 | /** | ||
177 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list | 197 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list |
178 | * @gl: the glock | 198 | * @gl: the glock |
179 | * | 199 | * |
@@ -181,8 +201,13 @@ static void gfs2_glock_hold(struct gfs2_glock *gl) | |||
181 | 201 | ||
182 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | 202 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) |
183 | { | 203 | { |
204 | int may_reclaim; | ||
205 | may_reclaim = (demote_ok(gl) && | ||
206 | (atomic_read(&gl->gl_ref) == 1 || | ||
207 | (gl->gl_name.ln_type == LM_TYPE_INODE && | ||
208 | atomic_read(&gl->gl_ref) <= 2))); | ||
184 | spin_lock(&lru_lock); | 209 | spin_lock(&lru_lock); |
185 | if (list_empty(&gl->gl_lru) && gl->gl_state != LM_ST_UNLOCKED) { | 210 | if (list_empty(&gl->gl_lru) && may_reclaim) { |
186 | list_add_tail(&gl->gl_lru, &lru_list); | 211 | list_add_tail(&gl->gl_lru, &lru_list); |
187 | atomic_inc(&lru_count); | 212 | atomic_inc(&lru_count); |
188 | } | 213 | } |
@@ -190,6 +215,21 @@ static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | |||
190 | } | 215 | } |
191 | 216 | ||
192 | /** | 217 | /** |
218 | * gfs2_glock_put_nolock() - Decrement reference count on glock | ||
219 | * @gl: The glock to put | ||
220 | * | ||
221 | * This function should only be used if the caller has its own reference | ||
222 | * to the glock, in addition to the one it is dropping. | ||
223 | */ | ||
224 | |||
225 | static void gfs2_glock_put_nolock(struct gfs2_glock *gl) | ||
226 | { | ||
227 | if (atomic_dec_and_test(&gl->gl_ref)) | ||
228 | GLOCK_BUG_ON(gl, 1); | ||
229 | gfs2_glock_schedule_for_reclaim(gl); | ||
230 | } | ||
231 | |||
232 | /** | ||
193 | * gfs2_glock_put() - Decrement reference count on glock | 233 | * gfs2_glock_put() - Decrement reference count on glock |
194 | * @gl: The glock to put | 234 | * @gl: The glock to put |
195 | * | 235 | * |
@@ -214,9 +254,9 @@ int gfs2_glock_put(struct gfs2_glock *gl) | |||
214 | rv = 1; | 254 | rv = 1; |
215 | goto out; | 255 | goto out; |
216 | } | 256 | } |
217 | /* 1 for being hashed, 1 for having state != LM_ST_UNLOCKED */ | 257 | spin_lock(&gl->gl_spin); |
218 | if (atomic_read(&gl->gl_ref) == 2) | 258 | gfs2_glock_schedule_for_reclaim(gl); |
219 | gfs2_glock_schedule_for_reclaim(gl); | 259 | spin_unlock(&gl->gl_spin); |
220 | write_unlock(gl_lock_addr(gl->gl_hash)); | 260 | write_unlock(gl_lock_addr(gl->gl_hash)); |
221 | out: | 261 | out: |
222 | return rv; | 262 | return rv; |
@@ -398,7 +438,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) | |||
398 | if (held2) | 438 | if (held2) |
399 | gfs2_glock_hold(gl); | 439 | gfs2_glock_hold(gl); |
400 | else | 440 | else |
401 | gfs2_glock_put(gl); | 441 | gfs2_glock_put_nolock(gl); |
402 | } | 442 | } |
403 | 443 | ||
404 | gl->gl_state = new_state; | 444 | gl->gl_state = new_state; |
@@ -633,7 +673,7 @@ out: | |||
633 | out_sched: | 673 | out_sched: |
634 | gfs2_glock_hold(gl); | 674 | gfs2_glock_hold(gl); |
635 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 675 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
636 | gfs2_glock_put(gl); | 676 | gfs2_glock_put_nolock(gl); |
637 | out_unlock: | 677 | out_unlock: |
638 | clear_bit(GLF_LOCK, &gl->gl_flags); | 678 | clear_bit(GLF_LOCK, &gl->gl_flags); |
639 | goto out; | 679 | goto out; |
@@ -1274,26 +1314,6 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) | |||
1274 | gfs2_glock_put(gl); | 1314 | gfs2_glock_put(gl); |
1275 | } | 1315 | } |
1276 | 1316 | ||
1277 | /** | ||
1278 | * demote_ok - Check to see if it's ok to unlock a glock | ||
1279 | * @gl: the glock | ||
1280 | * | ||
1281 | * Returns: 1 if it's ok | ||
1282 | */ | ||
1283 | |||
1284 | static int demote_ok(const struct gfs2_glock *gl) | ||
1285 | { | ||
1286 | const struct gfs2_glock_operations *glops = gl->gl_ops; | ||
1287 | |||
1288 | if (gl->gl_state == LM_ST_UNLOCKED) | ||
1289 | return 0; | ||
1290 | if (!list_empty(&gl->gl_holders)) | ||
1291 | return 0; | ||
1292 | if (glops->go_demote_ok) | ||
1293 | return glops->go_demote_ok(gl); | ||
1294 | return 1; | ||
1295 | } | ||
1296 | |||
1297 | 1317 | ||
1298 | static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | 1318 | static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) |
1299 | { | 1319 | { |