]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
msg: do not abort when driver->del_event() returns -ENOENT 56034/head
authorKefu Chai <tchaikov@gmail.com>
Thu, 7 Mar 2024 11:48:54 +0000 (19:48 +0800)
committerKefu Chai <tchaikov@gmail.com>
Sun, 10 Mar 2024 11:09:53 +0000 (19:09 +0800)
when shutting down a connection, we call into
`EpollDriver::del_event(..., EVENT_READABLE | EVENT_WRITABLE)`, and
its caller, `EventCenter::delete_file_event()` considers a negative
return value from this function a signal of bug and aborts in that
case. but in linux, if a nic is hot unplugged, all the socket file
descriptors associated with it are closed, and we would have following
chain:

__fput() -> eventpoll_release() -> eventpoll_release_file() -> __ep_remove()

in __ep_remove(), the epitem representing the fd is removed from
the list. so if we perform the cleanup when shutting down the
TCP connection, and try to unregister the fd from the interest list,
-ENOENT is returned.

librbd is using EpollDriver as well, and it sits at the client side.
the machine on which librbd is running could unplug its NIC without
shutting down librbd first. so, if librbd happen to be reading/writing
to the socket associated with the NIC being unplugged, there are
chances that librbd could crash due to the `ceph_abort_msg()` call
in `EventCenter::delete_file_event()`. but this is not a fatal error,
as we are unregistering the fd anyway.

in this change, in order to avoid the crash, we don't consider it a
bug if `driver->del_event()` returns -ENOENT anymore.

Fixes: https://tracker.ceph.com/issues/64788
Co-Authored-by: Zhang Jiao <zhangjiao@cmss.chinamobile.com>
Signed-off-by: Kefu Chai <tchaikov@gmail.com>
src/msg/async/Event.cc

index 4662e42bd144dae1ca1b359152ba17a4eb108af4..926fdcdb1cc3dd4374515b00270c226180ade473 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "include/compat.h"
 #include "common/errno.h"
+#include <cerrno>
 #include "Event.h"
 
 #ifdef HAVE_DPDK
@@ -285,7 +286,10 @@ void EventCenter::delete_file_event(int fd, int mask)
     return ;
 
   int r = driver->del_event(fd, event->mask, mask);
-  if (r < 0) {
+  if (r < 0 && r != -ENOENT) {
+    // if the socket fd is closed by the underlying nic driver, the
+    // corresponding epoll item would be removed from the interest list, that'd
+    // lead to ENOENT when removing the fd from the list.
     // see create_file_event
     ceph_abort_msg("BUG!");
   }