diff mbox series

[v3,2/4] Linux: Add close_range

Message ID 20201223163651.2634504-2-adhemerval.zanella@linaro.org
State New
Headers show
Series [v3,1/4] support: Add xclone | expand

Commit Message

Adhemerval Zanella Netto Dec. 23, 2020, 4:36 p.m. UTC
Changed from previous version:

  - Fixed manual wording.
  - Fixed test lowfd usage and a gaps check.
  - Added a new subtest to check for unsigned argument.
  - Fixed typos.
--

It was added on Linux 5.9 (278a5fbaed89).  Although FreeBSD has added
the same syscall, this only adds the symbol on Linux ports.  This
syscall is required to provided a fail-safe way to implement the
closefrom symbol (BZ #10353).

The tst-close_range-consts.py requires a toolchain with an updated
kernel headers that provides the close_range.h UAPI kernel header.

Checked on x86_64-linux-gnu on kernel v5.9 and v5.4.
---
 NEWS                                          |   2 +
 include/bits/unistd_ext.h                     |   6 +
 manual/llio.texi                              |  38 +++
 sysdeps/unix/sysv/linux/Makefile              |  13 +-
 sysdeps/unix/sysv/linux/Versions              |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/bits/unistd_ext.h     |  11 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/syscalls.list         |   1 +
 .../unix/sysv/linux/tst-close_range-consts.py |  49 ++++
 sysdeps/unix/sysv/linux/tst-close_range.c     | 222 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 35 files changed, 369 insertions(+), 2 deletions(-)
 create mode 100644 include/bits/unistd_ext.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range-consts.py
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range.c

Comments

Florian Weimer March 9, 2021, 9:47 a.m. UTC | #1
* Adhemerval Zanella via Libc-alpha:

> diff --git a/manual/llio.texi b/manual/llio.texi
> index c0a53e1a6e..ceb18ac89a 100644
> --- a/manual/llio.texi
> +++ b/manual/llio.texi
> @@ -284,6 +284,44 @@ of trying to close its underlying file descriptor with @code{close}.
>  This flushes any buffered output and updates the stream object to
>  indicate that it is closed.
>  
> +@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
> +@standards{Linux, unistd.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
> +@c This is a syscall for Linux v5.9.  There is no fallback emulation for
> +@c older kernels.
> +
> +The function @code{clode_range} closes the file descriptor from @var{lowfd}
> +to @var{maxfd} (inclusive).  This function is similar to call @code{close} in
> +specified file descriptor range depending on the @var{flags}.
> +
> +The @var{flags} add options on how the files are closes.  Linux currently
> +supports:.

Spurios “.” at end of line.

> +@vtable @code
> +@item CLOSE_RANGE_UNSHARE
> +Unshare the file descriptor table before closing file descriptors.
> +@end vtable
> +
> +The normal return value from @code{close_range} is @math{0}; a value
> +of @math{-1} is returned in case of failure.  The following @code{errno} error
> +conditions are defined for this function:
> +
> +@table @code
> +@item EINVAL
> +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flags}
> +is used.
> +
> +@item ENOMEM
> +Either there is not enough memory for the operation, or the process is
> +out of address space.
> +
> +@item EMFILE
> +The process has too many files open.
> +The maximum number of file descriptors is controlled by the
> +@end table
> +@end deftypefun

The ENOMEM and EMFILE descriptions are not really clear in this context.
Are these failures only possible with CLOSE_RANGE_UNSHARE?

It may make sense to mention the lack of emulation (so that callers have
to be aware of ENOSYS for the time being) and that the function is
specific to Linux.

Based on the description, it is not clear what happens if the range
contains closed descriptors.  Maybe mention that already-closed
descriptors are simply skipped?

> index c35f783e2a..e2a6fa763f 100644
> --- a/sysdeps/unix/sysv/linux/Versions
> +++ b/sysdeps/unix/sysv/linux/Versions
> @@ -169,6 +169,9 @@ libc {
>    }
>    GLIBC_2.32 {
>    }
> +  GLIBC_2.33 {
> +    close_range;
> +  }

Needs to be GLIBC_2.34 now.  Also the copyright year needs adjusting.

> diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> index c315cc5cb8..799c59512c 100644
> --- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> +++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> @@ -33,4 +33,15 @@
>     not detached and has not been joined.  */
>  extern __pid_t gettid (void) __THROW;
>  
> +/* Unshare the file descriptor table before closing file descriptors.  */
> +#define CLOSE_RANGE_UNSHARE     (1U << 1)

Needs to be indented.

Please include <linux/close_range.h> if available.  It's a separate
header so that we can use it.

I think if you do that, the consistency check won't add much value
because it can't really test anything.

> +/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
> +   are define by the CLOSE_RANGE prefix.  This function behaves like close
> +   on the range, but in a fail-safe where it will either fail and not close
> +   any file descriptor or close all of them.  Returns 0 on successor or -1
> +   for failure (and sets errno accordingly).  */
> +extern int close_range (unsigned int __fd, unsigned int __max_fd,
> +			int __flags) __THROW;
> +
>  #endif

Maybe add /* __USE_GNU */ to the #endif, given that it's now at a
distance from the #ifdef.

> diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
> new file mode 100644
> index 0000000000..131cf27c72
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
> @@ -0,0 +1,222 @@

> +#define NFDS 100
> +
> +static int
> +open_multiple_temp_files (void)
> +{
> +  /* Check if the temporary file descriptor has no no gaps.  */
> +  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
> +  for (int i = 1; i <= NFDS; i++)
> +    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
> +		  lowfd + i);
> +  return lowfd;
> +}

Okay, this ensures that there are no gaps.

> +
> +static void
> +close_range_test_common (int lowfd, unsigned int flags)
> +{
> +  const int maximum_fd = lowfd + NFDS;
> +  const int half_fd = maximum_fd / 2;
> +  const int gap_1 = maximum_fd - 8;

I think half_fd should be should be lowfd + NFDS / 2.

> +_Noreturn static int
> +close_range_test_fn (void *arg)
> +{
> +  int lowfd = (int) ((uintptr_t) arg);
> +  close_range_test_common (lowfd, 0);
> +  exit (EXIT_SUCCESS);
> +}
> +
> +/* Check if a clone_range on a subprocess created with CLONE_FILES close
> +   the shared file descriptor table entries in the parent.  */
> +static void
> +close_range_test_subprocess (void)
> +{
> +  struct support_descriptors *descrs = support_descriptors_list ();
> +
> +  /* Check if the temporary file descriptor has no no gaps.  */
> +  int lowfd = open_multiple_temp_files ();
> +
> +  enum { stack_size = 4096 };
> +  DEFINE_STACK (stack, stack_size);
> +  pid_t pid = xclone (close_range_test_fn, (void*) (uintptr_t) lowfd, stack,
> +		      stack_size, CLONE_FILES | SIGCHLD);

stack_size is too small, I think.  Future error checking (possible with
clone3) would lead to failures.

> +static void
> +close_range_unshare_test (void)
> +{
> +  struct support_descriptors *descrs1 = support_descriptors_list ();
> +
> +  /* Check if the temporary file descriptor has no no gaps.  */
> +  int lowfd = open_multiple_temp_files ();
> +
> +  struct support_descriptors *descrs2 = support_descriptors_list ();
> +
> +  enum { stack_size = 4096 };
> +  DEFINE_STACK (stack, stack_size);
> +  pid_t pid = xclone (close_range_unshare_test_fn, (void*) (uintptr_t) lowfd,
> +		      stack, stack_size, CLONE_FILES | SIGCHLD);

Likewise.

Thanks,
Florian
Christian Brauner March 9, 2021, 10:02 a.m. UTC | #2
On Tue, Mar 09, 2021 at 10:47:59AM +0100, Florian Weimer via Libc-alpha wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
> > diff --git a/manual/llio.texi b/manual/llio.texi
> > index c0a53e1a6e..ceb18ac89a 100644
> > --- a/manual/llio.texi
> > +++ b/manual/llio.texi
> > @@ -284,6 +284,44 @@ of trying to close its underlying file descriptor with @code{close}.
> >  This flushes any buffered output and updates the stream object to
> >  indicate that it is closed.
> >  
> > +@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
> > +@standards{Linux, unistd.h}
> > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
> > +@c This is a syscall for Linux v5.9.  There is no fallback emulation for
> > +@c older kernels.
> > +
> > +The function @code{clode_range} closes the file descriptor from @var{lowfd}
> > +to @var{maxfd} (inclusive).  This function is similar to call @code{close} in
> > +specified file descriptor range depending on the @var{flags}.
> > +
> > +The @var{flags} add options on how the files are closes.  Linux currently
> > +supports:.
> 
> Spurios “.” at end of line.
> 
> > +@vtable @code
> > +@item CLOSE_RANGE_UNSHARE
> > +Unshare the file descriptor table before closing file descriptors.
> > +@end vtable
> > +
> > +The normal return value from @code{close_range} is @math{0}; a value
> > +of @math{-1} is returned in case of failure.  The following @code{errno} error
> > +conditions are defined for this function:
> > +
> > +@table @code
> > +@item EINVAL
> > +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flags}
> > +is used.
> > +
> > +@item ENOMEM
> > +Either there is not enough memory for the operation, or the process is
> > +out of address space.
> > +
> > +@item EMFILE
> > +The process has too many files open.
> > +The maximum number of file descriptors is controlled by the
> > +@end table
> > +@end deftypefun
> 
> The ENOMEM and EMFILE descriptions are not really clear in this context.
> Are these failures only possible with CLOSE_RANGE_UNSHARE?

Hey, just to confirm: Yes, these errors can only occur with
CLOSE_RANGE_UNSHARE when the new file descriptor table is created.

Christian
Adhemerval Zanella Netto March 9, 2021, 5:53 p.m. UTC | #3
On 09/03/2021 06:47, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/manual/llio.texi b/manual/llio.texi
>> index c0a53e1a6e..ceb18ac89a 100644
>> --- a/manual/llio.texi
>> +++ b/manual/llio.texi
>> @@ -284,6 +284,44 @@ of trying to close its underlying file descriptor with @code{close}.
>>  This flushes any buffered output and updates the stream object to
>>  indicate that it is closed.
>>  
>> +@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
>> +@standards{Linux, unistd.h}
>> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
>> +@c This is a syscall for Linux v5.9.  There is no fallback emulation for
>> +@c older kernels.
>> +
>> +The function @code{clode_range} closes the file descriptor from @var{lowfd}

I will fix this 'clode_range' as well.

>> +to @var{maxfd} (inclusive).  This function is similar to call @code{close} in
>> +specified file descriptor range depending on the @var{flags}.
>> +
>> +The @var{flags} add options on how the files are closes.  Linux currently
>> +supports:.
> 
> Spurios “.” at end of line.

Ack.

> 
>> +@vtable @code
>> +@item CLOSE_RANGE_UNSHARE
>> +Unshare the file descriptor table before closing file descriptors.
>> +@end vtable
>> +
>> +The normal return value from @code{close_range} is @math{0}; a value
>> +of @math{-1} is returned in case of failure.  The following @code{errno} error
>> +conditions are defined for this function:
>> +
>> +@table @code
>> +@item EINVAL
>> +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flags}
>> +is used.
>> +
>> +@item ENOMEM
>> +Either there is not enough memory for the operation, or the process is
>> +out of address space.
>> +
>> +@item EMFILE
>> +The process has too many files open.
>> +The maximum number of file descriptors is controlled by the
>> +@end table
>> +@end deftypefun
> 
> The ENOMEM and EMFILE descriptions are not really clear in this context.
> Are these failures only possible with CLOSE_RANGE_UNSHARE?

Yes, as Christian noted.

> 
> It may make sense to mention the lack of emulation (so that callers have
> to be aware of ENOSYS for the time being) and that the function is
> specific to Linux.

Ack.

> 
> Based on the description, it is not clear what happens if the range
> contains closed descriptors.  Maybe mention that already-closed
> descriptors are simply skipped?
> 
>> index c35f783e2a..e2a6fa763f 100644
>> --- a/sysdeps/unix/sysv/linux/Versions
>> +++ b/sysdeps/unix/sysv/linux/Versions
>> @@ -169,6 +169,9 @@ libc {
>>    }
>>    GLIBC_2.32 {
>>    }
>> +  GLIBC_2.33 {
>> +    close_range;
>> +  }
> 
> Needs to be GLIBC_2.34 now.  Also the copyright year needs adjusting.



> 
>> diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>> index c315cc5cb8..799c59512c 100644
>> --- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>> +++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>> @@ -33,4 +33,15 @@
>>     not detached and has not been joined.  */
>>  extern __pid_t gettid (void) __THROW;
>>  
>> +/* Unshare the file descriptor table before closing file descriptors.  */I d
>> +#define CLOSE_RANGE_UNSHARE     (1U << 1)
> 
> Needs to be indented.
> 
> Please include <linux/close_range.h> if available.  It's a separate
> header so that we can use it.
> 
> I think if you do that, the consistency check won't add much value
> because it can't really test anything.

I am not very found of adding Linux headers, specially on installed
headers; but it seems we are already doing it for statx.h. I have 
added:

--
#ifdef __has_include
# if __has_include ("linux/close_range.h")
#  include "linux/close_range.h"
# endif
#endif
#ifndef CLOSE_RANGE_UNSHARE
# define CLOSE_RANGE_UNSHARE (1U << 1)
#endif
--

This is very recent kernel and it will take some time until we get
the minimum kernel near the one that starts to provide the close_range
flags (v5.9).  So I think the consistent check would be useful to
system that do not use use the latest kernel headers.

> 
>> +/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
>> +   are define by the CLOSE_RANGE prefix.  This function behaves like close
>> +   on the range, but in a fail-safe where it will either fail and not close
>> +   any file descriptor or close all of them.  Returns 0 on successor or -1
>> +   for failure (and sets errno accordingly).  */
>> +extern int close_range (unsigned int __fd, unsigned int __max_fd,
>> +			int __flags) __THROW;
>> +
>>  #endif
> 
> Maybe add /* __USE_GNU */ to the #endif, given that it's now at a
> distance from the #ifdef.

Ack.

> 
>> diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
>> new file mode 100644
>> index 0000000000..131cf27c72
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
>> @@ -0,0 +1,222 @@
> 
>> +#define NFDS 100
>> +
>> +static int
>> +open_multiple_temp_files (void)
>> +{
>> +  /* Check if the temporary file descriptor has no no gaps.  */
>> +  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
>> +  for (int i = 1; i <= NFDS; i++)
>> +    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
>> +		  lowfd + i);
>> +  return lowfd;
>> +}
> 
> Okay, this ensures that there are no gaps.
> 
>> +
>> +static void
>> +close_range_test_common (int lowfd, unsigned int flags)
>> +{
>> +  const int maximum_fd = lowfd + NFDS;
>> +  const int half_fd = maximum_fd / 2;
>> +  const int gap_1 = maximum_fd - 8;
> 
> I think half_fd should be should be lowfd + NFDS / 2.

Ack.

> 
>> +_Noreturn static int
>> +close_range_test_fn (void *arg)
>> +{
>> +  int lowfd = (int) ((uintptr_t) arg);
>> +  close_range_test_common (lowfd, 0);
>> +  exit (EXIT_SUCCESS);
>> +}
>> +
>> +/* Check if a clone_range on a subprocess created with CLONE_FILES close
>> +   the shared file descriptor table entries in the parent.  */
>> +static void
>> +close_range_test_subprocess (void)
>> +{
>> +  struct support_descriptors *descrs = support_descriptors_list ();
>> +
>> +  /* Check if the temporary file descriptor has no no gaps.  */
>> +  int lowfd = open_multiple_temp_files ();
>> +
>> +  enum { stack_size = 4096 };
>> +  DEFINE_STACK (stack, stack_size);
>> +  pid_t pid = xclone (close_range_test_fn, (void*) (uintptr_t) lowfd, stack,
>> +		      stack_size, CLONE_FILES | SIGCHLD);
> 
> stack_size is too small, I think.  Future error checking (possible with
> clone3) would lead to failures.

Ack, I will change to use a new way similar to the xsigaltstack.

> 
>> +static void
>> +close_range_unshare_test (void)
>> +{
>> +  struct support_descriptors *descrs1 = support_descriptors_list ();
>> +
>> +  /* Check if the temporary file descriptor has no no gaps.  */
>> +  int lowfd = open_multiple_temp_files ();
>> +
>> +  struct support_descriptors *descrs2 = support_descriptors_list ();
>> +
>> +  enum { stack_size = 4096 };
>> +  DEFINE_STACK (stack, stack_size);
>> +  pid_t pid = xclone (close_range_unshare_test_fn, (void*) (uintptr_t) lowfd,
>> +		      stack, stack_size, CLONE_FILES | SIGCHLD);
> 
> Likewise.
> 
> Thanks,
> Florian
>
Florian Weimer March 9, 2021, 6:30 p.m. UTC | #4
* Adhemerval Zanella:

>>> diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>>> index c315cc5cb8..799c59512c 100644
>>> --- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>>> +++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>>> @@ -33,4 +33,15 @@
>>>     not detached and has not been joined.  */
>>>  extern __pid_t gettid (void) __THROW;
>>>  
>>> +/* Unshare the file descriptor table before closing file descriptors.  */I d
>>> +#define CLOSE_RANGE_UNSHARE     (1U << 1)
>> 
>> Needs to be indented.
>> 
>> Please include <linux/close_range.h> if available.  It's a separate
>> header so that we can use it.
>> 
>> I think if you do that, the consistency check won't add much value
>> because it can't really test anything.
>
> I am not very found of adding Linux headers, specially on installed
> headers; but it seems we are already doing it for statx.h. I have 
> added:
>
> --
> #ifdef __has_include
> # if __has_include ("linux/close_range.h")
> #  include "linux/close_range.h"
> # endif
> #endif
> #ifndef CLOSE_RANGE_UNSHARE
> # define CLOSE_RANGE_UNSHARE (1U << 1)
> #endif
> --
>
> This is very recent kernel and it will take some time until we get
> the minimum kernel near the one that starts to provide the close_range
> flags (v5.9).  So I think the consistent check would be useful to
> system that do not use use the latest kernel headers.

My point was that if the kernel headers are too old, there is nothing to
check, and if they contain CLOSE_RANGE_UNSHARE, the built-in definition
is not checked either.  But then the risk of divergence is greatly
reduced with this approach.

Thanks,
Florian
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index 0820984547..9e829841f6 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,8 @@  Major new features:
   The 32-bit RISC-V port requires at least Linux 5.4, GCC 7.1 and binutils
   2.28.
 
+* On Linux, the close_range function has been added.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/include/bits/unistd_ext.h b/include/bits/unistd_ext.h
new file mode 100644
index 0000000000..277be05746
--- /dev/null
+++ b/include/bits/unistd_ext.h
@@ -0,0 +1,6 @@ 
+#include_next <bits/unistd_ext.h>
+
+#ifndef _ISOMAC
+extern int __close_range (unsigned int lowfd, unsigned int highfd, int flags);
+libc_hidden_proto (__close_range);
+#endif
diff --git a/manual/llio.texi b/manual/llio.texi
index c0a53e1a6e..ceb18ac89a 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -284,6 +284,44 @@  of trying to close its underlying file descriptor with @code{close}.
 This flushes any buffered output and updates the stream object to
 indicate that it is closed.
 
+@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
+@standards{Linux, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
+@c This is a syscall for Linux v5.9.  There is no fallback emulation for
+@c older kernels.
+
+The function @code{clode_range} closes the file descriptor from @var{lowfd}
+to @var{maxfd} (inclusive).  This function is similar to call @code{close} in
+specified file descriptor range depending on the @var{flags}.
+
+The @var{flags} add options on how the files are closes.  Linux currently
+supports:.
+
+@vtable @code
+@item CLOSE_RANGE_UNSHARE
+Unshare the file descriptor table before closing file descriptors.
+@end vtable
+
+The normal return value from @code{close_range} is @math{0}; a value
+of @math{-1} is returned in case of failure.  The following @code{errno} error
+conditions are defined for this function:
+
+@table @code
+@item EINVAL
+The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flags}
+is used.
+
+@item ENOMEM
+Either there is not enough memory for the operation, or the process is
+out of address space.
+
+@item EMFILE
+The process has too many files open.
+The maximum number of file descriptors is controlled by the
+@end table
+@end deftypefun
+
+
 @node I/O Primitives
 @section Input and Output Primitives
 
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 09604e128b..e06c2a1f0d 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -61,7 +61,7 @@  sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
 		   timerfd_gettime timerfd_settime prctl \
 		   process_vm_readv process_vm_writev clock_adjtime \
-		   time64-support pselect32
+		   time64-support pselect32 close_range
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
@@ -103,7 +103,8 @@  tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
 	 tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \
 	 test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \
 	 tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \
-	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux
+	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux \
+	 tst-close_range
 tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc
 
 CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
@@ -177,6 +178,14 @@  $(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py
 	  < /dev/null > $@ 2>&1; $(evaluate-test)
 $(objpfx)tst-mman-consts.out: $(sysdeps-linux-python-deps)
 
+tests-special += $(objpfx)tst-close_range-consts.out
+$(objpfx)tst-close_range-consts.out: ../sysdeps/unix/sysv/linux/tst-close_range-consts.py
+	$(sysdeps-linux-python) \
+	../sysdeps/unix/sysv/linux/tst-close_range-consts.py \
+	    $(sysdeps-linux-python-cc) \
+	< /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-close_range-consts.out: $(sysdeps-linux-python-deps)
+
 $(objpfx)tst-gettid: $(shared-thread-library)
 $(objpfx)tst-gettid-kill: $(shared-thread-library)
 $(objpfx)tst-tgkill: $(shared-thread-library)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index c35f783e2a..e2a6fa763f 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -169,6 +169,9 @@  libc {
   }
   GLIBC_2.32 {
   }
+  GLIBC_2.33 {
+    close_range;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 4cc1c6a591..a52decb822 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2160,6 +2160,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 26ad9845e4..ed085c9b3c 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2242,6 +2242,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bb9dfd4daf..88a17c2fdf 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1920,6 +1920,7 @@  GLIBC_2.32 wprintf F
 GLIBC_2.32 write F
 GLIBC_2.32 writev F
 GLIBC_2.32 wscanf F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 9ab3924888..a690962068 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -141,6 +141,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
index c315cc5cb8..799c59512c 100644
--- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
+++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
@@ -33,4 +33,15 @@ 
    not detached and has not been joined.  */
 extern __pid_t gettid (void) __THROW;
 
+/* Unshare the file descriptor table before closing file descriptors.  */
+#define CLOSE_RANGE_UNSHARE     (1U << 1)
+
+/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
+   are define by the CLOSE_RANGE prefix.  This function behaves like close
+   on the range, but in a fail-safe where it will either fail and not close
+   any file descriptor or close all of them.  Returns 0 on successor or -1
+   for failure (and sets errno accordingly).  */
+extern int close_range (unsigned int __fd, unsigned int __max_fd,
+			int __flags) __THROW;
+
 #endif
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 14a84dac8f..d37882413c 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2104,6 +2104,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 5c8502f3d3..61450e47d5 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2063,6 +2063,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 4f0d3c1eb5..672ff8a002 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2229,6 +2229,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e3b345b803..53e53005e9 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2095,6 +2095,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c4891479d3..cc0d93b381 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2175,6 +2175,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 143b0163b4..b4acf52c41 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2155,6 +2155,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b2295f1937..fadbf99d4b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2146,6 +2146,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index aa9c6a4dca..c456ebcea3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2152,6 +2152,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5939588ad5..5ed54e7c94 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2146,6 +2146,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 92556c4237..67b611ef6d 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2193,6 +2193,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 26c93dff05..ed0f239cd5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2202,6 +2202,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index c2ca00709e..a4b9900036 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2065,6 +2065,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0ea50dc851..e5d666dab3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2355,6 +2355,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 0263e284d4..f8c34aca7c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -595,6 +595,7 @@  GLIBC_2.33 clock_nanosleep F
 GLIBC_2.33 clock_settime F
 GLIBC_2.33 clone F
 GLIBC_2.33 close F
+GLIBC_2.33 close_range F
 GLIBC_2.33 closedir F
 GLIBC_2.33 closelog F
 GLIBC_2.33 confstr F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 1626c5351f..6042d42aba 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2122,6 +2122,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index a66426eb4d..46d2de3030 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2200,6 +2200,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index ab351873ae..9fda4babba 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2101,6 +2101,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d36f228192..110f7ebf22 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2067,6 +2067,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 59b4313280..1b31685a24 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2191,6 +2191,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 266dcdfa08..9ad88bf7b3 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2118,6 +2118,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index 01ec2bfa95..53575669c7 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -101,3 +101,4 @@  pkey_alloc	EXTRA	pkey_alloc	i:ii	pkey_alloc
 pkey_free	EXTRA	pkey_free	i:i	pkey_free
 gettid          EXTRA   gettid          Ei:     __gettid	gettid
 tgkill          EXTRA   tgkill          i:iii   __tgkill	tgkill
+close_range     EXTRA   close_range     i:iii   __close_range   close_range
diff --git a/sysdeps/unix/sysv/linux/tst-close_range-consts.py b/sysdeps/unix/sysv/linux/tst-close_range-consts.py
new file mode 100644
index 0000000000..3a0d4423e8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range-consts.py
@@ -0,0 +1,49 @@ 
+#!/usr/bin/python3
+# Test that glibc's unistd_ext.h constants match the kernel's.
+# Copyright (C) 2020 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
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description="Test that glibc's unistd_ext.h constants match "
+                    "the kernel's.")
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+    linux_version_glibc = (5, 9)
+    sys.exit(glibcextract.compare_macro_consts(
+        '#define _GNU_SOURCE 1\n'
+        '#include <unistd.h>\n',
+        '#define _GNU_SOURCE 1\n'
+        '#include <linux/close_range.h>\n',
+        args.cc,
+        'CLOSE_RANGE_.*',
+        None,
+        linux_version_glibc > linux_version_headers,
+        linux_version_headers > linux_version_glibc))
+
+if __name__ == '__main__':
+    main()
diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
new file mode 100644
index 0000000000..131cf27c72
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range.c
@@ -0,0 +1,222 @@ 
+/* Test for the close_range system call.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <array_length.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+#include <support/xsched.h>
+#include <support/xunistd.h>
+
+#define NFDS 100
+
+static int
+open_multiple_temp_files (void)
+{
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+  for (int i = 1; i <= NFDS; i++)
+    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
+		  lowfd + i);
+  return lowfd;
+}
+
+static void
+close_range_test_max_upper_limit (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  int lowfd = open_multiple_temp_files ();
+
+  {
+    int r = close_range (lowfd, ~0U, 0);
+    if (r == -1 && errno == ENOSYS)
+      FAIL_UNSUPPORTED ("close_range not supported");
+    TEST_COMPARE (r, 0);
+  }
+
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+static void
+close_range_test_common (int lowfd, unsigned int flags)
+{
+  const int maximum_fd = lowfd + NFDS;
+  const int half_fd = maximum_fd / 2;
+  const int gap_1 = maximum_fd - 8;
+
+  /* Close half of the descriptors and check result.  */
+  TEST_COMPARE (close_range (lowfd, half_fd, flags), 0);
+  for (int i = lowfd; i <= half_fd; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = half_fd + 1; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (lowfd + 57);
+  xclose (lowfd + 78);
+  xclose (lowfd + 81);
+  xclose (lowfd + 82);
+  xclose (lowfd + 84);
+  xclose (lowfd + 90);
+
+  TEST_COMPARE (close_range (half_fd + 1, gap_1, flags), 0);
+  for (int i = half_fd + 1; i < gap_1; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = gap_1 + 1; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  /* Close the remaining but the last one.  */
+  TEST_COMPARE (close_range (gap_1 + 1, maximum_fd - 1, flags), 0);
+  for (int i = gap_1 + 1; i < maximum_fd - 1; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  TEST_VERIFY (fcntl (maximum_fd, F_GETFL) > -1);
+
+  /* Close the last one.  */
+  TEST_COMPARE (close_range (maximum_fd, maximum_fd, flags), 0);
+  TEST_COMPARE (fcntl (maximum_fd, F_GETFL), -1);
+  TEST_COMPARE (errno, EBADF);
+}
+
+/* Basic tests: check if the syscall close ranges with and without gaps.  */
+static void
+close_range_test (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = open_multiple_temp_files ();
+
+  close_range_test_common (lowfd, 0);
+
+  /* Double check by check the /proc.  */
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+_Noreturn static int
+close_range_test_fn (void *arg)
+{
+  int lowfd = (int) ((uintptr_t) arg);
+  close_range_test_common (lowfd, 0);
+  exit (EXIT_SUCCESS);
+}
+
+/* Check if a clone_range on a subprocess created with CLONE_FILES close
+   the shared file descriptor table entries in the parent.  */
+static void
+close_range_test_subprocess (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = open_multiple_temp_files ();
+
+  enum { stack_size = 4096 };
+  DEFINE_STACK (stack, stack_size);
+  pid_t pid = xclone (close_range_test_fn, (void*) (uintptr_t) lowfd, stack,
+		      stack_size, CLONE_FILES | SIGCHLD);
+  TEST_VERIFY_EXIT (pid > 0);
+  int status;
+  xwaitpid (pid, &status, 0);
+  TEST_VERIFY (WIFEXITED (status));
+  TEST_COMPARE (WEXITSTATUS(status), 0);
+
+  for (int i = lowfd; i < NFDS; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) < 0);
+
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+
+_Noreturn static int
+close_range_unshare_test_fn (void *arg)
+{
+  int lowfd = (int) ((uintptr_t) arg);
+  close_range_test_common (lowfd, CLOSE_RANGE_UNSHARE);
+  exit (EXIT_SUCCESS);
+}
+
+/* Check if a close_range with CLOSE_RANGE_UNSHARE issued from a subprocess
+   created with CLONE_FILES does not close the parent file descriptor list.  */
+static void
+close_range_unshare_test (void)
+{
+  struct support_descriptors *descrs1 = support_descriptors_list ();
+
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = open_multiple_temp_files ();
+
+  struct support_descriptors *descrs2 = support_descriptors_list ();
+
+  enum { stack_size = 4096 };
+  DEFINE_STACK (stack, stack_size);
+  pid_t pid = xclone (close_range_unshare_test_fn, (void*) (uintptr_t) lowfd,
+		      stack, stack_size, CLONE_FILES | SIGCHLD);
+  TEST_VERIFY_EXIT (pid > 0);
+  int status;
+  xwaitpid (pid, &status, 0);
+  TEST_VERIFY (WIFEXITED (status));
+  TEST_COMPARE (WEXITSTATUS(status), 0);
+
+  for (int i = 0; i < NFDS; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  support_descriptors_check (descrs2);
+  support_descriptors_free (descrs2);
+
+  TEST_COMPARE (close_range (lowfd, lowfd + NFDS, 0), 0);
+
+  support_descriptors_check (descrs1);
+  support_descriptors_free (descrs1);
+}
+
+static int
+do_test (void)
+{
+  close_range_test_max_upper_limit ();
+  close_range_test ();
+  close_range_test_subprocess ();
+  close_range_unshare_test ();
+
+  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 4fff61818b..5089a21981 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2076,6 +2076,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 102ed47a9c..c3db0fc7ca 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2173,6 +2173,7 @@  GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F