linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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


  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).