diff mbox series

[v3,1/3] tools/nolibc: fix up #error compile failures with -ENOSYS

Message ID f2776eb566b8cf2409d2c21f83ebf85ab92d2f09.1685780412.git.falcon@tinylab.org (mailing list archive)
State Accepted
Commit ca50df3098939578d577477a9464a46a2e9fea66
Headers show
Series nolibc: add part2 of support for rv32 | expand

Commit Message

Zhangjin Wu June 3, 2023, 9:01 a.m. UTC
Compiling nolibc for rv32 got such errors:

    In file included from nolibc/sysroot/riscv/include/nolibc.h:99,
                     from nolibc/sysroot/riscv/include/errno.h:26,
                     from nolibc/sysroot/riscv/include/stdio.h:14,
                     from tools/testing/selftests/nolibc/nolibc-test.c:12:
    nolibc/sysroot/riscv/include/sys.h:946:2: error: #error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll()
      946 | #error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll()
          |  ^~~~~
    nolibc/sysroot/riscv/include/sys.h:1062:2: error: #error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select()
     1062 | #error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select()

If a syscall is not supported by a target platform, 'return -ENOSYS' is
better than '#error', which lets the other syscalls work as-is and
allows developers to fix up the test failures reported by nolibc-test
one by one later.

This converts all of the '#error' to 'return -ENOSYS', so, all of the
'#error' failures are fixed.

Suggested-by: Arnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/linux-riscv/5e7d2adf-e96f-41ca-a4c6-5c87a25d4c9c@app.fastmail.com/
Signed-off-by: Zhangjin Wu <falcon@tinylab.org>
---
 tools/include/nolibc/sys.h | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

Comments

Arnd Bergmann June 6, 2023, 7:35 a.m. UTC | #1
On Sat, Jun 3, 2023, at 11:01, Zhangjin Wu wrote:
>
> Suggested-by: Arnd Bergmann <arnd@arndb.de>
> Link: 
> https://lore.kernel.org/linux-riscv/5e7d2adf-e96f-41ca-a4c6-5c87a25d4c9c@app.fastmail.com/
> Signed-off-by: Zhangjin Wu <falcon@tinylab.org>
> ---
>  tools/include/nolibc/sys.h | 26 +++++++++++++-------------
>  1 file changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
> index 856249a11890..78c86f124335 100644
> --- a/tools/include/nolibc/sys.h
> +++ b/tools/include/nolibc/sys.h
> @@ -124,7 +124,7 @@ int sys_chmod(const char *path, mode_t mode)
>  #elif defined(__NR_chmod)
>  	return my_syscall2(__NR_chmod, path, mode);
>  #else
> -#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement 
> sys_chmod()
> +	return -ENOSYS;
>  #endif
>  }

I think the most logical would be to have each syscall (chmod,
fchmodat, ...) have its own function that returns -ENOSYS if
that is not defined, and have the logic that decides which one
to use as a separate function.

This patch is a step in that direction though, so I think that's
totally fine.

     Arnd
Zhangjin Wu June 7, 2023, 5:19 a.m. UTC | #2
> On Sat, Jun 3, 2023, at 11:01, Zhangjin Wu wrote:
> >
> > Suggested-by: Arnd Bergmann <arnd@arndb.de>
> > Link:
> > https://lore.kernel.org/linux-riscv/5e7d2adf-e96f-41ca-a4c6-5c87a25d4c9c@app.fastmail.com/
> > Signed-off-by: Zhangjin Wu <falcon@tinylab.org>
> > ---
> >  tools/include/nolibc/sys.h | 26 +++++++++++++-------------
> >  1 file changed, 13 insertions(+), 13 deletions(-)
> >
> > diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
> > index 856249a11890..78c86f124335 100644
> > --- a/tools/include/nolibc/sys.h
> > +++ b/tools/include/nolibc/sys.h
> > @@ -124,7 +124,7 @@ int sys_chmod(const char *path, mode_t mode)
> >  #elif defined(__NR_chmod)
> >  	return my_syscall2(__NR_chmod, path, mode);
> >  #else
> > -#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement
> > sys_chmod()
> > +	return -ENOSYS;
> >  #endif
> >  }
>
> I think the most logical would be to have each syscall (chmod,
> fchmodat, ...) have its own function that returns -ENOSYS if
> that is not defined, and have the logic that decides which one
> to use as a separate function.
>

Yeah, agreed, we can clean up them one by one, If split them to their own
syscalls, I have two questions (for Arnd, and Willy too):

1. do we need to add the corresponding library routines at the same time?

  Use llseek() as an example, there will be llseek() and lsee64(). If off_t
  would be converted to 64bit, then, they can be simply added as follows:

    #define lseek64 lseek
    #define llseek lseek

  Or something like this:

    static __attribute__((unused))
    loff_t lseek(int fd, loff_t offset, int whence)
    {
    	return lseek(fd, offset, whence);
    }

    static __attribute__((unused))
    off64_t lseek(int fd, off64_t offset, int whence)
    {
    	return lseek(fd, offset, whence);
    }

  This one aligns with the other already added library routines.

  Which one do you like more?

2. If so, how to cope with the new types when add the library routines?

  Still use the above llseek() as an example, If not use '#define' method,
  We may need to declare loff_t and off64_t in std.h too:

    #define off64_t off_t
    #define loff_t off_t

  Or align with the other new types, use 'typedef' instead of '#define'.

  And further, use poll() as an example, in its manpage [1], there may be some
  new types, such as 'nfds_t', but 'int' is used in tools/include/nolibc/sys.h
  currently, do we need to add nfds_t?

  The 'idtypes_t' and 'id_t' types used by waitid() [2] is similar, both
  of them can simply use the 'int' type.

The above two questions are important to the coming patches, it may determine
how I should tune the new llseek() and waitid() syscalls and their library
routines. very welcome your suggestions.

> This patch is a step in that direction though, so I think that's
> totally fine.

Thanks, so, can I pick your Reviewed-by for the first two patches? I'm ready to
send v4 now ;-)

Best regards,
Zhangjin

---
[1]: https://linux.die.net/man/2/poll
[2]: https://linux.die.net/man/2/waitid

>
>      Arnd
Arnd Bergmann June 7, 2023, 8:45 a.m. UTC | #3
On Wed, Jun 7, 2023, at 07:19, Zhangjin Wu wrote:
>> On Sat, Jun 3, 2023, at 11:01, Zhangjin Wu wrote:
>
> Yeah, agreed, we can clean up them one by one, If split them to their own
> syscalls, I have two questions (for Arnd, and Willy too):
>
> 1. do we need to add the corresponding library routines at the same time?
>
>   Use llseek() as an example, there will be llseek() and lsee64(). If off_t
>   would be converted to 64bit, then, they can be simply added as follows:
>
>     #define lseek64 lseek
>     #define llseek lseek
>
>   Or something like this:
>
>     static __attribute__((unused))
>     loff_t lseek(int fd, loff_t offset, int whence)
>     {
>     	return lseek(fd, offset, whence);
>     }
>
>     static __attribute__((unused))
>     off64_t lseek(int fd, off64_t offset, int whence)
>     {
>     	return lseek(fd, offset, whence);
>     }
>
>   This one aligns with the other already added library routines.
>
>   Which one do you like more?

lseek() is probably not a good example, as the llseek and lseek64
library functions are both nonstandard, and I'd suggest leaving them
out of nolibc altogether.

Are there any examples of functions where we actually want mulitple
versions?

> 2. If so, how to cope with the new types when add the library routines?
>
>   Still use the above llseek() as an example, If not use '#define' method,
>   We may need to declare loff_t and off64_t in std.h too:
>
>     #define off64_t off_t
>     #define loff_t off_t
>
>   Or align with the other new types, use 'typedef' instead of '#define'.

If we do want to include the explicit off64_t interfaces from glibc,
I'd suggest doing it the same way as musl:
https://git.musl-libc.org/cgit/musl/tree/include/unistd.h#n201

>
>> This patch is a step in that direction though, so I think that's
>> totally fine.
>
> Thanks, so, can I pick your Reviewed-by for the first two patches? I'm ready to
> send v4 now ;-)

Yes, please do.

     Arnd
Zhangjin Wu June 7, 2023, 9:46 a.m. UTC | #4
> On Wed, Jun 7, 2023, at 07:19, Zhangjin Wu wrote:
> >> On Sat, Jun 3, 2023, at 11:01, Zhangjin Wu wrote:
> >
> > Yeah, agreed, we can clean up them one by one, If split them to their own
> > syscalls, I have two questions (for Arnd, and Willy too):
> >
> > 1. do we need to add the corresponding library routines at the same time?
> >
> >   Use llseek() as an example, there will be llseek() and lsee64(). If off_t
> >   would be converted to 64bit, then, they can be simply added as follows:
> >
> >     #define lseek64 lseek
> >     #define llseek lseek
> >
> >   Or something like this:
> >
> >     static __attribute__((unused))
> >     loff_t lseek(int fd, loff_t offset, int whence)
> >     {
> >     	return lseek(fd, offset, whence);
> >     }
> >
> >     static __attribute__((unused))
> >     off64_t lseek(int fd, off64_t offset, int whence)
> >     {
> >     	return lseek(fd, offset, whence);
> >     }
> >
> >   This one aligns with the other already added library routines.
> >
> >   Which one do you like more?
> 
> lseek() is probably not a good example, as the llseek and lseek64
> library functions are both nonstandard, and I'd suggest leaving them
> out of nolibc altogether.
>

Ok, agree, as the 64bit version of lseek may be enough for nolibc, if a target
application really require, they can add the alias themselves.

> Are there any examples of functions where we actually want mulitple
> versions?
>

For example, the following ones are related to the syscalls being added,
all of them have similar library routines in current sys.h:

* waitid, https://linux.die.net/man/2/waitid
* ppoll, https://linux.die.net/man/2/ppoll
* pselect, https://linux.die.net/man/2/pselect6
* clock_gettime, https://linux.die.net/man/2/clock_gettime

The similar routines are put in right side:

* waitid --> waitpid, wait, wait4
* ppoll --> poll
* pselect --> select
* clock_gettime --> gettimeofday

For the clock_gettime, it may also let us think about if we need to add
its friends (clock_getres, clock_settime) together.

> > 2. If so, how to cope with the new types when add the library routines?
> >
> >   Still use the above llseek() as an example, If not use '#define' method,
> >   We may need to declare loff_t and off64_t in std.h too:
> >
> >     #define off64_t off_t
> >     #define loff_t off_t
> >
> >   Or align with the other new types, use 'typedef' instead of '#define'.
> 
> If we do want to include the explicit off64_t interfaces from glibc,
> I'd suggest doing it the same way as musl:
> https://git.musl-libc.org/cgit/musl/tree/include/unistd.h#n201
>

Thanks.

> >
> >> This patch is a step in that direction though, so I think that's
> >> totally fine.
> >
> > Thanks, so, can I pick your Reviewed-by for the first two patches? I'm ready to
> > send v4 now ;-)
> 
> Yes, please do.
>

Thanks very much, just added the Reviewed-by lines in v4 and have
already sent v4 out, welcome your review on the revision of the 3rd one,
it is almost consistent with the original Makefile now.

Best regards,
Zhangjin

>      Arnd
Arnd Bergmann June 7, 2023, 10:02 a.m. UTC | #5
On Wed, Jun 7, 2023, at 11:46, Zhangjin Wu wrote:
>> On Wed, Jun 7, 2023, at 07:19, Zhangjin Wu wrote:
>
> Ok, agree, as the 64bit version of lseek may be enough for nolibc, if a target
> application really require, they can add the alias themselves.
>
>> Are there any examples of functions where we actually want mulitple
>> versions?
>>
>
> For example, the following ones are related to the syscalls being added,
> all of them have similar library routines in current sys.h:
>
> * waitid, https://linux.die.net/man/2/waitid
> * ppoll, https://linux.die.net/man/2/ppoll
> * pselect, https://linux.die.net/man/2/pselect6
> * clock_gettime, https://linux.die.net/man/2/clock_gettime
>
> The similar routines are put in right side:
>
> * waitid --> waitpid, wait, wait4
> * ppoll --> poll
> * pselect --> select
> * clock_gettime --> gettimeofday

Ok, I think these are all useful to have in both versions.

All four of these examples are old enough that I think it's
sufficient just expose them to userspace as the bare system
calls, and have the older library calls be implemented using
them without a fallback to the native syscalls of the same
name on architectures that have both, newer architectures
would only have the latest version anyway.

> For the clock_gettime, it may also let us think about if we need to add
> its friends (clock_getres, clock_settime) together.

Yes, I think that makes sense. We also need clock_settime()
to implement settimeofday() on rv32.

Ideally, I'd love to extend the tooling around system calls
in the kernel so we can automatically generate the low-level
wrapper functions from syscall.tbl, but this needs a lot of
other work that you should not need to depend on for what
you are doing right now.

     Arnd
Zhangjin Wu June 7, 2023, 1:26 p.m. UTC | #6
> On Wed, Jun 7, 2023, at 11:46, Zhangjin Wu wrote:
> >> On Wed, Jun 7, 2023, at 07:19, Zhangjin Wu wrote:
> >
> > Ok, agree, as the 64bit version of lseek may be enough for nolibc, if a target
> > application really require, they can add the alias themselves.
> >
> >> Are there any examples of functions where we actually want mulitple
> >> versions?
> >>
> >
> > For example, the following ones are related to the syscalls being added,
> > all of them have similar library routines in current sys.h:
> >
> > * waitid, https://linux.die.net/man/2/waitid
> > * ppoll, https://linux.die.net/man/2/ppoll
> > * pselect, https://linux.die.net/man/2/pselect6
> > * clock_gettime, https://linux.die.net/man/2/clock_gettime
> >
> > The similar routines are put in right side:
> >
> > * waitid --> waitpid, wait, wait4
> > * ppoll --> poll
> > * pselect --> select
> > * clock_gettime --> gettimeofday
> 
> Ok, I think these are all useful to have in both versions.
> 
> All four of these examples are old enough that I think it's
> sufficient just expose them to userspace as the bare system
> calls, and have the older library calls be implemented using
> them without a fallback to the native syscalls of the same
> name on architectures that have both, newer architectures
> would only have the latest version anyway.
>

Ok, Thanks, I have already added parts of them, will send waitid and
64bit lseek at first.

> > For the clock_gettime, it may also let us think about if we need to add
> > its friends (clock_getres, clock_settime) together.
> 
> Yes, I think that makes sense. We also need clock_settime()
> to implement settimeofday() on rv32.
>

Ok.

> Ideally, I'd love to extend the tooling around system calls
> in the kernel so we can automatically generate the low-level
> wrapper functions from syscall.tbl,

That's cool.

BTW, I did something on dead syscall elimination [1] (DSE, RFC
patchset), a v1 has been prepared locally, but not sent out yet.

It also requires to work with the syscall.tbl or the generic
include/uapi/asm-generic/unistd.h, welcome your feedback on the RFC
patchset [1] and you should be the right reviewer of the coming v1 ;-)

The left issue of RFC version is finding a way to not KEEP the exception
entries (in ld script) added by get_user/put_user() if the corresponding
syscalls are not really used, such KEEPs of exception entries reverts
the ownership from "syscalls -> get_user/put_user" to "get_user/put_user
-> syscalls" and blocks the gc'ing of the sections of such syscalls.

In the coming v1, I used a script trick to drop the wrongly KEPT
exception entries to allow drop all of the unused syscalls at last. Will
clean up them asap. But it is a little slow and looks ugly, it is only
for a further demo of the possibility.

In v2 of DSE, I'm wondering whether it is possible to drop all of the
manually added KEEP operations from ld scripts and use some conditional
attributes (for the sections added by get_user/put_user) to build the
'used' references from "syscalls" to "sections created by
get_user/put_user", this may need support from gcc and ld, welcome your
suggestions too, thanks.

And that RFC patchset added a patch to record the used 'syscalls' in
nolibc automatically ;-)

[1]: https://lore.kernel.org/linux-riscv/cover.1676594211.git.falcon@tinylab.org/
[2]: https://reviews.llvm.org/D96838

> but this needs a lot of
> other work that you should not need to depend on for what
> you are doing right now.

Ok, welcome to share any progress.

Thanks,
Zhangjin

> 
>      Arnd
diff mbox series

Patch

diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 856249a11890..78c86f124335 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -124,7 +124,7 @@  int sys_chmod(const char *path, mode_t mode)
 #elif defined(__NR_chmod)
 	return my_syscall2(__NR_chmod, path, mode);
 #else
-#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod()
+	return -ENOSYS;
 #endif
 }
 
@@ -153,7 +153,7 @@  int sys_chown(const char *path, uid_t owner, gid_t group)
 #elif defined(__NR_chown)
 	return my_syscall3(__NR_chown, path, owner, group);
 #else
-#error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown()
+	return -ENOSYS;
 #endif
 }
 
@@ -251,7 +251,7 @@  int sys_dup2(int old, int new)
 #elif defined(__NR_dup2)
 	return my_syscall2(__NR_dup2, old, new);
 #else
-#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2()
+	return -ENOSYS;
 #endif
 }
 
@@ -351,7 +351,7 @@  pid_t sys_fork(void)
 #elif defined(__NR_fork)
 	return my_syscall0(__NR_fork);
 #else
-#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork()
+	return -ENOSYS;
 #endif
 }
 #endif
@@ -648,7 +648,7 @@  int sys_link(const char *old, const char *new)
 #elif defined(__NR_link)
 	return my_syscall2(__NR_link, old, new);
 #else
-#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link()
+	return -ENOSYS;
 #endif
 }
 
@@ -700,7 +700,7 @@  int sys_mkdir(const char *path, mode_t mode)
 #elif defined(__NR_mkdir)
 	return my_syscall2(__NR_mkdir, path, mode);
 #else
-#error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir()
+	return -ENOSYS;
 #endif
 }
 
@@ -729,7 +729,7 @@  long sys_mknod(const char *path, mode_t mode, dev_t dev)
 #elif defined(__NR_mknod)
 	return my_syscall3(__NR_mknod, path, mode, dev);
 #else
-#error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod()
+	return -ENOSYS;
 #endif
 }
 
@@ -848,7 +848,7 @@  int sys_open(const char *path, int flags, mode_t mode)
 #elif defined(__NR_open)
 	return my_syscall3(__NR_open, path, flags, mode);
 #else
-#error Neither __NR_openat nor __NR_open defined, cannot implement sys_open()
+	return -ENOSYS;
 #endif
 }
 
@@ -943,7 +943,7 @@  int sys_poll(struct pollfd *fds, int nfds, int timeout)
 #elif defined(__NR_poll)
 	return my_syscall3(__NR_poll, fds, nfds, timeout);
 #else
-#error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll()
+	return -ENOSYS;
 #endif
 }
 
@@ -1059,7 +1059,7 @@  int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva
 #endif
 	return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
 #else
-#error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select()
+	return -ENOSYS;
 #endif
 }
 
@@ -1196,7 +1196,7 @@  int sys_stat(const char *path, struct stat *buf)
 #elif defined(__NR_stat)
 	ret = my_syscall2(__NR_stat, path, &stat);
 #else
-#error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat()
+	return -ENOSYS;
 #endif
 	buf->st_dev          = stat.st_dev;
 	buf->st_ino          = stat.st_ino;
@@ -1243,7 +1243,7 @@  int sys_symlink(const char *old, const char *new)
 #elif defined(__NR_symlink)
 	return my_syscall2(__NR_symlink, old, new);
 #else
-#error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink()
+	return -ENOSYS;
 #endif
 }
 
@@ -1312,7 +1312,7 @@  int sys_unlink(const char *path)
 #elif defined(__NR_unlink)
 	return my_syscall1(__NR_unlink, path);
 #else
-#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink()
+	return -ENOSYS;
 #endif
 }