Commit 65d6e954 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull gfs2 updates from Andreas Gruenbacher:

 - Fix a glock state (non-)transition bug when a dlm request times out
   and is canceled, and we have locking requests that can now be granted
   immediately

 - Various fixes and cleanups in how the logd and quotad daemons are
   woken up and terminated

 - Fix several bugs in the quota data reference counting and shrinking.
   Free quota data objects synchronously in put_super() instead of
   letting call_rcu() run wild

 - Make sure not to deallocate quota data during a withdraw; rather,
   defer quota data deallocation to put_super(). Withdraws can happen in
   contexts in which callers on the stack are holding quota data
   references

 - Many minor quota fixes and cleanups by Bob

 - Update the the mailing list address for gfs2 and dlm. (It's the same
   list for both and we are moving it to gfs2@lists.linux.dev)

 - Various other minor cleanups

* tag 'gfs2-v6.5-rc5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: (51 commits)
  MAINTAINERS: Update dlm mailing list
  MAINTAINERS: Update gfs2 mailing list
  gfs2: change qd_slot_count to qd_slot_ref
  gfs2: check for no eligible quota changes
  gfs2: Remove useless assignment
  gfs2: simplify slot_get
  gfs2: Simplify qd2offset
  gfs2: introduce qd_bh_get_or_undo
  gfs2: Remove quota allocation info from quota file
  gfs2: use constant for array size
  gfs2: Set qd_sync_gen in do_sync
  gfs2: Remove useless err set
  gfs2: Small gfs2_quota_lock cleanup
  gfs2: move qdsb_put and reduce redundancy
  gfs2: improvements to sysfs status
  gfs2: Don't try to sync non-changes
  gfs2: Simplify function need_sync
  gfs2: remove unneeded pg_oflow variable
  gfs2: remove unneeded variable done
  gfs2: pass sdp to gfs2_write_buf_to_page
  ...
parents 9e310ea5 2938fd75
......@@ -20,8 +20,7 @@ The gl_holders list contains all the queued lock requests (not
just the holders) associated with the glock. If there are any
held locks, then they will be contiguous entries at the head
of the list. Locks are granted in strictly the order that they
are queued, except for those marked LM_FLAG_PRIORITY which are
used only during recovery, and even then only for journal locks.
are queued.
There are three lock states that users of the glock layer can request,
namely shared (SH), deferred (DF) and exclusive (EX). Those translate
......
......@@ -6118,7 +6118,7 @@ F: include/video/udlfb.h
DISTRIBUTED LOCK MANAGER (DLM)
M: Christine Caulfield <ccaulfie@redhat.com>
M: David Teigland <teigland@redhat.com>
L: cluster-devel@redhat.com
L: gfs2@lists.linux.dev
S: Supported
W: http://sources.redhat.com/cluster/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git
......@@ -8774,7 +8774,7 @@ F: scripts/get_maintainer.pl
GFS2 FILE SYSTEM
M: Bob Peterson <rpeterso@redhat.com>
M: Andreas Gruenbacher <agruenba@redhat.com>
L: cluster-devel@redhat.com
L: gfs2@lists.linux.dev
S: Supported
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
......
......@@ -183,13 +183,13 @@ static int gfs2_writepages(struct address_space *mapping,
int ret;
/*
* Even if we didn't write any pages here, we might still be holding
* Even if we didn't write enough pages here, we might still be holding
* dirty pages in the ail. We forcibly flush the ail because we don't
* want balance_dirty_pages() to loop indefinitely trying to write out
* pages held in the ail that it can't find.
*/
ret = iomap_writepages(mapping, wbc, &wpc, &gfs2_writeback_ops);
if (ret == 0)
if (ret == 0 && wbc->nr_to_write > 0)
set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
return ret;
}
......@@ -272,8 +272,7 @@ static int gfs2_write_jdata_batch(struct address_space *mapping,
* not be suitable for data integrity
* writeout).
*/
*done_index = folio->index +
folio_nr_pages(folio);
*done_index = folio_next_index(folio);
ret = 1;
break;
}
......
......@@ -161,7 +161,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip)
int error;
down_write(&ip->i_rw_mutex);
page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
page = grab_cache_page(inode->i_mapping, 0);
error = -ENOMEM;
if (!page)
goto out;
......
......@@ -176,7 +176,7 @@ void gfs2_glock_free(struct gfs2_glock *gl)
wake_up_glock(gl);
call_rcu(&gl->gl_rcu, gfs2_glock_dealloc);
if (atomic_dec_and_test(&sdp->sd_glock_disposal))
wake_up(&sdp->sd_glock_wait);
wake_up(&sdp->sd_kill_wait);
}
/**
......@@ -468,10 +468,10 @@ int gfs2_instantiate(struct gfs2_holder *gh)
* do_promote - promote as many requests as possible on the current queue
* @gl: The glock
*
* Returns: 1 if there is a blocked holder at the head of the list
* Returns true on success (i.e., progress was made or there are no waiters).
*/
static int do_promote(struct gfs2_glock *gl)
static bool do_promote(struct gfs2_glock *gl)
{
struct gfs2_holder *gh, *current_gh;
......@@ -484,10 +484,10 @@ static int do_promote(struct gfs2_glock *gl)
* If we get here, it means we may not grant this
* holder for some reason. If this holder is at the
* head of the list, it means we have a blocked holder
* at the head, so return 1.
* at the head, so return false.
*/
if (list_is_first(&gh->gh_list, &gl->gl_holders))
return 1;
return false;
do_error(gl, 0);
break;
}
......@@ -497,7 +497,7 @@ static int do_promote(struct gfs2_glock *gl)
if (!current_gh)
current_gh = gh;
}
return 0;
return true;
}
/**
......@@ -591,10 +591,11 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
if (gh && !test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) {
/* move to back of queue and try next entry */
if (ret & LM_OUT_CANCELED) {
if ((gh->gh_flags & LM_FLAG_PRIORITY) == 0)
list_move_tail(&gh->gh_list, &gl->gl_holders);
gh = find_first_waiter(gl);
gl->gl_target = gh->gh_state;
if (do_promote(gl))
goto out;
goto retry;
}
/* Some error or failed "try lock" - report it */
......@@ -679,8 +680,7 @@ __acquires(&gl->gl_lockref.lock)
gh && !(gh->gh_flags & LM_FLAG_NOEXP))
goto skip_inval;
lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP |
LM_FLAG_PRIORITY);
lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP);
GLOCK_BUG_ON(gl, gl->gl_state == target);
GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
if ((target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) &&
......@@ -834,7 +834,7 @@ __acquires(&gl->gl_lockref.lock)
} else {
if (test_bit(GLF_DEMOTE, &gl->gl_flags))
gfs2_demote_wake(gl);
if (do_promote(gl) == 0)
if (do_promote(gl))
goto out_unlock;
gh = find_first_waiter(gl);
gl->gl_target = gh->gh_state;
......@@ -1022,7 +1022,7 @@ static void delete_work_func(struct work_struct *work)
* step entirely.
*/
if (gfs2_try_evict(gl)) {
if (test_bit(SDF_DEACTIVATING, &sdp->sd_flags))
if (test_bit(SDF_KILL, &sdp->sd_flags))
goto out;
if (gfs2_queue_verify_evict(gl))
return;
......@@ -1035,7 +1035,7 @@ static void delete_work_func(struct work_struct *work)
GFS2_BLKST_UNLINKED);
if (IS_ERR(inode)) {
if (PTR_ERR(inode) == -EAGAIN &&
!test_bit(SDF_DEACTIVATING, &sdp->sd_flags) &&
!test_bit(SDF_KILL, &sdp->sd_flags) &&
gfs2_queue_verify_evict(gl))
return;
} else {
......@@ -1231,7 +1231,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
out_free:
gfs2_glock_dealloc(&gl->gl_rcu);
if (atomic_dec_and_test(&sdp->sd_glock_disposal))
wake_up(&sdp->sd_glock_wait);
wake_up(&sdp->sd_kill_wait);
out:
return ret;
......@@ -1515,27 +1515,20 @@ __acquires(&gl->gl_lockref.lock)
}
if (test_bit(HIF_HOLDER, &gh2->gh_iflags))
continue;
if (unlikely((gh->gh_flags & LM_FLAG_PRIORITY) && !insert_pt))
insert_pt = &gh2->gh_list;
}
trace_gfs2_glock_queue(gh, 1);
gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT);
gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT);
if (likely(insert_pt == NULL)) {
list_add_tail(&gh->gh_list, &gl->gl_holders);
if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
goto do_cancel;
return;
}
list_add_tail(&gh->gh_list, insert_pt);
do_cancel:
gh = list_first_entry(&gl->gl_holders, struct gfs2_holder, gh_list);
if (!(gh->gh_flags & LM_FLAG_PRIORITY)) {
spin_unlock(&gl->gl_lockref.lock);
if (sdp->sd_lockstruct.ls_ops->lm_cancel)
sdp->sd_lockstruct.ls_ops->lm_cancel(gl);
spin_lock(&gl->gl_lockref.lock);
}
return;
trap_recursive:
......@@ -2195,7 +2188,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp)
flush_workqueue(glock_workqueue);
glock_hash_walk(clear_glock, sdp);
flush_workqueue(glock_workqueue);
wait_event_timeout(sdp->sd_glock_wait,
wait_event_timeout(sdp->sd_kill_wait,
atomic_read(&sdp->sd_glock_disposal) == 0,
HZ * 600);
glock_hash_walk(dump_glock_func, sdp);
......@@ -2227,8 +2220,6 @@ static const char *hflags2str(char *buf, u16 flags, unsigned long iflags)
*p++ = 'e';
if (flags & LM_FLAG_ANY)
*p++ = 'A';
if (flags & LM_FLAG_PRIORITY)
*p++ = 'p';
if (flags & LM_FLAG_NODE_SCOPE)
*p++ = 'n';
if (flags & GL_ASYNC)
......
......@@ -68,14 +68,6 @@ enum {
* also be granted in SHARED. The preferred state is whichever is compatible
* with other granted locks, or the specified state if no other locks exist.
*
* LM_FLAG_PRIORITY
* Override fairness considerations. Suppose a lock is held in a shared state
* and there is a pending request for the deferred state. A shared lock
* request with the priority flag would be allowed to bypass the deferred
* request and directly join the other shared lock. A shared lock request
* without the priority flag might be forced to wait until the deferred
* requested had acquired and released the lock.
*
* LM_FLAG_NODE_SCOPE
* This holder agrees to share the lock within this node. In other words,
* the glock is held in EX mode according to DLM, but local holders on the
......@@ -86,7 +78,6 @@ enum {
#define LM_FLAG_TRY_1CB 0x0002
#define LM_FLAG_NOEXP 0x0004
#define LM_FLAG_ANY 0x0008
#define LM_FLAG_PRIORITY 0x0010
#define LM_FLAG_NODE_SCOPE 0x0020
#define GL_ASYNC 0x0040
#define GL_EXACT 0x0080
......
......@@ -637,7 +637,7 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
if (!remote || sb_rdonly(sdp->sd_vfs) ||
test_bit(SDF_DEACTIVATING, &sdp->sd_flags))
test_bit(SDF_KILL, &sdp->sd_flags))
return;
if (gl->gl_demote_state == LM_ST_UNLOCKED &&
......
......@@ -452,7 +452,7 @@ struct gfs2_quota_data {
s64 qd_change_sync;
unsigned int qd_slot;
unsigned int qd_slot_count;
unsigned int qd_slot_ref;
struct buffer_head *qd_bh;
struct gfs2_quota_change *qd_bh_qc;
......@@ -537,6 +537,7 @@ struct gfs2_statfs_change_host {
#define GFS2_QUOTA_OFF 0
#define GFS2_QUOTA_ACCOUNT 1
#define GFS2_QUOTA_ON 2
#define GFS2_QUOTA_QUIET 3 /* on but not complaining */
#define GFS2_DATA_DEFAULT GFS2_DATA_ORDERED
#define GFS2_DATA_WRITEBACK 1
......@@ -606,7 +607,7 @@ enum {
SDF_REMOTE_WITHDRAW = 13, /* Performing remote recovery */
SDF_WITHDRAW_RECOVERY = 14, /* Wait for journal recovery when we are
withdrawing */
SDF_DEACTIVATING = 15,
SDF_KILL = 15,
SDF_EVICTING = 16,
SDF_FROZEN = 17,
};
......@@ -716,7 +717,7 @@ struct gfs2_sbd {
struct gfs2_glock *sd_rename_gl;
struct gfs2_glock *sd_freeze_gl;
struct work_struct sd_freeze_work;
wait_queue_head_t sd_glock_wait;
wait_queue_head_t sd_kill_wait;
wait_queue_head_t sd_async_glock_wait;
atomic_t sd_glock_disposal;
struct completion sd_locking_init;
......
......@@ -276,9 +276,15 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
* gfs2_lookup_simple callers expect ENOENT
* and do not check for NULL.
*/
if (inode == NULL)
return ERR_PTR(-ENOENT);
else
if (IS_ERR_OR_NULL(inode))
return inode ? inode : ERR_PTR(-ENOENT);
/*
* Must not call back into the filesystem when allocating
* pages in the metadata inode's address space.
*/
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
return inode;
}
......
......@@ -222,11 +222,6 @@ static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,
lkf |= DLM_LKF_NOQUEUEBAST;
}
if (gfs_flags & LM_FLAG_PRIORITY) {
lkf |= DLM_LKF_NOORDER;
lkf |= DLM_LKF_HEADQUE;
}
if (gfs_flags & LM_FLAG_ANY) {
if (req == DLM_LOCK_PR)
lkf |= DLM_LKF_ALTCW;
......
......@@ -1227,6 +1227,21 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
gfs2_log_unlock(sdp);
}
static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
{
return atomic_read(&sdp->sd_log_pinned) +
atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh1);
}
static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
{
return sdp->sd_jdesc->jd_blocks -
atomic_read(&sdp->sd_log_blks_free) +
atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh2);
}
/**
* gfs2_log_commit - Commit a transaction to the log
* @sdp: the filesystem
......@@ -1246,9 +1261,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
log_refund(sdp, tr);
if (atomic_read(&sdp->sd_log_pinned) > atomic_read(&sdp->sd_log_thresh1) ||
((sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free)) >
atomic_read(&sdp->sd_log_thresh2)))
if (gfs2_ail_flush_reqd(sdp) || gfs2_jrnl_flush_reqd(sdp))
wake_up(&sdp->sd_logd_waitq);
}
......@@ -1271,24 +1284,6 @@ static void gfs2_log_shutdown(struct gfs2_sbd *sdp)
gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
}
static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
{
return (atomic_read(&sdp->sd_log_pinned) +
atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh1));
}
static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
{
unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free);
if (test_and_clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags))
return 1;
return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh2);
}
/**
* gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
* @data: Pointer to GFS2 superblock
......@@ -1301,14 +1296,11 @@ int gfs2_logd(void *data)
{
struct gfs2_sbd *sdp = data;
unsigned long t = 1;
DEFINE_WAIT(wait);
while (!kthread_should_stop()) {
if (gfs2_withdrawn(sdp))
break;
if (gfs2_withdrawn(sdp)) {
msleep_interruptible(HZ);
continue;
}
/* Check for errors writing to the journal */
if (sdp->sd_log_error) {
gfs2_lm(sdp,
......@@ -1317,7 +1309,7 @@ int gfs2_logd(void *data)
"prevent further damage.\n",
sdp->sd_fsname, sdp->sd_log_error);
gfs2_withdraw(sdp);
continue;
break;
}
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
......@@ -1326,7 +1318,9 @@ int gfs2_logd(void *data)
GFS2_LFC_LOGD_JFLUSH_REQD);
}
if (gfs2_ail_flush_reqd(sdp)) {
if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) ||
gfs2_ail_flush_reqd(sdp)) {
clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp);
gfs2_ail1_empty(sdp, 0);
......@@ -1338,17 +1332,14 @@ int gfs2_logd(void *data)
try_to_freeze();
do {
prepare_to_wait(&sdp->sd_logd_waitq, &wait,
TASK_INTERRUPTIBLE);
if (!gfs2_ail_flush_reqd(sdp) &&
!gfs2_jrnl_flush_reqd(sdp) &&
!kthread_should_stop())
t = schedule_timeout(t);
} while(t && !gfs2_ail_flush_reqd(sdp) &&
!gfs2_jrnl_flush_reqd(sdp) &&
!kthread_should_stop());
finish_wait(&sdp->sd_logd_waitq, &wait);
t = wait_event_interruptible_timeout(sdp->sd_logd_waitq,
test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) ||
gfs2_ail_flush_reqd(sdp) ||
gfs2_jrnl_flush_reqd(sdp) ||
sdp->sd_log_error ||
gfs2_withdrawn(sdp) ||
kthread_should_stop(),
t);
}
return 0;
......
......@@ -456,7 +456,7 @@ static bool gfs2_jhead_pg_srch(struct gfs2_jdesc *jd,
* Find the folio with 'index' in the journal's mapping. Search the folio for
* the journal head if requested (cleanup == false). Release refs on the
* folio so the page cache can reclaim it. We grabbed a
* reference on this folio twice, first when we did a find_or_create_page()
* reference on this folio twice, first when we did a grab_cache_page()
* to obtain the folio to add it to the bio and second when we do a
* filemap_get_folio() here to get the folio to wait on while I/O on it is being
* completed.
......@@ -481,7 +481,7 @@ static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index,
if (!*done)
*done = gfs2_jhead_pg_srch(jd, head, &folio->page);
/* filemap_get_folio() and the earlier find_or_create_page() */
/* filemap_get_folio() and the earlier grab_cache_page() */
folio_put_refs(folio, 2);
}
......@@ -535,8 +535,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head,
for (; block < je->lblock + je->blocks; block++, dblock++) {
if (!page) {
page = find_or_create_page(mapping,
block >> shift, GFP_NOFS);
page = grab_cache_page(mapping, block >> shift);
if (!page) {
ret = -ENOMEM;
done = true;
......
......@@ -152,9 +152,9 @@ static int __init init_gfs2_fs(void)
goto fail_shrinker;
error = -ENOMEM;
gfs_recovery_wq = alloc_workqueue("gfs_recovery",
gfs2_recovery_wq = alloc_workqueue("gfs2_recovery",
WQ_MEM_RECLAIM | WQ_FREEZABLE, 0);
if (!gfs_recovery_wq)
if (!gfs2_recovery_wq)
goto fail_wq1;
gfs2_control_wq = alloc_workqueue("gfs2_control",
......@@ -162,7 +162,7 @@ static int __init init_gfs2_fs(void)
if (!gfs2_control_wq)
goto fail_wq2;
gfs2_freeze_wq = alloc_workqueue("freeze_workqueue", 0, 0);
gfs2_freeze_wq = alloc_workqueue("gfs2_freeze", 0, 0);
if (!gfs2_freeze_wq)
goto fail_wq3;
......@@ -194,7 +194,7 @@ static int __init init_gfs2_fs(void)
fail_wq3:
destroy_workqueue(gfs2_control_wq);
fail_wq2:
destroy_workqueue(gfs_recovery_wq);
destroy_workqueue(gfs2_recovery_wq);
fail_wq1:
unregister_shrinker(&gfs2_qd_shrinker);
fail_shrinker:
......@@ -234,7 +234,7 @@ static void __exit exit_gfs2_fs(void)
gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_fs_type);
destroy_workqueue(gfs_recovery_wq);
destroy_workqueue(gfs2_recovery_wq);
destroy_workqueue(gfs2_control_wq);
destroy_workqueue(gfs2_freeze_wq);
list_lru_destroy(&gfs2_qd_lru);
......
......@@ -87,7 +87,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
gfs2_tune_init(&sdp->sd_tune);
init_waitqueue_head(&sdp->sd_glock_wait);
init_waitqueue_head(&sdp->sd_kill_wait);
init_waitqueue_head(&sdp->sd_async_glock_wait);
atomic_set(&sdp->sd_glock_disposal, 0);
init_completion(&sdp->sd_locking_init);
......@@ -1103,29 +1103,49 @@ static int init_threads(struct gfs2_sbd *sdp)
struct task_struct *p;
int error = 0;
p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
p = kthread_create(gfs2_logd, sdp, "gfs2_logd/%s", sdp->sd_fsname);
if (IS_ERR(p)) {
error = PTR_ERR(p);
fs_err(sdp, "can't start logd thread: %d\n", error);
fs_err(sdp, "can't create logd thread: %d\n", error);
return error;
}
get_task_struct(p);
sdp->sd_logd_process = p;
p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
p = kthread_create(gfs2_quotad, sdp, "gfs2_quotad/%s", sdp->sd_fsname);
if (IS_ERR(p)) {
error = PTR_ERR(p);
fs_err(sdp, "can't start quotad thread: %d\n", error);
fs_err(sdp, "can't create quotad thread: %d\n", error);
goto fail;
}
get_task_struct(p);
sdp->sd_quotad_process = p;
wake_up_process(sdp->sd_logd_process);
wake_up_process(sdp->sd_quotad_process);
return 0;
fail:
kthread_stop(sdp->sd_logd_process);
put_task_struct(sdp->sd_logd_process);
sdp->sd_logd_process = NULL;
return error;
}
void gfs2_destroy_threads(struct gfs2_sbd *sdp)
{
if (sdp->sd_logd_process) {
kthread_stop(sdp->sd_logd_process);
put_task_struct(sdp->sd_logd_process);
sdp->sd_logd_process = NULL;
}
if (sdp->sd_quotad_process) {
kthread_stop(sdp->sd_quotad_process);
put_task_struct(sdp->sd_quotad_process);
sdp->sd_quotad_process = NULL;
}
}
/**
* gfs2_fill_super - Read in superblock
* @sb: The VFS superblock
......@@ -1276,12 +1296,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
if (error) {
gfs2_freeze_unlock(&sdp->sd_freeze_gh);
if (sdp->sd_quotad_process)
kthread_stop(sdp->sd_quotad_process);
sdp->sd_quotad_process = NULL;
if (sdp->sd_logd_process)
kthread_stop(sdp->sd_logd_process);
sdp->sd_logd_process = NULL;
gfs2_destroy_threads(sdp);
fs_err(sdp, "can't make FS RW: %d\n", error);
goto fail_per_node;
}
......@@ -1381,6 +1396,7 @@ static const struct constant_table gfs2_param_quota[] = {
{"off", GFS2_QUOTA_OFF},
{"account", GFS2_QUOTA_ACCOUNT},
{"on", GFS2_QUOTA_ON},
{"quiet", GFS2_QUOTA_QUIET},
{}
};
......@@ -1786,9 +1802,9 @@ static void gfs2_kill_sb(struct super_block *sb)
/*
* Flush and then drain the delete workqueue here (via
* destroy_workqueue()) to ensure that any delete work that
* may be running will also see the SDF_DEACTIVATING flag.
* may be running will also see the SDF_KILL flag.
*/
set_bit(SDF_DEACTIVATING, &sdp->sd_flags);
set_bit(SDF_KILL, &sdp->sd_flags);
gfs2_flush_delete_work(sdp);
destroy_workqueue(sdp->sd_delete_wq);
......
This diff is collapsed.
......@@ -27,7 +27,7 @@
#include "util.h"
#include "dir.h"
struct workqueue_struct *gfs_recovery_wq;
struct workqueue_struct *gfs2_recovery_wq;
int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
struct buffer_head **bh)
......@@ -570,7 +570,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
return -EBUSY;
/* we have JDF_RECOVERY, queue should always succeed */
rv = queue_work(gfs_recovery_wq, &jd->jd_work);
rv = queue_work(gfs2_recovery_wq, &jd->jd_work);
BUG_ON(!rv);
if (wait)
......
......@@ -9,7 +9,7 @@
#include "incore.h"
extern struct workqueue_struct *gfs_recovery_wq;
extern struct workqueue_struct *gfs2_recovery_wq;
static inline void gfs2_replay_incr_blk(struct gfs2_jdesc *jd, u32 *blk)
{
......
......@@ -546,20 +546,10 @@ void gfs2_make_fs_ro(struct gfs2_sbd *sdp)
{
int log_write_allowed = test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
if (!test_bit(SDF_DEACTIVATING, &sdp->sd_flags))
if (!test_bit(SDF_KILL, &sdp->sd_flags))
gfs2_flush_delete_work(sdp);
if (!log_write_allowed && current == sdp->sd_quotad_process)
fs_warn(sdp, "The quotad daemon is withdrawing.\n");
else if (sdp->sd_quotad_process)
kthread_stop(sdp->sd_quotad_process);
sdp->sd_quotad_process = NULL;
if (!log_write_allowed && current == sdp->sd_logd_process)
fs_warn(sdp, "The logd daemon is withdrawing.\n");
else if (sdp->sd_logd_process)
kthread_stop(sdp->sd_logd_process);
sdp->sd_logd_process = NULL;
gfs2_destroy_threads(sdp);
if (log_write_allowed) {
gfs2_quota_sync(sdp->sd_vfs, 0);
......@@ -580,15 +570,8 @@ void gfs2_make_fs_ro(struct gfs2_sbd *sdp)
gfs2_log_is_empty(sdp),
HZ * 5);
gfs2_assert_warn(sdp, gfs2_log_is_empty(sdp));
} else {
wait_event_timeout(sdp->sd_log_waitq,
gfs2_log_is_empty(sdp),
HZ * 5);
}
gfs2_quota_cleanup(sdp);
if (!log_write_allowed)
sdp->sd_vfs->s_flags |= SB_RDONLY;
}
/**
......@@ -622,6 +605,10 @@ static void gfs2_put_super(struct super_block *sb)
if (!sb_rdonly(sb)) {
gfs2_make_fs_ro(sdp);
}
if (gfs2_withdrawn(sdp)) {
gfs2_destroy_threads(sdp);
gfs2_quota_cleanup(sdp);
}
WARN_ON(gfs2_withdrawing(sdp));
/* At this point, we're through modifying the disk */
......@@ -1134,6 +1121,9 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
case GFS2_QUOTA_ON:
state = "on";
break;
case GFS2_QUOTA_QUIET:
state = "quiet";
break;
default:
state = "unknown";
break;
......
......@@ -36,6 +36,7 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
extern void gfs2_make_fs_ro(struct gfs2_sbd *sdp);
extern void gfs2_online_uevent(struct gfs2_sbd *sdp);
extern void gfs2_destroy_threads(struct gfs2_sbd *sdp);
extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
s64 dinodes);
......
......@@ -98,7 +98,10 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
"sd_log_flush_head: %d\n"
"sd_log_flush_tail: %d\n"
"sd_log_blks_reserved: %d\n"
"sd_log_revokes_available: %d\n",
"sd_log_revokes_available: %d\n"
"sd_log_pinned: %d\n"
"sd_log_thresh1: %d\n"
"sd_log_thresh2: %d\n",
test_bit(SDF_JOURNAL_CHECKED, &f),
test_bit(SDF_JOURNAL_LIVE, &f),
(sdp->sd_jdesc ? sdp->sd_jdesc->jd_jid : 0),
......@@ -118,7 +121,7 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
test_bit(SDF_WITHDRAW_IN_PROG, &f),
test_bit(SDF_REMOTE_WITHDRAW, &f),
test_bit(SDF_WITHDRAW_RECOVERY, &f),
test_bit(SDF_DEACTIVATING, &f),
test_bit(SDF_KILL, &f),
sdp->sd_log_error,
rwsem_is_locked(&sdp->sd_log_flush_lock),
sdp->sd_log_num_revoke,
......@@ -128,7 +131,10 @@ static ssize_t status_show(struct gfs2_sbd *sdp, char *buf)
sdp->sd_log_flush_head,
sdp->sd_log_flush_tail,
sdp->sd_log_blks_reserved,
atomic_read(&sdp->sd_log_revokes_available));
atomic_read(&sdp->sd_log_revokes_available),
atomic_read(&sdp->sd_log_pinned),
atomic_read(&sdp->sd_log_thresh1),
atomic_read(&sdp->sd_log_thresh2));
return s;
}
......
......@@ -9,6 +9,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/kthread.h>
#include <linux/crc32.h>
#include <linux/gfs2_ondisk.h>
#include <linux/delay.h>
......@@ -150,7 +151,14 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
if (!sb_rdonly(sdp->sd_vfs)) {
bool locked = mutex_trylock(&sdp->sd_freeze_mutex);
gfs2_make_fs_ro(sdp);
wake_up(&sdp->sd_logd_waitq);
wake_up(&sdp->sd_quota_wait);
wait_event_timeout(sdp->sd_log_waitq,
gfs2_log_is_empty(sdp),
HZ * 5);
sdp->sd_vfs->s_flags |= SB_RDONLY;
if (locked)
mutex_unlock(&sdp->sd_freeze_mutex);
......@@ -315,19 +323,19 @@ int gfs2_withdraw(struct gfs2_sbd *sdp)
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
const struct lm_lockops *lm = ls->ls_ops;
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW &&
test_and_set_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
if (!test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags))
return -1;
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
unsigned long old = READ_ONCE(sdp->sd_flags), new;
wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG,
do {
if (old & BIT(SDF_WITHDRAWN)) {
wait_on_bit(&sdp->sd_flags,
SDF_WITHDRAW_IN_PROG,
TASK_UNINTERRUPTIBLE);
return -1;
}
new = old | BIT(SDF_WITHDRAWN) | BIT(SDF_WITHDRAW_IN_PROG);
} while (unlikely(!try_cmpxchg(&sdp->sd_flags, &old, new)));
set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags);
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
fs_err(sdp, "about to withdraw this file system\n");
BUG_ON(sdp->sd_args.ar_debug);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment