* [Cluster-devel] [PATCH 1/9] gfs2: Fix up gfs2_glock_async_wait
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 2/9] gfs2: Instantiate glocks ouside of glock state engine Andreas Gruenbacher
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
Since commit 1fc05c8d8426 ("gfs2: cancel timed-out glock requests"), a
pending locking request can be canceled by calling gfs2_glock_dq() on
the pending holder. In gfs2_glock_async_wait(), when we time out, use
that to cancel the remaining locking requests and dequeue the locking
requests already granted. That's simpler as well as more efficient than
waiting for all locking requests to eventually be granted and dequeuing
them then.
In addition, gfs2_glock_async_wait() promises that by the time the
function completes, all glocks are either granted or dequeued, but the
implementation doesn't keep that promise if individual locking requests
fail. Fix that as well.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 53 ++++++++++++++-----------------------------------
1 file changed, 15 insertions(+), 38 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index c992d53013d3..f8a98fcbc04c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1355,7 +1355,6 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd;
int i, ret = 0, timeout = 0;
unsigned long start_time = jiffies;
- bool keep_waiting;
might_sleep();
/*
@@ -1365,53 +1364,31 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
for (i = 0; i < num_gh; i++)
timeout += ghs[i].gh_gl->gl_hold_time << 1;
-wait_for_dlm:
if (!wait_event_timeout(sdp->sd_async_glock_wait,
- !glocks_pending(num_gh, ghs), timeout))
+ !glocks_pending(num_gh, ghs), timeout)) {
ret = -ESTALE; /* request timed out. */
+ goto out;
+ }
- /*
- * If dlm granted all our requests, we need to adjust the glock
- * minimum hold time values according to how long we waited.
- *
- * If our request timed out, we need to repeatedly release any held
- * glocks we acquired thus far to allow dlm to acquire the remaining
- * glocks without deadlocking. We cannot currently cancel outstanding
- * glock acquisitions.
- *
- * The HIF_WAIT bit tells us which requests still need a response from
- * dlm.
- *
- * If dlm sent us any errors, we return the first error we find.
- */
- keep_waiting = false;
for (i = 0; i < num_gh; i++) {
- /* Skip holders we have already dequeued below. */
- if (!gfs2_holder_queued(&ghs[i]))
- continue;
- /* Skip holders with a pending DLM response. */
- if (test_bit(HIF_WAIT, &ghs[i].gh_iflags)) {
- keep_waiting = true;
- continue;
- }
+ struct gfs2_holder *gh = &ghs[i];
- if (test_bit(HIF_HOLDER, &ghs[i].gh_iflags)) {
- if (ret == -ESTALE)
- gfs2_glock_dq(&ghs[i]);
- else
- gfs2_glock_update_hold_time(ghs[i].gh_gl,
- start_time);
+ if (test_bit(HIF_HOLDER, &gh->gh_iflags)) {
+ gfs2_glock_update_hold_time(gh->gh_gl,
+ start_time);
}
if (!ret)
- ret = ghs[i].gh_error;
+ ret = gh->gh_error;
}
- if (keep_waiting)
- goto wait_for_dlm;
+out:
+ if (ret) {
+ for (i = 0; i < num_gh; i++) {
+ struct gfs2_holder *gh = &ghs[i];
- /*
- * At this point, we've either acquired all locks or released them all.
- */
+ gfs2_glock_dq(gh);
+ }
+ }
return ret;
}
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 2/9] gfs2: Instantiate glocks ouside of glock state engine
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 1/9] gfs2: Fix up gfs2_glock_async_wait Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 3/9] gfs2: Revert 'Fix "truncate in progress" hang' Andreas Gruenbacher
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
Instantiate glocks outside of the glock state engine: there is no real
reason for instantiating them inside the glock state engine; it only
complicates the code.
Instead, instantiate them in gfs2_glock_wait() and gfs2_glock_async_wait()
using the new gfs2_glock_holder_ready() helper. On top of that, the only
other place that acquires a glock without using gfs2_glock_wait() or
gfs2_glock_async_wait() is gfs2_upgrade_iopen_glock(), so call
gfs2_glock_holder_ready() there as well.
If a dinode has a pending truncate, the glock-specific instantiate function
for inodes wakes up the truncate function in the quota daemon. Waiting for
the completion of the truncate was previously done by the glock state
engine, but we now need to wait in inode_go_instantiate().
This also means that gfs2_instantiate() will now no longer return any
"special" error codes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 66 ++++++++++++++++++++++++-------------------------
fs/gfs2/glock.h | 2 ++
fs/gfs2/glops.c | 2 +-
fs/gfs2/super.c | 2 +-
4 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index f8a98fcbc04c..41bee3db8c0d 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -478,8 +478,7 @@ find_first_strong_holder(struct gfs2_glock *gl)
* gfs2_instantiate - Call the glops instantiate function
* @gh: The glock holder
*
- * Returns: 0 if instantiate was successful, 2 if type specific operation is
- * underway, or error.
+ * Returns: 0 if instantiate was successful, or error.
*/
int gfs2_instantiate(struct gfs2_holder *gh)
{
@@ -524,18 +523,12 @@ int gfs2_instantiate(struct gfs2_holder *gh)
*/
static int do_promote(struct gfs2_glock *gl)
-__releases(&gl->gl_lockref.lock)
-__acquires(&gl->gl_lockref.lock)
{
struct gfs2_holder *gh, *tmp, *first_gh;
bool incompat_holders_demoted = false;
- bool lock_released;
- int ret;
-restart:
first_gh = find_first_strong_holder(gl);
list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
- lock_released = false;
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
continue;
if (!may_grant(gl, first_gh, gh)) {
@@ -554,32 +547,9 @@ __acquires(&gl->gl_lockref.lock)
incompat_holders_demoted = true;
first_gh = gh;
}
- if (test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags) &&
- !(gh->gh_flags & GL_SKIP) && gl->gl_ops->go_instantiate) {
- lock_released = true;
- spin_unlock(&gl->gl_lockref.lock);
- ret = gfs2_instantiate(gh);
- spin_lock(&gl->gl_lockref.lock);
- if (ret) {
- if (ret == 1)
- return 2;
- gh->gh_error = ret;
- list_del_init(&gh->gh_list);
- trace_gfs2_glock_queue(gh, 0);
- gfs2_holder_wake(gh);
- goto restart;
- }
- }
set_bit(HIF_HOLDER, &gh->gh_iflags);
trace_gfs2_promote(gh);
gfs2_holder_wake(gh);
- /*
- * If we released the gl_lockref.lock the holders list may have
- * changed. For that reason, we start again at the start of
- * the holders queue.
- */
- if (lock_released)
- goto restart;
}
return 0;
}
@@ -1313,6 +1283,25 @@ static void gfs2_glock_update_hold_time(struct gfs2_glock *gl,
}
}
+/**
+ * gfs2_glock_holder_ready - holder is ready and its error code can be collected
+ * @gh: the glock holder
+ *
+ * Called when a glock holder no longer needs to be waited for because it is
+ * now either held (HIF_HOLDER set; gh_error == 0), or acquiring the lock has
+ * failed (gh_error != 0).
+ */
+
+int gfs2_glock_holder_ready(struct gfs2_holder *gh)
+{
+ if (gh->gh_error || (gh->gh_flags & GL_SKIP))
+ return gh->gh_error;
+ gh->gh_error = gfs2_instantiate(gh);
+ if (gh->gh_error)
+ gfs2_glock_dq(gh);
+ return gh->gh_error;
+}
+
/**
* gfs2_glock_wait - wait on a glock acquisition
* @gh: the glock holder
@@ -1327,7 +1316,7 @@ int gfs2_glock_wait(struct gfs2_holder *gh)
might_sleep();
wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE);
gfs2_glock_update_hold_time(gh->gh_gl, start_time);
- return gh->gh_error;
+ return gfs2_glock_holder_ready(gh);
}
static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs)
@@ -1372,13 +1361,15 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
for (i = 0; i < num_gh; i++) {
struct gfs2_holder *gh = &ghs[i];
+ int ret2;
if (test_bit(HIF_HOLDER, &gh->gh_iflags)) {
gfs2_glock_update_hold_time(gh->gh_gl,
start_time);
}
+ ret2 = gfs2_glock_holder_ready(gh);
if (!ret)
- ret = gh->gh_error;
+ ret = ret2;
}
out:
@@ -2233,9 +2224,18 @@ void gfs2_glock_finish_truncate(struct gfs2_inode *ip)
spin_lock(&gl->gl_lockref.lock);
clear_bit(GLF_LOCK, &gl->gl_flags);
run_queue(gl, 1);
+ wake_up_glock(gl);
spin_unlock(&gl->gl_lockref.lock);
}
+void gfs2_wait_truncate(struct gfs2_inode *ip)
+{
+ struct gfs2_glock *gl = ip->i_gl;
+ wait_queue_head_t *wq = glock_waitqueue(&gl->gl_name);
+
+ wait_event(*wq, !(ip->i_diskflags & GFS2_DIF_TRUNC_IN_PROG));
+}
+
static const char *state2str(unsigned state)
{
switch(state) {
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index c0ae9100a0bc..2796d5414ec9 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -213,6 +213,7 @@ extern void gfs2_holder_uninit(struct gfs2_holder *gh);
extern int gfs2_glock_nq(struct gfs2_holder *gh);
extern int gfs2_glock_poll(struct gfs2_holder *gh);
extern int gfs2_instantiate(struct gfs2_holder *gh);
+extern int gfs2_glock_holder_ready(struct gfs2_holder *gh);
extern int gfs2_glock_wait(struct gfs2_holder *gh);
extern int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs);
extern void gfs2_glock_dq(struct gfs2_holder *gh);
@@ -274,6 +275,7 @@ extern bool gfs2_delete_work_queued(const struct gfs2_glock *gl);
extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
extern void gfs2_glock_finish_truncate(struct gfs2_inode *ip);
+extern void gfs2_wait_truncate(struct gfs2_inode *ip);
extern void gfs2_glock_thaw(struct gfs2_sbd *sdp);
extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl);
extern void gfs2_glock_free(struct gfs2_glock *gl);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 392800f082a6..6bc096610654 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -510,7 +510,7 @@ static int inode_go_instantiate(struct gfs2_holder *gh)
list_add(&ip->i_trunc_list, &sdp->sd_trunc_list);
spin_unlock(&sdp->sd_trunc_lock);
wake_up(&sdp->sd_quota_wait);
- error = 1;
+ gfs2_wait_truncate(ip);
}
out:
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index bdb773e5c88f..b5b0f285b27f 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1196,7 +1196,7 @@ static bool gfs2_upgrade_iopen_glock(struct inode *inode)
gfs2_glock_dq(gh);
return false;
}
- return true;
+ return gfs2_glock_holder_ready(gh) == 0;
}
/**
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 3/9] gfs2: Revert 'Fix "truncate in progress" hang'
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 1/9] gfs2: Fix up gfs2_glock_async_wait Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 2/9] gfs2: Instantiate glocks ouside of glock state engine Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 4/9] gfs2: Add new go_held glock operation Andreas Gruenbacher
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
Now that interrupted truncates are completed in the context of the
process taking the glock, there is no need for the glock state engine to
delegate that task to gfs2_quotad or for quotad to perform those
truncates anymore. Get rid of the obsolete associated infrastructure.
Reverts commit 813e0c46c9e2 ("GFS2: Fix "truncate in progress" hang").
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
fs/gfs2/glock.c | 41 +++++------------------------------------
fs/gfs2/glock.h | 2 --
fs/gfs2/glops.c | 11 ++---------
fs/gfs2/incore.h | 3 ---
fs/gfs2/main.c | 1 -
fs/gfs2/ops_fstype.c | 2 --
fs/gfs2/quota.c | 28 +---------------------------
7 files changed, 8 insertions(+), 80 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 41bee3db8c0d..347c7bc1fae3 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -518,8 +518,7 @@ 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, or 2
- * if a type specific operation is underway.
+ * Returns: 1 if there is a blocked holder at the head of the list
*/
static int do_promote(struct gfs2_glock *gl)
@@ -627,7 +626,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
const struct gfs2_glock_operations *glops = gl->gl_ops;
struct gfs2_holder *gh;
unsigned state = ret & LM_OUT_ST_MASK;
- int rv;
spin_lock(&gl->gl_lockref.lock);
trace_gfs2_glock_state_change(gl, state);
@@ -685,6 +683,8 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
gfs2_demote_wake(gl);
if (state != LM_ST_UNLOCKED) {
if (glops->go_xmote_bh) {
+ int rv;
+
spin_unlock(&gl->gl_lockref.lock);
rv = glops->go_xmote_bh(gl);
spin_lock(&gl->gl_lockref.lock);
@@ -693,13 +693,10 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
goto out;
}
}
- rv = do_promote(gl);
- if (rv == 2)
- goto out_locked;
+ do_promote(gl);
}
out:
clear_bit(GLF_LOCK, &gl->gl_flags);
-out_locked:
spin_unlock(&gl->gl_lockref.lock);
}
@@ -856,7 +853,6 @@ __releases(&gl->gl_lockref.lock)
__acquires(&gl->gl_lockref.lock)
{
struct gfs2_holder *gh = NULL;
- int ret;
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags))
return;
@@ -875,18 +871,14 @@ __acquires(&gl->gl_lockref.lock)
} else {
if (test_bit(GLF_DEMOTE, &gl->gl_flags))
gfs2_demote_wake(gl);
- ret = do_promote(gl);
- if (ret == 0)
+ if (do_promote(gl) == 0)
goto out_unlock;
- if (ret == 2)
- goto out;
gh = find_first_waiter(gl);
gl->gl_target = gh->gh_state;
if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)))
do_error(gl, 0); /* Fail queued try locks */
}
do_xmote(gl, gh, gl->gl_target);
-out:
return;
out_sched:
@@ -2213,29 +2205,6 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp)
glock_hash_walk(dump_glock_func, sdp);
}
-void gfs2_glock_finish_truncate(struct gfs2_inode *ip)
-{
- struct gfs2_glock *gl = ip->i_gl;
- int ret;
-
- ret = gfs2_truncatei_resume(ip);
- gfs2_glock_assert_withdraw(gl, ret == 0);
-
- spin_lock(&gl->gl_lockref.lock);
- clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl, 1);
- wake_up_glock(gl);
- spin_unlock(&gl->gl_lockref.lock);
-}
-
-void gfs2_wait_truncate(struct gfs2_inode *ip)
-{
- struct gfs2_glock *gl = ip->i_gl;
- wait_queue_head_t *wq = glock_waitqueue(&gl->gl_name);
-
- wait_event(*wq, !(ip->i_diskflags & GFS2_DIF_TRUNC_IN_PROG));
-}
-
static const char *state2str(unsigned state)
{
switch(state) {
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 2796d5414ec9..5aed8b500cf5 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -274,8 +274,6 @@ extern void gfs2_cancel_delete_work(struct gfs2_glock *gl);
extern bool gfs2_delete_work_queued(const struct gfs2_glock *gl);
extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
-extern void gfs2_glock_finish_truncate(struct gfs2_inode *ip);
-extern void gfs2_wait_truncate(struct gfs2_inode *ip);
extern void gfs2_glock_thaw(struct gfs2_sbd *sdp);
extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl);
extern void gfs2_glock_free(struct gfs2_glock *gl);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 6bc096610654..c387f80ca65e 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -488,7 +488,6 @@ int gfs2_inode_refresh(struct gfs2_inode *ip)
static int inode_go_instantiate(struct gfs2_holder *gh)
{
struct gfs2_glock *gl = gh->gh_gl;
- struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
struct gfs2_inode *ip = gl->gl_object;
int error = 0;
@@ -504,14 +503,8 @@ static int inode_go_instantiate(struct gfs2_holder *gh)
if ((ip->i_diskflags & GFS2_DIF_TRUNC_IN_PROG) &&
(gl->gl_state == LM_ST_EXCLUSIVE) &&
- (gh->gh_state == LM_ST_EXCLUSIVE)) {
- spin_lock(&sdp->sd_trunc_lock);
- if (list_empty(&ip->i_trunc_list))
- list_add(&ip->i_trunc_list, &sdp->sd_trunc_list);
- spin_unlock(&sdp->sd_trunc_lock);
- wake_up(&sdp->sd_quota_wait);
- gfs2_wait_truncate(ip);
- }
+ (gh->gh_state == LM_ST_EXCLUSIVE))
+ error = gfs2_truncatei_resume(ip);
out:
return error;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 8c00fb389ae5..9e319c8f9efd 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -396,7 +396,6 @@ struct gfs2_inode {
atomic_t i_sizehint; /* hint of the write size */
struct rw_semaphore i_rw_mutex;
struct list_head i_ordered;
- struct list_head i_trunc_list;
__be64 *i_hash_cache;
u32 i_entries;
u32 i_diskflags;
@@ -784,8 +783,6 @@ struct gfs2_sbd {
struct mutex sd_quota_mutex;
struct mutex sd_quota_sync_mutex;
wait_queue_head_t sd_quota_wait;
- struct list_head sd_trunc_list;
- spinlock_t sd_trunc_lock;
unsigned int sd_quota_slots;
unsigned long *sd_quota_bitmap;
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 244187e3e70f..d94791527dcb 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -38,7 +38,6 @@ static void gfs2_init_inode_once(void *foo)
inode_init_once(&ip->i_inode);
atomic_set(&ip->i_sizehint, 0);
init_rwsem(&ip->i_rw_mutex);
- INIT_LIST_HEAD(&ip->i_trunc_list);
INIT_LIST_HEAD(&ip->i_ordered);
ip->i_qadata = NULL;
gfs2_holder_mark_uninitialized(&ip->i_rgd_gh);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index c9b423c874a3..549879929c84 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -106,8 +106,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
mutex_init(&sdp->sd_quota_mutex);
mutex_init(&sdp->sd_quota_sync_mutex);
init_waitqueue_head(&sdp->sd_quota_wait);
- INIT_LIST_HEAD(&sdp->sd_trunc_list);
- spin_lock_init(&sdp->sd_trunc_lock);
spin_lock_init(&sdp->sd_bitmap_lock);
INIT_LIST_HEAD(&sdp->sd_sc_inodes_list);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 59d727a4ae2c..a6667e8d781f 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1517,25 +1517,6 @@ static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg,
}
}
-static void quotad_check_trunc_list(struct gfs2_sbd *sdp)
-{
- struct gfs2_inode *ip;
-
- while(1) {
- ip = NULL;
- spin_lock(&sdp->sd_trunc_lock);
- if (!list_empty(&sdp->sd_trunc_list)) {
- ip = list_first_entry(&sdp->sd_trunc_list,
- struct gfs2_inode, i_trunc_list);
- list_del_init(&ip->i_trunc_list);
- }
- spin_unlock(&sdp->sd_trunc_lock);
- if (ip == NULL)
- return;
- gfs2_glock_finish_truncate(ip);
- }
-}
-
void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) {
if (!sdp->sd_statfs_force_sync) {
sdp->sd_statfs_force_sync = 1;
@@ -1558,7 +1539,6 @@ int gfs2_quotad(void *data)
unsigned long quotad_timeo = 0;
unsigned long t = 0;
DEFINE_WAIT(wait);
- int empty;
while (!kthread_should_stop()) {
@@ -1579,19 +1559,13 @@ int gfs2_quotad(void *data)
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
"ad_timeo, &tune->gt_quota_quantum);
- /* Check for & recover partially truncated inodes */
- quotad_check_trunc_list(sdp);
-
try_to_freeze();
bypass:
t = min(quotad_timeo, statfs_timeo);
prepare_to_wait(&sdp->sd_quota_wait, &wait, TASK_INTERRUPTIBLE);
- spin_lock(&sdp->sd_trunc_lock);
- empty = list_empty(&sdp->sd_trunc_list);
- spin_unlock(&sdp->sd_trunc_lock);
- if (empty && !sdp->sd_statfs_force_sync)
+ if (!sdp->sd_statfs_force_sync)
t -= schedule_timeout(t);
else
t = 0;
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 4/9] gfs2: Add new go_held glock operation
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
` (2 preceding siblings ...)
2022-06-29 16:37 ` [Cluster-devel] [PATCH 3/9] gfs2: Revert 'Fix "truncate in progress" hang' Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 5/9] gfs2: Make go_instantiate take a glock Andreas Gruenbacher
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
Right now, inode_go_instantiate() contains functionality that relates to
how a glock is held rather than the glock itself, like waiting for
pending direct I/O to complete and completing interrupted truncates.
This code is meant to be run each time a holder is acquired, but
go_instantiate is actually only called once, when the glock is
instantiated.
To fix that, introduce a new go_held glock operation that is called each
time a glock holder is acquired. Move the holder specific code in
inode_go_instantiate() over to inode_go_held().
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 10 ++++++++--
fs/gfs2/glops.c | 19 +++++++++++++------
fs/gfs2/incore.h | 1 +
3 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 347c7bc1fae3..6fe088644d7d 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -488,7 +488,7 @@ int gfs2_instantiate(struct gfs2_holder *gh)
again:
if (!test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags))
- return 0;
+ goto done;
/*
* Since we unlock the lockref lock, we set a flag to indicate
@@ -511,7 +511,13 @@ int gfs2_instantiate(struct gfs2_holder *gh)
if (!ret)
clear_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags);
clear_and_wake_up_bit(GLF_INSTANTIATE_IN_PROG, &gl->gl_flags);
- return ret;
+ if (ret)
+ return ret;
+
+done:
+ if (glops->go_held)
+ return glops->go_held(gh);
+ return 0;
}
/**
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index c387f80ca65e..4e0a9909087c 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -489,14 +489,21 @@ static int inode_go_instantiate(struct gfs2_holder *gh)
{
struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_inode *ip = gl->gl_object;
- int error = 0;
if (!ip) /* no inode to populate - read it in later */
- goto out;
+ return 0;
- error = gfs2_inode_refresh(ip);
- if (error)
- goto out;
+ return gfs2_inode_refresh(ip);
+}
+
+static int inode_go_held(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_inode *ip = gl->gl_object;
+ int error = 0;
+
+ if (!ip) /* no inode to populate - read it in later */
+ return 0;
if (gh->gh_state != LM_ST_DEFERRED)
inode_dio_wait(&ip->i_inode);
@@ -506,7 +513,6 @@ static int inode_go_instantiate(struct gfs2_holder *gh)
(gh->gh_state == LM_ST_EXCLUSIVE))
error = gfs2_truncatei_resume(ip);
-out:
return error;
}
@@ -730,6 +736,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
.go_inval = inode_go_inval,
.go_demote_ok = inode_go_demote_ok,
.go_instantiate = inode_go_instantiate,
+ .go_held = inode_go_held,
.go_dump = inode_go_dump,
.go_type = LM_TYPE_INODE,
.go_flags = GLOF_ASPACE | GLOF_LRU | GLOF_LVB,
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 9e319c8f9efd..15e4258a1dad 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -220,6 +220,7 @@ struct gfs2_glock_operations {
void (*go_inval) (struct gfs2_glock *gl, int flags);
int (*go_demote_ok) (const struct gfs2_glock *gl);
int (*go_instantiate) (struct gfs2_holder *gh);
+ int (*go_held)(struct gfs2_holder *gh);
void (*go_dump)(struct seq_file *seq, struct gfs2_glock *gl,
const char *fs_id_buf);
void (*go_callback)(struct gfs2_glock *gl, bool remote);
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 5/9] gfs2: Make go_instantiate take a glock
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
` (3 preceding siblings ...)
2022-06-29 16:37 ` [Cluster-devel] [PATCH 4/9] gfs2: Add new go_held glock operation Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 6/9] gfs2: Use better variable name Andreas Gruenbacher
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
Make go_instantiate take a glock instead of a glock holder as its argument:
this handler is supposed to instantiate the object associated with the glock.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 2 +-
fs/gfs2/glops.c | 3 +--
fs/gfs2/incore.h | 2 +-
fs/gfs2/rgrp.c | 3 +--
fs/gfs2/rgrp.h | 2 +-
5 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 6fe088644d7d..832af9a03b15 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -507,7 +507,7 @@ int gfs2_instantiate(struct gfs2_holder *gh)
goto again;
}
- ret = glops->go_instantiate(gh);
+ ret = glops->go_instantiate(gl);
if (!ret)
clear_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags);
clear_and_wake_up_bit(GLF_INSTANTIATE_IN_PROG, &gl->gl_flags);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 4e0a9909087c..49210a2e7ce7 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -485,9 +485,8 @@ int gfs2_inode_refresh(struct gfs2_inode *ip)
* Returns: errno
*/
-static int inode_go_instantiate(struct gfs2_holder *gh)
+static int inode_go_instantiate(struct gfs2_glock *gl)
{
- struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_inode *ip = gl->gl_object;
if (!ip) /* no inode to populate - read it in later */
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 15e4258a1dad..d09d9892cd05 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -219,7 +219,7 @@ struct gfs2_glock_operations {
int (*go_xmote_bh)(struct gfs2_glock *gl);
void (*go_inval) (struct gfs2_glock *gl, int flags);
int (*go_demote_ok) (const struct gfs2_glock *gl);
- int (*go_instantiate) (struct gfs2_holder *gh);
+ int (*go_instantiate) (struct gfs2_glock *gl);
int (*go_held)(struct gfs2_holder *gh);
void (*go_dump)(struct seq_file *seq, struct gfs2_glock *gl,
const char *fs_id_buf);
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 8a63870eef5a..5439bad3083e 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -1196,9 +1196,8 @@ static void rgrp_set_bitmap_flags(struct gfs2_rgrpd *rgd)
* Returns: errno
*/
-int gfs2_rgrp_go_instantiate(struct gfs2_holder *gh)
+int gfs2_rgrp_go_instantiate(struct gfs2_glock *gl)
{
- struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_rgrpd *rgd = gl->gl_object;
struct gfs2_sbd *sdp = rgd->rd_sbd;
unsigned int length = rgd->rd_length;
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index 46dd94e9e085..c75bac45d314 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -31,7 +31,7 @@ extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
extern int gfs2_rindex_update(struct gfs2_sbd *sdp);
extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
-extern int gfs2_rgrp_go_instantiate(struct gfs2_holder *gh);
+extern int gfs2_rgrp_go_instantiate(struct gfs2_glock *gl);
extern void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd);
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 6/9] gfs2: Use better variable name
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
` (4 preceding siblings ...)
2022-06-29 16:37 ` [Cluster-devel] [PATCH 5/9] gfs2: Make go_instantiate take a glock Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 7/9] gfs2: do_promote glock holder stealing fix Andreas Gruenbacher
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
In do_promote() and add_to_queue(), use current_gh as the variable name
for the first strong holder we could find: this matches the variable
name is may_grant(), and more clearly indicates that we're interested in
one (any) of the current strong holders.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 832af9a03b15..27b519099579 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -529,14 +529,14 @@ int gfs2_instantiate(struct gfs2_holder *gh)
static int do_promote(struct gfs2_glock *gl)
{
- struct gfs2_holder *gh, *tmp, *first_gh;
+ struct gfs2_holder *gh, *tmp, *current_gh;
bool incompat_holders_demoted = false;
- first_gh = find_first_strong_holder(gl);
+ current_gh = find_first_strong_holder(gl);
list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
continue;
- if (!may_grant(gl, first_gh, gh)) {
+ if (!may_grant(gl, current_gh, gh)) {
/*
* If we get here, it means we may not grant this holder for
* some reason. If this holder is the head of the list, it
@@ -548,9 +548,9 @@ static int do_promote(struct gfs2_glock *gl)
break;
}
if (!incompat_holders_demoted) {
- demote_incompat_holders(gl, first_gh);
+ demote_incompat_holders(gl, current_gh);
incompat_holders_demoted = true;
- first_gh = gh;
+ current_gh = gh;
}
set_bit(HIF_HOLDER, &gh->gh_iflags);
trace_gfs2_promote(gh);
@@ -1456,10 +1456,10 @@ __acquires(&gl->gl_lockref.lock)
if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
if (test_bit(GLF_LOCK, &gl->gl_flags)) {
- struct gfs2_holder *first_gh;
+ struct gfs2_holder *current_gh;
- first_gh = find_first_strong_holder(gl);
- try_futile = !may_grant(gl, first_gh, gh);
+ current_gh = find_first_strong_holder(gl);
+ try_futile = !may_grant(gl, current_gh, gh);
}
if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags))
goto fail;
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 7/9] gfs2: do_promote glock holder stealing fix
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
` (5 preceding siblings ...)
2022-06-29 16:37 ` [Cluster-devel] [PATCH 6/9] gfs2: Use better variable name Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 8/9] gfs2: List traversal in do_promote is safe Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 9/9] Revert "gfs2: Stop using glock holder auto-demotion for now" Andreas Gruenbacher
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
From: Bob Peterson <rpeterso@redhat.com>
In do_promote(), when the glock had no strong holders, we were
accidentally calling demote_incompat_holders() with new_gh == NULL, so
no weak holders were considered incompatible. Instead, the new holder
should have been passed in.
For doing that, the HIF_HOLDER flag needs to be set in new_gh to prevent
may_grant() from complaining. This means that the new holder will now
be recognized as a current holder, so skip over it explicitly in
demote_incompat_holders() to prevent it from being dequeued.
To further clarify things, we can now rename new_gh to current_gh in
demote_incompat_holders(); after all, the HIF_HOLDER flag is already set,
which means the new holder is already a current holder.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 27b519099579..2138460a7369 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -405,10 +405,13 @@ static void do_error(struct gfs2_glock *gl, const int ret)
/**
* demote_incompat_holders - demote incompatible demoteable holders
* @gl: the glock we want to promote
- * @new_gh: the new holder to be promoted
+ * @current_gh: the newly promoted holder
+ *
+ * We're passing the newly promoted holder in @current_gh, but actually, any of
+ * the strong holders would do.
*/
static void demote_incompat_holders(struct gfs2_glock *gl,
- struct gfs2_holder *new_gh)
+ struct gfs2_holder *current_gh)
{
struct gfs2_holder *gh, *tmp;
@@ -424,8 +427,10 @@ static void demote_incompat_holders(struct gfs2_glock *gl,
*/
if (!test_bit(HIF_HOLDER, &gh->gh_iflags))
return;
+ if (gh == current_gh)
+ continue;
if (test_bit(HIF_MAY_DEMOTE, &gh->gh_iflags) &&
- !may_grant(gl, new_gh, gh)) {
+ !may_grant(gl, current_gh, gh)) {
/*
* We should not recurse into do_promote because
* __gfs2_glock_dq only calls handle_callback,
@@ -547,14 +552,14 @@ static int do_promote(struct gfs2_glock *gl)
do_error(gl, 0);
break;
}
+ set_bit(HIF_HOLDER, &gh->gh_iflags);
+ trace_gfs2_promote(gh);
+ gfs2_holder_wake(gh);
if (!incompat_holders_demoted) {
+ current_gh = gh;
demote_incompat_holders(gl, current_gh);
incompat_holders_demoted = true;
- current_gh = gh;
}
- set_bit(HIF_HOLDER, &gh->gh_iflags);
- trace_gfs2_promote(gh);
- gfs2_holder_wake(gh);
}
return 0;
}
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 8/9] gfs2: List traversal in do_promote is safe
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
` (6 preceding siblings ...)
2022-06-29 16:37 ` [Cluster-devel] [PATCH 7/9] gfs2: do_promote glock holder stealing fix Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
2022-06-29 16:37 ` [Cluster-devel] [PATCH 9/9] Revert "gfs2: Stop using glock holder auto-demotion for now" Andreas Gruenbacher
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
In do_promote(), we're never removing the current entry from the list
and so the list traversal is actually safe. Switch back to
list_for_each_entry().
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 2138460a7369..e79f17d6d001 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -534,11 +534,11 @@ int gfs2_instantiate(struct gfs2_holder *gh)
static int do_promote(struct gfs2_glock *gl)
{
- struct gfs2_holder *gh, *tmp, *current_gh;
+ struct gfs2_holder *gh, *current_gh;
bool incompat_holders_demoted = false;
current_gh = find_first_strong_holder(gl);
- list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
+ list_for_each_entry(gh, &gl->gl_holders, gh_list) {
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
continue;
if (!may_grant(gl, current_gh, gh)) {
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Cluster-devel] [PATCH 9/9] Revert "gfs2: Stop using glock holder auto-demotion for now"
2022-06-29 16:37 [Cluster-devel] [PATCH 0/9] gfs2: glock instantiation and holder auto-demotion fixes Andreas Gruenbacher
` (7 preceding siblings ...)
2022-06-29 16:37 ` [Cluster-devel] [PATCH 8/9] gfs2: List traversal in do_promote is safe Andreas Gruenbacher
@ 2022-06-29 16:37 ` Andreas Gruenbacher
8 siblings, 0 replies; 10+ messages in thread
From: Andreas Gruenbacher @ 2022-06-29 16:37 UTC (permalink / raw)
To: cluster-devel.redhat.com
With the glock holder auto-demotion in do_promote fixed, we can
re-enable this feature.
This reverts commit e1fa9ea85ce89207d2ac0316da35a4a7736801f9.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/file.c | 46 ++++++++++++++++++++++++++++++++--------------
1 file changed, 32 insertions(+), 14 deletions(-)
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 2cceb193dcd8..fee69467f11e 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -832,6 +832,7 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
ret = gfs2_glock_nq(gh);
if (ret)
goto out_uninit;
+retry_under_glock:
pagefault_disable();
to->nofault = true;
ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
@@ -845,10 +846,14 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
read = ret;
if (should_fault_in_pages(to, iocb, &prev_count, &window_size)) {
- gfs2_glock_dq(gh);
+ gfs2_holder_allow_demote(gh);
window_size -= fault_in_iov_iter_writeable(to, window_size);
- if (window_size)
+ gfs2_holder_disallow_demote(gh);
+ if (window_size) {
+ if (gfs2_holder_queued(gh))
+ goto retry_under_glock;
goto retry;
+ }
}
out_unlock:
if (gfs2_holder_queued(gh))
@@ -897,6 +902,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
/* Silently fall back to buffered I/O when writing beyond EOF */
if (iocb->ki_pos + iov_iter_count(from) > i_size_read(&ip->i_inode))
goto out_unlock;
+retry_under_glock:
from->nofault = true;
ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL,
@@ -913,10 +919,14 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
written = ret;
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
- gfs2_glock_dq(gh);
+ gfs2_holder_allow_demote(gh);
window_size -= fault_in_iov_iter_readable(from, window_size);
- if (window_size)
+ gfs2_holder_disallow_demote(gh);
+ if (window_size) {
+ if (gfs2_holder_queued(gh))
+ goto retry_under_glock;
goto retry;
+ }
}
out_unlock:
if (gfs2_holder_queued(gh))
@@ -968,6 +978,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
ret = gfs2_glock_nq(&gh);
if (ret)
goto out_uninit;
+retry_under_glock:
pagefault_disable();
ret = generic_file_read_iter(iocb, to);
pagefault_enable();
@@ -977,10 +988,14 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
read += ret;
if (should_fault_in_pages(to, iocb, &prev_count, &window_size)) {
- gfs2_glock_dq(&gh);
+ gfs2_holder_allow_demote(&gh);
window_size -= fault_in_iov_iter_writeable(to, window_size);
- if (window_size)
+ gfs2_holder_disallow_demote(&gh);
+ if (window_size) {
+ if (gfs2_holder_queued(&gh))
+ goto retry_under_glock;
goto retry;
+ }
}
out_unlock:
if (gfs2_holder_queued(&gh))
@@ -1019,17 +1034,22 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, gh);
retry:
+ ret = gfs2_glock_nq(gh);
+ if (ret)
+ goto out_uninit;
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
+retry_under_glock:
+ gfs2_holder_allow_demote(gh);
window_size -= fault_in_iov_iter_readable(from, window_size);
+ gfs2_holder_disallow_demote(gh);
if (!window_size) {
ret = -EFAULT;
- goto out_uninit;
+ goto out_unlock;
}
+ if (!gfs2_holder_queued(gh))
+ goto retry;
from->count = min(from->count, window_size);
}
- ret = gfs2_glock_nq(gh);
- if (ret)
- goto out_uninit;
if (inode == sdp->sd_rindex) {
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
@@ -1057,10 +1077,8 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
goto out_unlock;
from->count = orig_count - written;
- if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
- gfs2_glock_dq(gh);
- goto retry;
- }
+ if (should_fault_in_pages(from, iocb, &prev_count, &window_size))
+ goto retry_under_glock;
out_unlock:
if (gfs2_holder_queued(gh))
gfs2_glock_dq(gh);
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread