]> git.karo-electronics.de Git - linux-beck.git/commitdiff
GFS2: update freeze code to use freeze/thaw_super on all nodes
authorBenjamin Marzinski <bmarzins@redhat.com>
Fri, 14 Nov 2014 02:42:04 +0000 (20:42 -0600)
committerSteven Whitehouse <swhiteho@redhat.com>
Mon, 17 Nov 2014 10:36:39 +0000 (10:36 +0000)
The current gfs2 freezing code is considerably more complicated than it
should be because it doesn't use the vfs freezing code on any node except
the one that begins the freeze.  This is because it needs to acquire a
cluster glock before calling the vfs code to prevent a deadlock, and
without the new freeze_super and thaw_super hooks, that was impossible. To
deal with the issue, gfs2 had to do some hacky locking tricks to make sure
that a frozen node couldn't be holding on a lock it needed to do the
unfreeze ioctl.

This patch makes use of the new hooks to simply the gfs2 locking code. Now,
all the nodes in the cluster freeze and thaw in exactly the same way. Every
node in the cluster caches the freeze glock in the shared state.  The new
freeze_super hook allows the freezing node to grab this freeze glock in
the exclusive state without first calling the vfs freeze_super function.
All the nodes in the cluster see this lock change, and call the vfs
freeze_super function. The vfs locking code guarantees that the nodes can't
get stuck holding the glocks necessary to unfreeze the system.  To
unfreeze, the freezing node uses the new thaw_super hook to drop the freeze
glock. Again, all the nodes notice this, reacquire the glock in shared mode
and call the vfs thaw_super function.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/glops.c
fs/gfs2/glops.h
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/log.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/super.c
fs/gfs2/super.h
fs/gfs2/trans.c

index 1cc0bba6313f21216202d81f8fc1bb283496003a..fe91951c33617adbcae820f1cce048df84a254a8 100644 (file)
@@ -28,6 +28,8 @@
 #include "trans.h"
 #include "dir.h"
 
+struct workqueue_struct *gfs2_freeze_wq;
+
 static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
 {
        fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
@@ -94,11 +96,8 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
          * on the stack */
        tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
        tr.tr_ip = _RET_IP_;
-       sb_start_intwrite(sdp->sd_vfs);
-       if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0) {
-               sb_end_intwrite(sdp->sd_vfs);
+       if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0)
                return;
-       }
        WARN_ON_ONCE(current->journal_info);
        current->journal_info = &tr;
 
@@ -469,20 +468,19 @@ static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
 
 static void freeze_go_sync(struct gfs2_glock *gl)
 {
+       int error = 0;
        struct gfs2_sbd *sdp = gl->gl_sbd;
-       DEFINE_WAIT(wait);
 
        if (gl->gl_state == LM_ST_SHARED &&
            test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
-               atomic_set(&sdp->sd_log_freeze, 1);
-               wake_up(&sdp->sd_logd_waitq);
-               do {
-                       prepare_to_wait(&sdp->sd_log_frozen_wait, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-                       if (atomic_read(&sdp->sd_log_freeze))
-                               io_schedule();
-               } while(atomic_read(&sdp->sd_log_freeze));
-               finish_wait(&sdp->sd_log_frozen_wait, &wait);
+               atomic_set(&sdp->sd_freeze_state, SFS_STARTING_FREEZE);
+               error = freeze_super(sdp->sd_vfs);
+               if (error) {
+                       printk(KERN_INFO "GFS2: couldn't freeze filesystem: %d\n", error);
+                       gfs2_assert_withdraw(sdp, 0);
+               }
+               queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work);
+               gfs2_log_flush(sdp, NULL, FREEZE_FLUSH);
        }
 }
 
index 7455d2629bcb1f828ed40220965886401be30163..8ed1857c1a8d3337a55f9a9eb729174715dd5def 100644 (file)
@@ -12,6 +12,8 @@
 
 #include "incore.h"
 
+extern struct workqueue_struct *gfs2_freeze_wq;
+
 extern const struct gfs2_glock_operations gfs2_meta_glops;
 extern const struct gfs2_glock_operations gfs2_inode_glops;
 extern const struct gfs2_glock_operations gfs2_rgrp_glops;
index 1b899187be5aae15719bec953a37d555618b285c..7a2dbbc0d6348e39872491b3e6a070c5729f93f5 100644 (file)
@@ -588,6 +588,12 @@ enum {
        SDF_SKIP_DLM_UNLOCK     = 8,
 };
 
+enum gfs2_freeze_state {
+       SFS_UNFROZEN            = 0,
+       SFS_STARTING_FREEZE     = 1,
+       SFS_FROZEN              = 2,
+};
+
 #define GFS2_FSNAME_LEN                256
 
 struct gfs2_inum_host {
@@ -685,6 +691,7 @@ struct gfs2_sbd {
        struct gfs2_holder sd_live_gh;
        struct gfs2_glock *sd_rename_gl;
        struct gfs2_glock *sd_freeze_gl;
+       struct work_struct sd_freeze_work;
        wait_queue_head_t sd_glock_wait;
        atomic_t sd_glock_disposal;
        struct completion sd_locking_init;
@@ -789,6 +796,9 @@ struct gfs2_sbd {
        wait_queue_head_t sd_log_flush_wait;
        int sd_log_error;
 
+       atomic_t sd_reserving_log;
+       wait_queue_head_t sd_reserving_log_wait;
+
        unsigned int sd_log_flush_head;
        u64 sd_log_flush_wrapped;
 
@@ -798,12 +808,8 @@ struct gfs2_sbd {
 
        /* For quiescing the filesystem */
        struct gfs2_holder sd_freeze_gh;
-       struct gfs2_holder sd_freeze_root_gh;
-       struct gfs2_holder sd_thaw_gh;
-       atomic_t sd_log_freeze;
-       atomic_t sd_frozen_root;
-       wait_queue_head_t sd_frozen_root_wait;
-       wait_queue_head_t sd_log_frozen_wait;
+       atomic_t sd_freeze_state;
+       struct mutex sd_freeze_mutex;
 
        char sd_fsname[GFS2_FSNAME_LEN];
        char sd_table_name[GFS2_FSNAME_LEN];
index b41b5c7898dae527f8a3fb2d577c5540e5b4252b..04065e5af4b6773faf5ae8c8d49334110c762218 100644 (file)
@@ -1618,26 +1618,18 @@ int gfs2_permission(struct inode *inode, int mask)
 {
        struct gfs2_inode *ip;
        struct gfs2_holder i_gh;
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
        int error;
        int unlock = 0;
-       int frozen_root = 0;
 
 
        ip = GFS2_I(inode);
        if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
-               if (unlikely(gfs2_glock_is_held_excl(sdp->sd_freeze_gl) &&
-                            inode == sdp->sd_root_dir->d_inode &&
-                            atomic_inc_not_zero(&sdp->sd_frozen_root)))
-                       frozen_root = 1;
-               else {
-                       if (mask & MAY_NOT_BLOCK)
-                               return -ECHILD;
-                       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
-                       if (error)
-                               return error;
-                       unlock = 1;
-               }
+               if (mask & MAY_NOT_BLOCK)
+                       return -ECHILD;
+               error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+               if (error)
+                       return error;
+               unlock = 1;
        }
 
        if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
@@ -1646,8 +1638,6 @@ int gfs2_permission(struct inode *inode, int mask)
                error = generic_permission(inode, mask);
        if (unlock)
                gfs2_glock_dq_uninit(&i_gh);
-       else if (frozen_root && atomic_dec_and_test(&sdp->sd_frozen_root))
-               wake_up(&sdp->sd_frozen_root_wait);
 
        return error;
 }
@@ -1820,29 +1810,19 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
        struct inode *inode = dentry->d_inode;
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
        int error;
        int unlock = 0;
-       int frozen_root = 0;
 
        if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
-               if (unlikely(gfs2_glock_is_held_excl(sdp->sd_freeze_gl) &&
-                            inode == sdp->sd_root_dir->d_inode &&
-                            atomic_inc_not_zero(&sdp->sd_frozen_root)))
-                       frozen_root = 1;
-               else {
-                       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
-                       if (error)
-                               return error;
-                       unlock = 1;
-               }
+               error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
+               if (error)
+                       return error;
+               unlock = 1;
        }
 
        generic_fillattr(inode, stat);
        if (unlock)
                gfs2_glock_dq_uninit(&gh);
-       else if (frozen_root && atomic_dec_and_test(&sdp->sd_frozen_root))
-               wake_up(&sdp->sd_frozen_root_wait);
 
        return 0;
 }
index 3966fadbcebd4cdba16c78a22f3ad56be57ffad2..536e7a6252cd8072835373b928878a4d91fb6e4a 100644 (file)
@@ -339,6 +339,7 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
 
 int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
 {
+       int ret = 0;
        unsigned reserved_blks = 7 * (4096 / sdp->sd_vfs->s_blocksize);
        unsigned wanted = blks + reserved_blks;
        DEFINE_WAIT(wait);
@@ -362,9 +363,13 @@ retry:
                } while(free_blocks <= wanted);
                finish_wait(&sdp->sd_log_waitq, &wait);
        }
+       atomic_inc(&sdp->sd_reserving_log);
        if (atomic_cmpxchg(&sdp->sd_log_blks_free, free_blocks,
-                               free_blocks - blks) != free_blocks)
+                               free_blocks - blks) != free_blocks) {
+               if (atomic_dec_and_test(&sdp->sd_reserving_log))
+                       wake_up(&sdp->sd_reserving_log_wait);
                goto retry;
+       }
        trace_gfs2_log_blocks(sdp, -blks);
 
        /*
@@ -377,9 +382,11 @@ retry:
        down_read(&sdp->sd_log_flush_lock);
        if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) {
                gfs2_log_release(sdp, blks);
-               return -EROFS;
+               ret = -EROFS;
        }
-       return 0;
+       if (atomic_dec_and_test(&sdp->sd_reserving_log))
+               wake_up(&sdp->sd_reserving_log_wait);
+       return ret;
 }
 
 /**
@@ -652,9 +659,12 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
        u32 hash;
        int rw = WRITE_FLUSH_FUA | REQ_META;
        struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
+       enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
        lh = page_address(page);
        clear_page(lh);
 
+       gfs2_assert_withdraw(sdp, (state != SFS_FROZEN));
+
        tail = current_tail(sdp);
 
        lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
@@ -695,6 +705,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
                    enum gfs2_flush_type type)
 {
        struct gfs2_trans *tr;
+       enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
 
        down_write(&sdp->sd_log_flush_lock);
 
@@ -713,8 +724,12 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
                INIT_LIST_HEAD(&tr->tr_ail1_list);
                INIT_LIST_HEAD(&tr->tr_ail2_list);
                tr->tr_first = sdp->sd_log_flush_head;
+               if (unlikely (state == SFS_FROZEN))
+                       gfs2_assert_withdraw(sdp, !tr->tr_num_buf_new && !tr->tr_num_databuf_new);
        }
 
+       if (unlikely(state == SFS_FROZEN))
+               gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
        gfs2_assert_withdraw(sdp,
                        sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
 
@@ -745,8 +760,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
        spin_unlock(&sdp->sd_ail_lock);
        gfs2_log_unlock(sdp);
 
-       if (atomic_read(&sdp->sd_log_freeze))
-               type = FREEZE_FLUSH;
        if (type != NORMAL_FLUSH) {
                if (!sdp->sd_log_idle) {
                        for (;;) {
@@ -763,21 +776,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
                }
                if (type == SHUTDOWN_FLUSH || type == FREEZE_FLUSH)
                        gfs2_log_shutdown(sdp);
-               if (type == FREEZE_FLUSH) {
-                       int error;
-
-                       atomic_set(&sdp->sd_log_freeze, 0);
-                       wake_up(&sdp->sd_log_frozen_wait);
-                       error = gfs2_glock_nq_init(sdp->sd_freeze_gl,
-                                                  LM_ST_SHARED, 0,
-                                                  &sdp->sd_thaw_gh);
-                       if (error) {
-                               printk(KERN_INFO "GFS2: couln't get freeze lock : %d\n", error);
-                               gfs2_assert_withdraw(sdp, 0);
-                       }
-                       else
-                               gfs2_glock_dq_uninit(&sdp->sd_thaw_gh);
-               }
+               if (type == FREEZE_FLUSH)
+                       atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
        }
 
        trace_gfs2_log_flush(sdp, 0);
@@ -888,7 +888,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
 
 static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
 {
-       return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1) || atomic_read(&sdp->sd_log_freeze));
+       return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1));
 }
 
 static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
index 82b6ac829656985e4f38c0a6f1ca66db9a7fe395..241a399bf83dd10a0ad69c29b5d0646e4b884ee9 100644 (file)
@@ -30,6 +30,7 @@
 #include "quota.h"
 #include "recovery.h"
 #include "dir.h"
+#include "glops.h"
 
 struct workqueue_struct *gfs2_control_wq;
 
@@ -161,9 +162,14 @@ static int __init init_gfs2_fs(void)
        if (!gfs2_control_wq)
                goto fail_recovery;
 
+       gfs2_freeze_wq = alloc_workqueue("freeze_workqueue", 0, 0);
+
+       if (!gfs2_freeze_wq)
+               goto fail_control;
+
        gfs2_page_pool = mempool_create_page_pool(64, 0);
        if (!gfs2_page_pool)
-               goto fail_control;
+               goto fail_freeze;
 
        gfs2_register_debugfs();
 
@@ -171,6 +177,8 @@ static int __init init_gfs2_fs(void)
 
        return 0;
 
+fail_freeze:
+       destroy_workqueue(gfs2_freeze_wq);
 fail_control:
        destroy_workqueue(gfs2_control_wq);
 fail_recovery:
@@ -224,6 +232,7 @@ static void __exit exit_gfs2_fs(void)
        unregister_filesystem(&gfs2meta_fs_type);
        destroy_workqueue(gfs_recovery_wq);
        destroy_workqueue(gfs2_control_wq);
+       destroy_workqueue(gfs2_freeze_wq);
        list_lru_destroy(&gfs2_qd_lru);
 
        rcu_barrier();
index d3eae244076e590fa82632c6c3481f14ab16be0b..b5803acb8818967d54e8f495012106dcb8d79d85 100644 (file)
@@ -129,11 +129,11 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        init_rwsem(&sdp->sd_log_flush_lock);
        atomic_set(&sdp->sd_log_in_flight, 0);
+       atomic_set(&sdp->sd_reserving_log, 0);
+       init_waitqueue_head(&sdp->sd_reserving_log_wait);
        init_waitqueue_head(&sdp->sd_log_flush_wait);
-       init_waitqueue_head(&sdp->sd_log_frozen_wait);
-       atomic_set(&sdp->sd_log_freeze, 0);
-       atomic_set(&sdp->sd_frozen_root, 0);
-       init_waitqueue_head(&sdp->sd_frozen_root_wait);
+       atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
+       mutex_init(&sdp->sd_freeze_mutex);
 
        return sdp;
 }
@@ -760,15 +760,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
        set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
        gfs2_glock_dq_uninit(&ji_gh);
        jindex = 0;
-       if (!sdp->sd_args.ar_spectator) {
-               error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
-                                          &sdp->sd_thaw_gh);
-               if (error) {
-                       fs_err(sdp, "can't acquire freeze glock: %d\n", error);
-                       goto fail_jinode_gh;
-               }
-       }
-       gfs2_glock_dq_uninit(&sdp->sd_thaw_gh);
+       INIT_WORK(&sdp->sd_freeze_work, gfs2_freeze_func);
        return 0;
 
 fail_jinode_gh:
index a346f56c4c6df97dfbc1459b61a9f6d70e42bc11..5b327f837de7187a1ac6fd1b35e01b5be058f211 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/wait.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
+#include <linux/kernel.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -399,7 +400,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
 {
        struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
        struct gfs2_glock *j_gl = ip->i_gl;
-       struct gfs2_holder thaw_gh;
+       struct gfs2_holder freeze_gh;
        struct gfs2_log_header_host head;
        int error;
 
@@ -408,7 +409,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
                return error;
 
        error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
-                                  &thaw_gh);
+                                  &freeze_gh);
        if (error)
                goto fail_threads;
 
@@ -434,13 +435,13 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
 
        set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
 
-       gfs2_glock_dq_uninit(&thaw_gh);
+       gfs2_glock_dq_uninit(&freeze_gh);
 
        return 0;
 
 fail:
-       thaw_gh.gh_flags |= GL_NOCACHE;
-       gfs2_glock_dq_uninit(&thaw_gh);
+       freeze_gh.gh_flags |= GL_NOCACHE;
+       gfs2_glock_dq_uninit(&freeze_gh);
 fail_threads:
        kthread_stop(sdp->sd_quotad_process);
        kthread_stop(sdp->sd_logd_process);
@@ -580,14 +581,15 @@ int gfs2_statfs_sync(struct super_block *sb, int type)
        struct buffer_head *m_bh, *l_bh;
        int error;
 
+       sb_start_write(sb);
        error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
                                   &gh);
        if (error)
-               return error;
+               goto out;
 
        error = gfs2_meta_inode_buffer(m_ip, &m_bh);
        if (error)
-               goto out;
+               goto out_unlock;
 
        spin_lock(&sdp->sd_statfs_spin);
        gfs2_statfs_change_in(m_sc, m_bh->b_data +
@@ -615,8 +617,10 @@ out_bh2:
        brelse(l_bh);
 out_bh:
        brelse(m_bh);
-out:
+out_unlock:
        gfs2_glock_dq_uninit(&gh);
+out:
+       sb_end_write(sb);
        return error;
 }
 
@@ -643,14 +647,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
        struct lfcc *lfcc;
        LIST_HEAD(list);
        struct gfs2_log_header_host lh;
-       struct gfs2_inode *dip = GFS2_I(sdp->sd_root_dir->d_inode);
        int error;
 
-       error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0,
-                                  &sdp->sd_freeze_root_gh);
-       if (error)
-               return error;
-       atomic_set(&sdp->sd_frozen_root, 1);
        list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
                lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
                if (!lfcc) {
@@ -692,11 +690,6 @@ out:
                gfs2_glock_dq_uninit(&lfcc->gh);
                kfree(lfcc);
        }
-       if (error) {
-               atomic_dec(&sdp->sd_frozen_root);
-               wait_event(sdp->sd_frozen_root_wait, atomic_read(&sdp->sd_frozen_root) == 0);
-               gfs2_glock_dq_uninit(&sdp->sd_freeze_root_gh);
-       }
        return error;
 }
 
@@ -834,18 +827,14 @@ out:
 
 static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 {
-       struct gfs2_holder thaw_gh;
+       struct gfs2_holder freeze_gh;
        int error;
 
        error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
-                                  &thaw_gh);
+                                  &freeze_gh);
        if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
                return error;
 
-       down_write(&sdp->sd_log_flush_lock);
-       clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
-       up_write(&sdp->sd_log_flush_lock);
-
        kthread_stop(sdp->sd_quotad_process);
        kthread_stop(sdp->sd_logd_process);
 
@@ -853,11 +842,16 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
        gfs2_quota_sync(sdp->sd_vfs, 0);
        gfs2_statfs_sync(sdp->sd_vfs, 0);
 
+       down_write(&sdp->sd_log_flush_lock);
+       clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+       up_write(&sdp->sd_log_flush_lock);
+
        gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH);
+       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 (thaw_gh.gh_gl)
-               gfs2_glock_dq_uninit(&thaw_gh);
+       if (freeze_gh.gh_gl)
+               gfs2_glock_dq_uninit(&freeze_gh);
 
        gfs2_quota_cleanup(sdp);
 
@@ -943,11 +937,41 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
        struct gfs2_sbd *sdp = sb->s_fs_info;
 
        gfs2_quota_sync(sb, -1);
-       if (wait && sdp && !atomic_read(&sdp->sd_log_freeze))
+       if (wait && sdp)
                gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
        return 0;
 }
 
+void gfs2_freeze_func(struct work_struct *work)
+{
+       int error;
+       struct gfs2_holder freeze_gh;
+       struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_freeze_work);
+       struct super_block *sb = sdp->sd_vfs;
+
+       atomic_inc(&sb->s_active);
+       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
+                                  &freeze_gh);
+       if (error) {
+               printk(KERN_INFO "GFS2: couln't get freeze lock : %d\n", error);
+               gfs2_assert_withdraw(sdp, 0);
+       }
+       else {
+               atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
+               error = thaw_super(sb);
+               if (error) {
+                       printk(KERN_INFO "GFS2: couldn't thaw filesystem: %d\n",
+                              error);
+                       gfs2_assert_withdraw(sdp, 0);
+               }
+               if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+                       freeze_gh.gh_flags |= GL_NOCACHE;
+               gfs2_glock_dq_uninit(&freeze_gh);
+       }
+       deactivate_super(sb);
+       return;
+}
+
 /**
  * gfs2_freeze - prevent further writes to the filesystem
  * @sb: the VFS structure for the filesystem
@@ -957,10 +981,16 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
 static int gfs2_freeze(struct super_block *sb)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       int error;
+       int error = 0;
 
-       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
-               return -EINVAL;
+       mutex_lock(&sdp->sd_freeze_mutex);
+       if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
+               goto out;
+
+       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
+               error = -EINVAL;
+               goto out;
+       }
 
        for (;;) {
                error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
@@ -980,7 +1010,10 @@ static int gfs2_freeze(struct super_block *sb)
                fs_err(sdp, "retrying...\n");
                msleep(1000);
        }
-       return 0;
+       error = 0;
+out:
+       mutex_unlock(&sdp->sd_freeze_mutex);
+       return error;
 }
 
 /**
@@ -993,10 +1026,15 @@ static int gfs2_unfreeze(struct super_block *sb)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
 
+       mutex_lock(&sdp->sd_freeze_mutex);
+        if (atomic_read(&sdp->sd_freeze_state) != SFS_FROZEN ||
+           sdp->sd_freeze_gh.gh_gl == NULL) {
+               mutex_unlock(&sdp->sd_freeze_mutex);
+                return 0;
+       }
+
        gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
-       atomic_dec(&sdp->sd_frozen_root);
-       wait_event(sdp->sd_frozen_root_wait, atomic_read(&sdp->sd_frozen_root) == 0);
-       gfs2_glock_dq_uninit(&sdp->sd_freeze_root_gh);
+       mutex_unlock(&sdp->sd_freeze_mutex);
        return 0;
 }
 
@@ -1618,8 +1656,8 @@ const struct super_operations gfs2_super_ops = {
        .evict_inode            = gfs2_evict_inode,
        .put_super              = gfs2_put_super,
        .sync_fs                = gfs2_sync_fs,
-       .freeze_fs              = gfs2_freeze,
-       .unfreeze_fs            = gfs2_unfreeze,
+       .freeze_super           = gfs2_freeze,
+       .thaw_super             = gfs2_unfreeze,
        .statfs                 = gfs2_statfs,
        .remount_fs             = gfs2_remount_fs,
        .drop_inode             = gfs2_drop_inode,
index 90e3322ffa10ab4564195aa22ba156262dc304ff..73c97dccae212e92f28215ca7fce6ce0be10d09a 100644 (file)
@@ -45,6 +45,7 @@ extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc,
 extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
                          struct buffer_head *l_bh);
 extern int gfs2_statfs_sync(struct super_block *sb, int type);
+extern void gfs2_freeze_func(struct work_struct *work);
 
 extern struct file_system_type gfs2_fs_type;
 extern struct file_system_type gfs2meta_fs_type;
index 42bfd33619793fb5bdda021ba9a7b9a027585e86..88bff243066910a1ee57d08432d409ed2fabadf2 100644 (file)
@@ -89,14 +89,17 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
 {
        struct gfs2_trans *tr = current->journal_info;
        s64 nbuf;
+       int alloced = tr->tr_alloced;
+
        BUG_ON(!tr);
        current->journal_info = NULL;
 
        if (!tr->tr_touched) {
                gfs2_log_release(sdp, tr->tr_reserved);
-               if (tr->tr_alloced)
+               if (alloced) {
                        kfree(tr);
-               sb_end_intwrite(sdp->sd_vfs);
+                       sb_end_intwrite(sdp->sd_vfs);
+               }
                return;
        }
 
@@ -109,13 +112,14 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
                gfs2_print_trans(tr);
 
        gfs2_log_commit(sdp, tr);
-       if (tr->tr_alloced && !tr->tr_attached)
+       if (alloced && !tr->tr_attached)
                        kfree(tr);
        up_read(&sdp->sd_log_flush_lock);
 
        if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
                gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
-       sb_end_intwrite(sdp->sd_vfs);
+       if (alloced)
+               sb_end_intwrite(sdp->sd_vfs);
 }
 
 static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
@@ -192,6 +196,7 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
 {
        struct gfs2_meta_header *mh;
        struct gfs2_trans *tr;
+       enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
 
        tr = current->journal_info;
        tr->tr_touched = 1;
@@ -205,6 +210,10 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
                       (unsigned long long)bd->bd_bh->b_blocknr);
                BUG();
        }
+       if (unlikely(state == SFS_FROZEN)) {
+               printk(KERN_INFO "GFS2:adding buf while frozen\n");
+               gfs2_assert_withdraw(sdp, 0);
+       }
        gfs2_pin(sdp, bd->bd_bh);
        mh->__pad0 = cpu_to_be64(0);
        mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);