Import upstream version 1.6.0
Debian Janitor
1 year, 3 months ago
0 | 0 | cmake_minimum_required (VERSION 2.8 FATAL_ERROR) |
1 | 1 | project (tcmu-runner C) |
2 | set(VERSION 1.5.4) | |
2 | set(VERSION 1.6.0) | |
3 | 3 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wdeclaration-after-statement -std=c99") |
4 | 4 | |
5 | 5 | include(GNUInstallDirs) |
431 | 431 | * the first command sent to us so clear |
432 | 432 | * lock state to avoid later blacklist errors. |
433 | 433 | */ |
434 | pthread_mutex_lock(&rdev->state_lock); | |
434 | pthread_mutex_lock(&rdev->rdev_lock); | |
435 | 435 | if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED) { |
436 | 436 | tcmu_dev_dbg(dev, "Dropping lock\n"); |
437 | 437 | rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED; |
438 | 438 | } |
439 | pthread_mutex_unlock(&rdev->state_lock); | |
439 | pthread_mutex_unlock(&rdev->rdev_lock); | |
440 | 440 | } |
441 | 441 | } |
442 | 442 | |
559 | 559 | if (!lock_is_required(dev)) |
560 | 560 | return ret; |
561 | 561 | |
562 | pthread_mutex_lock(&rdev->state_lock); | |
562 | pthread_mutex_lock(&rdev->rdev_lock); | |
563 | 563 | if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED) { |
564 | 564 | /* For both read/write cases in this state is good */ |
565 | 565 | goto done; |
616 | 616 | } |
617 | 617 | |
618 | 618 | done: |
619 | pthread_mutex_unlock(&rdev->state_lock); | |
619 | pthread_mutex_unlock(&rdev->rdev_lock); | |
620 | 620 | return ret; |
621 | 621 | } |
622 | 622 |
26 | 26 | #include "libtcmu_common.h" |
27 | 27 | #include "libtcmu_priv.h" |
28 | 28 | #include "be_byteshift.h" |
29 | ||
30 | __thread int __tcmu_is_ework_thread = 0; | |
29 | 31 | |
30 | 32 | int tcmu_cdb_get_length(uint8_t *cdb) |
31 | 33 | { |
64 | 66 | |
65 | 67 | switch (tcmu_cdb_get_length(cdb)) { |
66 | 68 | case 6: |
67 | val = be16toh(*((uint16_t *)&cdb[2])); | |
69 | val = get_unaligned_be16(&cdb[2]); | |
68 | 70 | return ((cdb[1] & 0x1f) << 16) | val; |
69 | 71 | case 10: |
70 | return be32toh(*((u_int32_t *)&cdb[2])); | |
72 | return get_unaligned_be32(&cdb[2]); | |
71 | 73 | case 12: |
72 | return be32toh(*((u_int32_t *)&cdb[2])); | |
74 | return get_unaligned_be32(&cdb[2]); | |
73 | 75 | case 16: |
74 | return be64toh(*((u_int64_t *)&cdb[2])); | |
76 | return get_unaligned_be64(&cdb[2]); | |
75 | 77 | default: |
76 | assert_perror(EINVAL); | |
78 | assert(0); | |
77 | 79 | return 0; /* not reached */ |
78 | 80 | } |
79 | 81 | } |
84 | 86 | case 6: |
85 | 87 | return cdb[4]; |
86 | 88 | case 10: |
87 | return be16toh(*((uint16_t *)&cdb[7])); | |
89 | return get_unaligned_be16(&cdb[7]); | |
88 | 90 | case 12: |
89 | return be32toh(*((u_int32_t *)&cdb[6])); | |
91 | return get_unaligned_be32(&cdb[6]); | |
90 | 92 | case 16: |
91 | return be32toh(*((u_int32_t *)&cdb[10])); | |
93 | return get_unaligned_be32(&cdb[10]); | |
92 | 94 | default: |
93 | assert_perror(EINVAL); | |
95 | assert(0); | |
94 | 96 | return 0; /* not reached */ |
95 | 97 | } |
96 | 98 | } |
7 | 7 | |
8 | 8 | #ifndef _TCMU_BE_BYTESHIFT_H |
9 | 9 | #define _TCMU_BE_BYTESHIFT_H |
10 | ||
11 | #include <endian.h> | |
12 | #include <stdint.h> | |
13 | #include <string.h> | |
14 | ||
10 | 15 | |
11 | 16 | static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) |
12 | 17 | { |
47 | 52 | return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; |
48 | 53 | } |
49 | 54 | |
50 | static inline uint16_t get_unaligned_be32(const void *p) | |
55 | static inline uint32_t get_unaligned_be32(const void *p) | |
51 | 56 | { |
52 | 57 | return __get_unaligned_be32(p); |
53 | 58 | } |
54 | 59 | |
60 | static inline uint64_t get_unaligned_be64(const void *p) | |
61 | { | |
62 | uint64_t val; | |
63 | memcpy(&val, p, sizeof(val)); | |
64 | return be64toh(val); | |
65 | } | |
66 | ||
67 | static inline void put_unaligned_be64(uint64_t val, void *p) | |
68 | { | |
69 | val = htobe64(val); | |
70 | memcpy(p, &val, sizeof(val)); | |
71 | } | |
72 | ||
55 | 73 | #endif |
12 | 12 | case $ID in |
13 | 13 | fedora|rhel|centos) |
14 | 14 | # for generic |
15 | $SUDO yum install -y cmake make gcc libnl3 glib2 zlib kmod | |
16 | $SUDO yum install -y libnl3-devel glib2-devel zlib-devel kmod-devel gperftools-devel | |
15 | $SUDO yum install -y cmake make gcc | |
16 | $SUDO yum install -y libnl3 | |
17 | $SUDO yum install -y libnl3-devel | |
18 | $SUDO yum install -y glib2 | |
19 | $SUDO yum install -y glib2-devel | |
20 | $SUDO yum install -y zlib | |
21 | $SUDO yum install -y zlib-devel | |
22 | $SUDO yum install -y kmod | |
23 | $SUDO yum install -y kmod-devel | |
24 | $SUDO yum install -y gperftools-devel | |
17 | 25 | |
18 | 26 | # for glusterfs |
19 | $SUDO yum install -y glusterfs-api glusterfs-api-devel | |
27 | $SUDO yum install -y glusterfs-api | |
28 | $SUDO yum install -y glusterfs-api-devel | |
20 | 29 | # for ceph |
21 | $SUDO yum install -y librados2 librados2-devel librbd1 | |
30 | $SUDO yum install -y librados2 | |
31 | $SUDO yum install -y librados2-devel | |
32 | $SUDO yum install -y librbd1 | |
22 | 33 | yum search librbd-devel | grep -q "N/S matched" && LIBRBD=librbd || LIBRBD=librbd1 |
23 | 34 | $SUDO yum install -y $LIBRBD-devel |
24 | 35 | ;; |
27 | 38 | $SUDO apt update |
28 | 39 | |
29 | 40 | # for generic |
30 | $SUDO apt install -y cmake make gcc zlib1g kmod | |
31 | $SUDO apt install -y libnl-3-dev libnl-genl-3-dev libglib2.0-0 libkmod-dev libgoogle-perftools-dev | |
41 | $SUDO apt install -y cmake make gcc | |
42 | $SUDO apt install -y zlib1g kmod | |
43 | $SUDO apt install -y libnl-3-dev | |
44 | $SUDO apt install -y libnl-genl-3-dev | |
45 | $SUDO apt install -y libglib2.0-0 | |
46 | $SUDO apt install -y libkmod-dev | |
47 | $SUDO apt install -y libgoogle-perftools-dev | |
32 | 48 | |
33 | 49 | # for glusterfs |
34 | 50 | $SUDO apt install -y libglusterfs-dev |
35 | 51 | |
36 | 52 | # for ceph |
37 | $SUDO apt install -y librados2 librbd-dev | |
53 | $SUDO apt install -y librados2 | |
54 | $SUDO apt install -y librbd-dev | |
38 | 55 | ;; |
39 | 56 | sles|opensuse-tumbleweed) |
40 | 57 | # for generic |
41 | $SUDO zypper install -y cmake make gcc libnl3-200 glib2 zlib kmod | |
42 | $SUDO zypper install -y libnl3-devel glib2-devel zlib-devel libkmod-devel gperftools-devel | |
58 | $SUDO zypper install -y cmake make gcc | |
59 | $SUDO zypper install -y libnl3-200 | |
60 | $SUDO zypper install -y glib2 | |
61 | $SUDO zypper install -y zlib | |
62 | $SUDO zypper install -y kmod | |
63 | $SUDO zypper install -y libnl3-devel | |
64 | $SUDO zypper install -y glib2-devel | |
65 | $SUDO zypper install -y zlib-devel | |
66 | $SUDO zypper install -y libkmod-devel | |
67 | $SUDO zypper install -y gperftools-devel | |
43 | 68 | |
44 | 69 | #for glusterfs |
45 | $SUDO zypper install -y glusterfs-devel glusterfs | |
70 | $SUDO zypper install -y glusterfs | |
71 | $SUDO zypper install -y glusterfs-devel | |
46 | 72 | #for ceph |
47 | $SUDO zypper install -y librbd-devel librados-devel librados2 | |
73 | $SUDO zypper install -y librbd-devel | |
74 | $SUDO zypper install -y librados-devel | |
75 | $SUDO zypper install -y librados2 | |
48 | 76 | ;; |
49 | 77 | *) |
50 | 78 | echo "TODO: distro not supported for now!" |
842 | 842 | void tcmu_set_thread_name(const char *prefix, struct tcmu_device *dev) |
843 | 843 | { |
844 | 844 | const char *uio = dev ? tcmu_dev_get_uio_name(dev) : NULL; |
845 | char cname[TCMU_THREAD_NAME_LEN]; | |
846 | 845 | char *pname; |
847 | ||
848 | if (pthread_getname_np(pthread_self(), cname, TCMU_THREAD_NAME_LEN)) | |
849 | return; | |
850 | 846 | |
851 | 847 | /* |
852 | 848 | * If we are trying to set the pthread name in the |
853 | 849 | * event work thread, we must ignore it. |
854 | 850 | */ |
855 | if (!strcmp(cname, "ework-thread")) { | |
851 | if (__tcmu_is_ework_thread) { | |
856 | 852 | tcmu_dev_warn(dev, "Do not set name for event work thread in the callback fn\n"); |
857 | 853 | return; |
858 | 854 | } |
859 | 855 | |
860 | 856 | if (!prefix) { |
861 | 857 | tcmu_dev_err(dev, "Failed to set name for thread %lu\n", |
862 | pthread_self()); | |
858 | (long unsigned int)pthread_self()); | |
863 | 859 | return; |
864 | 860 | } |
865 | 861 | |
1022 | 1018 | bool tcmu_dev_get_unmap_enabled(struct tcmu_device *dev) |
1023 | 1019 | { |
1024 | 1020 | return dev->unmap_enabled; |
1021 | } | |
1022 | ||
1023 | void tcmu_dev_set_write_protect_enabled(struct tcmu_device *dev, bool enabled) | |
1024 | { | |
1025 | dev->write_protect_enabled = enabled; | |
1026 | } | |
1027 | ||
1028 | bool tcmu_dev_get_write_protect_enabled(struct tcmu_device *dev) | |
1029 | { | |
1030 | return dev->write_protect_enabled; | |
1025 | 1031 | } |
1026 | 1032 | |
1027 | 1033 | int tcmu_dev_get_fd(struct tcmu_device *dev) |
1063 | 1069 | /* get length of map from file */ |
1064 | 1070 | ssize_t size; |
1065 | 1071 | char *size_name; |
1066 | ||
1072 | ||
1067 | 1073 | if (asprintf(&size_name, sizefmt, dev->dev_name) == -1) { |
1068 | 1074 | tcmu_err("cannot construct device map size filename\n"); |
1069 | 1075 | goto err_free; |
13 | 13 | #define __LIBTCMU_COMMON_H |
14 | 14 | |
15 | 15 | #include <stdbool.h> |
16 | #include <pthread.h> | |
16 | 17 | |
17 | 18 | #ifdef __cplusplus |
18 | 19 | extern "C" { |
136 | 137 | bool tcmu_dev_get_solid_state_media(struct tcmu_device *dev); |
137 | 138 | void tcmu_dev_set_unmap_enabled(struct tcmu_device *dev, bool enabled); |
138 | 139 | bool tcmu_dev_get_unmap_enabled(struct tcmu_device *dev); |
140 | void tcmu_dev_set_write_protect_enabled(struct tcmu_device *dev, bool enabled); | |
141 | bool tcmu_dev_get_write_protect_enabled(struct tcmu_device *dev); | |
139 | 142 | struct tcmulib_handler *tcmu_dev_get_handler(struct tcmu_device *dev); |
140 | 143 | void tcmu_dev_flush_ring(struct tcmu_device *dev); |
141 | 144 | bool tcmu_dev_oooc_supported(struct tcmu_device* dev); |
192 | 195 | */ |
193 | 196 | void tcmu_thread_cancel(pthread_t thread); |
194 | 197 | |
198 | extern __thread int __tcmu_is_ework_thread; | |
199 | ||
195 | 200 | #ifdef __cplusplus |
196 | 201 | } |
197 | 202 | #endif |
201 | 201 | |
202 | 202 | do { |
203 | 203 | len = read(fd, buf, count); |
204 | } while (errno == EAGAIN); | |
204 | } while (len < 0 && errno == EAGAIN); | |
205 | 205 | |
206 | 206 | errno = save; |
207 | 207 | return len; |
402 | 402 | int fd = (intptr_t) data; |
403 | 403 | char *buf, *msg; |
404 | 404 | int count, ret, written = 0, r, pid = 0; |
405 | char pname[TCMU_THREAD_NAME_LEN]; | |
406 | 405 | |
407 | 406 | if (fd == -1) |
408 | 407 | return -1; |
411 | 410 | if (pid <= 0) |
412 | 411 | return -1; |
413 | 412 | |
414 | if (pthread_getname_np(pthread_self(), pname, TCMU_THREAD_NAME_LEN)) | |
415 | return -1; | |
416 | ||
417 | 413 | /* |
418 | 414 | * format: timestamp pid [loglevel] msg |
419 | 415 | */ |
420 | ret = asprintf(&msg, "%s %d:%s [%s] %s", timestamp, pid, pname, | |
416 | ret = asprintf(&msg, "%s %d [%s] %s", timestamp, pid, | |
421 | 417 | loglevel_string(pri), str); |
422 | 418 | if (ret < 0) |
423 | 419 | return -1; |
54 | 54 | unsigned int write_cache_enabled:1; |
55 | 55 | unsigned int solid_state_media:1; |
56 | 56 | unsigned int unmap_enabled:1; |
57 | unsigned int write_protect_enabled:1; | |
57 | 58 | |
58 | 59 | char dev_name[16]; /* e.g. "uio14" */ |
59 | 60 | char tcm_hba_name[16]; /* e.g. "user_8" */ |
614 | 614 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
615 | 615 | bool is_open = false; |
616 | 616 | |
617 | pthread_mutex_lock(&rdev->state_lock); | |
617 | pthread_mutex_lock(&rdev->rdev_lock); | |
618 | 618 | /* check if this was already called due to thread cancelation */ |
619 | 619 | if (rdev->flags & TCMUR_DEV_FLAG_STOPPED) { |
620 | pthread_mutex_unlock(&rdev->state_lock); | |
620 | pthread_mutex_unlock(&rdev->rdev_lock); | |
621 | 621 | return; |
622 | 622 | } |
623 | 623 | rdev->flags |= TCMUR_DEV_FLAG_STOPPING; |
624 | pthread_mutex_unlock(&rdev->state_lock); | |
624 | pthread_mutex_unlock(&rdev->rdev_lock); | |
625 | 625 | |
626 | 626 | /* |
627 | 627 | * The lock thread can fire off the recovery thread, so make sure |
632 | 632 | |
633 | 633 | tcmu_release_dev_lock(dev); |
634 | 634 | |
635 | pthread_mutex_lock(&rdev->state_lock); | |
635 | pthread_mutex_lock(&rdev->rdev_lock); | |
636 | 636 | if (rdev->flags & TCMUR_DEV_FLAG_IS_OPEN) { |
637 | 637 | rdev->flags &= ~TCMUR_DEV_FLAG_IS_OPEN; |
638 | 638 | is_open = true; |
639 | 639 | } |
640 | pthread_mutex_unlock(&rdev->state_lock); | |
640 | pthread_mutex_unlock(&rdev->rdev_lock); | |
641 | 641 | |
642 | 642 | if (is_open) |
643 | 643 | rhandler->close(dev); |
644 | 644 | |
645 | pthread_mutex_lock(&rdev->state_lock); | |
645 | pthread_mutex_lock(&rdev->rdev_lock); | |
646 | 646 | rdev->flags |= TCMUR_DEV_FLAG_STOPPED; |
647 | pthread_mutex_unlock(&rdev->state_lock); | |
647 | pthread_mutex_unlock(&rdev->rdev_lock); | |
648 | 648 | |
649 | 649 | tcmu_dev_dbg(dev, "cmdproc cleanup done\n"); |
650 | 650 | } |
656 | 656 | |
657 | 657 | ret = clock_gettime(CLOCK_MONOTONIC_COARSE, time); |
658 | 658 | if (!ret) { |
659 | tcmu_dev_dbg(dev, "Current time %lu secs.\n", time->tv_sec); | |
659 | tcmu_dev_dbg(dev, "Current time %"PRIdMAX" secs.\n", (intmax_t)time->tv_sec); | |
660 | 660 | return 0; |
661 | 661 | } |
662 | 662 | |
680 | 680 | |
681 | 681 | memset(tmo, 0, sizeof(*tmo)); |
682 | 682 | |
683 | pthread_spin_lock(&rdev->lock); | |
683 | pthread_spin_lock(&rdev->cmds_list_lock); | |
684 | 684 | list_for_each(&rdev->cmds_list, tcmur_cmd, cmds_list_entry) { |
685 | 685 | if (tcmur_cmd->timed_out) |
686 | 686 | continue; |
699 | 699 | tmo->tv_sec = 0; |
700 | 700 | } |
701 | 701 | |
702 | tcmu_dev_dbg(dev, "Next cmd id %hu timeout in %lu secs. Current time %lu. Start time %lu\n", | |
703 | tcmur_cmd->lib_cmd->cmd_id, tmo->tv_sec, | |
704 | curr_time->tv_sec, tcmur_cmd->start_time.tv_sec); | |
702 | tcmu_dev_dbg(dev, "Next cmd id %hu timeout in %"PRIdMAX" secs. Current time %"PRIdMAX". Start time %"PRIdMAX"\n", | |
703 | tcmur_cmd->lib_cmd->cmd_id, (intmax_t)tmo->tv_sec, | |
704 | (intmax_t)curr_time->tv_sec, (intmax_t)tcmur_cmd->start_time.tv_sec); | |
705 | 705 | break; |
706 | 706 | } |
707 | pthread_spin_unlock(&rdev->lock); | |
707 | pthread_spin_unlock(&rdev->cmds_list_lock); | |
708 | 708 | |
709 | 709 | return has_timeout; |
710 | 710 | } |
727 | 727 | if (tcmur_get_time(dev, &curr_time)) |
728 | 728 | return; |
729 | 729 | |
730 | pthread_spin_lock(&rdev->lock); | |
730 | pthread_spin_lock(&rdev->cmds_list_lock); | |
731 | 731 | list_for_each(&rdev->cmds_list, tcmur_cmd, cmds_list_entry) { |
732 | 732 | if (tcmur_cmd->timed_out) |
733 | 733 | continue; |
757 | 757 | */ |
758 | 758 | tcmu_notify_cmd_timed_out(dev); |
759 | 759 | } |
760 | pthread_spin_unlock(&rdev->lock); | |
760 | pthread_spin_unlock(&rdev->cmds_list_lock); | |
761 | 761 | } |
762 | 762 | |
763 | 763 | static void tcmur_tcmulib_cmd_start(struct tcmu_device *dev, |
774 | 774 | if (rdev->cmd_time_out) { |
775 | 775 | tcmur_cmd->start_time.tv_sec = curr_time->tv_sec; |
776 | 776 | |
777 | pthread_spin_lock(&rdev->lock); | |
777 | pthread_spin_lock(&rdev->cmds_list_lock); | |
778 | 778 | list_add_tail(&rdev->cmds_list, &tcmur_cmd->cmds_list_entry); |
779 | pthread_spin_unlock(&rdev->lock); | |
779 | pthread_spin_unlock(&rdev->cmds_list_lock); | |
780 | 780 | } |
781 | 781 | } |
782 | 782 | |
871 | 871 | * requests that LIO has completed. We only need to wait for replies |
872 | 872 | * for outstanding requests so throttle the cmdproc thread now. |
873 | 873 | */ |
874 | pthread_mutex_lock(&rdev->state_lock); | |
874 | pthread_mutex_lock(&rdev->rdev_lock); | |
875 | 875 | if (rdev->flags & TCMUR_DEV_FLAG_STOPPING) |
876 | 876 | dev_stopping = true; |
877 | pthread_mutex_unlock(&rdev->state_lock); | |
877 | pthread_mutex_unlock(&rdev->rdev_lock); | |
878 | 878 | } |
879 | 879 | |
880 | 880 | /* |
1019 | 1019 | tcmu_dev_dbg(dev, "Got block_size %d, size in bytes %"PRId64"\n", |
1020 | 1020 | block_size, dev_size); |
1021 | 1021 | |
1022 | ret = pthread_spin_init(&rdev->lock, 0); | |
1022 | ret = pthread_spin_init(&rdev->cmds_list_lock, 0); | |
1023 | 1023 | if (ret) { |
1024 | 1024 | ret = -ret; |
1025 | 1025 | goto free_rdev; |
1037 | 1037 | goto cleanup_caw_lock; |
1038 | 1038 | } |
1039 | 1039 | |
1040 | ret = pthread_mutex_init(&rdev->state_lock, NULL); | |
1040 | ret = pthread_mutex_init(&rdev->rdev_lock, NULL); | |
1041 | 1041 | if (ret) { |
1042 | 1042 | ret = -ret; |
1043 | 1043 | goto cleanup_format_lock; |
1045 | 1045 | |
1046 | 1046 | ret = setup_io_work_queue(dev); |
1047 | 1047 | if (ret < 0) |
1048 | goto cleanup_state_lock; | |
1048 | goto cleanup_rdev_lock; | |
1049 | 1049 | |
1050 | 1050 | ret = setup_aio_tracking(rdev); |
1051 | 1051 | if (ret < 0) |
1087 | 1087 | cleanup_aio_tracking(rdev); |
1088 | 1088 | cleanup_io_work_queue: |
1089 | 1089 | cleanup_io_work_queue(dev, true); |
1090 | cleanup_state_lock: | |
1091 | pthread_mutex_destroy(&rdev->state_lock); | |
1090 | cleanup_rdev_lock: | |
1091 | pthread_mutex_destroy(&rdev->rdev_lock); | |
1092 | 1092 | cleanup_format_lock: |
1093 | 1093 | pthread_mutex_destroy(&rdev->format_lock); |
1094 | 1094 | cleanup_caw_lock: |
1095 | 1095 | pthread_mutex_destroy(&rdev->caw_lock); |
1096 | 1096 | cleanup_dev_lock: |
1097 | pthread_spin_destroy(&rdev->lock); | |
1097 | pthread_spin_destroy(&rdev->cmds_list_lock); | |
1098 | 1098 | free_rdev: |
1099 | 1099 | free(rdev); |
1100 | 1100 | return ret; |
1105 | 1105 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
1106 | 1106 | int ret; |
1107 | 1107 | |
1108 | pthread_mutex_lock(&rdev->state_lock); | |
1108 | pthread_mutex_lock(&rdev->rdev_lock); | |
1109 | 1109 | rdev->flags |= TCMUR_DEV_FLAG_STOPPING; |
1110 | pthread_mutex_unlock(&rdev->state_lock); | |
1110 | pthread_mutex_unlock(&rdev->rdev_lock); | |
1111 | 1111 | |
1112 | 1112 | /* |
1113 | 1113 | * The order of cleaning up worker threads and calling ->removed() |
1129 | 1129 | |
1130 | 1130 | tcmur_destroy_work(rdev->event_work); |
1131 | 1131 | |
1132 | ret = pthread_mutex_destroy(&rdev->state_lock); | |
1132 | ret = pthread_mutex_destroy(&rdev->rdev_lock); | |
1133 | 1133 | if (ret != 0) |
1134 | 1134 | tcmu_err("could not cleanup state lock %d\n", ret); |
1135 | 1135 | |
1141 | 1141 | if (ret != 0) |
1142 | 1142 | tcmu_err("could not cleanup caw lock %d\n", ret); |
1143 | 1143 | |
1144 | ret = pthread_spin_destroy(&rdev->lock); | |
1144 | ret = pthread_spin_destroy(&rdev->cmds_list_lock); | |
1145 | 1145 | if (ret != 0) |
1146 | 1146 | tcmu_err("could not cleanup mailbox lock %d\n", ret); |
1147 | 1147 | |
1397 | 1397 | g_unix_signal_add(SIGTERM, handle_sig, loop) <= 0 || |
1398 | 1398 | g_unix_signal_add(SIGHUP, handle_sighup, loop) <= 0) { |
1399 | 1399 | tcmu_err("couldn't setup signal handlers\n"); |
1400 | goto unwatch_cfg; | |
1400 | goto loop_unref; | |
1401 | 1401 | } |
1402 | 1402 | |
1403 | 1403 | /* Set up event for libtcmu */ |
1423 | 1423 | |
1424 | 1424 | tcmu_crit("Exiting...\n"); |
1425 | 1425 | g_bus_unown_name(reg_id); |
1426 | g_main_loop_unref(loop); | |
1427 | 1426 | g_source_remove(watch_id); |
1428 | 1427 | g_io_channel_shutdown(libtcmu_gio, TRUE, NULL); |
1429 | 1428 | g_io_channel_unref (libtcmu_gio); |
1430 | g_object_unref(manager); | |
1429 | if (manager) | |
1430 | g_object_unref(manager); | |
1431 | 1431 | |
1432 | 1432 | ret = 0; |
1433 | 1433 | |
1434 | unwatch_cfg: | |
1434 | loop_unref: | |
1435 | g_main_loop_unref(loop); | |
1435 | 1436 | if (watching_cfg) |
1436 | 1437 | tcmu_unwatch_config(tcmu_cfg); |
1437 | 1438 | tcmulib_close(tcmulib_context); |
108 | 108 | size_t iov_cnt; |
109 | 109 | }; |
110 | 110 | |
111 | static pthread_mutex_t blacklist_caches_lock = PTHREAD_MUTEX_INITIALIZER; | |
112 | static darray(char *) blacklist_caches; | |
111 | static pthread_mutex_t blocklist_caches_lock = PTHREAD_MUTEX_INITIALIZER; | |
112 | static darray(char *) blocklist_caches; | |
113 | 113 | |
114 | 114 | #ifdef LIBRADOS_SUPPORTS_SERVICES |
115 | 115 | |
215 | 215 | } |
216 | 216 | |
217 | 217 | ret = tcmu_rbd_report_event(dev); |
218 | if (ret < 0) | |
219 | tcmu_dev_err(dev, "Could not update status. (Err %d)\n", ret); | |
220 | 218 | |
221 | 219 | free_meta_buf: |
222 | 220 | free(metadata_buf); |
237 | 235 | } |
238 | 236 | |
239 | 237 | #ifdef RBD_LOCK_ACQUIRE_SUPPORT |
240 | static void tcmu_rbd_service_status_update(struct tcmu_device *dev, | |
238 | static int tcmu_rbd_service_status_update(struct tcmu_device *dev, | |
241 | 239 | bool has_lock) |
242 | 240 | { |
241 | return 0; | |
243 | 242 | } |
244 | 243 | #endif /* RBD_LOCK_ACQUIRE_SUPPORT */ |
245 | 244 | |
246 | 245 | #endif /* LIBRADOS_SUPPORTS_SERVICES */ |
247 | 246 | |
248 | 247 | #if defined LIBRADOS_SUPPORTS_GETADDRS || defined RBD_LOCK_ACQUIRE_SUPPORT |
249 | static void tcmu_rbd_rm_stale_entry_from_blacklist(struct tcmu_device *dev, char *addrs) | |
250 | { | |
251 | struct tcmu_rbd_state *state = tcmur_dev_get_private(dev); | |
248 | ||
249 | static int tcmu_rbd_remove_blocklist(struct tcmu_device *dev, char *addr) | |
250 | { | |
251 | struct tcmu_rbd_state *state = tcmur_dev_get_private(dev); | |
252 | char *cmd; | |
253 | int ret; | |
254 | ||
255 | ret = asprintf(&cmd, | |
256 | "{\"prefix\": \"osd blocklist\"," | |
257 | "\"blocklistop\": \"rm\"," | |
258 | "\"addr\": \"%s\"}", | |
259 | addr); | |
260 | if (ret < 0) { | |
261 | tcmu_dev_warn(dev, "Could not allocate blocklist rm command. (Err %d)\n", | |
262 | ret); | |
263 | return -1; | |
264 | } | |
265 | ret = rados_mon_command(state->cluster, (const char**)&cmd, 1, NULL, 0, | |
266 | NULL, NULL, NULL, NULL); | |
267 | free(cmd); | |
268 | if (ret < 0) { | |
269 | tcmu_dev_dbg(dev, "Could not rm blocklist entry '%s'. (Err %d)\n", | |
270 | addr, ret); | |
271 | return 1; | |
272 | } | |
273 | return 0; | |
274 | } | |
275 | ||
276 | /* Old style */ | |
277 | static int tcmu_rbd_remove_blacklist(struct tcmu_device *dev, char *addr) | |
278 | { | |
279 | struct tcmu_rbd_state *state = tcmur_dev_get_private(dev); | |
280 | char *cmd; | |
281 | int ret; | |
282 | ||
283 | ret = asprintf(&cmd, | |
284 | "{\"prefix\": \"osd blacklist\"," | |
285 | "\"blacklistop\": \"rm\"," | |
286 | "\"addr\": \"%s\"}", | |
287 | addr); | |
288 | if (ret < 0) { | |
289 | tcmu_dev_warn(dev, "Could not allocate blacklist rm command. (Err %d)\n", | |
290 | ret); | |
291 | return -1; | |
292 | } | |
293 | ret = rados_mon_command(state->cluster, (const char**)&cmd, 1, NULL, 0, | |
294 | NULL, NULL, NULL, NULL); | |
295 | free(cmd); | |
296 | if (ret < 0) { | |
297 | tcmu_dev_err(dev, "Could not rm blacklist entry '%s'. (Err %d)\n", | |
298 | addr, ret); | |
299 | return 1; | |
300 | } | |
301 | return 0; | |
302 | } | |
303 | ||
304 | static void tcmu_rbd_rm_stale_entry_from_blocklist(struct tcmu_device *dev, char *addrs) | |
305 | { | |
252 | 306 | const char *p, *q, *end; |
253 | char *cmd, *addr; | |
307 | char *addr; | |
254 | 308 | int ret; |
255 | 309 | |
256 | 310 | /* |
302 | 356 | p = NULL; |
303 | 357 | } |
304 | 358 | |
305 | ret = asprintf(&cmd, | |
306 | "{\"prefix\": \"osd blacklist\"," | |
307 | "\"blacklistop\": \"rm\"," | |
308 | "\"addr\": \"%s\"}", | |
309 | addr); | |
359 | ret = tcmu_rbd_remove_blocklist(dev, addr); | |
360 | if (ret > 0) | |
361 | ret = tcmu_rbd_remove_blacklist(dev, addr); | |
310 | 362 | free(addr); |
311 | if (ret < 0) { | |
312 | tcmu_dev_warn(dev, "Could not allocate command. (Err %d)\n", | |
313 | ret); | |
363 | if (ret) | |
314 | 364 | return; |
315 | } | |
316 | ret = rados_mon_command(state->cluster, (const char**)&cmd, 1, NULL, 0, | |
317 | NULL, NULL, NULL, NULL); | |
318 | free(cmd); | |
319 | if (ret < 0) { | |
320 | tcmu_dev_err(dev, "Could not rm blacklist entry '%s'. (Err %d)\n", | |
321 | addr, ret); | |
322 | return; | |
323 | } | |
324 | } | |
325 | } | |
326 | ||
327 | static int tcmu_rbd_rm_stale_entries_from_blacklist(struct tcmu_device *dev) | |
365 | } | |
366 | } | |
367 | ||
368 | static int tcmu_rbd_rm_stale_entries_from_blocklist(struct tcmu_device *dev) | |
328 | 369 | { |
329 | 370 | char **entry, *tmp_entry; |
330 | 371 | int ret = 0; |
331 | 372 | int i; |
332 | 373 | |
333 | pthread_mutex_lock(&blacklist_caches_lock); | |
334 | if (darray_empty(blacklist_caches)) | |
374 | pthread_mutex_lock(&blocklist_caches_lock); | |
375 | if (darray_empty(blocklist_caches)) | |
335 | 376 | goto unlock; |
336 | 377 | |
337 | /* Try to remove all the stale blacklist entities */ | |
338 | darray_foreach(entry, blacklist_caches) { | |
339 | tcmu_dev_info(dev, "removing addrs: {%s}\n", *entry); | |
340 | tcmu_rbd_rm_stale_entry_from_blacklist(dev, *entry); | |
378 | /* Try to remove all the stale blocklist entities */ | |
379 | darray_foreach(entry, blocklist_caches) { | |
380 | tcmu_dev_info(dev, "removing blocklist entry: {%s}\n", *entry); | |
381 | tcmu_rbd_rm_stale_entry_from_blocklist(dev, *entry); | |
341 | 382 | } |
342 | 383 | |
343 | 384 | unlock: |
344 | for (i = darray_size(blacklist_caches) - 1; i >= 0; i--) { | |
345 | tmp_entry = darray_item(blacklist_caches, i); | |
346 | darray_remove(blacklist_caches, i); | |
385 | for (i = darray_size(blocklist_caches) - 1; i >= 0; i--) { | |
386 | tmp_entry = darray_item(blocklist_caches, i); | |
387 | darray_remove(blocklist_caches, i); | |
347 | 388 | free(tmp_entry); |
348 | 389 | } |
349 | 390 | |
350 | pthread_mutex_unlock(&blacklist_caches_lock); | |
391 | pthread_mutex_unlock(&blocklist_caches_lock); | |
351 | 392 | return ret; |
352 | 393 | } |
353 | 394 | #endif // LIBRADOS_SUPPORTS_GETADDRS || RBD_LOCK_ACQUIRE_SUPPORT |
640 | 681 | * Returns: |
641 | 682 | * 0 = client is not owner. |
642 | 683 | * 1 = client is owner. |
643 | * -ESHUTDOWN/-EBLACKLISTED(-108) = client is blacklisted. | |
684 | * -ESHUTDOWN/-EBLOCKLISTED(-108) = client is blocklisted. | |
644 | 685 | * -ETIMEDOUT = rados osd op timeout has expired. |
645 | 686 | * -EIO = misc error. |
646 | 687 | */ |
652 | 693 | ret = rbd_is_exclusive_lock_owner(state->image, &is_owner); |
653 | 694 | if (ret < 0) { |
654 | 695 | if (ret == -ESHUTDOWN) { |
655 | tcmu_dev_dbg(dev, "Client is blacklisted. Could not check lock ownership.\n"); | |
696 | tcmu_dev_dbg(dev, "Client is blocklisted. Could not check lock ownership.\n"); | |
656 | 697 | } else { |
657 | 698 | tcmu_dev_err(dev, "Could not check lock ownership. Error: %s.\n", |
658 | 699 | strerror(-ret)); |
911 | 952 | ret = rbd_lock_get_owners(state->image, &lock_mode, owners1, |
912 | 953 | &num_owners1); |
913 | 954 | if ((!ret && !num_owners1) || ret < 0) { |
914 | tcmu_dev_warn(dev, "Could not get lock owners to store blacklist entry %d!\n", | |
955 | tcmu_dev_warn(dev, "Could not get lock owners to store blocklist entry %d!\n", | |
915 | 956 | ret); |
916 | 957 | } else { |
917 | 958 | int is_owner; |
920 | 961 | ret = rbd_is_exclusive_lock_owner(state->image, &is_owner); |
921 | 962 | if (ret) { |
922 | 963 | rbd_lock_get_owners_cleanup(owners1, num_owners1); |
923 | tcmu_dev_warn(dev, "Could not check lock owners to store blacklist entry %d!\n", | |
964 | tcmu_dev_warn(dev, "Could not check lock owners to store blocklist entry %d!\n", | |
924 | 965 | ret); |
925 | 966 | goto no_owner; |
926 | 967 | } |
929 | 970 | ret = rbd_lock_get_owners(state->image, &lock_mode, owners2, |
930 | 971 | &num_owners2); |
931 | 972 | if ((!ret && !num_owners2) || ret < 0) { |
932 | tcmu_dev_warn(dev, "Could not get lock owners to store blacklist entry %d!\n", | |
973 | tcmu_dev_warn(dev, "Could not get lock owners to store blocklist entry %d!\n", | |
933 | 974 | ret); |
934 | /* Only we didn't lose the lock during the above check will we store the blacklist list */ | |
975 | /* Only we didn't lose the lock during the above check will we store the blocklist list */ | |
935 | 976 | } else if (!strcmp(owners1[0], owners2[0]) && is_owner) { |
936 | 977 | state->addrs = strdup(owners1[0]); // ignore the errors |
937 | 978 | } |
943 | 984 | #endif |
944 | 985 | |
945 | 986 | set_lock_tag: |
946 | tcmu_dev_warn(dev, "Acquired exclusive lock.\n"); | |
987 | tcmu_dev_info(dev, "Acquired exclusive lock.\n"); | |
947 | 988 | if (tag != TCMU_INVALID_LOCK_TAG) |
948 | 989 | ret = tcmu_rbd_set_lock_tag(dev, tag); |
949 | 990 | |
1024 | 1065 | char *config, *dev_cfg_dup; |
1025 | 1066 | struct tcmu_rbd_state *state; |
1026 | 1067 | uint32_t max_blocks, unmap_gran; |
1027 | int ret; | |
1028 | 1068 | char buf[128]; |
1069 | char *savedptr = NULL; | |
1070 | int ret; | |
1029 | 1071 | |
1030 | 1072 | state = calloc(1, sizeof(*state)); |
1031 | 1073 | if (!state) |
1051 | 1093 | } |
1052 | 1094 | config += 1; /* get past '/' */ |
1053 | 1095 | |
1054 | pool = strtok(config, "/"); | |
1096 | pool = strtok_r(config, "/", &savedptr); | |
1055 | 1097 | if (!pool) { |
1056 | 1098 | tcmu_dev_err(dev, "Could not get pool name\n"); |
1057 | 1099 | ret = -EINVAL; |
1064 | 1106 | goto free_config; |
1065 | 1107 | } |
1066 | 1108 | |
1067 | name = strtok(NULL, ";"); | |
1109 | name = strtok_r(NULL, ";", &savedptr); | |
1068 | 1110 | if (!name) { |
1069 | 1111 | tcmu_dev_err(dev, "Could not get image name\n"); |
1070 | 1112 | ret = -EINVAL; |
1079 | 1121 | } |
1080 | 1122 | |
1081 | 1123 | /* The next options are optional */ |
1082 | next_opt = strtok(NULL, ";"); | |
1124 | next_opt = strtok_r(NULL, ";", &savedptr); | |
1083 | 1125 | while (next_opt) { |
1084 | 1126 | if (!strncmp(next_opt, "osd_op_timeout=", 15)) { |
1085 | 1127 | state->osd_op_timeout = strdup(next_opt + 15); |
1104 | 1146 | goto free_config; |
1105 | 1147 | } |
1106 | 1148 | } |
1107 | next_opt = strtok(NULL, ";"); | |
1149 | next_opt = strtok_r(NULL, ";", &savedptr); | |
1108 | 1150 | } |
1109 | 1151 | |
1110 | 1152 | ret = tcmu_rbd_image_open(dev); |
1152 | 1194 | tcmu_dev_set_write_cache_enabled(dev, 0); |
1153 | 1195 | |
1154 | 1196 | #if defined LIBRADOS_SUPPORTS_GETADDRS || defined RBD_LOCK_ACQUIRE_SUPPORT |
1155 | tcmu_rbd_rm_stale_entries_from_blacklist(dev); | |
1197 | tcmu_rbd_rm_stale_entries_from_blocklist(dev); | |
1156 | 1198 | #endif |
1157 | 1199 | |
1158 | 1200 | #ifdef LIBRADOS_SUPPORTS_GETADDRS |
1159 | 1201 | /* Get current entry address for the image */ |
1160 | 1202 | ret = rados_getaddrs(state->cluster, &state->addrs); |
1203 | if (ret < 0) { | |
1204 | tcmu_dev_err(dev, "Could not get address. (Err %d)\n", ret); | |
1205 | goto stop_image; | |
1206 | } | |
1161 | 1207 | tcmu_dev_info(dev, "address: {%s}\n", state->addrs); |
1162 | if (ret < 0) | |
1163 | return ret; | |
1164 | 1208 | #endif |
1165 | 1209 | |
1166 | 1210 | free(dev_cfg_dup); |
1183 | 1227 | |
1184 | 1228 | /* |
1185 | 1229 | * Since we are closing the device, but current device maybe |
1186 | * already blacklisted by other tcmu nodes. Let's just save | |
1187 | * the entity addrs into the blacklist_caches, and let any | |
1230 | * already blocklisted by other tcmu nodes. Let's just save | |
1231 | * the entity addrs into the blocklist_caches, and let any | |
1188 | 1232 | * other new device help remove it. |
1189 | 1233 | */ |
1190 | 1234 | if (state->addrs) { |
1191 | pthread_mutex_lock(&blacklist_caches_lock); | |
1192 | darray_append(blacklist_caches, state->addrs); | |
1193 | pthread_mutex_unlock(&blacklist_caches_lock); | |
1235 | pthread_mutex_lock(&blocklist_caches_lock); | |
1236 | darray_append(blocklist_caches, state->addrs); | |
1237 | pthread_mutex_unlock(&blocklist_caches_lock); | |
1238 | tcmu_dev_info(dev, "appended blocklist entry: {%s}\n", state->addrs); | |
1194 | 1239 | state->addrs = NULL; |
1195 | 1240 | } |
1196 | 1241 | |
1197 | 1242 | tcmu_rbd_state_free(state); |
1198 | 1243 | } |
1199 | 1244 | |
1200 | static int tcmu_rbd_handle_blacklisted_cmd(struct tcmu_device *dev) | |
1245 | static int tcmu_rbd_handle_blocklisted_cmd(struct tcmu_device *dev) | |
1201 | 1246 | { |
1202 | 1247 | tcmu_notify_lock_lost(dev); |
1203 | 1248 | /* |
1204 | 1249 | * This will happen during failback normally, because |
1205 | * running IO is failed due to librbd's immediate blacklisting | |
1250 | * running IO is failed due to librbd's immediate blocklisting | |
1206 | 1251 | * during lock acquisition on a higher priority path. |
1207 | 1252 | */ |
1208 | 1253 | return TCMU_STS_BUSY; |
1227 | 1272 | * that end up reaching it after the initiator's failover/recovery |
1228 | 1273 | * timeout. For implicit and explicit FO, we will just disable |
1229 | 1274 | * the iscsi port, and let the initiator switch paths which will |
1230 | * result in us getting blacklisted, so fail with a retryable | |
1275 | * result in us getting blocklisted, so fail with a retryable | |
1231 | 1276 | * error. |
1232 | 1277 | */ |
1233 | 1278 | return TCMU_STS_TIMEOUT; |
1316 | 1361 | if (ret == -ETIMEDOUT) { |
1317 | 1362 | tcmu_r = tcmu_rbd_handle_timedout_cmd(dev); |
1318 | 1363 | } else if (ret == -ESHUTDOWN || ret == -EROFS) { |
1319 | tcmu_r = tcmu_rbd_handle_blacklisted_cmd(dev); | |
1364 | tcmu_r = tcmu_rbd_handle_blocklisted_cmd(dev); | |
1320 | 1365 | } else if (ret == -EILSEQ && aio_cb->type == RBD_AIO_TYPE_CAW) { |
1321 | 1366 | cmp_offset = aio_cb->caw.miscompare_offset - aio_cb->caw.offset; |
1322 | 1367 | tcmu_dev_dbg(dev, "CAW miscompare at offset %u.\n", cmp_offset); |
1637 | 1682 | case TCMULIB_CFG_DEV_SIZE: |
1638 | 1683 | /* |
1639 | 1684 | * Apps will already have resized on the ceph side, so no |
1640 | * need to double check and have to also handle unblacklisting | |
1685 | * need to double check and have to also handle unblocklisting | |
1641 | 1686 | * the client from this context. |
1642 | 1687 | */ |
1643 | 1688 | return 0; |
1650 | 1695 | |
1651 | 1696 | static int tcmu_rbd_init(void) |
1652 | 1697 | { |
1653 | darray_init(blacklist_caches); | |
1698 | darray_init(blocklist_caches); | |
1654 | 1699 | return 0; |
1655 | 1700 | } |
1656 | 1701 | |
1659 | 1704 | char **entry; |
1660 | 1705 | |
1661 | 1706 | tcmu_info("destroying the rbd handler\n"); |
1662 | pthread_mutex_lock(&blacklist_caches_lock); | |
1663 | if (darray_empty(blacklist_caches)) | |
1707 | pthread_mutex_lock(&blocklist_caches_lock); | |
1708 | if (darray_empty(blocklist_caches)) | |
1664 | 1709 | goto unlock; |
1665 | 1710 | |
1666 | /* Try to remove all the stale blacklist entities */ | |
1667 | darray_foreach(entry, blacklist_caches) | |
1711 | /* Try to remove all the stale blocklist entities */ | |
1712 | darray_foreach(entry, blocklist_caches) | |
1668 | 1713 | free(*entry); |
1669 | 1714 | |
1670 | darray_free(blacklist_caches); | |
1715 | darray_free(blocklist_caches); | |
1671 | 1716 | |
1672 | 1717 | unlock: |
1673 | pthread_mutex_unlock(&blacklist_caches_lock); | |
1718 | pthread_mutex_unlock(&blocklist_caches_lock); | |
1674 | 1719 | } |
1675 | 1720 | |
1676 | 1721 | /* |
799 | 799 | orig_buf[0] = used_len - 1; |
800 | 800 | } |
801 | 801 | |
802 | if (tcmu_dev_get_write_protect_enabled(dev)) { | |
803 | if (sense_ten) { | |
804 | orig_buf[3] |= 0x80; | |
805 | } else { | |
806 | orig_buf[2] |= 0x80; | |
807 | } | |
808 | } | |
809 | ||
802 | 810 | tcmu_memcpy_into_iovec(iovec, iov_cnt, orig_buf, alloc_len); |
803 | 811 | free(orig_buf); |
804 | 812 | return TCMU_STS_OK; |
28 | 28 | static struct list_head tpg_recovery_list = LIST_HEAD_INIT(tpg_recovery_list); |
29 | 29 | /* |
30 | 30 | * Locking ordering: |
31 | * rdev->state_lock | |
31 | * rdev->rdev_lock | |
32 | 32 | * tpg_recovery_lock |
33 | 33 | */ |
34 | 34 | static pthread_mutex_t tpg_recovery_lock = PTHREAD_MUTEX_INITIALIZER; |
34 | 34 | Summary: A daemon that handles the userspace side of the LIO TCM-User backstore |
35 | 35 | Group: System Environment/Daemons |
36 | 36 | License: ASL 2.0 or LGPLv2+ |
37 | Version: 1.5.4 | |
37 | Version: 1.6.0 | |
38 | 38 | URL: https://github.com/open-iscsi/tcmu-runner |
39 | 39 | |
40 | 40 | #%define _RC |
41 | Release: %{?_RC:%{_RC}}%{dist} | |
41 | Release: %{?_RC:%{_RC}}%{?dist} | |
42 | 42 | BuildRoot: %(mktemp -udp %{_tmppath}/%{name}-%{version}%{?_RC:-%{_RC}}) |
43 | 43 | Source: %{name}-%{version}%{?_RC:-%{_RC}}.tar.gz |
44 | 44 | ExclusiveOS: Linux |
39 | 39 | struct tcmur_cmd *tcmur_cmd = cmd->hm_private; |
40 | 40 | struct timespec curr_time; |
41 | 41 | |
42 | pthread_cleanup_push(_cleanup_spin_lock, (void *)&rdev->lock); | |
43 | pthread_spin_lock(&rdev->lock); | |
42 | pthread_cleanup_push(_cleanup_spin_lock, (void *)&rdev->cmds_list_lock); | |
43 | pthread_spin_lock(&rdev->cmds_list_lock); | |
44 | 44 | |
45 | 45 | if (tcmur_cmd->timed_out) { |
46 | 46 | if (tcmur_get_time(dev, &curr_time)) { |
59 | 59 | |
60 | 60 | tcmulib_command_complete(dev, cmd, rc); |
61 | 61 | |
62 | pthread_spin_unlock(&rdev->lock); | |
62 | pthread_spin_unlock(&rdev->cmds_list_lock); | |
63 | 63 | pthread_cleanup_pop(0); |
64 | 64 | } |
65 | 65 | |
2328 | 2328 | { |
2329 | 2329 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
2330 | 2330 | |
2331 | pthread_mutex_lock(&rdev->state_lock); | |
2331 | pthread_mutex_lock(&rdev->rdev_lock); | |
2332 | 2332 | rdev->pending_uas |= (1 << ua); |
2333 | pthread_mutex_unlock(&rdev->state_lock); | |
2333 | pthread_mutex_unlock(&rdev->rdev_lock); | |
2334 | 2334 | } |
2335 | 2335 | |
2336 | 2336 | /* |
2347 | 2347 | /* The kernel will handle REPORT_LUNS */ |
2348 | 2348 | return TCMU_STS_NOT_HANDLED; |
2349 | 2349 | } |
2350 | pthread_mutex_lock(&rdev->state_lock); | |
2350 | pthread_mutex_lock(&rdev->rdev_lock); | |
2351 | 2351 | |
2352 | 2352 | if (!rdev->pending_uas) { |
2353 | 2353 | ret = TCMU_STS_NOT_HANDLED; |
2363 | 2363 | rdev->pending_uas &= ~(1 << ua); |
2364 | 2364 | |
2365 | 2365 | unlock: |
2366 | pthread_mutex_unlock(&rdev->state_lock); | |
2366 | pthread_mutex_unlock(&rdev->rdev_lock); | |
2367 | 2367 | return ret; |
2368 | 2368 | } |
2369 | 2369 |
28 | 28 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
29 | 29 | int in_recov = false; |
30 | 30 | |
31 | pthread_mutex_lock(&rdev->state_lock); | |
31 | pthread_mutex_lock(&rdev->rdev_lock); | |
32 | 32 | if (rdev->flags & TCMUR_DEV_FLAG_IN_RECOVERY) |
33 | 33 | in_recov = true; |
34 | pthread_mutex_unlock(&rdev->state_lock); | |
34 | pthread_mutex_unlock(&rdev->rdev_lock); | |
35 | 35 | return in_recov; |
36 | 36 | } |
37 | 37 | |
45 | 45 | int ret, attempt = 0; |
46 | 46 | bool needs_close = false; |
47 | 47 | |
48 | pthread_mutex_lock(&rdev->state_lock); | |
48 | pthread_mutex_lock(&rdev->rdev_lock); | |
49 | 49 | if (rdev->flags & TCMUR_DEV_FLAG_STOPPING) { |
50 | 50 | ret = 0; |
51 | 51 | goto done; |
52 | 52 | } |
53 | pthread_mutex_unlock(&rdev->state_lock); | |
53 | pthread_mutex_unlock(&rdev->rdev_lock); | |
54 | 54 | |
55 | 55 | /* |
56 | 56 | * There are no SCSI commands running but there may be |
59 | 59 | */ |
60 | 60 | tcmur_flush_work(rdev->event_work); |
61 | 61 | |
62 | pthread_mutex_lock(&rdev->state_lock); | |
62 | pthread_mutex_lock(&rdev->rdev_lock); | |
63 | 63 | if (rdev->flags & TCMUR_DEV_FLAG_IS_OPEN) |
64 | 64 | needs_close = true; |
65 | 65 | rdev->flags &= ~TCMUR_DEV_FLAG_IS_OPEN; |
66 | pthread_mutex_unlock(&rdev->state_lock); | |
66 | pthread_mutex_unlock(&rdev->rdev_lock); | |
67 | 67 | |
68 | 68 | if (pthread_self() != rdev->cmdproc_thread) |
69 | 69 | /* |
76 | 76 | tcmu_dev_dbg(dev, "Waiting for outstanding commands to complete\n"); |
77 | 77 | ret = aio_wait_for_empty_queue(rdev); |
78 | 78 | if (ret) { |
79 | pthread_mutex_lock(&rdev->state_lock); | |
79 | pthread_mutex_lock(&rdev->rdev_lock); | |
80 | 80 | goto done; |
81 | 81 | } |
82 | 82 | |
85 | 85 | rhandler->close(dev); |
86 | 86 | } |
87 | 87 | |
88 | pthread_mutex_lock(&rdev->state_lock); | |
88 | pthread_mutex_lock(&rdev->rdev_lock); | |
89 | 89 | ret = -EIO; |
90 | 90 | while (ret != 0 && !(rdev->flags & TCMUR_DEV_FLAG_STOPPING) && |
91 | 91 | (retries < 0 || attempt <= retries)) { |
92 | pthread_mutex_unlock(&rdev->state_lock); | |
92 | pthread_mutex_unlock(&rdev->rdev_lock); | |
93 | 93 | |
94 | 94 | tcmu_dev_dbg(dev, "Opening device. Attempt %d\n", attempt); |
95 | 95 | ret = rhandler->open(dev, true); |
98 | 98 | sleep(1); |
99 | 99 | } |
100 | 100 | |
101 | pthread_mutex_lock(&rdev->state_lock); | |
101 | pthread_mutex_lock(&rdev->rdev_lock); | |
102 | 102 | if (!ret) { |
103 | 103 | rdev->flags |= TCMUR_DEV_FLAG_IS_OPEN; |
104 | 104 | rdev->lock_lost = false; |
108 | 108 | |
109 | 109 | done: |
110 | 110 | rdev->flags &= ~TCMUR_DEV_FLAG_IN_RECOVERY; |
111 | pthread_mutex_unlock(&rdev->state_lock); | |
111 | pthread_mutex_unlock(&rdev->rdev_lock); | |
112 | 112 | |
113 | 113 | return ret; |
114 | 114 | } |
122 | 122 | { |
123 | 123 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
124 | 124 | |
125 | pthread_mutex_lock(&rdev->state_lock); | |
125 | pthread_mutex_lock(&rdev->rdev_lock); | |
126 | 126 | if (rdev->flags & TCMUR_DEV_FLAG_IN_RECOVERY) { |
127 | pthread_mutex_unlock(&rdev->state_lock); | |
127 | pthread_mutex_unlock(&rdev->rdev_lock); | |
128 | 128 | return -EBUSY; |
129 | 129 | } |
130 | 130 | rdev->flags |= TCMUR_DEV_FLAG_IN_RECOVERY; |
131 | pthread_mutex_unlock(&rdev->state_lock); | |
131 | pthread_mutex_unlock(&rdev->rdev_lock); | |
132 | 132 | |
133 | 133 | return __tcmu_reopen_dev(dev, retries); |
134 | 134 | } |
143 | 143 | * handlers to fail/complete normally to avoid a segfault. |
144 | 144 | */ |
145 | 145 | tcmu_dev_dbg(dev, "Waiting on recovery thread\n"); |
146 | pthread_mutex_lock(&rdev->state_lock); | |
146 | pthread_mutex_lock(&rdev->rdev_lock); | |
147 | 147 | while (rdev->flags & TCMUR_DEV_FLAG_IN_RECOVERY) { |
148 | pthread_mutex_unlock(&rdev->state_lock); | |
148 | pthread_mutex_unlock(&rdev->rdev_lock); | |
149 | 149 | sleep(1); |
150 | pthread_mutex_lock(&rdev->state_lock); | |
151 | } | |
152 | pthread_mutex_unlock(&rdev->state_lock); | |
150 | pthread_mutex_lock(&rdev->rdev_lock); | |
151 | } | |
152 | pthread_mutex_unlock(&rdev->rdev_lock); | |
153 | 153 | tcmu_dev_dbg(dev, "Recovery thread wait done\n"); |
154 | 154 | } |
155 | 155 | |
166 | 166 | */ |
167 | 167 | sleep(1); |
168 | 168 | |
169 | pthread_mutex_lock(&rdev->state_lock); | |
169 | pthread_mutex_lock(&rdev->rdev_lock); | |
170 | 170 | ret = rhandler->report_event(dev); |
171 | 171 | if (ret) |
172 | 172 | tcmu_dev_err(dev, "Could not report events. Error %d.\n", ret); |
173 | pthread_mutex_unlock(&rdev->state_lock); | |
173 | pthread_mutex_unlock(&rdev->rdev_lock); | |
174 | 174 | } |
175 | 175 | |
176 | 176 | static void tcmu_report_event(struct tcmu_device *dev) |
235 | 235 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
236 | 236 | bool report; |
237 | 237 | |
238 | pthread_mutex_lock(&rdev->state_lock); | |
238 | pthread_mutex_lock(&rdev->rdev_lock); | |
239 | 239 | report =__tcmu_notify_conn_lost(dev); |
240 | pthread_mutex_unlock(&rdev->state_lock); | |
240 | pthread_mutex_unlock(&rdev->rdev_lock); | |
241 | 241 | |
242 | 242 | if (report) |
243 | 243 | tcmu_report_event(dev); |
266 | 266 | { |
267 | 267 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
268 | 268 | |
269 | pthread_mutex_lock(&rdev->state_lock); | |
269 | pthread_mutex_lock(&rdev->rdev_lock); | |
270 | 270 | tcmu_dev_warn(dev, "Async lock drop. Old state %d\n", rdev->lock_state); |
271 | 271 | /* |
272 | 272 | * We could be getting stale IO completions. If we are trying to |
275 | 275 | if (rdev->lock_state != TCMUR_DEV_LOCK_WRITE_LOCKING) { |
276 | 276 | __tcmu_notify_lock_lost(dev); |
277 | 277 | } |
278 | pthread_mutex_unlock(&rdev->state_lock); | |
278 | pthread_mutex_unlock(&rdev->rdev_lock); | |
279 | 279 | } |
280 | 280 | |
281 | 281 | void tcmu_release_dev_lock(struct tcmu_device *dev) |
284 | 284 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
285 | 285 | int ret; |
286 | 286 | |
287 | pthread_mutex_lock(&rdev->state_lock); | |
287 | pthread_mutex_lock(&rdev->rdev_lock); | |
288 | 288 | if (rdev->lock_state != TCMUR_DEV_LOCK_WRITE_LOCKED) { |
289 | pthread_mutex_unlock(&rdev->state_lock); | |
289 | pthread_mutex_unlock(&rdev->rdev_lock); | |
290 | 290 | return; |
291 | 291 | } |
292 | 292 | |
293 | 293 | if (!(rdev->flags & TCMUR_DEV_FLAG_IS_OPEN)) { |
294 | 294 | tcmu_dev_dbg(dev, "Device is closed so unlock is not needed\n"); |
295 | 295 | rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED; |
296 | pthread_mutex_unlock(&rdev->state_lock); | |
296 | pthread_mutex_unlock(&rdev->rdev_lock); | |
297 | 297 | return; |
298 | 298 | } |
299 | 299 | |
300 | pthread_mutex_unlock(&rdev->state_lock); | |
300 | pthread_mutex_unlock(&rdev->rdev_lock); | |
301 | 301 | |
302 | 302 | ret = rhandler->unlock(dev); |
303 | 303 | if (ret != TCMU_STS_OK) |
308 | 308 | * to unlocked to prevent new IO from executing in case the lock |
309 | 309 | * is in a state where it cannot be fenced. |
310 | 310 | */ |
311 | pthread_mutex_lock(&rdev->state_lock); | |
311 | pthread_mutex_lock(&rdev->rdev_lock); | |
312 | 312 | rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED; |
313 | pthread_mutex_unlock(&rdev->state_lock); | |
313 | pthread_mutex_unlock(&rdev->rdev_lock); | |
314 | 314 | } |
315 | 315 | |
316 | 316 | int tcmu_get_lock_tag(struct tcmu_device *dev, uint16_t *tag) |
322 | 322 | if (rdev->failover_type != TCMUR_DEV_FAILOVER_EXPLICIT) |
323 | 323 | return 0; |
324 | 324 | |
325 | pthread_mutex_lock(&rdev->state_lock); | |
325 | pthread_mutex_lock(&rdev->rdev_lock); | |
326 | 326 | if (!(rdev->flags & TCMUR_DEV_FLAG_IS_OPEN)) { |
327 | 327 | /* |
328 | 328 | * Return tmp error until the recovery thread is able to |
329 | 329 | * start up. |
330 | 330 | */ |
331 | pthread_mutex_unlock(&rdev->state_lock); | |
331 | pthread_mutex_unlock(&rdev->rdev_lock); | |
332 | 332 | return TCMU_STS_BUSY; |
333 | 333 | } |
334 | pthread_mutex_unlock(&rdev->state_lock); | |
334 | pthread_mutex_unlock(&rdev->rdev_lock); | |
335 | 335 | |
336 | 336 | retry: |
337 | 337 | ret = rhandler->get_lock_tag(dev, tag); |
414 | 414 | */ |
415 | 415 | |
416 | 416 | reopen = false; |
417 | pthread_mutex_lock(&rdev->state_lock); | |
417 | pthread_mutex_lock(&rdev->rdev_lock); | |
418 | 418 | if (rdev->lock_lost || !(rdev->flags & TCMUR_DEV_FLAG_IS_OPEN)) |
419 | 419 | reopen = true; |
420 | pthread_mutex_unlock(&rdev->state_lock); | |
420 | pthread_mutex_unlock(&rdev->rdev_lock); | |
421 | 421 | |
422 | 422 | retry: |
423 | 423 | tcmu_dev_dbg(dev, "lock call state %d retries %d. tag %hu reopen %d\n", |
435 | 435 | } |
436 | 436 | } |
437 | 437 | |
438 | pthread_mutex_lock(&rdev->state_lock); | |
438 | pthread_mutex_lock(&rdev->rdev_lock); | |
439 | 439 | if (rdev->lock_state == TCMUR_DEV_LOCK_READ_LOCKING) { |
440 | pthread_mutex_unlock(&rdev->state_lock); | |
440 | pthread_mutex_unlock(&rdev->rdev_lock); | |
441 | 441 | ret = TCMU_STS_OK; |
442 | 442 | goto done; |
443 | 443 | } |
444 | pthread_mutex_unlock(&rdev->state_lock); | |
444 | pthread_mutex_unlock(&rdev->rdev_lock); | |
445 | 445 | |
446 | 446 | ret = rhandler->lock(dev, tag); |
447 | 447 | if (ret == TCMU_STS_FENCED) { |
475 | 475 | tcmu_dev_flush_ring(dev); |
476 | 476 | |
477 | 477 | /* TODO: set UA based on bgly's patches */ |
478 | pthread_mutex_lock(&rdev->state_lock); | |
478 | pthread_mutex_lock(&rdev->rdev_lock); | |
479 | 479 | if (ret != TCMU_STS_OK) { |
480 | 480 | rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED; |
481 | 481 | tcmu_dev_info(dev, "Lock acquisition unsuccessful\n"); |
497 | 497 | |
498 | 498 | tcmu_cfgfs_dev_exec_action(dev, "block_dev", 0); |
499 | 499 | |
500 | pthread_mutex_unlock(&rdev->state_lock); | |
500 | pthread_mutex_unlock(&rdev->rdev_lock); | |
501 | 501 | |
502 | 502 | return ret; |
503 | 503 | } |
511 | 511 | if (!rhandler->get_lock_state) |
512 | 512 | return; |
513 | 513 | |
514 | pthread_mutex_lock(&rdev->state_lock); | |
514 | pthread_mutex_lock(&rdev->rdev_lock); | |
515 | 515 | if (!(rdev->flags & TCMUR_DEV_FLAG_IS_OPEN)) { |
516 | 516 | tcmu_dev_dbg(dev, "device closed.\n"); |
517 | 517 | state = TCMUR_DEV_LOCK_UNKNOWN; |
518 | 518 | goto check_state; |
519 | 519 | } |
520 | pthread_mutex_unlock(&rdev->state_lock); | |
520 | pthread_mutex_unlock(&rdev->rdev_lock); | |
521 | 521 | |
522 | 522 | state = rhandler->get_lock_state(dev); |
523 | pthread_mutex_lock(&rdev->state_lock); | |
523 | pthread_mutex_lock(&rdev->rdev_lock); | |
524 | 524 | check_state: |
525 | 525 | if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED && |
526 | 526 | state != TCMUR_DEV_LOCK_WRITE_LOCKED) { |
527 | 527 | tcmu_dev_dbg(dev, "Updated out of sync lock state.\n"); |
528 | 528 | __tcmu_notify_lock_lost(dev); |
529 | 529 | } |
530 | pthread_mutex_unlock(&rdev->state_lock); | |
530 | pthread_mutex_unlock(&rdev->rdev_lock); | |
531 | 531 | } |
532 | 532 | |
533 | 533 | void tcmur_dev_set_private(struct tcmu_device *dev, void *private) |
548 | 548 | { |
549 | 549 | struct tcmur_device *rdev = tcmu_dev_get_private(dev); |
550 | 550 | |
551 | pthread_mutex_lock(&rdev->state_lock); | |
551 | pthread_mutex_lock(&rdev->rdev_lock); | |
552 | 552 | rdev->cmd_timed_out_cnt++; |
553 | 553 | __tcmu_notify_conn_lost(dev); |
554 | pthread_mutex_unlock(&rdev->state_lock); | |
554 | pthread_mutex_unlock(&rdev->rdev_lock); | |
555 | 555 | |
556 | 556 | tcmu_report_event(dev); |
557 | 557 | } |
47 | 47 | |
48 | 48 | pthread_t cmdproc_thread; |
49 | 49 | |
50 | /* General lock for the members from "flags" to "pending_uas" */ | |
51 | pthread_mutex_t rdev_lock; | |
52 | ||
50 | 53 | /* TCMUR_DEV flags */ |
51 | 54 | uint32_t flags; |
52 | 55 | uint8_t failover_type; |
62 | 65 | bool lock_lost; |
63 | 66 | uint8_t lock_state; |
64 | 67 | |
65 | /* General lock for lock state, thread, dev state, etc */ | |
66 | pthread_mutex_t state_lock; | |
67 | 68 | int pending_uas; |
68 | 69 | |
69 | 70 | /* |
74 | 75 | struct tcmu_io_queue work_queue; |
75 | 76 | struct tcmu_track_aio track_queue; |
76 | 77 | |
77 | pthread_spinlock_t lock; /* protects concurrent updates to mailbox */ | |
78 | 78 | pthread_mutex_t caw_lock; /* for atomic CAW operation */ |
79 | 79 | |
80 | 80 | uint32_t format_progress; |
81 | 81 | pthread_mutex_t format_lock; /* for atomic format operations */ |
82 | 82 | |
83 | 83 | int cmd_time_out; |
84 | ||
85 | pthread_spinlock_t cmds_list_lock; /* protects cmds_list */ | |
84 | 86 | struct list_head cmds_list; |
85 | 87 | }; |
86 | 88 |
40 | 40 | |
41 | 41 | static void __tcmur_flush_work(struct tcmur_work *work) |
42 | 42 | { |
43 | char pname[TCMU_THREAD_NAME_LEN]; | |
44 | ||
45 | if (pthread_getname_np(pthread_self(), pname, TCMU_THREAD_NAME_LEN)) | |
46 | return; | |
47 | ||
48 | 43 | /* |
49 | 44 | * The event work thread may need to do a handler reopen |
50 | 45 | * call and try to flush itself. Just ignore. |
51 | 46 | */ |
52 | if (!strcmp(pname, "ework-thread")) | |
47 | if (__tcmu_is_ework_thread) | |
53 | 48 | return; |
54 | 49 | |
55 | 50 | /* |
78 | 73 | struct private *p = data; |
79 | 74 | |
80 | 75 | tcmu_set_thread_name("ework-thread", NULL); |
76 | __tcmu_is_ework_thread = 1; | |
81 | 77 | |
82 | 78 | p->work_fn(p->data); |
83 | 79 |