Compare with v1:
Better readability and also check for dup3.

I haven't tested this patch again some stress tests as I don't know why
the `dpkg-buildpackage -B` on my qemu got stuck at:

```
...
../scripts/evaluate-test.sh stdio-common/scanf14 $? false false > 
/home/1speaker/apt-source/glibc-2.41/build-tree/hurd-i386-libc/stdio-common/scanf14.test-result
```

Not sure what to do next so I sent this patch for the sake of backup.

Best,
Zhaoming

---
 sysdeps/mach/hurd/dup3.c  | 62 +++++++++++++++++++++++++++++----------
 sysdeps/mach/hurd/fcntl.c | 52 ++++++++++++++++++++++++--------
 2 files changed, 86 insertions(+), 28 deletions(-)

diff --git a/sysdeps/mach/hurd/dup3.c b/sysdeps/mach/hurd/dup3.c
index 22af45b4..224a803c 100644
--- a/sysdeps/mach/hurd/dup3.c
+++ b/sysdeps/mach/hurd/dup3.c
@@ -69,6 +69,7 @@ __dup3 (int fd, int fd2, int flags)
        {
          /* Get a hold of the destination descriptor.  */
          struct hurd_fd *d2;
+         error_t err;
 
          __mutex_lock (&_hurd_dtable_lock);
 
@@ -107,22 +108,51 @@ __dup3 (int fd, int fd2, int flags)
            }
          else
            {
-             /* Give the ports each a user ref for the new descriptor.  */
-             __mach_port_mod_refs (__mach_task_self (), port,
-                                   MACH_PORT_RIGHT_SEND, 1);
-             if (ctty != MACH_PORT_NULL)
-               __mach_port_mod_refs (__mach_task_self (), ctty,
-                                     MACH_PORT_RIGHT_SEND, 1);
-
-             /* Install the ports and flags in the new descriptor slot.  */
-             __spin_lock (&d2->port.lock);
-             if (flags & O_CLOEXEC)
-               d2->flags = d_flags | FD_CLOEXEC;
-             else
-               /* dup clears FD_CLOEXEC.  */
-               d2->flags = d_flags & ~FD_CLOEXEC;
-             _hurd_port_set (&d2->ctty, ctty);
-             _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
+             /* Give the io server port a user ref for the new descriptor.  */
+             err = __mach_port_mod_refs (__mach_task_self (), port,
+                     MACH_PORT_RIGHT_SEND, 1);
+
+             if (err == KERN_UREFS_OVERFLOW)
+               fd2 = __hurd_fail (EMFILE);
+             else if (err)
+               fd2 = __hurd_fail (EINVAL);
+             else if (ctty != MACH_PORT_NULL)
+               {
+                 /* We have confirmed the io server port has got a user ref
+                    count, now give ctty port a user ref for the new
+                    descriptor.  */
+                 err = __mach_port_mod_refs (__mach_task_self (), ctty,
+                         MACH_PORT_RIGHT_SEND, 1);
+
+                 if (err)
+                   {
+                     /* In this case the io server port has got a ref count
+                        but the ctty port fails to get ont, so we need to
+                        clean the ref count we just assigned.  */
+                     __mach_port_mod_refs (__mach_task_self (), port,
+                             MACH_PORT_RIGHT_SEND, -1);
+                     if (err == KERN_UREFS_OVERFLOW)
+                       fd2 = __hurd_fail (EMFILE);
+                     else
+                       fd2 = __hurd_fail (EINVAL);
+                   }
+               }
+
+             if (!err)
+               {
+                 /* The ref counts of the ports are incremented
+                    successfully.  */
+                 /* Install the ports and flags in the new descriptor slot.  */
+                 __spin_lock (&d2->port.lock);
+                 if (flags & O_CLOEXEC)
+                   d2->flags = d_flags | FD_CLOEXEC;
+                 else
+                   /* dup clears FD_CLOEXEC.  */
+                   d2->flags = d_flags & ~FD_CLOEXEC;
+                 if (ctty != MACH_PORT_NULL)
+                   _hurd_port_set (&d2->ctty, ctty);
+                 _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
+               }
            }
        }
 
diff --git a/sysdeps/mach/hurd/fcntl.c b/sysdeps/mach/hurd/fcntl.c
index a65c190c..56d850e8 100644
--- a/sysdeps/mach/hurd/fcntl.c
+++ b/sysdeps/mach/hurd/fcntl.c
@@ -83,18 +83,46 @@ __libc_fcntl (int fd, int cmd, ...)
          result = -1;
        else
          {
-           /* Give the ports each a user ref for the new descriptor.  */
-           __mach_port_mod_refs (__mach_task_self (), port,
-                                 MACH_PORT_RIGHT_SEND, 1);
-           if (ctty != MACH_PORT_NULL)
-             __mach_port_mod_refs (__mach_task_self (), ctty,
-                                   MACH_PORT_RIGHT_SEND, 1);
-
-           /* Install the ports and flags in the new descriptor.  */
-           if (ctty != MACH_PORT_NULL)
-             _hurd_port_set (&new->ctty, ctty);
-           new->flags = flags;
-           _hurd_port_locked_set (&new->port, port); /* Unlocks NEW.  */
+           /* Give the io server port a user ref for the new descriptor.  */
+           err = __mach_port_mod_refs (__mach_task_self (), port,
+                   MACH_PORT_RIGHT_SEND, 1);
+
+           if (err == KERN_UREFS_OVERFLOW)
+              result = __hurd_fail (EMFILE);
+            else if (err)
+              result = __hurd_fail (EINVAL);
+            else if (ctty != MACH_PORT_NULL)
+             {
+                /* We have confirmed the io server port has got a user ref
+                  count, now give ctty port a user ref for the new
+                  descriptor.  */
+                err = __mach_port_mod_refs (__mach_task_self (), ctty,
+                       MACH_PORT_RIGHT_SEND, 1);
+
+               if (err)
+                 {
+                    /* In this case the io server port has got a ref count
+                    but the ctty port fails to get one, so we need to clean
+                    the ref count we just assigned.  */
+                    __mach_port_mod_refs (__mach_task_self (), port,
+                           MACH_PORT_RIGHT_SEND, -1);
+                    if (err == KERN_UREFS_OVERFLOW)
+                     result = __hurd_fail (EMFILE);
+                    else
+                      result = __hurd_fail (EINVAL);
+                  }
+             }
+
+           if (!err)
+             {
+               /* The ref counts of the ports are incremented successfully.  */
+               /* Install the ports and flags in the new descriptor.  */
+               if (ctty != MACH_PORT_NULL)
+                 _hurd_port_set (&new->ctty, ctty);
+               new->flags = flags;
+               /* Unlocks NEW.  */
+               _hurd_port_locked_set (&new->port, port);
+             }
          }
 
        HURD_CRITICAL_END;
-- 
2.47.2


Reply via email to