Linux: Add getdents64 system call

Message ID 87tvdff39e.fsf@oldenburg2.str.redhat.com
State Committed
Headers

Commit Message

Florian Weimer May 28, 2019, 7:26 a.m. UTC
  * Carlos O'Donell:

> On 5/15/19 11:10 AM, Florian Weimer wrote:
>> No 32-bit system call wrapper is added because the interface
>> is problematic because it cannot deal with 32-bit inode numbers

(should say 64-bit inode numbers)

>> and 64-bit directory hashes.
>
> Are you saying we do not want to ever add a getdents syscall wrapper
> because it would have problems that users couldn't fix, or problems
> the user could fix if they were careful?

The whole thing would be confusing.  The position of d_type is different
on 64-bit architectures, and future 32-bit architectures may not even
have it.

>> A future commit will deprecate the undocumented getdirentries
>> and getdirentries64 functions.
>
> Why are getdirentries and getdirentries64 considered deprecated?
> Is it because getdents and getdents64 superseded them?

They perform a useless lseek call.

>> +/* These functions are only implemented on Linux.  The public
>> +   interface for getdents64 is declared in <unistd.h>.  */
>> +extern __ssize_t __getdents (int __fd, void *__buf, size_t __nbytes)
>>        attribute_hidden;
>> +extern __ssize_t __getdents64 (int __fd, void *__buf, size_t __nbytes);
>> +libc_hidden_proto (__getdents64)
>> +
>
> We use void*, but the linux man pages use 'struct linux_dirent64',
> what should we use?

void * is the correct type.  The buffer may be smaller than struct
linux_dirent64.

>>   extern int __alphasort64 (const struct dirent64 **a, const struct dirent64 **b)
>>        __attribute_pure__;
>>   extern int __versionsort64 (const struct dirent64 **a,
>> diff --git a/manual/filesys.texi b/manual/filesys.texi
>> index 28480e7608..aa4a44dc96 100644
>> --- a/manual/filesys.texi
>> +++ b/manual/filesys.texi
>> @@ -242,6 +242,7 @@ here to the stream facilities for ordinary files, described in
>>   * Scanning Directory Content::  Get entries for user selected subset of
>>                                    contents in given directory.
>>   * Simple Directory Lister Mark II::  Revised version of the program.
>> +* Low-level Directory Access::  Async-signal-functions for directory access.
>
> Please use:
>
> "AS-Safe functions for directory access." ("AS-safe" is defined in the safety notes)
>
> or
>
> "Asynchronous-signal-safe functions for directory access."

Thanks, fixed.  Also added an @xref to the section itself.

>>   @end menu
>>     @node Directory Entries
>> @@ -360,6 +361,10 @@ You shouldn't ever allocate objects of the @code{struct dirent} or
>>   you.  Instead, you refer to these objects using the pointers returned by
>>   the following functions.
>>   +Directory streams are a high-level interface.  On Linux,
>> alternative
>> +interfaces for accessing directories using file descriptors are
>> +available.  @xref{Low-level Directory Access}.
>
> Should this be:
>
> "available in @xref{Low-level Directory Access}."
>
> Rather than having the @xref as a distinct sentence?

No, @xref is intended to be used that way.  It would have to be @ref at
an end of a sentence.  I can use that if you prefer.

>>   @deftypefun {DIR *} opendir (const char *@var{dirname})
>>   @standards{POSIX.1, dirent.h}
>>   @safety{@prelim{}@mtsafe{}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{} @acsfd{}}}
>> @@ -826,6 +831,39 @@ After the call the returned entries are available for direct use.
>>   Note the simple selector function in this example.  Since we want to see
>>   all directory entries we always return @code{1}.
>>   +@node Low-level Directory Access
>> +@subsection Low-level Directory Access
>> +
>> +The stream-based directory functions are not async-signal-safe and
>> +cannot be used after @code{vfork}.  The functions below provide an
>> +alternative that can be used in these contexts.
>> +
>> +Directory data is obtained from a file descriptor, as created by the
>> +@code{open} function, with or without the @code{O_DIRECTORY} flag.
>> +@xref{Opening and Closing Files}.
>
> Should this reference be parenthetical?
>
> e.g.  ... flag (@xref{Opening and Closing Files}).

It would need to be @pxref then.  Not sure if that's an improvement.

I'm attaching an updated patch with the indicated changes.

Thanks,
Florian

Linux: Add getdents64 system call

No 32-bit system call wrapper is added because the interface
is problematic because it cannot deal with 64-bit inode numbers
and 64-bit directory hashes.

A future commit will deprecate the undocumented getdirentries
and getdirentries64 functions.

2019-05-27  Florian Weimer  <fweimer@redhat.com>

	Linux: Add getdents64 system call.
	* include/dirnent.h (getdents): Add comment and change buffer
	argument type to void *.
	(getdents64): Likewise.  Add hidden prototype.
	* sysdeps/unix/sysv/linux/bits/Versions (GLIBC_2.30): Export
	getdents64.
	* sysdeps/unix/sysv/linux/Makefile [$(subdir) == dirent] (tests):
	Add tst-getdents64.
	* sysdeps/unix/sysv/linux/bits/unistd_ext.h (getdents64): Declare.
	* sysdeps/unix/sysv/linux/getdents.c (__getdents): Change buffer
	argument type to void *.
	* sysdeps/unix/sysv/linux/getdents64.c (__getdents64): Likewise.
	Add hidden definition and getdents64 alias.
	* sysdeps/unix/sysv/linux/mips/mips64/getdents64.c (__getdents64):
	Likewise.
	* sysdeps/unix/sysv/linux/tst-getdents64.c: New file.
	* manual/filesys.texi (Accessing Directories): Add Low-level
	Directory Access node reference.
	(Opening a Directory): Cross-reference it.
	(Low-level Directory Access): New node.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30): Add
	getdents64.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
	Likewise.
  

Comments

Carlos O'Donell May 28, 2019, 7:55 p.m. UTC | #1
On 5/28/19 3:26 AM, Florian Weimer wrote:
> * Carlos O'Donell:
> 
>> On 5/15/19 11:10 AM, Florian Weimer wrote:
>>> No 32-bit system call wrapper is added because the interface
>>> is problematic because it cannot deal with 32-bit inode numbers
> 
> (should say 64-bit inode numbers)

I figured that.

>>> and 64-bit directory hashes.
>>
>> Are you saying we do not want to ever add a getdents syscall wrapper
>> because it would have problems that users couldn't fix, or problems
>> the user could fix if they were careful?
> 
> The whole thing would be confusing.  The position of d_type is different
> on 64-bit architectures, and future 32-bit architectures may not even
> have it.

Right, I noticed that d_type moved when comparing the two arches.

Is there any reason we don't define getdents defaulting to getdents64?

Is it because of the established precedent set for all the other fs-related
32-bit and 64-bit syscalls, whose default selection for a non-specific name
like getdents, is predicated on large-file support being turned on?

>>> A future commit will deprecate the undocumented getdirentries
>>> and getdirentries64 functions.
>>
>> Why are getdirentries and getdirentries64 considered deprecated?
>> Is it because getdents and getdents64 superseded them?
> 
> They perform a useless lseek call.

So if I understand correctly:

* The have poorer performance.

* We can confuse developers when presenting two similar interfaces for
   effectively the same operations.

The downside is that there may be BSD software that we make harder to
port because you have to rewrite getdirentries into getdents64.

Unless there is a stronger reason for deprecation I would simply leave
getdirentries.

Are the above reasons the full list? Do you consider these reasons enough
for deprecation of getdirenties?

I know I'm getting ahead of myself here, but while we're at it we might
as well have a precursor conversation to the future patch.

>>> +/* These functions are only implemented on Linux.  The public
>>> +   interface for getdents64 is declared in <unistd.h>.  */
>>> +extern __ssize_t __getdents (int __fd, void *__buf, size_t __nbytes)
>>>         attribute_hidden;
>>> +extern __ssize_t __getdents64 (int __fd, void *__buf, size_t __nbytes);
>>> +libc_hidden_proto (__getdents64)
>>> +
>>
>> We use void*, but the linux man pages use 'struct linux_dirent64',
>> what should we use?
> 
> void * is the correct type.  The buffer may be smaller than struct
> linux_dirent64.

Right because d_reclen could indicate that.

>>>    extern int __alphasort64 (const struct dirent64 **a, const struct dirent64 **b)
>>>         __attribute_pure__;
>>>    extern int __versionsort64 (const struct dirent64 **a,
>>> diff --git a/manual/filesys.texi b/manual/filesys.texi
>>> index 28480e7608..aa4a44dc96 100644
>>> --- a/manual/filesys.texi
>>> +++ b/manual/filesys.texi
>>> @@ -242,6 +242,7 @@ here to the stream facilities for ordinary files, described in
>>>    * Scanning Directory Content::  Get entries for user selected subset of
>>>                                     contents in given directory.
>>>    * Simple Directory Lister Mark II::  Revised version of the program.
>>> +* Low-level Directory Access::  Async-signal-functions for directory access.
>>
>> Please use:
>>
>> "AS-Safe functions for directory access." ("AS-safe" is defined in the safety notes)
>>
>> or
>>
>> "Asynchronous-signal-safe functions for directory access."
> 
> Thanks, fixed.  Also added an @xref to the section itself.

OK.

>>>    @end menu
>>>      @node Directory Entries
>>> @@ -360,6 +361,10 @@ You shouldn't ever allocate objects of the @code{struct dirent} or
>>>    you.  Instead, you refer to these objects using the pointers returned by
>>>    the following functions.
>>>    +Directory streams are a high-level interface.  On Linux,
>>> alternative
>>> +interfaces for accessing directories using file descriptors are
>>> +available.  @xref{Low-level Directory Access}.
>>
>> Should this be:
>>
>> "available in @xref{Low-level Directory Access}."
>>
>> Rather than having the @xref as a distinct sentence?
> 
> No, @xref is intended to be used that way.  It would have to be @ref at
> an end of a sentence.  I can use that if you prefer.

You are right. What you have is good. Suggestion withdrawn.

>>>    @deftypefun {DIR *} opendir (const char *@var{dirname})
>>>    @standards{POSIX.1, dirent.h}
>>>    @safety{@prelim{}@mtsafe{}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{} @acsfd{}}}
>>> @@ -826,6 +831,39 @@ After the call the returned entries are available for direct use.
>>>    Note the simple selector function in this example.  Since we want to see
>>>    all directory entries we always return @code{1}.
>>>    +@node Low-level Directory Access
>>> +@subsection Low-level Directory Access
>>> +
>>> +The stream-based directory functions are not async-signal-safe and
>>> +cannot be used after @code{vfork}.  The functions below provide an
>>> +alternative that can be used in these contexts.
>>> +
>>> +Directory data is obtained from a file descriptor, as created by the
>>> +@code{open} function, with or without the @code{O_DIRECTORY} flag.
>>> +@xref{Opening and Closing Files}.
>>
>> Should this reference be parenthetical?
>>
>> e.g.  ... flag (@xref{Opening and Closing Files}).
> 
> It would need to be @pxref then.  Not sure if that's an improvement.
> 
> I'm attaching an updated patch with the indicated changes.
> 

I withdraw this suggestion.

> Thanks,
> Florian
> 
> Linux: Add getdents64 system call
> 
> No 32-bit system call wrapper is added because the interface
> is problematic because it cannot deal with 64-bit inode numbers
> and 64-bit directory hashes.
> 
> A future commit will deprecate the undocumented getdirentries
> and getdirentries64 functions.
> 
> 2019-05-27  Florian Weimer  <fweimer@redhat.com>
> 
> 	Linux: Add getdents64 system call.
> 	* include/dirnent.h (getdents): Add comment and change buffer
> 	argument type to void *.
> 	(getdents64): Likewise.  Add hidden prototype.
> 	* sysdeps/unix/sysv/linux/bits/Versions (GLIBC_2.30): Export
> 	getdents64.
> 	* sysdeps/unix/sysv/linux/Makefile [$(subdir) == dirent] (tests):
> 	Add tst-getdents64.
> 	* sysdeps/unix/sysv/linux/bits/unistd_ext.h (getdents64): Declare.
> 	* sysdeps/unix/sysv/linux/getdents.c (__getdents): Change buffer
> 	argument type to void *.
> 	* sysdeps/unix/sysv/linux/getdents64.c (__getdents64): Likewise.
> 	Add hidden definition and getdents64 alias.
> 	* sysdeps/unix/sysv/linux/mips/mips64/getdents64.c (__getdents64):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/tst-getdents64.c: New file.
> 	* manual/filesys.texi (Accessing Directories): Add Low-level
> 	Directory Access node reference.
> 	(Opening a Directory): Cross-reference it.
> 	(Low-level Directory Access): New node.
> 	* sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30): Add
> 	getdents64.
> 	* sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 

This version looks good to me, it adds a new linux syscall wrapper for
direct use for linux developers.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> diff --git a/NEWS b/NEWS
> index c885b960ca..ededf627b3 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -20,7 +20,7 @@ Major new features:
>     twalk function, but it passes an additional caller-supplied argument
>     to the callback function.
>   
> -* On Linux, the gettid and tgkill functions have been added.
> +* On Linux, the getdents64, gettid, and tgkill functions have been added.

OK.

>   
>   * Minguo (Republic of China) calendar support has been added as an
>     alternative calendar for the following locales: zh_TW, cmn_TW, hak_TW,
> diff --git a/include/dirent.h b/include/dirent.h
> index 400835eefe..3736803bce 100644
> --- a/include/dirent.h
> +++ b/include/dirent.h
> @@ -35,10 +35,14 @@ extern __ssize_t __getdirentries (int __fd, char *__restrict __buf,
>   				size_t __nbytes,
>   				__off_t *__restrict __basep)
>        __THROW __nonnull ((2, 4));
> -extern __ssize_t __getdents (int __fd, char *__buf, size_t __nbytes)
> -     attribute_hidden;
> -extern __ssize_t __getdents64 (int __fd, char *__buf, size_t __nbytes)
> +
> +/* These functions are only implemented on Linux.  The public
> +   interface for getdents64 is declared in <unistd.h>.  */
> +extern __ssize_t __getdents (int __fd, void *__buf, size_t __nbytes)

OK.

>        attribute_hidden;
> +extern __ssize_t __getdents64 (int __fd, void *__buf, size_t __nbytes);
> +libc_hidden_proto (__getdents64)
> +

OK.

>   extern int __alphasort64 (const struct dirent64 **a, const struct dirent64 **b)
>        __attribute_pure__;
>   extern int __versionsort64 (const struct dirent64 **a,
> diff --git a/manual/filesys.texi b/manual/filesys.texi
> index 28480e7608..513319418a 100644
> --- a/manual/filesys.texi
> +++ b/manual/filesys.texi
> @@ -242,6 +242,7 @@ here to the stream facilities for ordinary files, described in
>   * Scanning Directory Content::  Get entries for user selected subset of
>                                    contents in given directory.
>   * Simple Directory Lister Mark II::  Revised version of the program.
> +* Low-level Directory Access::  AS-Safe functions for directory access.

OK.

>   @end menu
>   
>   @node Directory Entries
> @@ -360,6 +361,10 @@ You shouldn't ever allocate objects of the @code{struct dirent} or
>   you.  Instead, you refer to these objects using the pointers returned by
>   the following functions.
>   
> +Directory streams are a high-level interface.  On Linux, alternative
> +interfaces for accessing directories using file descriptors are
> +available.  @xref{Low-level Directory Access}.

OK.

> +
>   @deftypefun {DIR *} opendir (const char *@var{dirname})
>   @standards{POSIX.1, dirent.h}
>   @safety{@prelim{}@mtsafe{}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{} @acsfd{}}}
> @@ -826,6 +831,39 @@ After the call the returned entries are available for direct use.
>   Note the simple selector function in this example.  Since we want to see
>   all directory entries we always return @code{1}.
>   
> +@node Low-level Directory Access
> +@subsection Low-level Directory Access
> +
> +The stream-based directory functions are not AS-Safe and cannot be
> +used after @code{vfork}.  @xref{POSIX Safety Concepts}.  The functions

OK.

> +below provide an alternative that can be used in these contexts.
> +
> +Directory data is obtained from a file descriptor, as created by the
> +@code{open} function, with or without the @code{O_DIRECTORY} flag.
> +@xref{Opening and Closing Files}.
> +

OK.

> +@deftypefun ssize_t getdents64 (int @var{fd}, void *@var{buffer}, size_t @var{length})
> +@standards{Linux, unistd.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +The @code{getdents64} function reads at most @var{length} bytes of
> +directory entry data from the file descriptor @var{fd} and stores it
> +into the byte array starting at @var{buffer}.
> +
> +On success, the function returns the number of bytes written to the
> +buffer.  This number is zero if @var{fd} is already at the end of the
> +directory stream.  On error, the function returns @code{-1} and sets
> +@code{errno} to the appropriate error code.
> +

OK.

> +The data is stored as a sequence of @code{struct dirent64} records,
> +which can be traversed using the @code{d_reclen} member.  The buffer
> +should be large enough to hold the largest possible directory entry.
> +Note that some file systems support file names longer than
> +@code{NAME_MAX} bytes (e.g., because they support up to 255 Unicode
> +characters), so a buffer size of at least 1024 is recommended.
> +

OK.

> +This function is specific to Linux.
> +@end deftypefun

OK.

> +
>   
>   @node Working with Directory Trees
>   @section Working with Directory Trees
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index d2f0b60ea9..afcdc658b5 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -188,6 +188,7 @@ inhibit-glue = yes
>   
>   ifeq ($(subdir),dirent)
>   sysdep_routines += getdirentries getdirentries64
> +tests += tst-getdents64

OK.

>   tests-internal += tst-readdir64-compat
>   endif
>   
> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
> index c7137e2c2c..1ca102a9e2 100644
> --- a/sysdeps/unix/sysv/linux/Versions
> +++ b/sysdeps/unix/sysv/linux/Versions
> @@ -175,7 +175,7 @@ libc {
>       getcpu;
>     }
>     GLIBC_2.30 {
> -    gettid; tgkill;
> +    getdents64; gettid; tgkill;

OK.

>     }
>     GLIBC_PRIVATE {
>       # functions used in other libraries
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 324909d553..a4c31932cb 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2141,6 +2141,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 084e475569..fe85a35620 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2216,6 +2216,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index f58d16e210..bc3df8dcea 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -126,6 +126,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> index 0061172f23..6e7b2bb83d 100644
> --- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> +++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> @@ -22,6 +22,12 @@
>   
>   #ifdef __USE_GNU
>   
> +/* Read from the directory descriptor FD into LENGTH bytes at BUFFER.
> +   Return the number of bytes read on success (0 for end of
> +   directory), and -1 for failure.  */
> +extern ssize_t getdents64 (int __fd, void *__buffer, size_t __length)
> +  __THROW __nonnull ((2));

OK.

> +
>   /* Return the kernel thread ID (TID) of the current thread.  The
>      returned value is not subject to caching.  Most Linux system calls
>      accept a TID in place of a PID.  Using the TID to change properties
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 38f6abaa30..9b3cee65bb 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2085,6 +2085,7 @@ GLIBC_2.29 xdrstdio_create F
>   GLIBC_2.29 xencrypt F
>   GLIBC_2.29 xprt_register F
>   GLIBC_2.29 xprt_unregister F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/getdents.c b/sysdeps/unix/sysv/linux/getdents.c
> index e796d9354b..3eec4c4221 100644
> --- a/sysdeps/unix/sysv/linux/getdents.c
> +++ b/sysdeps/unix/sysv/linux/getdents.c
> @@ -31,8 +31,10 @@
>   /* Pack the dirent64 struct down into 32-bit offset/inode fields, and
>      ensure that no overflow occurs.  */
>   ssize_t
> -__getdents (int fd, char *buf, size_t nbytes)
> +__getdents (int fd, void *buf0, size_t nbytes)
>   {
> +  char *buf = buf0;

OK.

> +
>     union
>     {
>       /* For !_DIRENT_MATCHES_DIRENT64 kernel 'linux_dirent64' has the same
> diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
> index 0786a15195..a6dd22106d 100644
> --- a/sysdeps/unix/sysv/linux/getdents64.c
> +++ b/sysdeps/unix/sysv/linux/getdents64.c
> @@ -20,12 +20,14 @@
>   #include <dirent.h>
>   #include <errno.h>
>   
> -/* The kernel struct linux_dirent64 matches the 'struct getdents64' type.  */
> +/* The kernel struct linux_dirent64 matches the 'struct dirent64' type.  */
>   ssize_t
> -__getdents64 (int fd, char *buf, size_t nbytes)
> +__getdents64 (int fd, void *buf, size_t nbytes)

OK.

>   {
>     return INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
>   }
> +libc_hidden_def (__getdents64)
> +weak_alias (__getdents64, getdents64)
>   
>   #if _DIRENT_MATCHES_DIRENT64
>   strong_alias (__getdents64, __getdents)
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index eb628f907b..75edece94a 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2037,6 +2037,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 6f240d9a59..edeaf8e722 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2203,6 +2203,7 @@ GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 vm86 F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index e589e3d7e2..b5d460eeb2 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2069,6 +2069,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 02c3ceee8d..05633b3cb8 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -127,6 +127,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index f9a86bd951..47eb7b4608 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2146,6 +2146,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index d153fe0df5..f7ced487f7 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2133,6 +2133,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index fb3a9b18fc..e49dc4272e 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2120,6 +2120,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 22c80418f6..daa3b60c5b 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2118,6 +2118,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
> index 8771c3c904..1e22fa4325 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
> @@ -25,8 +25,10 @@
>   #include <scratch_buffer.h>
>   
>   ssize_t
> -__getdents64 (int fd, char *buf, size_t nbytes)
> +__getdents64 (int fd, void *buf0, size_t nbytes)
>   {
> +  char *buf = buf0;

OK.

> +
>   #ifdef __NR_getdents64
>     ssize_t ret = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
>     if (ret != -1)
> @@ -107,6 +109,9 @@ __getdents64 (int fd, char *buf, size_t nbytes)
>     scratch_buffer_free (&tmpbuf);
>     return (char *) dp - buf;
>   }
> +libc_hidden_def (__getdents64)
> +weak_alias (__getdents64, getdents64)
> +
>   #if _DIRENT_MATCHES_DIRENT64
>   strong_alias (__getdents64, __getdents)
>   #endif
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index a32aafb552..457ce0b6f2 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2126,6 +2126,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 45342a587e..63d5c03bfb 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2120,6 +2120,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index fe1e96c170..7fec0c9670 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2174,6 +2174,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index cbcad5db98..9200a54309 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2176,6 +2176,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 060994eccf..ef7779905f 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2209,6 +2209,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index af68ed8d01..2860df8ebc 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2039,6 +2039,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index d317dc0586..2229a1dcc0 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2243,6 +2243,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 07d75c0481..31010e6cf7 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2103,6 +2103,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 0fdcd6109c..576295deff 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2171,6 +2171,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index ca871ad4be..abf0473683 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2075,6 +2075,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index b559e5b316..41977f6e9c 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -2041,6 +2041,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 37daaa28e4..3d2f00ca52 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2165,6 +2165,7 @@ GLIBC_2.30 __nldbl_vwarn F
>   GLIBC_2.30 __nldbl_vwarnx F
>   GLIBC_2.30 __nldbl_warn F
>   GLIBC_2.30 __nldbl_warnx F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 5f0a3adc3c..2f20643e8e 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2092,6 +2092,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/tst-getdents64.c b/sysdeps/unix/sysv/linux/tst-getdents64.c
> new file mode 100644
> index 0000000000..c1f7721221
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-getdents64.c
> @@ -0,0 +1,113 @@
> +/* Test for reading directories with getdents64.

OK.

> +   Copyright (C) 2019 Free Software Foundation, Inc.

OK.

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <dirent.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <support/xunistd.h>
> +#include <unistd.h>
> +
> +static int
> +do_test (void)
> +{
> +  /* The test compares the iteration order with readdir64.  */
> +  DIR *reference = opendir (".");
> +  TEST_VERIFY_EXIT (reference != NULL);
> +
> +  int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
> +  TEST_VERIFY (fd >= 0);
> +
> +  /* Perform two passes, with a rewind operating between passes.  */
> +  for (int pass = 0; pass < 2; ++pass)

OK.

> +    {
> +      /* Check that we need to fill the buffer multiple times.  */
> +      int read_count = 0;
> +
> +      while (true)
> +        {
> +          /* Simple way to make sure that the memcpy below does not read
> +             non-existing data.  */
> +          struct
> +          {
> +            char buffer[1024];
> +            struct dirent64 pad;
> +          } data;
> +
> +          ssize_t ret = getdents64 (fd, &data.buffer, sizeof (data.buffer));

OK.

> +          if (ret < 0)
> +            FAIL_EXIT1 ("getdents64: %m");
> +          if (ret == 0)
> +            break;
> +          ++read_count;
> +
> +          char *current = data.buffer;
> +          char *end = data.buffer + ret;
> +          while (current != end)
> +            {
> +              struct dirent64 entry;
> +              memcpy (&entry, current, sizeof (entry));
> +              /* Truncate overlong strings.  */
> +              entry.d_name[sizeof (entry.d_name) - 1] = '\0';
> +              TEST_VERIFY (strlen (entry.d_name) < sizeof (entry.d_name) - 1);
> +
> +              errno = 0;
> +              struct dirent64 *refentry = readdir64 (reference);
> +              if (refentry == NULL && errno == 0)
> +                FAIL_EXIT1 ("readdir64 failed too early, at: %s",
> +                            entry.d_name);
> +              else if (refentry == NULL)
> +                FAIL_EXIT1 ("readdir64: %m");
> +
> +              TEST_COMPARE_STRING (entry.d_name, refentry->d_name);
> +              TEST_COMPARE (entry.d_ino, refentry->d_ino);
> +              TEST_COMPARE (entry.d_off, refentry->d_off);
> +              TEST_COMPARE (entry.d_type, refentry->d_type);
> +
> +              /* Offset zero is reserved for the first entry.  */
> +              TEST_VERIFY (entry.d_off != 0);
> +
> +              TEST_VERIFY_EXIT (entry.d_reclen <= end - current);
> +              current += entry.d_reclen;

OK.

> +            }
> +        }
> +
> +      /* We expect to have reached the end of the stream.  */
> +      errno = 0;
> +      TEST_VERIFY (readdir64 (reference) == NULL);
> +      TEST_COMPARE (errno, 0);
> +
> +      /* direntries_read has been called more than once.  */
> +      TEST_VERIFY (read_count > 0);
> +
> +      /* Rewind both directory streams.  */
> +      xlseek (fd, 0, SEEK_SET);
> +      rewinddir (reference);
> +    }
> +
> +  xclose (fd);
> +  closedir (reference);
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index c82b3ba7b8..59f85d9373 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2050,6 +2050,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
>   GLIBC_2.3.4 setsourcefilter F
>   GLIBC_2.3.4 xdr_quad_t F
>   GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index ed89c34c55..67a4e238d6 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2149,6 +2149,7 @@ GLIBC_2.28 thrd_yield F
>   GLIBC_2.29 getcpu F
>   GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
>   GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> +GLIBC_2.30 getdents64 F
>   GLIBC_2.30 gettid F
>   GLIBC_2.30 tgkill F
>   GLIBC_2.30 twalk_r F
>
  
Adhemerval Zanella May 28, 2019, 8:37 p.m. UTC | #2
On 28/05/2019 16:55, Carlos O'Donell wrote:
> On 5/28/19 3:26 AM, Florian Weimer wrote:
>> * Carlos O'Donell:
>>
>>> On 5/15/19 11:10 AM, Florian Weimer wrote:
>>>> No 32-bit system call wrapper is added because the interface
>>>> is problematic because it cannot deal with 32-bit inode numbers
>>
>> (should say 64-bit inode numbers)
> 
> I figured that.
> 
>>>> and 64-bit directory hashes.
>>>
>>> Are you saying we do not want to ever add a getdents syscall wrapper
>>> because it would have problems that users couldn't fix, or problems
>>> the user could fix if they were careful?
>>
>> The whole thing would be confusing.  The position of d_type is different
>> on 64-bit architectures, and future 32-bit architectures may not even
>> have it.
> 
> Right, I noticed that d_type moved when comparing the two arches.
> 
> Is there any reason we don't define getdents defaulting to getdents64?
> 
> Is it because of the established precedent set for all the other fs-related
> 32-bit and 64-bit syscalls, whose default selection for a non-specific name
> like getdents, is predicated on large-file support being turned on?

I would prefer that if we eventually make a switch to make default fs-related
function to route to LFS variants to do as a whole instead of a symbol base.
Otherwise there is potential case of using wrong type, in this case it would
require to explicit use dirent64 type when calling getdents for 32-bit archs.  

> 
>>>> A future commit will deprecate the undocumented getdirentries
>>>> and getdirentries64 functions.
>>>
>>> Why are getdirentries and getdirentries64 considered deprecated?
>>> Is it because getdents and getdents64 superseded them?
>>
>> They perform a useless lseek call.
> 
> So if I understand correctly:
> 
> * The have poorer performance.
> 
> * We can confuse developers when presenting two similar interfaces for
>   effectively the same operations.
> 
> The downside is that there may be BSD software that we make harder to
> port because you have to rewrite getdirentries into getdents64.
> 
> Unless there is a stronger reason for deprecation I would simply leave
> getdirentries.
> 
> Are the above reasons the full list? Do you consider these reasons enough
> for deprecation of getdirenties?
> 
> I know I'm getting ahead of myself here, but while we're at it we might
> as well have a precursor conversation to the future patch.

My understanding is lseek from getdirentries is not really useless, but
exactly the semantic it aims to provide. Linux getdents does not have
the concept of offset, different than BSDs one which is usually 
syscall (FreeBSD for instance).

I am not sure, however, who usefull this is in reality. On FreeBSD repo
(not including ports), I see few uses: sdiff tool is the only binary and
opendir seems call it internally.

Now that glibc is providing a LFS variant, I think it would be better
served by a wrapper library instead (like libbsd).
  
Florian Weimer May 29, 2019, 8:17 a.m. UTC | #3
* Adhemerval Zanella:

> My understanding is lseek from getdirentries is not really useless, but
> exactly the semantic it aims to provide. Linux getdents does not have
> the concept of offset, different than BSDs one which is usually 
> syscall (FreeBSD for instance).

It's not a real offset in FreeBSD, either, in the sense that you can
perform arithmetic on it.  Our implementation is not compatible because
it does not perform a NULL check and assumes that the pointer to the
base offset is always non-NULL.

> I am not sure, however, who usefull this is in reality. On FreeBSD repo
> (not including ports), I see few uses: sdiff tool is the only binary and
> opendir seems call it internally.

I think providing this function is also misleading because there are
differences in parsing the directory stream.

Thanks,
Florian
  
Adhemerval Zanella May 29, 2019, 1:16 p.m. UTC | #4
On 29/05/2019 05:17, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> My understanding is lseek from getdirentries is not really useless, but
>> exactly the semantic it aims to provide. Linux getdents does not have
>> the concept of offset, different than BSDs one which is usually 
>> syscall (FreeBSD for instance).
> 
> It's not a real offset in FreeBSD, either, in the sense that you can
> perform arithmetic on it.  Our implementation is not compatible because
> it does not perform a NULL check and assumes that the pointer to the
> base offset is always non-NULL.
> 
>> I am not sure, however, who usefull this is in reality. On FreeBSD repo
>> (not including ports), I see few uses: sdiff tool is the only binary and
>> opendir seems call it internally.
> 
> I think providing this function is also misleading because there are
> differences in parsing the directory stream.

Right, this is two more point in favour of deprecating it.
  
Florian Weimer May 29, 2019, 1:26 p.m. UTC | #5
* Adhemerval Zanella:

> On 29/05/2019 05:17, Florian Weimer wrote:
>> * Adhemerval Zanella:
>> 
>>> My understanding is lseek from getdirentries is not really useless, but
>>> exactly the semantic it aims to provide. Linux getdents does not have
>>> the concept of offset, different than BSDs one which is usually 
>>> syscall (FreeBSD for instance).
>> 
>> It's not a real offset in FreeBSD, either, in the sense that you can
>> perform arithmetic on it.  Our implementation is not compatible because
>> it does not perform a NULL check and assumes that the pointer to the
>> base offset is always non-NULL.
>> 
>>> I am not sure, however, who usefull this is in reality. On FreeBSD repo
>>> (not including ports), I see few uses: sdiff tool is the only binary and
>>> opendir seems call it internally.
>> 
>> I think providing this function is also misleading because there are
>> differences in parsing the directory stream.
>
> Right, this is two more point in favour of deprecating it.

Does this mean that you agree with adding the getdents64 system call
wrapper?

Thanks,
Florian
  
Adhemerval Zanella May 29, 2019, 1:37 p.m. UTC | #6
On 29/05/2019 10:26, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> On 29/05/2019 05:17, Florian Weimer wrote:
>>> * Adhemerval Zanella:
>>>
>>>> My understanding is lseek from getdirentries is not really useless, but
>>>> exactly the semantic it aims to provide. Linux getdents does not have
>>>> the concept of offset, different than BSDs one which is usually 
>>>> syscall (FreeBSD for instance).
>>>
>>> It's not a real offset in FreeBSD, either, in the sense that you can
>>> perform arithmetic on it.  Our implementation is not compatible because
>>> it does not perform a NULL check and assumes that the pointer to the
>>> base offset is always non-NULL.
>>>
>>>> I am not sure, however, who usefull this is in reality. On FreeBSD repo
>>>> (not including ports), I see few uses: sdiff tool is the only binary and
>>>> opendir seems call it internally.
>>>
>>> I think providing this function is also misleading because there are
>>> differences in parsing the directory stream.
>>
>> Right, this is two more point in favour of deprecating it.
> 
> Does this mean that you agree with adding the getdents64 system call
> wrapper?
> 

Sorry if I wasn't clear. I am referring to a possible future deprecation
of getdirentries and getdirentries64.

I agree with adding getdents64.
  

Patch

diff --git a/NEWS b/NEWS
index c885b960ca..ededf627b3 100644
--- a/NEWS
+++ b/NEWS
@@ -20,7 +20,7 @@  Major new features:
   twalk function, but it passes an additional caller-supplied argument
   to the callback function.
 
-* On Linux, the gettid and tgkill functions have been added.
+* On Linux, the getdents64, gettid, and tgkill functions have been added.
 
 * Minguo (Republic of China) calendar support has been added as an
   alternative calendar for the following locales: zh_TW, cmn_TW, hak_TW,
diff --git a/include/dirent.h b/include/dirent.h
index 400835eefe..3736803bce 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -35,10 +35,14 @@  extern __ssize_t __getdirentries (int __fd, char *__restrict __buf,
 				size_t __nbytes,
 				__off_t *__restrict __basep)
      __THROW __nonnull ((2, 4));
-extern __ssize_t __getdents (int __fd, char *__buf, size_t __nbytes)
-     attribute_hidden;
-extern __ssize_t __getdents64 (int __fd, char *__buf, size_t __nbytes)
+
+/* These functions are only implemented on Linux.  The public
+   interface for getdents64 is declared in <unistd.h>.  */
+extern __ssize_t __getdents (int __fd, void *__buf, size_t __nbytes)
      attribute_hidden;
+extern __ssize_t __getdents64 (int __fd, void *__buf, size_t __nbytes);
+libc_hidden_proto (__getdents64)
+
 extern int __alphasort64 (const struct dirent64 **a, const struct dirent64 **b)
      __attribute_pure__;
 extern int __versionsort64 (const struct dirent64 **a,
diff --git a/manual/filesys.texi b/manual/filesys.texi
index 28480e7608..513319418a 100644
--- a/manual/filesys.texi
+++ b/manual/filesys.texi
@@ -242,6 +242,7 @@  here to the stream facilities for ordinary files, described in
 * Scanning Directory Content::  Get entries for user selected subset of
                                  contents in given directory.
 * Simple Directory Lister Mark II::  Revised version of the program.
+* Low-level Directory Access::  AS-Safe functions for directory access.
 @end menu
 
 @node Directory Entries
@@ -360,6 +361,10 @@  You shouldn't ever allocate objects of the @code{struct dirent} or
 you.  Instead, you refer to these objects using the pointers returned by
 the following functions.
 
+Directory streams are a high-level interface.  On Linux, alternative
+interfaces for accessing directories using file descriptors are
+available.  @xref{Low-level Directory Access}.
+
 @deftypefun {DIR *} opendir (const char *@var{dirname})
 @standards{POSIX.1, dirent.h}
 @safety{@prelim{}@mtsafe{}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{} @acsfd{}}}
@@ -826,6 +831,39 @@  After the call the returned entries are available for direct use.
 Note the simple selector function in this example.  Since we want to see
 all directory entries we always return @code{1}.
 
+@node Low-level Directory Access
+@subsection Low-level Directory Access
+
+The stream-based directory functions are not AS-Safe and cannot be
+used after @code{vfork}.  @xref{POSIX Safety Concepts}.  The functions
+below provide an alternative that can be used in these contexts.
+
+Directory data is obtained from a file descriptor, as created by the
+@code{open} function, with or without the @code{O_DIRECTORY} flag.
+@xref{Opening and Closing Files}.
+
+@deftypefun ssize_t getdents64 (int @var{fd}, void *@var{buffer}, size_t @var{length})
+@standards{Linux, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+The @code{getdents64} function reads at most @var{length} bytes of
+directory entry data from the file descriptor @var{fd} and stores it
+into the byte array starting at @var{buffer}.
+
+On success, the function returns the number of bytes written to the
+buffer.  This number is zero if @var{fd} is already at the end of the
+directory stream.  On error, the function returns @code{-1} and sets
+@code{errno} to the appropriate error code.
+
+The data is stored as a sequence of @code{struct dirent64} records,
+which can be traversed using the @code{d_reclen} member.  The buffer
+should be large enough to hold the largest possible directory entry.
+Note that some file systems support file names longer than
+@code{NAME_MAX} bytes (e.g., because they support up to 255 Unicode
+characters), so a buffer size of at least 1024 is recommended.
+
+This function is specific to Linux.
+@end deftypefun
+
 
 @node Working with Directory Trees
 @section Working with Directory Trees
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index d2f0b60ea9..afcdc658b5 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -188,6 +188,7 @@  inhibit-glue = yes
 
 ifeq ($(subdir),dirent)
 sysdep_routines += getdirentries getdirentries64
+tests += tst-getdents64
 tests-internal += tst-readdir64-compat
 endif
 
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index c7137e2c2c..1ca102a9e2 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -175,7 +175,7 @@  libc {
     getcpu;
   }
   GLIBC_2.30 {
-    gettid; tgkill;
+    getdents64; gettid; tgkill;
   }
   GLIBC_PRIVATE {
     # functions used in other libraries
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 324909d553..a4c31932cb 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2141,6 +2141,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 084e475569..fe85a35620 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2216,6 +2216,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index f58d16e210..bc3df8dcea 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -126,6 +126,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
index 0061172f23..6e7b2bb83d 100644
--- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
+++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
@@ -22,6 +22,12 @@ 
 
 #ifdef __USE_GNU
 
+/* Read from the directory descriptor FD into LENGTH bytes at BUFFER.
+   Return the number of bytes read on success (0 for end of
+   directory), and -1 for failure.  */
+extern ssize_t getdents64 (int __fd, void *__buffer, size_t __length)
+  __THROW __nonnull ((2));
+
 /* Return the kernel thread ID (TID) of the current thread.  The
    returned value is not subject to caching.  Most Linux system calls
    accept a TID in place of a PID.  Using the TID to change properties
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 38f6abaa30..9b3cee65bb 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2085,6 +2085,7 @@  GLIBC_2.29 xdrstdio_create F
 GLIBC_2.29 xencrypt F
 GLIBC_2.29 xprt_register F
 GLIBC_2.29 xprt_unregister F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/getdents.c b/sysdeps/unix/sysv/linux/getdents.c
index e796d9354b..3eec4c4221 100644
--- a/sysdeps/unix/sysv/linux/getdents.c
+++ b/sysdeps/unix/sysv/linux/getdents.c
@@ -31,8 +31,10 @@ 
 /* Pack the dirent64 struct down into 32-bit offset/inode fields, and
    ensure that no overflow occurs.  */
 ssize_t
-__getdents (int fd, char *buf, size_t nbytes)
+__getdents (int fd, void *buf0, size_t nbytes)
 {
+  char *buf = buf0;
+
   union
   {
     /* For !_DIRENT_MATCHES_DIRENT64 kernel 'linux_dirent64' has the same
diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
index 0786a15195..a6dd22106d 100644
--- a/sysdeps/unix/sysv/linux/getdents64.c
+++ b/sysdeps/unix/sysv/linux/getdents64.c
@@ -20,12 +20,14 @@ 
 #include <dirent.h>
 #include <errno.h>
 
-/* The kernel struct linux_dirent64 matches the 'struct getdents64' type.  */
+/* The kernel struct linux_dirent64 matches the 'struct dirent64' type.  */
 ssize_t
-__getdents64 (int fd, char *buf, size_t nbytes)
+__getdents64 (int fd, void *buf, size_t nbytes)
 {
   return INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
 }
+libc_hidden_def (__getdents64)
+weak_alias (__getdents64, getdents64)
 
 #if _DIRENT_MATCHES_DIRENT64
 strong_alias (__getdents64, __getdents)
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index eb628f907b..75edece94a 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2037,6 +2037,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 6f240d9a59..edeaf8e722 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2203,6 +2203,7 @@  GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 vm86 F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e589e3d7e2..b5d460eeb2 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2069,6 +2069,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 02c3ceee8d..05633b3cb8 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -127,6 +127,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index f9a86bd951..47eb7b4608 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2146,6 +2146,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index d153fe0df5..f7ced487f7 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2133,6 +2133,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index fb3a9b18fc..e49dc4272e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2120,6 +2120,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 22c80418f6..daa3b60c5b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2118,6 +2118,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
index 8771c3c904..1e22fa4325 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
+++ b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
@@ -25,8 +25,10 @@ 
 #include <scratch_buffer.h>
 
 ssize_t
-__getdents64 (int fd, char *buf, size_t nbytes)
+__getdents64 (int fd, void *buf0, size_t nbytes)
 {
+  char *buf = buf0;
+
 #ifdef __NR_getdents64
   ssize_t ret = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
   if (ret != -1)
@@ -107,6 +109,9 @@  __getdents64 (int fd, char *buf, size_t nbytes)
   scratch_buffer_free (&tmpbuf);
   return (char *) dp - buf;
 }
+libc_hidden_def (__getdents64)
+weak_alias (__getdents64, getdents64)
+
 #if _DIRENT_MATCHES_DIRENT64
 strong_alias (__getdents64, __getdents)
 #endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index a32aafb552..457ce0b6f2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2126,6 +2126,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 45342a587e..63d5c03bfb 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2120,6 +2120,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index fe1e96c170..7fec0c9670 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2174,6 +2174,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index cbcad5db98..9200a54309 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2176,6 +2176,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 060994eccf..ef7779905f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2209,6 +2209,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index af68ed8d01..2860df8ebc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2039,6 +2039,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index d317dc0586..2229a1dcc0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2243,6 +2243,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 07d75c0481..31010e6cf7 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2103,6 +2103,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 0fdcd6109c..576295deff 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2171,6 +2171,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index ca871ad4be..abf0473683 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2075,6 +2075,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index b559e5b316..41977f6e9c 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -2041,6 +2041,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 37daaa28e4..3d2f00ca52 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2165,6 +2165,7 @@  GLIBC_2.30 __nldbl_vwarn F
 GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 5f0a3adc3c..2f20643e8e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2092,6 +2092,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/tst-getdents64.c b/sysdeps/unix/sysv/linux/tst-getdents64.c
new file mode 100644
index 0000000000..c1f7721221
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-getdents64.c
@@ -0,0 +1,113 @@ 
+/* Test for reading directories with getdents64.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+  /* The test compares the iteration order with readdir64.  */
+  DIR *reference = opendir (".");
+  TEST_VERIFY_EXIT (reference != NULL);
+
+  int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
+  TEST_VERIFY (fd >= 0);
+
+  /* Perform two passes, with a rewind operating between passes.  */
+  for (int pass = 0; pass < 2; ++pass)
+    {
+      /* Check that we need to fill the buffer multiple times.  */
+      int read_count = 0;
+
+      while (true)
+        {
+          /* Simple way to make sure that the memcpy below does not read
+             non-existing data.  */
+          struct
+          {
+            char buffer[1024];
+            struct dirent64 pad;
+          } data;
+
+          ssize_t ret = getdents64 (fd, &data.buffer, sizeof (data.buffer));
+          if (ret < 0)
+            FAIL_EXIT1 ("getdents64: %m");
+          if (ret == 0)
+            break;
+          ++read_count;
+
+          char *current = data.buffer;
+          char *end = data.buffer + ret;
+          while (current != end)
+            {
+              struct dirent64 entry;
+              memcpy (&entry, current, sizeof (entry));
+              /* Truncate overlong strings.  */
+              entry.d_name[sizeof (entry.d_name) - 1] = '\0';
+              TEST_VERIFY (strlen (entry.d_name) < sizeof (entry.d_name) - 1);
+
+              errno = 0;
+              struct dirent64 *refentry = readdir64 (reference);
+              if (refentry == NULL && errno == 0)
+                FAIL_EXIT1 ("readdir64 failed too early, at: %s",
+                            entry.d_name);
+              else if (refentry == NULL)
+                FAIL_EXIT1 ("readdir64: %m");
+
+              TEST_COMPARE_STRING (entry.d_name, refentry->d_name);
+              TEST_COMPARE (entry.d_ino, refentry->d_ino);
+              TEST_COMPARE (entry.d_off, refentry->d_off);
+              TEST_COMPARE (entry.d_type, refentry->d_type);
+
+              /* Offset zero is reserved for the first entry.  */
+              TEST_VERIFY (entry.d_off != 0);
+
+              TEST_VERIFY_EXIT (entry.d_reclen <= end - current);
+              current += entry.d_reclen;
+            }
+        }
+
+      /* We expect to have reached the end of the stream.  */
+      errno = 0;
+      TEST_VERIFY (readdir64 (reference) == NULL);
+      TEST_COMPARE (errno, 0);
+
+      /* direntries_read has been called more than once.  */
+      TEST_VERIFY (read_count > 0);
+
+      /* Rewind both directory streams.  */
+      xlseek (fd, 0, SEEK_SET);
+      rewinddir (reference);
+    }
+
+  xclose (fd);
+  closedir (reference);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index c82b3ba7b8..59f85d9373 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2050,6 +2050,7 @@  GLIBC_2.3.4 setipv4sourcefilter F
 GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index ed89c34c55..67a4e238d6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2149,6 +2149,7 @@  GLIBC_2.28 thrd_yield F
 GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
+GLIBC_2.30 getdents64 F
 GLIBC_2.30 gettid F
 GLIBC_2.30 tgkill F
 GLIBC_2.30 twalk_r F