patchset: nfs_instantiate() might succeed leaving dentry negative unhashed

相关的问题: 4.19 __nfs3_proc_setacls()空指针解引用问题

[PATCH 0/3] nfs_instantiate() might succeed leaving dentry negative unhashed:

在添加提交 b0c6108ecf64 ("nfs_instantiate(): prevent multiple aliases for directory inode") 后,我的 NFS 客户端在同时对本地文件系统和通过 knfsd 导出的相同文件系统执行 Lustre 竞争测试时崩溃:

    BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
     Call Trace:
      ? iput+0x76/0x200
      ? d_splice_alias+0x307/0x3c0
      ? dput.part.31+0x96/0x110
      ? nfs_instantiate+0x45/0x160 [nfs]
      nfs3_proc_setacls+0xa/0x20 [nfsv3]
      nfs3_proc_create+0x1cc/0x230 [nfsv3]
      nfs_create+0x83/0x160 [nfs]
      path_openat+0x11aa/0x14d0
      do_filp_open+0x93/0x100
      ? __check_object_size+0xa3/0x181
      do_sys_open+0x184/0x220
      do_syscall_64+0x5b/0x1b0
      entry_SYSCALL_64_after_hwframe+0x65/0xca

   158 static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
   159         struct posix_acl *dfacl)
   160 {
161     struct nfs_server *server = NFS_SERVER(inode);

0x28 的偏移量是 struct inode 中的 i_sb,我们传递了一个空指针 (NULL inode) 给 nfs3_proc_setacls()。

在分析这个问题后,我发现 R12 中的 dentry 在 nfs_instantiate() 之后有一个空的 inode,这在我们在 nfs_fhget() 之后将其移动到别名中是合理的(见上述提交)。确实,在子节点列表中是 d_splice_alias() 之后留下的相同的正 dentry。通常来说,移动它对于调用者来说是可以的,除了 NFSv3,因为我们希望 inode 指针能够随着 dentry 回到调用栈,以便我们可以在其上设置 ACL 或在 EXCLUSIVE 的情况下设置属性。

第一个补丁将 nfs_instantiate() 拆分开来,以便我们可以有两个调用路径,原始路径——其调用者不关心哪个 dentry 最终被散列,另一个新路径返回 dentry 或别名。

第二个补丁修改了 NFSv3,使其使用后者路径,供需要引用 dentry 的调用者使用。

第三个补丁删除了对正 dentry 的测试,因为这似乎是不可能的——我找不到路径能够触发它,并且在我所有的测试中从未触发过。

1 406cd91533dcc NFS: Refactor nfs_instantiate() for dentry referencing callers

2 17fd6e457b30e NFSv3: use nfs_add_or_obtain() to create and reference inodes

3 581057c8346b9 NFS: remove unused check for negative dentry