diff mbox series

[LTP-FAIL,02/21] fs: refactor ksys_umount

Message ID d28d2235-9b1c-0403-59ca-e57ac5d0460e@arm.com (mailing list archive)
State New, archived
Headers show
Series None | expand

Commit Message

Vikas Kumar Aug. 6, 2020, 9:43 a.m. UTC
Hi Christoph,

We have seen LTP test(utime06 and umount03) failure in Next Master with 
commit Id 41525f56e256("fs: refactor ksys_umount").
I didn't analysis root cause of problem, i am reporting this issue.

---------------------------------------------
LTP Testcase    Result    Exit Value
----------------------------------- ---------
umount03          FAIL           4
utime06             FAIL           2
--------------------------------------------

LTP utime06 Fail Log:
/dev/loop0 is mounted; will not make a filesystem here!
utime06     0  TINFO  :  Using test device LTP_DEV='/dev/loop0'
utime06     0  TINFO  :  Formatting /dev/loop0 with ext2 opts='' extra 
opts=''
utime06     1  TBROK  :  tst_mkfs.c:102: utime06.c:122: mkfs.ext2 failed 
with 1
utime06     2  TBROK  :  tst_mkfs.c:102: Remaining cases broken

LTP umount03 Fail Log:
tst_device.c:262: INFO: Using test device LTP_DEV='/dev/loop0'
tst_mkfs.c:89: INFO: Formatting /dev/loop0 with ext2 opts='' extra opts=''
mke2fs 1.44.5 (15-Dec-2018)
tst_test.c:1244: INFO: Timeout per run is 0h 05m 00s
umount03.c:35: PASS: umount() fails as expected: EPERM (1)
tst_device.c:383: INFO: umount('mntpoint') failed with EBUSY, try 1...
tst_device.c:387: INFO: Likely gvfsd-trash is probing newly mounted fs, 
kill it to speed up tests.
tst_device.c:383: INFO: umount('mntpoint') failed with EBUSY, try 2...
tst_device.c:383: INFO: umount('mntpoint') failed with EBUSY, try 3...
tst_device.c:383: INFO: umount('mntpoint') failed with EBUSY, try 48...
tst_device.c:383: INFO: umount('mntpoint') failed with EBUSY, try 49...
tst_device.c:383: INFO: umount('mntpoint') failed with EBUSY, try 50...
tst_device.c:394: WARN: Failed to umount('mntpoint') after 50 retries
tst_tmpdir.c:336: WARN: tst_rmdir: rmobj(/scratch/ltp-Lnmh7tbxY6/gx0hJU) 
failed: remove(/scratch/ltp-Lnmh7tbxY6/gx0hJU/mntpoint) failed; 
errno=16: EBUSY

Regards,

Vikas


Below Commit ID 41525f56e256 Bisected for This fail:

     commit 41525f56e2564c2feff4fb2824823900efb3a39f
     Author: Christoph Hellwig <hch@lst.de>
     Date:   Tue Jul 21 10:54:34 2020 +0200

     fs: refactor ksys_umount

     Factor out a path_umount helper that takes a struct path * instead 
of the
     actual file name.  This will allow to convert the init and devtmpfs 
code
     to properly mount based on a kernel pointer instead of relying on the
     implicit set_fs(KERNEL_DS) during early init.

     Signed-off-by: Christoph Hellwig <hch@lst.de>

---
  fs/namespace.c | 40 ++++++++++++++++++----------------------
  1 file changed, 18 insertions(+), 22 deletions(-)

Comments

Christoph Hellwig Aug. 6, 2020, 2:17 p.m. UTC | #1
Fix for umount03 below.  The other one works fine here, but from
your logs this might be a follow on if you run it after umount without
the fix.

---
From 718c12b6559c6be5fac39837b496fd1cd325a0d5 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Thu, 6 Aug 2020 16:07:10 +0200
Subject: fs: fix a struct path leak in path_umount

Make sure we also put the dentry and vfsmnt in the illegal flags
and !may_mount cases.

Fixes: 41525f56e256 ("fs: refactor ksys_umount")
Reported-by: Vikas Kumar <vikas.kumar2@arm.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/namespace.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index a7301790abb211..1180437dfab909 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1708,15 +1708,16 @@ static inline bool may_mandlock(void)
 
 int path_umount(struct path *path, int flags)
 {
-	struct mount *mnt;
+	struct mount *mnt = real_mount(path->mnt);
 	int retval;
 
+	retval = -EINVAL;
 	if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
-		return -EINVAL;
+		goto dput_and_out;
+	retval = -EPERM;
 	if (!may_mount())
-		return -EPERM;
+		goto dput_and_out;
 
-	mnt = real_mount(path->mnt);
 	retval = -EINVAL;
 	if (path->dentry != path->mnt->mnt_root)
 		goto dput_and_out;
Al Viro Aug. 6, 2020, 2:32 p.m. UTC | #2
On Thu, Aug 06, 2020 at 04:17:32PM +0200, Christoph Hellwig wrote:
> Fix for umount03 below.  The other one works fine here, but from
> your logs this might be a follow on if you run it after umount without
> the fix.

Ugh...

How about 
static int may_umount(const struct path *path, int flags)
{
        struct mount *mnt = real_mount(path->mnt);

        if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
                return -EINVAL;
        if (!may_mount())
                return -EPERM;
        if (path->dentry != path->mnt->mnt_root)
                return -EINVAL;
        if (!check_mnt(mnt))
                return -EINVAL;
        if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
                return -EINVAL;
        if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
                return -EPERM;
	return 0;
}

int path_umount(const struct path *path, int flags)
{
        struct mount *mnt = real_mount(path->mnt);
        int err;

	err = may_umount(path, flags);
	if (!err)
		err = do_umount(mnt, flags);

        /* we mustn't call path_put() as that would clear mnt_expiry_mark */
        dput(path->dentry);
        mntput_no_expire(mnt);
        return err;
}

instead?
Christoph Hellwig Aug. 6, 2020, 2:48 p.m. UTC | #3
On Thu, Aug 06, 2020 at 03:32:21PM +0100, Al Viro wrote:
> On Thu, Aug 06, 2020 at 04:17:32PM +0200, Christoph Hellwig wrote:
> > Fix for umount03 below.  The other one works fine here, but from
> > your logs this might be a follow on if you run it after umount without
> > the fix.
> 
> Ugh...
> 
> How about 
> static int may_umount(const struct path *path, int flags)

may_umount is already take.  But with can_umount this would work:

---
From e4ccb3da160831a43eeea48c68d2d43fd7cf6724 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Thu, 6 Aug 2020 16:07:10 +0200
Subject: fs: fix a struct path leak in path_umount

Make sure we also put the dentry and vfsmnt in the illegal flags
and !may_umount cases.

Fixes: 41525f56e256 ("fs: refactor ksys_umount")
Reported-by: Vikas Kumar <vikas.kumar2@arm.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/namespace.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index a7301790abb211..1c74a46367df4e 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1706,34 +1706,38 @@ static inline bool may_mandlock(void)
 }
 #endif
 
-int path_umount(struct path *path, int flags)
+static int can_umount(const struct path *path, int flags)
 {
-	struct mount *mnt;
-	int retval;
+	struct mount *mnt = real_mount(path->mnt);
 
 	if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
 		return -EINVAL;
 	if (!may_mount())
 		return -EPERM;
-
-	mnt = real_mount(path->mnt);
-	retval = -EINVAL;
 	if (path->dentry != path->mnt->mnt_root)
-		goto dput_and_out;
+		return -EINVAL;
 	if (!check_mnt(mnt))
-		goto dput_and_out;
+		return -EINVAL;
 	if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
-		goto dput_and_out;
-	retval = -EPERM;
+		return -EINVAL;
 	if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
-		goto dput_and_out;
+		return -EPERM;
+	return 0;
+}
+
+int path_umount(struct path *path, int flags)
+{
+	struct mount *mnt = real_mount(path->mnt);
+	int ret;
+
+	ret = can_umount(path, flags);
+	if (!ret)
+		ret = do_umount(mnt, flags);
 
-	retval = do_umount(mnt, flags);
-dput_and_out:
 	/* we mustn't call path_put() as that would clear mnt_expiry_mark */
 	dput(path->dentry);
 	mntput_no_expire(mnt);
-	return retval;
+	return ret;
 }
 
 static int ksys_umount(char __user *name, int flags)
diff mbox series

Patch

diff --git a/fs/namespace.c b/fs/namespace.c
index 6f8234f74bed90..43834b59eff6c3 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1706,36 +1706,19 @@  static inline bool may_mandlock(void)
  }
  #endif

-/*
- * Now umount can handle mount points as well as block devices.
- * This is important for filesystems which use unnamed block devices.
- *
- * We now support a flag for forced unmount like the other 'big iron'
- * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
- */
-
-int ksys_umount(char __user *name, int flags)
+static int path_umount(struct path *path, int flags)
  {
-    struct path path;
      struct mount *mnt;
      int retval;
-    int lookup_flags = LOOKUP_MOUNTPOINT;

      if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
          return -EINVAL;
-
      if (!may_mount())
          return -EPERM;

-    if (!(flags & UMOUNT_NOFOLLOW))
-        lookup_flags |= LOOKUP_FOLLOW;
-
-    retval = user_path_at(AT_FDCWD, name, lookup_flags, &path);
-    if (retval)
-        goto out;
-    mnt = real_mount(path.mnt);
+    mnt = real_mount(path->mnt);
      retval = -EINVAL;
-    if (path.dentry != path.mnt->mnt_root)
+    if (path->dentry != path->mnt->mnt_root)
          goto dput_and_out;
      if (!check_mnt(mnt))
          goto dput_and_out;
@@ -1748,12 +1731,25 @@  int ksys_umount(char __user *name, int flags)
      retval = do_umount(mnt, flags);
  dput_and_out:
      /* we mustn't call path_put() as that would clear mnt_expiry_mark */
-    dput(path.dentry);
+    dput(path->dentry);
      mntput_no_expire(mnt);
-out:
      return retval;
  }

+int ksys_umount(char __user *name, int flags)
+{
+    int lookup_flags = LOOKUP_MOUNTPOINT;
+    struct path path;
+    int ret;
+
+    if (!(flags & UMOUNT_NOFOLLOW))
+        lookup_flags |= LOOKUP_FOLLOW;
+    ret = user_path_at(AT_FDCWD, name, lookup_flags, &path);
+    if (ret)
+        return ret;
+    return path_umount(&path, flags);
+}
+
SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
  {