Currently vfsub_lookup_one_len[_unlocked]() don't
set `struct path.mnt` before passing it up to VFS
in vfs_getattr(), which can hit a kernel bug/oops.

Looking at fs/, other usage of `struct path.mnt`
never checks for NULL, so it's assumed to be set,
and thus should always be set by callers.

Many other places in aufs do set/pass `mnt` right,
particularly seen w/ calls to vfsub_dentry_open(),
including another two callers of vfsub_get_attr().

This patch introduces a `struct vfsmount` to the
functions by replacing `struct dentry *parent` w/
`struct path *ppath`, which contains both *dentry
and *mnt, and passes *mnt instead of NULL for VFS.

This fixes a ~10 year old bug (checked) that is
exposed by AppArmor when accessing the provided
`path.mnt.mnt_flags` since commit (torvalds.git):
(with a public report 4 years 10 months ago [1])

        commit 02125a826459a6ad142f8d91c5b6357562f96615
        Author: Al Viro <v...@zeniv.linux.org.uk>
        Date:   Mon Dec 5 08:43:34 2011 -0500

            fix apparmor dereferencing potentially freed dentry,
        sanitize__d_path() API

And `path.mnt` is NULL at least since early 2009,
maybe longer (aufs2-standalone.git, aufs2 branch):

        commit d8a76a43eff98f77bf47650ff430e80952af5f82
        Author: J. R. Okajima <hooano...@yahoo.co.jp>
        Date:   Wed Mar 25 22:39:29 2009 +0900

            aufs2 standalone version for linux-2.6.

More details on checking the ~10 year old bug below.

Nowadays it's hit even without AppArmor in 5.15-rcN.

Traces:
===

AppArmor disabled:

    [   89.908402] BUG: kernel NULL pointer dereference, address: 
0000000000000018
    ...
    [   89.918876] CPU: 0 PID: 669 Comm: openat Not tainted 5.15.0-rc2+ #4
    [   89.921600] Hardware name: QEMU Standard PC ...
    [   89.925159] RIP: 0010:vfs_getattr_nosec+0x81/0x140
    ...
    [   89.976333] Call Trace:
    [   89.977852]  vfsub_update_h_iattr+0x92/0xa0
    [   89.980511]  vfsub_lookup_one_len+0x5e/0x70
    [   89.984948]  au_wh_test+0x1c/0x80
    [   89.986344]  au_lkup_dentry+0x192/0x520
    [   89.988310]  aufs_lookup.part.0+0x10e/0x200
    [   89.990470]  aufs_atomic_open+0x198/0x400
    [   89.992114]  ? may_create+0x133/0x140
    [   89.993037]  path_openat+0x645/0x1070
    [   89.994588]  do_filp_open+0xad/0x120
    [   89.995507]  do_sys_openat2+0x241/0x320
    [   89.996685]  do_sys_open+0x3f/0x80
    [   89.997795]  do_syscall_64+0x3b/0x90
    [   89.998985]  entry_SYSCALL_64_after_hwframe+0x44/0xae

AppArmor enabled:

    [   63.182645] BUG: kernel NULL pointer dereference, address: 
0000000000000018
    ...
    [   63.203176] CPU: 0 PID: 799 Comm: openat Not tainted 5.15.0-rc2+ #4
    [   63.206765] Hardware name: QEMU Standard PC ...
    [   63.210428] RIP: 0010:common_perm_cond+0x17/0x70
    ...
    [   63.248667] Call Trace:
    [   63.249558]  security_inode_getattr+0x2b/0x40
    [   63.251174]  vfs_getattr+0x18/0x40
    [   63.252573]  vfsub_update_h_iattr+0x92/0xa0
    [   63.253711]  ? lookup_dcache+0x38/0x60
    [   63.254613]  ? lookup_one_len+0x6b/0x90
    [   63.255545]  vfsub_lookup_one_len+0x5e/0x70
    [   63.256631]  au_wh_test+0x1c/0x80
    [   63.257459]  au_lkup_dentry+0x192/0x520
    [   63.258431]  aufs_lookup.part.0+0x10e/0x200
    [   63.259446]  aufs_atomic_open+0x198/0x400
    [   63.260371]  ? h_permission+0x5a/0xc0
    [   63.261074]  path_openat+0x645/0x1070
    [   63.261769]  do_filp_open+0xad/0x120
    [   63.262487]  do_sys_openat2+0x241/0x320
    [   63.263229]  do_sys_open+0x3f/0x80
    [   63.263835]  do_syscall_64+0x3b/0x90
    [   63.264437]  entry_SYSCALL_64_after_hwframe+0x44/0xae

Changes:
===

Unfortunately the changed functions (and callers)
are referenced in many locations in the aufs code,
so even though the core change is small, a lot of
resulting changes are required.

Thankfully it's a simple modification to replace
`struct dentry/path` in the function call and it's
usually already available (otherwise, get `mnt` w/
`au_br_mnt(au_sbr(dentry->d_sb, bindex))` as done
in other functions in aufs.

    vfsub_lookup_one_len
    - au_drinfo_do_store
    - au_drinfo_do_load
    - vfsub_lkup_one
    - - au_do_ren_after_cpup
    - - au_do_lookup
    - - au_sio_lkup_one
    - - - au_do_lookup
    - - - au_lkup_neg
    - - - au_may_del
    - - - au_wh_test
    - - - au_whtmp_lkup
    - - au_h_verify_dentry
    - - au_dr_hino
    - - au_ren_rev_rename
    - - au_ren_rev_whtmp
    - - au_do_plink_lkup
    - - do_whplink
    - - vfsub_call_lkup_one
    - - - au_sio_lkup_one
    - - au_wh_test
    - - - au_do_lookup
    - - - au_diropq_test
    - - - - au_do_lookup
    - - unlink_wh_name
    - - do_diropq
    - - au_wh_lkup
    - au_xino_create2
    vfsub_lookup_one_len_unlocked
    - au_lkup_by_ino

Reproducer:
===

- openat("test", O_CREAT)
- read-only branch with "test" file
  (apparently for vfsub_lookup_one_len() -> vfsub_update_h_iattr())
- read-write branch on fuseblk
  (for vfsub_update_h_iattr() -> vfsub_getattr())
  without the "test" file
- [optional in v5.15/required in earlier versions:
   apparmor-enabled application]

1) test app

        # cat openat.c
        #include <stdio.h>
        #include <fcntl.h>

        int main() {
                int rc;
                rc = openat(AT_FDCWD, "test", O_RDWR | O_CREAT | S_IRWXU);
                if (rc < 0) {
                        perror("openat");
                        return 1;
                }
                return 0;
        }

        # gcc -o openat openat.c

2) ntfs-3g mount (fuseblk)

        # truncate -s 1g ntfs.img
        # DEV=$(losetup -f --show ntfs.img)
        # mkfs.ntfs --fast $DEV

        # mkdir ntfs
        # mount -t ntfs-3g $DEV ntfs

        # mount | grep ntfs
        /dev/loop6 on /home/ubuntu/ntfs type fuseblk 
(rw,relatime,user_id=0,group_id=0,allow_other,blksize=4096)

3) aufs mount (with 'test' file in the read-only branch)

        # mkdir ro aufs
        # touch ro/test
        # mount -t aufs -o br=ntfs:ro none aufs

4) [optional] enable apparmor for the test app (even in complain mode for 
aa-genprof)

        # aa-genprof ./openat &
        ...
        Please start the application to be profiled in
        another window and exercise its functionality now.
        ...
        <press enter>
        [1]+  Stopped                 aa-genprof ./openat

5) remove 'test' file from read-write branch (still exists in read-only branch)

        # cd aufs
        # rm test

6) run the test app

        # ../openat
        Killed

        (See kernel error above.)

The 10 year old bug:
===

The commit that introduced AppArmor's access to `path.mnt.mnt_flags`
(dated 2011/12/05) was introduced in v3.2-rc5 (dated 2011/12/09) and
released in v3.2 (dated 2012/01/04).

    ~/git/linux$ git describe --contains 
02125a826459a6ad142f8d91c5b6357562f96615
    v3.2-rc5~37^2

The bug reproduces in a Ubuntu 12.04 Precise Pangolin VM, that runs
a 3.2-based kernel by default, with aufs support.  But for the sake
of in-depth analysis, let's go with aufs upstream sources.

Build the aufs3.2 branch from aufs3-linux.git (based on linux v3.2;
note that aufs sets `path.mnt = NULL` since 2.6), adding 3 patches
for apparmor userspace tools in apparmor 2.8.0 (kernel-patches/3.2)
from [2].

Enable aufs, fuse, apparmor, devtmpfs, and ext4; this allows 12.04
to boot w/ this kernel.  You need the initrd.img from its original
3.2 kernel for the boot process to finish (udev/scripts.)

Now follow the reproducer steps above, and the bug is hit w/ v3.2.

    [   68.628728] BUG: unable to handle kernel NULL pointer dereference at 
0000000000000061
    ...
    [   68.629648] Pid: 1807, comm: openat Not tainted 3.2.0 #4 QEMU Standard 
PC (i440FX + PIIX, 1996)
    [   68.629648] RIP: 0010:[<ffffffff81245057>]  [<ffffffff81245057>] 
aa_get_name+0x77/0x340
    ...
    [   68.629648] Call Trace:
    [   68.629648]  [<ffffffff8124a848>] aa_path_perm+0x78/0x190
    [   68.629648]  [<ffffffff811f1f37>] ? fuse_change_attributes+0x57/0xc0
    [   68.629648]  [<ffffffff811eb288>] ? 
fuse_change_entry_timeout.isra.10+0x38/0x50
    [   68.629648]  [<ffffffff8124978b>] common_perm+0x5b/0x70
    [   68.629648]  [<ffffffff812497ec>] apparmor_inode_getattr+0x4c/0x50
    [   68.629648]  [<ffffffff8122628b>] security_inode_getattr+0x1b/0x30
    [   68.629648]  [<ffffffff8111ac7a>] vfs_getattr+0x2a/0x80
    [   68.629648]  [<ffffffff811fd6a7>] vfsub_update_h_iattr+0x67/0x70
    [   68.629648]  [<ffffffff81226267>] ? security_inode_permission+0x17/0x20
    [   68.629648]  [<ffffffff8112176e>] ? lookup_one_len+0xee/0x120
    [   68.629648]  [<ffffffff810d66da>] ? get_page_from_freelist+0x30a/0x7b0
    [   68.629648]  [<ffffffff811fd92b>] vfsub_lookup_one_len+0x3b/0x50
    [   68.629648]  [<ffffffff8120477b>] au_lkup_one+0x1b/0x30
    [   68.629648]  [<ffffffff812013ef>] au_wh_test+0x1f/0xd0
    [   68.629648]  [<ffffffff8112ab47>] ? dget_parent+0x27/0x60
    [   68.629648]  [<ffffffff814f1ec8>] ? mutex_lock+0x18/0x40
    [   68.629648]  [<ffffffff81204b30>] au_lkup_dentry+0x370/0x4d0
    [   68.629648]  [<ffffffff8110f7f0>] ? __kmalloc+0xf0/0x190
    [   68.629648]  [<ffffffff8120388a>] ? au_di_alloc+0x4a/0xb0
    [   68.629648]  [<ffffffff8120c44c>] aufs_lookup+0xec/0x240
    [   68.629648]  [<ffffffff811208d0>] d_alloc_and_lookup+0x40/0x80
    [   68.629648]  [<ffffffff8112d3c0>] ? d_lookup+0x30/0x50
    [   68.629648]  [<ffffffff8112133f>] __lookup_hash.part.30+0xbf/0xe0
    [   68.629648]  [<ffffffff81226267>] ? security_inode_permission+0x17/0x20
    [   68.629648]  [<ffffffff81124568>] lookup_hash+0x48/0x60
    [   68.629648]  [<ffffffff81124d8f>] do_last+0x38f/0x910
    [   68.629648]  [<ffffffff811253dd>] path_openat+0xcd/0x3c0
    [   68.629648]  [<ffffffff810f1979>] ? handle_mm_fault+0x139/0x240
    [   68.629648]  [<ffffffff811257bd>] do_filp_open+0x3d/0xa0
    [   68.629648]  [<ffffffff81281f12>] ? __strncpy_from_user+0x22/0x60
    [   68.629648]  [<ffffffff81131307>] ? alloc_fd+0x47/0x140
    [   68.629648]  [<ffffffff81115872>] do_sys_open+0xf2/0x1d0
    [   68.629648]  [<ffffffff8111597c>] sys_openat+0xc/0x10
    [   68.629648]  [<ffffffff814fa57b>] system_call_fastpath+0x16/0x1b

[1] 
https://unix.stackexchange.com/questions/324571/docker-run-causing-kernel-panic
[2] https://launchpad.net/apparmor/2.8/2.8.0/+download/apparmor-2.8.0.tar.gz

Signed-off-by: Mauricio Faria de Oliveira <m...@canonical.com>
---
 fs/aufs/cpup.c     |  5 ++++-
 fs/aufs/dentry.c   | 36 +++++++++++++++++++++++++-----------
 fs/aufs/dentry.h   |  2 +-
 fs/aufs/dirren.c   |  6 +++---
 fs/aufs/export.c   |  2 +-
 fs/aufs/i_op_del.c |  6 +++++-
 fs/aufs/i_op_ren.c | 12 ++++++++++--
 fs/aufs/plink.c    | 12 ++++++++++--
 fs/aufs/vfsub.c    | 15 ++++++++-------
 fs/aufs/vfsub.h    | 10 +++++-----
 fs/aufs/whout.c    | 36 ++++++++++++++++++++++++++----------
 fs/aufs/whout.h    |  4 ++--
 fs/aufs/xino.c     |  6 +++++-
 13 files changed, 105 insertions(+), 47 deletions(-)

diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c
index dbaa01a55904..2a9a76335e75 100644
--- a/fs/aufs/cpup.c
+++ b/fs/aufs/cpup.c
@@ -759,11 +759,14 @@ static int au_do_ren_after_cpup(struct au_cp_generic 
*cpg, struct path *h_path)
                        h_path->dentry = dget(au_h_dptr(dentry, bdst));
                au_set_h_dptr(dentry, bdst, h_dentry);
        } else {
+               struct path h_ppath;
                err = 0;
                parent = dget_parent(dentry);
                h_parent = au_h_dptr(parent, bdst);
                dput(parent);
-               h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent);
+               h_ppath.dentry = h_parent;
+               h_ppath.mnt = au_br_mnt(au_sbr(parent->d_sb, bdst));
+               h_path->dentry = vfsub_lkup_one(&dentry->d_name, &h_ppath);
                if (IS_ERR(h_path->dentry))
                        err = PTR_ERR(h_path->dentry);
        }
diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c
index 4b63daab7220..1775ec6ac189 100644
--- a/fs/aufs/dentry.c
+++ b/fs/aufs/dentry.c
@@ -34,20 +34,24 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
 {
        struct dentry *h_dentry;
        struct inode *h_inode;
-       struct au_branch *br;
+       struct au_branch *br = au_sbr(dentry->d_sb, bindex);
        struct user_namespace *h_userns;
        int wh_found, opq;
        unsigned char wh_able;
        const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
        const unsigned char ignore_perm = !!au_ftest_lkup(args->flags,
                                                          IGNORE_PERM);
+       struct path h_path;
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(br)
+       };
 
        wh_found = 0;
-       br = au_sbr(dentry->d_sb, bindex);
        h_userns = au_br_userns(br);
        wh_able = !!au_br_whable(br->br_perm);
        if (wh_able)
-               wh_found = au_wh_test(h_userns, h_parent, &args->whname,
+               wh_found = au_wh_test(h_userns, &h_ppath, &args->whname,
                                      ignore_perm);
        h_dentry = ERR_PTR(wh_found);
        if (!wh_found)
@@ -63,9 +67,9 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
 
 real_lookup:
        if (!ignore_perm)
-               h_dentry = vfsub_lkup_one(args->name, h_parent);
+               h_dentry = vfsub_lkup_one(args->name, &h_ppath);
        else
-               h_dentry = au_sio_lkup_one(h_userns, args->name, h_parent);
+               h_dentry = au_sio_lkup_one(h_userns, args->name, &h_ppath);
        if (IS_ERR(h_dentry)) {
                if (PTR_ERR(h_dentry) == -ENAMETOOLONG
                    && !allow_neg)
@@ -99,8 +103,10 @@ real_lookup:
            || (d_really_is_positive(dentry) && !d_is_dir(dentry)))
                goto out; /* success */
 
+       h_path.dentry = h_dentry;
+       h_path.mnt = au_br_mnt(au_sbr(dentry->d_sb, bindex));
        inode_lock_shared_nested(h_inode, AuLsc_I_CHILD);
-       opq = au_diropq_test(h_userns, h_dentry);
+       opq = au_diropq_test(h_userns, &h_path);
        inode_unlock_shared(h_inode);
        if (opq > 0)
                au_set_dbdiropq(dentry, bindex);
@@ -246,18 +252,19 @@ out:
 }
 
 struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr 
*name,
-                              struct dentry *parent)
+                              struct path *ppath)
 {
+       struct dentry *parent = ppath->dentry;
        struct dentry *dentry;
        int wkq_err;
 
        if (!au_test_h_perm_sio(userns, d_inode(parent), MAY_EXEC))
-               dentry = vfsub_lkup_one(name, parent);
+               dentry = vfsub_lkup_one(name, ppath);
        else {
                struct vfsub_lkup_one_args args = {
                        .errp   = &dentry,
                        .name   = name,
-                       .parent = parent
+                       .ppath  = ppath,
                };
 
                wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args);
@@ -277,15 +284,18 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t 
bindex, int wh)
        struct dentry *parent, *h_parent, *h_dentry;
        struct au_branch *br;
        struct user_namespace *h_userns;
+       struct path h_ppath;
 
        parent = dget_parent(dentry);
        h_parent = au_h_dptr(parent, bindex);
        br = au_sbr(dentry->d_sb, bindex);
        h_userns = au_br_userns(br);
+       h_ppath.dentry = h_parent;
+       h_ppath.mnt = au_br_mnt(au_sbr(parent->d_sb, bindex));
        if (wh)
                h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
        else
-               h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
+               h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath);
        err = PTR_ERR(h_dentry);
        if (IS_ERR(h_dentry))
                goto out;
@@ -360,6 +370,10 @@ static int au_h_verify_dentry(struct dentry *h_dentry, 
struct dentry *h_parent,
        struct inode *h_inode;
        struct dentry *h_d;
        struct super_block *h_sb;
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(br)
+       };
 
        err = 0;
        memset(&ia, -1, sizeof(ia));
@@ -374,7 +388,7 @@ static int au_h_verify_dentry(struct dentry *h_dentry, 
struct dentry *h_parent,
                goto out;
 
        /* main purpose is namei.c:cached_lookup() and d_revalidate */
-       h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent);
+       h_d = vfsub_lkup_one(&h_dentry->d_name, &h_ppath);
        err = PTR_ERR(h_d);
        if (IS_ERR(h_d))
                goto out;
diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h
index a1df828fd132..26d1332d269b 100644
--- a/fs/aufs/dentry.h
+++ b/fs/aufs/dentry.h
@@ -74,7 +74,7 @@ struct au_do_lookup_args {
 extern const struct dentry_operations aufs_dop, aufs_dop_noreval;
 struct au_branch;
 struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr 
*name,
-                              struct dentry *parent);
+                              struct path *ppath);
 int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode 
*h_dir,
                struct dentry *h_parent, struct au_branch *br);
 
diff --git a/fs/aufs/dirren.c b/fs/aufs/dirren.c
index 42f590603c91..d7026bd5531b 100644
--- a/fs/aufs/dirren.c
+++ b/fs/aufs/dirren.c
@@ -263,7 +263,7 @@ static int au_dr_hino(struct super_block *sb, aufs_bindex_t 
bindex,
                dir = d_inode(path->dentry);
                inode_lock_nested(dir, AuLsc_I_CHILD);
        }
-       hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry);
+       hinopath.dentry = vfsub_lkup_one(&hinoname, path);
        err = PTR_ERR(hinopath.dentry);
        if (IS_ERR(hinopath.dentry))
                goto out_unlock;
@@ -619,7 +619,7 @@ static int au_drinfo_do_store(struct au_drinfo_store *w,
        AuDebugOn(elm
                  && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm)));
 
-       infopath.dentry = vfsub_lookup_one_len(w->whname, w->h_ppath.dentry,
+       infopath.dentry = vfsub_lookup_one_len(w->whname, &w->h_ppath,
                                               w->whnamelen);
        AuTraceErrPtr(infopath.dentry);
        if (IS_ERR(infopath.dentry)) {
@@ -1003,7 +1003,7 @@ static struct au_drinfo *au_drinfo_do_load(struct path 
*h_ppath,
        unlocked = 0;
        h_dir = d_inode(h_ppath->dentry);
        inode_lock_shared_nested(h_dir, AuLsc_I_PARENT);
-       infopath.dentry = vfsub_lookup_one_len(whname, h_ppath->dentry,
+       infopath.dentry = vfsub_lookup_one_len(whname, h_ppath,
                                               whnamelen);
        if (IS_ERR(infopath.dentry)) {
                drinfo = (void *)infopath.dentry;
diff --git a/fs/aufs/export.c b/fs/aufs/export.c
index cb4bcfc8af40..e28bceb7386a 100644
--- a/fs/aufs/export.c
+++ b/fs/aufs/export.c
@@ -406,7 +406,7 @@ static struct dentry *au_lkup_by_ino(struct path *path, 
ino_t ino,
 
        /* do not call vfsub_lkup_one() */
        dir = d_inode(parent);
-       dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen);
+       dentry = vfsub_lookup_one_len_unlocked(arg.name, path, arg.namelen);
        AuTraceErrPtr(dentry);
        if (IS_ERR(dentry))
                goto out_name;
diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c
index a11987581548..6d80a35c3c10 100644
--- a/fs/aufs/i_op_del.c
+++ b/fs/aufs/i_op_del.c
@@ -95,6 +95,10 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
        struct dentry *h_dentry, *h_latest;
        struct inode *h_inode;
        struct user_namespace *h_userns;
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(au_sbr(dentry->d_sb, bindex))
+       };
 
        h_dentry = au_h_dptr(dentry, bindex);
        if (d_really_is_positive(dentry)) {
@@ -138,7 +142,7 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
                                       MAY_EXEC | MAY_WRITE)))
                goto out;
 
-       h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
+       h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath);
        err = -EIO;
        if (IS_ERR(h_latest))
                goto out;
diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c
index 022b6e8cef11..c107e8d7f288 100644
--- a/fs/aufs/i_op_ren.c
+++ b/fs/aufs/i_op_ren.c
@@ -150,9 +150,13 @@ static void au_ren_rev_rename(int err, struct au_ren_args 
*a)
 {
        int rerr;
        struct inode *delegated;
+       struct path h_ppath = {
+               .dentry = a->src_h_parent,
+               .mnt = a->h_path.mnt
+       };
 
        a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name,
-                                         a->src_h_parent);
+                                         &h_ppath);
        rerr = PTR_ERR(a->h_path.dentry);
        if (IS_ERR(a->h_path.dentry)) {
                RevertFailure("lkup one %pd", a->src_dentry);
@@ -179,9 +183,13 @@ static void au_ren_rev_whtmp(int err, struct au_ren_args 
*a)
 {
        int rerr;
        struct inode *delegated;
+       struct path h_ppath = {
+               .dentry = a->dst_h_parent,
+               .mnt = a->h_path.mnt
+       };
 
        a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name,
-                                         a->dst_h_parent);
+                                         &h_ppath);
        rerr = PTR_ERR(a->h_path.dentry);
        if (IS_ERR(a->h_path.dentry)) {
                RevertFailure("lkup one %pd", a->dst_dentry);
diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c
index 518350041aa2..cb3a71523fb5 100644
--- a/fs/aufs/plink.c
+++ b/fs/aufs/plink.c
@@ -216,10 +216,14 @@ static struct dentry *au_do_plink_lkup(struct qstr 
*tgtname,
 {
        struct dentry *h_dentry;
        struct inode *h_inode;
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(br)
+       };
 
        h_inode = d_inode(h_parent);
        inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2);
-       h_dentry = vfsub_lkup_one(tgtname, h_parent);
+       h_dentry = vfsub_lkup_one(tgtname, &h_ppath);
        inode_unlock_shared(h_inode);
        return h_dentry;
 }
@@ -270,12 +274,16 @@ static int do_whplink(struct qstr *tgt, struct dentry 
*h_parent,
        struct path h_path = {
                .mnt = au_br_mnt(br)
        };
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(br)
+       };
        struct inode *h_dir, *delegated;
 
        h_dir = d_inode(h_parent);
        inode_lock_nested(h_dir, AuLsc_I_CHILD2);
 again:
-       h_path.dentry = vfsub_lkup_one(tgt, h_parent);
+       h_path.dentry = vfsub_lkup_one(tgt, &h_ppath);
        err = PTR_ERR(h_path.dentry);
        if (IS_ERR(h_path.dentry))
                goto out;
diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c
index 77682fba944f..dd9d3f8900fd 100644
--- a/fs/aufs/vfsub.c
+++ b/fs/aufs/vfsub.c
@@ -165,11 +165,12 @@ int vfsub_kern_path(const char *name, unsigned int flags, 
struct path *path)
        return err;
 }
 
-struct dentry *__vfsub_lookup_one_len(const char *name, struct dentry *parent,
+struct dentry *__vfsub_lookup_one_len(const char *name, struct path *ppath,
                                      int len, bool locked)
 {
+       struct dentry *parent = ppath->dentry;
        struct path path = {
-               .mnt = NULL
+               .mnt = ppath->mnt
        };
 
        if (locked) {
@@ -191,21 +192,21 @@ out:
 }
 
 struct dentry *vfsub_lookup_one_len_unlocked(const char *name,
-                                            struct dentry *parent, int len)
+                                            struct path *ppath, int len)
 {
-       return __vfsub_lookup_one_len(name, parent, len, false);
+       return __vfsub_lookup_one_len(name, ppath, len, false);
 }
 
-struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
+struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath,
                                    int len)
 {
-       return __vfsub_lookup_one_len(name, parent, len, true);
+       return __vfsub_lookup_one_len(name, ppath, len, true);
 }
 
 void vfsub_call_lkup_one(void *args)
 {
        struct vfsub_lkup_one_args *a = args;
-       *a->errp = vfsub_lkup_one(a->name, a->parent);
+       *a->errp = vfsub_lkup_one(a->name, a->ppath);
 }
 
 /* ---------------------------------------------------------------------- */
diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h
index 8e1fca0406e4..cd4390f8f392 100644
--- a/fs/aufs/vfsub.h
+++ b/fs/aufs/vfsub.h
@@ -103,20 +103,20 @@ int vfsub_atomic_open(struct inode *dir, struct dentry 
*dentry,
 int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
 
 struct dentry *vfsub_lookup_one_len_unlocked(const char *name,
-                                            struct dentry *parent, int len);
-struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
+                                            struct path *ppath, int len);
+struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath,
                                    int len);
 
 struct vfsub_lkup_one_args {
        struct dentry **errp;
        struct qstr *name;
-       struct dentry *parent;
+       struct path *ppath;
 };
 
 static inline struct dentry *vfsub_lkup_one(struct qstr *name,
-                                           struct dentry *parent)
+                                           struct path *ppath)
 {
-       return vfsub_lookup_one_len(name->name, parent, name->len);
+       return vfsub_lookup_one_len(name->name, ppath, name->len);
 }
 
 void vfsub_call_lkup_one(void *args);
diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c
index 8849e6239dd1..e54e6b707c2d 100644
--- a/fs/aufs/whout.c
+++ b/fs/aufs/whout.c
@@ -64,16 +64,17 @@ int au_wh_name_alloc(struct qstr *wh, const struct qstr 
*name)
  * test if the @wh_name exists under @h_parent.
  * @try_sio specifies the necessary of super-io.
  */
-int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
+int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath,
               struct qstr *wh_name, int try_sio)
 {
        int err;
        struct dentry *wh_dentry;
 
+
        if (!try_sio)
-               wh_dentry = vfsub_lkup_one(wh_name, h_parent);
+               wh_dentry = vfsub_lkup_one(wh_name, h_ppath);
        else
-               wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_parent);
+               wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_ppath);
        err = PTR_ERR(wh_dentry);
        if (IS_ERR(wh_dentry)) {
                if (err == -ENAMETOOLONG)
@@ -102,13 +103,13 @@ out:
 /*
  * test if the @h_dentry sets opaque or not.
  */
-int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry)
+int au_diropq_test(struct user_namespace *h_userns, struct path *h_path)
 {
        int err;
        struct inode *h_dir;
 
-       h_dir = d_inode(h_dentry);
-       err = au_wh_test(h_userns, h_dentry, &diropq_name,
+       h_dir = d_inode(h_path->dentry);
+       err = au_wh_test(h_userns, h_path, &diropq_name,
                         au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC));
        return err;
 }
@@ -127,6 +128,10 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, 
struct au_branch *br,
        static unsigned short cnt;
        struct qstr qs;
        struct user_namespace *h_userns;
+       struct path h_ppath = {
+              .dentry = h_parent,
+              .mnt = au_br_mnt(br)
+       };
 
        BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
 
@@ -154,7 +159,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, 
struct au_branch *br,
        qs.name = name;
        for (i = 0; i < 3; i++) {
                sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
-               dentry = au_sio_lkup_one(h_userns, &qs, h_parent);
+               dentry = au_sio_lkup_one(h_userns, &qs, &h_ppath);
                if (IS_ERR(dentry) || d_is_negative(dentry))
                        goto out_name;
                dput(dentry);
@@ -255,9 +260,13 @@ static int unlink_wh_name(struct dentry *h_parent, struct 
qstr *wh,
        struct path h_path = {
                .mnt = au_br_mnt(br)
        };
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(br)
+       };
 
        err = 0;
-       h_path.dentry = vfsub_lkup_one(wh, h_parent);
+       h_path.dentry = vfsub_lkup_one(wh, &h_ppath);
        if (IS_ERR(h_path.dentry))
                err = PTR_ERR(h_path.dentry);
        else {
@@ -705,12 +714,15 @@ static struct dentry *do_diropq(struct dentry *dentry, 
aufs_bindex_t bindex,
        struct dentry *opq_dentry, *h_dentry;
        struct super_block *sb;
        struct au_branch *br;
+       struct path h_path;
        int err;
 
        sb = dentry->d_sb;
        br = au_sbr(sb, bindex);
        h_dentry = au_h_dptr(dentry, bindex);
-       opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry);
+       h_path.dentry = h_dentry;
+       h_path.mnt = au_br_mnt(br);
+       opq_dentry = vfsub_lkup_one(&diropq_name, &h_path);
        if (IS_ERR(opq_dentry))
                goto out;
 
@@ -791,11 +803,15 @@ struct dentry *au_wh_lkup(struct dentry *h_parent, struct 
qstr *base_name,
        int err;
        struct qstr wh_name;
        struct dentry *wh_dentry;
+       struct path h_ppath = {
+               .dentry = h_parent,
+               .mnt = au_br_mnt(br)
+       };
 
        err = au_wh_name_alloc(&wh_name, base_name);
        wh_dentry = ERR_PTR(err);
        if (!err) {
-               wh_dentry = vfsub_lkup_one(&wh_name, h_parent);
+               wh_dentry = vfsub_lkup_one(&wh_name, &h_ppath);
                au_kfree_try_rcu(wh_name.name);
        }
        return wh_dentry;
diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h
index 08bce298f8a3..d55c4f9a9659 100644
--- a/fs/aufs/whout.h
+++ b/fs/aufs/whout.h
@@ -29,9 +29,9 @@
 
 /* whout.c */
 int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
-int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
+int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath,
               struct qstr *wh_name, int try_sio);
-int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry);
+int au_diropq_test(struct user_namespace *h_userns, struct path *h_path);
 struct au_branch;
 struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
                             struct qstr *prefix);
diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c
index b126b34206f3..7e7ba771f378 100644
--- a/fs/aufs/xino.c
+++ b/fs/aufs/xino.c
@@ -241,6 +241,10 @@ struct file *au_xino_create2(struct super_block *sb, 
struct path *base,
        struct path path;
        int err, do_unlock;
        struct au_xino_lock_dir ldir;
+       struct path ppath = {
+               .dentry = base->dentry->d_parent,
+               .mnt = base->mnt
+       };
 
        do_unlock = 1;
        au_xino_lock_dir(sb, base, &ldir);
@@ -250,7 +254,7 @@ struct file *au_xino_create2(struct super_block *sb, struct 
path *base,
        IMustLock(dir);
 
        name = &dentry->d_name;
-       path.dentry = vfsub_lookup_one_len(name->name, parent, name->len);
+       path.dentry = vfsub_lookup_one_len(name->name, &ppath, name->len);
        if (IS_ERR(path.dentry)) {
                file = (void *)path.dentry;
                pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry));
-- 
2.30.2


Reply via email to