From 73118ca8baf78dddd1f9c8ac67c1d80b47d9830e Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Fri, 5 Apr 2019 04:41:38 +0100 Subject: 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 Signed-off-by: Andreas Gruenbacher --- fs/gfs2/lops.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'fs/gfs2/lops.c') 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, -- cgit v1.2.3