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)
error = mpage_read_folio(folio, gfs2_block_map);
}
if (unlikely(gfs2_withdrawn(sdp)))
if (gfs2_withdrawing_or_withdrawn(sdp))
return -EIO;
return error;
......
......@@ -32,21 +32,25 @@
static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
{
struct dentry *parent;
struct dentry *parent = NULL;
struct gfs2_sbd *sdp;
struct gfs2_inode *dip;
struct inode *inode;
struct inode *dinode, *inode;
struct gfs2_holder d_gh;
struct gfs2_inode *ip = NULL;
int error, valid = 0;
int had_lock = 0;
if (flags & LOOKUP_RCU)
return -ECHILD;
parent = dget_parent(dentry);
sdp = GFS2_SB(d_inode(parent));
dip = GFS2_I(d_inode(parent));
if (flags & LOOKUP_RCU) {
dinode = d_inode_rcu(READ_ONCE(dentry->d_parent));
if (!dinode)
return -ECHILD;
} else {
parent = dget_parent(dentry);
dinode = d_inode(parent);
}
sdp = GFS2_SB(dinode);
dip = GFS2_I(dinode);
inode = d_inode(dentry);
if (inode) {
......@@ -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);
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)
goto out;
}
......
......@@ -138,8 +138,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
return ERR_PTR(-ESTALE);
inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino,
GFS2_BLKST_DINODE);
if (IS_ERR(inode))
return ERR_CAST(inode);
return d_obtain_alias(inode);
}
......
......@@ -1442,7 +1442,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_POSIX))
return -ENOLCK;
if (unlikely(gfs2_withdrawn(sdp))) {
if (gfs2_withdrawing_or_withdrawn(sdp)) {
if (fl->fl_type == F_UNLCK)
locks_lock_file_wait(file, fl);
return -EIO;
......
......@@ -156,7 +156,7 @@ static bool glock_blocked_by_withdraw(struct gfs2_glock *gl)
{
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
if (likely(!gfs2_withdrawn(sdp)))
if (!gfs2_withdrawing_or_withdrawn(sdp))
return false;
if (gl->gl_ops->go_flags & GLOF_NONDISK)
return false;
......@@ -278,7 +278,7 @@ static void __gfs2_glock_put(struct gfs2_glock *gl)
GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
if (mapping) {
truncate_inode_pages_final(mapping);
if (!gfs2_withdrawn(sdp))
if (!gfs2_withdrawing_or_withdrawn(sdp))
GLOCK_BUG_ON(gl, !mapping_empty(mapping));
}
trace_gfs2_glock_put(gl);
......@@ -516,6 +516,23 @@ static inline struct gfs2_holder *find_first_waiter(const struct gfs2_glock *gl)
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
* @gl: the glock
......@@ -757,7 +774,7 @@ __acquires(&gl->gl_lockref.lock)
* gfs2_gl_hash_clear calls clear_glock) and recovery is complete
* 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);
if (glock_blocked_by_withdraw(gl) &&
(target != LM_ST_UNLOCKED ||
......@@ -794,7 +811,7 @@ __acquires(&gl->gl_lockref.lock)
gfs2_glock_queue_work(gl, 0);
} else if (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 */
finish_xmote(gl, target);
......@@ -1555,11 +1572,30 @@ __acquires(&gl->gl_lockref.lock)
int gfs2_glock_nq(struct gfs2_holder *gh)
{
struct gfs2_glock *gl = gh->gh_gl;
int error = 0;
int error;
if (glock_blocked_by_withdraw(gl) && !(gh->gh_flags & LM_FLAG_NOEXP))
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))
gfs2_glock_remove_from_lru(gl);
......@@ -1575,6 +1611,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
run_queue(gl, 1);
spin_unlock(&gl->gl_lockref.lock);
error = 0;
if (!(gh->gh_flags & GL_ASYNC))
error = gfs2_glock_wait(gh);
......
......@@ -84,6 +84,7 @@ enum {
#define GL_SKIP 0x0100
#define GL_NOPID 0x0200
#define GL_NOCACHE 0x0400
#define GL_NOBLOCK 0x0800
/*
* lm_async_cb return flags
......
......@@ -174,7 +174,7 @@ static int gfs2_rgrp_metasync(struct gfs2_glock *gl)
filemap_fdatawrite_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);
if (error)
gfs2_io_error(sdp);
......@@ -494,7 +494,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip)
/**
* inode_go_instantiate - read in an inode if necessary
* @gh: The glock holder
* @gl: The glock
*
* Returns: errno
*/
......
......@@ -1882,10 +1882,10 @@ int gfs2_permission(struct mnt_idmap *idmap, struct inode *inode,
WARN_ON_ONCE(!may_not_block);
return -ECHILD;
}
if (gfs2_glock_is_locked_by_me(gl) == NULL) {
if (may_not_block)
return -ECHILD;
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
int noblock = may_not_block ? GL_NOBLOCK : 0;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
LM_FLAG_ANY | noblock, &i_gh);
if (error)
return error;
}
......
......@@ -1122,7 +1122,7 @@ static void gdlm_recover_prep(void *arg)
struct gfs2_sbd *sdp = arg;
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");
return;
}
......@@ -1148,7 +1148,7 @@ static void gdlm_recover_slot(void *arg, struct dlm_slot *slot)
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
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",
jid);
return;
......@@ -1177,7 +1177,7 @@ static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots,
struct gfs2_sbd *sdp = arg;
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");
return;
}
......@@ -1208,7 +1208,7 @@ static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid,
{
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",
jid);
return;
......
......@@ -126,7 +126,7 @@ __acquires(&sdp->sd_ail_lock)
}
}
if (gfs2_withdrawn(sdp)) {
if (gfs2_withdrawing_or_withdrawn(sdp)) {
gfs2_remove_from_ail(bd);
continue;
}
......@@ -352,14 +352,15 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
* @sdp: The superblock
* @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;
int oldest_tr = 1;
int ret;
bool empty;
spin_lock(&sdp->sd_ail_lock);
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)
oldest_tr = 0;
}
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);
if (test_bit(SDF_WITHDRAWING, &sdp->sd_flags)) {
gfs2_lm(sdp, "fatal: I/O error(s)\n");
gfs2_withdraw(sdp);
}
return ret;
return empty;
}
static void gfs2_ail1_wait(struct gfs2_sbd *sdp)
......@@ -814,6 +810,9 @@ void gfs2_flush_revokes(struct gfs2_sbd *sdp)
gfs2_log_lock(sdp);
gfs2_ail1_empty(sdp, max_revokes);
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,
struct super_block *sb = sdp->sd_vfs;
u64 dblock;
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
return;
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,
static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
{
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)) {
gfs2_ordered_wait(sdp);
......@@ -974,8 +974,9 @@ void gfs2_ail_drain(struct gfs2_sbd *sdp)
static void empty_ail1_list(struct gfs2_sbd *sdp)
{
unsigned long start = jiffies;
bool empty = false;
for (;;) {
while (!empty) {
if (time_after(jiffies, start + (HZ * 600))) {
fs_err(sdp, "Error: In %s for 10 minutes! t=%d\n",
__func__, current->journal_info ? 1 : 0);
......@@ -984,9 +985,14 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
}
gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp);
if (gfs2_ail1_empty(sdp, 0))
return;
empty = gfs2_ail1_empty(sdp, 0);
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)
* Do this check while holding the log_flush_lock to prevent new
* 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;
/* 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)
goto out_withdraw;
gfs2_ordered_write(sdp);
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw;
lops_before_commit(sdp, tr);
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw;
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;
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)
} else if (sdp->sd_log_tail != sdp->sd_log_flush_tail && !sdp->sd_log_idle) {
log_write_header(sdp, flags);
}
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw;
lops_after_commit(sdp, tr);
......@@ -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 (!sdp->sd_log_idle) {
empty_ail1_list(sdp);
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
goto out_withdraw;
log_write_header(sdp, flags);
}
......@@ -1297,8 +1304,9 @@ int gfs2_logd(void *data)
struct gfs2_sbd *sdp = data;
unsigned long t = 1;
set_freezable();
while (!kthread_should_stop()) {
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
break;
/* Check for errors writing to the journal */
......@@ -1330,18 +1338,19 @@ int gfs2_logd(void *data)
t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
try_to_freeze();
t = wait_event_interruptible_timeout(sdp->sd_logd_waitq,
t = wait_event_freezable_timeout(sdp->sd_logd_waitq,
test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) ||
gfs2_ail_flush_reqd(sdp) ||
gfs2_jrnl_flush_reqd(sdp) ||
sdp->sd_log_error ||
gfs2_withdrawn(sdp) ||
gfs2_withdrawing_or_withdrawn(sdp) ||
kthread_should_stop(),
t);
}
if (gfs2_withdrawing(sdp))
gfs2_withdraw(sdp);
return 0;
}
......@@ -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
* process them in order as necessary.
*/
static void gfs2_end_log_read(struct bio *bio)
{
struct page *page;
struct bio_vec *bvec;
struct bvec_iter_all iter_all;
int error = blk_status_to_errno(bio->bi_status);
struct folio_iter fi;
bio_for_each_segment_all(bvec, bio, iter_all) {
page = bvec->bv_page;
if (bio->bi_status) {
int err = blk_status_to_errno(bio->bi_status);
SetPageError(page);
mapping_set_error(page->mapping, err);
}
unlock_page(page);
bio_for_each_folio_all(fi, bio) {
/* We're abusing wb_err to get the error to gfs2_find_jhead */
filemap_set_wb_err(fi.folio->mapping, error);
folio_end_read(fi.folio, !error);
}
bio_put(bio);
......@@ -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_wait_locked(folio);
if (folio_test_error(folio))
if (!folio_test_uptodate(folio))
*done = true;
if (!*done)
......
......@@ -252,7 +252,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
struct buffer_head *bh, *bhs[2];
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;
return -EIO;
}
......@@ -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)
{
if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp) &&
!gfs2_withdraw_in_prog(sdp))
return -EIO;
wait_on_buffer(bh);
......@@ -321,7 +323,8 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
gfs2_io_error_bh_wd(sdp, bh);
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 0;
......
......@@ -1073,7 +1073,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(!gfs2_withdrawn(sdp)) && lm->lm_unmount)
if (!gfs2_withdrawing_or_withdrawn(sdp) && lm->lm_unmount)
lm->lm_unmount(sdp);
}
......
......@@ -128,7 +128,7 @@ static void gfs2_qd_dispose(struct gfs2_quota_data *qd)
hlist_bl_del_rcu(&qd->qd_hlist);
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_slot_ref);
gfs2_assert_warn(sdp, !qd->qd_bh_count);
......@@ -1505,7 +1505,8 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
LIST_HEAD(dispose);
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);
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)
{
if (error == 0 || error == -EROFS)
return;
if (!gfs2_withdrawn(sdp)) {
if (!gfs2_withdrawing_or_withdrawn(sdp)) {
if (!cmpxchg(&sdp->sd_log_error, 0, error))
fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error);
wake_up(&sdp->sd_logd_waitq);
......@@ -1582,8 +1583,9 @@ int gfs2_quotad(void *data)
unsigned long quotad_timeo = 0;
unsigned long t = 0;
set_freezable();
while (!kthread_should_stop()) {
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
break;
/* Update the master statfs file */
......@@ -1601,13 +1603,11 @@ int gfs2_quotad(void *data)
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
&quotad_timeo, &tune->gt_quota_quantum);
try_to_freeze();
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 ||
gfs2_withdrawn(sdp) ||
gfs2_withdrawing_or_withdrawn(sdp) ||
kthread_should_stop(),
t);
......
......@@ -411,7 +411,7 @@ void gfs2_recover_func(struct work_struct *work)
int error = 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",
jd->jd_jid);
goto fail;
......
......@@ -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
* @mask: Mask to use (normally 0x55555.... but adjusted for search start)
* @state: The state we are searching for
*
* We xor the bitmap data with a patter which is the bitwise opposite
* of what we are looking for, this gives rise to a pattern of ones
* 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
* 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
* 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)
/**
* 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.
* 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)
}
/**
* 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
* @msecs: The time limit in milliseconds
*
......@@ -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,
rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes,
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;
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)
int error;
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
return -EIO;
error = gfs2_find_jhead(sdp->sd_jdesc, &head, false);
......@@ -153,7 +153,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
gfs2_log_pointers_init(sdp, head.lh_blkno);
error = gfs2_quota_init(sdp);
if (!error && gfs2_withdrawn(sdp))
if (!error && gfs2_withdrawing_or_withdrawn(sdp))
error = -EIO;
if (!error)
set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
......@@ -499,7 +499,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
return;
}
if (unlikely(gfs2_withdrawn(sdp)))
if (gfs2_withdrawing_or_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);
......@@ -605,7 +605,7 @@ static void gfs2_put_super(struct super_block *sb)
if (!sb_rdonly(sb))
gfs2_make_fs_ro(sdp);
else {
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
gfs2_destroy_threads(sdp);
gfs2_quota_cleanup(sdp);
......@@ -673,28 +673,6 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
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)
{
struct super_block *sb = sdp->sd_vfs;
......@@ -724,7 +702,7 @@ void gfs2_freeze_func(struct work_struct *work)
if (test_bit(SDF_FROZEN, &sdp->sd_flags))
goto freeze_failed;
error = gfs2_freeze_locally(sdp);
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
if (error)
goto freeze_failed;
......@@ -759,12 +737,13 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
if (!mutex_trylock(&sdp->sd_freeze_mutex))
return -EBUSY;
error = -EBUSY;
if (test_bit(SDF_FROZEN, &sdp->sd_flags))
goto out;
if (test_bit(SDF_FROZEN, &sdp->sd_flags)) {
mutex_unlock(&sdp->sd_freeze_mutex);
return -EBUSY;
}
for (;;) {
error = gfs2_freeze_locally(sdp);
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
if (error) {
fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
error);
......@@ -772,8 +751,11 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
}
error = gfs2_lock_fs_check_clean(sdp);
if (!error)
break; /* success */
if (!error) {
set_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
set_bit(SDF_FROZEN, &sdp->sd_flags);
break;
}
error = gfs2_do_thaw(sdp);
if (error)
......@@ -793,14 +775,23 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
}
out:
if (!error) {
set_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);
set_bit(SDF_FROZEN, &sdp->sd_flags);
}
mutex_unlock(&sdp->sd_freeze_mutex);
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
* @sb: the VFS structure for the filesystem
......@@ -814,10 +805,12 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
if (!mutex_trylock(&sdp->sd_freeze_mutex))
return -EBUSY;
error = -EINVAL;
if (!test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags))
goto out;
if (!test_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags)) {
mutex_unlock(&sdp->sd_freeze_mutex);
return -EINVAL;
}
atomic_inc(&sb->s_active);
gfs2_freeze_unlock(&sdp->sd_freeze_gh);
error = gfs2_do_thaw(sdp);
......@@ -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_FROZEN, &sdp->sd_flags);
}
out:
mutex_unlock(&sdp->sd_freeze_mutex);
deactivate_super(sb);
return error;
}
......@@ -1065,16 +1058,6 @@ static int gfs2_drop_inode(struct 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
* @s: seq_file structure
......@@ -1096,7 +1079,7 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
statfs_slow = sdp->sd_tune.gt_statfs_slow;
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");
if (args->ar_lockproto[0])
seq_show_option(s, "lockproto", args->ar_lockproto);
......@@ -1607,6 +1590,7 @@ const struct super_operations gfs2_super_ops = {
.put_super = gfs2_put_super,
.sync_fs = gfs2_sync_fs,
.freeze_super = gfs2_freeze_super,
.freeze_fs = gfs2_freeze_fs,
.thaw_super = gfs2_thaw_super,
.statfs = gfs2_statfs,
.drop_inode = gfs2_drop_inode,
......
......@@ -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)
{
unsigned int b = gfs2_withdrawn(sdp);
unsigned int b = gfs2_withdrawing_or_withdrawn(sdp);
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)
(unsigned long long)bd->bd_bh->b_blocknr);
BUG();
}
if (unlikely(gfs2_withdrawn(sdp))) {
if (gfs2_withdrawing_or_withdrawn(sdp)) {
fs_info(sdp, "GFS2:adding buf while withdrawn! 0x%llx\n",
(unsigned long long)bd->bd_bh->b_blocknr);
goto out_unlock;
......
......@@ -372,7 +372,7 @@ void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
const char *function, char *file, unsigned int line,
bool delayed)
{
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
return;
fs_err(sdp,
......@@ -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,
bool withdraw)
{
if (gfs2_withdrawn(sdp))
if (gfs2_withdrawing_or_withdrawn(sdp))
return;
fs_err(sdp, "fatal: I/O error\n"
......
......@@ -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
*/
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) ||
test_bit(SDF_WITHDRAWING, &sdp->sd_flags);
return unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags) ||
test_bit(SDF_WITHDRAWING, &sdp->sd_flags));
}
/**
......@@ -213,13 +214,13 @@ static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
*/
static inline bool gfs2_withdrawing(struct gfs2_sbd *sdp)
{
return test_bit(SDF_WITHDRAWING, &sdp->sd_flags) &&
!test_bit(SDF_WITHDRAWN, &sdp->sd_flags);
return unlikely(test_bit(SDF_WITHDRAWING, &sdp->sd_flags) &&
!test_bit(SDF_WITHDRAWN, &sdp->sd_flags));
}
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) \
......
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