* [Cluster-devel] [PATCH 01/11] gfs2: Allow ASPACE glocks to also have an lvb
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
@ 2020-01-20 9:12 ` Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 02/11] gfs2: Don't add glocks to the LRU while still in use Andreas Gruenbacher
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:12 UTC (permalink / raw)
To: cluster-devel.redhat.com
From: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
fs/gfs2/glock.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index b7123de7c180..cabffdc126fd 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -125,12 +125,11 @@ static void gfs2_glock_dealloc(struct rcu_head *rcu)
{
struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu);
- if (gl->gl_ops->go_flags & GLOF_ASPACE) {
+ kfree(gl->gl_lksb.sb_lvbptr);
+ if (gl->gl_ops->go_flags & GLOF_ASPACE)
kmem_cache_free(gfs2_glock_aspace_cachep, gl);
- } else {
- kfree(gl->gl_lksb.sb_lvbptr);
+ else
kmem_cache_free(gfs2_glock_cachep, gl);
- }
}
void gfs2_glock_free(struct gfs2_glock *gl)
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 02/11] gfs2: Don't add glocks to the LRU while still in use
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 01/11] gfs2: Allow ASPACE glocks to also have an lvb Andreas Gruenbacher
@ 2020-01-20 9:12 ` Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 03/11] gfs2: Keep track of deletes in inode LVBs Andreas Gruenbacher
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:12 UTC (permalink / raw)
To: cluster-devel.redhat.com
Only add glocks to the LRU once they're no longer in use. They will outlive
the inode they are associated with if they are cached (not GL_NOCACHE) or if
they have some pending work attached.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 2 +-
fs/gfs2/glock.h | 1 -
fs/gfs2/super.c | 1 -
3 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index cabffdc126fd..2aa21bab8e1c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -178,7 +178,7 @@ static int demote_ok(const struct gfs2_glock *gl)
}
-void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
+static void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
{
if (!(gl->gl_ops->go_flags & GLOF_LRU))
return;
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index b8adaf80e4c5..dc23cbf6ae7a 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -238,7 +238,6 @@ extern void gfs2_glock_complete(struct gfs2_glock *gl, int ret);
extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
extern void gfs2_glock_finish_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);
extern int __init gfs2_glock_init(void);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 68cc7c291a81..2621d925812b 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1378,7 +1378,6 @@ static void gfs2_evict_inode(struct inode *inode)
gfs2_dir_hash_inval(ip);
glock_clear_object(ip->i_gl, ip);
wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE);
- gfs2_glock_add_to_lru(ip->i_gl);
gfs2_glock_put_eventually(ip->i_gl);
ip->i_gl = NULL;
if (gfs2_holder_initialized(&ip->i_iopen_gh)) {
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 03/11] gfs2: Keep track of deletes in inode LVBs
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 01/11] gfs2: Allow ASPACE glocks to also have an lvb Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 02/11] gfs2: Don't add glocks to the LRU while still in use Andreas Gruenbacher
@ 2020-01-20 9:12 ` Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 04/11] gfs2: Turn gl_delete into a delayed work Andreas Gruenbacher
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:12 UTC (permalink / raw)
To: cluster-devel.redhat.com
When deleting an inode, keep track of the generation of the deleted inode in
the inode glock Lock Value Block (LVB). When trying to delete an inode
remotely, check the last-known inode generation against the deleted inode
generation to skip duplicate remote deletes. This avoids taking the resource
group glock in order to verify the block type.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 19 +++++++++++++++++++
fs/gfs2/glock.h | 3 +++
fs/gfs2/glops.c | 2 +-
fs/gfs2/super.c | 3 +++
include/uapi/linux/gfs2_ondisk.h | 6 ++++++
5 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 2aa21bab8e1c..3a9502af895b 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -677,6 +677,25 @@ __acquires(&gl->gl_lockref.lock)
return;
}
+void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation)
+{
+ struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr;
+
+ if (ri->ri_magic == 0)
+ ri->ri_magic = cpu_to_be32(GFS2_MAGIC);
+ if (ri->ri_magic == cpu_to_be32(GFS2_MAGIC))
+ ri->ri_generation_deleted = cpu_to_be64(generation);
+}
+
+bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
+{
+ struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr;
+
+ if (ri->ri_magic != cpu_to_be32(GFS2_MAGIC))
+ return false;
+ return generation <= be64_to_cpu(ri->ri_generation_deleted);
+}
+
static void delete_work_func(struct work_struct *work)
{
struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index dc23cbf6ae7a..63d0486bdbc4 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -305,4 +305,7 @@ static inline void glock_clear_object(struct gfs2_glock *gl, void *object)
spin_unlock(&gl->gl_lockref.lock);
}
+extern void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation);
+extern bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation);
+
#endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 4ede1f18de85..4b4676fb8c3e 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -593,7 +593,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
.go_lock = inode_go_lock,
.go_dump = inode_go_dump,
.go_type = LM_TYPE_INODE,
- .go_flags = GLOF_ASPACE | GLOF_LRU,
+ .go_flags = GLOF_ASPACE | GLOF_LRU | GLOF_LVB,
};
const struct gfs2_glock_operations gfs2_rgrp_glops = {
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 2621d925812b..b108b6379fb7 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1278,6 +1278,8 @@ static void gfs2_evict_inode(struct inode *inode)
goto out;
}
+ if (gfs2_inode_already_deleted(ip->i_gl, ip->i_no_formal_ino))
+ goto out_truncate;
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
if (error)
goto out_truncate;
@@ -1331,6 +1333,7 @@ static void gfs2_evict_inode(struct inode *inode)
that subsequent inode creates don't see an old gl_object. */
glock_clear_object(ip->i_gl, ip);
error = gfs2_dinode_dealloc(ip);
+ gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino);
goto out_unlock;
out_truncate:
diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h
index 2dc10a034de1..07e508e6691b 100644
--- a/include/uapi/linux/gfs2_ondisk.h
+++ b/include/uapi/linux/gfs2_ondisk.h
@@ -171,6 +171,12 @@ struct gfs2_rindex {
#define GFS2_RGF_NOALLOC 0x00000008
#define GFS2_RGF_TRIMMED 0x00000010
+struct gfs2_inode_lvb {
+ __be32 ri_magic;
+ __be32 __pad;
+ __be64 ri_generation_deleted;
+};
+
struct gfs2_rgrp_lvb {
__be32 rl_magic;
__be32 rl_flags;
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 04/11] gfs2: Turn gl_delete into a delayed work
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (2 preceding siblings ...)
2020-01-20 9:12 ` [Cluster-devel] [PATCH 03/11] gfs2: Keep track of deletes in inode LVBs Andreas Gruenbacher
@ 2020-01-20 9:12 ` Andreas Gruenbacher
2020-01-20 9:12 ` [Cluster-devel] [PATCH 05/11] gfs2: Give up the iopen glock on contention Andreas Gruenbacher
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:12 UTC (permalink / raw)
To: cluster-devel.redhat.com
We'll want to queue a delayed work in a future patch.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 5 +++--
fs/gfs2/glops.c | 3 ++-
fs/gfs2/incore.h | 4 ++--
fs/gfs2/rgrp.c | 3 ++-
fs/gfs2/super.c | 3 ++-
5 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 3a9502af895b..e71f23ebb99b 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -698,7 +698,8 @@ bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
static void delete_work_func(struct work_struct *work)
{
- struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct gfs2_glock *gl = container_of(dwork, struct gfs2_glock, gl_delete);
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
struct inode *inode;
u64 no_addr = gl->gl_name.ln_number;
@@ -871,7 +872,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_object = NULL;
gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
- INIT_WORK(&gl->gl_delete, delete_work_func);
+ INIT_DELAYED_WORK(&gl->gl_delete, delete_work_func);
mapping = gfs2_glock2aspace(gl);
if (mapping) {
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 4b4676fb8c3e..3534878db98d 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -577,7 +577,8 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
if (gl->gl_demote_state == LM_ST_UNLOCKED &&
gl->gl_state == LM_ST_SHARED && ip) {
gl->gl_lockref.count++;
- if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
+ if (!queue_delayed_work(gfs2_delete_workqueue,
+ &gl->gl_delete, 0))
gl->gl_lockref.count--;
}
}
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 5f89c515f5bb..d7282356cbf5 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -375,8 +375,8 @@ struct gfs2_glock {
atomic_t gl_revokes;
struct delayed_work gl_work;
union {
- /* For inode and iopen glocks only */
- struct work_struct gl_delete;
+ /* For iopen glocks only */
+ struct delayed_work gl_delete;
/* For rgrp glocks only */
struct {
loff_t start;
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 2466bb44a23c..34a8fab53e5b 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -1873,7 +1873,8 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
*/
ip = gl->gl_object;
- if (ip || queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
+ if (ip || !queue_delayed_work(gfs2_delete_workqueue,
+ &gl->gl_delete, 0))
gfs2_glock_put(gl);
else
found++;
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index b108b6379fb7..1a029beaaaca 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1017,7 +1017,8 @@ static int gfs2_drop_inode(struct inode *inode)
struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
gfs2_glock_hold(gl);
- if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
+ if (!queue_delayed_work(gfs2_delete_workqueue,
+ &gl->gl_delete, 0))
gfs2_glock_queue_put(gl);
return false;
}
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 05/11] gfs2: Give up the iopen glock on contention
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (3 preceding siblings ...)
2020-01-20 9:12 ` [Cluster-devel] [PATCH 04/11] gfs2: Turn gl_delete into a delayed work Andreas Gruenbacher
@ 2020-01-20 9:12 ` Andreas Gruenbacher
2020-01-20 9:13 ` [Cluster-devel] [PATCH 06/11] gfs2: Try harder to delete inodes locally Andreas Gruenbacher
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:12 UTC (permalink / raw)
To: cluster-devel.redhat.com
When there's contention on the iopen glock, it means that the link count
of the corresponding inode has dropped to zero on a remote node and that
node is trying to delete the inode. In that case, try to evict the
inode so that the iopen glock will be released and give the remote node
some time to delete the inode itself.
When the inode is still open, the inode's reference count won't drop to
zero, and we'll keep hold of the inode and its iopen glock. The remote
node will time out its request to grab the iopen glock, and when the
inode is closed, we'll try to delete it ourself.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/gfs2/incore.h | 1 +
fs/gfs2/super.c | 7 +++++--
3 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index e71f23ebb99b..38ba77b35b50 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -696,6 +696,42 @@ bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
return generation <= be64_to_cpu(ri->ri_generation_deleted);
}
+static bool gfs2_try_evict(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip;
+ bool evicted = false;
+
+ /*
+ * 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. This will
+ * allow the remote node to go ahead and delete the inode without us
+ * having to do it, which will avoid rgrp glock thrashing.
+ *
+ * The remote node is likely still holding the corresponding inode
+ * glock, so it will run before we get to verify that the delete has
+ * happened below.
+ */
+ spin_lock(&gl->gl_lockref.lock);
+ ip = gl->gl_object;
+ if (ip && !igrab(&ip->i_inode))
+ ip = NULL;
+ spin_unlock(&gl->gl_lockref.lock);
+ if (ip) {
+ set_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
+ d_prune_aliases(&ip->i_inode);
+ iput(&ip->i_inode);
+
+ /* If the inode was evicted, gl->gl_object will now be NULL. */
+ spin_lock(&gl->gl_lockref.lock);
+ ip = gl->gl_object;
+ if (ip)
+ clear_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
+ spin_unlock(&gl->gl_lockref.lock);
+ evicted = !ip;
+ }
+ return evicted;
+}
+
static void delete_work_func(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -710,6 +746,22 @@ static void delete_work_func(struct work_struct *work)
if (test_bit(GLF_INODE_CREATING, &gl->gl_flags))
goto out;
+ if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+ /*
+ * If we can evict the inode, give the remote node trying to
+ * delete the inode some time before verifying that the delete
+ * has happened. If we cause contention on the inode glock
+ * immediately, the remote node will think that we still have
+ * the inode in use, and so it will give up waiting.
+ */
+ if (gfs2_try_evict(gl)) {
+ if (queue_delayed_work(gfs2_delete_workqueue,
+ &gl->gl_delete, 5 * HZ))
+ return;
+ goto out;
+ }
+ }
+
inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED);
if (!IS_ERR_OR_NULL(inode)) {
d_prune_aliases(inode);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index d7282356cbf5..aecdde83c22c 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -397,6 +397,7 @@ enum {
GIF_ORDERED = 4,
GIF_FREE_VFS_INODE = 5,
GIF_GLOP_PENDING = 6,
+ GIF_DEFERRED_DELETE = 7,
};
struct gfs2_inode {
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 1a029beaaaca..874949b17495 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1263,9 +1263,12 @@ static void gfs2_evict_inode(struct inode *inode)
if (test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));
gfs2_holder_mark_uninitialized(&gh);
- goto alloc_failed;
+ goto out_delete;
}
+ if (test_bit(GIF_DEFERRED_DELETE, &ip->i_flags))
+ goto out;
+
/* Deletes should never happen under memory pressure anymore. */
if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))
goto out;
@@ -1297,7 +1300,7 @@ static void gfs2_evict_inode(struct inode *inode)
if (inode->i_nlink)
goto out_truncate;
-alloc_failed:
+out_delete:
if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 06/11] gfs2: Try harder to delete inodes locally
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (4 preceding siblings ...)
2020-01-20 9:12 ` [Cluster-devel] [PATCH 05/11] gfs2: Give up the iopen glock on contention Andreas Gruenbacher
@ 2020-01-20 9:13 ` Andreas Gruenbacher
2020-01-20 9:13 ` [Cluster-devel] [PATCH 07/11] gfs2: Minor gfs2_lookup_by_inum cleanup Andreas Gruenbacher
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:13 UTC (permalink / raw)
To: cluster-devel.redhat.com
When an inode's link count drops to zero and the inode is cached on
other nodes, the current behavior of gfs2 is to immediately give up and
to rely on the other node(s) to delete the inode if there is iopen glock
contention. This leads to resource group glock bouncing and the loss of
caching. With the previous patches in place, we can fix that by not
giving up immediately.
When the inode is still open on other nodes, those nodes won't be able
to evict the inode and give up the iopen glock. In that case, our lock
conversion request will time out. The unlink system call will block for
the duration of the iopen lock conversion request. We're also holding
the inode glock in EX mode for an extended duration, so other nodes
won't be able to make progress on the inode, either.
This is worse than what we had before, but we can prevent other nodes
from getting stuck by aborting our iopen locking request if there is
contention on the inode glock, and we can also switch to performing the
delete asynchronously in that case. Those will the the subjects of
future patches.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/super.c | 53 +++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 47 insertions(+), 6 deletions(-)
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 874949b17495..d5b44290da7f 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1222,6 +1222,50 @@ static void gfs2_glock_put_eventually(struct gfs2_glock *gl)
gfs2_glock_put(gl);
}
+static bool gfs2_upgrade_iopen_glock(struct inode *inode)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_holder *gh = &ip->i_iopen_gh;
+ long timeout = 5 * HZ;
+ int error;
+
+ gh->gh_flags |= GL_NOCACHE;
+ gfs2_glock_dq_wait(gh);
+
+ /*
+ * If there are no other lock holders, we'll get the lock immediately.
+ * Otherwise, the other nodes holding the lock will be notified about
+ * our locking request. If they don't have the inode open, they'll
+ * evict the cached inode and release the lock. As a last resort,
+ * we'll eventually time out.
+ *
+ * Note that we're passing the LM_FLAG_TRY_1CB flag to the first
+ * locking request is an optimization to notify lock holders as soon as
+ * possible. Without that flag, they'd be notified implicitly by the
+ * second locking request.
+ */
+
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY | LM_FLAG_TRY_1CB | GL_NOCACHE, gh);
+ error = gfs2_glock_nq(gh);
+ if (error != GLR_TRYFAILED)
+ return !error;
+
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, GL_ASYNC | GL_NOCACHE, gh);
+ error = gfs2_glock_nq(gh);
+ if (error)
+ return false;
+
+ timeout = wait_event_interruptible_timeout(sdp->sd_async_glock_wait,
+ !test_bit(HIF_WAIT, &gh->gh_iflags),
+ timeout);
+ if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) {
+ gfs2_glock_dq(gh);
+ return false;
+ }
+ return true;
+}
+
/**
* gfs2_evict_inode - Remove an inode from cache
* @inode: The inode to evict
@@ -1303,13 +1347,10 @@ static void gfs2_evict_inode(struct inode *inode)
out_delete:
if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
- ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
- gfs2_glock_dq_wait(&ip->i_iopen_gh);
- gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE,
- &ip->i_iopen_gh);
- error = gfs2_glock_nq(&ip->i_iopen_gh);
- if (error)
+ if (!gfs2_upgrade_iopen_glock(inode)) {
+ gfs2_holder_uninit(&ip->i_iopen_gh);
goto out_truncate;
+ }
}
if (S_ISDIR(inode->i_mode) &&
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 07/11] gfs2: Minor gfs2_lookup_by_inum cleanup
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (5 preceding siblings ...)
2020-01-20 9:13 ` [Cluster-devel] [PATCH 06/11] gfs2: Try harder to delete inodes locally Andreas Gruenbacher
@ 2020-01-20 9:13 ` Andreas Gruenbacher
2020-01-20 9:13 ` [Cluster-devel] [PATCH 08/11] gfs2: Move inode generation number check into gfs2_inode_lookup Andreas Gruenbacher
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:13 UTC (permalink / raw)
To: cluster-devel.redhat.com
Use a zero no_formal_ino instead of a NULL pointer to indicate that any inode
generation number will qualify: a valid inode never has a zero no_formal_ino.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/export.c | 4 +++-
fs/gfs2/glock.c | 2 +-
fs/gfs2/inode.c | 11 +++++++++--
fs/gfs2/inode.h | 2 +-
4 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c
index 3f717285ee48..756d05779200 100644
--- a/fs/gfs2/export.c
+++ b/fs/gfs2/export.c
@@ -134,7 +134,9 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
struct gfs2_sbd *sdp = sb->s_fs_info;
struct inode *inode;
- inode = gfs2_lookup_by_inum(sdp, inum->no_addr, &inum->no_formal_ino,
+ if (!inum->no_formal_ino)
+ return ERR_PTR(-ESTALE);
+ inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino,
GFS2_BLKST_DINODE);
if (IS_ERR(inode))
return ERR_CAST(inode);
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 38ba77b35b50..58da551ecb5c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -762,7 +762,7 @@ static void delete_work_func(struct work_struct *work)
}
}
- inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED);
+ inode = gfs2_lookup_by_inum(sdp, no_addr, 0, GFS2_BLKST_UNLINKED);
if (!IS_ERR_OR_NULL(inode)) {
d_prune_aliases(inode);
iput(inode);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index dafef10b91f1..41fc23710529 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -212,8 +212,15 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
return ERR_PTR(error);
}
+/**
+ * gfs2_lookup_by_inum - look up an inode by inode number
+ * @sdp: The super block
+ * @no_addr: The inode number
+ * @no_formal_ino: The inode generation number (0 for any)
+ * @blktype: Requested block type (see gfs2_inode_lookup)
+ */
struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
- u64 *no_formal_ino, unsigned int blktype)
+ u64 no_formal_ino, unsigned int blktype)
{
struct super_block *sb = sdp->sd_vfs;
struct inode *inode;
@@ -226,7 +233,7 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
/* Two extra checks for NFS only */
if (no_formal_ino) {
error = -ESTALE;
- if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino)
+ if (GFS2_I(inode)->i_no_formal_ino != no_formal_ino)
goto fail_iput;
error = -EIO;
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 580adbf0b5e1..b52ecf4ffe63 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -92,7 +92,7 @@ extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
u64 no_addr, u64 no_formal_ino,
unsigned int blktype);
extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
- u64 *no_formal_ino,
+ u64 no_formal_ino,
unsigned int blktype);
extern int gfs2_inode_refresh(struct gfs2_inode *ip);
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 08/11] gfs2: Move inode generation number check into gfs2_inode_lookup
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (6 preceding siblings ...)
2020-01-20 9:13 ` [Cluster-devel] [PATCH 07/11] gfs2: Minor gfs2_lookup_by_inum cleanup Andreas Gruenbacher
@ 2020-01-20 9:13 ` Andreas Gruenbacher
2020-01-20 9:13 ` [Cluster-devel] [PATCH 09/11] gfs2: Check inode generation number in delete_work_func Andreas Gruenbacher
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:13 UTC (permalink / raw)
To: cluster-devel.redhat.com
Move the inode generation number check from gfs2_lookup_by_inum into
gfs2_inode_lookup: gfs2_inode_lookup may be able to decide that an inode with
the given inode generation number cannot exist without having to verify the
block type or reading the inode from disk.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/inode.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 41fc23710529..e12e694a1bbb 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -114,6 +114,10 @@ static void gfs2_set_iop(struct inode *inode)
* placeholder because it doesn't otherwise make sense), the on-disk block type
* is verified to be @blktype.
*
+ * When @no_formal_ino is non-zero, this function will return ERR_PTR(-ESTALE)
+ * if it detects that @no_formal_ino doesn't match the actual inode generation
+ * number. However, it doesn't always know unless @type is DT_UNKNOWN.
+ *
* Returns: A VFS inode, or an error
*/
@@ -158,6 +162,11 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
if (error)
goto fail_put;
+ error = -ESTALE;
+ if (no_formal_ino &&
+ gfs2_inode_already_deleted(ip->i_gl, no_formal_ino))
+ goto fail_put;
+
if (blktype != GFS2_BLKST_FREE) {
error = gfs2_check_blk_type(sdp, no_addr,
blktype);
@@ -189,9 +198,15 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
/* Lowest possible timestamp; will be overwritten in gfs2_dinode_in. */
inode->i_atime.tv_sec = 1LL << (8 * sizeof(inode->i_atime.tv_sec) - 1);
inode->i_atime.tv_nsec = 0;
+ }
+ error = -ESTALE;
+ if (no_formal_ino && ip->i_no_formal_ino &&
+ no_formal_ino != ip->i_no_formal_ino)
+ goto fail_refresh;
+
+ if (inode->i_state & I_NEW)
unlock_new_inode(inode);
- }
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
@@ -226,16 +241,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
struct inode *inode;
int error;
- inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, blktype);
+ inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, no_formal_ino,
+ blktype);
if (IS_ERR(inode))
return inode;
- /* Two extra checks for NFS only */
if (no_formal_ino) {
- error = -ESTALE;
- if (GFS2_I(inode)->i_no_formal_ino != no_formal_ino)
- goto fail_iput;
-
error = -EIO;
if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM)
goto fail_iput;
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 09/11] gfs2: Check inode generation number in delete_work_func
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (7 preceding siblings ...)
2020-01-20 9:13 ` [Cluster-devel] [PATCH 08/11] gfs2: Move inode generation number check into gfs2_inode_lookup Andreas Gruenbacher
@ 2020-01-20 9:13 ` Andreas Gruenbacher
2020-01-20 9:13 ` [Cluster-devel] [PATCH 10/11] gfs2: Wake up when setting GLF_DEMOTE Andreas Gruenbacher
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:13 UTC (permalink / raw)
To: cluster-devel.redhat.com
In delete_work_func, if the iopen glock still has an inode attached,
limit the inode lookup to that specific generation number: in the likely
case that the inode was deleted on the node on which the inode's link
count dropped to zero, we can skip verifying the on-disk block type and
reading in the inode. The same applies if another node that had the
inode open as well managed to delete the inode before us.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 4 +++-
fs/gfs2/incore.h | 5 ++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 58da551ecb5c..1f906a3281b0 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -717,6 +717,7 @@ static bool gfs2_try_evict(struct gfs2_glock *gl)
ip = NULL;
spin_unlock(&gl->gl_lockref.lock);
if (ip) {
+ gl->gl_no_formal_ino = ip->i_no_formal_ino;
set_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
d_prune_aliases(&ip->i_inode);
iput(&ip->i_inode);
@@ -762,7 +763,8 @@ static void delete_work_func(struct work_struct *work)
}
}
- inode = gfs2_lookup_by_inum(sdp, no_addr, 0, GFS2_BLKST_UNLINKED);
+ inode = gfs2_lookup_by_inum(sdp, no_addr, gl->gl_no_formal_ino,
+ GFS2_BLKST_UNLINKED);
if (!IS_ERR_OR_NULL(inode)) {
d_prune_aliases(inode);
iput(inode);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index aecdde83c22c..f7a770a12107 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -376,7 +376,10 @@ struct gfs2_glock {
struct delayed_work gl_work;
union {
/* For iopen glocks only */
- struct delayed_work gl_delete;
+ struct {
+ struct delayed_work gl_delete;
+ u64 gl_no_formal_ino;
+ };
/* For rgrp glocks only */
struct {
loff_t start;
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 10/11] gfs2: Wake up when setting GLF_DEMOTE
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (8 preceding siblings ...)
2020-01-20 9:13 ` [Cluster-devel] [PATCH 09/11] gfs2: Check inode generation number in delete_work_func Andreas Gruenbacher
@ 2020-01-20 9:13 ` Andreas Gruenbacher
2020-01-20 9:13 ` [Cluster-devel] [PATCH 11/11] gfs2: Smarter iopen glock waiting Andreas Gruenbacher
2020-01-23 12:41 ` [Cluster-devel] [PATCH 08/11] gfs2: Move inode generation number check into gfs2_inode_lookup Andreas Gruenbacher
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:13 UTC (permalink / raw)
To: cluster-devel.redhat.com
Wake up the sdp->sd_async_glock_wait wait queue when setting the GLF_DEMOTE
flag.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 1f906a3281b0..5c3dfec991f6 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -437,6 +437,15 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
gl->gl_tchange = jiffies;
}
+static void gfs2_set_demote(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+
+ set_bit(GLF_DEMOTE, &gl->gl_flags);
+ smp_mb();
+ wake_up(&sdp->sd_async_glock_wait);
+}
+
static void gfs2_demote_wake(struct gfs2_glock *gl)
{
gl->gl_demote_state = LM_ST_EXCLUSIVE;
@@ -795,7 +804,7 @@ static void glock_work_func(struct work_struct *work)
if (!delay) {
clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags);
- set_bit(GLF_DEMOTE, &gl->gl_flags);
+ gfs2_set_demote(gl);
}
}
run_queue(gl, 0);
@@ -1140,9 +1149,10 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
static void handle_callback(struct gfs2_glock *gl, unsigned int state,
unsigned long delay, bool remote)
{
- int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE;
-
- set_bit(bit, &gl->gl_flags);
+ if (delay)
+ set_bit(GLF_PENDING_DEMOTE, &gl->gl_flags);
+ else
+ gfs2_set_demote(gl);
if (gl->gl_demote_state == LM_ST_EXCLUSIVE) {
gl->gl_demote_state = state;
gl->gl_demote_time = jiffies;
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 11/11] gfs2: Smarter iopen glock waiting
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (9 preceding siblings ...)
2020-01-20 9:13 ` [Cluster-devel] [PATCH 10/11] gfs2: Wake up when setting GLF_DEMOTE Andreas Gruenbacher
@ 2020-01-20 9:13 ` Andreas Gruenbacher
2020-01-23 12:41 ` [Cluster-devel] [PATCH 08/11] gfs2: Move inode generation number check into gfs2_inode_lookup Andreas Gruenbacher
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-20 9:13 UTC (permalink / raw)
To: cluster-devel.redhat.com
When trying to upgrade the iopen glock from a shared to an exclusive lock in
gfs2_evict_inode, abort the wait when there is contention on the corresponding
inode glock: in that case, the inode must still be in active use on another
node, and we're not guaranteed to get the iopen glock in reasonable time.
To make this work even better, poke the inode glock when we notice contention
on the iopen glock and we can't evict the corresponsing inode and release the
iopen glock immediately.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glock.c | 34 ++++++++++++++++++++++++++++++++--
fs/gfs2/super.c | 11 ++++++++---
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 5c3dfec991f6..b32c800c895e 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -705,6 +705,17 @@ bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
return generation <= be64_to_cpu(ri->ri_generation_deleted);
}
+static void gfs2_glock_poke(struct gfs2_glock *gl)
+{
+ int flags = LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_ANY | GL_SKIP;
+ struct gfs2_holder gh;
+ int error;
+
+ error = gfs2_glock_nq_init(gl, LM_ST_SHARED, flags, &gh);
+ if (!error)
+ gfs2_glock_dq(&gh);
+}
+
static bool gfs2_try_evict(struct gfs2_glock *gl)
{
struct gfs2_inode *ip;
@@ -726,6 +737,8 @@ static bool gfs2_try_evict(struct gfs2_glock *gl)
ip = NULL;
spin_unlock(&gl->gl_lockref.lock);
if (ip) {
+ struct gfs2_glock *inode_gl = NULL;
+
gl->gl_no_formal_ino = ip->i_no_formal_ino;
set_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
d_prune_aliases(&ip->i_inode);
@@ -734,9 +747,16 @@ static bool gfs2_try_evict(struct gfs2_glock *gl)
/* If the inode was evicted, gl->gl_object will now be NULL. */
spin_lock(&gl->gl_lockref.lock);
ip = gl->gl_object;
- if (ip)
+ if (ip) {
+ inode_gl = ip->i_gl;
+ inode_gl->gl_lockref.count++;
clear_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
+ }
spin_unlock(&gl->gl_lockref.lock);
+ if (inode_gl) {
+ gfs2_glock_poke(inode_gl);
+ gfs2_glock_put(inode_gl);
+ }
evicted = !ip;
}
return evicted;
@@ -763,13 +783,23 @@ static void delete_work_func(struct work_struct *work)
* has happened. If we cause contention on the inode glock
* immediately, the remote node will think that we still have
* the inode in use, and so it will give up waiting.
+ *
+ * If we can't evict the inode, signal to the remote node that
+ * the inode is still in use. We'll later try to delete the
+ * inode locally in gfs2_evict_inode.
+ *
+ * FIXME: We only need to verify that the remote node has
+ * deleted the inode because nodes before this remote delete
+ * rework won't cooperate. At a later time, when we no longer
+ * care about compatibility with such nodes, we can skip this
+ * step entirely.
*/
if (gfs2_try_evict(gl)) {
if (queue_delayed_work(gfs2_delete_workqueue,
&gl->gl_delete, 5 * HZ))
return;
- goto out;
}
+ goto out;
}
inode = gfs2_lookup_by_inum(sdp, no_addr, gl->gl_no_formal_ino,
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index d5b44290da7f..942d45e85d5c 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1237,8 +1237,12 @@ static bool gfs2_upgrade_iopen_glock(struct inode *inode)
* If there are no other lock holders, we'll get the lock immediately.
* Otherwise, the other nodes holding the lock will be notified about
* our locking request. If they don't have the inode open, they'll
- * evict the cached inode and release the lock. As a last resort,
- * we'll eventually time out.
+ * evict the cached inode and release the lock. Otherwise, if they
+ * poke the inode glock, we'll take this as an indication that they
+ * still need the iopen glock and that they'll take care of deleting
+ * the inode when they're done. As a last resort, if another node
+ * keeps holding the iopen glock without showing any activity on the
+ * inode glock, we'll eventually time out.
*
* Note that we're passing the LM_FLAG_TRY_1CB flag to the first
* locking request is an optimization to notify lock holders as soon as
@@ -1257,7 +1261,8 @@ static bool gfs2_upgrade_iopen_glock(struct inode *inode)
return false;
timeout = wait_event_interruptible_timeout(sdp->sd_async_glock_wait,
- !test_bit(HIF_WAIT, &gh->gh_iflags),
+ !test_bit(HIF_WAIT, &gh->gh_iflags) ||
+ test_bit(GLF_DEMOTE, &ip->i_gl->gl_flags),
timeout);
if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) {
gfs2_glock_dq(gh);
--
2.20.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [Cluster-devel] [PATCH 08/11] gfs2: Move inode generation number check into gfs2_inode_lookup
2020-01-20 9:12 [Cluster-devel] [PATCH 00/11] gfs2: iopen glock locking scheme rework Andreas Gruenbacher
` (10 preceding siblings ...)
2020-01-20 9:13 ` [Cluster-devel] [PATCH 11/11] gfs2: Smarter iopen glock waiting Andreas Gruenbacher
@ 2020-01-23 12:41 ` Andreas Gruenbacher
11 siblings, 0 replies; 13+ messages in thread
From: Andreas Gruenbacher @ 2020-01-23 12:41 UTC (permalink / raw)
To: cluster-devel.redhat.com
As it turns out, this patch needs the following fix.
Thanks,
Andreas
diff --git b/fs/gfs2/inode.c a/fs/gfs2/inode.c
index e12e694a1bbb..9c06680c798f 100644
--- b/fs/gfs2/inode.c
+++ a/fs/gfs2/inode.c
@@ -202,8 +202,12 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
error = -ESTALE;
if (no_formal_ino && ip->i_no_formal_ino &&
- no_formal_ino != ip->i_no_formal_ino)
- goto fail_refresh;
+ no_formal_ino != ip->i_no_formal_ino) {
+ if (inode->i_state & I_NEW)
+ goto fail_refresh;
+ iput(inode);
+ return ERR_PTR(error);
+ }
if (inode->i_state & I_NEW)
unlock_new_inode(inode);
^ permalink raw reply related [flat|nested] 13+ messages in thread