From patchwork Mon Sep 12 01:40:17 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Kent X-Patchwork-Id: 9325637 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9EA0A607D3 for ; Mon, 12 Sep 2016 01:41:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 96E9E28B8A for ; Mon, 12 Sep 2016 01:41:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8B3D428B8B; Mon, 12 Sep 2016 01:41:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0F9ED28B8C for ; Mon, 12 Sep 2016 01:41:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756241AbcILBki (ORCPT ); Sun, 11 Sep 2016 21:40:38 -0400 Received: from out4-smtp.messagingengine.com ([66.111.4.28]:59707 "EHLO out4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756080AbcILBkg (ORCPT ); Sun, 11 Sep 2016 21:40:36 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 96DF720673; Sun, 11 Sep 2016 21:40:20 -0400 (EDT) Received: from frontend1 ([10.202.2.160]) by compute7.internal (MEProxy); Sun, 11 Sep 2016 21:40:20 -0400 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=themaw.net; h=cc :content-transfer-encoding:content-type:date:from:message-id :mime-version:subject:to:x-sasl-enc:x-sasl-enc; s=mesmtp; bh=5td 2PKH0kTKn9g2SKYhZH3KJQDY=; b=e/iNhyKoihJCyai1hSw2Jt1Mcvwwaz8GMR0 st9S/nOqLSF4vKgKsUgUjT3EldqOOC9IPgUXv4WA+RQNFVzZVOYKPKeNIlotVkxF pFU21NN08dSioBpgMICilpUH8fjQLJCXHIgeRkUlb1xnQXFMIf8Ynlez1gO+4bUf 0LSGrSGs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:message-id:mime-version:subject:to:x-sasl-enc :x-sasl-enc; s=smtpout; bh=5td2PKH0kTKn9g2SKYhZH3KJQDY=; b=bq6cp dFtIyKbK84tgF0mcAJihbxD4gJ72+2vvoUbMe16Z+JMhP65DKL5p0AbN4+0OhPW8 pZF7kdr6b2a3cylwgqiJBjGfBN7Fpzil7p9FVCVFqXe4uyiD1D6GGfKDLVXx4K5L K6mFW1y0qyC92b1+AqJmN59LIjyxEOsnSSTC3I= X-Sasl-enc: YWK2Wvnayk7p1f7OBmSqLuuzRyKwJ7tS2G71RMFB4BpB 1473644420 Received: from pluto.themaw.net (106-69-253-208.dyn.iinet.net.au [106.69.253.208]) by mail.messagingengine.com (Postfix) with ESMTPA id 0BF52F29CF; Sun, 11 Sep 2016 21:40:20 -0400 (EDT) Received: from pluto.themaw.net (localhost [127.0.0.1]) by pluto.themaw.net (Postfix) with ESMTP id 92EE6A0061; Mon, 12 Sep 2016 09:40:17 +0800 (AWST) Subject: [PATCH] autofs - use dentry flags to block walks during expire From: Ian Kent To: Al Viro Cc: Takashi Iwai , autofs mailing list , NeilBrown , Kernel Mailing List , linux-fsdevel , Andrew Morton Date: Mon, 12 Sep 2016 09:40:17 +0800 Message-ID: <20160912014017.1773.73060.stgit@pluto.themaw.net> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Somewhere along the way the autofs expire operation has changed to hold a spin lock over expired dentry selection. The autofs indirect mount expired dentry selection is complicated and quite lengthy so it isn't appropriate to hold a spin lock over the operation. Commit 47be6184 added a might_sleep() to dput() causing a BUG() about this usage to be issued. But the spin lock doesn't need to be held over this check, the autofs dentry info. flags are enough to block walks into dentrys during the expire. I've left the direct mount expire as it is (for now) becuase it is much simpler and quicker than the indirect mount expire and adding spin lock release and re-aquires would do nothing more than add overhead. Fixes: 47be61845c77 ("fs/dcache.c: avoid soft-lockup in dput()") Signed-off-by: Ian Kent Cc: Takashi Iwai Cc: Andrew Morton Cc: NeilBrown --- fs/autofs4/expire.c | 55 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index b493909..d8e6d42 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -417,6 +417,7 @@ static struct dentry *should_expire(struct dentry *dentry, } return NULL; } + /* * Find an eligible tree to time-out * A tree is eligible if :- @@ -432,6 +433,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, struct dentry *root = sb->s_root; struct dentry *dentry; struct dentry *expired; + struct dentry *found; struct autofs_info *ino; if (!root) @@ -442,31 +444,46 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, dentry = NULL; while ((dentry = get_next_positive_subdir(dentry, root))) { + int flags = how; + spin_lock(&sbi->fs_lock); ino = autofs4_dentry_ino(dentry); - if (ino->flags & AUTOFS_INF_WANT_EXPIRE) - expired = NULL; - else - expired = should_expire(dentry, mnt, timeout, how); - if (!expired) { + if (ino->flags & AUTOFS_INF_WANT_EXPIRE) { spin_unlock(&sbi->fs_lock); continue; } + spin_unlock(&sbi->fs_lock); + + expired = should_expire(dentry, mnt, timeout, flags); + if (!expired) + continue; + + spin_lock(&sbi->fs_lock); ino = autofs4_dentry_ino(expired); ino->flags |= AUTOFS_INF_WANT_EXPIRE; spin_unlock(&sbi->fs_lock); synchronize_rcu(); - spin_lock(&sbi->fs_lock); - if (should_expire(expired, mnt, timeout, how)) { - if (expired != dentry) - dput(dentry); - goto found; - } + /* Make sure a reference is not taken on found if + * things have changed. + */ + flags &= ~AUTOFS_EXP_LEAVES; + found = should_expire(expired, mnt, timeout, how); + if (!found || found != expired) + /* Something has changed, continue */ + goto next; + + if (expired != dentry) + dput(dentry); + + spin_lock(&sbi->fs_lock); + goto found; +next: + spin_lock(&sbi->fs_lock); ino->flags &= ~AUTOFS_INF_WANT_EXPIRE; + spin_unlock(&sbi->fs_lock); if (expired != dentry) dput(expired); - spin_unlock(&sbi->fs_lock); } return NULL; @@ -483,6 +500,7 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk) struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); int status; + int state; /* Block on any pending expire */ if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE)) @@ -490,8 +508,19 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk) if (rcu_walk) return -ECHILD; +retry: spin_lock(&sbi->fs_lock); - if (ino->flags & AUTOFS_INF_EXPIRING) { + state = ino->flags & (AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING); + if (state == AUTOFS_INF_WANT_EXPIRE) { + spin_unlock(&sbi->fs_lock); + /* + * Possibly being selected for expire, wait until + * it's selected or not. + */ + schedule_timeout_uninterruptible(HZ/10); + goto retry; + } + if (state & AUTOFS_INF_EXPIRING) { spin_unlock(&sbi->fs_lock); pr_debug("waiting for expire %p name=%pd\n", dentry, dentry);