diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-29 09:12:12 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-29 09:12:12 -0500 |
commit | 484adff8a06cb5d952832f5487ae863f54c0fb69 (patch) | |
tree | e43a9387a3a313cfdb4a34298d532dc7a1b7391c | |
parent | 7aabffcab47a0f881c7640f5c108e8d3f2e35ebf (diff) |
[GFS2] Update locking in log.c
Replace the lock_for_trans()/lock_for_flush() functions with an rwsem.
In fact the sd_log_flush_lock becomes an rwsem (the write part of it)
and is extended slightly to cover everything that the lock_for_flush()
used to cover. The read part of the lock is instead of lock_for_trans().
This corrects the races in the original code and reduces the code size.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r-- | fs/gfs2/incore.h | 6 | ||||
-rw-r--r-- | fs/gfs2/log.c | 67 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 4 | ||||
-rw-r--r-- | fs/gfs2/trans.c | 4 |
4 files changed, 22 insertions, 59 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index be307185f492..35163b562460 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -611,10 +611,6 @@ struct gfs2_sbd { | |||
611 | /* Log stuff */ | 611 | /* Log stuff */ |
612 | 612 | ||
613 | spinlock_t sd_log_lock; | 613 | spinlock_t sd_log_lock; |
614 | atomic_t sd_log_trans_count; | ||
615 | wait_queue_head_t sd_log_trans_wq; | ||
616 | atomic_t sd_log_flush_count; | ||
617 | wait_queue_head_t sd_log_flush_wq; | ||
618 | 614 | ||
619 | unsigned int sd_log_blks_reserved; | 615 | unsigned int sd_log_blks_reserved; |
620 | unsigned int sd_log_commited_buf; | 616 | unsigned int sd_log_commited_buf; |
@@ -643,7 +639,7 @@ struct gfs2_sbd { | |||
643 | int sd_log_idle; | 639 | int sd_log_idle; |
644 | 640 | ||
645 | unsigned long sd_log_flush_time; | 641 | unsigned long sd_log_flush_time; |
646 | struct mutex sd_log_flush_lock; | 642 | struct rw_semaphore sd_log_flush_lock; |
647 | struct list_head sd_log_flush_list; | 643 | struct list_head sd_log_flush_list; |
648 | 644 | ||
649 | unsigned int sd_log_flush_head; | 645 | unsigned int sd_log_flush_head; |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 16c14441a371..b103d9acf40d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -29,32 +29,6 @@ | |||
29 | 29 | ||
30 | #define PULL 1 | 30 | #define PULL 1 |
31 | 31 | ||
32 | static void lock_for_trans(struct gfs2_sbd *sdp) | ||
33 | { | ||
34 | wait_event(sdp->sd_log_trans_wq, atomic_read(&sdp->sd_log_flush_count) ? 0 : 1); | ||
35 | atomic_inc(&sdp->sd_log_trans_count); | ||
36 | } | ||
37 | |||
38 | static void unlock_from_trans(struct gfs2_sbd *sdp) | ||
39 | { | ||
40 | gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_trans_count)); | ||
41 | if (atomic_dec_and_test(&sdp->sd_log_trans_count)) | ||
42 | wake_up(&sdp->sd_log_flush_wq); | ||
43 | } | ||
44 | |||
45 | static void gfs2_lock_for_flush(struct gfs2_sbd *sdp) | ||
46 | { | ||
47 | atomic_inc(&sdp->sd_log_flush_count); | ||
48 | wait_event(sdp->sd_log_flush_wq, atomic_read(&sdp->sd_log_trans_count) ? 0 : 1); | ||
49 | } | ||
50 | |||
51 | static void gfs2_unlock_from_flush(struct gfs2_sbd *sdp) | ||
52 | { | ||
53 | gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_flush_count)); | ||
54 | if (atomic_dec_and_test(&sdp->sd_log_flush_count)) | ||
55 | wake_up(&sdp->sd_log_trans_wq); | ||
56 | } | ||
57 | |||
58 | /** | 32 | /** |
59 | * gfs2_struct2blk - compute stuff | 33 | * gfs2_struct2blk - compute stuff |
60 | * @sdp: the filesystem | 34 | * @sdp: the filesystem |
@@ -109,9 +83,8 @@ void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) | |||
109 | first = NULL; | 83 | first = NULL; |
110 | 84 | ||
111 | for (;;) { | 85 | for (;;) { |
112 | if (first && | 86 | if (first && (head->prev != first || |
113 | (head->prev != first || | 87 | gfs2_ail1_empty_one(sdp, first_ai, 0))) |
114 | gfs2_ail1_empty_one(sdp, first_ai, 0))) | ||
115 | break; | 88 | break; |
116 | 89 | ||
117 | for (tmp = head->prev; tmp != head; tmp = tmp->prev) { | 90 | for (tmp = head->prev; tmp != head; tmp = tmp->prev) { |
@@ -194,23 +167,21 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) | |||
194 | return -EINVAL; | 167 | return -EINVAL; |
195 | 168 | ||
196 | mutex_lock(&sdp->sd_log_reserve_mutex); | 169 | mutex_lock(&sdp->sd_log_reserve_mutex); |
197 | for (;;) { | 170 | gfs2_log_lock(sdp); |
198 | gfs2_log_lock(sdp); | 171 | while(sdp->sd_log_blks_free <= blks) { |
199 | if (sdp->sd_log_blks_free > blks) { | ||
200 | sdp->sd_log_blks_free -= blks; | ||
201 | gfs2_log_unlock(sdp); | ||
202 | mutex_unlock(&sdp->sd_log_reserve_mutex); | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | gfs2_log_unlock(sdp); | 172 | gfs2_log_unlock(sdp); |
207 | gfs2_ail1_empty(sdp, 0); | 173 | gfs2_ail1_empty(sdp, 0); |
208 | gfs2_log_flush(sdp); | 174 | gfs2_log_flush(sdp); |
209 | 175 | ||
210 | if (try++) | 176 | if (try++) |
211 | gfs2_ail1_start(sdp, 0); | 177 | gfs2_ail1_start(sdp, 0); |
178 | gfs2_log_lock(sdp); | ||
212 | } | 179 | } |
213 | lock_for_trans(sdp); | 180 | sdp->sd_log_blks_free -= blks; |
181 | gfs2_log_unlock(sdp); | ||
182 | mutex_unlock(&sdp->sd_log_reserve_mutex); | ||
183 | |||
184 | down_read(&sdp->sd_log_flush_lock); | ||
214 | 185 | ||
215 | return 0; | 186 | return 0; |
216 | } | 187 | } |
@@ -224,7 +195,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) | |||
224 | 195 | ||
225 | void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) | 196 | void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) |
226 | { | 197 | { |
227 | unlock_from_trans(sdp); | 198 | up_read(&sdp->sd_log_flush_lock); |
228 | 199 | ||
229 | gfs2_log_lock(sdp); | 200 | gfs2_log_lock(sdp); |
230 | sdp->sd_log_blks_free += blks; | 201 | sdp->sd_log_blks_free += blks; |
@@ -474,20 +445,20 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
474 | ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); | 445 | ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); |
475 | INIT_LIST_HEAD(&ai->ai_ail1_list); | 446 | INIT_LIST_HEAD(&ai->ai_ail1_list); |
476 | INIT_LIST_HEAD(&ai->ai_ail2_list); | 447 | INIT_LIST_HEAD(&ai->ai_ail2_list); |
477 | gfs2_lock_for_flush(sdp); | 448 | |
449 | down_write(&sdp->sd_log_flush_lock); | ||
478 | 450 | ||
479 | if (gl) { | 451 | if (gl) { |
480 | gfs2_log_lock(sdp); | 452 | gfs2_log_lock(sdp); |
481 | if (list_empty(&gl->gl_le.le_list)) { | 453 | if (list_empty(&gl->gl_le.le_list)) { |
482 | gfs2_log_unlock(sdp); | 454 | gfs2_log_unlock(sdp); |
483 | gfs2_unlock_from_flush(sdp); | 455 | up_write(&sdp->sd_log_flush_lock); |
484 | kfree(ai); | 456 | kfree(ai); |
485 | return; | 457 | return; |
486 | } | 458 | } |
487 | gfs2_log_unlock(sdp); | 459 | gfs2_log_unlock(sdp); |
488 | } | 460 | } |
489 | 461 | ||
490 | mutex_lock(&sdp->sd_log_flush_lock); | ||
491 | 462 | ||
492 | gfs2_assert_withdraw(sdp, | 463 | gfs2_assert_withdraw(sdp, |
493 | sdp->sd_log_num_buf == sdp->sd_log_commited_buf); | 464 | sdp->sd_log_num_buf == sdp->sd_log_commited_buf); |
@@ -519,9 +490,8 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
519 | } | 490 | } |
520 | gfs2_log_unlock(sdp); | 491 | gfs2_log_unlock(sdp); |
521 | 492 | ||
522 | mutex_unlock(&sdp->sd_log_flush_lock); | ||
523 | sdp->sd_vfs->s_dirt = 0; | 493 | sdp->sd_vfs->s_dirt = 0; |
524 | gfs2_unlock_from_flush(sdp); | 494 | up_write(&sdp->sd_log_flush_lock); |
525 | 495 | ||
526 | kfree(ai); | 496 | kfree(ai); |
527 | } | 497 | } |
@@ -573,7 +543,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | |||
573 | lops_incore_commit(sdp, tr); | 543 | lops_incore_commit(sdp, tr); |
574 | 544 | ||
575 | sdp->sd_vfs->s_dirt = 1; | 545 | sdp->sd_vfs->s_dirt = 1; |
576 | unlock_from_trans(sdp); | 546 | up_read(&sdp->sd_log_flush_lock); |
577 | 547 | ||
578 | gfs2_log_lock(sdp); | 548 | gfs2_log_lock(sdp); |
579 | if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) { | 549 | if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) { |
@@ -591,9 +561,8 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | |||
591 | 561 | ||
592 | void gfs2_log_shutdown(struct gfs2_sbd *sdp) | 562 | void gfs2_log_shutdown(struct gfs2_sbd *sdp) |
593 | { | 563 | { |
594 | mutex_lock(&sdp->sd_log_flush_lock); | 564 | down_write(&sdp->sd_log_flush_lock); |
595 | 565 | ||
596 | gfs2_assert_withdraw(sdp, !atomic_read(&sdp->sd_log_trans_count)); | ||
597 | gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); | 566 | gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); |
598 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); | 567 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); |
599 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); | 568 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); |
@@ -618,6 +587,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) | |||
618 | sdp->sd_log_wraps++; | 587 | sdp->sd_log_wraps++; |
619 | sdp->sd_log_tail = sdp->sd_log_head; | 588 | sdp->sd_log_tail = sdp->sd_log_head; |
620 | 589 | ||
621 | mutex_unlock(&sdp->sd_log_flush_lock); | 590 | up_write(&sdp->sd_log_flush_lock); |
622 | } | 591 | } |
623 | 592 | ||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 2628bf326334..5166455b9fdd 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -88,8 +88,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
88 | mutex_init(&sdp->sd_quota_mutex); | 88 | mutex_init(&sdp->sd_quota_mutex); |
89 | 89 | ||
90 | spin_lock_init(&sdp->sd_log_lock); | 90 | spin_lock_init(&sdp->sd_log_lock); |
91 | init_waitqueue_head(&sdp->sd_log_trans_wq); | ||
92 | init_waitqueue_head(&sdp->sd_log_flush_wq); | ||
93 | 91 | ||
94 | INIT_LIST_HEAD(&sdp->sd_log_le_gl); | 92 | INIT_LIST_HEAD(&sdp->sd_log_le_gl); |
95 | INIT_LIST_HEAD(&sdp->sd_log_le_buf); | 93 | INIT_LIST_HEAD(&sdp->sd_log_le_buf); |
@@ -101,7 +99,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
101 | INIT_LIST_HEAD(&sdp->sd_ail1_list); | 99 | INIT_LIST_HEAD(&sdp->sd_ail1_list); |
102 | INIT_LIST_HEAD(&sdp->sd_ail2_list); | 100 | INIT_LIST_HEAD(&sdp->sd_ail2_list); |
103 | 101 | ||
104 | mutex_init(&sdp->sd_log_flush_lock); | 102 | init_rwsem(&sdp->sd_log_flush_lock); |
105 | INIT_LIST_HEAD(&sdp->sd_log_flush_list); | 103 | INIT_LIST_HEAD(&sdp->sd_log_flush_list); |
106 | 104 | ||
107 | INIT_LIST_HEAD(&sdp->sd_revoke_list); | 105 | INIT_LIST_HEAD(&sdp->sd_revoke_list); |
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 63e7fed2bd47..aa1a619f0854 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c | |||
@@ -74,10 +74,10 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, | |||
74 | 74 | ||
75 | return 0; | 75 | return 0; |
76 | 76 | ||
77 | fail_gunlock: | 77 | fail_gunlock: |
78 | gfs2_glock_dq(&tr->tr_t_gh); | 78 | gfs2_glock_dq(&tr->tr_t_gh); |
79 | 79 | ||
80 | fail_holder_uninit: | 80 | fail_holder_uninit: |
81 | gfs2_holder_uninit(&tr->tr_t_gh); | 81 | gfs2_holder_uninit(&tr->tr_t_gh); |
82 | kfree(tr); | 82 | kfree(tr); |
83 | 83 | ||