Skip to content

Commit 5e4c763

Browse files
committed
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call gfs2_ail1_empty, then traverse the sd_ail1_list looking for transactions that had bds which were no longer queued to a glock. And if it found some, it would try to issue revokes for them, up to a predetermined maximum. There were two problems with how it did this. First was the fact that gfs2_ail1_empty moves transactions which have nothing remaining on the ail1 list from the sd_ail1_list to the sd_ail2_list, thus making its traversal of sd_ail1_list miss them completely, and therefore, never issue revokes for them. Second was the fact that there were three traversals (or partial traversals) of the sd_ail1_list, each of which took and then released the sd_ail_lock lock: First inside gfs2_ail1_empty, second to determine if there are any revokes to be issued, and third to actually issue them. All this taking and releasing of the sd_ail_lock meant other processes could modify the lists and the conditions in which we're working. This patch simplies the whole process by adding a new parameter to function gfs2_ail1_empty, max_revokes. For normal calls, this is passed in as 0, meaning we don't want to issue any revokes. For function gfs2_write_revokes, we pass in the maximum number of revokes we can, thus allowing gfs2_ail1_empty to add the revokes where needed. This simplies the code, allows for a single holding of the sd_ail_lock, and allows gfs2_ail1_empty to add revokes for all the necessary bd items without missing any. Signed-off-by: Bob Peterson <[email protected]> Reviewed-by: Andreas Gruenbacher <[email protected]>
1 parent 7d9f924 commit 5e4c763

File tree

1 file changed

+36
-38
lines changed

1 file changed

+36
-38
lines changed

fs/gfs2/log.c

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,13 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp)
191191
/**
192192
* gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced
193193
* @sdp: the filesystem
194-
* @ai: the AIL entry
194+
* @tr: the transaction
195+
* @max_revokes: If nonzero, issue revokes for the bd items for written buffers
195196
*
196197
*/
197198

198-
static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
199+
static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
200+
int *max_revokes)
199201
{
200202
struct gfs2_bufdata *bd, *s;
201203
struct buffer_head *bh;
@@ -220,26 +222,38 @@ static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
220222
gfs2_io_error_bh(sdp, bh);
221223
gfs2_withdraw_delayed(sdp);
222224
}
225+
/*
226+
* If we have space for revokes and the bd is no longer on any
227+
* buf list, we can just add a revoke for it immediately and
228+
* avoid having to put it on the ail2 list, where it would need
229+
* to be revoked later.
230+
*/
231+
if (*max_revokes && list_empty(&bd->bd_list)) {
232+
gfs2_add_revoke(sdp, bd);
233+
(*max_revokes)--;
234+
continue;
235+
}
223236
list_move(&bd->bd_ail_st_list, &tr->tr_ail2_list);
224237
}
225238
}
226239

227240
/**
228241
* gfs2_ail1_empty - Try to empty the ail1 lists
229242
* @sdp: The superblock
243+
* @max_revokes: If non-zero, add revokes where appropriate
230244
*
231245
* Tries to empty the ail1 lists, starting with the oldest first
232246
*/
233247

234-
static int gfs2_ail1_empty(struct gfs2_sbd *sdp)
248+
static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int max_revokes)
235249
{
236250
struct gfs2_trans *tr, *s;
237251
int oldest_tr = 1;
238252
int ret;
239253

240254
spin_lock(&sdp->sd_ail_lock);
241255
list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) {
242-
gfs2_ail1_empty_one(sdp, tr);
256+
gfs2_ail1_empty_one(sdp, tr, &max_revokes);
243257
if (list_empty(&tr->tr_ail1_list) && oldest_tr)
244258
list_move(&tr->tr_list, &sdp->sd_ail2_list);
245259
else
@@ -627,27 +641,24 @@ void gfs2_glock_remove_revoke(struct gfs2_glock *gl)
627641
}
628642
}
629643

644+
/**
645+
* gfs2_write_revokes - Add as many revokes to the system transaction as we can
646+
* @sdp: The GFS2 superblock
647+
*
648+
* Our usual strategy is to defer writing revokes as much as we can in the hope
649+
* that we'll eventually overwrite the journal, which will make those revokes
650+
* go away. This changes when we flush the log: at that point, there will
651+
* likely be some left-over space in the last revoke block of that transaction.
652+
* We can fill that space with additional revokes for blocks that have already
653+
* been written back. This will basically come at no cost now, and will save
654+
* us from having to keep track of those blocks on the AIL2 list later.
655+
*/
630656
void gfs2_write_revokes(struct gfs2_sbd *sdp)
631657
{
632-
struct gfs2_trans *tr;
633-
struct gfs2_bufdata *bd, *tmp;
634-
int have_revokes = 0;
658+
/* number of revokes we still have room for */
635659
int max_revokes = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / sizeof(u64);
636660

637-
gfs2_ail1_empty(sdp);
638-
spin_lock(&sdp->sd_ail_lock);
639-
list_for_each_entry_reverse(tr, &sdp->sd_ail1_list, tr_list) {
640-
list_for_each_entry(bd, &tr->tr_ail2_list, bd_ail_st_list) {
641-
if (list_empty(&bd->bd_list)) {
642-
have_revokes = 1;
643-
goto done;
644-
}
645-
}
646-
}
647-
done:
648-
spin_unlock(&sdp->sd_ail_lock);
649-
if (have_revokes == 0)
650-
return;
661+
gfs2_log_lock(sdp);
651662
while (sdp->sd_log_num_revoke > max_revokes)
652663
max_revokes += (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / sizeof(u64);
653664
max_revokes -= sdp->sd_log_num_revoke;
@@ -658,20 +669,7 @@ void gfs2_write_revokes(struct gfs2_sbd *sdp)
658669
if (!sdp->sd_log_blks_reserved)
659670
atomic_dec(&sdp->sd_log_blks_free);
660671
}
661-
gfs2_log_lock(sdp);
662-
spin_lock(&sdp->sd_ail_lock);
663-
list_for_each_entry_reverse(tr, &sdp->sd_ail1_list, tr_list) {
664-
list_for_each_entry_safe(bd, tmp, &tr->tr_ail2_list, bd_ail_st_list) {
665-
if (max_revokes == 0)
666-
goto out_of_blocks;
667-
if (!list_empty(&bd->bd_list))
668-
continue;
669-
gfs2_add_revoke(sdp, bd);
670-
max_revokes--;
671-
}
672-
}
673-
out_of_blocks:
674-
spin_unlock(&sdp->sd_ail_lock);
672+
gfs2_ail1_empty(sdp, max_revokes);
675673
gfs2_log_unlock(sdp);
676674

677675
if (!sdp->sd_log_num_revoke) {
@@ -870,7 +868,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
870868
for (;;) {
871869
gfs2_ail1_start(sdp);
872870
gfs2_ail1_wait(sdp);
873-
if (gfs2_ail1_empty(sdp))
871+
if (gfs2_ail1_empty(sdp, 0))
874872
break;
875873
}
876874
if (gfs2_withdrawn(sdp))
@@ -1040,7 +1038,7 @@ int gfs2_logd(void *data)
10401038

10411039
did_flush = false;
10421040
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
1043-
gfs2_ail1_empty(sdp);
1041+
gfs2_ail1_empty(sdp, 0);
10441042
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
10451043
GFS2_LFC_LOGD_JFLUSH_REQD);
10461044
did_flush = true;
@@ -1049,7 +1047,7 @@ int gfs2_logd(void *data)
10491047
if (gfs2_ail_flush_reqd(sdp)) {
10501048
gfs2_ail1_start(sdp);
10511049
gfs2_ail1_wait(sdp);
1052-
gfs2_ail1_empty(sdp);
1050+
gfs2_ail1_empty(sdp, 0);
10531051
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
10541052
GFS2_LFC_LOGD_AIL_FLUSH_REQD);
10551053
did_flush = true;

0 commit comments

Comments
 (0)