From: Bob Peterson <rpeterso@redhat.com>
To: cluster-devel <cluster-devel@redhat.com>,
Alexander Viro <viro@zeniv.linux.org.uk>,
<linux-fsdevel@vger.kernel.org>
Subject: [GFS2 PATCH 6/7] GFS2: Use non-blocking wait in gfs2_iget
Date: Tue, 24 May 2016 14:12:38 -0500 [thread overview]
Message-ID: <1464117159-17874-7-git-send-email-rpeterso@redhat.com> (raw)
In-Reply-To: <1464117159-17874-1-git-send-email-rpeterso@redhat.com>
From: Andreas Gruenbacher <agruenba@redhat.com>
Change gfs2_iget to use non-blocking lookups internally. This will be
used to prevent glock deadlocks.
(Requires exporting __iget from fs/inode.c.)
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/inode.c | 104 ++++++++++++++++++++++++++++++++++++--------------------
fs/gfs2/inode.h | 5 +++
fs/inode.c | 1 +
3 files changed, 74 insertions(+), 36 deletions(-)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 5dff5da..d1dde39 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -20,6 +20,7 @@
#include <linux/fiemap.h>
#include <linux/security.h>
#include <asm/uaccess.h>
+#include <linux/writeback.h>
#include "gfs2.h"
#include "incore.h"
@@ -37,61 +38,92 @@
#include "super.h"
#include "glops.h"
-struct gfs2_skip_data {
+struct gfs2_match {
u64 no_addr;
- int skipped;
- int non_block;
+ struct gfs2_freeing_inode *freeing;
};
-static int iget_test(struct inode *inode, void *opaque)
+/* gfs2_match_inode - Inode matching function
+ * @inode: inode pointer
+ * @l: hash value (unused, since it may not be able to hold our no_addr)
+ * @opaque: points to a gfs2_freeing_inode structure
+ */
+static int gfs2_match_inode(struct inode *inode, unsigned long l, void *opaque)
{
- struct gfs2_inode *ip = GFS2_I(inode);
- struct gfs2_skip_data *data = opaque;
+ struct gfs2_match *match = opaque;
+ struct gfs2_freeing_inode *freeing = match->freeing;
- if (ip->i_no_addr == data->no_addr) {
- if (data->non_block &&
- inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) {
- data->skipped = 1;
- return 0;
- }
- return 1;
+ if (GFS2_I(inode)->i_no_addr != match->no_addr)
+ return 0;
+
+ spin_lock(&inode->i_lock);
+ if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
+ freeing->wq = prepare_wait_on_freeing_inode(inode,
+ &freeing->bit_wait);
+ spin_unlock(&inode->i_lock);
+ return -1;
}
- return 0;
+ __iget(inode);
+ spin_unlock(&inode->i_lock);
+ return 1;
}
-static int iget_set(struct inode *inode, void *opaque)
+static int gfs2_test_inode(struct inode *inode, void *opaque)
{
- struct gfs2_inode *ip = GFS2_I(inode);
- struct gfs2_skip_data *data = opaque;
+ struct gfs2_match *match = opaque;
- if (data->skipped)
- return -ENOENT;
- inode->i_ino = (unsigned long)(data->no_addr);
- ip->i_no_addr = data->no_addr;
- return 0;
+ return GFS2_I(inode)->i_no_addr == match->no_addr;
}
struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr)
{
- unsigned long hash = (unsigned long)no_addr;
- struct gfs2_skip_data data;
+ struct gfs2_match match = {
+ .no_addr = no_addr,
+ };
- data.no_addr = no_addr;
- data.skipped = 0;
- data.non_block = 0;
- return ilookup5(sb, hash, iget_test, &data);
+ return ilookup5(sb, no_addr, gfs2_test_inode, &match);
}
static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr,
int non_block)
{
- struct gfs2_skip_data data;
- unsigned long hash = (unsigned long)no_addr;
+ struct gfs2_freeing_inode freeing;
+ struct gfs2_match match = {
+ .no_addr = no_addr,
+ .freeing = &freeing,
+ };
+ struct inode *inode;
- data.no_addr = no_addr;
- data.skipped = 0;
- data.non_block = non_block;
- return iget5_locked(sb, hash, iget_test, iget_set, &data);
+ while (1) {
+ freeing.wq = NULL;
+ inode = find_inode_nowait(sb, no_addr,
+ gfs2_match_inode, &match);
+ if (inode) {
+ wait_on_inode(inode);
+ return inode;
+ }
+ if (freeing.wq) {
+ if (non_block) {
+ finish_wait(freeing.wq, &freeing.bit_wait.wait);
+ return ERR_PTR(-EAGAIN);
+ }
+ schedule();
+ finish_wait(freeing.wq, &freeing.bit_wait.wait);
+ continue;
+ }
+
+ inode = new_inode(sb);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ inode->i_ino = no_addr;
+ GFS2_I(inode)->i_no_addr = no_addr;
+ if (insert_inode_locked4(inode, no_addr,
+ gfs2_test_inode, &match) < 0) {
+ iput(inode);
+ continue;
+ }
+ return inode;
+ }
}
/**
@@ -146,8 +178,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
int error;
inode = gfs2_iget(sb, no_addr, non_block);
- if (!inode)
- return ERR_PTR(-ENOMEM);
+ if (IS_ERR(inode))
+ return inode;
ip = GFS2_I(inode);
if (inode->i_state & I_NEW) {
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 22c27a8..4863513 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -93,6 +93,11 @@ err:
return -EIO;
}
+struct gfs2_freeing_inode {
+ wait_queue_head_t *wq;
+ struct wait_bit_queue bit_wait;
+};
+
extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
u64 no_addr, u64 no_formal_ino,
int non_block);
diff --git a/fs/inode.c b/fs/inode.c
index e00fec4..c18ace5 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -388,6 +388,7 @@ void __iget(struct inode *inode)
{
atomic_inc(&inode->i_count);
}
+EXPORT_SYMBOL(__iget);
/*
* get additional reference to inode; caller must already hold one.
--
2.5.5
next prev parent reply other threads:[~2016-05-24 19:12 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-05-24 19:12 [GFS2 PATCH 0/7] Fix glock deadlocks with deleted inodes Bob Peterson
2016-05-24 19:12 ` [GFS2 PATCH 1/7] Revert "GFS2: Eliminate parameter non_block on gfs2_inode_lookup" Bob Peterson
2016-05-24 19:12 ` [GFS2 PATCH 2/7] Revert "GFS2: Don't filter out I_FREEING inodes anymore" Bob Peterson
2016-05-24 19:12 ` [GFS2 PATCH 3/7] GFS2: Remove superfluous assignment Bob Peterson
2016-05-24 19:12 ` [GFS2 PATCH 4/7] GFS2: No need for non-blocking gfs2_ilookup in delete_work_func Bob Peterson
2016-05-24 19:12 ` [GFS2 PATCH 5/7] vfs: Introduce prepare_wait_on_freeing_inode Bob Peterson
2016-05-24 19:12 ` Bob Peterson [this message]
2016-05-24 19:12 ` [GFS2 PATCH 7/7] GFS2: Prevent deadlock in gfs2_lookup_by_inum Bob Peterson
2016-05-24 21:58 ` [Cluster-devel] [GFS2 PATCH 0/7] Fix glock deadlocks with deleted inodes Andreas Gruenbacher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1464117159-17874-7-git-send-email-rpeterso@redhat.com \
--to=rpeterso@redhat.com \
--cc=cluster-devel@redhat.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).