Author: mjg
Date: Thu Dec 17 18:52:30 2020
New Revision: 368732
URL: https://svnweb.freebsd.org/changeset/base/368732

Log:
  fd: reimplement close_range to avoid spurious relocking

Modified:
  head/sys/kern/kern_descrip.c

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c        Thu Dec 17 18:52:04 2020        
(r368731)
+++ head/sys/kern/kern_descrip.c        Thu Dec 17 18:52:30 2020        
(r368732)
@@ -307,6 +307,7 @@ fdfree(struct filedesc *fdp, int fd)
 {
        struct filedescent *fde;
 
+       FILEDESC_XLOCK_ASSERT(fdp);
        fde = &fdp->fd_ofiles[fd];
 #ifdef CAPABILITIES
        seqc_write_begin(&fde->fde_seqc);
@@ -1367,12 +1368,10 @@ int
 kern_close_range(struct thread *td, u_int lowfd, u_int highfd)
 {
        struct filedesc *fdp;
-       int fd, ret, lastfile;
+       const struct fdescenttbl *fdt;
+       struct file *fp;
+       int fd;
 
-       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,
@@ -1380,30 +1379,36 @@ kern_close_range(struct thread *td, u_int lowfd, u_int
         * be a usage error as all fd above 3 are in-fact already closed.
         */
        if (highfd < lowfd) {
-               ret = EINVAL;
-               goto out;
+               return (EINVAL);
        }
 
-       /*
-        * If 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.
-        */
-       lastfile = fdlastfile(fdp);
-       if (lastfile == -1)
-               goto out;
-       /* Clamped to [lowfd, lastfile] */
-       highfd = MIN(highfd, 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);
+       fdp = td->td_proc->p_fd;
+       FILEDESC_XLOCK(fdp);
+       fdt = atomic_load_ptr(&fdp->fd_files);
+       highfd = MIN(highfd, fdt->fdt_nfiles - 1);
+       fd = lowfd;
+       if (__predict_false(fd > highfd)) {
+               goto out_locked;
+       }
+       for (;;) {
+               fp = fdt->fdt_ofiles[fd].fde_file;
+               if (fp == NULL) {
+                       if (fd == highfd)
+                               goto out_locked;
+               } else {
+                       fdfree(fdp, fd);
+                       (void) closefp(fdp, fd, fp, td, true, true);
+                       if (fd == highfd)
+                               goto out_unlocked;
+                       FILEDESC_XLOCK(fdp);
+                       fdt = atomic_load_ptr(&fdp->fd_files);
                }
+               fd++;
        }
-out:
-       FILEDESC_SUNLOCK(fdp);
-       return (ret);
+out_locked:
+       FILEDESC_XUNLOCK(fdp);
+out_unlocked:
+       return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to