[lvm-devel] master - multipathd: fix fd leak when iscsi device logs in

lixiaokeng lixiaokeng at huawei.com
Thu Jul 9 07:02:51 UTC 2020


When one iscsi device logs in and logs out several times, the
number of fd, which points to '/dev/mapper/control', increases in
/proc/<multipathd-pid>/fd as follows,
[root at localhost fd]# ll | grep control
lrwx------. 1 root root 64 Jul  6 16:30 10 -> /dev/mapper/control
lrwx------. 1 root root 64 Jul  6 16:30 11 -> /dev/mapper/control
lrwx------. 1 root root 64 Jul  6 16:30 12 -> /dev/mapper/control
lrwx------. 1 root root 64 Jul  6 16:30 13 -> /dev/mapper/control
lrwx------. 1 root root 64 Jul  6 16:30 5 -> /dev/mapper/control
lrwx------. 1 root root 64 Jul  6 16:30 9 -> /dev/mapper/control

This is because that both wait_dmevents thread and uevqloop thread in
multipathd will concurrently open and use public _control_fd which points
to '/dev/mapper/control' by calling _open_and_assign_control_fd func.
Although, the legality of _control_fd will be checked before open
'/dev/mapper/control' in _open_control func. Due to lack of lock protection,
both wait_dmevents thread and uevqloop thread may concurrently find
_control_fd illegal, and concurrently open '/dev/mapper/control' and reset
the public _control_fd to their new fd, then finally the allocated fd in faster
one will leak.

The procedure details given as follows,
1. wait_dmevents thread
wait_dmevents
->dmevent_loop
    ->dm_get_events
        ->dm_task_run
            ->_open_control
                ->_open_and_assign_control_fd

2. uevqloop thread
uevqloop
->uevent_dispatch
    ->service_uevq
        ->ev_add_path
            ->__setup_multipath
                ->dm_get_info
                    ->dm_task_run
                        ->_open_control
                            ->_open_and_assign_control_fd

3. _open_control func
_open_control
    -> check whether _control_fd is legal, if _control_fd is legal, return 1
    -> _create_control
    ->_open_and_assign_control_fd
        -> open '/dev/mapper/control' and set _control_fd to the new fd

Here, we add _control_fd_mutex to protect the procedure of
open('/dev/mapper/control') in _open_and_assign_control_fd func.

Reported-by: Tianxiong Lu <lutianxiong at huawei.com>
Signed-off-by: lixiaokeng <lixiaokeng at huawei.com>
Signed-off-by: Guanghao Wu <wuguanghao3 at huawei.com>
Signed-off-by: Zhiqiang Liu <liuzhiqiang26 at huawei.com>
---
 libdm/ioctl/libdm-iface.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c
index 7ad549c..7168369 100644
--- a/libdm/ioctl/libdm-iface.c
+++ b/libdm/ioctl/libdm-iface.c
@@ -23,6 +23,7 @@
 #include <sys/ioctl.h>
 #include <sys/utsname.h>
 #include <limits.h>
+#include <pthread.h>

 #ifdef __linux__
 #  include "libdm/misc/kdev_t.h"
@@ -81,6 +82,7 @@ static dm_bitset_t _dm_bitset = NULL;
 static uint32_t _dm_device_major = 0;

 static int _control_fd = -1;
+static pthread_mutex_t _control_fd_mutex = PTHREAD_MUTEX_INITIALIZER;
 static int _hold_control_fd_open = 0;
 static int _version_checked = 0;
 static int _version_ok = 1;
@@ -404,10 +406,19 @@ static void _close_control_fd(void)
 #ifdef DM_IOCTLS
 static int _open_and_assign_control_fd(const char *control)
 {
+	pthread_mutex_lock(&_control_fd_mutex);
+
+	if (_control_fd != -1) {
+		pthread_mutex_unlock(&_control_fd_mutex);
+		return 1;
+	}
+
 	if ((_control_fd = open(control, O_RDWR)) < 0) {
 		log_sys_error("open", control);
+		pthread_mutex_unlock(&_control_fd_mutex);
 		return 0;
 	}
+	pthread_mutex_unlock(&_control_fd_mutex);

 	return 1;
 }
-- 
1.8.3.1




More information about the lvm-devel mailing list