From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752013AbdGGN23 (ORCPT ); Fri, 7 Jul 2017 09:28:29 -0400 Received: from mail-wr0-f172.google.com ([209.85.128.172]:35390 "EHLO mail-wr0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750984AbdGGN21 (ORCPT ); Fri, 7 Jul 2017 09:28:27 -0400 From: Gioh Kim To: viro@zeniv.linux.org.uk Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Gioh Kim Subject: [RFC] guarantee inode of alias's parent Date: Fri, 7 Jul 2017 15:28:11 +0200 Message-Id: <20170707132811.18832-1-gi-oh.kim@profitbricks.com> X-Mailer: git-send-email 2.11.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, My server with v4.4 generated panic at __d_unalias() function. It is following line. if (!mutex_trylock(&alias->d_parent->d_inode->i_mutex)) I checked panic message and found i_mutex pointer was garbage value. Call trace is like following: [] d_splice_alias+0x148/0x2a0 [] kernfs_iop_lookup+0x91/0xc0 [] lookup_real+0x18/0x60 [] __lookup_hash+0x33/0x40 [] walk_component+0x238/0x500 [] link_path_walk+0x16c/0x580 [] ? path_init+0x1f7/0x3c0 [] path_openat+0xab/0x14c0 [] do_filp_open+0x7c/0xd0 [] ? __alloc_fd+0x3a/0x170 [] do_sys_open+0x132/0x220 [] SyS_open+0x19/0x20 [] entry_SYSCALL_64_fastpath+0x12/0x6a Before __d_unalias(), the dentry and parent of the dentry are locked. But I wonder how I can assure of existence of the alias and the parent of the alias. Where is the code to lock alias and alias->d_parent? What will happend if alias->d_parent be deleted by another process? I checked kernel code of v4.10. It also does not have any lock before accessing alias->d_parent. Therefore I'm attaching a patch to show my idea, not solve a problem. This patch is based on v4.10.0 Signed-off-by: Gioh Kim --- fs/dcache.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/dcache.c b/fs/dcache.c index 95d71eda8142..f7909447849e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2899,6 +2899,7 @@ static int __d_unalias(struct inode *inode, struct mutex *m1 = NULL; struct rw_semaphore *m2 = NULL; int ret = -ESTALE; + struct dentry *alias_parent; /* If alias and dentry share a parent, then no extra locks required */ if (alias->d_parent == dentry->d_parent) @@ -2908,6 +2909,9 @@ static int __d_unalias(struct inode *inode, if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) goto out_err; m1 = &dentry->d_sb->s_vfs_rename_mutex; + alias_parent = dget_parent(alias->d_parent); + if (!alias_parent) + goto out_err; if (!inode_trylock_shared(alias->d_parent->d_inode)) goto out_err; m2 = &alias->d_parent->d_inode->i_rwsem; @@ -2919,6 +2923,7 @@ static int __d_unalias(struct inode *inode, up_read(m2); if (m1) mutex_unlock(m1); + dput(alias_parent); return ret; } -- 2.11.0