diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index c7ee4c16d1eb..d27a0b1080a9 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -210,9 +210,6 @@ static void gfs2_end_log_write(struct bio *bio) fs_err(sdp, "Error %d writing to journal, jid=%u\n", err, sdp->sd_jdesc->jd_jid); gfs2_withdraw(sdp); - /* prevent more writes to the journal */ - clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); - wake_up(&sdp->sd_logd_waitq); } bio_for_each_segment_all(bvec, bio, iter_all) { diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 1cce8e0f85da..6df65540e13d 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -49,7 +49,7 @@ int __gfs2_trans_begin(struct gfs2_trans *tr, struct gfs2_sbd *sdp, } BUG_ON(blocks == 0 && revokes == 0); - if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) + if (gfs2_withdrawn(sdp)) return -EROFS; tr->tr_ip = ip; @@ -85,25 +85,30 @@ int __gfs2_trans_begin(struct gfs2_trans *tr, struct gfs2_sbd *sdp, */ down_read(&sdp->sd_log_flush_lock); + if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) + goto out_not_live; if (gfs2_log_try_reserve(sdp, tr, &extra_revokes)) goto reserved; + up_read(&sdp->sd_log_flush_lock); gfs2_log_reserve(sdp, tr, &extra_revokes); down_read(&sdp->sd_log_flush_lock); + if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) { + revokes = tr->tr_revokes + extra_revokes; + gfs2_log_release_revokes(sdp, revokes); + gfs2_log_release(sdp, tr->tr_reserved); + goto out_not_live; + } reserved: gfs2_log_release_revokes(sdp, extra_revokes); - if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) { - gfs2_log_release_revokes(sdp, tr->tr_revokes); - up_read(&sdp->sd_log_flush_lock); - gfs2_log_release(sdp, tr->tr_reserved); - sb_end_intwrite(sdp->sd_vfs); - return -EROFS; - } - current->journal_info = tr; - return 0; + +out_not_live: + up_read(&sdp->sd_log_flush_lock); + sb_end_intwrite(sdp->sd_vfs); + return -EROFS; } int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index b8ce04338b24..02603200846d 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -117,35 +117,30 @@ void gfs2_freeze_unlock(struct gfs2_sbd *sdp) static void do_withdraw(struct gfs2_sbd *sdp) { + down_write(&sdp->sd_log_flush_lock); + if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + up_write(&sdp->sd_log_flush_lock); + return; + } + clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); + up_write(&sdp->sd_log_flush_lock); + gfs2_ail_drain(sdp); /* frees all transactions */ + wake_up(&sdp->sd_logd_waitq); + wake_up(&sdp->sd_quota_wait); + + wait_event_timeout(sdp->sd_log_waitq, + gfs2_log_is_empty(sdp), + HZ * 5); + + sdp->sd_vfs->s_flags |= SB_RDONLY; + /* - * Don't tell dlm we're bailing until we have no more buffers in the - * wind. If journal had an IO error, the log code should just purge - * the outstanding buffers rather than submitting new IO. - * - * During a normal unmount, gfs2_make_fs_ro calls gfs2_log_shutdown - * which clears SDF_JOURNAL_LIVE. In a withdraw, we must not write - * any UNMOUNT log header, so we can't call gfs2_log_shutdown, and - * therefore we need to clear SDF_JOURNAL_LIVE manually. + * Dequeue any pending non-system glock holders that can no + * longer be granted because the file system is withdrawn. */ - clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); - if (!sb_rdonly(sdp->sd_vfs)) { - wake_up(&sdp->sd_logd_waitq); - wake_up(&sdp->sd_quota_wait); - - wait_event_timeout(sdp->sd_log_waitq, - gfs2_log_is_empty(sdp), - HZ * 5); - - sdp->sd_vfs->s_flags |= SB_RDONLY; - - /* - * Dequeue any pending non-system glock holders that can no - * longer be granted because the file system is withdrawn. - */ - gfs2_withdraw_glocks(sdp); - } + gfs2_withdraw_glocks(sdp); } void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...)