From patchwork Tue Apr 28 16:10:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kinglong Mee X-Patchwork-Id: 6290991 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id EC524BEEE1 for ; Tue, 28 Apr 2015 16:10:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CB67920220 for ; Tue, 28 Apr 2015 16:10:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 961062021F for ; Tue, 28 Apr 2015 16:10:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965959AbbD1QKW (ORCPT ); Tue, 28 Apr 2015 12:10:22 -0400 Received: from mail-pa0-f66.google.com ([209.85.220.66]:35303 "EHLO mail-pa0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965836AbbD1QKV (ORCPT ); Tue, 28 Apr 2015 12:10:21 -0400 Received: by pabli10 with SMTP id li10so45888593pab.2 for ; Tue, 28 Apr 2015 09:10:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :content-type:content-transfer-encoding; bh=hcpDSO+ZtDTxHSd3vcWIi1tq7ccCRAvd/FtUts6VPaI=; b=WPLEK5ulA2QnFatxaJKhUFvQBYayurMxRHWeVA21WTL5mwI+sOw+HkVMjHgZUP72gO 0bu7ru6NecvJ3EDCBNAUEYO9NetYeBrFARq2c6nShoa32O4AeMNga2XIkNyeA3WpIgC1 sHx56zgkaHNQnmNqkBeyzCoE3qSMMSmLiJoIeIXoL+BnhRox2eDAQtP8/OGCIKwkyU/L +iI9Rpuk/UAQYvshJTFVIoQeHwndxhicJivXRlNcDNN8ALSNPxLXcm0BkWjEERy0NVzG 5Hb/zBL5/wj9Z3H/tng7HCAH7zTMIIPl1DLazH76N4upBCfxBrcnKC/IlYPWSxTLl+Sb 7baQ== X-Received: by 10.70.35.36 with SMTP id e4mr33744578pdj.56.1430237420789; Tue, 28 Apr 2015 09:10:20 -0700 (PDT) Received: from [192.168.99.5] ([104.143.41.79]) by mx.google.com with ESMTPSA id f1sm22890785pds.62.2015.04.28.09.10.17 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 28 Apr 2015 09:10:19 -0700 (PDT) Message-ID: <553FB0E7.7070601@gmail.com> Date: Wed, 29 Apr 2015 00:10:15 +0800 From: Kinglong Mee User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 MIME-Version: 1.0 To: "J. Bruce Fields" CC: "linux-nfs@vger.kernel.org" , Steve Dickson , kinglongmee@gmail.com Subject: [PATCH] NFSD: Avoid race of locking parent's mutex at cross mount 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.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, 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 When testing pseudo root, there is a mutex race between nfsd and rpc.mountd for locking parent inode. nfs-utils commit 6091c0a4c4 ("mountd: add support for case-insensitive file names") adds using name_to_handle_at which will locking parent. Apr 27 19:57:03 ntest kernel: rpc.mountd D ffff88006ac5fc28 0 1152 1 0x00000000 Apr 27 19:57:03 ntest kernel: ffff88006ac5fc28 ffff880068c38970 ffff880068c3de60 ffff88006ac5fc08 Apr 27 19:57:03 ntest kernel: ffff88006ac60000 ffff880035ecf694 ffff880068c3de60 00000000ffffffff Apr 27 19:57:03 ntest kernel: ffff880035ecf698 ffff88006ac5fc48 ffffffff8177ffd7 0000000000000000 Apr 27 19:57:03 ntest kernel: Call Trace: Apr 27 19:57:03 ntest kernel: [] schedule+0x37/0x90 Apr 27 19:57:03 ntest kernel: [] schedule_preempt_disabled+0xe/0x10 Apr 27 19:57:03 ntest kernel: [] __mutex_lock_slowpath+0xb2/0x120 Apr 27 19:57:03 ntest kernel: [] mutex_lock+0x23/0x40 Apr 27 19:57:03 ntest kernel: [] lookup_slow+0x34/0xc0 Apr 27 19:57:03 ntest kernel: [] path_lookupat+0x89e/0xc60 Apr 27 19:57:03 ntest kernel: [] ? kmem_cache_alloc+0x1e2/0x260 Apr 27 19:57:03 ntest kernel: [] ? getname_flags+0x56/0x200 Apr 27 19:57:03 ntest kernel: [] filename_lookup+0x27/0xc0 Apr 27 19:57:03 ntest kernel: [] user_path_at_empty+0x63/0xd0 Apr 27 19:57:03 ntest kernel: [] ? put_object+0x32/0x60 Apr 27 19:57:03 ntest kernel: [] ? delete_object_full+0x2d/0x40 Apr 27 19:57:03 ntest kernel: [] ? dput+0x33/0x230 Apr 27 19:57:03 ntest kernel: [] user_path_at+0x11/0x20 Apr 27 19:57:03 ntest kernel: [] SyS_name_to_handle_at+0x59/0x200 Apr 27 19:57:03 ntest kernel: [] system_call_fastpath+0x12/0x71 Apr 27 19:57:03 ntest kernel: nfsd S ffff88006e92b708 0 1170 2 0x00000000 Apr 27 19:57:03 ntest kernel: ffff88006e92b708 ffffffff81c12480 ffff88006acbcb80 ffff88006e92b758 Apr 27 19:57:03 ntest kernel: ffff88006e92c000 ffffffff82290040 ffff88006e92b758 ffffffff82290040 Apr 27 19:57:03 ntest kernel: 00000000fffffff5 ffff88006e92b728 ffffffff8177ffd7 0000000100043a09 Apr 27 19:57:03 ntest kernel: Call Trace: Apr 27 19:57:03 ntest kernel: [] schedule+0x37/0x90 Apr 27 19:57:03 ntest kernel: [] schedule_timeout+0x117/0x230 Apr 27 19:57:03 ntest kernel: [] ? internal_add_timer+0xb0/0xb0 Apr 27 19:57:03 ntest kernel: [] wait_for_completion_interruptible_timeout+0xf3/0x150 Apr 27 19:57:03 ntest kernel: [] ? wake_up_state+0x20/0x20 Apr 27 19:57:03 ntest kernel: [] cache_wait_req.isra.10+0x9c/0x110 [sunrpc] Apr 27 19:57:03 ntest kernel: [] ? sunrpc_init_cache_detail+0xc0/0xc0 [sunrpc] Apr 27 19:57:03 ntest kernel: [] cache_check+0x1d4/0x380 [sunrpc] Apr 27 19:57:03 ntest kernel: [] ? inode_doinit_with_dentry+0x48c/0x6a0 Apr 27 19:57:03 ntest kernel: [] exp_get_by_name+0x82/0xb0 [nfsd] Apr 27 19:57:03 ntest kernel: [] ? kmemleak_free+0x3a/0xa0 Apr 27 19:57:03 ntest kernel: [] ? inode_doinit_with_dentry+0x210/0x6a0 Apr 27 19:57:03 ntest kernel: [] ? selinux_d_instantiate+0x1c/0x20 Apr 27 19:57:03 ntest kernel: [] ? _d_rehash+0x37/0x40 Apr 27 19:57:03 ntest kernel: [] ? d_splice_alias+0xa6/0x2d0 Apr 27 19:57:03 ntest kernel: [] ? ext4_lookup+0xdb/0x160 Apr 27 19:57:03 ntest kernel: [] rqst_exp_get_by_name+0x64/0x140 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd_cross_mnt+0x76/0x1b0 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd4_encode_dirent+0x160/0x3d0 [nfsd] Apr 27 19:57:03 ntest kernel: [] ? nfsd4_encode_getattr+0x40/0x40 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd_readdir+0x1c1/0x2a0 [nfsd] Apr 27 19:57:03 ntest kernel: [] ? nfsd_direct_splice_actor+0x20/0x20 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd4_encode_readdir+0x120/0x220 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd4_encode_operation+0x7d/0x190 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd4_proc_compound+0x24d/0x6f0 [nfsd] Apr 27 19:57:03 ntest kernel: [] nfsd_dispatch+0xc3/0x220 [nfsd] Apr 27 19:57:03 ntest kernel: [] svc_process_common+0x43b/0x690 [sunrpc] Apr 27 19:57:03 ntest kernel: [] svc_process+0x103/0x1b0 [sunrpc] Apr 27 19:57:03 ntest kernel: [] nfsd+0xff/0x170 [nfsd] Apr 27 19:57:03 ntest kernel: [] ? nfsd_destroy+0x80/0x80 [nfsd] Apr 27 19:57:03 ntest kernel: [] kthread+0xd8/0xf0 Apr 27 19:57:03 ntest kernel: [] ? kthread_worker_fn+0x180/0x180 Apr 27 19:57:03 ntest kernel: [] ret_from_fork+0x42/0x70 Apr 27 19:57:03 ntest kernel: [] ? kthread_worker_fn+0x180/0x180 Signed-off-by: Kinglong Mee --- fs/nfsd/nfs4xdr.c | 12 +++++++----- fs/nfsd/vfs.c | 5 ++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 158badf..b1aa934 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2800,11 +2800,11 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, const char *name, int namlen) { struct svc_export *exp = cd->rd_fhp->fh_export; - struct dentry *dentry; + struct dentry *dentry, *parent = cd->rd_fhp->fh_dentry; __be32 nfserr; int ignore_crossmnt = 0; - dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); + dentry = lookup_one_len(name, parent, namlen); if (IS_ERR(dentry)) return nfserrno(PTR_ERR(dentry)); if (d_really_is_negative(dentry)) { @@ -2826,7 +2826,7 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, * directly from the mountpoint dentry. */ if (nfsd_mountpoint(dentry, exp)) { - int err; + int err, lock_err; if (!(exp->ex_flags & NFSEXP_V4ROOT) && !attributes_need_mount(cd->rd_bmval)) { @@ -2838,9 +2838,11 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, * Different "."/".." handling? Something else? * At least, add a comment here to explain.... */ + mutex_unlock(&d_inode(parent)->i_mutex); err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); - if (err) { - nfserr = nfserrno(err); + lock_err = mutex_lock_killable(&d_inode(parent)->i_mutex); + if (err || lock_err) { + nfserr = nfserrno(err ? err : lock_err); goto out_put; } nfserr = check_nfsd_access(exp, cd->rd_rqstp); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 84d770b..44420e4 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -221,7 +221,10 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, * check if we have crossed a mount point ... */ if (nfsd_mountpoint(dentry, exp)) { - if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { + mutex_unlock(&d_inode(dparent)->i_mutex); + host_err = nfsd_cross_mnt(rqstp, &dentry, &exp); + mutex_lock_nested(&d_inode(dparent)->i_mutex, I_MUTEX_PARENT); + if (host_err) { dput(dentry); goto out_nfserr; }