svn commit: r363879 - in stable/12: include lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys tests/sys/file

Kyle Evans kevans at FreeBSD.org
Wed Aug 5 03:54:02 UTC 2020


Author: kevans
Date: Wed Aug  5 03:53:57 2020
New Revision: 363879
URL: https://svnweb.freebsd.org/changeset/base/363879

Log:
  MFC r359836-r359837, r359891, r360236-r360237: close_range(2)
  
  This commit diverges from our usual procedure of committing generated files
  separately because the original commit, r359836, conflated userland use (in
  tests) with the implementation.
  
  __FreeBSD_version was already bumped ~15 hours prior to this MFC, 1201522
  marks the introduction of close_range.
  
  CPython will use this syscall for some pretty sizable performance gains.
  
  r359836:
  Implement a close_range(2) syscall
  
  close_range(min, max, flags) allows for a range of descriptors to be
  closed. The Python folk have indicated that they would much prefer this
  interface to closefrom(2), as the case may be that they/someone have special
  fds dup'd to higher in the range and they can't necessarily closefrom(min)
  because they don't want to hit the upper range, but relocating them to lower
  isn't necessarily feasible.
  
  sys_closefrom has been rewritten to use kern_close_range() using ~0U to
  indicate closing to the end of the range. This was chosen rather than
  requiring callers of kern_close_range() to hold FILEDESC_SLOCK across the
  call to kern_close_range for simplicity.
  
  The flags argument of close_range(2) is currently unused, so any flags set
  is currently EINVAL. It was added to the interface in Linux so that future
  flags could be added for, e.g., "halt on first error" and things of this
  nature.
  
  This patch is based on a syscall of the same design that is expected to be
  merged into Linux.
  
  r359837:
  sysent: re-roll after introduction of close_range in r359836
  
  r359891:
  close_range/closefrom: fix regression from close_range introduction
  
  close_range will clamp the range between [0, fdp->fd_lastfile], but failed
  to take into account that fdp->fd_lastfile can become -1 if all fds are
  closed. =-( In this scenario, just return because there's nothing further we
  can do at the moment.
  
  Add a test case for this, fork() and simply closefrom(0) twice in the child;
  on the second invocation, fdp->fd_lastfile == -1 and will trigger a panic
  before this change.
  
  r360236:
  close_range(2): use newly assigned AUE_CLOSERANGE
  
  r360237:
  sysent: re-roll after 360236 (AUE_CLOSERANGE used)

Modified:
  stable/12/include/unistd.h
  stable/12/lib/libc/sys/Makefile.inc
  stable/12/lib/libc/sys/Symbol.map
  stable/12/lib/libc/sys/closefrom.2
  stable/12/sys/compat/freebsd32/freebsd32_syscall.h
  stable/12/sys/compat/freebsd32/freebsd32_syscalls.c
  stable/12/sys/compat/freebsd32/freebsd32_sysent.c
  stable/12/sys/compat/freebsd32/freebsd32_systrace_args.c
  stable/12/sys/compat/freebsd32/syscalls.master
  stable/12/sys/kern/capabilities.conf
  stable/12/sys/kern/init_sysent.c
  stable/12/sys/kern/kern_descrip.c
  stable/12/sys/kern/syscalls.c
  stable/12/sys/kern/syscalls.master
  stable/12/sys/kern/systrace_args.c
  stable/12/sys/sys/syscall.h
  stable/12/sys/sys/syscall.mk
  stable/12/sys/sys/syscallsubr.h
  stable/12/sys/sys/sysproto.h
  stable/12/tests/sys/file/closefrom_test.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/include/unistd.h
==============================================================================
--- stable/12/include/unistd.h	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/include/unistd.h	Wed Aug  5 03:53:57 2020	(r363879)
@@ -494,6 +494,7 @@ struct crypt_data {
 int	 acct(const char *);
 int	 async_daemon(void);
 int	 check_utility_compat(const char *);
+int	 close_range(unsigned int, unsigned int, int);
 const char *
 	 crypt_get_format(void);
 char	*crypt_r(const char *, const char *, struct crypt_data *);

Modified: stable/12/lib/libc/sys/Makefile.inc
==============================================================================
--- stable/12/lib/libc/sys/Makefile.inc	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/lib/libc/sys/Makefile.inc	Wed Aug  5 03:53:57 2020	(r363879)
@@ -372,6 +372,7 @@ MLINKS+=chown.2 fchown.2 \
 	chown.2 lchown.2
 MLINKS+=clock_gettime.2 clock_getres.2 \
 	clock_gettime.2 clock_settime.2
+MLINKS+=closefrom.2 close_range.2
 MLINKS+=nanosleep.2 clock_nanosleep.2
 MLINKS+=cpuset.2 cpuset_getid.2 \
 	cpuset.2 cpuset_setid.2

Modified: stable/12/lib/libc/sys/Symbol.map
==============================================================================
--- stable/12/lib/libc/sys/Symbol.map	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/lib/libc/sys/Symbol.map	Wed Aug  5 03:53:57 2020	(r363879)
@@ -402,6 +402,7 @@ FBSD_1.5 {
 };
 
 FBSD_1.6 {
+	close_range;
 	fhlink;
 	fhlinkat;
 	fhreadlink;

Modified: stable/12/lib/libc/sys/closefrom.2
==============================================================================
--- stable/12/lib/libc/sys/closefrom.2	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/lib/libc/sys/closefrom.2	Wed Aug  5 03:53:57 2020	(r363879)
@@ -25,11 +25,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 12, 2009
+.Dd April 12, 2020
 .Dt CLOSEFROM 2
 .Os
 .Sh NAME
-.Nm closefrom
+.Nm closefrom ,
+.Nm close_range
 .Nd delete open file descriptors
 .Sh LIBRARY
 .Lb libc
@@ -37,6 +38,8 @@
 .In unistd.h
 .Ft void
 .Fn closefrom "int lowfd"
+.Ft int
+.Fn close_range "u_int lowfd" "u_int highfd" "int flags"
 .Sh DESCRIPTION
 The
 .Fn closefrom
@@ -44,6 +47,40 @@ system call deletes all open file descriptors greater 
 .Fa lowfd
 from the per-process object reference table.
 Any errors encountered while closing file descriptors are ignored.
+.Pp
+The
+.Fn close_range
+system call deletes all open file descriptors between
+.Fa lowfd
+and
+.Fa highfd
+inclusive, clamped to the range of open file descriptors.
+Any errors encountered while closing file descriptors are ignored.
+There are currently no defined
+.Fa flags .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn close_range
+returns a value
+of 0.
+Otherwise, a value of -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn close_range
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa highfd
+argument is lower than the
+.Fa lowfd
+argument.
+.It Bq Er EINVAL
+An invalid flag was set.
+.El
 .Sh SEE ALSO
 .Xr close 2
 .Sh HISTORY

Modified: stable/12/sys/compat/freebsd32/freebsd32_syscall.h
==============================================================================
--- stable/12/sys/compat/freebsd32/freebsd32_syscall.h	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/compat/freebsd32/freebsd32_syscall.h	Wed Aug  5 03:53:57 2020	(r363879)
@@ -495,4 +495,5 @@
 #define	FREEBSD32_SYS_fhlinkat	566
 #define	FREEBSD32_SYS_fhreadlink	567
 #define	FREEBSD32_SYS_freebsd32___sysctlbyname	570
-#define	FREEBSD32_SYS_MAXSYSCALL	571
+#define	FREEBSD32_SYS_close_range	575
+#define	FREEBSD32_SYS_MAXSYSCALL	576

Modified: stable/12/sys/compat/freebsd32/freebsd32_syscalls.c
==============================================================================
--- stable/12/sys/compat/freebsd32/freebsd32_syscalls.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/compat/freebsd32/freebsd32_syscalls.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -607,4 +607,9 @@ const char *freebsd32_syscallnames[] = {
 	"#568",			/* 568 = funlinkat */
 	"#569",			/* 569 = copy_file_range */
 	"freebsd32___sysctlbyname",			/* 570 = freebsd32___sysctlbyname */
+	"#571",			/* 571 = shm_open2 */
+	"#572",			/* 572 = shm_rename */
+	"#573",			/* 573 = sigfastblock */
+	"#574",			/* 574 = __realpathat */
+	"close_range",			/* 575 = close_range */
 };

Modified: stable/12/sys/compat/freebsd32/freebsd32_sysent.c
==============================================================================
--- stable/12/sys/compat/freebsd32/freebsd32_sysent.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/compat/freebsd32/freebsd32_sysent.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -654,4 +654,9 @@ struct sysent freebsd32_sysent[] = {
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 568 = funlinkat */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 569 = copy_file_range */
 	{ AS(freebsd32___sysctlbyname_args), (sy_call_t *)freebsd32___sysctlbyname, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 570 = freebsd32___sysctlbyname */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 571 = shm_open2 */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 572 = shm_rename */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 573 = sigfastblock */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 574 = __realpathat */
+	{ AS(close_range_args), (sy_call_t *)sys_close_range, AUE_CLOSERANGE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 575 = close_range */
 };

Modified: stable/12/sys/compat/freebsd32/freebsd32_systrace_args.c
==============================================================================
--- stable/12/sys/compat/freebsd32/freebsd32_systrace_args.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/compat/freebsd32/freebsd32_systrace_args.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -3322,6 +3322,15 @@ systrace_args(int sysnum, void *params, uint64_t *uarg
 		*n_args = 6;
 		break;
 	}
+	/* close_range */
+	case 575: {
+		struct close_range_args *p = params;
+		uarg[0] = p->lowfd; /* u_int */
+		uarg[1] = p->highfd; /* u_int */
+		iarg[2] = p->flags; /* int */
+		*n_args = 3;
+		break;
+	}
 	default:
 		*n_args = 0;
 		break;
@@ -8942,6 +8951,22 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *d
 			break;
 		};
 		break;
+	/* close_range */
+	case 575:
+		switch(ndx) {
+		case 0:
+			p = "u_int";
+			break;
+		case 1:
+			p = "u_int";
+			break;
+		case 2:
+			p = "int";
+			break;
+		default:
+			break;
+		};
+		break;
 	default:
 		break;
 	};
@@ -10813,6 +10838,11 @@ systrace_return_setargdesc(int sysnum, int ndx, char *
 		break;
 	/* freebsd32___sysctlbyname */
 	case 570:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* close_range */
+	case 575:
 		if (ndx == 0 || ndx == 1)
 			p = "int";
 		break;

Modified: stable/12/sys/compat/freebsd32/syscalls.master
==============================================================================
--- stable/12/sys/compat/freebsd32/syscalls.master	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/compat/freebsd32/syscalls.master	Wed Aug  5 03:53:57 2020	(r363879)
@@ -1132,5 +1132,11 @@
 570	AUE_SYSCTL	STD	{ int freebsd32___sysctlbyname(const char *name, \
 				    size_t namelen, void *old, uint32_t *oldlenp, \
 				    void *new, size_t newlen); }
+571	AUE_NULL	UNIMPL	shm_open2
+572	AUE_NULL	UNIMPL	shm_rename
+573	AUE_NULL	UNIMPL	sigfastblock
+574	AUE_NULL	UNIMPL	__realpathat
+575	AUE_CLOSERANGE	NOPROTO	{ int close_range(u_int lowfd, u_int highfd, \
+				    int flags); }
 
 ; vim: syntax=off

Modified: stable/12/sys/kern/capabilities.conf
==============================================================================
--- stable/12/sys/kern/capabilities.conf	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/kern/capabilities.conf	Wed Aug  5 03:53:57 2020	(r363879)
@@ -131,6 +131,7 @@ clock_gettime
 ## Always allow file descriptor close(2).
 ##
 close
+close_range
 closefrom
 
 ##

Modified: stable/12/sys/kern/init_sysent.c
==============================================================================
--- stable/12/sys/kern/init_sysent.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/kern/init_sysent.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -620,4 +620,9 @@ struct sysent sysent[] = {
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 568 = funlinkat */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 569 = copy_file_range */
 	{ AS(__sysctlbyname_args), (sy_call_t *)sys___sysctlbyname, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 570 = __sysctlbyname */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 571 = shm_open2 */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 572 = shm_rename */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 573 = sigfastblock */
+	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 574 = __realpathat */
+	{ AS(close_range_args), (sy_call_t *)sys_close_range, AUE_CLOSERANGE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 575 = close_range */
 };

Modified: stable/12/sys/kern/kern_descrip.c
==============================================================================
--- stable/12/sys/kern/kern_descrip.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/kern/kern_descrip.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -1263,6 +1263,65 @@ kern_close(struct thread *td, int fd)
 	return (closefp(fdp, fd, fp, td, 1));
 }
 
+int
+kern_close_range(struct thread *td, u_int lowfd, u_int highfd)
+{
+	struct filedesc *fdp;
+	int fd, ret;
+
+	ret = 0;
+	fdp = td->td_proc->p_fd;
+	FILEDESC_SLOCK(fdp);
+
+	/*
+	 * Check this prior to clamping; closefrom(3) with only fd 0, 1, and 2
+	 * open should not be a usage error.  From a close_range() perspective,
+	 * close_range(3, ~0U, 0) in the same scenario should also likely not
+	 * be a usage error as all fd above 3 are in-fact already closed.
+	 */
+	if (highfd < lowfd) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	/*
+	 * If fdp->fd_lastfile == -1, we're dealing with either a fresh file
+	 * table or one in which every fd has been closed.  Just return
+	 * successful; there's nothing left to do.
+	 */
+	if (fdp->fd_lastfile == -1)
+		goto out;
+	/* Clamped to [lowfd, fd_lastfile] */
+	highfd = MIN(highfd, fdp->fd_lastfile);
+	for (fd = lowfd; fd <= highfd; fd++) {
+		if (fdp->fd_ofiles[fd].fde_file != NULL) {
+			FILEDESC_SUNLOCK(fdp);
+			(void)kern_close(td, fd);
+			FILEDESC_SLOCK(fdp);
+		}
+	}
+out:
+	FILEDESC_SUNLOCK(fdp);
+	return (ret);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct close_range_args {
+	u_int	lowfd;
+	u_int	highfd;
+	int	flags;
+};
+#endif
+int
+sys_close_range(struct thread *td, struct close_range_args *uap)
+{
+
+	/* No flags currently defined */
+	if (uap->flags != 0)
+		return (EINVAL);
+	return (kern_close_range(td, uap->lowfd, uap->highfd));
+}
+
 /*
  * Close open file descriptors.
  */
@@ -1275,28 +1334,16 @@ struct closefrom_args {
 int
 sys_closefrom(struct thread *td, struct closefrom_args *uap)
 {
-	struct filedesc *fdp;
-	int fd;
+	u_int lowfd;
 
-	fdp = td->td_proc->p_fd;
 	AUDIT_ARG_FD(uap->lowfd);
 
 	/*
 	 * Treat negative starting file descriptor values identical to
 	 * closefrom(0) which closes all files.
 	 */
-	if (uap->lowfd < 0)
-		uap->lowfd = 0;
-	FILEDESC_SLOCK(fdp);
-	for (fd = uap->lowfd; fd <= fdp->fd_lastfile; fd++) {
-		if (fdp->fd_ofiles[fd].fde_file != NULL) {
-			FILEDESC_SUNLOCK(fdp);
-			(void)kern_close(td, fd);
-			FILEDESC_SLOCK(fdp);
-		}
-	}
-	FILEDESC_SUNLOCK(fdp);
-	return (0);
+	lowfd = MAX(0, uap->lowfd);
+	return (kern_close_range(td, lowfd, ~0U));
 }
 
 #if defined(COMPAT_43)

Modified: stable/12/sys/kern/syscalls.c
==============================================================================
--- stable/12/sys/kern/syscalls.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/kern/syscalls.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -577,4 +577,9 @@ const char *syscallnames[] = {
 	"#568",			/* 568 = funlinkat */
 	"#569",			/* 569 = copy_file_range */
 	"__sysctlbyname",			/* 570 = __sysctlbyname */
+	"#571",			/* 571 = shm_open2 */
+	"#572",			/* 572 = shm_rename */
+	"#573",			/* 573 = sigfastblock */
+	"#574",			/* 574 = __realpathat */
+	"close_range",			/* 575 = close_range */
 };

Modified: stable/12/sys/kern/syscalls.master
==============================================================================
--- stable/12/sys/kern/syscalls.master	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/kern/syscalls.master	Wed Aug  5 03:53:57 2020	(r363879)
@@ -1380,6 +1380,17 @@
 		    size_t newlen \
 		); \
 	}
+571	AUE_NULL	UNIMPL	shm_open2
+572	AUE_NULL	UNIMPL	shm_rename
+573	AUE_NULL	UNIMPL	sigfastblock
+574	AUE_NULL	UNIMPL	__realpathat
+575	AUE_CLOSERANGE	STD { \
+		int close_range( \
+		    u_int lowfd, \
+		    u_int highfd, \
+		    int flags \
+		); \
+	}
 
 
 ; Please copy any additions and changes to the following compatability tables:

Modified: stable/12/sys/kern/systrace_args.c
==============================================================================
--- stable/12/sys/kern/systrace_args.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/kern/systrace_args.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -3314,6 +3314,15 @@ systrace_args(int sysnum, void *params, uint64_t *uarg
 		*n_args = 6;
 		break;
 	}
+	/* close_range */
+	case 575: {
+		struct close_range_args *p = params;
+		uarg[0] = p->lowfd; /* u_int */
+		uarg[1] = p->highfd; /* u_int */
+		iarg[2] = p->flags; /* int */
+		*n_args = 3;
+		break;
+	}
 	default:
 		*n_args = 0;
 		break;
@@ -8847,6 +8856,22 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *d
 			break;
 		};
 		break;
+	/* close_range */
+	case 575:
+		switch(ndx) {
+		case 0:
+			p = "u_int";
+			break;
+		case 1:
+			p = "u_int";
+			break;
+		case 2:
+			p = "int";
+			break;
+		default:
+			break;
+		};
+		break;
 	default:
 		break;
 	};
@@ -10745,6 +10770,11 @@ systrace_return_setargdesc(int sysnum, int ndx, char *
 		break;
 	/* __sysctlbyname */
 	case 570:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* close_range */
+	case 575:
 		if (ndx == 0 || ndx == 1)
 			p = "int";
 		break;

Modified: stable/12/sys/sys/syscall.h
==============================================================================
--- stable/12/sys/sys/syscall.h	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/sys/syscall.h	Wed Aug  5 03:53:57 2020	(r363879)
@@ -504,4 +504,5 @@
 #define	SYS_fhlinkat	566
 #define	SYS_fhreadlink	567
 #define	SYS___sysctlbyname	570
-#define	SYS_MAXSYSCALL	571
+#define	SYS_close_range	575
+#define	SYS_MAXSYSCALL	576

Modified: stable/12/sys/sys/syscall.mk
==============================================================================
--- stable/12/sys/sys/syscall.mk	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/sys/syscall.mk	Wed Aug  5 03:53:57 2020	(r363879)
@@ -409,4 +409,5 @@ MIASM =  \
 	fhlink.o \
 	fhlinkat.o \
 	fhreadlink.o \
-	__sysctlbyname.o
+	__sysctlbyname.o \
+	close_range.o

Modified: stable/12/sys/sys/syscallsubr.h
==============================================================================
--- stable/12/sys/sys/syscallsubr.h	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/sys/syscallsubr.h	Wed Aug  5 03:53:57 2020	(r363879)
@@ -93,6 +93,7 @@ int	kern_clock_nanosleep(struct thread *td, clockid_t 
 	    const struct timespec *rqtp, struct timespec *rmtp);
 int	kern_clock_settime(struct thread *td, clockid_t clock_id,
 	    struct timespec *ats);
+int	kern_close_range(struct thread *td, u_int lowfd, u_int highfd);
 int	kern_close(struct thread *td, int fd);
 int	kern_connectat(struct thread *td, int dirfd, int fd,
 	    struct sockaddr *sa);

Modified: stable/12/sys/sys/sysproto.h
==============================================================================
--- stable/12/sys/sys/sysproto.h	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/sys/sys/sysproto.h	Wed Aug  5 03:53:57 2020	(r363879)
@@ -1798,6 +1798,11 @@ struct __sysctlbyname_args {
 	char new_l_[PADL_(void *)]; void * new; char new_r_[PADR_(void *)];
 	char newlen_l_[PADL_(size_t)]; size_t newlen; char newlen_r_[PADR_(size_t)];
 };
+struct close_range_args {
+	char lowfd_l_[PADL_(u_int)]; u_int lowfd; char lowfd_r_[PADR_(u_int)];
+	char highfd_l_[PADL_(u_int)]; u_int highfd; char highfd_r_[PADR_(u_int)];
+	char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
 int	nosys(struct thread *, struct nosys_args *);
 void	sys_sys_exit(struct thread *, struct sys_exit_args *);
 int	sys_fork(struct thread *, struct fork_args *);
@@ -2183,6 +2188,7 @@ int	sys_fhlink(struct thread *, struct fhlink_args *);
 int	sys_fhlinkat(struct thread *, struct fhlinkat_args *);
 int	sys_fhreadlink(struct thread *, struct fhreadlink_args *);
 int	sys___sysctlbyname(struct thread *, struct __sysctlbyname_args *);
+int	sys_close_range(struct thread *, struct close_range_args *);
 
 #ifdef COMPAT_43
 
@@ -3085,6 +3091,7 @@ int	freebsd11_mknodat(struct thread *, struct freebsd1
 #define	SYS_AUE_fhlinkat	AUE_NULL
 #define	SYS_AUE_fhreadlink	AUE_NULL
 #define	SYS_AUE___sysctlbyname	AUE_SYSCTL
+#define	SYS_AUE_close_range	AUE_CLOSERANGE
 
 #undef PAD_
 #undef PADL_

Modified: stable/12/tests/sys/file/closefrom_test.c
==============================================================================
--- stable/12/tests/sys/file/closefrom_test.c	Wed Aug  5 03:30:03 2020	(r363878)
+++ stable/12/tests/sys/file/closefrom_test.c	Wed Aug  5 03:53:57 2020	(r363879)
@@ -146,7 +146,7 @@ main(void)
 	pid_t pid;
 	int fd, i, start;
 
-	printf("1..15\n");
+	printf("1..20\n");
 
 	/* We better start up with fd's 0, 1, and 2 open. */
 	start = devnull();
@@ -270,6 +270,60 @@ main(void)
 	if (fd != 3)
 		fail("closefrom", "highest fd %d", fd);
 	ok("closefrom");
+
+	/* Chew up another 8 fd */
+	for (i = 0; i < 8; i++)
+		(void)devnull();
+	fd = highest_fd();
+	start = fd - 7;
+
+	/* close_range() a hole in the middle */
+	close_range(start + 3, start + 5, 0);
+	for (i = start + 3; i < start + 6; ++i) {
+		if (close(i) == 0 || errno != EBADF) {
+			--i;
+			break;
+		}
+	}
+	if (i != start + 6)
+		fail("close_range", "failed to close at %d in %d - %d", i + 1,
+		    start + 3, start + 6);
+	ok("close_range");
+
+	/* close_range from the middle of the hole */
+	close_range(start + 4, start + 6, 0);
+	if ((i = highest_fd()) != fd)
+		fail("close_range", "highest fd %d", i);
+	ok("close_range");
+
+	/* close_range to the end; effectively closefrom(2) */
+	close_range(start + 3, ~0L, 0);
+	if ((i = highest_fd()) != start + 2)
+		fail("close_range", "highest fd %d", i);
+	ok("close_range");
+
+	/* Now close the rest */
+	close_range(start, start + 4, 0);
+	fd = highest_fd();
+	if (fd != 3)
+		fail("close_range", "highest fd %d", fd);
+	ok("close_range");
+
+	/* Fork a child process to test closefrom(0) twice. */
+	pid = fork();
+	if (pid < 0)
+		fail_err("fork");
+	if (pid == 0) {
+		/* Child. */
+		closefrom(0);
+		closefrom(0);
+		cok(info, "closefrom(0)");
+	}
+	if (wait(NULL) < 0)
+		fail_err("wait");
+	if (info->failed)
+		fail(info->tag, "%s", info->message);
+	ok(info->tag);
 
 	return (0);
 }


More information about the svn-src-stable-12 mailing list