diff options
author | Bob Peterson <rpeterso@redhat.com> | 2019-04-05 04:41:38 +0100 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2019-05-07 23:39:14 +0200 |
commit | 73118ca8baf78dddd1f9c8ac67c1d80b47d9830e (patch) | |
tree | 72c0d2a327c8bace37ce5984f39d971ab5768594 /fs/gfs2/lops.c | |
parent | 9287c6452d2b1f24ea8e84bd3cf6f3c6f267f712 (diff) |
gfs2: Replace gl_revokes with a GLF flag
The gl_revokes value determines how many outstanding revokes a glock has
on the superblock revokes list; this is used to avoid unnecessary log
flushes. However, gl_revokes is only ever tested for being zero, and it's
only decremented in revoke_lo_after_commit, which removes all revokes
from the list, so we know that the gl_revoke values of all the glocks on
the list will reach zero. Therefore, we can replace gl_revokes with a
bit flag. This saves an atomic counter in struct gfs2_glock.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2/lops.c')
-rw-r--r-- | fs/gfs2/lops.c | 33 |
1 files changed, 24 insertions, 9 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index b4f0a6a3ba59..2fd61853ba63 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -662,19 +662,34 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) { struct list_head *head = &sdp->sd_log_le_revoke; - struct gfs2_bufdata *bd; - struct gfs2_glock *gl; + struct gfs2_bufdata *bd, *tmp; - while (!list_empty(head)) { - bd = list_entry(head->next, struct gfs2_bufdata, bd_list); - list_del_init(&bd->bd_list); - gl = bd->bd_gl; - if (atomic_dec_return(&gl->gl_revokes) == 0) { - clear_bit(GLF_LFLUSH, &gl->gl_flags); - gfs2_glock_queue_put(gl); + /* + * Glocks can be referenced repeatedly on the revoke list, but the list + * only holds one reference. All glocks on the list will have the + * GLF_REVOKES flag set initially. + */ + + list_for_each_entry_safe(bd, tmp, head, bd_list) { + struct gfs2_glock *gl = bd->bd_gl; + + if (test_bit(GLF_REVOKES, &gl->gl_flags)) { + /* Keep each glock on the list exactly once. */ + clear_bit(GLF_REVOKES, &gl->gl_flags); + continue; } + list_del(&bd->bd_list); + kmem_cache_free(gfs2_bufdata_cachep, bd); + } + list_for_each_entry_safe(bd, tmp, head, bd_list) { + struct gfs2_glock *gl = bd->bd_gl; + + list_del(&bd->bd_list); kmem_cache_free(gfs2_bufdata_cachep, bd); + clear_bit(GLF_LFLUSH, &gl->gl_flags); + gfs2_glock_queue_put(gl); } + /* the list is empty now */ } static void revoke_lo_before_scan(struct gfs2_jdesc *jd, |