gfs2 changes
- Major withdraw / error handling overhaul based on dlm's new DLM_RELEASE_RECOVER feature: this allows gfs to treat withdraws like node failures. Make withdraws asynchronous. - Fix a bug in commitpull/1354/mergee4a8b5481cthat caused 'df' to remain out of sync. ('df' is still allowed to go slightly out of sync for short periods of time.) - Prevent recusive memory reclaim in gfs2_unstuff_dinode(). - Clean up SDF_JOURNAL_LIVE flag handling. - Fix remote evict for read-only filesystems. - Fix a misuse of bio_chain(). - Various other minor cleanups. -----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAmkvM/oUHGFncnVlbmJh QHJlZGhhdC5jb20ACgkQ1b+f6wMTZTqFLQ//Ra+FUIMYRrU83xd8OB+rXaFixymk riPnoXZHrccoRAARc6d/p/nTYmV7FSnTa2jlsUFshsO2jl/1OIRI6xqScL+W5dp9 ToxHKnezOsRmy5tXvomYy9Teo/ngz6dpv6ixVrn7qTGJJ5zpir0ji2fO+xUvCUQq IVGgvQN0O7ECUmmRXxjkRLhoEdus2Ye4jQkpJmqY9I1+H/0E43HlF2zDgoisTkiH baNtFkTgE65Hba2xhoTCt3NO17POgqGcRaLVOLv5dqGhLAQ33+jXeYduM6ujbqwk 1FznGf09NRBJVQkyJvbgZELdX+mWXvWf/2kPmW6TXd7phFiO7cByxN2aHHcu/wBp kh0ZgLFtvjyuR7wiyKf0tAKKPh250YiSkBuJU64dlHha2ZQuME6Z4dlYqBKwvPXf AwxAu0tB2bAjc2OXvPaHhLHjdpySEWqNZIITbfQPVPonRKed10IqCwlTd+j5/64H mnZCCxr2p2akrSYbQjl7h1k4LO7eX3cYJ23JoKIjwQ2hJE+Pd4li9+xhQCEQUVyE ou/ezUKc19Xe7uxG1412PrbmOtIMgKfpq2KW151b1KA3pfCUt7GMvpYlvmnf9Wzs XGjrQ1p4XdlxzQqe9XTrdO0IrNUNGDcky1Kqishje9SPa8FthwrtTuBSYL8nkcX6 3KRRzlFCRHfM5ng= =AWK2 -----END PGP SIGNATURE----- Merge tag 'gfs2-for-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2 Pull gfs2 updates from Andreas Gruenbacher: - Major withdraw / error handling overhaul based on dlm's new DLM_RELEASE_RECOVER feature: this allows gfs to treat withdraws like node failures. Make withdraws asynchronous - Fix a bug in commite4a8b5481cthat caused 'df' to remain out of sync. ('df' is still allowed to go slightly out of sync for short periods of time) - Prevent recusive memory reclaim in gfs2_unstuff_dinode() - Clean up SDF_JOURNAL_LIVE flag handling - Fix remote evict for read-only filesystems - Fix a misuse of bio_chain() - Various other minor cleanups * tag 'gfs2-for-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: (35 commits) gfs2: Fix use of bio_chain gfs2: Clean up SDF_JOURNAL_LIVE flag handling gfs2: No longer thaw filesystems during a withdraw gfs2: Withdraw immediately in gfs2_trans_add_meta gfs2: New gfs2_withdraw_helper gfs2: Clean up properly during a withdraw gfs2: Rename gfs2_{gl_dq_holders => withdraw_glocks} Revert "gfs2: fix infinite loop when checking ail item count before go_inval" Revert "gfs2: Allow some glocks to be used during withdraw" Revert "gfs2: Check for log write errors before telling dlm to unlock" Revert "gfs2: fix a deadlock on withdraw-during-mount" Revert "gfs2: Force withdraw to replay journals and wait for it to finish" (6/6) Revert "gfs2: Force withdraw to replay journals and wait for it to finish" (5/6) Revert "gfs2: Force withdraw to replay journals and wait for it to finish" (4/6) Revert "gfs2: Force withdraw to replay journals and wait for it to finish" (3/6) Revert "gfs2: Force withdraw to replay journals and wait for it to finish" (2/6) Revert "gfs2: Force withdraw to replay journals and wait for it to finish" (1/6) Revert "gfs2: don't stop reads while withdraw in progress" gfs2: Rename LM_FLAG_{NOEXP -> RECOVER} gfs2: Kill gfs2_io_error_bh_wd ...
commit
afcbce74f3
|
|
@ -4,6 +4,9 @@
|
||||||
Global File System 2
|
Global File System 2
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
GFS2 is a cluster file system. It allows a cluster of computers to
|
GFS2 is a cluster file system. It allows a cluster of computers to
|
||||||
simultaneously use a block device that is shared between them (with FC,
|
simultaneously use a block device that is shared between them (with FC,
|
||||||
iSCSI, NBD, etc). GFS2 reads and writes to the block device like a local
|
iSCSI, NBD, etc). GFS2 reads and writes to the block device like a local
|
||||||
|
|
@ -50,3 +53,12 @@ The following man pages are available from gfs2-utils:
|
||||||
gfs2_convert to convert a gfs filesystem to GFS2 in-place
|
gfs2_convert to convert a gfs filesystem to GFS2 in-place
|
||||||
mkfs.gfs2 to make a filesystem
|
mkfs.gfs2 to make a filesystem
|
||||||
============ =============================================
|
============ =============================================
|
||||||
|
|
||||||
|
Implementation Notes
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
glocks
|
||||||
|
uevents
|
||||||
|
|
@ -89,9 +89,7 @@ Documentation for filesystem implementations.
|
||||||
ext3
|
ext3
|
||||||
ext4/index
|
ext4/index
|
||||||
f2fs
|
f2fs
|
||||||
gfs2
|
gfs2/index
|
||||||
gfs2-uevents
|
|
||||||
gfs2-glocks
|
|
||||||
hfs
|
hfs
|
||||||
hfsplus
|
hfsplus
|
||||||
hpfs
|
hpfs
|
||||||
|
|
|
||||||
|
|
@ -10535,7 +10535,7 @@ L: gfs2@lists.linux.dev
|
||||||
S: Supported
|
S: Supported
|
||||||
B: https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=gfs2
|
B: https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=gfs2
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git
|
||||||
F: Documentation/filesystems/gfs2*
|
F: Documentation/filesystems/gfs2/
|
||||||
F: fs/gfs2/
|
F: fs/gfs2/
|
||||||
F: include/uapi/linux/gfs2_ondisk.h
|
F: include/uapi/linux/gfs2_ondisk.h
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -431,7 +431,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 (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
||||||
|
|
@ -1446,7 +1446,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
|
||||||
|
|
||||||
if (!(fl->c.flc_flags & FL_POSIX))
|
if (!(fl->c.flc_flags & FL_POSIX))
|
||||||
return -ENOLCK;
|
return -ENOLCK;
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_withdrawn(sdp)) {
|
||||||
if (lock_is_unlock(fl))
|
if (lock_is_unlock(fl))
|
||||||
locks_lock_file_wait(file, fl);
|
locks_lock_file_wait(file, fl);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
|
||||||
227
fs/gfs2/glock.c
227
fs/gfs2/glock.c
|
|
@ -137,33 +137,6 @@ static void gfs2_glock_dealloc(struct rcu_head *rcu)
|
||||||
kmem_cache_free(gfs2_glock_cachep, gl);
|
kmem_cache_free(gfs2_glock_cachep, gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* glock_blocked_by_withdraw - determine if we can still use a glock
|
|
||||||
* @gl: the glock
|
|
||||||
*
|
|
||||||
* We need to allow some glocks to be enqueued, dequeued, promoted, and demoted
|
|
||||||
* when we're withdrawn. For example, to maintain metadata integrity, we should
|
|
||||||
* disallow the use of inode and rgrp glocks when withdrawn. Other glocks like
|
|
||||||
* the iopen or freeze glock may be safely used because none of their
|
|
||||||
* metadata goes through the journal. So in general, we should disallow all
|
|
||||||
* glocks that are journaled, and allow all the others. One exception is:
|
|
||||||
* we need to allow our active journal to be promoted and demoted so others
|
|
||||||
* may recover it and we can reacquire it when they're done.
|
|
||||||
*/
|
|
||||||
static bool glock_blocked_by_withdraw(struct gfs2_glock *gl)
|
|
||||||
{
|
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
|
||||||
|
|
||||||
if (!gfs2_withdrawing_or_withdrawn(sdp))
|
|
||||||
return false;
|
|
||||||
if (gl->gl_ops->go_flags & GLOF_NONDISK)
|
|
||||||
return false;
|
|
||||||
if (!sdp->sd_jdesc ||
|
|
||||||
gl->gl_name.ln_number == sdp->sd_jdesc->jd_no_addr)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __gfs2_glock_free(struct gfs2_glock *gl)
|
static void __gfs2_glock_free(struct gfs2_glock *gl)
|
||||||
{
|
{
|
||||||
rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms);
|
rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms);
|
||||||
|
|
@ -270,7 +243,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_withdrawing_or_withdrawn(sdp))
|
if (!gfs2_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);
|
||||||
|
|
@ -485,8 +458,14 @@ done:
|
||||||
|
|
||||||
static void do_promote(struct gfs2_glock *gl)
|
static void do_promote(struct gfs2_glock *gl)
|
||||||
{
|
{
|
||||||
|
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||||
struct gfs2_holder *gh, *current_gh;
|
struct gfs2_holder *gh, *current_gh;
|
||||||
|
|
||||||
|
if (gfs2_withdrawn(sdp)) {
|
||||||
|
do_error(gl, LM_OUT_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
current_gh = find_first_holder(gl);
|
current_gh = find_first_holder(gl);
|
||||||
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
||||||
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
|
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
|
||||||
|
|
@ -592,7 +571,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
|
||||||
state_change(gl, state);
|
state_change(gl, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Demote to UN request arrived during demote to SH or DF */
|
/* Demote to UN request arrived during demote to SH or DF */
|
||||||
if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) &&
|
if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) &&
|
||||||
gl->gl_state != LM_ST_UNLOCKED &&
|
gl->gl_state != LM_ST_UNLOCKED &&
|
||||||
|
|
@ -663,16 +641,6 @@ out:
|
||||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
clear_bit(GLF_LOCK, &gl->gl_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_system_glock(struct gfs2_glock *gl)
|
|
||||||
{
|
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
|
||||||
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
|
|
||||||
|
|
||||||
if (gl == m_ip->i_gl)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do_xmote - Calls the DLM to change the state of a lock
|
* do_xmote - Calls the DLM to change the state of a lock
|
||||||
* @gl: The lock state
|
* @gl: The lock state
|
||||||
|
|
@ -691,95 +659,47 @@ __acquires(&gl->gl_lockref.lock)
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (target != LM_ST_UNLOCKED && glock_blocked_by_withdraw(gl) &&
|
/*
|
||||||
gh && !(gh->gh_flags & LM_FLAG_NOEXP))
|
* When a filesystem is withdrawing, the remaining cluster nodes will
|
||||||
goto skip_inval;
|
* take care of recovering the withdrawing node's journal. We only
|
||||||
|
* need to make sure that once we trigger remote recovery, we won't
|
||||||
|
* write to the shared block device anymore. This means that here,
|
||||||
|
*
|
||||||
|
* - no new writes to the filesystem must be triggered (->go_sync()).
|
||||||
|
*
|
||||||
|
* - any cached data should be discarded by calling ->go_inval(), dirty
|
||||||
|
* or not and journaled or unjournaled.
|
||||||
|
*
|
||||||
|
* - no more dlm locking operations should be issued (->lm_lock()).
|
||||||
|
*/
|
||||||
|
|
||||||
GLOCK_BUG_ON(gl, gl->gl_state == target);
|
GLOCK_BUG_ON(gl, gl->gl_state == target);
|
||||||
GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
|
GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
|
||||||
|
|
||||||
if (!glops->go_inval || !glops->go_sync)
|
if (!glops->go_inval || !glops->go_sync)
|
||||||
goto skip_inval;
|
goto skip_inval;
|
||||||
|
|
||||||
spin_unlock(&gl->gl_lockref.lock);
|
spin_unlock(&gl->gl_lockref.lock);
|
||||||
ret = glops->go_sync(gl);
|
if (!gfs2_withdrawn(sdp)) {
|
||||||
/* If we had a problem syncing (due to io errors or whatever,
|
ret = glops->go_sync(gl);
|
||||||
* we should not invalidate the metadata or tell dlm to
|
if (ret) {
|
||||||
* release the glock to other nodes.
|
if (cmpxchg(&sdp->sd_log_error, 0, ret)) {
|
||||||
*/
|
fs_err(sdp, "Error %d syncing glock\n", ret);
|
||||||
if (ret) {
|
gfs2_dump_glock(NULL, gl, true);
|
||||||
if (cmpxchg(&sdp->sd_log_error, 0, ret)) {
|
gfs2_withdraw(sdp);
|
||||||
fs_err(sdp, "Error %d syncing glock\n", ret);
|
}
|
||||||
gfs2_dump_glock(NULL, gl, true);
|
|
||||||
}
|
}
|
||||||
spin_lock(&gl->gl_lockref.lock);
|
|
||||||
goto skip_inval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) {
|
if (target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED)
|
||||||
/*
|
|
||||||
* The call to go_sync should have cleared out the ail list.
|
|
||||||
* If there are still items, we have a problem. We ought to
|
|
||||||
* withdraw, but we can't because the withdraw code also uses
|
|
||||||
* glocks. Warn about the error, dump the glock, then fall
|
|
||||||
* through and wait for logd to do the withdraw for us.
|
|
||||||
*/
|
|
||||||
if ((atomic_read(&gl->gl_ail_count) != 0) &&
|
|
||||||
(!cmpxchg(&sdp->sd_log_error, 0, -EIO))) {
|
|
||||||
gfs2_glock_assert_warn(gl,
|
|
||||||
!atomic_read(&gl->gl_ail_count));
|
|
||||||
gfs2_dump_glock(NULL, gl, true);
|
|
||||||
}
|
|
||||||
glops->go_inval(gl, target == LM_ST_DEFERRED ? 0 : DIO_METADATA);
|
glops->go_inval(gl, target == LM_ST_DEFERRED ? 0 : DIO_METADATA);
|
||||||
}
|
|
||||||
spin_lock(&gl->gl_lockref.lock);
|
spin_lock(&gl->gl_lockref.lock);
|
||||||
|
|
||||||
skip_inval:
|
skip_inval:
|
||||||
/*
|
if (gfs2_withdrawn(sdp)) {
|
||||||
* Check for an error encountered since we called go_sync and go_inval.
|
if (target != LM_ST_UNLOCKED)
|
||||||
* If so, we can't withdraw from the glock code because the withdraw
|
target = LM_OUT_ERROR;
|
||||||
* code itself uses glocks (see function signal_our_withdraw) to
|
goto out;
|
||||||
* change the mount to read-only. Most importantly, we must not call
|
|
||||||
* dlm to unlock the glock until the journal is in a known good state
|
|
||||||
* (after journal replay) otherwise other nodes may use the object
|
|
||||||
* (rgrp or dinode) and then later, journal replay will corrupt the
|
|
||||||
* file system. The best we can do here is wait for the logd daemon
|
|
||||||
* to see sd_log_error and withdraw, and in the meantime, requeue the
|
|
||||||
* work for later.
|
|
||||||
*
|
|
||||||
* We make a special exception for some system glocks, such as the
|
|
||||||
* system statfs inode glock, which needs to be granted before the
|
|
||||||
* gfs2_quotad daemon can exit, and that exit needs to finish before
|
|
||||||
* we can unmount the withdrawn file system.
|
|
||||||
*
|
|
||||||
* However, if we're just unlocking the lock (say, for unmount, when
|
|
||||||
* 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_withdrawing_or_withdrawn(sdp))
|
|
||||||
gfs2_withdraw_delayed(sdp);
|
|
||||||
if (glock_blocked_by_withdraw(gl) &&
|
|
||||||
(target != LM_ST_UNLOCKED ||
|
|
||||||
test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags))) {
|
|
||||||
if (!is_system_glock(gl)) {
|
|
||||||
request_demote(gl, LM_ST_UNLOCKED, 0, false);
|
|
||||||
/*
|
|
||||||
* Ordinarily, we would call dlm and its callback would call
|
|
||||||
* finish_xmote, which would call state_change() to the new state.
|
|
||||||
* Since we withdrew, we won't call dlm, so call state_change
|
|
||||||
* manually, but to the UNLOCKED state we desire.
|
|
||||||
*/
|
|
||||||
state_change(gl, LM_ST_UNLOCKED);
|
|
||||||
/*
|
|
||||||
* We skip telling dlm to do the locking, so we won't get a
|
|
||||||
* reply that would otherwise clear GLF_LOCK. So we clear it here.
|
|
||||||
*/
|
|
||||||
if (!test_bit(GLF_CANCELING, &gl->gl_flags))
|
|
||||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
|
||||||
clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
|
|
||||||
gl->gl_lockref.count++;
|
|
||||||
gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ls->ls_ops->lm_lock) {
|
if (ls->ls_ops->lm_lock) {
|
||||||
|
|
@ -795,19 +715,23 @@ skip_inval:
|
||||||
}
|
}
|
||||||
clear_bit(GLF_PENDING_REPLY, &gl->gl_flags);
|
clear_bit(GLF_PENDING_REPLY, &gl->gl_flags);
|
||||||
|
|
||||||
if (ret == -ENODEV && gl->gl_target == LM_ST_UNLOCKED &&
|
if (ret == -ENODEV) {
|
||||||
target == LM_ST_UNLOCKED) {
|
|
||||||
/*
|
/*
|
||||||
* The lockspace has been released and the lock has
|
* The lockspace has been released and the lock has
|
||||||
* been unlocked implicitly.
|
* been unlocked implicitly.
|
||||||
*/
|
*/
|
||||||
|
if (target != LM_ST_UNLOCKED) {
|
||||||
|
target = LM_OUT_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fs_err(sdp, "lm_lock ret %d\n", ret);
|
fs_err(sdp, "lm_lock ret %d\n", ret);
|
||||||
GLOCK_BUG_ON(gl, !gfs2_withdrawing_or_withdrawn(sdp));
|
GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
/* Complete the operation now. */
|
/* Complete the operation now. */
|
||||||
finish_xmote(gl, target);
|
finish_xmote(gl, target);
|
||||||
gl->gl_lockref.count++;
|
gl->gl_lockref.count++;
|
||||||
|
|
@ -966,14 +890,14 @@ static struct gfs2_inode *gfs2_grab_existing_inode(struct gfs2_glock *gl)
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfs2_try_evict(struct gfs2_glock *gl)
|
static void gfs2_try_to_evict(struct gfs2_glock *gl)
|
||||||
{
|
{
|
||||||
struct gfs2_inode *ip;
|
struct gfs2_inode *ip;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is contention on the iopen glock and we have an inode, try
|
* If there is contention on the iopen glock and we have an inode, try
|
||||||
* to grab and release the inode so that it can be evicted. The
|
* to grab and release the inode so that it can be evicted. The
|
||||||
* GIF_DEFER_DELETE flag indicates to gfs2_evict_inode() that the inode
|
* GLF_DEFER_DELETE flag indicates to gfs2_evict_inode() that the inode
|
||||||
* should not be deleted locally. This will allow the remote node to
|
* should not be deleted locally. This will allow the remote node to
|
||||||
* go ahead and delete the inode without us having to do it, which will
|
* go ahead and delete the inode without us having to do it, which will
|
||||||
* avoid rgrp glock thrashing.
|
* avoid rgrp glock thrashing.
|
||||||
|
|
@ -1026,8 +950,14 @@ static void delete_work_func(struct work_struct *work)
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||||
bool verify_delete = test_and_clear_bit(GLF_VERIFY_DELETE, &gl->gl_flags);
|
bool verify_delete = test_and_clear_bit(GLF_VERIFY_DELETE, &gl->gl_flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for the GLF_VERIFY_DELETE above: this ensures that we won't
|
||||||
|
* immediately process GLF_VERIFY_DELETE work that the below call to
|
||||||
|
* gfs2_try_to_evict() queues.
|
||||||
|
*/
|
||||||
|
|
||||||
if (test_and_clear_bit(GLF_TRY_TO_EVICT, &gl->gl_flags))
|
if (test_and_clear_bit(GLF_TRY_TO_EVICT, &gl->gl_flags))
|
||||||
gfs2_try_evict(gl);
|
gfs2_try_to_evict(gl);
|
||||||
|
|
||||||
if (verify_delete) {
|
if (verify_delete) {
|
||||||
u64 no_addr = gl->gl_name.ln_number;
|
u64 no_addr = gl->gl_name.ln_number;
|
||||||
|
|
@ -1211,10 +1141,13 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
|
||||||
|
|
||||||
mapping = gfs2_glock2aspace(gl);
|
mapping = gfs2_glock2aspace(gl);
|
||||||
if (mapping) {
|
if (mapping) {
|
||||||
|
gfp_t gfp_mask;
|
||||||
|
|
||||||
mapping->a_ops = &gfs2_meta_aops;
|
mapping->a_ops = &gfs2_meta_aops;
|
||||||
mapping->host = sdp->sd_inode;
|
mapping->host = sdp->sd_inode;
|
||||||
mapping->flags = 0;
|
mapping->flags = 0;
|
||||||
mapping_set_gfp_mask(mapping, GFP_NOFS);
|
gfp_mask = mapping_gfp_mask(sdp->sd_inode->i_mapping);
|
||||||
|
mapping_set_gfp_mask(mapping, gfp_mask);
|
||||||
mapping->i_private_data = NULL;
|
mapping->i_private_data = NULL;
|
||||||
mapping->writeback_index = 0;
|
mapping->writeback_index = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1241,7 +1174,7 @@ found:
|
||||||
* @state: the state we're requesting
|
* @state: the state we're requesting
|
||||||
* @flags: the modifier flags
|
* @flags: the modifier flags
|
||||||
* @gh: the holder structure
|
* @gh: the holder structure
|
||||||
*
|
* @ip: caller's return address for debugging
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void __gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, u16 flags,
|
void __gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, u16 flags,
|
||||||
|
|
@ -1539,9 +1472,10 @@ trap_recursive:
|
||||||
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;
|
||||||
|
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (glock_blocked_by_withdraw(gl) && !(gh->gh_flags & LM_FLAG_NOEXP))
|
if (gfs2_withdrawn(sdp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (gh->gh_flags & GL_NOBLOCK) {
|
if (gh->gh_flags & GL_NOBLOCK) {
|
||||||
|
|
@ -1566,7 +1500,7 @@ unlock:
|
||||||
gh->gh_error = 0;
|
gh->gh_error = 0;
|
||||||
spin_lock(&gl->gl_lockref.lock);
|
spin_lock(&gl->gl_lockref.lock);
|
||||||
add_to_queue(gh);
|
add_to_queue(gh);
|
||||||
if (unlikely((LM_FLAG_NOEXP & gh->gh_flags) &&
|
if (unlikely((LM_FLAG_RECOVER & gh->gh_flags) &&
|
||||||
test_and_clear_bit(GLF_HAVE_FROZEN_REPLY, &gl->gl_flags))) {
|
test_and_clear_bit(GLF_HAVE_FROZEN_REPLY, &gl->gl_flags))) {
|
||||||
set_bit(GLF_HAVE_REPLY, &gl->gl_flags);
|
set_bit(GLF_HAVE_REPLY, &gl->gl_flags);
|
||||||
gl->gl_lockref.count++;
|
gl->gl_lockref.count++;
|
||||||
|
|
@ -1639,7 +1573,6 @@ static void __gfs2_glock_dq(struct gfs2_holder *gh)
|
||||||
void gfs2_glock_dq(struct gfs2_holder *gh)
|
void gfs2_glock_dq(struct gfs2_holder *gh)
|
||||||
{
|
{
|
||||||
struct gfs2_glock *gl = gh->gh_gl;
|
struct gfs2_glock *gl = gh->gh_gl;
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
|
||||||
|
|
||||||
spin_lock(&gl->gl_lockref.lock);
|
spin_lock(&gl->gl_lockref.lock);
|
||||||
if (!gfs2_holder_queued(gh)) {
|
if (!gfs2_holder_queued(gh)) {
|
||||||
|
|
@ -1666,24 +1599,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If we're in the process of file system withdraw, we cannot just
|
|
||||||
* dequeue any glocks until our journal is recovered, lest we introduce
|
|
||||||
* file system corruption. We need two exceptions to this rule: We need
|
|
||||||
* to allow unlocking of nondisk glocks and the glock for our own
|
|
||||||
* journal that needs recovery.
|
|
||||||
*/
|
|
||||||
if (test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags) &&
|
|
||||||
glock_blocked_by_withdraw(gl) &&
|
|
||||||
gh->gh_gl != sdp->sd_jinode_gl) {
|
|
||||||
sdp->sd_glock_dqs_held++;
|
|
||||||
spin_unlock(&gl->gl_lockref.lock);
|
|
||||||
might_sleep();
|
|
||||||
wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY,
|
|
||||||
TASK_UNINTERRUPTIBLE);
|
|
||||||
spin_lock(&gl->gl_lockref.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
__gfs2_glock_dq(gh);
|
__gfs2_glock_dq(gh);
|
||||||
out:
|
out:
|
||||||
spin_unlock(&gl->gl_lockref.lock);
|
spin_unlock(&gl->gl_lockref.lock);
|
||||||
|
|
@ -1871,7 +1786,7 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
|
||||||
*
|
*
|
||||||
* Glocks are not frozen if (a) the result of the dlm operation is
|
* Glocks are not frozen if (a) the result of the dlm operation is
|
||||||
* an error, (b) the locking operation was an unlock operation or
|
* an error, (b) the locking operation was an unlock operation or
|
||||||
* (c) if there is a "noexp" flagged request anywhere in the queue
|
* (c) if there is a "recover" flagged request anywhere in the queue
|
||||||
*
|
*
|
||||||
* Returns: 1 if freezing should occur, 0 otherwise
|
* Returns: 1 if freezing should occur, 0 otherwise
|
||||||
*/
|
*/
|
||||||
|
|
@ -1888,7 +1803,7 @@ static int gfs2_should_freeze(const struct gfs2_glock *gl)
|
||||||
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
||||||
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
|
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
|
||||||
continue;
|
continue;
|
||||||
if (LM_FLAG_NOEXP & gh->gh_flags)
|
if (LM_FLAG_RECOVER & gh->gh_flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2165,18 +2080,26 @@ static void dump_glock_func(struct gfs2_glock *gl)
|
||||||
dump_glock(NULL, gl, true);
|
dump_glock(NULL, gl, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void withdraw_dq(struct gfs2_glock *gl)
|
static void withdraw_glock(struct gfs2_glock *gl)
|
||||||
{
|
{
|
||||||
spin_lock(&gl->gl_lockref.lock);
|
spin_lock(&gl->gl_lockref.lock);
|
||||||
if (!__lockref_is_dead(&gl->gl_lockref) &&
|
if (!__lockref_is_dead(&gl->gl_lockref)) {
|
||||||
glock_blocked_by_withdraw(gl))
|
/*
|
||||||
|
* We don't want to write back any more dirty data. Unlock the
|
||||||
|
* remaining inode and resource group glocks; this will cause
|
||||||
|
* their ->go_inval() hooks to toss out all the remaining
|
||||||
|
* cached data, dirty or not.
|
||||||
|
*/
|
||||||
|
if (gl->gl_ops->go_inval && gl->gl_state != LM_ST_UNLOCKED)
|
||||||
|
request_demote(gl, LM_ST_UNLOCKED, 0, false);
|
||||||
do_error(gl, LM_OUT_ERROR); /* remove pending waiters */
|
do_error(gl, LM_OUT_ERROR); /* remove pending waiters */
|
||||||
|
}
|
||||||
spin_unlock(&gl->gl_lockref.lock);
|
spin_unlock(&gl->gl_lockref.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfs2_gl_dq_holders(struct gfs2_sbd *sdp)
|
void gfs2_withdraw_glocks(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
glock_hash_walk(withdraw_dq, sdp);
|
glock_hash_walk(withdraw_glock, sdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2237,7 +2160,7 @@ static const char *hflags2str(char *buf, u16 flags, unsigned long iflags)
|
||||||
*p++ = 't';
|
*p++ = 't';
|
||||||
if (flags & LM_FLAG_TRY_1CB)
|
if (flags & LM_FLAG_TRY_1CB)
|
||||||
*p++ = 'T';
|
*p++ = 'T';
|
||||||
if (flags & LM_FLAG_NOEXP)
|
if (flags & LM_FLAG_RECOVER)
|
||||||
*p++ = 'e';
|
*p++ = 'e';
|
||||||
if (flags & LM_FLAG_ANY)
|
if (flags & LM_FLAG_ANY)
|
||||||
*p++ = 'A';
|
*p++ = 'A';
|
||||||
|
|
@ -2324,8 +2247,6 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
|
||||||
*p++ = 'o';
|
*p++ = 'o';
|
||||||
if (test_bit(GLF_BLOCKING, gflags))
|
if (test_bit(GLF_BLOCKING, gflags))
|
||||||
*p++ = 'b';
|
*p++ = 'b';
|
||||||
if (test_bit(GLF_UNLOCKED, gflags))
|
|
||||||
*p++ = 'x';
|
|
||||||
if (test_bit(GLF_INSTANTIATE_NEEDED, gflags))
|
if (test_bit(GLF_INSTANTIATE_NEEDED, gflags))
|
||||||
*p++ = 'n';
|
*p++ = 'n';
|
||||||
if (test_bit(GLF_INSTANTIATE_IN_PROG, gflags))
|
if (test_bit(GLF_INSTANTIATE_IN_PROG, gflags))
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,10 @@ enum {
|
||||||
* LM_FLAG_TRY_1CB
|
* LM_FLAG_TRY_1CB
|
||||||
* Send one blocking callback if TRY is set and the lock is not granted.
|
* Send one blocking callback if TRY is set and the lock is not granted.
|
||||||
*
|
*
|
||||||
* LM_FLAG_NOEXP
|
* LM_FLAG_RECOVER
|
||||||
* GFS sets this flag on lock requests it makes while doing journal recovery.
|
* GFS sets this flag on lock requests it makes while doing journal recovery.
|
||||||
* These special requests should not be blocked due to the recovery like
|
* While ordinary requests are blocked until the end of recovery, requests
|
||||||
* ordinary locks would be.
|
* with this flag set do proceed.
|
||||||
*
|
*
|
||||||
* LM_FLAG_ANY
|
* LM_FLAG_ANY
|
||||||
* A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
|
* A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
|
||||||
|
|
@ -80,7 +80,7 @@ enum {
|
||||||
|
|
||||||
#define LM_FLAG_TRY 0x0001
|
#define LM_FLAG_TRY 0x0001
|
||||||
#define LM_FLAG_TRY_1CB 0x0002
|
#define LM_FLAG_TRY_1CB 0x0002
|
||||||
#define LM_FLAG_NOEXP 0x0004
|
#define LM_FLAG_RECOVER 0x0004
|
||||||
#define LM_FLAG_ANY 0x0008
|
#define LM_FLAG_ANY 0x0008
|
||||||
#define LM_FLAG_NODE_SCOPE 0x0020
|
#define LM_FLAG_NODE_SCOPE 0x0020
|
||||||
#define GL_ASYNC 0x0040
|
#define GL_ASYNC 0x0040
|
||||||
|
|
@ -136,7 +136,7 @@ struct lm_lockops {
|
||||||
void (*lm_first_done) (struct gfs2_sbd *sdp);
|
void (*lm_first_done) (struct gfs2_sbd *sdp);
|
||||||
void (*lm_recovery_result) (struct gfs2_sbd *sdp, unsigned int jid,
|
void (*lm_recovery_result) (struct gfs2_sbd *sdp, unsigned int jid,
|
||||||
unsigned int result);
|
unsigned int result);
|
||||||
void (*lm_unmount) (struct gfs2_sbd *sdp);
|
void (*lm_unmount) (struct gfs2_sbd *sdp, bool clean);
|
||||||
void (*lm_withdraw) (struct gfs2_sbd *sdp);
|
void (*lm_withdraw) (struct gfs2_sbd *sdp);
|
||||||
void (*lm_put_lock) (struct gfs2_glock *gl);
|
void (*lm_put_lock) (struct gfs2_glock *gl);
|
||||||
int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state,
|
int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state,
|
||||||
|
|
@ -263,7 +263,7 @@ bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later);
|
||||||
void gfs2_cancel_delete_work(struct gfs2_glock *gl);
|
void gfs2_cancel_delete_work(struct gfs2_glock *gl);
|
||||||
void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
|
void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
|
||||||
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
|
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
|
||||||
void gfs2_gl_dq_holders(struct gfs2_sbd *sdp);
|
void gfs2_withdraw_glocks(struct gfs2_sbd *sdp);
|
||||||
void gfs2_glock_thaw(struct gfs2_sbd *sdp);
|
void gfs2_glock_thaw(struct gfs2_sbd *sdp);
|
||||||
void gfs2_glock_free(struct gfs2_glock *gl);
|
void gfs2_glock_free(struct gfs2_glock *gl);
|
||||||
void gfs2_glock_free_later(struct gfs2_glock *gl);
|
void gfs2_glock_free_later(struct gfs2_glock *gl);
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
struct workqueue_struct *gfs2_freeze_wq;
|
struct workqueue_struct *gfs2_freeze_wq;
|
||||||
|
|
||||||
extern struct workqueue_struct *gfs2_control_wq;
|
|
||||||
|
|
||||||
static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
|
static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||||
|
|
@ -45,7 +43,7 @@ static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
|
||||||
gl->gl_name.ln_type, gl->gl_name.ln_number,
|
gl->gl_name.ln_type, gl->gl_name.ln_number,
|
||||||
gfs2_glock2aspace(gl));
|
gfs2_glock2aspace(gl));
|
||||||
gfs2_lm(sdp, "AIL error\n");
|
gfs2_lm(sdp, "AIL error\n");
|
||||||
gfs2_withdraw_delayed(sdp);
|
gfs2_withdraw(sdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -83,9 +81,6 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync,
|
||||||
GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count));
|
GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count));
|
||||||
spin_unlock(&sdp->sd_ail_lock);
|
spin_unlock(&sdp->sd_ail_lock);
|
||||||
gfs2_log_unlock(sdp);
|
gfs2_log_unlock(sdp);
|
||||||
|
|
||||||
if (gfs2_withdrawing(sdp))
|
|
||||||
gfs2_withdraw(sdp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -178,7 +173,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_withdrawing_or_withdrawn(sdp));
|
WARN_ON_ONCE(error && !gfs2_withdrawn(sdp));
|
||||||
mapping_set_error(metamapping, error);
|
mapping_set_error(metamapping, error);
|
||||||
if (error)
|
if (error)
|
||||||
gfs2_io_error(sdp);
|
gfs2_io_error(sdp);
|
||||||
|
|
@ -237,6 +232,7 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
|
||||||
end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1;
|
end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1;
|
||||||
gfs2_rgrp_brelse(rgd);
|
gfs2_rgrp_brelse(rgd);
|
||||||
WARN_ON_ONCE(!(flags & DIO_METADATA));
|
WARN_ON_ONCE(!(flags & DIO_METADATA));
|
||||||
|
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
|
||||||
truncate_inode_pages_range(mapping, start, end);
|
truncate_inode_pages_range(mapping, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,6 +359,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
|
||||||
{
|
{
|
||||||
struct gfs2_inode *ip = gfs2_glock2inode(gl);
|
struct gfs2_inode *ip = gfs2_glock2inode(gl);
|
||||||
|
|
||||||
|
gfs2_assert_withdraw(gl->gl_name.ln_sbd, !atomic_read(&gl->gl_ail_count));
|
||||||
|
|
||||||
if (flags & DIO_METADATA) {
|
if (flags & DIO_METADATA) {
|
||||||
struct address_space *mapping = gfs2_glock2aspace(gl);
|
struct address_space *mapping = gfs2_glock2aspace(gl);
|
||||||
truncate_inode_pages(mapping, 0);
|
truncate_inode_pages(mapping, 0);
|
||||||
|
|
@ -608,10 +606,10 @@ static int freeze_go_xmote_bh(struct gfs2_glock *gl)
|
||||||
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
|
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
|
||||||
|
|
||||||
error = gfs2_find_jhead(sdp->sd_jdesc, &head);
|
error = gfs2_find_jhead(sdp->sd_jdesc, &head);
|
||||||
if (gfs2_assert_withdraw_delayed(sdp, !error))
|
if (gfs2_assert_withdraw(sdp, !error))
|
||||||
return error;
|
return error;
|
||||||
if (gfs2_assert_withdraw_delayed(sdp, head.lh_flags &
|
if (gfs2_assert_withdraw(sdp, head.lh_flags &
|
||||||
GFS2_LOG_HEAD_UNMOUNT))
|
GFS2_LOG_HEAD_UNMOUNT))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
gfs2_log_pointers_init(sdp, &head);
|
gfs2_log_pointers_init(sdp, &head);
|
||||||
}
|
}
|
||||||
|
|
@ -630,8 +628,7 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
|
||||||
struct gfs2_inode *ip = gl->gl_object;
|
struct gfs2_inode *ip = gl->gl_object;
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||||
|
|
||||||
if (!remote || sb_rdonly(sdp->sd_vfs) ||
|
if (!remote || test_bit(SDF_KILL, &sdp->sd_flags))
|
||||||
test_bit(SDF_KILL, &sdp->sd_flags))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gl->gl_demote_state == LM_ST_UNLOCKED &&
|
if (gl->gl_demote_state == LM_ST_UNLOCKED &&
|
||||||
|
|
@ -642,76 +639,8 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* inode_go_unlocked - wake up anyone waiting for dlm's unlock ast
|
|
||||||
* @gl: glock being unlocked
|
|
||||||
*
|
|
||||||
* For now, this is only used for the journal inode glock. In withdraw
|
|
||||||
* situations, we need to wait for the glock to be unlocked so that we know
|
|
||||||
* other nodes may proceed with recovery / journal replay.
|
|
||||||
*/
|
|
||||||
static void inode_go_unlocked(struct gfs2_glock *gl)
|
|
||||||
{
|
|
||||||
/* Note that we cannot reference gl_object because it's already set
|
|
||||||
* to NULL by this point in its lifecycle. */
|
|
||||||
if (!test_bit(GLF_UNLOCKED, &gl->gl_flags))
|
|
||||||
return;
|
|
||||||
clear_bit_unlock(GLF_UNLOCKED, &gl->gl_flags);
|
|
||||||
wake_up_bit(&gl->gl_flags, GLF_UNLOCKED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* nondisk_go_callback - used to signal when a node did a withdraw
|
|
||||||
* @gl: the nondisk glock
|
|
||||||
* @remote: true if this came from a different cluster node
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void nondisk_go_callback(struct gfs2_glock *gl, bool remote)
|
|
||||||
{
|
|
||||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
|
||||||
|
|
||||||
/* Ignore the callback unless it's from another node, and it's the
|
|
||||||
live lock. */
|
|
||||||
if (!remote || gl->gl_name.ln_number != GFS2_LIVE_LOCK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* First order of business is to cancel the demote request. We don't
|
|
||||||
* really want to demote a nondisk glock. At best it's just to inform
|
|
||||||
* us of another node's withdraw. We'll keep it in SH mode. */
|
|
||||||
clear_bit(GLF_DEMOTE, &gl->gl_flags);
|
|
||||||
clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags);
|
|
||||||
|
|
||||||
/* Ignore the unlock if we're withdrawn, unmounting, or in recovery. */
|
|
||||||
if (test_bit(SDF_NORECOVERY, &sdp->sd_flags) ||
|
|
||||||
test_bit(SDF_WITHDRAWN, &sdp->sd_flags) ||
|
|
||||||
test_bit(SDF_REMOTE_WITHDRAW, &sdp->sd_flags))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We only care when a node wants us to unlock, because that means
|
|
||||||
* they want a journal recovered. */
|
|
||||||
if (gl->gl_demote_state != LM_ST_UNLOCKED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sdp->sd_args.ar_spectator) {
|
|
||||||
fs_warn(sdp, "Spectator node cannot recover journals.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs_warn(sdp, "Some node has withdrawn; checking for recovery.\n");
|
|
||||||
set_bit(SDF_REMOTE_WITHDRAW, &sdp->sd_flags);
|
|
||||||
/*
|
|
||||||
* We can't call remote_withdraw directly here or gfs2_recover_journal
|
|
||||||
* because this is called from the glock unlock function and the
|
|
||||||
* remote_withdraw needs to enqueue and dequeue the same "live" glock
|
|
||||||
* we were called from. So we queue it to the control work queue in
|
|
||||||
* lock_dlm.
|
|
||||||
*/
|
|
||||||
queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_meta_glops = {
|
const struct gfs2_glock_operations gfs2_meta_glops = {
|
||||||
.go_type = LM_TYPE_META,
|
.go_type = LM_TYPE_META,
|
||||||
.go_flags = GLOF_NONDISK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_inode_glops = {
|
const struct gfs2_glock_operations gfs2_inode_glops = {
|
||||||
|
|
@ -722,7 +651,6 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
|
||||||
.go_dump = inode_go_dump,
|
.go_dump = inode_go_dump,
|
||||||
.go_type = LM_TYPE_INODE,
|
.go_type = LM_TYPE_INODE,
|
||||||
.go_flags = GLOF_ASPACE | GLOF_LVB,
|
.go_flags = GLOF_ASPACE | GLOF_LVB,
|
||||||
.go_unlocked = inode_go_unlocked,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_rgrp_glops = {
|
const struct gfs2_glock_operations gfs2_rgrp_glops = {
|
||||||
|
|
@ -738,36 +666,30 @@ const struct gfs2_glock_operations gfs2_freeze_glops = {
|
||||||
.go_xmote_bh = freeze_go_xmote_bh,
|
.go_xmote_bh = freeze_go_xmote_bh,
|
||||||
.go_callback = freeze_go_callback,
|
.go_callback = freeze_go_callback,
|
||||||
.go_type = LM_TYPE_NONDISK,
|
.go_type = LM_TYPE_NONDISK,
|
||||||
.go_flags = GLOF_NONDISK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_iopen_glops = {
|
const struct gfs2_glock_operations gfs2_iopen_glops = {
|
||||||
.go_type = LM_TYPE_IOPEN,
|
.go_type = LM_TYPE_IOPEN,
|
||||||
.go_callback = iopen_go_callback,
|
.go_callback = iopen_go_callback,
|
||||||
.go_dump = inode_go_dump,
|
.go_dump = inode_go_dump,
|
||||||
.go_flags = GLOF_NONDISK,
|
|
||||||
.go_subclass = 1,
|
.go_subclass = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_flock_glops = {
|
const struct gfs2_glock_operations gfs2_flock_glops = {
|
||||||
.go_type = LM_TYPE_FLOCK,
|
.go_type = LM_TYPE_FLOCK,
|
||||||
.go_flags = GLOF_NONDISK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_nondisk_glops = {
|
const struct gfs2_glock_operations gfs2_nondisk_glops = {
|
||||||
.go_type = LM_TYPE_NONDISK,
|
.go_type = LM_TYPE_NONDISK,
|
||||||
.go_flags = GLOF_NONDISK,
|
|
||||||
.go_callback = nondisk_go_callback,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_quota_glops = {
|
const struct gfs2_glock_operations gfs2_quota_glops = {
|
||||||
.go_type = LM_TYPE_QUOTA,
|
.go_type = LM_TYPE_QUOTA,
|
||||||
.go_flags = GLOF_LVB | GLOF_NONDISK,
|
.go_flags = GLOF_LVB,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations gfs2_journal_glops = {
|
const struct gfs2_glock_operations gfs2_journal_glops = {
|
||||||
.go_type = LM_TYPE_JOURNAL,
|
.go_type = LM_TYPE_JOURNAL,
|
||||||
.go_flags = GLOF_NONDISK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct gfs2_glock_operations *gfs2_glops_list[] = {
|
const struct gfs2_glock_operations *gfs2_glops_list[] = {
|
||||||
|
|
|
||||||
|
|
@ -223,13 +223,11 @@ struct gfs2_glock_operations {
|
||||||
void (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl,
|
void (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl,
|
||||||
const char *fs_id_buf);
|
const char *fs_id_buf);
|
||||||
void (*go_callback)(struct gfs2_glock *gl, bool remote);
|
void (*go_callback)(struct gfs2_glock *gl, bool remote);
|
||||||
void (*go_unlocked)(struct gfs2_glock *gl);
|
|
||||||
const int go_subclass;
|
const int go_subclass;
|
||||||
const int go_type;
|
const int go_type;
|
||||||
const unsigned long go_flags;
|
const unsigned long go_flags;
|
||||||
#define GLOF_ASPACE 1 /* address space attached */
|
#define GLOF_ASPACE 1 /* address space attached */
|
||||||
#define GLOF_LVB 2 /* Lock Value Block attached */
|
#define GLOF_LVB 2 /* Lock Value Block attached */
|
||||||
#define GLOF_NONDISK 8 /* not I/O related */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -326,7 +324,6 @@ enum {
|
||||||
GLF_LRU = 13,
|
GLF_LRU = 13,
|
||||||
GLF_OBJECT = 14, /* Used only for tracing */
|
GLF_OBJECT = 14, /* Used only for tracing */
|
||||||
GLF_BLOCKING = 15,
|
GLF_BLOCKING = 15,
|
||||||
GLF_UNLOCKED = 16, /* Wait for glock to be unlocked */
|
|
||||||
GLF_TRY_TO_EVICT = 17, /* iopen glocks only */
|
GLF_TRY_TO_EVICT = 17, /* iopen glocks only */
|
||||||
GLF_VERIFY_DELETE = 18, /* iopen glocks only */
|
GLF_VERIFY_DELETE = 18, /* iopen glocks only */
|
||||||
GLF_PENDING_REPLY = 19,
|
GLF_PENDING_REPLY = 19,
|
||||||
|
|
@ -520,8 +517,6 @@ struct gfs2_jdesc {
|
||||||
|
|
||||||
struct list_head jd_revoke_list;
|
struct list_head jd_revoke_list;
|
||||||
unsigned int jd_replay_tail;
|
unsigned int jd_replay_tail;
|
||||||
|
|
||||||
u64 jd_no_addr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gfs2_statfs_change_host {
|
struct gfs2_statfs_change_host {
|
||||||
|
|
@ -542,8 +537,7 @@ struct gfs2_statfs_change_host {
|
||||||
|
|
||||||
#define GFS2_ERRORS_DEFAULT GFS2_ERRORS_WITHDRAW
|
#define GFS2_ERRORS_DEFAULT GFS2_ERRORS_WITHDRAW
|
||||||
#define GFS2_ERRORS_WITHDRAW 0
|
#define GFS2_ERRORS_WITHDRAW 0
|
||||||
#define GFS2_ERRORS_CONTINUE 1 /* place holder for future feature */
|
#define GFS2_ERRORS_DEACTIVATE 1
|
||||||
#define GFS2_ERRORS_RO 2 /* place holder for future feature */
|
|
||||||
#define GFS2_ERRORS_PANIC 3
|
#define GFS2_ERRORS_PANIC 3
|
||||||
|
|
||||||
struct gfs2_args {
|
struct gfs2_args {
|
||||||
|
|
@ -559,7 +553,7 @@ struct gfs2_args {
|
||||||
unsigned int ar_data:2; /* ordered/writeback */
|
unsigned int ar_data:2; /* ordered/writeback */
|
||||||
unsigned int ar_meta:1; /* mount metafs */
|
unsigned int ar_meta:1; /* mount metafs */
|
||||||
unsigned int ar_discard:1; /* discard requests */
|
unsigned int ar_discard:1; /* discard requests */
|
||||||
unsigned int ar_errors:2; /* errors=withdraw | panic */
|
unsigned int ar_errors:2; /* errors=withdraw | deactivate | panic */
|
||||||
unsigned int ar_nobarrier:1; /* do not send barriers */
|
unsigned int ar_nobarrier:1; /* do not send barriers */
|
||||||
unsigned int ar_rgrplvb:1; /* use lvbs for rgrp info */
|
unsigned int ar_rgrplvb:1; /* use lvbs for rgrp info */
|
||||||
unsigned int ar_got_rgrplvb:1; /* Was the rgrplvb opt given? */
|
unsigned int ar_got_rgrplvb:1; /* Was the rgrplvb opt given? */
|
||||||
|
|
@ -585,6 +579,7 @@ struct gfs2_tune {
|
||||||
unsigned int gt_complain_secs;
|
unsigned int gt_complain_secs;
|
||||||
unsigned int gt_statfs_quantum;
|
unsigned int gt_statfs_quantum;
|
||||||
unsigned int gt_statfs_slow;
|
unsigned int gt_statfs_slow;
|
||||||
|
unsigned int gt_withdraw_helper_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -599,11 +594,6 @@ enum {
|
||||||
SDF_SKIP_DLM_UNLOCK = 8,
|
SDF_SKIP_DLM_UNLOCK = 8,
|
||||||
SDF_FORCE_AIL_FLUSH = 9,
|
SDF_FORCE_AIL_FLUSH = 9,
|
||||||
SDF_FREEZE_INITIATOR = 10,
|
SDF_FREEZE_INITIATOR = 10,
|
||||||
SDF_WITHDRAWING = 11, /* Will withdraw eventually */
|
|
||||||
SDF_WITHDRAW_IN_PROG = 12, /* Withdraw is in progress */
|
|
||||||
SDF_REMOTE_WITHDRAW = 13, /* Performing remote recovery */
|
|
||||||
SDF_WITHDRAW_RECOVERY = 14, /* Wait for journal recovery when we are
|
|
||||||
withdrawing */
|
|
||||||
SDF_KILL = 15,
|
SDF_KILL = 15,
|
||||||
SDF_EVICTING = 16,
|
SDF_EVICTING = 16,
|
||||||
SDF_FROZEN = 17,
|
SDF_FROZEN = 17,
|
||||||
|
|
@ -716,11 +706,13 @@ struct gfs2_sbd {
|
||||||
struct gfs2_glock *sd_rename_gl;
|
struct gfs2_glock *sd_rename_gl;
|
||||||
struct gfs2_glock *sd_freeze_gl;
|
struct gfs2_glock *sd_freeze_gl;
|
||||||
struct work_struct sd_freeze_work;
|
struct work_struct sd_freeze_work;
|
||||||
|
struct work_struct sd_withdraw_work;
|
||||||
wait_queue_head_t sd_kill_wait;
|
wait_queue_head_t sd_kill_wait;
|
||||||
wait_queue_head_t sd_async_glock_wait;
|
wait_queue_head_t sd_async_glock_wait;
|
||||||
atomic_t sd_glock_disposal;
|
atomic_t sd_glock_disposal;
|
||||||
struct completion sd_locking_init;
|
struct completion sd_locking_init;
|
||||||
struct completion sd_wdack;
|
struct completion sd_withdraw_helper;
|
||||||
|
int sd_withdraw_helper_status;
|
||||||
struct delayed_work sd_control_work;
|
struct delayed_work sd_control_work;
|
||||||
|
|
||||||
/* Inode Stuff */
|
/* Inode Stuff */
|
||||||
|
|
@ -761,7 +753,6 @@ struct gfs2_sbd {
|
||||||
struct gfs2_jdesc *sd_jdesc;
|
struct gfs2_jdesc *sd_jdesc;
|
||||||
struct gfs2_holder sd_journal_gh;
|
struct gfs2_holder sd_journal_gh;
|
||||||
struct gfs2_holder sd_jinode_gh;
|
struct gfs2_holder sd_jinode_gh;
|
||||||
struct gfs2_glock *sd_jinode_gl;
|
|
||||||
|
|
||||||
struct gfs2_holder sd_sc_gh;
|
struct gfs2_holder sd_sc_gh;
|
||||||
struct buffer_head *sd_sc_bh;
|
struct buffer_head *sd_sc_bh;
|
||||||
|
|
@ -846,7 +837,6 @@ struct gfs2_sbd {
|
||||||
|
|
||||||
unsigned long sd_last_warning;
|
unsigned long sd_last_warning;
|
||||||
struct dentry *debugfs_dir; /* debugfs directory */
|
struct dentry *debugfs_dir; /* debugfs directory */
|
||||||
unsigned long sd_glock_dqs_held;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GFS2_BAD_INO 1
|
#define GFS2_BAD_INO 1
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,19 @@ static int iget_set(struct inode *inode, void *opaque)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gfs2_setup_inode(struct inode *inode)
|
||||||
|
{
|
||||||
|
gfp_t gfp_mask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure all page cache allocations are done from GFP_NOFS context to
|
||||||
|
* prevent direct reclaim recursion back into the filesystem and blowing
|
||||||
|
* stacks or deadlocking.
|
||||||
|
*/
|
||||||
|
gfp_mask = mapping_gfp_mask(inode->i_mapping);
|
||||||
|
mapping_set_gfp_mask(inode->i_mapping, gfp_mask & ~__GFP_FS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gfs2_inode_lookup - Lookup an inode
|
* gfs2_inode_lookup - Lookup an inode
|
||||||
* @sb: The super block
|
* @sb: The super block
|
||||||
|
|
@ -132,6 +145,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
||||||
struct gfs2_glock *io_gl;
|
struct gfs2_glock *io_gl;
|
||||||
int extra_flags = 0;
|
int extra_flags = 0;
|
||||||
|
|
||||||
|
gfs2_setup_inode(inode);
|
||||||
error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE,
|
error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE,
|
||||||
&ip->i_gl);
|
&ip->i_gl);
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
|
|
@ -752,6 +766,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
if (!inode)
|
if (!inode)
|
||||||
goto fail_gunlock;
|
goto fail_gunlock;
|
||||||
|
gfs2_setup_inode(inode);
|
||||||
ip = GFS2_I(inode);
|
ip = GFS2_I(inode);
|
||||||
|
|
||||||
error = posix_acl_create(dir, &mode, &default_acl, &acl);
|
error = posix_acl_create(dir, &mode, &default_acl, &acl);
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ err:
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gfs2_setup_inode(struct inode *inode);
|
||||||
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
|
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
|
||||||
u64 no_addr, u64 no_formal_ino,
|
u64 no_addr, u64 no_formal_ino,
|
||||||
unsigned int blktype);
|
unsigned int blktype);
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
|
|
||||||
#include "incore.h"
|
#include "incore.h"
|
||||||
#include "glock.h"
|
|
||||||
#include "glops.h"
|
|
||||||
#include "recovery.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "trace_gfs2.h"
|
#include "trace_gfs2.h"
|
||||||
|
|
@ -139,8 +136,6 @@ static void gdlm_ast(void *arg)
|
||||||
|
|
||||||
switch (gl->gl_lksb.sb_status) {
|
switch (gl->gl_lksb.sb_status) {
|
||||||
case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */
|
case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */
|
||||||
if (gl->gl_ops->go_unlocked)
|
|
||||||
gl->gl_ops->go_unlocked(gl);
|
|
||||||
gfs2_glock_free(gl);
|
gfs2_glock_free(gl);
|
||||||
return;
|
return;
|
||||||
case -DLM_ECANCEL: /* Cancel while getting lock */
|
case -DLM_ECANCEL: /* Cancel while getting lock */
|
||||||
|
|
@ -399,7 +394,6 @@ static void gdlm_cancel(struct gfs2_glock *gl)
|
||||||
/*
|
/*
|
||||||
* dlm/gfs2 recovery coordination using dlm_recover callbacks
|
* dlm/gfs2 recovery coordination using dlm_recover callbacks
|
||||||
*
|
*
|
||||||
* 0. gfs2 checks for another cluster node withdraw, needing journal replay
|
|
||||||
* 1. dlm_controld sees lockspace members change
|
* 1. dlm_controld sees lockspace members change
|
||||||
* 2. dlm_controld blocks dlm-kernel locking activity
|
* 2. dlm_controld blocks dlm-kernel locking activity
|
||||||
* 3. dlm_controld within dlm-kernel notifies gfs2 (recover_prep)
|
* 3. dlm_controld within dlm-kernel notifies gfs2 (recover_prep)
|
||||||
|
|
@ -657,28 +651,6 @@ static int control_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags)
|
||||||
&ls->ls_control_lksb, "control_lock");
|
&ls->ls_control_lksb, "control_lock");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* remote_withdraw - react to a node withdrawing from the file system
|
|
||||||
* @sdp: The superblock
|
|
||||||
*/
|
|
||||||
static void remote_withdraw(struct gfs2_sbd *sdp)
|
|
||||||
{
|
|
||||||
struct gfs2_jdesc *jd;
|
|
||||||
int ret = 0, count = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
|
|
||||||
if (jd->jd_jid == sdp->sd_lockstruct.ls_jid)
|
|
||||||
continue;
|
|
||||||
ret = gfs2_recover_journal(jd, true);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now drop the additional reference we acquired */
|
|
||||||
fs_err(sdp, "Journals checked: %d, ret = %d.\n", count, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gfs2_control_func(struct work_struct *work)
|
static void gfs2_control_func(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
|
struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
|
||||||
|
|
@ -689,13 +661,6 @@ static void gfs2_control_func(struct work_struct *work)
|
||||||
int recover_size;
|
int recover_size;
|
||||||
int i, error;
|
int i, error;
|
||||||
|
|
||||||
/* First check for other nodes that may have done a withdraw. */
|
|
||||||
if (test_bit(SDF_REMOTE_WITHDRAW, &sdp->sd_flags)) {
|
|
||||||
remote_withdraw(sdp);
|
|
||||||
clear_bit(SDF_REMOTE_WITHDRAW, &sdp->sd_flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&ls->ls_recover_spin);
|
spin_lock(&ls->ls_recover_spin);
|
||||||
/*
|
/*
|
||||||
* No MOUNT_DONE means we're still mounting; control_mount()
|
* No MOUNT_DONE means we're still mounting; control_mount()
|
||||||
|
|
@ -1195,7 +1160,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_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_withdrawn(sdp)) {
|
||||||
fs_err(sdp, "recover_prep ignored due to withdraw.\n");
|
fs_err(sdp, "recover_prep ignored due to withdraw.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1221,7 +1186,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_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_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;
|
||||||
|
|
@ -1250,7 +1215,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_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_withdrawn(sdp)) {
|
||||||
fs_err(sdp, "recover_done ignored due to withdraw.\n");
|
fs_err(sdp, "recover_done ignored due to withdraw.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1281,7 +1246,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_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_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;
|
||||||
|
|
@ -1438,7 +1403,15 @@ static void gdlm_first_done(struct gfs2_sbd *sdp)
|
||||||
fs_err(sdp, "mount first_done error %d\n", error);
|
fs_err(sdp, "mount first_done error %d\n", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gdlm_unmount(struct gfs2_sbd *sdp)
|
/*
|
||||||
|
* gdlm_unmount - release our lockspace
|
||||||
|
* @sdp: the superblock
|
||||||
|
* @clean: Indicates whether or not the remaining nodes in the cluster should
|
||||||
|
* perform recovery. Recovery is necessary when a node withdraws and
|
||||||
|
* its journal remains dirty. Recovery isn't necessary when a node
|
||||||
|
* cleanly unmounts a filesystem.
|
||||||
|
*/
|
||||||
|
static void gdlm_unmount(struct gfs2_sbd *sdp, bool clean)
|
||||||
{
|
{
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
|
|
||||||
|
|
@ -1456,7 +1429,9 @@ static void gdlm_unmount(struct gfs2_sbd *sdp)
|
||||||
release:
|
release:
|
||||||
down_write(&ls->ls_sem);
|
down_write(&ls->ls_sem);
|
||||||
if (ls->ls_dlm) {
|
if (ls->ls_dlm) {
|
||||||
dlm_release_lockspace(ls->ls_dlm, DLM_RELEASE_NORMAL);
|
dlm_release_lockspace(ls->ls_dlm,
|
||||||
|
clean ? DLM_RELEASE_NORMAL :
|
||||||
|
DLM_RELEASE_RECOVER);
|
||||||
ls->ls_dlm = NULL;
|
ls->ls_dlm = NULL;
|
||||||
}
|
}
|
||||||
up_write(&ls->ls_sem);
|
up_write(&ls->ls_sem);
|
||||||
|
|
|
||||||
|
|
@ -112,13 +112,11 @@ __acquires(&sdp->sd_ail_lock)
|
||||||
&tr->tr_ail2_list);
|
&tr->tr_ail2_list);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!cmpxchg(&sdp->sd_log_error, 0, -EIO)) {
|
if (!cmpxchg(&sdp->sd_log_error, 0, -EIO))
|
||||||
gfs2_io_error_bh(sdp, bh);
|
gfs2_io_error_bh(sdp, bh);
|
||||||
gfs2_withdraw_delayed(sdp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_withdrawn(sdp)) {
|
||||||
gfs2_remove_from_ail(bd);
|
gfs2_remove_from_ail(bd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -324,10 +322,8 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!buffer_uptodate(bh) &&
|
if (!buffer_uptodate(bh) &&
|
||||||
!cmpxchg(&sdp->sd_log_error, 0, -EIO)) {
|
!cmpxchg(&sdp->sd_log_error, 0, -EIO))
|
||||||
gfs2_io_error_bh(sdp, bh);
|
gfs2_io_error_bh(sdp, bh);
|
||||||
gfs2_withdraw_delayed(sdp);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* If we have space for revokes and the bd is no longer on any
|
* If we have space for revokes and the bd is no longer on any
|
||||||
* buf list, we can just add a revoke for it immediately and
|
* buf list, we can just add a revoke for it immediately and
|
||||||
|
|
@ -807,9 +803,6 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -837,7 +830,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_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
|
page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
|
||||||
|
|
@ -984,12 +977,9 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
|
||||||
gfs2_ail1_wait(sdp);
|
gfs2_ail1_wait(sdp);
|
||||||
empty = gfs2_ail1_empty(sdp, 0);
|
empty = gfs2_ail1_empty(sdp, 0);
|
||||||
|
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfs2_withdrawing(sdp))
|
|
||||||
gfs2_withdraw(sdp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1050,7 +1040,7 @@ repeat:
|
||||||
* 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_withdrawing_or_withdrawn(sdp) ||
|
if (gfs2_withdrawn(sdp) ||
|
||||||
!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
|
!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1071,7 +1061,7 @@ repeat:
|
||||||
sdp->sd_log_tr = NULL;
|
sdp->sd_log_tr = NULL;
|
||||||
tr->tr_first = first_log_head;
|
tr->tr_first = first_log_head;
|
||||||
if (unlikely(frozen)) {
|
if (unlikely(frozen)) {
|
||||||
if (gfs2_assert_withdraw_delayed(sdp,
|
if (gfs2_assert_withdraw(sdp,
|
||||||
!tr->tr_num_buf_new && !tr->tr_num_databuf_new))
|
!tr->tr_num_buf_new && !tr->tr_num_databuf_new))
|
||||||
goto out_withdraw;
|
goto out_withdraw;
|
||||||
}
|
}
|
||||||
|
|
@ -1096,18 +1086,18 @@ repeat:
|
||||||
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
|
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
|
||||||
|
|
||||||
if (unlikely(frozen))
|
if (unlikely(frozen))
|
||||||
if (gfs2_assert_withdraw_delayed(sdp, !reserved_revokes))
|
if (gfs2_assert_withdraw(sdp, !reserved_revokes))
|
||||||
goto out_withdraw;
|
goto out_withdraw;
|
||||||
|
|
||||||
gfs2_ordered_write(sdp);
|
gfs2_ordered_write(sdp);
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
goto out_withdraw;
|
goto out_withdraw;
|
||||||
lops_before_commit(sdp, tr);
|
lops_before_commit(sdp, tr);
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
goto out_withdraw;
|
goto out_withdraw;
|
||||||
if (sdp->sd_jdesc)
|
if (sdp->sd_jdesc)
|
||||||
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_withdrawing_or_withdrawn(sdp))
|
if (gfs2_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) {
|
||||||
|
|
@ -1115,7 +1105,7 @@ repeat:
|
||||||
} 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_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
goto out_withdraw;
|
goto out_withdraw;
|
||||||
lops_after_commit(sdp, tr);
|
lops_after_commit(sdp, tr);
|
||||||
|
|
||||||
|
|
@ -1133,7 +1123,7 @@ repeat:
|
||||||
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_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
goto out_withdraw;
|
goto out_withdraw;
|
||||||
log_write_header(sdp, flags);
|
log_write_header(sdp, flags);
|
||||||
}
|
}
|
||||||
|
|
@ -1151,13 +1141,11 @@ out_end:
|
||||||
reserved_blocks += (reserved_revokes - sdp->sd_ldptrs) / sdp->sd_inptrs;
|
reserved_blocks += (reserved_revokes - sdp->sd_ldptrs) / sdp->sd_inptrs;
|
||||||
out:
|
out:
|
||||||
if (used_blocks != reserved_blocks) {
|
if (used_blocks != reserved_blocks) {
|
||||||
gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks);
|
gfs2_assert_withdraw(sdp, used_blocks < reserved_blocks);
|
||||||
gfs2_log_release(sdp, reserved_blocks - used_blocks);
|
gfs2_log_release(sdp, reserved_blocks - used_blocks);
|
||||||
}
|
}
|
||||||
up_write(&sdp->sd_log_flush_lock);
|
up_write(&sdp->sd_log_flush_lock);
|
||||||
gfs2_trans_free(sdp, tr);
|
gfs2_trans_free(sdp, tr);
|
||||||
if (gfs2_withdrawing(sdp))
|
|
||||||
gfs2_withdraw(sdp);
|
|
||||||
trace_gfs2_log_flush(sdp, 0, flags);
|
trace_gfs2_log_flush(sdp, 0, flags);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1304,20 +1292,9 @@ int gfs2_logd(void *data)
|
||||||
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_should_stop()) {
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Check for errors writing to the journal */
|
|
||||||
if (sdp->sd_log_error) {
|
|
||||||
gfs2_lm(sdp,
|
|
||||||
"GFS2: fsid=%s: error %d: "
|
|
||||||
"withdrawing the file system to "
|
|
||||||
"prevent further damage.\n",
|
|
||||||
sdp->sd_fsname, sdp->sd_log_error);
|
|
||||||
gfs2_withdraw(sdp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
|
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
|
||||||
gfs2_ail1_empty(sdp, 0);
|
gfs2_ail1_empty(sdp, 0);
|
||||||
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
|
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
|
||||||
|
|
@ -1340,15 +1317,11 @@ int gfs2_logd(void *data)
|
||||||
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 ||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||||
if (test_set_buffer_pinned(bh))
|
if (test_set_buffer_pinned(bh))
|
||||||
gfs2_assert_withdraw(sdp, 0);
|
gfs2_assert_withdraw(sdp, 0);
|
||||||
if (!buffer_uptodate(bh))
|
if (!buffer_uptodate(bh))
|
||||||
gfs2_io_error_bh_wd(sdp, bh);
|
gfs2_io_error_bh(sdp, bh);
|
||||||
bd = bh->b_private;
|
bd = bh->b_private;
|
||||||
/* If this buffer is in the AIL and it has already been written
|
/* If this buffer is in the AIL and it has already been written
|
||||||
* to in-place disk block, remove it from the AIL.
|
* to in-place disk block, remove it from the AIL.
|
||||||
|
|
@ -209,10 +209,7 @@ static void gfs2_end_log_write(struct bio *bio)
|
||||||
if (!cmpxchg(&sdp->sd_log_error, 0, err))
|
if (!cmpxchg(&sdp->sd_log_error, 0, err))
|
||||||
fs_err(sdp, "Error %d writing to journal, jid=%u\n",
|
fs_err(sdp, "Error %d writing to journal, jid=%u\n",
|
||||||
err, sdp->sd_jdesc->jd_jid);
|
err, sdp->sd_jdesc->jd_jid);
|
||||||
gfs2_withdraw_delayed(sdp);
|
gfs2_withdraw(sdp);
|
||||||
/* prevent more writes to the journal */
|
|
||||||
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
|
|
||||||
wake_up(&sdp->sd_logd_waitq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bio_for_each_segment_all(bvec, bio, iter_all) {
|
bio_for_each_segment_all(bvec, bio, iter_all) {
|
||||||
|
|
@ -487,7 +484,7 @@ static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs)
|
||||||
new = bio_alloc(prev->bi_bdev, nr_iovecs, prev->bi_opf, GFP_NOIO);
|
new = bio_alloc(prev->bi_bdev, nr_iovecs, prev->bi_opf, GFP_NOIO);
|
||||||
bio_clone_blkg_association(new, prev);
|
bio_clone_blkg_association(new, prev);
|
||||||
new->bi_iter.bi_sector = bio_end_sector(prev);
|
new->bi_iter.bi_sector = bio_end_sector(prev);
|
||||||
bio_chain(new, prev);
|
bio_chain(prev, new);
|
||||||
submit_bio(prev);
|
submit_bio(prev);
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
@ -562,8 +559,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
|
||||||
bio = gfs2_log_alloc_bio(sdp, dblock, gfs2_end_log_read);
|
bio = gfs2_log_alloc_bio(sdp, dblock, gfs2_end_log_read);
|
||||||
bio->bi_opf = REQ_OP_READ;
|
bio->bi_opf = REQ_OP_READ;
|
||||||
add_block_to_new_bio:
|
add_block_to_new_bio:
|
||||||
if (!bio_add_folio(bio, folio, bsize, off))
|
bio_add_folio_nofail(bio, folio, bsize, off);
|
||||||
BUG();
|
|
||||||
block_added:
|
block_added:
|
||||||
off += bsize;
|
off += bsize;
|
||||||
if (off == folio_size(folio))
|
if (off == folio_size(folio))
|
||||||
|
|
|
||||||
|
|
@ -263,8 +263,7 @@ 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 (gfs2_withdrawing_or_withdrawn(sdp) &&
|
if (gfs2_withdrawn(sdp)) {
|
||||||
!gfs2_withdraw_in_prog(sdp)) {
|
|
||||||
*bhp = NULL;
|
*bhp = NULL;
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +302,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
|
||||||
if (unlikely(!buffer_uptodate(bh))) {
|
if (unlikely(!buffer_uptodate(bh))) {
|
||||||
struct gfs2_trans *tr = current->journal_info;
|
struct gfs2_trans *tr = current->journal_info;
|
||||||
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
|
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
|
||||||
gfs2_io_error_bh_wd(sdp, bh);
|
gfs2_io_error_bh(sdp, bh);
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
*bhp = NULL;
|
*bhp = NULL;
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -322,8 +321,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)
|
int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||||
{
|
{
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp) &&
|
if (gfs2_withdrawn(sdp))
|
||||||
!gfs2_withdraw_in_prog(sdp))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
wait_on_buffer(bh);
|
wait_on_buffer(bh);
|
||||||
|
|
@ -331,11 +329,10 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||||
if (!buffer_uptodate(bh)) {
|
if (!buffer_uptodate(bh)) {
|
||||||
struct gfs2_trans *tr = current->journal_info;
|
struct gfs2_trans *tr = current->journal_info;
|
||||||
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
|
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
|
||||||
gfs2_io_error_bh_wd(sdp, bh);
|
gfs2_io_error_bh(sdp, bh);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp) &&
|
if (gfs2_withdrawn(sdp))
|
||||||
!gfs2_withdraw_in_prog(sdp))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
|
||||||
gt->gt_new_files_jdata = 0;
|
gt->gt_new_files_jdata = 0;
|
||||||
gt->gt_max_readahead = BIT(18);
|
gt->gt_max_readahead = BIT(18);
|
||||||
gt->gt_complain_secs = 10;
|
gt->gt_complain_secs = 10;
|
||||||
|
gt->gt_withdraw_helper_timeout = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_sbd(struct gfs2_sbd *sdp)
|
void free_sbd(struct gfs2_sbd *sdp)
|
||||||
|
|
@ -92,7 +93,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
|
||||||
init_waitqueue_head(&sdp->sd_async_glock_wait);
|
init_waitqueue_head(&sdp->sd_async_glock_wait);
|
||||||
atomic_set(&sdp->sd_glock_disposal, 0);
|
atomic_set(&sdp->sd_glock_disposal, 0);
|
||||||
init_completion(&sdp->sd_locking_init);
|
init_completion(&sdp->sd_locking_init);
|
||||||
init_completion(&sdp->sd_wdack);
|
init_completion(&sdp->sd_withdraw_helper);
|
||||||
spin_lock_init(&sdp->sd_statfs_spin);
|
spin_lock_init(&sdp->sd_statfs_spin);
|
||||||
|
|
||||||
spin_lock_init(&sdp->sd_rindex_spin);
|
spin_lock_init(&sdp->sd_rindex_spin);
|
||||||
|
|
@ -370,7 +371,7 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
|
||||||
error = gfs2_glock_nq_num(sdp,
|
error = gfs2_glock_nq_num(sdp,
|
||||||
GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
|
GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
|
||||||
LM_ST_EXCLUSIVE,
|
LM_ST_EXCLUSIVE,
|
||||||
LM_FLAG_NOEXP | GL_NOCACHE | GL_NOPID,
|
LM_FLAG_RECOVER | GL_NOCACHE | GL_NOPID,
|
||||||
mount_gh);
|
mount_gh);
|
||||||
if (error) {
|
if (error) {
|
||||||
fs_err(sdp, "can't acquire mount glock: %d\n", error);
|
fs_err(sdp, "can't acquire mount glock: %d\n", error);
|
||||||
|
|
@ -380,7 +381,7 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
|
||||||
error = gfs2_glock_nq_num(sdp,
|
error = gfs2_glock_nq_num(sdp,
|
||||||
GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
|
GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
|
||||||
LM_ST_SHARED,
|
LM_ST_SHARED,
|
||||||
LM_FLAG_NOEXP | GL_EXACT | GL_NOPID,
|
LM_FLAG_RECOVER | GL_EXACT | GL_NOPID,
|
||||||
&sdp->sd_live_gh);
|
&sdp->sd_live_gh);
|
||||||
if (error) {
|
if (error) {
|
||||||
fs_err(sdp, "can't acquire live glock: %d\n", error);
|
fs_err(sdp, "can't acquire live glock: %d\n", error);
|
||||||
|
|
@ -542,8 +543,6 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
|
||||||
mutex_lock(&sdp->sd_jindex_mutex);
|
mutex_lock(&sdp->sd_jindex_mutex);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct gfs2_inode *jip;
|
|
||||||
|
|
||||||
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh);
|
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
|
|
@ -584,8 +583,6 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
|
||||||
d_mark_dontcache(jd->jd_inode);
|
d_mark_dontcache(jd->jd_inode);
|
||||||
spin_lock(&sdp->sd_jindex_spin);
|
spin_lock(&sdp->sd_jindex_spin);
|
||||||
jd->jd_jid = sdp->sd_journals++;
|
jd->jd_jid = sdp->sd_journals++;
|
||||||
jip = GFS2_I(jd->jd_inode);
|
|
||||||
jd->jd_no_addr = jip->i_no_addr;
|
|
||||||
list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
|
list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
|
||||||
spin_unlock(&sdp->sd_jindex_spin);
|
spin_unlock(&sdp->sd_jindex_spin);
|
||||||
}
|
}
|
||||||
|
|
@ -745,7 +742,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
||||||
error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
|
error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
|
||||||
&gfs2_journal_glops,
|
&gfs2_journal_glops,
|
||||||
LM_ST_EXCLUSIVE,
|
LM_ST_EXCLUSIVE,
|
||||||
LM_FLAG_NOEXP | GL_NOCACHE | GL_NOPID,
|
LM_FLAG_RECOVER | GL_NOPID,
|
||||||
&sdp->sd_journal_gh);
|
&sdp->sd_journal_gh);
|
||||||
if (error) {
|
if (error) {
|
||||||
fs_err(sdp, "can't acquire journal glock: %d\n", error);
|
fs_err(sdp, "can't acquire journal glock: %d\n", error);
|
||||||
|
|
@ -753,9 +750,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = GFS2_I(sdp->sd_jdesc->jd_inode);
|
ip = GFS2_I(sdp->sd_jdesc->jd_inode);
|
||||||
sdp->sd_jinode_gl = ip->i_gl;
|
|
||||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
|
||||||
LM_FLAG_NOEXP | GL_EXACT |
|
LM_FLAG_RECOVER | GL_EXACT |
|
||||||
GL_NOCACHE | GL_NOPID,
|
GL_NOCACHE | GL_NOPID,
|
||||||
&sdp->sd_jinode_gh);
|
&sdp->sd_jinode_gh);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
@ -821,13 +817,10 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
||||||
fail_statfs:
|
fail_statfs:
|
||||||
uninit_statfs(sdp);
|
uninit_statfs(sdp);
|
||||||
fail_jinode_gh:
|
fail_jinode_gh:
|
||||||
/* A withdraw may have done dq/uninit so now we need to check it */
|
if (!sdp->sd_args.ar_spectator)
|
||||||
if (!sdp->sd_args.ar_spectator &&
|
|
||||||
gfs2_holder_initialized(&sdp->sd_jinode_gh))
|
|
||||||
gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
|
gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
|
||||||
fail_journal_gh:
|
fail_journal_gh:
|
||||||
if (!sdp->sd_args.ar_spectator &&
|
if (!sdp->sd_args.ar_spectator)
|
||||||
gfs2_holder_initialized(&sdp->sd_journal_gh))
|
|
||||||
gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
|
gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
|
||||||
fail_jindex:
|
fail_jindex:
|
||||||
gfs2_jindex_free(sdp);
|
gfs2_jindex_free(sdp);
|
||||||
|
|
@ -1040,8 +1033,8 @@ hostdata_error:
|
||||||
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 (!gfs2_withdrawing_or_withdrawn(sdp) && lm->lm_unmount)
|
if (!gfs2_withdrawn(sdp) && lm->lm_unmount)
|
||||||
lm->lm_unmount(sdp);
|
lm->lm_unmount(sdp, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_on_journal(struct gfs2_sbd *sdp)
|
static int wait_on_journal(struct gfs2_sbd *sdp)
|
||||||
|
|
@ -1183,7 +1176,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||||
|
|
||||||
mapping = gfs2_aspace(sdp);
|
mapping = gfs2_aspace(sdp);
|
||||||
mapping->a_ops = &gfs2_rgrp_aops;
|
mapping->a_ops = &gfs2_rgrp_aops;
|
||||||
mapping_set_gfp_mask(mapping, GFP_NOFS);
|
gfs2_setup_inode(sdp->sd_inode);
|
||||||
|
|
||||||
error = init_names(sdp, silent);
|
error = init_names(sdp, silent);
|
||||||
if (error)
|
if (error)
|
||||||
|
|
@ -1215,6 +1208,8 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||||
if (error)
|
if (error)
|
||||||
goto fail_debug;
|
goto fail_debug;
|
||||||
|
|
||||||
|
INIT_WORK(&sdp->sd_withdraw_work, gfs2_withdraw_func);
|
||||||
|
|
||||||
error = init_locking(sdp, &mount_gh, DO);
|
error = init_locking(sdp, &mount_gh, DO);
|
||||||
if (error)
|
if (error)
|
||||||
goto fail_lm;
|
goto fail_lm;
|
||||||
|
|
@ -1401,12 +1396,14 @@ static const struct constant_table gfs2_param_data[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum opt_errors {
|
enum opt_errors {
|
||||||
Opt_errors_withdraw = GFS2_ERRORS_WITHDRAW,
|
Opt_errors_withdraw = GFS2_ERRORS_WITHDRAW,
|
||||||
Opt_errors_panic = GFS2_ERRORS_PANIC,
|
Opt_errors_deactivate = GFS2_ERRORS_DEACTIVATE,
|
||||||
|
Opt_errors_panic = GFS2_ERRORS_PANIC,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct constant_table gfs2_param_errors[] = {
|
static const struct constant_table gfs2_param_errors[] = {
|
||||||
{"withdraw", Opt_errors_withdraw },
|
{"withdraw", Opt_errors_withdraw },
|
||||||
|
{"deactivate", Opt_errors_deactivate },
|
||||||
{"panic", Opt_errors_panic },
|
{"panic", Opt_errors_panic },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,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_withdrawing_or_withdrawn(sdp)) {
|
if (!gfs2_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);
|
||||||
|
|
@ -1551,27 +1551,13 @@ 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_withdrawing_or_withdrawn(sdp)) {
|
if (!gfs2_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg,
|
|
||||||
int (*fxn)(struct super_block *sb, int type),
|
|
||||||
unsigned long t, unsigned long *timeo,
|
|
||||||
unsigned int *new_timeo)
|
|
||||||
{
|
|
||||||
if (t >= *timeo) {
|
|
||||||
int error = fxn(sdp->sd_vfs, 0);
|
|
||||||
quotad_error(sdp, msg, error);
|
|
||||||
*timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ;
|
|
||||||
} else {
|
|
||||||
*timeo -= t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) {
|
void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) {
|
||||||
if (!sdp->sd_statfs_force_sync) {
|
if (!sdp->sd_statfs_force_sync) {
|
||||||
sdp->sd_statfs_force_sync = 1;
|
sdp->sd_statfs_force_sync = 1;
|
||||||
|
|
@ -1589,36 +1575,46 @@ void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) {
|
||||||
int gfs2_quotad(void *data)
|
int gfs2_quotad(void *data)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = data;
|
struct gfs2_sbd *sdp = data;
|
||||||
struct gfs2_tune *tune = &sdp->sd_tune;
|
unsigned long now = jiffies;
|
||||||
unsigned long statfs_timeo = 0;
|
unsigned long statfs_deadline = now;
|
||||||
unsigned long quotad_timeo = 0;
|
unsigned long quotad_deadline = now;
|
||||||
unsigned long t = 0;
|
|
||||||
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_should_stop()) {
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
unsigned long t;
|
||||||
|
|
||||||
|
if (gfs2_withdrawn(sdp))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Update the master statfs file */
|
now = jiffies;
|
||||||
if (sdp->sd_statfs_force_sync) {
|
if (sdp->sd_statfs_force_sync ||
|
||||||
int error = gfs2_statfs_sync(sdp->sd_vfs, 0);
|
time_after(now, statfs_deadline)) {
|
||||||
|
unsigned int quantum;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Update the master statfs file */
|
||||||
|
error = gfs2_statfs_sync(sdp->sd_vfs, 0);
|
||||||
quotad_error(sdp, "statfs", error);
|
quotad_error(sdp, "statfs", error);
|
||||||
statfs_timeo = gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
|
|
||||||
|
quantum = gfs2_tune_get(sdp, gt_statfs_quantum);
|
||||||
|
statfs_deadline = now + quantum * HZ;
|
||||||
}
|
}
|
||||||
else
|
if (time_after(now, quotad_deadline)) {
|
||||||
quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t,
|
unsigned int quantum;
|
||||||
&statfs_timeo,
|
int error;
|
||||||
&tune->gt_statfs_quantum);
|
|
||||||
|
|
||||||
/* Update quota file */
|
/* Update the quota file */
|
||||||
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
|
error = gfs2_quota_sync(sdp->sd_vfs, 0);
|
||||||
"ad_timeo, &tune->gt_quota_quantum);
|
quotad_error(sdp, "sync", error);
|
||||||
|
|
||||||
t = min(quotad_timeo, statfs_timeo);
|
quantum = gfs2_tune_get(sdp, gt_quota_quantum);
|
||||||
|
quotad_deadline = now + quantum * HZ;
|
||||||
|
}
|
||||||
|
|
||||||
t = wait_event_freezable_timeout(sdp->sd_quota_wait,
|
t = min(statfs_deadline - now, quotad_deadline - now);
|
||||||
|
wait_event_freezable_timeout(sdp->sd_quota_wait,
|
||||||
sdp->sd_statfs_force_sync ||
|
sdp->sd_statfs_force_sync ||
|
||||||
gfs2_withdrawing_or_withdrawn(sdp) ||
|
gfs2_withdrawn(sdp) ||
|
||||||
kthread_should_stop(),
|
kthread_should_stop(),
|
||||||
t);
|
t);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,7 @@ void gfs2_recover_func(struct work_struct *work)
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int jlocked = 0;
|
int jlocked = 0;
|
||||||
|
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_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;
|
||||||
|
|
@ -424,7 +424,8 @@ void gfs2_recover_func(struct work_struct *work)
|
||||||
|
|
||||||
error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
|
error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
|
||||||
LM_ST_EXCLUSIVE,
|
LM_ST_EXCLUSIVE,
|
||||||
LM_FLAG_NOEXP | LM_FLAG_TRY | GL_NOCACHE,
|
LM_FLAG_RECOVER | LM_FLAG_TRY |
|
||||||
|
GL_NOCACHE,
|
||||||
&j_gh);
|
&j_gh);
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -440,7 +441,8 @@ void gfs2_recover_func(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
|
||||||
LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh);
|
LM_FLAG_RECOVER | GL_NOCACHE,
|
||||||
|
&ji_gh);
|
||||||
if (error)
|
if (error)
|
||||||
goto fail_gunlock_j;
|
goto fail_gunlock_j;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,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_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (sdp->sd_log_sequence == 0) {
|
if (sdp->sd_log_sequence == 0) {
|
||||||
|
|
@ -147,7 +147,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
|
||||||
}
|
}
|
||||||
|
|
||||||
error = gfs2_quota_init(sdp);
|
error = gfs2_quota_init(sdp);
|
||||||
if (!error && gfs2_withdrawing_or_withdrawn(sdp))
|
if (!error && gfs2_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);
|
||||||
|
|
@ -351,7 +351,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp)
|
||||||
gfs2_freeze_unlock(sdp);
|
gfs2_freeze_unlock(sdp);
|
||||||
|
|
||||||
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
|
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
|
||||||
LM_FLAG_NOEXP | GL_NOPID,
|
LM_FLAG_RECOVER | GL_NOPID,
|
||||||
&sdp->sd_freeze_gh);
|
&sdp->sd_freeze_gh);
|
||||||
if (error)
|
if (error)
|
||||||
goto relock_shared;
|
goto relock_shared;
|
||||||
|
|
@ -491,7 +491,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
|
||||||
if (unlikely(!ip->i_gl))
|
if (unlikely(!ip->i_gl))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_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);
|
||||||
|
|
@ -597,13 +597,13 @@ restart:
|
||||||
if (!sb_rdonly(sb))
|
if (!sb_rdonly(sb))
|
||||||
gfs2_make_fs_ro(sdp);
|
gfs2_make_fs_ro(sdp);
|
||||||
else {
|
else {
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
gfs2_destroy_threads(sdp);
|
gfs2_destroy_threads(sdp);
|
||||||
|
|
||||||
gfs2_quota_cleanup(sdp);
|
gfs2_quota_cleanup(sdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
WARN_ON(gfs2_withdrawing(sdp));
|
flush_work(&sdp->sd_withdraw_work);
|
||||||
|
|
||||||
/* At this point, we're through modifying the disk */
|
/* At this point, we're through modifying the disk */
|
||||||
|
|
||||||
|
|
@ -749,9 +749,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = gfs2_do_thaw(sdp, who, freeze_owner);
|
(void)gfs2_do_thaw(sdp, who, freeze_owner);
|
||||||
if (error)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (error == -EBUSY)
|
if (error == -EBUSY)
|
||||||
fs_err(sdp, "waiting for recovery before freeze\n");
|
fs_err(sdp, "waiting for recovery before freeze\n");
|
||||||
|
|
@ -778,7 +776,7 @@ static int gfs2_freeze_fs(struct super_block *sb)
|
||||||
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
|
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
|
||||||
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
|
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
|
||||||
GFS2_LFC_FREEZE_GO_SYNC);
|
GFS2_LFC_FREEZE_GO_SYNC);
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -819,20 +817,6 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who,
|
||||||
return error;
|
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);
|
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&sdp->sd_freeze_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* statfs_slow_fill - fill in the sg for a given RG
|
* statfs_slow_fill - fill in the sg for a given RG
|
||||||
* @rgd: the RG
|
* @rgd: the RG
|
||||||
|
|
@ -1147,6 +1131,9 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
|
||||||
case GFS2_ERRORS_WITHDRAW:
|
case GFS2_ERRORS_WITHDRAW:
|
||||||
state = "withdraw";
|
state = "withdraw";
|
||||||
break;
|
break;
|
||||||
|
case GFS2_ERRORS_DEACTIVATE:
|
||||||
|
state = "deactivate";
|
||||||
|
break;
|
||||||
case GFS2_ERRORS_PANIC:
|
case GFS2_ERRORS_PANIC:
|
||||||
state = "panic";
|
state = "panic";
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc,
|
||||||
void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh);
|
void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh);
|
||||||
int gfs2_statfs_sync(struct super_block *sb, int type);
|
int gfs2_statfs_sync(struct super_block *sb, int type);
|
||||||
void gfs2_freeze_func(struct work_struct *work);
|
void gfs2_freeze_func(struct work_struct *work);
|
||||||
void gfs2_thaw_freeze_initiator(struct super_block *sb);
|
|
||||||
|
|
||||||
void free_local_statfs_inodes(struct gfs2_sbd *sdp);
|
void free_local_statfs_inodes(struct gfs2_sbd *sdp);
|
||||||
struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp,
|
struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp,
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ static struct kset *gfs2_kset;
|
||||||
|
|
||||||
static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
return snprintf(buf, PAGE_SIZE, "%u:%u\n",
|
return sysfs_emit(buf, "%u:%u\n",
|
||||||
MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev));
|
MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
unsigned long f = sdp->sd_flags;
|
unsigned long f = sdp->sd_flags;
|
||||||
ssize_t s;
|
ssize_t s;
|
||||||
|
|
||||||
s = snprintf(buf, PAGE_SIZE,
|
s = sysfs_emit(buf,
|
||||||
"Journal Checked: %d\n"
|
"Journal Checked: %d\n"
|
||||||
"Journal Live: %d\n"
|
"Journal Live: %d\n"
|
||||||
"Journal ID: %d\n"
|
"Journal ID: %d\n"
|
||||||
|
|
@ -84,10 +84,6 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
"Force AIL Flush: %d\n"
|
"Force AIL Flush: %d\n"
|
||||||
"FS Freeze Initiator: %d\n"
|
"FS Freeze Initiator: %d\n"
|
||||||
"FS Frozen: %d\n"
|
"FS Frozen: %d\n"
|
||||||
"Withdrawing: %d\n"
|
|
||||||
"Withdraw In Prog: %d\n"
|
|
||||||
"Remote Withdraw: %d\n"
|
|
||||||
"Withdraw Recovery: %d\n"
|
|
||||||
"Killing: %d\n"
|
"Killing: %d\n"
|
||||||
"sd_log_error: %d\n"
|
"sd_log_error: %d\n"
|
||||||
"sd_log_flush_lock: %d\n"
|
"sd_log_flush_lock: %d\n"
|
||||||
|
|
@ -117,10 +113,6 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
test_bit(SDF_FORCE_AIL_FLUSH, &f),
|
test_bit(SDF_FORCE_AIL_FLUSH, &f),
|
||||||
test_bit(SDF_FREEZE_INITIATOR, &f),
|
test_bit(SDF_FREEZE_INITIATOR, &f),
|
||||||
test_bit(SDF_FROZEN, &f),
|
test_bit(SDF_FROZEN, &f),
|
||||||
test_bit(SDF_WITHDRAWING, &f),
|
|
||||||
test_bit(SDF_WITHDRAW_IN_PROG, &f),
|
|
||||||
test_bit(SDF_REMOTE_WITHDRAW, &f),
|
|
||||||
test_bit(SDF_WITHDRAW_RECOVERY, &f),
|
|
||||||
test_bit(SDF_KILL, &f),
|
test_bit(SDF_KILL, &f),
|
||||||
sdp->sd_log_error,
|
sdp->sd_log_error,
|
||||||
rwsem_is_locked(&sdp->sd_log_flush_lock),
|
rwsem_is_locked(&sdp->sd_log_flush_lock),
|
||||||
|
|
@ -140,7 +132,7 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
|
|
||||||
static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname);
|
return sysfs_emit(buf, "%s\n", sdp->sd_fsname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
|
|
@ -150,7 +142,7 @@ static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
if (uuid_is_null(&s->s_uuid))
|
if (uuid_is_null(&s->s_uuid))
|
||||||
return 0;
|
return 0;
|
||||||
return snprintf(buf, PAGE_SIZE, "%pUB\n", &s->s_uuid);
|
return sysfs_emit(buf, "%pUB\n", &s->s_uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
|
|
@ -158,7 +150,7 @@ static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
struct super_block *sb = sdp->sd_vfs;
|
struct super_block *sb = sdp->sd_vfs;
|
||||||
int frozen = (sb->s_writers.frozen == SB_UNFROZEN) ? 0 : 1;
|
int frozen = (sb->s_writers.frozen == SB_UNFROZEN) ? 0 : 1;
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%d\n", frozen);
|
return sysfs_emit(buf, "%d\n", frozen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
||||||
|
|
@ -193,8 +185,8 @@ 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_withdrawing_or_withdrawn(sdp);
|
unsigned int b = gfs2_withdrawn(sdp);
|
||||||
return snprintf(buf, PAGE_SIZE, "%u\n", b);
|
return sysfs_emit(buf, "%u\n", b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
||||||
|
|
@ -397,7 +389,7 @@ static struct kobj_type gfs2_ktype = {
|
||||||
static ssize_t proto_name_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t proto_name_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
const struct lm_lockops *ops = sdp->sd_lockstruct.ls_ops;
|
const struct lm_lockops *ops = sdp->sd_lockstruct.ls_ops;
|
||||||
return sprintf(buf, "%s\n", ops->lm_proto_name);
|
return sysfs_emit(buf, "%s\n", ops->lm_proto_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
|
|
@ -408,7 +400,7 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
|
|
||||||
if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))
|
if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))
|
||||||
val = 1;
|
val = 1;
|
||||||
ret = sprintf(buf, "%d\n", val);
|
ret = sysfs_emit(buf, "%d\n", val);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,33 +425,27 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t wdack_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t withdraw_helper_status_store(struct gfs2_sbd *sdp,
|
||||||
{
|
const char *buf,
|
||||||
int val = completion_done(&sdp->sd_wdack) ? 1 : 0;
|
size_t len)
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t wdack_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
|
||||||
{
|
{
|
||||||
int ret, val;
|
int ret, val;
|
||||||
|
|
||||||
ret = kstrtoint(buf, 0, &val);
|
ret = kstrtoint(buf, 0, &val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (val < 0 || val > 1)
|
||||||
if ((val == 1) &&
|
|
||||||
!strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm"))
|
|
||||||
complete(&sdp->sd_wdack);
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
sdp->sd_withdraw_helper_status = val;
|
||||||
|
complete(&sdp->sd_withdraw_helper);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
return sprintf(buf, "%d\n", ls->ls_first);
|
return sysfs_emit(buf, "%d\n", ls->ls_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
||||||
|
|
@ -492,7 +478,7 @@ out:
|
||||||
static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
return sprintf(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags));
|
return sysfs_emit(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)
|
int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)
|
||||||
|
|
@ -550,18 +536,18 @@ out:
|
||||||
static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
return sprintf(buf, "%d\n", ls->ls_recover_jid_done);
|
return sysfs_emit(buf, "%d\n", ls->ls_recover_jid_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
return sprintf(buf, "%d\n", ls->ls_recover_jid_status);
|
return sysfs_emit(buf, "%d\n", ls->ls_recover_jid_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d\n", sdp->sd_lockstruct.ls_jid);
|
return sysfs_emit(buf, "%d\n", sdp->sd_lockstruct.ls_jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
||||||
|
|
@ -599,7 +585,7 @@ static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
|
||||||
|
|
||||||
GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
|
GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
|
||||||
GDLM_ATTR(block, 0644, block_show, block_store);
|
GDLM_ATTR(block, 0644, block_show, block_store);
|
||||||
GDLM_ATTR(withdraw, 0644, wdack_show, wdack_store);
|
GDLM_ATTR(withdraw, 0200, NULL, withdraw_helper_status_store);
|
||||||
GDLM_ATTR(jid, 0644, jid_show, jid_store);
|
GDLM_ATTR(jid, 0644, jid_show, jid_store);
|
||||||
GDLM_ATTR(first, 0644, lkfirst_show, lkfirst_store);
|
GDLM_ATTR(first, 0644, lkfirst_show, lkfirst_store);
|
||||||
GDLM_ATTR(first_done, 0444, first_done_show, NULL);
|
GDLM_ATTR(first_done, 0444, first_done_show, NULL);
|
||||||
|
|
@ -626,7 +612,7 @@ static struct attribute *lock_module_attrs[] = {
|
||||||
|
|
||||||
static ssize_t quota_scale_show(struct gfs2_sbd *sdp, char *buf)
|
static ssize_t quota_scale_show(struct gfs2_sbd *sdp, char *buf)
|
||||||
{
|
{
|
||||||
return snprintf(buf, PAGE_SIZE, "%u %u\n",
|
return sysfs_emit(buf, "%u %u\n",
|
||||||
sdp->sd_tune.gt_quota_scale_num,
|
sdp->sd_tune.gt_quota_scale_num,
|
||||||
sdp->sd_tune.gt_quota_scale_den);
|
sdp->sd_tune.gt_quota_scale_den);
|
||||||
}
|
}
|
||||||
|
|
@ -679,7 +665,7 @@ static struct gfs2_attr tune_attr_##name = __ATTR(name, 0644, show, store)
|
||||||
#define TUNE_ATTR_2(name, store) \
|
#define TUNE_ATTR_2(name, store) \
|
||||||
static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
|
static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
|
||||||
{ \
|
{ \
|
||||||
return snprintf(buf, PAGE_SIZE, "%u\n", sdp->sd_tune.gt_##name); \
|
return sysfs_emit(buf, "%u\n", sdp->sd_tune.gt_##name); \
|
||||||
} \
|
} \
|
||||||
TUNE_ATTR_3(name, name##_show, store)
|
TUNE_ATTR_3(name, name##_show, store)
|
||||||
|
|
||||||
|
|
@ -698,6 +684,7 @@ TUNE_ATTR(statfs_slow, 0);
|
||||||
TUNE_ATTR(new_files_jdata, 0);
|
TUNE_ATTR(new_files_jdata, 0);
|
||||||
TUNE_ATTR(statfs_quantum, 1);
|
TUNE_ATTR(statfs_quantum, 1);
|
||||||
TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
|
TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
|
||||||
|
TUNE_ATTR(withdraw_helper_timeout, 1);
|
||||||
|
|
||||||
static struct attribute *tune_attrs[] = {
|
static struct attribute *tune_attrs[] = {
|
||||||
&tune_attr_quota_warn_period.attr,
|
&tune_attr_quota_warn_period.attr,
|
||||||
|
|
@ -708,6 +695,7 @@ static struct attribute *tune_attrs[] = {
|
||||||
&tune_attr_statfs_quantum.attr,
|
&tune_attr_statfs_quantum.attr,
|
||||||
&tune_attr_quota_scale.attr,
|
&tune_attr_quota_scale.attr,
|
||||||
&tune_attr_new_files_jdata.attr,
|
&tune_attr_new_files_jdata.attr,
|
||||||
|
&tune_attr_withdraw_helper_timeout.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@
|
||||||
{(1UL << GLF_LRU), "L" }, \
|
{(1UL << GLF_LRU), "L" }, \
|
||||||
{(1UL << GLF_OBJECT), "o" }, \
|
{(1UL << GLF_OBJECT), "o" }, \
|
||||||
{(1UL << GLF_BLOCKING), "b" }, \
|
{(1UL << GLF_BLOCKING), "b" }, \
|
||||||
{(1UL << GLF_UNLOCKED), "x" }, \
|
|
||||||
{(1UL << GLF_INSTANTIATE_NEEDED), "n" }, \
|
{(1UL << GLF_INSTANTIATE_NEEDED), "n" }, \
|
||||||
{(1UL << GLF_INSTANTIATE_IN_PROG), "N" }, \
|
{(1UL << GLF_INSTANTIATE_IN_PROG), "N" }, \
|
||||||
{(1UL << GLF_TRY_TO_EVICT), "e" }, \
|
{(1UL << GLF_TRY_TO_EVICT), "e" }, \
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ int __gfs2_trans_begin(struct gfs2_trans *tr, struct gfs2_sbd *sdp,
|
||||||
}
|
}
|
||||||
BUG_ON(blocks == 0 && revokes == 0);
|
BUG_ON(blocks == 0 && revokes == 0);
|
||||||
|
|
||||||
if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
|
if (gfs2_withdrawn(sdp))
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
|
||||||
tr->tr_ip = ip;
|
tr->tr_ip = ip;
|
||||||
|
|
@ -85,25 +85,30 @@ int __gfs2_trans_begin(struct gfs2_trans *tr, struct gfs2_sbd *sdp,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
down_read(&sdp->sd_log_flush_lock);
|
down_read(&sdp->sd_log_flush_lock);
|
||||||
|
if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)))
|
||||||
|
goto out_not_live;
|
||||||
if (gfs2_log_try_reserve(sdp, tr, &extra_revokes))
|
if (gfs2_log_try_reserve(sdp, tr, &extra_revokes))
|
||||||
goto reserved;
|
goto reserved;
|
||||||
|
|
||||||
up_read(&sdp->sd_log_flush_lock);
|
up_read(&sdp->sd_log_flush_lock);
|
||||||
gfs2_log_reserve(sdp, tr, &extra_revokes);
|
gfs2_log_reserve(sdp, tr, &extra_revokes);
|
||||||
down_read(&sdp->sd_log_flush_lock);
|
down_read(&sdp->sd_log_flush_lock);
|
||||||
|
if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) {
|
||||||
|
revokes = tr->tr_revokes + extra_revokes;
|
||||||
|
gfs2_log_release_revokes(sdp, revokes);
|
||||||
|
gfs2_log_release(sdp, tr->tr_reserved);
|
||||||
|
goto out_not_live;
|
||||||
|
}
|
||||||
|
|
||||||
reserved:
|
reserved:
|
||||||
gfs2_log_release_revokes(sdp, extra_revokes);
|
gfs2_log_release_revokes(sdp, extra_revokes);
|
||||||
if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) {
|
|
||||||
gfs2_log_release_revokes(sdp, tr->tr_revokes);
|
|
||||||
up_read(&sdp->sd_log_flush_lock);
|
|
||||||
gfs2_log_release(sdp, tr->tr_reserved);
|
|
||||||
sb_end_intwrite(sdp->sd_vfs);
|
|
||||||
return -EROFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
current->journal_info = tr;
|
current->journal_info = tr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_not_live:
|
||||||
|
up_read(&sdp->sd_log_flush_lock);
|
||||||
|
sb_end_intwrite(sdp->sd_vfs);
|
||||||
|
return -EROFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
||||||
|
|
@ -255,7 +260,6 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
|
||||||
struct gfs2_bufdata *bd;
|
struct gfs2_bufdata *bd;
|
||||||
struct gfs2_meta_header *mh;
|
struct gfs2_meta_header *mh;
|
||||||
struct gfs2_trans *tr = current->journal_info;
|
struct gfs2_trans *tr = current->journal_info;
|
||||||
bool withdraw = false;
|
|
||||||
|
|
||||||
lock_buffer(bh);
|
lock_buffer(bh);
|
||||||
if (buffer_pinned(bh)) {
|
if (buffer_pinned(bh)) {
|
||||||
|
|
@ -289,14 +293,14 @@ 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 (gfs2_withdrawing_or_withdrawn(sdp)) {
|
if (gfs2_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;
|
||||||
}
|
}
|
||||||
if (unlikely(sb->s_writers.frozen == SB_FREEZE_COMPLETE)) {
|
if (unlikely(sb->s_writers.frozen == SB_FREEZE_COMPLETE)) {
|
||||||
fs_info(sdp, "GFS2:adding buf while frozen\n");
|
fs_info(sdp, "GFS2:adding buf while frozen\n");
|
||||||
withdraw = true;
|
gfs2_withdraw(sdp);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
gfs2_pin(sdp, bd->bd_bh);
|
gfs2_pin(sdp, bd->bd_bh);
|
||||||
|
|
@ -306,8 +310,6 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
|
||||||
tr->tr_num_buf_new++;
|
tr->tr_num_buf_new++;
|
||||||
out_unlock:
|
out_unlock:
|
||||||
gfs2_log_unlock(sdp);
|
gfs2_log_unlock(sdp);
|
||||||
if (withdraw)
|
|
||||||
gfs2_assert_withdraw(sdp, 0);
|
|
||||||
out:
|
out:
|
||||||
unlock_buffer(bh);
|
unlock_buffer(bh);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
328
fs/gfs2/util.c
328
fs/gfs2/util.c
|
|
@ -58,7 +58,7 @@ int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
|
||||||
struct gfs2_inode *ip;
|
struct gfs2_inode *ip;
|
||||||
|
|
||||||
ip = GFS2_I(jd->jd_inode);
|
ip = GFS2_I(jd->jd_inode);
|
||||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP |
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_RECOVER |
|
||||||
GL_EXACT | GL_NOCACHE, &j_gh);
|
GL_EXACT | GL_NOCACHE, &j_gh);
|
||||||
if (error) {
|
if (error) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|
@ -99,7 +99,7 @@ out_unlock:
|
||||||
*/
|
*/
|
||||||
int gfs2_freeze_lock_shared(struct gfs2_sbd *sdp)
|
int gfs2_freeze_lock_shared(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
int flags = LM_FLAG_NOEXP | GL_EXACT;
|
int flags = LM_FLAG_RECOVER | GL_EXACT;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, flags,
|
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, flags,
|
||||||
|
|
@ -115,182 +115,32 @@ void gfs2_freeze_unlock(struct gfs2_sbd *sdp)
|
||||||
gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
|
gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_our_withdraw(struct gfs2_sbd *sdp)
|
static void do_withdraw(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
struct gfs2_glock *live_gl = sdp->sd_live_gh.gh_gl;
|
down_write(&sdp->sd_log_flush_lock);
|
||||||
struct inode *inode;
|
if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
|
||||||
struct gfs2_inode *ip;
|
up_write(&sdp->sd_log_flush_lock);
|
||||||
struct gfs2_glock *i_gl;
|
|
||||||
u64 no_formal_ino;
|
|
||||||
int ret = 0;
|
|
||||||
int tries;
|
|
||||||
|
|
||||||
if (test_bit(SDF_NORECOVERY, &sdp->sd_flags) || !sdp->sd_jdesc)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
|
||||||
|
up_write(&sdp->sd_log_flush_lock);
|
||||||
|
|
||||||
gfs2_ail_drain(sdp); /* frees all transactions */
|
gfs2_ail_drain(sdp); /* frees all transactions */
|
||||||
inode = sdp->sd_jdesc->jd_inode;
|
|
||||||
ip = GFS2_I(inode);
|
|
||||||
i_gl = ip->i_gl;
|
|
||||||
no_formal_ino = ip->i_no_formal_ino;
|
|
||||||
|
|
||||||
/* Prevent any glock dq until withdraw recovery is complete */
|
wake_up(&sdp->sd_logd_waitq);
|
||||||
set_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags);
|
wake_up(&sdp->sd_quota_wait);
|
||||||
/*
|
|
||||||
* Don't tell dlm we're bailing until we have no more buffers in the
|
|
||||||
* wind. If journal had an IO error, the log code should just purge
|
|
||||||
* the outstanding buffers rather than submitting new IO. Making the
|
|
||||||
* file system read-only will flush the journal, etc.
|
|
||||||
*
|
|
||||||
* During a normal unmount, gfs2_make_fs_ro calls gfs2_log_shutdown
|
|
||||||
* which clears SDF_JOURNAL_LIVE. In a withdraw, we must not write
|
|
||||||
* any UNMOUNT log header, so we can't call gfs2_log_shutdown, and
|
|
||||||
* therefore we need to clear SDF_JOURNAL_LIVE manually.
|
|
||||||
*/
|
|
||||||
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
|
|
||||||
if (!sb_rdonly(sdp->sd_vfs)) {
|
|
||||||
bool locked = mutex_trylock(&sdp->sd_freeze_mutex);
|
|
||||||
|
|
||||||
wake_up(&sdp->sd_logd_waitq);
|
wait_event_timeout(sdp->sd_log_waitq,
|
||||||
wake_up(&sdp->sd_quota_wait);
|
gfs2_log_is_empty(sdp),
|
||||||
|
HZ * 5);
|
||||||
|
|
||||||
wait_event_timeout(sdp->sd_log_waitq,
|
sdp->sd_vfs->s_flags |= SB_RDONLY;
|
||||||
gfs2_log_is_empty(sdp),
|
|
||||||
HZ * 5);
|
|
||||||
|
|
||||||
sdp->sd_vfs->s_flags |= SB_RDONLY;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdp->sd_lockstruct.ls_ops->lm_lock == NULL) { /* lock_nolock */
|
|
||||||
if (!ret)
|
|
||||||
ret = -EIO;
|
|
||||||
clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags);
|
|
||||||
goto skip_recovery;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Drop the glock for our journal so another node can recover it.
|
|
||||||
*/
|
|
||||||
if (gfs2_holder_initialized(&sdp->sd_journal_gh)) {
|
|
||||||
gfs2_glock_dq_wait(&sdp->sd_journal_gh);
|
|
||||||
gfs2_holder_uninit(&sdp->sd_journal_gh);
|
|
||||||
}
|
|
||||||
sdp->sd_jinode_gh.gh_flags |= GL_NOCACHE;
|
|
||||||
gfs2_glock_dq(&sdp->sd_jinode_gh);
|
|
||||||
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
|
* Dequeue any pending non-system glock holders that can no
|
||||||
|
* longer be granted because the file system is withdrawn.
|
||||||
*/
|
*/
|
||||||
gfs2_holder_uninit(&sdp->sd_jinode_gh);
|
gfs2_withdraw_glocks(sdp);
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: We need to be careful here:
|
|
||||||
* Our iput of jd_inode will evict it. The evict will dequeue its
|
|
||||||
* glock, but the glock dq will wait for the withdraw unless we have
|
|
||||||
* exception code in glock_dq.
|
|
||||||
*/
|
|
||||||
iput(inode);
|
|
||||||
sdp->sd_jdesc->jd_inode = NULL;
|
|
||||||
/*
|
|
||||||
* Wait until the journal inode's glock is freed. This allows try locks
|
|
||||||
* on other nodes to be successful, otherwise we remain the owner of
|
|
||||||
* the glock as far as dlm is concerned.
|
|
||||||
*/
|
|
||||||
if (i_gl->gl_ops->go_unlocked) {
|
|
||||||
set_bit(GLF_UNLOCKED, &i_gl->gl_flags);
|
|
||||||
wait_on_bit(&i_gl->gl_flags, GLF_UNLOCKED, TASK_UNINTERRUPTIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dequeue the "live" glock, but keep a reference so it's never freed.
|
|
||||||
*/
|
|
||||||
gfs2_glock_hold(live_gl);
|
|
||||||
gfs2_glock_dq_wait(&sdp->sd_live_gh);
|
|
||||||
/*
|
|
||||||
* We enqueue the "live" glock in EX so that all other nodes
|
|
||||||
* get a demote request and act on it. We don't really want the
|
|
||||||
* lock in EX, so we send a "try" lock with 1CB to produce a callback.
|
|
||||||
*/
|
|
||||||
fs_warn(sdp, "Requesting recovery of jid %d.\n",
|
|
||||||
sdp->sd_lockstruct.ls_jid);
|
|
||||||
gfs2_holder_reinit(LM_ST_EXCLUSIVE,
|
|
||||||
LM_FLAG_TRY_1CB | LM_FLAG_NOEXP | GL_NOPID,
|
|
||||||
&sdp->sd_live_gh);
|
|
||||||
msleep(GL_GLOCK_MAX_HOLD);
|
|
||||||
/*
|
|
||||||
* This will likely fail in a cluster, but succeed standalone:
|
|
||||||
*/
|
|
||||||
ret = gfs2_glock_nq(&sdp->sd_live_gh);
|
|
||||||
|
|
||||||
gfs2_glock_put(live_gl); /* drop extra reference we acquired */
|
|
||||||
clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we actually got the "live" lock in EX mode, there are no other
|
|
||||||
* nodes available to replay our journal.
|
|
||||||
*/
|
|
||||||
if (ret == 0) {
|
|
||||||
fs_warn(sdp, "No other mounters found.\n");
|
|
||||||
/*
|
|
||||||
* We are about to release the lockspace. By keeping live_gl
|
|
||||||
* locked here, we ensure that the next mounter coming along
|
|
||||||
* will be a "first" mounter which will perform recovery.
|
|
||||||
*/
|
|
||||||
goto skip_recovery;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* At this point our journal is evicted, so we need to get a new inode
|
|
||||||
* for it. Once done, we need to call gfs2_find_jhead which
|
|
||||||
* calls gfs2_map_journal_extents to map it for us again.
|
|
||||||
*
|
|
||||||
* Note that we don't really want it to look up a FREE block. The
|
|
||||||
* GFS2_BLKST_FREE simply overrides a block check in gfs2_inode_lookup
|
|
||||||
* which would otherwise fail because it requires grabbing an rgrp
|
|
||||||
* glock, which would fail with -EIO because we're withdrawing.
|
|
||||||
*/
|
|
||||||
inode = gfs2_inode_lookup(sdp->sd_vfs, DT_UNKNOWN,
|
|
||||||
sdp->sd_jdesc->jd_no_addr, no_formal_ino,
|
|
||||||
GFS2_BLKST_FREE);
|
|
||||||
if (IS_ERR(inode)) {
|
|
||||||
fs_warn(sdp, "Reprocessing of jid %d failed with %ld.\n",
|
|
||||||
sdp->sd_lockstruct.ls_jid, PTR_ERR(inode));
|
|
||||||
goto skip_recovery;
|
|
||||||
}
|
|
||||||
sdp->sd_jdesc->jd_inode = inode;
|
|
||||||
d_mark_dontcache(inode);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now wait until recovery is complete.
|
|
||||||
*/
|
|
||||||
for (tries = 0; tries < 10; tries++) {
|
|
||||||
ret = check_journal_clean(sdp, sdp->sd_jdesc, false);
|
|
||||||
if (!ret)
|
|
||||||
break;
|
|
||||||
msleep(HZ);
|
|
||||||
fs_warn(sdp, "Waiting for journal recovery jid %d.\n",
|
|
||||||
sdp->sd_lockstruct.ls_jid);
|
|
||||||
}
|
|
||||||
skip_recovery:
|
|
||||||
if (!ret)
|
|
||||||
fs_warn(sdp, "Journal recovery complete for jid %d.\n",
|
|
||||||
sdp->sd_lockstruct.ls_jid);
|
|
||||||
else
|
|
||||||
fs_warn(sdp, "Journal recovery skipped for jid %d until next "
|
|
||||||
"mount.\n", sdp->sd_lockstruct.ls_jid);
|
|
||||||
fs_warn(sdp, "Glock dequeues delayed: %lu\n", sdp->sd_glock_dqs_held);
|
|
||||||
sdp->sd_glock_dqs_held = 0;
|
|
||||||
wake_up_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...)
|
void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...)
|
||||||
|
|
@ -309,43 +159,104 @@ void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...)
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfs2_withdraw(struct gfs2_sbd *sdp)
|
/**
|
||||||
|
* gfs2_offline_uevent - run gfs2_withdraw_helper
|
||||||
|
* @sdp: The GFS2 superblock
|
||||||
|
*/
|
||||||
|
static bool gfs2_offline_uevent(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
|
long timeout;
|
||||||
|
|
||||||
|
/* Skip protocol "lock_nolock" which doesn't require shared storage. */
|
||||||
|
if (!ls->ls_ops->lm_lock)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The gfs2_withdraw_helper replies by writing one of the following
|
||||||
|
* status codes to "/sys$DEVPATH/lock_module/withdraw":
|
||||||
|
*
|
||||||
|
* 0 - The shared block device has been marked inactive. Future write
|
||||||
|
* operations will fail.
|
||||||
|
*
|
||||||
|
* 1 - The shared block device may still be active and carry out
|
||||||
|
* write operations.
|
||||||
|
*
|
||||||
|
* If the "offline" uevent isn't reacted upon in time, the event
|
||||||
|
* handler is assumed to have failed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sdp->sd_withdraw_helper_status = -1;
|
||||||
|
kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
|
||||||
|
timeout = gfs2_tune_get(sdp, gt_withdraw_helper_timeout) * HZ;
|
||||||
|
wait_for_completion_timeout(&sdp->sd_withdraw_helper, timeout);
|
||||||
|
if (sdp->sd_withdraw_helper_status == -1) {
|
||||||
|
fs_err(sdp, "%s timed out\n", "gfs2_withdraw_helper");
|
||||||
|
} else {
|
||||||
|
fs_err(sdp, "%s %s with status %d\n",
|
||||||
|
"gfs2_withdraw_helper",
|
||||||
|
sdp->sd_withdraw_helper_status == 0 ?
|
||||||
|
"succeeded" : "failed",
|
||||||
|
sdp->sd_withdraw_helper_status);
|
||||||
|
}
|
||||||
|
return sdp->sd_withdraw_helper_status == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfs2_withdraw_func(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_withdraw_work);
|
||||||
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
|
||||||
const struct lm_lockops *lm = ls->ls_ops;
|
const struct lm_lockops *lm = ls->ls_ops;
|
||||||
|
bool device_inactive;
|
||||||
|
|
||||||
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
|
if (test_bit(SDF_KILL, &sdp->sd_flags))
|
||||||
unsigned long old = READ_ONCE(sdp->sd_flags), new;
|
return;
|
||||||
|
|
||||||
do {
|
BUG_ON(sdp->sd_args.ar_debug);
|
||||||
if (old & BIT(SDF_WITHDRAWN)) {
|
|
||||||
wait_on_bit(&sdp->sd_flags,
|
|
||||||
SDF_WITHDRAW_IN_PROG,
|
|
||||||
TASK_UNINTERRUPTIBLE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
new = old | BIT(SDF_WITHDRAWN) | BIT(SDF_WITHDRAW_IN_PROG);
|
|
||||||
} while (unlikely(!try_cmpxchg(&sdp->sd_flags, &old, new)));
|
|
||||||
|
|
||||||
fs_err(sdp, "about to withdraw this file system\n");
|
/*
|
||||||
BUG_ON(sdp->sd_args.ar_debug);
|
* Try to deactivate the shared block device so that no more I/O will
|
||||||
|
* go through. If successful, we can immediately trigger remote
|
||||||
|
* recovery. Otherwise, we must first empty out all our local caches.
|
||||||
|
*/
|
||||||
|
|
||||||
signal_our_withdraw(sdp);
|
device_inactive = gfs2_offline_uevent(sdp);
|
||||||
|
|
||||||
kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
|
if (sdp->sd_args.ar_errors == GFS2_ERRORS_DEACTIVATE && !device_inactive)
|
||||||
|
panic("GFS2: fsid=%s: panic requested\n", sdp->sd_fsname);
|
||||||
|
|
||||||
if (!strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm"))
|
if (lm->lm_unmount) {
|
||||||
wait_for_completion(&sdp->sd_wdack);
|
if (device_inactive) {
|
||||||
|
lm->lm_unmount(sdp, false);
|
||||||
if (lm->lm_unmount) {
|
do_withdraw(sdp);
|
||||||
fs_err(sdp, "telling LM to unmount\n");
|
} else {
|
||||||
lm->lm_unmount(sdp);
|
do_withdraw(sdp);
|
||||||
|
lm->lm_unmount(sdp, false);
|
||||||
}
|
}
|
||||||
fs_err(sdp, "File system withdrawn\n");
|
} else {
|
||||||
|
do_withdraw(sdp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_err(sdp, "file system withdrawn\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfs2_withdraw(struct gfs2_sbd *sdp)
|
||||||
|
{
|
||||||
|
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW ||
|
||||||
|
sdp->sd_args.ar_errors == GFS2_ERRORS_DEACTIVATE) {
|
||||||
|
if (test_and_set_bit(SDF_WITHDRAWN, &sdp->sd_flags))
|
||||||
|
return;
|
||||||
|
|
||||||
dump_stack();
|
dump_stack();
|
||||||
clear_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags);
|
/*
|
||||||
smp_mb__after_atomic();
|
* There is no need to withdraw when the superblock hasn't been
|
||||||
wake_up_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG);
|
* fully initialized, yet.
|
||||||
|
*/
|
||||||
|
if (!(sdp->sd_vfs->s_flags & SB_BORN))
|
||||||
|
return;
|
||||||
|
fs_err(sdp, "about to withdraw this file system\n");
|
||||||
|
schedule_work(&sdp->sd_withdraw_work);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
|
if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
|
||||||
|
|
@ -357,10 +268,9 @@ void gfs2_withdraw(struct gfs2_sbd *sdp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
|
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)
|
|
||||||
{
|
{
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fs_err(sdp,
|
fs_err(sdp,
|
||||||
|
|
@ -368,17 +278,7 @@ void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
|
||||||
"function = %s, file = %s, line = %u\n",
|
"function = %s, file = %s, line = %u\n",
|
||||||
assertion, function, file, line);
|
assertion, function, file, line);
|
||||||
|
|
||||||
/*
|
gfs2_withdraw(sdp);
|
||||||
* If errors=panic was specified on mount, it won't help to delay the
|
|
||||||
* withdraw.
|
|
||||||
*/
|
|
||||||
if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
|
|
||||||
delayed = false;
|
|
||||||
|
|
||||||
if (delayed)
|
|
||||||
gfs2_withdraw_delayed(sdp);
|
|
||||||
else
|
|
||||||
gfs2_withdraw(sdp);
|
|
||||||
dump_stack();
|
dump_stack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -520,22 +420,18 @@ void gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gfs2_io_error_bh_i - Flag a buffer I/O error
|
* gfs2_io_error_bh_i - Flag a buffer I/O error and withdraw
|
||||||
* @withdraw: withdraw the filesystem
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
|
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)
|
|
||||||
{
|
{
|
||||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
if (gfs2_withdrawn(sdp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fs_err(sdp, "fatal: I/O error - "
|
fs_err(sdp, "fatal: I/O error - "
|
||||||
"block = %llu, "
|
"block = %llu, "
|
||||||
"function = %s, file = %s, line = %u\n",
|
"function = %s, file = %s, line = %u\n",
|
||||||
(unsigned long long)bh->b_blocknr, function, file, line);
|
(unsigned long long)bh->b_blocknr, function, file, line);
|
||||||
if (withdraw)
|
gfs2_withdraw(sdp);
|
||||||
gfs2_withdraw(sdp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,24 +37,14 @@ do { \
|
||||||
|
|
||||||
|
|
||||||
void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
|
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);
|
|
||||||
|
|
||||||
#define gfs2_assert_withdraw(sdp, assertion) \
|
#define gfs2_assert_withdraw(sdp, assertion) \
|
||||||
({ \
|
({ \
|
||||||
bool _bool = (assertion); \
|
bool _bool = (assertion); \
|
||||||
if (unlikely(!_bool)) \
|
if (unlikely(!_bool)) \
|
||||||
gfs2_assert_withdraw_i((sdp), #assertion, \
|
gfs2_assert_withdraw_i((sdp), #assertion, \
|
||||||
__func__, __FILE__, __LINE__, false); \
|
__func__, __FILE__, __LINE__); \
|
||||||
!_bool; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define gfs2_assert_withdraw_delayed(sdp, assertion) \
|
|
||||||
({ \
|
|
||||||
bool _bool = (assertion); \
|
|
||||||
if (unlikely(!_bool)) \
|
|
||||||
gfs2_assert_withdraw_i((sdp), #assertion, \
|
|
||||||
__func__, __FILE__, __LINE__, true); \
|
|
||||||
!_bool; \
|
!_bool; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -161,14 +151,10 @@ gfs2_io_error_i((sdp), __func__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
|
||||||
void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
|
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);
|
|
||||||
|
|
||||||
#define gfs2_io_error_bh_wd(sdp, bh) \
|
|
||||||
gfs2_io_error_bh_i((sdp), (bh), __func__, __FILE__, __LINE__, true)
|
|
||||||
|
|
||||||
#define gfs2_io_error_bh(sdp, bh) \
|
#define gfs2_io_error_bh(sdp, bh) \
|
||||||
gfs2_io_error_bh_i((sdp), (bh), __func__, __FILE__, __LINE__, false)
|
gfs2_io_error_bh_i((sdp), (bh), __func__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
|
||||||
extern struct kmem_cache *gfs2_glock_cachep;
|
extern struct kmem_cache *gfs2_glock_cachep;
|
||||||
|
|
@ -193,38 +179,12 @@ static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gfs2_withdraw_delayed - withdraw as soon as possible without deadlocks
|
* gfs2_withdrawn - test whether the file system is withdrawn
|
||||||
* @sdp: the superblock
|
* @sdp: the superblock
|
||||||
*/
|
*/
|
||||||
static inline void gfs2_withdraw_delayed(struct gfs2_sbd *sdp)
|
static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
set_bit(SDF_WITHDRAWING, &sdp->sd_flags);
|
return unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gfs2_withdrawing_or_withdrawn - test whether the file system is withdrawing
|
|
||||||
* or withdrawn
|
|
||||||
* @sdp: the superblock
|
|
||||||
*/
|
|
||||||
static inline bool gfs2_withdrawing_or_withdrawn(struct gfs2_sbd *sdp)
|
|
||||||
{
|
|
||||||
return unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags) ||
|
|
||||||
test_bit(SDF_WITHDRAWING, &sdp->sd_flags));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gfs2_withdrawing - check if a withdraw is pending
|
|
||||||
* @sdp: the superblock
|
|
||||||
*/
|
|
||||||
static inline bool gfs2_withdrawing(struct gfs2_sbd *sdp)
|
|
||||||
{
|
|
||||||
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 unlikely(test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define gfs2_tune_get(sdp, field) \
|
#define gfs2_tune_get(sdp, field) \
|
||||||
|
|
@ -232,6 +192,8 @@ gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
|
||||||
|
|
||||||
__printf(2, 3)
|
__printf(2, 3)
|
||||||
void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...);
|
void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...);
|
||||||
|
|
||||||
|
void gfs2_withdraw_func(struct work_struct *work);
|
||||||
void gfs2_withdraw(struct gfs2_sbd *sdp);
|
void gfs2_withdraw(struct gfs2_sbd *sdp);
|
||||||
|
|
||||||
#endif /* __UTIL_DOT_H__ */
|
#endif /* __UTIL_DOT_H__ */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue