On Tue, Jun 13, 2023 at 12:29 PM Andrew Price <anpr...@redhat.com> wrote:
> On 12/06/2023 17:33, Andreas Gruenbacher wrote:
> > So far, at mount time, gfs2 would take the freeze glock in shared mode
> > and then immediately drop it again, turning it into a cached glock that
> > can be reclaimed at any time.  To freeze the filesystem cluster-wide,
> > the node initiating the freeze would take the freeze glock in exclusive
> > mode, which would cause the freeze glock's freeze_go_sync() callback to
> > run on each node.  There, gfs2 would freeze the filesystem and schedule
> > gfs2_freeze_func() to run.  gfs2_freeze_func() would re-acquire the
> > freeze glock in shared mode, thaw the filesystem, and drop the freeze
> > glock again.  The initiating node would keep the freeze glock held in
> > exclusive mode.  To thaw the filesystem, the initiating node would drop
> > the freeze glock again, which would allow gfs2_freeze_func() to resume
> > on all nodes, leaving the filesystem in the thawed state.
> >
> > It turns out that in freeze_go_sync(), we cannot reliably and safely
> > freeze the filesystem.  This is primarily because the final unmount of a
> > filesystem takes a write lock on the s_umount rw semaphore before
> > calling into gfs2_put_super(), and freeze_go_sync() needs to call
> > freeze_super() which also takes a write lock on the same semaphore,
> > causing a deadlock.  We could work around this by trying to take an
> > active reference on the super block first, which would prevent unmount
> > from running at the same time.  But that can fail, and freeze_go_sync()
> > isn't actually allowed to fail.
> >
> > To get around this, this patch changes the freeze glock locking scheme
> > as follows:
> >
> > At mount time, each node takes the freeze glock in shared mode.  To
> > freeze a filesystem, the initiating node first freezes the filesystem
> > locally and then drops and re-acquires the freeze glock in exclusive
> > mode.  All other nodes notice that there is contention on the freeze
> > glock in their go_callback callbacks, and they schedule
> > gfs2_freeze_func() to run.  There, they freeze the filesystem locally
> > and drop and re-acquire the freeze glock before re-thawing the
> > filesystem.  This is happening outside of the glock state engine, so
> > there, we are allowed to fail.
> >
> >  From a cluster point of view, taking and immediately dropping a glock is
> > indistinguishable from taking the glock and only dropping it upon
> > contention, so this new scheme is compatible with the old one.
>
> Nice!
>
> > Signed-off-by: Andreas Gruenbacher <agrue...@redhat.com>
> > ---
> >   fs/gfs2/glops.c      |  52 +++++--------
> >   fs/gfs2/log.c        |   2 -
> >   fs/gfs2/ops_fstype.c |   5 +-
> >   fs/gfs2/recovery.c   |  24 +++---
> >   fs/gfs2/super.c      | 179 ++++++++++++++++++++++++++++++++++---------
> >   fs/gfs2/super.h      |   1 +
> >   fs/gfs2/util.c       |  32 +++-----
> >   7 files changed, 185 insertions(+), 110 deletions(-)
> >
> > diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
> > index 01d433ed6ce7..7c48c7afd6a4 100644
> > --- a/fs/gfs2/glops.c
> > +++ b/fs/gfs2/glops.c
> > @@ -561,47 +561,33 @@ static void inode_go_dump(struct seq_file *seq, 
> > struct gfs2_glock *gl,
> >   }
> >
> >   /**
> > - * freeze_go_sync - promote/demote the freeze glock
> > + * freeze_go_callback - A cluster node is requesting a freeze
> >    * @gl: the glock
> > + * @remote: true if this came from a different cluster node
> >    */
> >
> > -static int freeze_go_sync(struct gfs2_glock *gl)
> > +static void freeze_go_callback(struct gfs2_glock *gl, bool remote)
> >   {
> > -     int error = 0;
> >       struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
> > +     struct super_block *sb = sdp->sd_vfs;
> > +
> > +     if (!remote ||
> > +         gl->gl_state != LM_ST_SHARED ||
> > +         gl->gl_demote_state != LM_ST_UNLOCKED)
> > +             return;
> >
> >       /*
> > -      * We need to check gl_state == LM_ST_SHARED here and not gl_req ==
> > -      * LM_ST_EXCLUSIVE. That's because when any node does a freeze,
> > -      * all the nodes should have the freeze glock in SH mode and they all
> > -      * call do_xmote: One for EX and the others for UN. They ALL must
> > -      * freeze locally, and they ALL must queue freeze work. The 
> > freeze_work
> > -      * calls freeze_func, which tries to reacquire the freeze glock in SH,
> > -      * effectively waiting for the thaw on the node who holds it in EX.
> > -      * Once thawed, the work func acquires the freeze glock in
> > -      * SH and everybody goes back to thawed.
> > +      * Try to get an active super block reference to prevent racing with
> > +      * unmount (see trylock_super()).  But note that unmount isn't the 
> > only
> > +      * place where a write lock on s_umount is taken, and we can fail here
> > +      * because of things like remount as well.
> >        */
> > -     if (gl->gl_state == LM_ST_SHARED && !gfs2_withdrawn(sdp) &&
> > -         !test_bit(SDF_NORECOVERY, &sdp->sd_flags)) {
> > -             atomic_set(&sdp->sd_freeze_state, SFS_STARTING_FREEZE);
> > -             error = freeze_super(sdp->sd_vfs);
> > -             if (error) {
> > -                     fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
> > -                             error);
> > -                     if (gfs2_withdrawn(sdp)) {
> > -                             atomic_set(&sdp->sd_freeze_state, 
> > SFS_UNFROZEN);
> > -                             return 0;
> > -                     }
> > -                     gfs2_assert_withdraw(sdp, 0);
> > -             }
> > -             queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work);
> > -             if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
> > -                     gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
> > -                                    GFS2_LFC_FREEZE_GO_SYNC);
> > -             else /* read-only mounts */
> > -                     atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
> > +     if (down_read_trylock(&sb->s_umount)) {
> > +             atomic_inc(&sb->s_active);
> > +             up_read(&sb->s_umount);
> > +             if (!queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work))
> > +                     deactivate_super(sb);
> >       }
> > -     return 0;
> >   }
> >
> >   /**
> > @@ -761,9 +747,9 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
> >   };
> >
> >   const struct gfs2_glock_operations gfs2_freeze_glops = {
> > -     .go_sync = freeze_go_sync,
> >       .go_xmote_bh = freeze_go_xmote_bh,
> >       .go_demote_ok = freeze_go_demote_ok,
> > +     .go_callback = freeze_go_callback,
> >       .go_type = LM_TYPE_NONDISK,
> >       .go_flags = GLOF_NONDISK,
> >   };
> > diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
> > index d750d1128bed..dca535311dee 100644
> > --- a/fs/gfs2/log.c
> > +++ b/fs/gfs2/log.c
> > @@ -1136,8 +1136,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct 
> > gfs2_glock *gl, u32 flags)
> >               if (flags & (GFS2_LOG_HEAD_FLUSH_SHUTDOWN |
> >                            GFS2_LOG_HEAD_FLUSH_FREEZE))
> >                       gfs2_log_shutdown(sdp);
> > -             if (flags & GFS2_LOG_HEAD_FLUSH_FREEZE)
> > -                     atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
> >       }
> >
> >   out_end:
> > diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
> > index 12eedba45dbb..4ce5718719ac 100644
> > --- a/fs/gfs2/ops_fstype.c
> > +++ b/fs/gfs2/ops_fstype.c
> > @@ -1140,7 +1140,6 @@ static int gfs2_fill_super(struct super_block *sb, 
> > struct fs_context *fc)
> >       int silent = fc->sb_flags & SB_SILENT;
> >       struct gfs2_sbd *sdp;
> >       struct gfs2_holder mount_gh;
> > -     struct gfs2_holder freeze_gh;
> >       int error;
> >
> >       sdp = init_sbd(sb);
> > @@ -1269,15 +1268,15 @@ static int gfs2_fill_super(struct super_block *sb, 
> > struct fs_context *fc)
> >               }
> >       }
> >
> > -     error = gfs2_freeze_lock_shared(sdp, &freeze_gh, 0);
> > +     error = gfs2_freeze_lock_shared(sdp, &sdp->sd_freeze_gh, 0);
> >       if (error)
> >               goto fail_per_node;
> >
> >       if (!sb_rdonly(sb))
> >               error = gfs2_make_fs_rw(sdp);
> >
> > -     gfs2_freeze_unlock(&freeze_gh);
> >       if (error) {
> > +             gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> >               if (sdp->sd_quotad_process)
> >                       kthread_stop(sdp->sd_quotad_process);
> >               sdp->sd_quotad_process = NULL;
> > diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
> > index 61ef07da40b2..afeda936e2be 100644
> > --- a/fs/gfs2/recovery.c
> > +++ b/fs/gfs2/recovery.c
> > @@ -404,7 +404,7 @@ void gfs2_recover_func(struct work_struct *work)
> >       struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
> >       struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
> >       struct gfs2_log_header_host head;
> > -     struct gfs2_holder j_gh, ji_gh, thaw_gh;
> > +     struct gfs2_holder j_gh, ji_gh;
> >       ktime_t t_start, t_jlck, t_jhd, t_tlck, t_rep;
> >       int ro = 0;
> >       unsigned int pass;
> > @@ -465,14 +465,14 @@ void gfs2_recover_func(struct work_struct *work)
> >               ktime_ms_delta(t_jhd, t_jlck));
> >
> >       if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
> > -             fs_info(sdp, "jid=%u: Acquiring the freeze glock...\n",
> > -                     jd->jd_jid);
> > -
> > -             /* Acquire a shared hold on the freeze glock */
> > +             mutex_lock(&sdp->sd_freeze_mutex);
> >
> > -             error = gfs2_freeze_lock_shared(sdp, &thaw_gh, 
> > LM_FLAG_PRIORITY);
> > -             if (error)
> > +             if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN) {
> > +                     mutex_unlock(&sdp->sd_freeze_mutex);
> > +                     fs_warn(sdp, "jid=%u: Can't replay: filesystem "
> > +                             "is frozen\n", jd->jd_jid);
> >                       goto fail_gunlock_ji;
> > +             }
> >
> >               if (test_bit(SDF_RORECOVERY, &sdp->sd_flags)) {
> >                       ro = 1;
> > @@ -496,7 +496,7 @@ void gfs2_recover_func(struct work_struct *work)
> >                       fs_warn(sdp, "jid=%u: Can't replay: read-only block "
> >                               "device\n", jd->jd_jid);
> >                       error = -EROFS;
> > -                     goto fail_gunlock_thaw;
> > +                     goto fail_gunlock_nofreeze;
> >               }
> >
> >               t_tlck = ktime_get();
> > @@ -514,7 +514,7 @@ void gfs2_recover_func(struct work_struct *work)
> >                       lops_after_scan(jd, error, pass);
> >                       if (error) {
> >                               up_read(&sdp->sd_log_flush_lock);
> > -                             goto fail_gunlock_thaw;
> > +                             goto fail_gunlock_nofreeze;
> >                       }
> >               }
> >
> > @@ -522,7 +522,7 @@ void gfs2_recover_func(struct work_struct *work)
> >               clean_journal(jd, &head);
> >               up_read(&sdp->sd_log_flush_lock);
> >
> > -             gfs2_freeze_unlock(&thaw_gh);
> > +             mutex_unlock(&sdp->sd_freeze_mutex);
> >               t_rep = ktime_get();
> >               fs_info(sdp, "jid=%u: Journal replayed in %lldms 
> > [jlck:%lldms, "
> >                       "jhead:%lldms, tlck:%lldms, replay:%lldms]\n",
> > @@ -543,8 +543,8 @@ void gfs2_recover_func(struct work_struct *work)
> >       fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
> >       goto done;
> >
> > -fail_gunlock_thaw:
> > -     gfs2_freeze_unlock(&thaw_gh);
> > +fail_gunlock_nofreeze:
> > +     mutex_unlock(&sdp->sd_freeze_mutex);
> >   fail_gunlock_ji:
> >       if (jlocked) {
> >               gfs2_glock_dq_uninit(&ji_gh);
> > diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
> > index 5f3e699ae922..eb41ab32695a 100644
> > --- a/fs/gfs2/super.c
> > +++ b/fs/gfs2/super.c
> > @@ -332,7 +332,12 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd 
> > *sdp)
> >       struct lfcc *lfcc;
> >       LIST_HEAD(list);
> >       struct gfs2_log_header_host lh;
> > -     int error;
> > +     int error, error2;
> > +
> > +     /*
> > +      * Grab all the journal glocks in SH mode.  We are *probably* doing
> > +      * that to prevent recovery.
> > +      */
> >
> >       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
> >               lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
> > @@ -349,11 +354,13 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd 
> > *sdp)
> >               list_add(&lfcc->list, &list);
> >       }
> >
> > +     gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +
> >       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
> >                                  LM_FLAG_NOEXP | GL_NOPID,
> >                                  &sdp->sd_freeze_gh);
> >       if (error)
> > -             goto out;
> > +             goto relock_shared;
> >
> >       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
> >               error = gfs2_jdesc_check(jd);
> > @@ -368,8 +375,14 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd 
> > *sdp)
> >               }
> >       }
> >
> > -     if (error)
> > -             gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +     if (!error)
> > +             goto out;  /* success */
> > +
> > +     gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +
> > +relock_shared:
> > +     error2 = gfs2_freeze_lock_shared(sdp, &sdp->sd_freeze_gh, 0);
> > +     gfs2_assert_withdraw(sdp, !error2);
> >
> >   out:
> >       while (!list_empty(&list)) {
> > @@ -615,6 +628,8 @@ static void gfs2_put_super(struct super_block *sb)
> >
> >       /*  Release stuff  */
> >
> > +     gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +
> >       iput(sdp->sd_jindex);
> >       iput(sdp->sd_statfs_inode);
> >       iput(sdp->sd_rindex);
> > @@ -669,31 +684,81 @@ static int gfs2_sync_fs(struct super_block *sb, int 
> > wait)
> >       return sdp->sd_log_error;
> >   }
> >
> > -void gfs2_freeze_func(struct work_struct *work)
> > +static int gfs2_freeze_locally(struct gfs2_sbd *sdp)
> >   {
> > -     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;
> > +     int error;
> >
> > -     atomic_inc(&sb->s_active);
> > -     error = gfs2_freeze_lock_shared(sdp, &freeze_gh, 0);
> > -     if (error) {
> > -             gfs2_assert_withdraw(sdp, 0);
> > -     } else {
> > -             atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
> > -             error = thaw_super(sb);
> > -             if (error) {
> > -                     fs_info(sdp, "GFS2: couldn't thaw filesystem: %d\n",
> > -                             error);
> > -                     gfs2_assert_withdraw(sdp, 0);
> > +     atomic_set(&sdp->sd_freeze_state, SFS_STARTING_FREEZE);
> > +
> > +     error = freeze_super(sb);
> > +     if (error)
> > +             goto fail;
> > +
> > +     if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
> > +             gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
> > +                            GFS2_LFC_FREEZE_GO_SYNC);
> > +             if (gfs2_withdrawn(sdp)) {
> > +                     thaw_super(sb);
> > +                     error = -EIO;
> > +                     goto fail;
> >               }
> > -             gfs2_freeze_unlock(&freeze_gh);
> >       }
> > +     return 0;
> > +
> > +fail:
> > +     atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
> > +     return error;
> > +}
> > +
> > +static int gfs2_do_thaw(struct gfs2_sbd *sdp)
> > +{
> > +     struct super_block *sb = sdp->sd_vfs;
> > +     int error;
> > +
> > +     error = gfs2_freeze_lock_shared(sdp, &sdp->sd_freeze_gh, 0);
> > +     if (error)
> > +             goto fail;
> > +     error = thaw_super(sb);
> > +     if (!error)
> > +             return 0;
> > +
> > +fail:
> > +     fs_info(sdp, "GFS2: couldn't thaw filesystem: %d\n", error);
> > +     gfs2_assert_withdraw(sdp, 0);
> > +     return error;
> > +}
> > +
> > +void gfs2_freeze_func(struct work_struct *work)
> > +{
> > +     struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, 
> > sd_freeze_work);
> > +     struct super_block *sb = sdp->sd_vfs;
> > +     int error;
> > +
> > +     mutex_lock(&sdp->sd_freeze_mutex);
> > +     error = -EBUSY;
> > +     if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
> > +             goto out_unlock;
> > +
> > +     error = gfs2_freeze_locally(sdp);
> > +     if (error)
> > +             goto out_unlock;
> > +
> > +     gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +     atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
> > +
> > +     error = gfs2_do_thaw(sdp);
> > +     if (error)
> > +             goto out;
> > +
> > +     atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
> > +
> > +out_unlock:
> > +     mutex_unlock(&sdp->sd_freeze_mutex);
> >       deactivate_super(sb);
> > -     clear_bit_unlock(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
> > -     wake_up_bit(&sdp->sd_flags, SDF_FREEZE_INITIATOR);
> > -     return;
> > +out:
> > +     if (error)
> > +             fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n", error);
> >   }
> >
> >   /**
> > @@ -707,21 +772,27 @@ static int gfs2_freeze_super(struct super_block *sb)
> >       struct gfs2_sbd *sdp = sb->s_fs_info;
> >       int error;
> >
> > -     mutex_lock(&sdp->sd_freeze_mutex);
> > -     if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN) {
> > -             error = -EBUSY;
> > +     if (!mutex_trylock(&sdp->sd_freeze_mutex))
> > +             return -EBUSY;
> > +     error = -EBUSY;
> > +     if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
> >               goto out;
> > -     }
> >
> >       for (;;) {
> > -             if (gfs2_withdrawn(sdp)) {
> > -                     error = -EINVAL;
> > +             error = gfs2_freeze_locally(sdp);
> > +             if (error) {
> > +                     fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
> > +                             error);
> >                       goto out;
> >               }
> >
> >               error = gfs2_lock_fs_check_clean(sdp);
> >               if (!error)
> > -                     break;
> > +                     break;  /* success */
> > +
> > +             error = gfs2_do_thaw(sdp);
> > +             if (error)
> > +                     goto out;
> >
> >               if (error == -EBUSY)
> >                       fs_err(sdp, "waiting for recovery before freeze\n");
> > @@ -735,8 +806,12 @@ static int gfs2_freeze_super(struct super_block *sb)
> >               fs_err(sdp, "retrying...\n");
> >               msleep(1000);
> >       }
> > -     set_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
> > +
> >   out:
> > +     if (!error) {
> > +             set_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
> > +             atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
> > +     }
> >       mutex_unlock(&sdp->sd_freeze_mutex);
> >       return error;
> >   }
> > @@ -750,17 +825,47 @@ static int gfs2_freeze_super(struct super_block *sb)
> >   static int gfs2_thaw_super(struct super_block *sb)
> >   {
> >       struct gfs2_sbd *sdp = sb->s_fs_info;
> > +     int error;
> >
> > -     mutex_lock(&sdp->sd_freeze_mutex);
> > -     if (atomic_read(&sdp->sd_freeze_state) != SFS_FROZEN ||
> > -         !gfs2_holder_initialized(&sdp->sd_freeze_gh)) {
> > -             mutex_unlock(&sdp->sd_freeze_mutex);
> > -             return -EINVAL;
> > +     if (!mutex_trylock(&sdp->sd_freeze_mutex))
> > +             return -EBUSY;
> > +     error = -EINVAL;
> > +     if (!test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags))
> > +             goto out;
> > +
> > +     gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +
> > +     error = gfs2_do_thaw(sdp);
> > +
> > +     if (!error) {
> > +             clear_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
> > +             atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
> >       }
> > +out:
> > +     mutex_unlock(&sdp->sd_freeze_mutex);
> > +     return error;
> > +}
> > +
> > +void gfs2_thaw_freeze_initiator(struct super_block *sb)
> > +{
> > +     struct gfs2_sbd *sdp = sb->s_fs_info;
> > +
> > +     mutex_lock(&sdp->sd_freeze_mutex);
> > +     if (!test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags))
> > +             goto out;
> >
> >       gfs2_freeze_unlock(&sdp->sd_freeze_gh);
> > +#if 0
> > +     int error;
> > +     error = thaw_super(sb);
> > +     if (error)
> > +             fs_info(sdp, "GFS2: couldn't thaw filesystem: %d\n", error);
> > +     clear_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
> > +     atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
> > +#endif
>
> Can be removed.

Ah, of course, thanks.

Andreas

> Andy
>
> > +
> > +out:
> >       mutex_unlock(&sdp->sd_freeze_mutex);
> > -     return wait_on_bit(&sdp->sd_flags, SDF_FREEZE_INITIATOR, 
> > TASK_INTERRUPTIBLE);
> >   }
> >
> >   /**
> > diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
> > index 58d13fd77aed..bba58629bc45 100644
> > --- a/fs/gfs2/super.h
> > +++ b/fs/gfs2/super.h
> > @@ -46,6 +46,7 @@ extern void gfs2_statfs_change_out(const struct 
> > gfs2_statfs_change_host *sc,
> >   extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh);
> >   extern int gfs2_statfs_sync(struct super_block *sb, int type);
> >   extern void gfs2_freeze_func(struct work_struct *work);
> > +extern void gfs2_thaw_freeze_initiator(struct super_block *sb);
> >
> >   extern void free_local_statfs_inodes(struct gfs2_sbd *sdp);
> >   extern struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp,
> > diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
> > index 1743caee5505..00494dffb47c 100644
> > --- a/fs/gfs2/util.c
> > +++ b/fs/gfs2/util.c
> > @@ -124,7 +124,6 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
> >       struct gfs2_inode *ip;
> >       struct gfs2_glock *i_gl;
> >       u64 no_formal_ino;
> > -     int log_write_allowed = test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
> >       int ret = 0;
> >       int tries;
> >
> > @@ -152,24 +151,18 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
> >        */
> >       clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
> >       if (!sb_rdonly(sdp->sd_vfs)) {
> > -             struct gfs2_holder freeze_gh;
> > -
> > -             gfs2_holder_mark_uninitialized(&freeze_gh);
> > -             if (sdp->sd_freeze_gl &&
> > -                 !gfs2_glock_is_locked_by_me(sdp->sd_freeze_gl)) {
> > -                     ret = gfs2_freeze_lock_shared(sdp, &freeze_gh,
> > -                                     log_write_allowed ? 0 : LM_FLAG_TRY);
> > -                     if (ret == GLR_TRYFAILED)
> > -                             ret = 0;
> > -             }
> > -             if (!ret)
> > -                     gfs2_make_fs_ro(sdp);
> > +             bool locked = mutex_trylock(&sdp->sd_freeze_mutex);
> > +
> > +             gfs2_make_fs_ro(sdp);
> > +
> > +             if (locked)
> > +                     mutex_unlock(&sdp->sd_freeze_mutex);
> > +
> >               /*
> >                * Dequeue any pending non-system glock holders that can no
> >                * longer be granted because the file system is withdrawn.
> >                */
> >               gfs2_gl_dq_holders(sdp);
> > -             gfs2_freeze_unlock(&freeze_gh);
> >       }
> >
> >       if (sdp->sd_lockstruct.ls_ops->lm_lock == NULL) { /* lock_nolock */
> > @@ -187,15 +180,8 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
> >       }
> >       sdp->sd_jinode_gh.gh_flags |= GL_NOCACHE;
> >       gfs2_glock_dq(&sdp->sd_jinode_gh);
> > -     if (test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags)) {
> > -             /* Make sure gfs2_thaw_super works if partially-frozen */
> > -             flush_work(&sdp->sd_freeze_work);
> > -             atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
> > -             thaw_super(sdp->sd_vfs);
> > -     } else {
> > -             wait_on_bit(&i_gl->gl_flags, GLF_DEMOTE,
> > -                         TASK_UNINTERRUPTIBLE);
> > -     }
> > +     gfs2_thaw_freeze_initiator(sdp->sd_vfs);
> > +     wait_on_bit(&i_gl->gl_flags, GLF_DEMOTE, TASK_UNINTERRUPTIBLE);
> >
> >       /*
> >        * holder_uninit to force glock_put, to force dlm to let go
>

Reply via email to