From patchwork Thu Jun 26 19:12:58 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 4430921 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 3FB7EBEEAA for ; Thu, 26 Jun 2014 19:15:43 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4648A201BB for ; Thu, 26 Jun 2014 19:15:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3D0B42024D for ; Thu, 26 Jun 2014 19:15:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751312AbaFZTPg (ORCPT ); Thu, 26 Jun 2014 15:15:36 -0400 Received: from mail-qc0-f176.google.com ([209.85.216.176]:62787 "EHLO mail-qc0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751508AbaFZTPc (ORCPT ); Thu, 26 Jun 2014 15:15:32 -0400 Received: by mail-qc0-f176.google.com with SMTP id w7so3523533qcr.21 for ; Thu, 26 Jun 2014 12:15:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=V56suIx5rK2+CEcpHllFkxJfNgnIiFVLyd3SUWmuw3Y=; b=edkR5l0zW2NzF+MpSJ6akMiIOfe0HMdMmeT5MNJiCptkiIZEhSJLAO9RaOcpD6bQZ9 thYpBoD+dcyYXyxC8JNjooYhmh/33qyujxKfhYoD47iBYqcsnRH+qPOEvbNBmDOQeDdX 1fS9lSXxRiV0HzpQD16jUWJMY+8pU2cdsmfKZfkqyWId6CvxSTiTaSvPKuOuh6tlXN5H dYPWvQJETBeo/70aThUa/9SKSCkNqCh0ImqXUG+Ed8P2FcmMUa5xQgid5L8EYoNHTBME vHhGrRCqsKsFEdbPazBAyETQGxLWCdG3ftx9u+XZoqpyaNg6rth61J32oom/PrD+A5bp 9XPg== X-Gm-Message-State: ALoCoQnTxPLeW35mnoe8YiKZg02OkXwyILWI2/cw9zioDryP78A8B6JczP3R3nlLtPA55mj2vezF X-Received: by 10.140.48.161 with SMTP id o30mr24583814qga.68.1403810131683; Thu, 26 Jun 2014 12:15:31 -0700 (PDT) Received: from tlielax.poochiereds.net ([2001:470:8:d63:3a60:77ff:fe93:a95d]) by mx.google.com with ESMTPSA id 88sm4763039qgh.5.2014.06.26.12.15.30 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 26 Jun 2014 12:15:30 -0700 (PDT) From: Jeff Layton To: bfields@fieldses.org Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 078/117] nfsd: reduce cl_lock thrashing in release_openowner Date: Thu, 26 Jun 2014 15:12:58 -0400 Message-Id: <1403810017-16062-79-git-send-email-jlayton@primarydata.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1403810017-16062-1-git-send-email-jlayton@primarydata.com> References: <1403810017-16062-1-git-send-email-jlayton@primarydata.com> Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 Releasing an openowner is a bit inefficient as it can potentially thrash the cl_lock if you have a lot of stateids attached to it. Once we remove the client_mutex, it'll also potentially be dangerous to do this. Add some functions to make it easier to defer the part of putting a generic stateid reference that needs to be done outside the cl_lock while doing the parts that must be done while holding it under a single lock. First we unhash each open stateid. Then we call put_generic_stateid_locked which will put the reference to an nfs4_ol_stateid. If it turns out to be the last reference, it'll go ahead and remove the stid from the IDR tree and put it onto the reaplist using the st_locks list_head. Then, after dropping the lock we'll call free_stateid_reaplist to walk the list of stateids that are fully unhashed and ready to be freed, and free each of them. This function can sleep, so it must be done outside any spinlocks. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4state.c | 94 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 207120f721e3..60dc6b4921dd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -938,6 +938,30 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp) nfs4_put_stid(&stp->st_stid); } +/* + * Put the persistent reference to an already unhashed generic stateid, while + * holding the cl_lock. If it's the last reference, then put it onto the + * reaplist for later destruction. + */ +static void put_generic_stateid_locked(struct nfs4_ol_stateid *stp, + struct list_head *reaplist) +{ + struct nfs4_stid *s = &stp->st_stid; + struct nfs4_client *clp = s->sc_client; + + lockdep_assert_held(&clp->cl_lock); + + WARN_ON_ONCE(!list_empty(&stp->st_locks)); + + if (!atomic_dec_and_test(&s->sc_count)) { + wake_up_all(&close_wq); + return; + } + + remove_stid_locked(clp, s); + list_add(&stp->st_locks, reaplist); +} + static void unhash_lock_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); @@ -968,6 +992,25 @@ static void unhash_lockowner_locked(struct nfs4_lockowner *lo) list_del_init(&lo->lo_owner.so_strhash); } +/* + * Free a list of generic stateids that were collected earlier after being + * fully unhashed. + */ +static void +free_stateid_reaplist(struct list_head *reaplist) +{ + struct nfs4_ol_stateid *stp; + + might_sleep(); + + while (!list_empty(reaplist)) { + stp = list_first_entry(reaplist, struct nfs4_ol_stateid, + st_locks); + list_del(&stp->st_locks); + stp->st_stid.sc_free(&stp->st_stid); + } +} + static void release_lockowner(struct nfs4_lockowner *lo) { struct nfs4_client *clp = lo->lo_owner.so_client; @@ -982,23 +1025,10 @@ static void release_lockowner(struct nfs4_lockowner *lo) stp = list_first_entry(&lo->lo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); unhash_lock_stateid(stp); - /* - * We now know that no new references can be added to the - * stateid. If ours is the last one, finish the unhashing - * and put it on the list to be reaped. - */ - if (atomic_dec_and_test(&stp->st_stid.sc_count)) { - remove_stid_locked(clp, &stp->st_stid); - list_add(&stp->st_locks, &reaplist); - } + put_generic_stateid_locked(stp, &reaplist); } spin_unlock(&clp->cl_lock); - while (!list_empty(&reaplist)) { - stp = list_first_entry(&reaplist, struct nfs4_ol_stateid, - st_locks); - list_del(&stp->st_locks); - stp->st_stid.sc_free(&stp->st_stid); - } + free_stateid_reaplist(&reaplist); nfs4_put_stateowner(&lo->lo_owner); } @@ -1019,16 +1049,10 @@ static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp) static void unhash_open_stateid(struct nfs4_ol_stateid *stp) { - spin_lock(&stp->st_stateowner->so_client->cl_lock); + lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); + unhash_generic_stateid(stp); release_open_stateid_locks(stp); - spin_unlock(&stp->st_stateowner->so_client->cl_lock); -} - -static void release_open_stateid(struct nfs4_ol_stateid *stp) -{ - unhash_open_stateid(stp); - put_generic_stateid(stp); } static void unhash_openowner_locked(struct nfs4_openowner *oo) @@ -1052,30 +1076,24 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) } } -static void release_openowner_stateids(struct nfs4_openowner *oo) +static void release_openowner(struct nfs4_openowner *oo) { struct nfs4_ol_stateid *stp; struct nfs4_client *clp = oo->oo_owner.so_client; + struct list_head reaplist; - lockdep_assert_held(&clp->cl_lock); + INIT_LIST_HEAD(&reaplist); + spin_lock(&clp->cl_lock); + unhash_openowner_locked(oo); while (!list_empty(&oo->oo_owner.so_stateids)) { stp = list_first_entry(&oo->oo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); - spin_unlock(&clp->cl_lock); - release_open_stateid(stp); - spin_lock(&clp->cl_lock); + unhash_open_stateid(stp); + put_generic_stateid_locked(stp, &reaplist); } -} - -static void release_openowner(struct nfs4_openowner *oo) -{ - struct nfs4_client *clp = oo->oo_owner.so_client; - - spin_lock(&clp->cl_lock); - unhash_openowner_locked(oo); - release_openowner_stateids(oo); spin_unlock(&clp->cl_lock); + free_stateid_reaplist(&reaplist); release_last_closed_stateid(oo); nfs4_put_stateowner(&oo->oo_owner); } @@ -4654,7 +4672,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) struct nfs4_client *clp = s->st_stid.sc_client; s->st_stid.sc_type = NFS4_CLOSED_STID; + spin_lock(&clp->cl_lock); unhash_open_stateid(s); + spin_unlock(&clp->cl_lock); if (clp->cl_minorversion) put_generic_stateid(s);