Hi, Function gfs2_ail_empty_gl is part of the sync process (go_sync) for a glock. The go_sync glop is called to sync the metadata for a glock so we can, in good conscience, tell dlm to release the lock to another node. Its goal is not only to sync the metadata for the glock, but also to ensure all the glock's revokes are written properly as well.
The sync is accomplished by first calling a log_flush. Then it calls function gfs2_ail_empty_gl to make sure all the revokes are written for the glock. Before this patch, function gfs2_ail_empty_gl was not doing that correctly. It was checking for NEW items that needed to be revoked (gl_ail_count) and if there weren't any, it was exiting. But the log flush could have introduced new items on the sdp revokes list, so they're still pending, but still accounted for in gl->gl_revokes. This patch rearranges function gfs2_ail_empty_gl so that it first processes new revokes for its ail list, then follows through with its second log flush (for revokes both new and old) and then calls log_flush_wait to make sure the revokes are written back. Signed-off-by: Bob Peterson <rpete...@redhat.com> --- fs/gfs2/glops.c | 68 +++++++++++++++++++++------------------------------------ 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 9406e46c31fc..cdd48f52d6b3 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -90,56 +90,38 @@ static int gfs2_ail_empty_gl(struct gfs2_glock *gl) struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_trans tr; int ret; + bool need_flush = false; memset(&tr, 0, sizeof(tr)); INIT_LIST_HEAD(&tr.tr_buf); INIT_LIST_HEAD(&tr.tr_databuf); tr.tr_revokes = atomic_read(&gl->gl_ail_count); - if (!tr.tr_revokes) { - bool have_revokes; - bool log_in_flight; - - /* - * We have nothing on the ail, but there could be revokes on - * the sdp revoke queue, in which case, we still want to flush - * the log and wait for it to finish. - * - * If the sdp revoke list is empty too, we might still have an - * io outstanding for writing revokes, so we should wait for - * it before returning. - * - * If none of these conditions are true, our revokes are all - * flushed and we can return. - */ - gfs2_log_lock(sdp); - have_revokes = !list_empty(&sdp->sd_log_revokes); - log_in_flight = atomic_read(&sdp->sd_log_in_flight); - gfs2_log_unlock(sdp); - if (have_revokes) - goto flush; - if (log_in_flight) - log_flush_wait(sdp); - return 0; + if (tr.tr_revokes) { + /* A shortened, inline version of gfs2_trans_begin() + * tr->alloced is not set since the transaction structure is + * on the stack */ + tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, + sizeof(u64)); + tr.tr_ip = _RET_IP_; + ret = gfs2_log_reserve(sdp, tr.tr_reserved); + if (ret < 0) + return ret; + WARN_ON_ONCE(current->journal_info); + current->journal_info = &tr; + + __gfs2_ail_flush(gl, 0, tr.tr_revokes); + + gfs2_trans_end(sdp); + need_flush = true; + } else if (atomic_read(&gl->gl_revokes)) { + need_flush = true; + } + if (need_flush) { + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_AIL_EMPTY_GL); + log_flush_wait(sdp); } - - /* A shortened, inline version of gfs2_trans_begin() - * tr->alloced is not set since the transaction structure is - * on the stack */ - tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); - tr.tr_ip = _RET_IP_; - ret = gfs2_log_reserve(sdp, tr.tr_reserved); - if (ret < 0) - return ret; - WARN_ON_ONCE(current->journal_info); - current->journal_info = &tr; - - __gfs2_ail_flush(gl, 0, tr.tr_revokes); - - gfs2_trans_end(sdp); -flush: - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | - GFS2_LFC_AIL_EMPTY_GL); return 0; }