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