From patchwork Fri May 13 17:42:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 9092741 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 5142BBF29F for ; Fri, 13 May 2016 17:42:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6093C20218 for ; Fri, 13 May 2016 17:42:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 383742017D for ; Fri, 13 May 2016 17:42:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753380AbcEMRmy (ORCPT ); Fri, 13 May 2016 13:42:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35068 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751573AbcEMRmy (ORCPT ); Fri, 13 May 2016 13:42:54 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0907515558; Fri, 13 May 2016 17:42:54 +0000 (UTC) Received: from nux.redhat.com (vpn1-6-107.ams2.redhat.com [10.36.6.107]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u4DHgUI3006938; Fri, 13 May 2016 13:42:51 -0400 From: Andreas Gruenbacher To: Alexander Viro , Bob Peterson , Steven Whitehouse Cc: Andreas Gruenbacher , cluster-devel@redhat.com, linux-fsdevel@vger.kernel.org Subject: [PATCH 6/7] GFS2: Use non-blocking wait in gfs2_iget Date: Fri, 13 May 2016 19:42:28 +0200 Message-Id: <1463161349-547-7-git-send-email-agruenba@redhat.com> In-Reply-To: <1463161349-547-1-git-send-email-agruenba@redhat.com> References: <1463161349-547-1-git-send-email-agruenba@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Fri, 13 May 2016 17:42:54 +0000 (UTC) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 3440219..1fa4799 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -20,6 +20,7 @@ #include #include #include +#include #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 2979a7f..2cb18bd 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -387,6 +387,7 @@ void __iget(struct inode *inode) { atomic_inc(&inode->i_count); } +EXPORT_SYMBOL(__iget); /* * get additional reference to inode; caller must already hold one.