Bob,

On Wed, 1 May 2019 at 01:03, Bob Peterson <rpete...@redhat.com> wrote:
> File system withdraws can be delayed when inconsistencies are
> discovered when we cannot withdraw immediately, for example, when
> critical spin_locks are held. But delaying the withdraw can cause
> gfs2 to ignore the error and keep running for a short period of time.
> For example, an rgrp glock may be dequeued and demoted while there
> are still buffers that haven't been properly revoked, due to io
> errors writing to the journal.
>
> This patch introduces a new concept of a pending withdraw, which
> means an inconsistency has been discovered and we need to withdraw
> at the earliest possible opportunity. In these cases, we aren't
> quite withdrawn yet, but we still need to not dequeue glocks and
> other critical things. If we dequeue the glocks and the withdraw
> results in our journal being replayed, the replay could overwrite
> data that's been modified by a different node that acquired the
> glock in the meantime.

this is looking good. Maybe we can improve our terminology a bit
though: how about SDF_FAULTY instead of SDF_WITHDRAW? Also,
SDF_SHUTDOWN really indicates that a filesystem is being or has been
withdrawn, so maybe that should really be called SDF_WITHDRAW?

Thanks,
Andreas

> Signed-off-by: Bob Peterson <rpete...@redhat.com>
> ---
>  fs/gfs2/aops.c       |  4 ++--
>  fs/gfs2/file.c       |  2 +-
>  fs/gfs2/glock.c      |  7 +++----
>  fs/gfs2/glops.c      |  2 +-
>  fs/gfs2/incore.h     |  1 +
>  fs/gfs2/log.c        | 20 ++++++++------------
>  fs/gfs2/meta_io.c    |  6 +++---
>  fs/gfs2/ops_fstype.c |  3 +--
>  fs/gfs2/quota.c      |  2 +-
>  fs/gfs2/super.c      |  6 +++---
>  fs/gfs2/sys.c        |  2 +-
>  fs/gfs2/util.h       | 12 ++++++++++++
>  12 files changed, 37 insertions(+), 30 deletions(-)
>
> diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
> index 05dd78f4b2b3..2bacce032a34 100644
> --- a/fs/gfs2/aops.c
> +++ b/fs/gfs2/aops.c
> @@ -521,7 +521,7 @@ static int __gfs2_readpage(void *file, struct page *page)
>                 error = mpage_readpage(page, gfs2_block_map);
>         }
>
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
> +       if (unlikely(gfs2_withdrawn(sdp)))
>                 return -EIO;
>
>         return error;
> @@ -638,7 +638,7 @@ static int gfs2_readpages(struct file *file, struct 
> address_space *mapping,
>         gfs2_glock_dq(&gh);
>  out_uninit:
>         gfs2_holder_uninit(&gh);
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
> +       if (unlikely(gfs2_withdrawn(sdp)))
>                 ret = -EIO;
>         return ret;
>  }
> diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> index 58a768e59712..bba39c73a43c 100644
> --- a/fs/gfs2/file.c
> +++ b/fs/gfs2/file.c
> @@ -1169,7 +1169,7 @@ static int gfs2_lock(struct file *file, int cmd, struct 
> file_lock *fl)
>                 cmd = F_SETLK;
>                 fl->fl_type = F_UNLCK;
>         }
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
> +       if (unlikely(gfs2_withdrawn(sdp))) {
>                 if (fl->fl_type == F_UNLCK)
>                         locks_lock_file_wait(file, fl);
>                 return -EIO;
> diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
> index 15c605cfcfc8..fe9f9a22426e 100644
> --- a/fs/gfs2/glock.c
> +++ b/fs/gfs2/glock.c
> @@ -547,7 +547,7 @@ __acquires(&gl->gl_lockref.lock)
>         unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0);
>         int ret;
>
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) &&
> +       if (unlikely(gfs2_withdrawn(sdp)) &&
>             target != LM_ST_UNLOCKED)
>                 return;
>         lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP |
> @@ -584,8 +584,7 @@ __acquires(&gl->gl_lockref.lock)
>                 }
>                 else if (ret) {
>                         fs_err(sdp, "lm_lock ret %d\n", ret);
> -                       GLOCK_BUG_ON(gl, !test_bit(SDF_SHUTDOWN,
> -                                                  &sdp->sd_flags));
> +                       GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp));
>                 }
>         } else { /* lock_nolock */
>                 finish_xmote(gl, target);
> @@ -1097,7 +1096,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
>         struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
>         int error = 0;
>
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
> +       if (unlikely(gfs2_withdrawn(sdp)))
>                 return -EIO;
>
>         if (test_bit(GLF_LRU, &gl->gl_flags))
> diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
> index 78510ab91835..b9f36a85a4d4 100644
> --- a/fs/gfs2/glops.c
> +++ b/fs/gfs2/glops.c
> @@ -538,7 +538,7 @@ static int freeze_go_xmote_bh(struct gfs2_glock *gl, 
> struct gfs2_holder *gh)
>                         gfs2_consist(sdp);
>
>                 /*  Initialize some head of the log stuff  */
> -               if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
> +               if (!gfs2_withdrawn(sdp)) {
>                         sdp->sd_log_sequence = head.lh_sequence + 1;
>                         gfs2_log_pointers_init(sdp, head.lh_blkno);
>                 }
> diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
> index c54800385298..003d9da937b4 100644
> --- a/fs/gfs2/incore.h
> +++ b/fs/gfs2/incore.h
> @@ -620,6 +620,7 @@ enum {
>         SDF_SKIP_DLM_UNLOCK     = 8,
>         SDF_FORCE_AIL_FLUSH     = 9,
>         SDF_AIL1_IO_ERROR       = 10,
> +       SDF_WITHDRAW            = 11, /* Will withdraw eventually */
>  };
>
>  enum gfs2_freeze_state {
> diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
> index 76da6f046379..944aaf3d1816 100644
> --- a/fs/gfs2/log.c
> +++ b/fs/gfs2/log.c
> @@ -92,8 +92,7 @@ static void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
>
>  static int gfs2_ail1_start_one(struct gfs2_sbd *sdp,
>                                struct writeback_control *wbc,
> -                              struct gfs2_trans *tr,
> -                              bool *withdraw)
> +                              struct gfs2_trans *tr)
>  __releases(&sdp->sd_ail_lock)
>  __acquires(&sdp->sd_ail_lock)
>  {
> @@ -112,7 +111,7 @@ __acquires(&sdp->sd_ail_lock)
>                             !test_and_set_bit(SDF_AIL1_IO_ERROR,
>                                               &sdp->sd_flags)) {
>                                 gfs2_io_error_bh(sdp, bh);
> -                               *withdraw = true;
> +                               set_bit(SDF_WITHDRAW, &sdp->sd_flags);
>                         }
>                         list_move(&bd->bd_ail_st_list, &tr->tr_ail2_list);
>                         continue;
> @@ -153,7 +152,6 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct 
> writeback_control *wbc)
>         struct list_head *head = &sdp->sd_ail1_list;
>         struct gfs2_trans *tr;
>         struct blk_plug plug;
> -       bool withdraw = false;
>
>         trace_gfs2_ail_flush(sdp, wbc, 1);
>         blk_start_plug(&plug);
> @@ -162,12 +160,12 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct 
> writeback_control *wbc)
>         list_for_each_entry_reverse(tr, head, tr_list) {
>                 if (wbc->nr_to_write <= 0)
>                         break;
> -               if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw))
> +               if (gfs2_ail1_start_one(sdp, wbc, tr))
>                         goto restart;
>         }
>         spin_unlock(&sdp->sd_ail_lock);
>         blk_finish_plug(&plug);
> -       if (withdraw)
> +       if (test_bit(SDF_WITHDRAW, &sdp->sd_flags))
>                 gfs2_lm_withdraw(sdp, NULL);
>         trace_gfs2_ail_flush(sdp, wbc, 0);
>  }
> @@ -196,8 +194,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp)
>   *
>   */
>
> -static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
> -                               bool *withdraw)
> +static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
>  {
>         struct gfs2_bufdata *bd, *s;
>         struct buffer_head *bh;
> @@ -211,7 +208,7 @@ static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, 
> struct gfs2_trans *tr,
>                 if (!buffer_uptodate(bh) &&
>                     !test_and_set_bit(SDF_AIL1_IO_ERROR, &sdp->sd_flags)) {
>                         gfs2_io_error_bh(sdp, bh);
> -                       *withdraw = true;
> +                       set_bit(SDF_WITHDRAW, &sdp->sd_flags);
>                 }
>                 list_move(&bd->bd_ail_st_list, &tr->tr_ail2_list);
>         }
> @@ -229,11 +226,10 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp)
>         struct gfs2_trans *tr, *s;
>         int oldest_tr = 1;
>         int ret;
> -       bool withdraw = false;
>
>         spin_lock(&sdp->sd_ail_lock);
>         list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) {
> -               gfs2_ail1_empty_one(sdp, tr, &withdraw);
> +               gfs2_ail1_empty_one(sdp, tr);
>                 if (list_empty(&tr->tr_ail1_list) && oldest_tr)
>                         list_move(&tr->tr_list, &sdp->sd_ail2_list);
>                 else
> @@ -242,7 +238,7 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp)
>         ret = list_empty(&sdp->sd_ail1_list);
>         spin_unlock(&sdp->sd_ail_lock);
>
> -       if (withdraw)
> +       if (test_bit(SDF_WITHDRAW, &sdp->sd_flags))
>                 gfs2_lm_withdraw(sdp, "fatal: I/O error(s)\n");
>
>         return ret;
> diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
> index 3201342404a7..b125008f064f 100644
> --- a/fs/gfs2/meta_io.c
> +++ b/fs/gfs2/meta_io.c
> @@ -255,7 +255,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int 
> flags,
>         struct buffer_head *bh, *bhs[2];
>         int num = 0;
>
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
> +       if (unlikely(gfs2_withdrawn(sdp))) {
>                 *bhp = NULL;
>                 return -EIO;
>         }
> @@ -313,7 +313,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int 
> flags,
>
>  int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
>  {
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
> +       if (unlikely(gfs2_withdrawn(sdp)))
>                 return -EIO;
>
>         wait_on_buffer(bh);
> @@ -324,7 +324,7 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct 
> buffer_head *bh)
>                         gfs2_io_error_bh_wd(sdp, bh);
>                 return -EIO;
>         }
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
> +       if (unlikely(gfs2_withdrawn(sdp)))
>                 return -EIO;
>
>         return 0;
> diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
> index abfaecde0e3d..075f64075ff6 100644
> --- a/fs/gfs2/ops_fstype.c
> +++ b/fs/gfs2/ops_fstype.c
> @@ -998,8 +998,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
>  void gfs2_lm_unmount(struct gfs2_sbd *sdp)
>  {
>         const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops;
> -       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) &&
> -           lm->lm_unmount)
> +       if (likely(!gfs2_withdrawn(sdp)) && lm->lm_unmount)
>                 lm->lm_unmount(sdp);
>  }
>
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index 2ae5a109eea7..a8dfc86fd682 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1478,7 +1478,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const 
> char *msg, int error)
>  {
>         if (error == 0 || error == -EROFS)
>                 return;
> -       if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
> +       if (!gfs2_withdrawn(sdp)) {
>                 fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error);
>                 sdp->sd_log_error = error;
>                 wake_up(&sdp->sd_logd_waitq);
> diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
> index dc4ec1ca3d4e..378519beb6c3 100644
> --- a/fs/gfs2/super.c
> +++ b/fs/gfs2/super.c
> @@ -807,7 +807,7 @@ static void gfs2_dirty_inode(struct inode *inode, int 
> flags)
>
>         if (!(flags & I_DIRTY_INODE))
>                 return;
> -       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
> +       if (unlikely(gfs2_withdrawn(sdp)))
>                 return;
>         if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
>                 ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
> @@ -856,7 +856,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
>
>         error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 
> GL_NOCACHE,
>                                    &freeze_gh);
> -       if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
> +       if (error && !gfs2_withdrawn(sdp))
>                 return error;
>
>         flush_workqueue(gfs2_delete_workqueue);
> @@ -1014,7 +1014,7 @@ static int gfs2_freeze(struct super_block *sb)
>         if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
>                 goto out;
>
> -       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
> +       if (gfs2_withdrawn(sdp)) {
>                 error = -EINVAL;
>                 goto out;
>         }
> diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
> index 1787d295834e..b772ff5509bb 100644
> --- a/fs/gfs2/sys.c
> +++ b/fs/gfs2/sys.c
> @@ -121,7 +121,7 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const 
> char *buf, size_t len)
>
>  static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
>  {
> -       unsigned int b = test_bit(SDF_SHUTDOWN, &sdp->sd_flags);
> +       unsigned int b = gfs2_withdrawn(sdp);
>         return snprintf(buf, PAGE_SIZE, "%u\n", b);
>  }
>
> diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
> index 9278fecba632..0df65555545f 100644
> --- a/fs/gfs2/util.h
> +++ b/fs/gfs2/util.h
> @@ -167,6 +167,18 @@ static inline unsigned int gfs2_tune_get_i(struct 
> gfs2_tune *gt,
>         return x;
>  }
>
> +/**
> + * gfs2_withdrawn - test whether the file system is withdrawing or withdrawn
> + * @sdp: the superblock
> + */
> +static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
> +{
> +       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags) ||
> +           test_bit(SDF_WITHDRAW, &sdp->sd_flags))
> +               return true;
> +       return false;
> +}
> +
>  #define gfs2_tune_get(sdp, field) \
>  gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
>
> --
> 2.20.1
>

Reply via email to