From 3216b0c1ff87a96a68f6a8a2a9fff804eb5819f1 Mon Sep 17 00:00:00 2001 From: Oknet Xu Date: Mon, 19 Sep 2016 14:11:56 +0800 Subject: [PATCH 1/2] TS-4879: Checking con.fd == NO_FD in UnixNetVConnection::connectUp() while we get return from check_emergency_throttle() --- iocore/net/P_UnixNet.h | 8 ++++---- iocore/net/UnixNetVConnection.cc | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/iocore/net/P_UnixNet.h b/iocore/net/P_UnixNet.h index b4fbc541908..9c917902f0a 100644 --- a/iocore/net/P_UnixNet.h +++ b/iocore/net/P_UnixNet.h @@ -261,13 +261,13 @@ check_shedding_warning() } } -TS_INLINE int +TS_INLINE bool emergency_throttle(ink_hrtime now) { - return emergency_throttle_time > now; + return (bool)(emergency_throttle_time > now); } -TS_INLINE int +TS_INLINE bool check_net_throttle(ThrottleType t, ink_hrtime now) { int connections = net_connections_to_throttle(t); @@ -302,7 +302,7 @@ check_throttle_warning() // descriptors. Close the connection immediately, the upper levels // will recover. // -TS_INLINE int +TS_INLINE bool check_emergency_throttle(Connection &con) { int fd = con.fd; diff --git a/iocore/net/UnixNetVConnection.cc b/iocore/net/UnixNetVConnection.cc index 60c1ad96dd2..9010820846c 100644 --- a/iocore/net/UnixNetVConnection.cc +++ b/iocore/net/UnixNetVConnection.cc @@ -1280,6 +1280,7 @@ UnixNetVConnection::connectUp(EThread *t, int fd) // If this is getting called from the TS API, then we are wiring up a file descriptor // provided by the caller. In that case, we know that the socket is already connected. if (fd == NO_FD) { + // Due to multi-threads system, the fd returned from con.open() may exceed the limitation of check_net_throttle(). res = con.open(options); if (res != 0) { goto fail; @@ -1297,14 +1298,24 @@ UnixNetVConnection::connectUp(EThread *t, int fd) con.is_bound = true; } + if (check_emergency_throttle(con)) { + // The `con' could be closed if there is hyper emergency + if (con.fd == NO_FD) { + // We need to decrement the stat because close_UnixNetVConnection only decrements with a valid connection descriptor. + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, -1); + // Set errno force to EMFILE (reached limit for open file descriptors) + errno = EMFILE; + res = -errno; + goto fail; + } + } + // Must connect after EventIO::Start() to avoid a race condition // when edge triggering is used. if (ep.start(get_PollDescriptor(t), this, EVENTIO_READ | EVENTIO_WRITE) < 0) { - lerrno = errno; - Debug("iocore_net", "connectUp : Failed to add to epoll list"); - action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *)0); // 0 == res - free(t); - return CONNECT_FAILURE; + res = -errno; + Debug("iocore_net", "connectUp : Failed to add to epoll list : %s", strerror(errno)); + goto fail; } if (fd == NO_FD) { @@ -1314,8 +1325,6 @@ UnixNetVConnection::connectUp(EThread *t, int fd) } } - check_emergency_throttle(con); - // start up next round immediately SET_HANDLER(&UnixNetVConnection::mainEvent); From cd3f83af040f9505a3224a41ce7de294899c760e Mon Sep 17 00:00:00 2001 From: Oknet Xu Date: Tue, 20 Sep 2016 21:06:14 +0800 Subject: [PATCH 2/2] TS-4879: Checking con.fd == NO_FD in NetAccept::do_blocking_accept() --- iocore/net/UnixNetAccept.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/iocore/net/UnixNetAccept.cc b/iocore/net/UnixNetAccept.cc index 92b633c7612..8750e03b6e6 100644 --- a/iocore/net/UnixNetAccept.cc +++ b/iocore/net/UnixNetAccept.cc @@ -280,14 +280,20 @@ NetAccept::do_blocking_accept(EThread *t) return -1; } + // The con.fd may exceed the limitation of check_net_throttle() because we do blocking accept here. + if (check_emergency_throttle(con)) { + // The `con' could be closed if there is hyper emergency + if (con.fd == NO_FD) { + return 0; + } + } + // Use 'NULL' to Bypass thread allocator vc = (UnixNetVConnection *)this->getNetProcessor()->allocate_vc(NULL); if (unlikely(!vc || shutdown_event_system == true)) { return -1; } - check_emergency_throttle(con); - NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, 1); vc->id = net_next_connection_number(); vc->con.move(con);