A while ago, finishdup() was changed to release fdplock before calling
closef() to avoid potential lock order problems in the file close path.
However, the dup* code can still invoke that path with fdplock held
through FRELE(). That is fixed by the diff below.

(In principle, the FRELE(fp, p) could be eliminated by getting fp while
the file descriptor table is locked. As long as the lock is held, other
threads are unable to close the file descriptor and hence the temporary
file reference is unnecessary.)

OK?

Index: kern/kern_descrip.c
===================================================================
RCS file: src/sys/kern/kern_descrip.c,v
retrieving revision 1.201
diff -u -p -r1.201 kern_descrip.c
--- kern/kern_descrip.c 13 Mar 2020 10:07:01 -0000      1.201
+++ kern/kern_descrip.c 10 Jun 2020 14:16:12 -0000
@@ -301,13 +301,14 @@ restart:
                return (EBADF);
        fdplock(fdp);
        if ((error = fdalloc(p, 0, &new)) != 0) {
-               FRELE(fp, p);
                if (error == ENOSPC) {
                        fdexpand(p);
                        fdpunlock(fdp);
+                       FRELE(fp, p);
                        goto restart;
                }
                fdpunlock(fdp);
+               FRELE(fp, p);
                return (error);
        }
        /* No need for FRELE(), finishdup() uses current ref. */
@@ -373,13 +374,14 @@ restart:
        fdplock(fdp);
        if (new >= fdp->fd_nfiles) {
                if ((error = fdalloc(p, new, &i)) != 0) {
-                       FRELE(fp, p);
                        if (error == ENOSPC) {
                                fdexpand(p);
                                fdpunlock(fdp);
+                               FRELE(fp, p);
                                goto restart;
                        }
                        fdpunlock(fdp);
+                       FRELE(fp, p);
                        return (error);
                }
                if (new != i)
@@ -433,13 +435,14 @@ restart:
                }
                fdplock(fdp);
                if ((error = fdalloc(p, newmin, &i)) != 0) {
-                       FRELE(fp, p);
                        if (error == ENOSPC) {
                                fdexpand(p);
                                fdpunlock(fdp);
+                               FRELE(fp, p);
                                goto restart;
                        }
                        fdpunlock(fdp);
+                       FRELE(fp, p);
                } else {
                        int dupflags = 0;
 

Reply via email to