diff mbox series

lib: tst_fd: Avoid tst_brk(TCONF, ...) on older distros

Message ID 20240124125813.6611-1-chrubis@suse.cz
State Accepted
Headers show
Series lib: tst_fd: Avoid tst_brk(TCONF, ...) on older distros | expand

Commit Message

Cyril Hrubis Jan. 24, 2024, 12:58 p.m. UTC
All the lapi/ functions does call tst_syscall() that does
tst_brk(TCONF, ...) on ENOSYS which exits the testrun prematurely on older
distributions.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
Reported-by: Martin Doucha <mdoucha@suse.cz>
---
 lib/tst_fd.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Comments

Martin Doucha Jan. 24, 2024, 1:54 p.m. UTC | #1
Hi,
Reviewed-by: Martin Doucha <mdoucha@suse.cz>

On 24. 01. 24 13:58, Cyril Hrubis wrote:
> All the lapi/ functions does call tst_syscall() that does
> tst_brk(TCONF, ...) on ENOSYS which exits the testrun prematurely on older
> distributions.
> 
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> Reported-by: Martin Doucha <mdoucha@suse.cz>
> ---
>   lib/tst_fd.c | 12 ++++++------
>   1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/tst_fd.c b/lib/tst_fd.c
> index ea84e1c85..ab7de81aa 100644
> --- a/lib/tst_fd.c
> +++ b/lib/tst_fd.c
> @@ -139,7 +139,7 @@ static void open_timerfd(struct tst_fd *fd)
>   
>   static void open_pidfd(struct tst_fd *fd)
>   {
> -	fd->fd = pidfd_open(getpid(), 0);
> +	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
>   	if (fd->fd < 0)
>   		tst_brk(TBROK | TERRNO, "pidfd_open()");
>   }
> @@ -194,7 +194,7 @@ static void open_io_uring(struct tst_fd *fd)
>   {
>   	struct io_uring_params uring_params = {};
>   
> -	fd->fd = io_uring_setup(1, &uring_params);
> +	fd->fd = syscall(__NR_io_uring_setup, 1, &uring_params);
>   	if (fd->fd < 0) {
>   		tst_res(TCONF | TERRNO,
>   			"Skipping %s", tst_fd_desc(fd));
> @@ -210,7 +210,7 @@ static void open_bpf_map(struct tst_fd *fd)
>   		.max_entries = 1,
>   	};
>   
> -	fd->fd = bpf(BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
> +	fd->fd = syscall(__NR_bpf, BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
>   	if (fd->fd < 0) {
>   		tst_res(TCONF | TERRNO,
>   			"Skipping %s", tst_fd_desc(fd));
> @@ -219,7 +219,7 @@ static void open_bpf_map(struct tst_fd *fd)
>   
>   static void open_fsopen(struct tst_fd *fd)
>   {
> -	fd->fd = fsopen("ext2", 0);
> +	fd->fd = syscall(__NR_fsopen, "ext2", 0);
>   	if (fd->fd < 0) {
>   		tst_res(TCONF | TERRNO,
>   			"Skipping %s", tst_fd_desc(fd));
> @@ -228,7 +228,7 @@ static void open_fsopen(struct tst_fd *fd)
>   
>   static void open_fspick(struct tst_fd *fd)
>   {
> -	fd->fd = fspick(AT_FDCWD, "/", 0);
> +	fd->fd = syscall(__NR_fspick, AT_FDCWD, "/", 0);
>   	if (fd->fd < 0) {
>   		tst_res(TCONF | TERRNO,
>   			"Skipping %s", tst_fd_desc(fd));
> @@ -237,7 +237,7 @@ static void open_fspick(struct tst_fd *fd)
>   
>   static void open_open_tree(struct tst_fd *fd)
>   {
> -	fd->fd = open_tree(AT_FDCWD, "/", 0);
> +	fd->fd = syscall(__NR_open_tree, AT_FDCWD, "/", 0);
>   	if (fd->fd < 0) {
>   		tst_res(TCONF | TERRNO,
>   			"Skipping %s", tst_fd_desc(fd));
Petr Vorel Jan. 24, 2024, 2:10 p.m. UTC | #2
Hi Cyril,

> All the lapi/ functions does call tst_syscall() that does
> tst_brk(TCONF, ...) on ENOSYS which exits the testrun prematurely on older
> distributions.

> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> Reported-by: Martin Doucha <mdoucha@suse.cz>

Good catch, thanks!

Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr
Cyril Hrubis Jan. 24, 2024, 2:11 p.m. UTC | #3
Hi!
Pushed, thanks.
Petr Vorel Jan. 24, 2024, 2:16 p.m. UTC | #4
> All the lapi/ functions does call tst_syscall() that does
> tst_brk(TCONF, ...) on ENOSYS which exits the testrun prematurely on older
> distributions.

> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> Reported-by: Martin Doucha <mdoucha@suse.cz>
> ---
>  lib/tst_fd.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)

> diff --git a/lib/tst_fd.c b/lib/tst_fd.c
> index ea84e1c85..ab7de81aa 100644
> --- a/lib/tst_fd.c
> +++ b/lib/tst_fd.c
> @@ -139,7 +139,7 @@ static void open_timerfd(struct tst_fd *fd)

>  static void open_pidfd(struct tst_fd *fd)
>  {
> -	fd->fd = pidfd_open(getpid(), 0);
> +	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
Actually at least here tst_syscall() needs to be called or it fails on older
distros due missing ENOSYS check in raw syscall():

tst_fd.c:144: TBROK: pidfd_open(): ENOSYS (38)

Other syscall() are probably skipped due tst_brk(), but I would replace them
anyway.

Also, I wonder if we can avoid tst_brk() because it quits the test.

Kind regards,
Petr

>  	if (fd->fd < 0)
>  		tst_brk(TBROK | TERRNO, "pidfd_open()");
>  }
> @@ -194,7 +194,7 @@ static void open_io_uring(struct tst_fd *fd)
>  {
>  	struct io_uring_params uring_params = {};

> -	fd->fd = io_uring_setup(1, &uring_params);
> +	fd->fd = syscall(__NR_io_uring_setup, 1, &uring_params);
>  	if (fd->fd < 0) {
>  		tst_res(TCONF | TERRNO,
>  			"Skipping %s", tst_fd_desc(fd));
> @@ -210,7 +210,7 @@ static void open_bpf_map(struct tst_fd *fd)
>  		.max_entries = 1,
>  	};

> -	fd->fd = bpf(BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
> +	fd->fd = syscall(__NR_bpf, BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
>  	if (fd->fd < 0) {
>  		tst_res(TCONF | TERRNO,
>  			"Skipping %s", tst_fd_desc(fd));
> @@ -219,7 +219,7 @@ static void open_bpf_map(struct tst_fd *fd)

>  static void open_fsopen(struct tst_fd *fd)
>  {
> -	fd->fd = fsopen("ext2", 0);
> +	fd->fd = syscall(__NR_fsopen, "ext2", 0);
>  	if (fd->fd < 0) {
>  		tst_res(TCONF | TERRNO,
>  			"Skipping %s", tst_fd_desc(fd));
> @@ -228,7 +228,7 @@ static void open_fsopen(struct tst_fd *fd)

>  static void open_fspick(struct tst_fd *fd)
>  {
> -	fd->fd = fspick(AT_FDCWD, "/", 0);
> +	fd->fd = syscall(__NR_fspick, AT_FDCWD, "/", 0);
>  	if (fd->fd < 0) {
>  		tst_res(TCONF | TERRNO,
>  			"Skipping %s", tst_fd_desc(fd));
> @@ -237,7 +237,7 @@ static void open_fspick(struct tst_fd *fd)

>  static void open_open_tree(struct tst_fd *fd)
>  {
> -	fd->fd = open_tree(AT_FDCWD, "/", 0);
> +	fd->fd = syscall(__NR_open_tree, AT_FDCWD, "/", 0);
>  	if (fd->fd < 0) {
>  		tst_res(TCONF | TERRNO,
>  			"Skipping %s", tst_fd_desc(fd));
Cyril Hrubis Jan. 24, 2024, 2:21 p.m. UTC | #5
Hi!
> Actually at least here tst_syscall() needs to be called or it fails on older
> distros due missing ENOSYS check in raw syscall():

Ah, no we have to handle the ENOSYS ourselves as we do in the other
cases. Sorry for not realizing that.

We likely need just:

diff --git a/lib/tst_fd.c b/lib/tst_fd.c
index ab7de81aa..8b26ff8e5 100644
--- a/lib/tst_fd.c
+++ b/lib/tst_fd.c
@@ -141,7 +141,7 @@ static void open_pidfd(struct tst_fd *fd)
 {
        fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
        if (fd->fd < 0)
-               tst_brk(TBROK | TERRNO, "pidfd_open()");
+               tst_res(TCONF | TERRNO, "pidfd_open()");
 }


The tst_sycall() can't be called there at all _because_ it calls
tst_brk() itself.
Petr Vorel Jan. 24, 2024, 2:22 p.m. UTC | #6
> Hi!
> Pushed, thanks.

Report too late, fix send.

Kind regards,
Petr
Petr Vorel Jan. 24, 2024, 2:25 p.m. UTC | #7
> Hi!
> > Actually at least here tst_syscall() needs to be called or it fails on older
> > distros due missing ENOSYS check in raw syscall():

> Ah, no we have to handle the ENOSYS ourselves as we do in the other
> cases. Sorry for not realizing that.

> We likely need just:

Yes, I also realized that when I double check your commit message.

Kind regards,
Petr

> diff --git a/lib/tst_fd.c b/lib/tst_fd.c
> index ab7de81aa..8b26ff8e5 100644
> --- a/lib/tst_fd.c
> +++ b/lib/tst_fd.c
> @@ -141,7 +141,7 @@ static void open_pidfd(struct tst_fd *fd)
>  {
>         fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
>         if (fd->fd < 0)
> -               tst_brk(TBROK | TERRNO, "pidfd_open()");
> +               tst_res(TCONF | TERRNO, "pidfd_open()");
>  }


> The tst_sycall() can't be called there at all _because_ it calls
> tst_brk() itself.
Martin Doucha Jan. 24, 2024, 2:36 p.m. UTC | #8
On 24. 01. 24 15:21, Cyril Hrubis wrote:
> Hi!
>> Actually at least here tst_syscall() needs to be called or it fails on older
>> distros due missing ENOSYS check in raw syscall():
> 
> Ah, no we have to handle the ENOSYS ourselves as we do in the other
> cases. Sorry for not realizing that.
> 
> We likely need just:
> 
> diff --git a/lib/tst_fd.c b/lib/tst_fd.c
> index ab7de81aa..8b26ff8e5 100644
> --- a/lib/tst_fd.c
> +++ b/lib/tst_fd.c
> @@ -141,7 +141,7 @@ static void open_pidfd(struct tst_fd *fd)
>   {
>          fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
>          if (fd->fd < 0)
> -               tst_brk(TBROK | TERRNO, "pidfd_open()");
> +               tst_res(TCONF | TERRNO, "pidfd_open()");
>   }

Yes, this will work. I missed the TBROK because I didn't look too 
closely at the unchanged lines in the patch...
Petr Vorel Jan. 24, 2024, 2:56 p.m. UTC | #9
Hi Martin, Cyril,

> On 24. 01. 24 15:21, Cyril Hrubis wrote:
> > Hi!
> > > Actually at least here tst_syscall() needs to be called or it fails on older
> > > distros due missing ENOSYS check in raw syscall():

> > Ah, no we have to handle the ENOSYS ourselves as we do in the other
> > cases. Sorry for not realizing that.

> > We likely need just:

> > diff --git a/lib/tst_fd.c b/lib/tst_fd.c
> > index ab7de81aa..8b26ff8e5 100644
> > --- a/lib/tst_fd.c
> > +++ b/lib/tst_fd.c
> > @@ -141,7 +141,7 @@ static void open_pidfd(struct tst_fd *fd)
> >   {
> >          fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
> >          if (fd->fd < 0)
> > -               tst_brk(TBROK | TERRNO, "pidfd_open()");
> > +               tst_res(TCONF | TERRNO, "pidfd_open()");
> >   }

Actually, the solution I posted [1] works on both old (affected) kernel and new
one:

-	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
+	fd->fd = tst_syscall(__NR_pidfd_open, getpid(), 0);
 	if (fd->fd < 0)
 		tst_brk(TBROK | TERRNO, "pidfd_open()");

I guess we should merge your solution (otherwise we would need to change other
cases to be consistent), but I'm a bit confused. Is it the reason why we use
syscall() + tst_res(TCONF) instead of tst_syscall() + tst_brk(TBROK) that for
some cases it's expected to fail, thus TBROK is not accepted? Again, I was blind
when doing review.

If yes, please just go ahead and merge it.

Kind regards,
Petr

[1] https://lore.kernel.org/ltp/20240124142108.303782-1-pvorel@suse.cz/

> Yes, this will work. I missed the TBROK because I didn't look too closely at
> the unchanged lines in the patch...
Cyril Hrubis Jan. 24, 2024, 3:19 p.m. UTC | #10
Hi!
> Actually, the solution I posted [1] works on both old (affected) kernel and new
> one:
> 
> -	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
> +	fd->fd = tst_syscall(__NR_pidfd_open, getpid(), 0);
>  	if (fd->fd < 0)
>  		tst_brk(TBROK | TERRNO, "pidfd_open()");

This cannot work on kenrel that does not implement pidfd_open. That's
what the code in tst_syscall() does:

#define tst_syscall(NR, ...) ({ \
        intptr_t tst_ret; \
        if (NR == __LTP__NR_INVALID_SYSCALL) { \
                errno = ENOSYS; \
                tst_ret = -1; \
        } else { \
                tst_ret = syscall(NR, ##__VA_ARGS__); \
        } \
        if (tst_ret == -1 && errno == ENOSYS) { \
                TST_SYSCALL_BRK__(NR, #NR); \
        } \
        tst_ret; \
})

This means that either if the syscall number is undefined or if the
actuall syscall fails with ENOSYS we call tst_brk(TCONF, ...) or
tst_brkm(TCONF, ...) on old API.

> I guess we should merge your solution (otherwise we would need to change other
> cases to be consistent), but I'm a bit confused. Is it the reason why we use
> syscall() + tst_res(TCONF) instead of tst_syscall() + tst_brk(TBROK) that for
> some cases it's expected to fail, thus TBROK is not accepted? Again, I was blind
> when doing review.

The problem is that if kernel does not implement a particular syscall
the tst_syscall() calls tst_brk() which ends the tst_fd iteration in the
middle. The tst_fd iterator just loop over different types of file
descriptors, if you call tst_brk() anywhere the test ends before we
managed to finish the loop. We do not want that to happen because of
either syscall not implemented in older kernels or syscalls disabled by
CONFIG options.

That's why we have to call syscall() and do tst_res(TCONF, ...) when the
syscall had failed. The tst_fd_next() will just continue with next fd
type if we failed to produce a valid fd.
Petr Vorel Jan. 24, 2024, 3:50 p.m. UTC | #11
> Hi!
> > Actually, the solution I posted [1] works on both old (affected) kernel and new
> > one:

> > -	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
> > +	fd->fd = tst_syscall(__NR_pidfd_open, getpid(), 0);
> >  	if (fd->fd < 0)
> >  		tst_brk(TBROK | TERRNO, "pidfd_open()");

> This cannot work on kenrel that does not implement pidfd_open. That's
> what the code in tst_syscall() does:

> #define tst_syscall(NR, ...) ({ \
>         intptr_t tst_ret; \
>         if (NR == __LTP__NR_INVALID_SYSCALL) { \
>                 errno = ENOSYS; \
>                 tst_ret = -1; \
>         } else { \
>                 tst_ret = syscall(NR, ##__VA_ARGS__); \
>         } \
>         if (tst_ret == -1 && errno == ENOSYS) { \
>                 TST_SYSCALL_BRK__(NR, #NR); \
>         } \
>         tst_ret; \
> })

> This means that either if the syscall number is undefined or if the
> actuall syscall fails with ENOSYS we call tst_brk(TCONF, ...) or
> tst_brkm(TCONF, ...) on old API.

> > I guess we should merge your solution (otherwise we would need to change other
> > cases to be consistent), but I'm a bit confused. Is it the reason why we use
> > syscall() + tst_res(TCONF) instead of tst_syscall() + tst_brk(TBROK) that for
> > some cases it's expected to fail, thus TBROK is not accepted? Again, I was blind
> > when doing review.

> The problem is that if kernel does not implement a particular syscall
> the tst_syscall() calls tst_brk() which ends the tst_fd iteration in the
> middle. The tst_fd iterator just loop over different types of file
> descriptors, if you call tst_brk() anywhere the test ends before we
> managed to finish the loop. We do not want that to happen because of
> either syscall not implemented in older kernels or syscalls disabled by
> CONFIG options.

> That's why we have to call syscall() and do tst_res(TCONF, ...) when the
> syscall had failed. The tst_fd_next() will just continue with next fd
> type if we failed to produce a valid fd.

Understand, you want to keep tst_res(), that makes sense.
And it does not make sense whether the failure is due ENOSYS or due other
failure (most likely due expected error).

Kind regards,
Petr
Petr Vorel Jan. 24, 2024, 4:57 p.m. UTC | #12
Hi Cyril, Martin,

FYI merged tst_res(TCONF) fix (fixed on 2 places).

Kind regards,
Petr
diff mbox series

Patch

diff --git a/lib/tst_fd.c b/lib/tst_fd.c
index ea84e1c85..ab7de81aa 100644
--- a/lib/tst_fd.c
+++ b/lib/tst_fd.c
@@ -139,7 +139,7 @@  static void open_timerfd(struct tst_fd *fd)
 
 static void open_pidfd(struct tst_fd *fd)
 {
-	fd->fd = pidfd_open(getpid(), 0);
+	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
 	if (fd->fd < 0)
 		tst_brk(TBROK | TERRNO, "pidfd_open()");
 }
@@ -194,7 +194,7 @@  static void open_io_uring(struct tst_fd *fd)
 {
 	struct io_uring_params uring_params = {};
 
-	fd->fd = io_uring_setup(1, &uring_params);
+	fd->fd = syscall(__NR_io_uring_setup, 1, &uring_params);
 	if (fd->fd < 0) {
 		tst_res(TCONF | TERRNO,
 			"Skipping %s", tst_fd_desc(fd));
@@ -210,7 +210,7 @@  static void open_bpf_map(struct tst_fd *fd)
 		.max_entries = 1,
 	};
 
-	fd->fd = bpf(BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
+	fd->fd = syscall(__NR_bpf, BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
 	if (fd->fd < 0) {
 		tst_res(TCONF | TERRNO,
 			"Skipping %s", tst_fd_desc(fd));
@@ -219,7 +219,7 @@  static void open_bpf_map(struct tst_fd *fd)
 
 static void open_fsopen(struct tst_fd *fd)
 {
-	fd->fd = fsopen("ext2", 0);
+	fd->fd = syscall(__NR_fsopen, "ext2", 0);
 	if (fd->fd < 0) {
 		tst_res(TCONF | TERRNO,
 			"Skipping %s", tst_fd_desc(fd));
@@ -228,7 +228,7 @@  static void open_fsopen(struct tst_fd *fd)
 
 static void open_fspick(struct tst_fd *fd)
 {
-	fd->fd = fspick(AT_FDCWD, "/", 0);
+	fd->fd = syscall(__NR_fspick, AT_FDCWD, "/", 0);
 	if (fd->fd < 0) {
 		tst_res(TCONF | TERRNO,
 			"Skipping %s", tst_fd_desc(fd));
@@ -237,7 +237,7 @@  static void open_fspick(struct tst_fd *fd)
 
 static void open_open_tree(struct tst_fd *fd)
 {
-	fd->fd = open_tree(AT_FDCWD, "/", 0);
+	fd->fd = syscall(__NR_open_tree, AT_FDCWD, "/", 0);
 	if (fd->fd < 0) {
 		tst_res(TCONF | TERRNO,
 			"Skipping %s", tst_fd_desc(fd));