Commit bfed9a92 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gfs2-v6.7-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull gfs2 updates from Andreas Gruenbacher:

 - Add support for non-blocking lookup (MAY_NOT_BLOCK / LOOKUP_RCU)

 - Various minor fixes and cleanups

* tag 'gfs2-v6.7-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Fix freeze consistency check in log_write_header
  gfs2: Refcounting fix in gfs2_thaw_super
  gfs2: Minor gfs2_{freeze,thaw}_super cleanup
  gfs2: Use wait_event_freezable_timeout() for freezable kthread
  gfs2: Add missing set_freezable() for freezable kthread
  gfs2: Remove use of error flag in journal reads
  gfs2: Lift withdraw check out of gfs2_ail1_empty
  gfs2: Rename gfs2_withdrawn to gfs2_withdrawing_or_withdrawn
  gfs2: Mark withdraws as unlikely
  gfs2: Minor gfs2_ail1_empty cleanup
  gfs2: use is_subdir()
  gfs2: d_obtain_alias(ERR_PTR(...)) will do the right thing
  gfs2: Use GL_NOBLOCK flag for non-blocking lookups
  gfs2: Add GL_NOBLOCK flag
  gfs2: rgrp: fix kernel-doc warnings
  gfs2: fix kernel BUG in gfs2_quota_cleanup
  gfs2: Fix inode_go_instantiate description
  gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump
parents affc5af3 e345b87b
...@@ -459,7 +459,7 @@ static int gfs2_read_folio(struct file *file, struct folio *folio) ...@@ -459,7 +459,7 @@ static int gfs2_read_folio(struct file *file, struct folio *folio)
error = mpage_read_folio(folio, gfs2_block_map); error = mpage_read_folio(folio, gfs2_block_map);
} }
if (unlikely(gfs2_withdrawn(sdp))) if (gfs2_withdrawing_or_withdrawn(sdp))
return -EIO; return -EIO;
return error; return error;
......
...@@ -32,21 +32,25 @@ ...@@ -32,21 +32,25 @@
static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
{ {
struct dentry *parent; struct dentry *parent = NULL;
struct gfs2_sbd *sdp; struct gfs2_sbd *sdp;
struct gfs2_inode *dip; struct gfs2_inode *dip;
struct inode *inode; struct inode *dinode, *inode;
struct gfs2_holder d_gh; struct gfs2_holder d_gh;
struct gfs2_inode *ip = NULL; struct gfs2_inode *ip = NULL;
int error, valid = 0; int error, valid = 0;
int had_lock = 0; int had_lock = 0;
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU) {
return -ECHILD; dinode = d_inode_rcu(READ_ONCE(dentry->d_parent));
if (!dinode)
parent = dget_parent(dentry); return -ECHILD;
sdp = GFS2_SB(d_inode(parent)); } else {
dip = GFS2_I(d_inode(parent)); parent = dget_parent(dentry);
dinode = d_inode(parent);
}
sdp = GFS2_SB(dinode);
dip = GFS2_I(dinode);
inode = d_inode(dentry); inode = d_inode(dentry);
if (inode) { if (inode) {
...@@ -62,7 +66,8 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) ...@@ -62,7 +66,8 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL); had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
if (!had_lock) { if (!had_lock) {
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
flags & LOOKUP_RCU ? GL_NOBLOCK : 0, &d_gh);
if (error) if (error)
goto out; goto out;
} }
......
...@@ -138,8 +138,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, ...@@ -138,8 +138,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino, inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino,
GFS2_BLKST_DINODE); GFS2_BLKST_DINODE);
if (IS_ERR(inode))
return ERR_CAST(inode);
return d_obtain_alias(inode); return d_obtain_alias(inode);
} }
......
...@@ -1442,7 +1442,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) ...@@ -1442,7 +1442,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_POSIX)) if (!(fl->fl_flags & FL_POSIX))
return -ENOLCK; return -ENOLCK;
if (unlikely(gfs2_withdrawn(sdp))) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
if (fl->fl_type == F_UNLCK) if (fl->fl_type == F_UNLCK)
locks_lock_file_wait(file, fl); locks_lock_file_wait(file, fl);
return -EIO; return -EIO;
......
...@@ -156,7 +156,7 @@ static bool glock_blocked_by_withdraw(struct gfs2_glock *gl) ...@@ -156,7 +156,7 @@ static bool glock_blocked_by_withdraw(struct gfs2_glock *gl)
{ {
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
if (likely(!gfs2_withdrawn(sdp))) if (!gfs2_withdrawing_or_withdrawn(sdp))
return false; return false;
if (gl->gl_ops->go_flags & GLOF_NONDISK) if (gl->gl_ops->go_flags & GLOF_NONDISK)
return false; return false;
...@@ -278,7 +278,7 @@ static void __gfs2_glock_put(struct gfs2_glock *gl) ...@@ -278,7 +278,7 @@ static void __gfs2_glock_put(struct gfs2_glock *gl)
GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
if (mapping) { if (mapping) {
truncate_inode_pages_final(mapping); truncate_inode_pages_final(mapping);
if (!gfs2_withdrawn(sdp)) if (!gfs2_withdrawing_or_withdrawn(sdp))
GLOCK_BUG_ON(gl, !mapping_empty(mapping)); GLOCK_BUG_ON(gl, !mapping_empty(mapping));
} }
trace_gfs2_glock_put(gl); trace_gfs2_glock_put(gl);
...@@ -516,6 +516,23 @@ static inline struct gfs2_holder *find_first_waiter(const struct gfs2_glock *gl) ...@@ -516,6 +516,23 @@ static inline struct gfs2_holder *find_first_waiter(const struct gfs2_glock *gl)
return NULL; return NULL;
} }
/**
* find_last_waiter - find the last gh that's waiting for the glock
* @gl: the glock
*
* This also is a fast way of finding out if there are any waiters.
*/
static inline struct gfs2_holder *find_last_waiter(const struct gfs2_glock *gl)
{
struct gfs2_holder *gh;
if (list_empty(&gl->gl_holders))
return NULL;
gh = list_last_entry(&gl->gl_holders, struct gfs2_holder, gh_list);
return test_bit(HIF_HOLDER, &gh->gh_iflags) ? NULL : gh;
}
/** /**
* state_change - record that the glock is now in a different state * state_change - record that the glock is now in a different state
* @gl: the glock * @gl: the glock
...@@ -757,7 +774,7 @@ __acquires(&gl->gl_lockref.lock) ...@@ -757,7 +774,7 @@ __acquires(&gl->gl_lockref.lock)
* gfs2_gl_hash_clear calls clear_glock) and recovery is complete * gfs2_gl_hash_clear calls clear_glock) and recovery is complete
* then it's okay to tell dlm to unlock it. * then it's okay to tell dlm to unlock it.
*/ */
if (unlikely(sdp->sd_log_error && !gfs2_withdrawn(sdp))) if (unlikely(sdp->sd_log_error) && !gfs2_withdrawing_or_withdrawn(sdp))
gfs2_withdraw_delayed(sdp); gfs2_withdraw_delayed(sdp);
if (glock_blocked_by_withdraw(gl) && if (glock_blocked_by_withdraw(gl) &&
(target != LM_ST_UNLOCKED || (target != LM_ST_UNLOCKED ||
...@@ -794,7 +811,7 @@ __acquires(&gl->gl_lockref.lock) ...@@ -794,7 +811,7 @@ __acquires(&gl->gl_lockref.lock)
gfs2_glock_queue_work(gl, 0); gfs2_glock_queue_work(gl, 0);
} else if (ret) { } else if (ret) {
fs_err(sdp, "lm_lock ret %d\n", ret); fs_err(sdp, "lm_lock ret %d\n", ret);
GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp)); GLOCK_BUG_ON(gl, !gfs2_withdrawing_or_withdrawn(sdp));
} }
} else { /* lock_nolock */ } else { /* lock_nolock */
finish_xmote(gl, target); finish_xmote(gl, target);
...@@ -1555,11 +1572,30 @@ __acquires(&gl->gl_lockref.lock) ...@@ -1555,11 +1572,30 @@ __acquires(&gl->gl_lockref.lock)
int gfs2_glock_nq(struct gfs2_holder *gh) int gfs2_glock_nq(struct gfs2_holder *gh)
{ {
struct gfs2_glock *gl = gh->gh_gl; struct gfs2_glock *gl = gh->gh_gl;
int error = 0; int error;
if (glock_blocked_by_withdraw(gl) && !(gh->gh_flags & LM_FLAG_NOEXP)) if (glock_blocked_by_withdraw(gl) && !(gh->gh_flags & LM_FLAG_NOEXP))
return -EIO; return -EIO;
if (gh->gh_flags & GL_NOBLOCK) {
struct gfs2_holder *current_gh;
error = -ECHILD;
spin_lock(&gl->gl_lockref.lock);
if (find_last_waiter(gl))
goto unlock;
current_gh = find_first_holder(gl);
if (!may_grant(gl, current_gh, gh))
goto unlock;
set_bit(HIF_HOLDER, &gh->gh_iflags);
list_add_tail(&gh->gh_list, &gl->gl_holders);
trace_gfs2_promote(gh);
error = 0;
unlock:
spin_unlock(&gl->gl_lockref.lock);
return error;
}
if (test_bit(GLF_LRU, &gl->gl_flags)) if (test_bit(GLF_LRU, &gl->gl_flags))
gfs2_glock_remove_from_lru(gl); gfs2_glock_remove_from_lru(gl);
...@@ -1575,6 +1611,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh) ...@@ -1575,6 +1611,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
run_queue(gl, 1); run_queue(gl, 1);
spin_unlock(&gl->gl_lockref.lock); spin_unlock(&gl->gl_lockref.lock);
error = 0;
if (!(gh->gh_flags & GL_ASYNC)) if (!(gh->gh_flags & GL_ASYNC))
error = gfs2_glock_wait(gh); error = gfs2_glock_wait(gh);
......
...@@ -84,6 +84,7 @@ enum { ...@@ -84,6 +84,7 @@ enum {
#define GL_SKIP 0x0100 #define GL_SKIP 0x0100
#define GL_NOPID 0x0200 #define GL_NOPID 0x0200
#define GL_NOCACHE 0x0400 #define GL_NOCACHE 0x0400
#define GL_NOBLOCK 0x0800
/* /*
* lm_async_cb return flags * lm_async_cb return flags
......
...@@ -174,7 +174,7 @@ static int gfs2_rgrp_metasync(struct gfs2_glock *gl) ...@@ -174,7 +174,7 @@ static int gfs2_rgrp_metasync(struct gfs2_glock *gl)
filemap_fdatawrite_range(metamapping, start, end); filemap_fdatawrite_range(metamapping, start, end);
error = filemap_fdatawait_range(metamapping, start, end); error = filemap_fdatawait_range(metamapping, start, end);
WARN_ON_ONCE(error && !gfs2_withdrawn(sdp)); WARN_ON_ONCE(error && !gfs2_withdrawing_or_withdrawn(sdp));
mapping_set_error(metamapping, error); mapping_set_error(metamapping, error);
if (error) if (error)
gfs2_io_error(sdp); gfs2_io_error(sdp);
...@@ -494,7 +494,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) ...@@ -494,7 +494,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip)
/** /**
* inode_go_instantiate - read in an inode if necessary * inode_go_instantiate - read in an inode if necessary
* @gh: The glock holder * @gl: The glock
* *
* Returns: errno * Returns: errno
*/ */
......
...@@ -1882,10 +1882,10 @@ int gfs2_permission(struct mnt_idmap *idmap, struct inode *inode, ...@@ -1882,10 +1882,10 @@ int gfs2_permission(struct mnt_idmap *idmap, struct inode *inode,
WARN_ON_ONCE(!may_not_block); WARN_ON_ONCE(!may_not_block);
return -ECHILD; return -ECHILD;
} }
if (gfs2_glock_is_locked_by_me(gl) == NULL) { if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
if (may_not_block) int noblock = may_not_block ? GL_NOBLOCK : 0;
return -ECHILD; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); LM_FLAG_ANY | noblock, &i_gh);
if (error) if (error)
return error; return error;
} }
......
...@@ -1122,7 +1122,7 @@ static void gdlm_recover_prep(void *arg) ...@@ -1122,7 +1122,7 @@ static void gdlm_recover_prep(void *arg)
struct gfs2_sbd *sdp = arg; struct gfs2_sbd *sdp = arg;
struct lm_lockstruct *ls = &sdp->sd_lockstruct; struct lm_lockstruct *ls = &sdp->sd_lockstruct;
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_err(sdp, "recover_prep ignored due to withdraw.\n"); fs_err(sdp, "recover_prep ignored due to withdraw.\n");
return; return;
} }
...@@ -1148,7 +1148,7 @@ static void gdlm_recover_slot(void *arg, struct dlm_slot *slot) ...@@ -1148,7 +1148,7 @@ static void gdlm_recover_slot(void *arg, struct dlm_slot *slot)
struct lm_lockstruct *ls = &sdp->sd_lockstruct; struct lm_lockstruct *ls = &sdp->sd_lockstruct;
int jid = slot->slot - 1; int jid = slot->slot - 1;
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_err(sdp, "recover_slot jid %d ignored due to withdraw.\n", fs_err(sdp, "recover_slot jid %d ignored due to withdraw.\n",
jid); jid);
return; return;
...@@ -1177,7 +1177,7 @@ static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots, ...@@ -1177,7 +1177,7 @@ static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots,
struct gfs2_sbd *sdp = arg; struct gfs2_sbd *sdp = arg;
struct lm_lockstruct *ls = &sdp->sd_lockstruct; struct lm_lockstruct *ls = &sdp->sd_lockstruct;
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_err(sdp, "recover_done ignored due to withdraw.\n"); fs_err(sdp, "recover_done ignored due to withdraw.\n");
return; return;
} }
...@@ -1208,7 +1208,7 @@ static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid, ...@@ -1208,7 +1208,7 @@ static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid,
{ {
struct lm_lockstruct *ls = &sdp->sd_lockstruct; struct lm_lockstruct *ls = &sdp->sd_lockstruct;
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_err(sdp, "recovery_result jid %d ignored due to withdraw.\n", fs_err(sdp, "recovery_result jid %d ignored due to withdraw.\n",
jid); jid);
return; return;
......
...@@ -126,7 +126,7 @@ __acquires(&sdp->sd_ail_lock) ...@@ -126,7 +126,7 @@ __acquires(&sdp->sd_ail_lock)
} }
} }
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
gfs2_remove_from_ail(bd); gfs2_remove_from_ail(bd);
continue; continue;
} }
...@@ -352,14 +352,15 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr, ...@@ -352,14 +352,15 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
* @sdp: The superblock * @sdp: The superblock
* @max_revokes: If non-zero, add revokes where appropriate * @max_revokes: If non-zero, add revokes where appropriate
* *
* Tries to empty the ail1 lists, starting with the oldest first * Tries to empty the ail1 lists, starting with the oldest first.
* Returns %true if the ail1 list is now empty.
*/ */
static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int max_revokes) static bool gfs2_ail1_empty(struct gfs2_sbd *sdp, int max_revokes)
{ {
struct gfs2_trans *tr, *s; struct gfs2_trans *tr, *s;
int oldest_tr = 1; int oldest_tr = 1;
int ret; bool empty;
spin_lock(&sdp->sd_ail_lock); spin_lock(&sdp->sd_ail_lock);
list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) { list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) {
...@@ -369,15 +370,10 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int max_revokes) ...@@ -369,15 +370,10 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int max_revokes)
oldest_tr = 0; oldest_tr = 0;
} }
gfs2_log_update_flush_tail(sdp); gfs2_log_update_flush_tail(sdp);
ret = list_empty(&sdp->sd_ail1_list); empty = list_empty(&sdp->sd_ail1_list);
spin_unlock(&sdp->sd_ail_lock); spin_unlock(&sdp->sd_ail_lock);
if (test_bit(SDF_WITHDRAWING, &sdp->sd_flags)) { return empty;
gfs2_lm(sdp, "fatal: I/O error(s)\n");
gfs2_withdraw(sdp);
}
return ret;
} }
static void gfs2_ail1_wait(struct gfs2_sbd *sdp) static void gfs2_ail1_wait(struct gfs2_sbd *sdp)
...@@ -814,6 +810,9 @@ void gfs2_flush_revokes(struct gfs2_sbd *sdp) ...@@ -814,6 +810,9 @@ void gfs2_flush_revokes(struct gfs2_sbd *sdp)
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
gfs2_ail1_empty(sdp, max_revokes); gfs2_ail1_empty(sdp, max_revokes);
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
if (gfs2_withdrawing(sdp))
gfs2_withdraw(sdp);
} }
/** /**
...@@ -841,7 +840,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, ...@@ -841,7 +840,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
struct super_block *sb = sdp->sd_vfs; struct super_block *sb = sdp->sd_vfs;
u64 dblock; u64 dblock;
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
return; return;
page = mempool_alloc(gfs2_page_pool, GFP_NOIO); page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
...@@ -914,8 +913,9 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, ...@@ -914,8 +913,9 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
static void log_write_header(struct gfs2_sbd *sdp, u32 flags) static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
{ {
blk_opf_t op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC; blk_opf_t op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC;
struct super_block *sb = sdp->sd_vfs;
gfs2_assert_withdraw(sdp, !test_bit(SDF_FROZEN, &sdp->sd_flags)); gfs2_assert_withdraw(sdp, sb->s_writers.frozen != SB_FREEZE_COMPLETE);
if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) { if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
gfs2_ordered_wait(sdp); gfs2_ordered_wait(sdp);
...@@ -974,8 +974,9 @@ void gfs2_ail_drain(struct gfs2_sbd *sdp) ...@@ -974,8 +974,9 @@ void gfs2_ail_drain(struct gfs2_sbd *sdp)
static void empty_ail1_list(struct gfs2_sbd *sdp) static void empty_ail1_list(struct gfs2_sbd *sdp)
{ {
unsigned long start = jiffies; unsigned long start = jiffies;
bool empty = false;
for (;;) { while (!empty) {
if (time_after(jiffies, start + (HZ * 600))) { if (time_after(jiffies, start + (HZ * 600))) {
fs_err(sdp, "Error: In %s for 10 minutes! t=%d\n", fs_err(sdp, "Error: In %s for 10 minutes! t=%d\n",
__func__, current->journal_info ? 1 : 0); __func__, current->journal_info ? 1 : 0);
...@@ -984,9 +985,14 @@ static void empty_ail1_list(struct gfs2_sbd *sdp) ...@@ -984,9 +985,14 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
} }
gfs2_ail1_start(sdp); gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp); gfs2_ail1_wait(sdp);
if (gfs2_ail1_empty(sdp, 0)) empty = gfs2_ail1_empty(sdp, 0);
return;
if (gfs2_withdrawing_or_withdrawn(sdp))
break;
} }
if (gfs2_withdrawing(sdp))
gfs2_withdraw(sdp);
} }
/** /**
...@@ -1047,7 +1053,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ...@@ -1047,7 +1053,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
* Do this check while holding the log_flush_lock to prevent new * Do this check while holding the log_flush_lock to prevent new
* buffers from being added to the ail via gfs2_pin() * buffers from being added to the ail via gfs2_pin()
*/ */
if (gfs2_withdrawn(sdp) || !test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) if (gfs2_withdrawing_or_withdrawn(sdp) ||
!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
goto out; goto out;
/* Log might have been flushed while we waited for the flush lock */ /* Log might have been flushed while we waited for the flush lock */
...@@ -1096,13 +1103,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ...@@ -1096,13 +1103,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
goto out_withdraw; goto out_withdraw;
gfs2_ordered_write(sdp); gfs2_ordered_write(sdp);
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw; goto out_withdraw;
lops_before_commit(sdp, tr); lops_before_commit(sdp, tr);
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw; goto out_withdraw;
gfs2_log_submit_bio(&sdp->sd_jdesc->jd_log_bio, REQ_OP_WRITE); gfs2_log_submit_bio(&sdp->sd_jdesc->jd_log_bio, REQ_OP_WRITE);
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw; goto out_withdraw;
if (sdp->sd_log_head != sdp->sd_log_flush_head) { if (sdp->sd_log_head != sdp->sd_log_flush_head) {
...@@ -1110,7 +1117,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ...@@ -1110,7 +1117,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
} else if (sdp->sd_log_tail != sdp->sd_log_flush_tail && !sdp->sd_log_idle) { } else if (sdp->sd_log_tail != sdp->sd_log_flush_tail && !sdp->sd_log_idle) {
log_write_header(sdp, flags); log_write_header(sdp, flags);
} }
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw; goto out_withdraw;
lops_after_commit(sdp, tr); lops_after_commit(sdp, tr);
...@@ -1128,7 +1135,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ...@@ -1128,7 +1135,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
if (!(flags & GFS2_LOG_HEAD_FLUSH_NORMAL)) { if (!(flags & GFS2_LOG_HEAD_FLUSH_NORMAL)) {
if (!sdp->sd_log_idle) { if (!sdp->sd_log_idle) {
empty_ail1_list(sdp); empty_ail1_list(sdp);
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw; goto out_withdraw;
log_write_header(sdp, flags); log_write_header(sdp, flags);
} }
...@@ -1297,8 +1304,9 @@ int gfs2_logd(void *data) ...@@ -1297,8 +1304,9 @@ int gfs2_logd(void *data)
struct gfs2_sbd *sdp = data; struct gfs2_sbd *sdp = data;
unsigned long t = 1; unsigned long t = 1;
set_freezable();
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
break; break;
/* Check for errors writing to the journal */ /* Check for errors writing to the journal */
...@@ -1330,18 +1338,19 @@ int gfs2_logd(void *data) ...@@ -1330,18 +1338,19 @@ int gfs2_logd(void *data)
t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
try_to_freeze(); t = wait_event_freezable_timeout(sdp->sd_logd_waitq,
t = wait_event_interruptible_timeout(sdp->sd_logd_waitq,
test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) ||
gfs2_ail_flush_reqd(sdp) || gfs2_ail_flush_reqd(sdp) ||
gfs2_jrnl_flush_reqd(sdp) || gfs2_jrnl_flush_reqd(sdp) ||
sdp->sd_log_error || sdp->sd_log_error ||
gfs2_withdrawn(sdp) || gfs2_withdrawing_or_withdrawn(sdp) ||
kthread_should_stop(), kthread_should_stop(),
t); t);
} }
if (gfs2_withdrawing(sdp))
gfs2_withdraw(sdp);
return 0; return 0;
} }
...@@ -391,22 +391,15 @@ static void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page) ...@@ -391,22 +391,15 @@ static void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
* Simply unlock the pages in the bio. The main thread will wait on them and * Simply unlock the pages in the bio. The main thread will wait on them and
* process them in order as necessary. * process them in order as necessary.
*/ */
static void gfs2_end_log_read(struct bio *bio) static void gfs2_end_log_read(struct bio *bio)
{ {
struct page *page; int error = blk_status_to_errno(bio->bi_status);
struct bio_vec *bvec; struct folio_iter fi;
struct bvec_iter_all iter_all;
bio_for_each_segment_all(bvec, bio, iter_all) { bio_for_each_folio_all(fi, bio) {
page = bvec->bv_page; /* We're abusing wb_err to get the error to gfs2_find_jhead */
if (bio->bi_status) { filemap_set_wb_err(fi.folio->mapping, error);
int err = blk_status_to_errno(bio->bi_status); folio_end_read(fi.folio, !error);
SetPageError(page);
mapping_set_error(page->mapping, err);
}
unlock_page(page);
} }
bio_put(bio); bio_put(bio);
...@@ -475,7 +468,7 @@ static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index, ...@@ -475,7 +468,7 @@ static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index,
folio = filemap_get_folio(jd->jd_inode->i_mapping, index); folio = filemap_get_folio(jd->jd_inode->i_mapping, index);
folio_wait_locked(folio); folio_wait_locked(folio);
if (folio_test_error(folio)) if (!folio_test_uptodate(folio))
*done = true; *done = true;
if (!*done) if (!*done)
......
...@@ -252,7 +252,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, ...@@ -252,7 +252,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
struct buffer_head *bh, *bhs[2]; struct buffer_head *bh, *bhs[2];
int num = 0; int num = 0;
if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp) &&
!gfs2_withdraw_in_prog(sdp)) {
*bhp = NULL; *bhp = NULL;
return -EIO; return -EIO;
} }
...@@ -310,7 +311,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, ...@@ -310,7 +311,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
{ {
if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp) &&
!gfs2_withdraw_in_prog(sdp))
return -EIO; return -EIO;
wait_on_buffer(bh); wait_on_buffer(bh);
...@@ -321,7 +323,8 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) ...@@ -321,7 +323,8 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
gfs2_io_error_bh_wd(sdp, bh); gfs2_io_error_bh_wd(sdp, bh);
return -EIO; return -EIO;
} }
if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp) &&
!gfs2_withdraw_in_prog(sdp))
return -EIO; return -EIO;
return 0; return 0;
......
...@@ -1073,7 +1073,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) ...@@ -1073,7 +1073,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
void gfs2_lm_unmount(struct gfs2_sbd *sdp) void gfs2_lm_unmount(struct gfs2_sbd *sdp)
{ {
const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops; const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops;
if (likely(!gfs2_withdrawn(sdp)) && lm->lm_unmount) if (!gfs2_withdrawing_or_withdrawn(sdp) && lm->lm_unmount)
lm->lm_unmount(sdp); lm->lm_unmount(sdp);
} }
......
...@@ -128,7 +128,7 @@ static void gfs2_qd_dispose(struct gfs2_quota_data *qd) ...@@ -128,7 +128,7 @@ static void gfs2_qd_dispose(struct gfs2_quota_data *qd)
hlist_bl_del_rcu(&qd->qd_hlist); hlist_bl_del_rcu(&qd->qd_hlist);
spin_unlock_bucket(qd->qd_hash); spin_unlock_bucket(qd->qd_hash);
if (!gfs2_withdrawn(sdp)) { if (!gfs2_withdrawing_or_withdrawn(sdp)) {
gfs2_assert_warn(sdp, !qd->qd_change); gfs2_assert_warn(sdp, !qd->qd_change);
gfs2_assert_warn(sdp, !qd->qd_slot_ref); gfs2_assert_warn(sdp, !qd->qd_slot_ref);
gfs2_assert_warn(sdp, !qd->qd_bh_count); gfs2_assert_warn(sdp, !qd->qd_bh_count);
...@@ -1505,7 +1505,8 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp) ...@@ -1505,7 +1505,8 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
LIST_HEAD(dispose); LIST_HEAD(dispose);
int count; int count;
BUG_ON(test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); BUG_ON(!test_bit(SDF_NORECOVERY, &sdp->sd_flags) &&
test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
spin_lock(&qd_lock); spin_lock(&qd_lock);
list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
...@@ -1539,7 +1540,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error) ...@@ -1539,7 +1540,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error)
{ {
if (error == 0 || error == -EROFS) if (error == 0 || error == -EROFS)
return; return;
if (!gfs2_withdrawn(sdp)) { if (!gfs2_withdrawing_or_withdrawn(sdp)) {
if (!cmpxchg(&sdp->sd_log_error, 0, error)) if (!cmpxchg(&sdp->sd_log_error, 0, error))
fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error); fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error);
wake_up(&sdp->sd_logd_waitq); wake_up(&sdp->sd_logd_waitq);
...@@ -1582,8 +1583,9 @@ int gfs2_quotad(void *data) ...@@ -1582,8 +1583,9 @@ int gfs2_quotad(void *data)
unsigned long quotad_timeo = 0; unsigned long quotad_timeo = 0;
unsigned long t = 0; unsigned long t = 0;
set_freezable();
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
break; break;
/* Update the master statfs file */ /* Update the master statfs file */
...@@ -1601,13 +1603,11 @@ int gfs2_quotad(void *data) ...@@ -1601,13 +1603,11 @@ int gfs2_quotad(void *data)
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
&quotad_timeo, &tune->gt_quota_quantum); &quotad_timeo, &tune->gt_quota_quantum);
try_to_freeze();
t = min(quotad_timeo, statfs_timeo); t = min(quotad_timeo, statfs_timeo);
t = wait_event_interruptible_timeout(sdp->sd_quota_wait, t = wait_event_freezable_timeout(sdp->sd_quota_wait,
sdp->sd_statfs_force_sync || sdp->sd_statfs_force_sync ||
gfs2_withdrawn(sdp) || gfs2_withdrawing_or_withdrawn(sdp) ||
kthread_should_stop(), kthread_should_stop(),
t); t);
......
...@@ -411,7 +411,7 @@ void gfs2_recover_func(struct work_struct *work) ...@@ -411,7 +411,7 @@ void gfs2_recover_func(struct work_struct *work)
int error = 0; int error = 0;
int jlocked = 0; int jlocked = 0;
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_err(sdp, "jid=%u: Recovery not attempted due to withdraw.\n", fs_err(sdp, "jid=%u: Recovery not attempted due to withdraw.\n",
jd->jd_jid); jd->jd_jid);
goto fail; goto fail;
......
...@@ -159,13 +159,13 @@ static inline u8 gfs2_testbit(const struct gfs2_rbm *rbm, bool use_clone) ...@@ -159,13 +159,13 @@ static inline u8 gfs2_testbit(const struct gfs2_rbm *rbm, bool use_clone)
} }
/** /**
* gfs2_bit_search * gfs2_bit_search - search bitmap for a state
* @ptr: Pointer to bitmap data * @ptr: Pointer to bitmap data
* @mask: Mask to use (normally 0x55555.... but adjusted for search start) * @mask: Mask to use (normally 0x55555.... but adjusted for search start)
* @state: The state we are searching for * @state: The state we are searching for
* *
* We xor the bitmap data with a patter which is the bitwise opposite * We xor the bitmap data with a pattern which is the bitwise opposite
* of what we are looking for, this gives rise to a pattern of ones * of what we are looking for. This gives rise to a pattern of ones
* wherever there is a match. Since we have two bits per entry, we * wherever there is a match. Since we have two bits per entry, we
* take this pattern, shift it down by one place and then and it with * take this pattern, shift it down by one place and then and it with
* the original. All the even bit positions (0,2,4, etc) then represent * the original. All the even bit positions (0,2,4, etc) then represent
...@@ -1188,7 +1188,7 @@ static void rgrp_set_bitmap_flags(struct gfs2_rgrpd *rgd) ...@@ -1188,7 +1188,7 @@ static void rgrp_set_bitmap_flags(struct gfs2_rgrpd *rgd)
/** /**
* gfs2_rgrp_go_instantiate - Read in a RG's header and bitmaps * gfs2_rgrp_go_instantiate - Read in a RG's header and bitmaps
* @gh: the glock holder representing the rgrpd to read in * @gl: the glock representing the rgrpd to read in
* *
* Read in all of a Resource Group's header and bitmap blocks. * Read in all of a Resource Group's header and bitmap blocks.
* Caller must eventually call gfs2_rgrp_brelse() to free the bitmaps. * Caller must eventually call gfs2_rgrp_brelse() to free the bitmaps.
...@@ -1967,7 +1967,7 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops) ...@@ -1967,7 +1967,7 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops)
} }
/** /**
* gfs2_rgrp_used_recently * gfs2_rgrp_used_recently - test if an rgrp has been used recently
* @rs: The block reservation with the rgrp to test * @rs: The block reservation with the rgrp to test
* @msecs: The time limit in milliseconds * @msecs: The time limit in milliseconds
* *
...@@ -2306,7 +2306,7 @@ void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd, ...@@ -2306,7 +2306,7 @@ void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd,
(unsigned long long)rgd->rd_addr, rgd->rd_flags, (unsigned long long)rgd->rd_addr, rgd->rd_flags,
rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes, rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes,
rgd->rd_requested, rgd->rd_reserved, rgd->rd_extfail_pt); rgd->rd_requested, rgd->rd_reserved, rgd->rd_extfail_pt);
if (rgd->rd_sbd->sd_args.ar_rgrplvb) { if (rgd->rd_sbd->sd_args.ar_rgrplvb && rgd->rd_rgl) {
struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl; struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl;
gfs2_print_dbg(seq, "%s L: f:%02x b:%u i:%u\n", fs_id_buf, gfs2_print_dbg(seq, "%s L: f:%02x b:%u i:%u\n", fs_id_buf,
......
...@@ -134,7 +134,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -134,7 +134,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
int error; int error;
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
return -EIO; return -EIO;
error = gfs2_find_jhead(sdp->sd_jdesc, &head, false); error = gfs2_find_jhead(sdp->sd_jdesc, &head, false);
...@@ -153,7 +153,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -153,7 +153,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
gfs2_log_pointers_init(sdp, head.lh_blkno); gfs2_log_pointers_init(sdp, head.lh_blkno);
error = gfs2_quota_init(sdp); error = gfs2_quota_init(sdp);
if (!error && gfs2_withdrawn(sdp)) if (!error && gfs2_withdrawing_or_withdrawn(sdp))
error = -EIO; error = -EIO;
if (!error) if (!error)
set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
...@@ -499,7 +499,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) ...@@ -499,7 +499,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
return; return;
} }
if (unlikely(gfs2_withdrawn(sdp))) if (gfs2_withdrawing_or_withdrawn(sdp))
return; return;
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
...@@ -605,7 +605,7 @@ static void gfs2_put_super(struct super_block *sb) ...@@ -605,7 +605,7 @@ static void gfs2_put_super(struct super_block *sb)
if (!sb_rdonly(sb)) if (!sb_rdonly(sb))
gfs2_make_fs_ro(sdp); gfs2_make_fs_ro(sdp);
else { else {
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
gfs2_destroy_threads(sdp); gfs2_destroy_threads(sdp);
gfs2_quota_cleanup(sdp); gfs2_quota_cleanup(sdp);
...@@ -673,28 +673,6 @@ static int gfs2_sync_fs(struct super_block *sb, int wait) ...@@ -673,28 +673,6 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
return sdp->sd_log_error; return sdp->sd_log_error;
} }
static int gfs2_freeze_locally(struct gfs2_sbd *sdp)
{
struct super_block *sb = sdp->sd_vfs;
int error;
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
if (error)
return error;
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)) {
error = thaw_super(sb, FREEZE_HOLDER_USERSPACE);
if (error)
return error;
return -EIO;
}
}
return 0;
}
static int gfs2_do_thaw(struct gfs2_sbd *sdp) static int gfs2_do_thaw(struct gfs2_sbd *sdp)
{ {
struct super_block *sb = sdp->sd_vfs; struct super_block *sb = sdp->sd_vfs;
...@@ -724,7 +702,7 @@ void gfs2_freeze_func(struct work_struct *work) ...@@ -724,7 +702,7 @@ void gfs2_freeze_func(struct work_struct *work)
if (test_bit(SDF_FROZEN, &sdp->sd_flags)) if (test_bit(SDF_FROZEN, &sdp->sd_flags))
goto freeze_failed; goto freeze_failed;
error = gfs2_freeze_locally(sdp); error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
if (error) if (error)
goto freeze_failed; goto freeze_failed;
...@@ -759,12 +737,13 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who) ...@@ -759,12 +737,13 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
if (!mutex_trylock(&sdp->sd_freeze_mutex)) if (!mutex_trylock(&sdp->sd_freeze_mutex))
return -EBUSY; return -EBUSY;
error = -EBUSY; if (test_bit(SDF_FROZEN, &sdp->sd_flags)) {
if (test_bit(SDF_FROZEN, &sdp->sd_flags)) mutex_unlock(&sdp->sd_freeze_mutex);
goto out; return -EBUSY;
}
for (;;) { for (;;) {
error = gfs2_freeze_locally(sdp); error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
if (error) { if (error) {
fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n", fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
error); error);
...@@ -772,8 +751,11 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who) ...@@ -772,8 +751,11 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
} }
error = gfs2_lock_fs_check_clean(sdp); error = gfs2_lock_fs_check_clean(sdp);
if (!error) if (!error) {
break; /* success */ set_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
set_bit(SDF_FROZEN, &sdp->sd_flags);
break;
}
error = gfs2_do_thaw(sdp); error = gfs2_do_thaw(sdp);
if (error) if (error)
...@@ -793,14 +775,23 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who) ...@@ -793,14 +775,23 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
} }
out: out:
if (!error) {
set_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
set_bit(SDF_FROZEN, &sdp->sd_flags);
}
mutex_unlock(&sdp->sd_freeze_mutex); mutex_unlock(&sdp->sd_freeze_mutex);
return error; return error;
} }
static int gfs2_freeze_fs(struct super_block *sb)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
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_withdrawing_or_withdrawn(sdp))
return -EIO;
}
return 0;
}
/** /**
* gfs2_thaw_super - reallow writes to the filesystem * gfs2_thaw_super - reallow writes to the filesystem
* @sb: the VFS structure for the filesystem * @sb: the VFS structure for the filesystem
...@@ -814,10 +805,12 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who) ...@@ -814,10 +805,12 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
if (!mutex_trylock(&sdp->sd_freeze_mutex)) if (!mutex_trylock(&sdp->sd_freeze_mutex))
return -EBUSY; return -EBUSY;
error = -EINVAL; if (!test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags)) {
if (!test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags)) mutex_unlock(&sdp->sd_freeze_mutex);
goto out; return -EINVAL;
}
atomic_inc(&sb->s_active);
gfs2_freeze_unlock(&sdp->sd_freeze_gh); gfs2_freeze_unlock(&sdp->sd_freeze_gh);
error = gfs2_do_thaw(sdp); error = gfs2_do_thaw(sdp);
...@@ -826,8 +819,8 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who) ...@@ -826,8 +819,8 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
clear_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags); clear_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
clear_bit(SDF_FROZEN, &sdp->sd_flags); clear_bit(SDF_FROZEN, &sdp->sd_flags);
} }
out:
mutex_unlock(&sdp->sd_freeze_mutex); mutex_unlock(&sdp->sd_freeze_mutex);
deactivate_super(sb);
return error; return error;
} }
...@@ -1065,16 +1058,6 @@ static int gfs2_drop_inode(struct inode *inode) ...@@ -1065,16 +1058,6 @@ static int gfs2_drop_inode(struct inode *inode)
return generic_drop_inode(inode); return generic_drop_inode(inode);
} }
static int is_ancestor(const struct dentry *d1, const struct dentry *d2)
{
do {
if (d1 == d2)
return 1;
d1 = d1->d_parent;
} while (!IS_ROOT(d1));
return 0;
}
/** /**
* gfs2_show_options - Show mount options for /proc/mounts * gfs2_show_options - Show mount options for /proc/mounts
* @s: seq_file structure * @s: seq_file structure
...@@ -1096,7 +1079,7 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root) ...@@ -1096,7 +1079,7 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
statfs_slow = sdp->sd_tune.gt_statfs_slow; statfs_slow = sdp->sd_tune.gt_statfs_slow;
spin_unlock(&sdp->sd_tune.gt_spin); spin_unlock(&sdp->sd_tune.gt_spin);
if (is_ancestor(root, sdp->sd_master_dir)) if (is_subdir(root, sdp->sd_master_dir))
seq_puts(s, ",meta"); seq_puts(s, ",meta");
if (args->ar_lockproto[0]) if (args->ar_lockproto[0])
seq_show_option(s, "lockproto", args->ar_lockproto); seq_show_option(s, "lockproto", args->ar_lockproto);
...@@ -1607,6 +1590,7 @@ const struct super_operations gfs2_super_ops = { ...@@ -1607,6 +1590,7 @@ const struct super_operations gfs2_super_ops = {
.put_super = gfs2_put_super, .put_super = gfs2_put_super,
.sync_fs = gfs2_sync_fs, .sync_fs = gfs2_sync_fs,
.freeze_super = gfs2_freeze_super, .freeze_super = gfs2_freeze_super,
.freeze_fs = gfs2_freeze_fs,
.thaw_super = gfs2_thaw_super, .thaw_super = gfs2_thaw_super,
.statfs = gfs2_statfs, .statfs = gfs2_statfs,
.drop_inode = gfs2_drop_inode, .drop_inode = gfs2_drop_inode,
......
...@@ -193,7 +193,7 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) ...@@ -193,7 +193,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) static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
{ {
unsigned int b = gfs2_withdrawn(sdp); unsigned int b = gfs2_withdrawing_or_withdrawn(sdp);
return snprintf(buf, PAGE_SIZE, "%u\n", b); return snprintf(buf, PAGE_SIZE, "%u\n", b);
} }
......
...@@ -268,7 +268,7 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) ...@@ -268,7 +268,7 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
(unsigned long long)bd->bd_bh->b_blocknr); (unsigned long long)bd->bd_bh->b_blocknr);
BUG(); BUG();
} }
if (unlikely(gfs2_withdrawn(sdp))) { if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_info(sdp, "GFS2:adding buf while withdrawn! 0x%llx\n", fs_info(sdp, "GFS2:adding buf while withdrawn! 0x%llx\n",
(unsigned long long)bd->bd_bh->b_blocknr); (unsigned long long)bd->bd_bh->b_blocknr);
goto out_unlock; goto out_unlock;
......
...@@ -372,7 +372,7 @@ void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, ...@@ -372,7 +372,7 @@ void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
const char *function, char *file, unsigned int line, const char *function, char *file, unsigned int line,
bool delayed) bool delayed)
{ {
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
return; return;
fs_err(sdp, fs_err(sdp,
...@@ -548,7 +548,7 @@ void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, ...@@ -548,7 +548,7 @@ void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
const char *function, char *file, unsigned int line, const char *function, char *file, unsigned int line,
bool withdraw) bool withdraw)
{ {
if (gfs2_withdrawn(sdp)) if (gfs2_withdrawing_or_withdrawn(sdp))
return; return;
fs_err(sdp, "fatal: I/O error\n" fs_err(sdp, "fatal: I/O error\n"
......
...@@ -198,13 +198,14 @@ static inline void gfs2_withdraw_delayed(struct gfs2_sbd *sdp) ...@@ -198,13 +198,14 @@ static inline void gfs2_withdraw_delayed(struct gfs2_sbd *sdp)
} }
/** /**
* gfs2_withdrawn - test whether the file system is withdrawing or withdrawn * gfs2_withdrawing_or_withdrawn - test whether the file system is withdrawing
* or withdrawn
* @sdp: the superblock * @sdp: the superblock
*/ */
static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp) static inline bool gfs2_withdrawing_or_withdrawn(struct gfs2_sbd *sdp)
{ {
return test_bit(SDF_WITHDRAWN, &sdp->sd_flags) || return unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags) ||
test_bit(SDF_WITHDRAWING, &sdp->sd_flags); test_bit(SDF_WITHDRAWING, &sdp->sd_flags));
} }
/** /**
...@@ -213,13 +214,13 @@ static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp) ...@@ -213,13 +214,13 @@ static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
*/ */
static inline bool gfs2_withdrawing(struct gfs2_sbd *sdp) static inline bool gfs2_withdrawing(struct gfs2_sbd *sdp)
{ {
return test_bit(SDF_WITHDRAWING, &sdp->sd_flags) && return unlikely(test_bit(SDF_WITHDRAWING, &sdp->sd_flags) &&
!test_bit(SDF_WITHDRAWN, &sdp->sd_flags); !test_bit(SDF_WITHDRAWN, &sdp->sd_flags));
} }
static inline bool gfs2_withdraw_in_prog(struct gfs2_sbd *sdp) static inline bool gfs2_withdraw_in_prog(struct gfs2_sbd *sdp)
{ {
return test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); return unlikely(test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags));
} }
#define gfs2_tune_get(sdp, field) \ #define gfs2_tune_get(sdp, field) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment