gfs2: Force withdraw to replay journals and wait for it to finish
[linux-2.6-microblaze.git] / fs / gfs2 / super.c
index 68cc7c2..693c6d1 100644 (file)
@@ -61,11 +61,13 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
        sdp->sd_journals = 0;
        spin_unlock(&sdp->sd_jindex_spin);
 
+       sdp->sd_jdesc = NULL;
        while (!list_empty(&list)) {
                jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
                gfs2_free_journal_extents(jd);
                list_del(&jd->jd_list);
                iput(jd->jd_inode);
+               jd->jd_inode = NULL;
                kfree(jd);
        }
 }
@@ -171,9 +173,13 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
                goto fail_threads;
 
        j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
+       if (gfs2_withdrawn(sdp)) {
+               error = -EIO;
+               goto fail;
+       }
 
        error = gfs2_find_jhead(sdp->sd_jdesc, &head, false);
-       if (error)
+       if (error || gfs2_withdrawn(sdp))
                goto fail;
 
        if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
@@ -187,7 +193,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
        gfs2_log_pointers_init(sdp, head.lh_blkno);
 
        error = gfs2_quota_init(sdp);
-       if (error)
+       if (error || gfs2_withdrawn(sdp))
                goto fail;
 
        set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
@@ -599,34 +605,63 @@ out:
 int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 {
        struct gfs2_holder freeze_gh;
-       int error;
-
-       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
-                                  &freeze_gh);
-       if (error && !gfs2_withdrawn(sdp))
-               return error;
+       int error = 0;
+       int log_write_allowed = test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+
+       gfs2_holder_mark_uninitialized(&freeze_gh);
+       if (sdp->sd_freeze_gl &&
+           !gfs2_glock_is_locked_by_me(sdp->sd_freeze_gl)) {
+               if (!log_write_allowed) {
+                       error = gfs2_glock_nq_init(sdp->sd_freeze_gl,
+                                                  LM_ST_SHARED, GL_NOCACHE |
+                                                  LM_FLAG_TRY, &freeze_gh);
+                       if (error == GLR_TRYFAILED)
+                               error = 0;
+               } else {
+                       error = gfs2_glock_nq_init(sdp->sd_freeze_gl,
+                                                  LM_ST_SHARED, GL_NOCACHE,
+                                                  &freeze_gh);
+                       if (error && !gfs2_withdrawn(sdp))
+                               return error;
+               }
+       }
 
        flush_workqueue(gfs2_delete_workqueue);
-       if (sdp->sd_quotad_process)
+       if (!log_write_allowed && current == sdp->sd_quotad_process)
+               fs_warn(sdp, "The quotad daemon is withdrawing.\n");
+       else if (sdp->sd_quotad_process)
                kthread_stop(sdp->sd_quotad_process);
        sdp->sd_quotad_process = NULL;
-       if (sdp->sd_logd_process)
+
+       if (!log_write_allowed && current == sdp->sd_logd_process)
+               fs_warn(sdp, "The logd daemon is withdrawing.\n");
+       else if (sdp->sd_logd_process)
                kthread_stop(sdp->sd_logd_process);
        sdp->sd_logd_process = NULL;
 
-       gfs2_quota_sync(sdp->sd_vfs, 0);
-       gfs2_statfs_sync(sdp->sd_vfs, 0);
-
-       gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SHUTDOWN |
-                      GFS2_LFC_MAKE_FS_RO);
-       wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0);
-       gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
+       if (log_write_allowed) {
+               gfs2_quota_sync(sdp->sd_vfs, 0);
+               gfs2_statfs_sync(sdp->sd_vfs, 0);
 
+               gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SHUTDOWN |
+                              GFS2_LFC_MAKE_FS_RO);
+               wait_event(sdp->sd_reserving_log_wait,
+                          atomic_read(&sdp->sd_reserving_log) == 0);
+               gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) ==
+                                sdp->sd_jdesc->jd_blocks);
+       } else {
+               wait_event_timeout(sdp->sd_reserving_log_wait,
+                                  atomic_read(&sdp->sd_reserving_log) == 0,
+                                  HZ * 5);
+       }
        if (gfs2_holder_initialized(&freeze_gh))
                gfs2_glock_dq_uninit(&freeze_gh);
 
        gfs2_quota_cleanup(sdp);
 
+       if (!log_write_allowed)
+               sdp->sd_vfs->s_flags |= SB_RDONLY;
+
        return error;
 }
 
@@ -677,8 +712,10 @@ restart:
        gfs2_glock_put(sdp->sd_freeze_gl);
 
        if (!sdp->sd_args.ar_spectator) {
-               gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
-               gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
+               if (gfs2_holder_initialized(&sdp->sd_journal_gh))
+                       gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
+               if (gfs2_holder_initialized(&sdp->sd_jinode_gh))
+                       gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
                gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
                gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
                iput(sdp->sd_sc_inode);