Codebase list tcmu / d5a6f70
New upstream version 1.5.4 Sébastien Delafond 3 years ago
27 changed file(s) with 1483 addition(s) and 590 deletion(s). Raw diff Collapse all Expand all
00 cmake_minimum_required (VERSION 2.8 FATAL_ERROR)
11 project (tcmu-runner C)
2 set(VERSION 1.5.2)
2 set(VERSION 1.5.4)
33 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wdeclaration-after-statement -std=c99")
44
55 include(GNUInstallDirs)
6767 ${LIBNL_LIB}
6868 ${LIBNL_GENL_LIB}
6969 ${GLIB_LIBRARIES}
70 ${PTHREAD}
7071 ${TCMALLOC_LIB}
7172 )
7273 install(TARGETS tcmu LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
9596
9697 # Stuff for building the main binary
9798 add_executable(tcmu-runner
99 tcmur_work.c
98100 tcmur_cmd_handler.c
99101 tcmur_aio.c
100102 tcmur_device.c
169171 )
170172
171173 if (with-fbo)
172 # Stuff for building the file optical handler
173 add_library(handler_file_optical
174 SHARED
175 scsi.c
176 file_optical.c
177 )
178 set_target_properties(handler_file_optical
179 PROPERTIES
180 PREFIX ""
181 )
182 target_include_directories(handler_file_optical
183 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
184 )
185 target_link_libraries(handler_file_optical ${PTHREAD} ${TCMALLOC_LIB})
186 install(TARGETS handler_file_optical DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
174 # Stuff for building the file optical handler
175 add_library(handler_file_optical
176 SHARED
177 scsi.c
178 file_optical.c
179 )
180
181 set_target_properties(handler_file_optical
182 PROPERTIES
183 PREFIX ""
184 )
185
186 target_include_directories(handler_file_optical
187 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
188 )
189 target_link_libraries(handler_file_optical ${PTHREAD} ${TCMALLOC_LIB})
190 install(TARGETS handler_file_optical DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
187191 endif (with-fbo)
188192
189193 # The minimal library consumer
194198 target_link_libraries(consumer tcmu)
195199
196200 if (with-zbc)
197 # Stuff for building the file zbc handler
198 add_library(handler_file_zbc
199 SHARED
200 scsi.c
201 file_zbc.c
202 )
203 set_target_properties(handler_file_zbc
204 PROPERTIES
205 PREFIX ""
206 )
207 target_include_directories(handler_file_zbc
208 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
209 )
210 target_link_libraries(handler_file_zbc ${TCMALLOC_LIB})
211 install(TARGETS handler_file_zbc DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
201 # Stuff for building the file zbc handler
202 add_library(handler_file_zbc
203 SHARED
204 scsi.c
205 file_zbc.c
206 )
207 set_target_properties(handler_file_zbc
208 PROPERTIES
209 PREFIX ""
210 )
211 target_include_directories(handler_file_zbc
212 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
213 )
214 target_link_libraries(handler_file_zbc ${TCMALLOC_LIB})
215 install(TARGETS handler_file_zbc DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
212216 endif (with-zbc)
213217
214218 if (with-rbd)
215 find_library(LIBRBD rbd)
216
217 # Stuff for building the rbd handler
218 add_library(handler_rbd
219 SHARED
220 rbd.c
221 )
222 set_target_properties(handler_rbd
223 PROPERTIES
224 PREFIX ""
225 )
226 target_include_directories(handler_rbd
227 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
228 )
229 target_link_libraries(handler_rbd
230 ${LIBRBD}
231 ${TCMALLOC_LIB}
232 )
233 install(TARGETS handler_rbd DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
219 find_library(LIBRBD rbd)
220
221 # Stuff for building the rbd handler
222 add_library(handler_rbd
223 SHARED
224 rbd.c
225 )
226 set_target_properties(handler_rbd
227 PROPERTIES
228 PREFIX ""
229 )
230 target_include_directories(handler_rbd
231 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
232 )
233 target_link_libraries(handler_rbd
234 ${LIBRBD}
235 ${TCMALLOC_LIB}
236 )
237 install(TARGETS handler_rbd DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
234238 endif (with-rbd)
235239
236240 if (with-glfs)
237 find_library(GFAPI gfapi)
238
239 set(GFAPI_VERSION760 0)
240
241 pkg_check_modules(GFAPI760 glusterfs-api>=7.6 QUIET)
242 if (GFAPI760_FOUND)
243 set(GFAPI_VERSION760 1)
244 endif (GFAPI760_FOUND)
245
246 # Stuff for building the glfs handler
247 add_library(handler_glfs
248 SHARED
249 glfs.c
250 )
251 set_target_properties(handler_glfs
252 PROPERTIES
253 PREFIX ""
254 )
255 target_include_directories(handler_glfs
256 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
257 )
258 target_link_libraries(handler_glfs
259 ${GFAPI}
260 ${TCMALLOC_LIB}
261 )
262 install(TARGETS handler_glfs DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
241 find_library(GFAPI gfapi)
242
243 set(GFAPI_VERSION760 0)
244
245 pkg_check_modules(GFAPI760 glusterfs-api>=7.6 QUIET)
246 if (GFAPI760_FOUND)
247 set(GFAPI_VERSION760 1)
248 endif (GFAPI760_FOUND)
249
250 set(GFAPI_VERSION766 0)
251
252 pkg_check_modules(GFAPI766 glusterfs-api>=7.6.6 QUIET)
253 if (GFAPI766_FOUND)
254 set(GFAPI_VERSION766 1)
255 endif (GFAPI766_FOUND)
256
257 # Stuff for building the glfs handler
258 add_library(handler_glfs
259 SHARED
260 glfs.c
261 )
262 set_target_properties(handler_glfs
263 PROPERTIES
264 PREFIX ""
265 )
266 target_include_directories(handler_glfs
267 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
268 )
269 target_link_libraries(handler_glfs
270 ${GFAPI}
271 ${TCMALLOC_LIB}
272 )
273 install(TARGETS handler_glfs DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
263274 endif (with-glfs)
264275
265276 if (with-qcow)
266 find_package(ZLIB REQUIRED)
267
268 # Stuff for building the qcow handler
269 add_library(handler_qcow
270 SHARED
271 qcow.c
272 )
273 set_target_properties(handler_qcow
274 PROPERTIES
275 PREFIX ""
276 )
277 target_include_directories(handler_qcow
278 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
279 )
280
281 CHECK_INCLUDE_FILE("linux/falloc.h" HAVE_LINUX_FALLOC)
282 if (HAVE_LINUX_FALLOC)
283 set_target_properties(handler_qcow
284 PROPERTIES
285 COMPILE_FLAGS "-DHAVE_LINUX_FALLOC"
286 )
287 endif (HAVE_LINUX_FALLOC)
288 target_link_libraries(handler_qcow
289 ${ZLIB_LIBRARIES}
290 ${TCMALLOC_LIB}
291 )
292 install(TARGETS handler_qcow DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
277 find_package(ZLIB REQUIRED)
278
279 # Stuff for building the qcow handler
280 add_library(handler_qcow
281 SHARED
282 qcow.c
283 )
284 set_target_properties(handler_qcow
285 PROPERTIES
286 PREFIX ""
287 )
288 target_include_directories(handler_qcow
289 PUBLIC ${PROJECT_SOURCE_DIR}/ccan
290 )
291
292 CHECK_INCLUDE_FILE("linux/falloc.h" HAVE_LINUX_FALLOC)
293 if (HAVE_LINUX_FALLOC)
294 set_target_properties(handler_qcow
295 PROPERTIES
296 COMPILE_FLAGS "-DHAVE_LINUX_FALLOC"
297 )
298 endif (HAVE_LINUX_FALLOC)
299 target_link_libraries(handler_qcow
300 ${ZLIB_LIBRARIES}
301 ${TCMALLOC_LIB}
302 )
303 install(TARGETS handler_qcow DESTINATION ${CMAKE_INSTALL_LIBDIR}/tcmu-runner)
293304 endif (with-qcow)
294305
295306 # stamp out a header file to pass some of the CMake settings
317328 if (SUPPORT_SYSTEMD)
318329 install(FILES tcmu-runner.service DESTINATION /usr/lib/systemd/system/)
319330 endif (SUPPORT_SYSTEMD)
320 install(FILES tcmu-runner.8
321 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man8)
331 install(FILES tcmu-runner.8 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man8)
2424 #include "libtcmu_priv.h"
2525 #include "tcmu-runner.h"
2626 #include "tcmur_device.h"
27 #include "tcmur_work.h"
2728 #include "target.h"
2829 #include "alua.h"
2930
431432 * lock state to avoid later blacklist errors.
432433 */
433434 pthread_mutex_lock(&rdev->state_lock);
434 if (rdev->lock_state == TCMUR_DEV_LOCK_LOCKED) {
435 if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED) {
435436 tcmu_dev_dbg(dev, "Dropping lock\n");
436437 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
437438 }
541542 return !!rhandler->lock;
542543 }
543544
544 static void *alua_lock_thread_fn(void *arg)
545 {
545 static void alua_event_work_fn(void *arg)
546 {
547 struct tcmu_device *dev = arg;
548
546549 /* TODO: set UA based on bgly's patches */
547 tcmu_acquire_dev_lock(arg, -1);
548 return NULL;
549 }
550
551 int alua_implicit_transition(struct tcmu_device *dev, struct tcmulib_cmd *cmd)
550 tcmu_acquire_dev_lock(dev, -1);
551 }
552
553 int alua_implicit_transition(struct tcmu_device *dev, struct tcmulib_cmd *cmd,
554 bool is_read)
552555 {
553556 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
554 pthread_attr_t attr;
555557 int ret = TCMU_STS_OK;
556558
557559 if (!lock_is_required(dev))
558560 return ret;
559561
560562 pthread_mutex_lock(&rdev->state_lock);
561 if (rdev->lock_state == TCMUR_DEV_LOCK_LOCKED) {
563 if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED) {
564 /* For both read/write cases in this state is good */
562565 goto done;
563 } else if (rdev->lock_state == TCMUR_DEV_LOCK_LOCKING) {
564 tcmu_dev_dbg(dev, "Lock acquisition operation is already in process.\n");
566 } else if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKING) {
567 /* For both read/write cases in this state should return busy */
568 tcmu_dev_dbg(dev, "Write lock acquisition operation is already in process.\n");
565569 ret = TCMU_STS_BUSY;
566570 goto done;
567 }
568
569 tcmu_dev_info(dev, "Starting lock acquisition operation.\n");
570
571 rdev->lock_state = TCMUR_DEV_LOCK_LOCKING;
572
573 /*
574 * Make the lock_thread as detached to fix the memory leakage bug.
575 */
576 pthread_attr_init(&attr);
577 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
571 } else if (rdev->lock_state == TCMUR_DEV_LOCK_READ_LOCKING) {
572 /* For both read/write they need to retry */
573 tcmu_dev_dbg(dev, "Read lock acquisition operation is already in process.\n");
574 ret = TCMU_STS_BUSY;
575 goto done;
576 } else if (is_read) {
577 if (rdev->lock_state == TCMUR_DEV_LOCK_READ_LOCKED)
578 goto done;
579
580 tcmu_dev_info(dev, "Starting read lock acquisition operation.\n");
581
582 /*
583 * Since we are here, current lock state should be one of:
584 * TCMUR_DEV_LOCK_UNLOCKED
585 * TCMUR_DEV_LOCK_UNKNOWN
586 *
587 * Will not acquire the lock, just reopen the device.
588 */
589 rdev->lock_state = TCMUR_DEV_LOCK_READ_LOCKING;
590 } else {
591 tcmu_dev_info(dev, "Starting write lock acquisition operation.\n");
592
593 /*
594 * Since we are here, current lock state should be one of:
595 * TCMUR_DEV_LOCK_UNLOCKED
596 * TCMUR_DEV_LOCK_UNKNOWN
597 * TCMUR_DEV_LOCK_READ_LOCKING
598 * TCMUR_DEV_LOCK_READ_LOCKED
599 *
600 * May will reopen the deivce and Will acquire the lock later.
601 */
602 rdev->lock_state = TCMUR_DEV_LOCK_WRITE_LOCKING;
603 }
578604
579605 /*
580606 * The initiator is going to be queueing commands, so do this
581607 * in the background to avoid command timeouts.
582608 */
583 if (pthread_create(&rdev->lock_thread, &attr, alua_lock_thread_fn,
584 dev)) {
609 if (tcmur_run_work(rdev->event_work, dev, alua_event_work_fn)) {
585610 tcmu_dev_err(dev, "Could not start implicit transition thread:%s\n",
586611 strerror(errno));
587612 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
589614 } else {
590615 ret = TCMU_STS_BUSY;
591616 }
592
593 pthread_attr_destroy(&attr);
594617
595618 done:
596619 pthread_mutex_unlock(&rdev->state_lock);
767790 return ret;
768791 }
769792
770 int alua_check_state(struct tcmu_device *dev, struct tcmulib_cmd *cmd)
793 int alua_check_state(struct tcmu_device *dev, struct tcmulib_cmd *cmd, bool is_read)
771794 {
772795 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
773796
774797 if (rdev->failover_type == TCMUR_DEV_FAILOVER_EXPLICIT) {
775 if (rdev->lock_state != TCMUR_DEV_LOCK_LOCKED) {
798 if (rdev->lock_state != TCMUR_DEV_LOCK_WRITE_LOCKED) {
776799 tcmu_dev_dbg(dev, "device lock not held.\n");
777800 return TCMU_STS_FENCED;
778801 }
779802 } else if (rdev->failover_type == TCMUR_DEV_FAILOVER_IMPLICIT) {
780 return alua_implicit_transition(dev, cmd);
803 return alua_implicit_transition(dev, cmd, is_read);
781804 }
782805
783806 return TCMU_STS_OK;
4444 struct tgt_port *tcmu_get_enabled_port(struct list_head *);
4545 int tcmu_get_alua_grps(struct tcmu_device *, struct list_head *);
4646 void tcmu_release_alua_grps(struct list_head *);
47 int alua_implicit_transition(struct tcmu_device *dev, struct tcmulib_cmd *cmd);
47 int alua_implicit_transition(struct tcmu_device *dev, struct tcmulib_cmd *cmd,
48 bool is_read);
4849 bool lock_is_required(struct tcmu_device *dev);
49 int alua_check_state(struct tcmu_device *dev, struct tcmulib_cmd *cmd);
50 int alua_check_state(struct tcmu_device *dev, struct tcmulib_cmd *cmd, bool is_read);
5051
5152 #endif
313313 return copied;
314314 }
315315
316 #define CDB_TO_BUF_SIZE(bytes) ((bytes) * 3 + 1)
316 #define CDB_TO_BUF_SIZE(bytes) ((bytes) * 3 + 2)
317317 #define CDB_FIX_BYTES 64 /* 64 bytes for default */
318318 #define CDB_FIX_SIZE CDB_TO_BUF_SIZE(CDB_FIX_BYTES)
319319 void tcmu_cdb_print_info(struct tcmu_device *dev,
320320 const struct tcmulib_cmd *cmd,
321321 const char *info)
322322 {
323 int i, n, bytes;
323 int i, n, bytes, info_len = 0;
324324 char fix[CDB_FIX_SIZE], *buf;
325325
326326 buf = fix;
329329 if (bytes < 0)
330330 return;
331331
332 if (bytes > CDB_FIX_SIZE) {
333 buf = malloc(CDB_TO_BUF_SIZE(bytes));
332 if (info)
333 info_len = strlen(info);
334
335 if (CDB_TO_BUF_SIZE(bytes) + info_len > CDB_FIX_SIZE) {
336 buf = malloc(CDB_TO_BUF_SIZE(bytes) + info_len);
334337 if (!buf) {
335338 tcmu_dev_err(dev, "out of memory\n");
336339 return;
352355 tcmu_dev_dbg_scsi_cmd(dev, "%s", buf);
353356 }
354357
355 if (bytes > CDB_FIX_SIZE)
358 if (buf != fix)
356359 free(buf);
357360 }
358361
0 #!/bin/sh
0 #!/bin/bash
11 #
22 # Userspace side of the LIO TCM-User backstore
33 #
2222 yum search librbd-devel | grep -q "N/S matched" && LIBRBD=librbd || LIBRBD=librbd1
2323 $SUDO yum install -y $LIBRBD-devel
2424 ;;
25 debian)
26 # Update APT cache
27 $SUDO apt update
28
29 # 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
32
33 # for glusterfs
34 $SUDO apt install -y libglusterfs-dev
35
36 # for ceph
37 $SUDO apt install -y librados2 librbd-dev
38 ;;
39 sles|opensuse-tumbleweed)
40 # 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
43
44 #for glusterfs
45 $SUDO zypper install -y glusterfs-devel glusterfs
46 #for ceph
47 $SUDO zypper install -y librbd-devel librados-devel librados2
48 ;;
2549 *)
26 echo "TODO: only fedora/rhel/centos are supported for now!"
50 echo "TODO: distro not supported for now!"
2751 ;;
2852 esac
2953 else
10031003 struct fbo_state *state = tcmur_dev_get_private(dev);
10041004 uint8_t sense[SENSE_BUFFERSIZE];
10051005
1006 tcmu_set_thread_name("fbo-cache", dev);
1007
10061008 pthread_mutex_lock(&state->state_mtx);
10071009 state->async_cache_count++;
10081010 state->flags |= FBO_BUSY_EVENT;
13181320 struct fbo_state *state = tcmur_dev_get_private(dev);
13191321 uint8_t sense[SENSE_BUFFERSIZE];
13201322
1323 tcmu_set_thread_name("fbo-format", dev);
1324
13211325 pthread_mutex_lock(&state->state_mtx);
13221326 state->flags |= FBO_BUSY_EVENT | FBO_FORMAT_IMMED;
13231327 pthread_mutex_unlock(&state->state_mtx);
951951 case 0x00:
952952 /* Supported VPD pages */
953953 data[3] = 5;
954 data[4] = 0x83;
955 data[5] = 0xb0;
956 data[6] = 0xb1;
957 data[7] = 0xb6;
958
959 tcmu_memcpy_into_iovec(iovec, iov_cnt, data, 8);
954 data[4] = 0x0;
955 data[5] = 0x83;
956 data[6] = 0xb0;
957 data[7] = 0xb1;
958 data[8] = 0xb6;
959
960 tcmu_memcpy_into_iovec(iovec, iov_cnt, data, 9);
960961 break;
961962
962963 case 0x83:
21272128
21282129 /* Get the zone of the current LBA */
21292130 zone = zbc_get_zone(zdev, lba, false);
2130 if (lba + nr_lbas > zone->start + zone->len) {
2131 tcmu_dev_err(dev,
2132 "Write boundary violation lba %"PRIu64", xfer len %zu\n",
2133 lba, nr_lbas);
2134 return tcmu_sense_set_data(cmd->sense_buf,
2135 ILLEGAL_REQUEST,
2136 ASC_WRITE_BOUNDARY_VIOLATION);
2137 }
21382131
21392132 /* If the zone is not open, implicitly open it */
21402133 if (zbc_zone_seq(zone) && !zbc_zone_is_open(zone)) {
+161
-41
glfs.c less more
3636 /* cache protection */
3737 pthread_mutex_t glfs_lock;
3838
39 #if GFAPI_VERSION766
40 #define GF_ENFORCE_MANDATORY_LOCK "trusted.glusterfs.enforce-mandatory-lock"
41 #endif
42
3943 typedef enum gluster_transport {
4044 GLUSTER_TRANSPORT_TCP,
4145 GLUSTER_TRANSPORT_UNIX,
7074 glfs_t *fs;
7175 glfs_fd_t *gfd;
7276 gluster_server *hosts;
77 bool no_fencing;
7378
7479 /*
7580 * Current tcmu helper API reports WCE=1, but doesn't
98103 darray(char *) cfgstring;
99104 } gluster_cacheconn;
100105
101 static darray(struct gluster_cacheconn *) glfs_cache = darray_new();
106 static darray(struct gluster_cacheconn *) glfs_cache;
102107
103108 const char *const gluster_transport_lookup[] = {
104109 [GLUSTER_TRANSPORT_TCP] = "tcp",
529534 goto unref;
530535 }
531536
537 #if GFAPI_VERSION766
538 ret = glfs_fsetxattr(gfsp->gfd, GF_ENFORCE_MANDATORY_LOCK, "set", 4, 0);
539 if (ret) {
540 if (errno == EINVAL) {
541 gfsp->no_fencing = true;
542 } else {
543 tcmu_dev_err(dev,"glfs_fsetxattr failed: %m\n");
544 goto close;
545 }
546 }
547 #endif
548
532549 ret = glfs_lstat(gfsp->fs, gfsp->hosts->path, &st);
533550 if (ret) {
534551 tcmu_dev_warn(dev, "glfs_lstat failed: %m\n");
545562 if (round_down(st.st_size, block_size) == dev_size)
546563 goto out;
547564
548 if (!reopen) {
549 ret = -EINVAL;
550 goto close;
551 }
552
553 /*
554 * If we are here this should be in reopen path,
555 * then we should also update the device size in
556 * kernel.
557 */
558 tcmu_dev_info(dev,
559 "device size and backing size disagree:device %lld backing %lld\n",
560 dev_size, (long long) st.st_size);
561
565 if (reopen)
566 goto out;
567
568 tcmu_dev_warn(dev,
569 "device size (%lld) and backing file size (%lld) not matching, updating it to kernel\n",
570 (long long)dev_size, (long long) st.st_size);
571
572 /* Update the device size in kernel. */
562573 ret = tcmur_dev_update_size(dev, st.st_size);
563574 if (ret)
564575 goto close;
576
577 tcmu_dev_info(dev, "loaded with size (%lld)\n", (long long) st.st_size);
565578 }
566579
567580 out:
599612 glfs_cbk_cookie *cookie = data;
600613 struct tcmu_device *dev = cookie->dev;
601614 struct tcmur_cmd *tcmur_cmd = cookie->tcmur_cmd;
615 #if GFAPI_VERSION766
616 struct glfs_state *gfsp = tcmur_dev_get_private(dev);
617 #endif
602618 size_t length = cookie->length;
603
604 if (ret < 0 || ret != length) {
619 int err = -errno;
620
621 if (ret < 0) {
622 switch (err) {
623 case -ETIMEDOUT:
624 /*
625 * TIMEDOUT is a scenario where the fop can
626 * not reach the server for 30 minutes.
627 */
628 tcmu_dev_err(dev, "Timing out cmd after 30 minutes.\n");
629
630 tcmu_notify_cmd_timed_out(dev);
631 ret = TCMU_STS_TIMEOUT;
632 break;
633 #if GFAPI_VERSION766
634 case -EAGAIN:
635 case -EBUSY:
636 case -ENOTCONN:
637 /*
638 * The lock maybe preemted and then any IO to
639 * land on the file without a lock will be
640 * rejected with EBUSY.
641 *
642 * And if local is disconnected, we should get
643 * ENOTCONN for further requests. But if the
644 * connection is reestablished and at the same
645 * time another client has taken the lock we
646 * will get EBUSY too.
647 */
648 if (!gfsp->no_fencing) {
649 tcmu_dev_dbg(dev, "failed with errno %d.\n", err);
650 tcmu_notify_lock_lost(dev);
651 ret = TCMU_STS_BUSY;
652 break;
653 }
654 #endif
655 default:
656 tcmu_dev_dbg(dev, "failed with errno %d.\n", err);
657 ret = TCMU_STS_HW_ERR;
658 }
659 } else if (ret != length) {
660 tcmu_dev_dbg(dev, "ret(%zu) != length(%zu).\n", ret, length);
661
605662 /* Read/write/flush failed */
606663 switch (cookie->op) {
607664 case TCMU_GLFS_READ:
665 /* ENOENT for READ operation means EOF,
666 * see glusterfs commit 9fe5c6d3
667 */
668 if (err == -ENOENT) {
669 ret = TCMU_STS_OK;
670 break;
671 }
608672 ret = TCMU_STS_RD_ERR;
609673 break;
610674 case TCMU_GLFS_WRITE:
703767 /* Let the targetcli command return success */
704768 ret = 0;
705769 } else if (st.st_size != cfg->data.dev_size) {
706 tcmu_dev_err(dev,
707 "device size and backing size disagree: device %"PRId64" backing %lld\n",
708 cfg->data.dev_size, (long long) st.st_size);
709 ret = -EINVAL;
770 /*
771 * Currently we cannot update the size to kernel here,
772 * because it will be overrided by kernel with the old
773 * value after it gets the genl reply.
774 */
775 tcmu_dev_warn(dev,
776 "device size (%lld) and backing file size (%lld) not matching, and ignoring it\n",
777 (long long)cfg->data.dev_size, (long long) st.st_size);
778 return -EINVAL;
710779 }
711780 return ret;
712781 case TCMULIB_CFG_DEV_CFGSTR:
816885 return TCMU_STS_NO_RESOURCE;
817886 }
818887
819 /*
820 * Return scsi status or TCMU_STS_NOT_HANDLED
821 */
822 static int tcmu_glfs_handle_cmd(struct tcmu_device *dev,
823 struct tcmur_cmd *tcmur_cmd)
824 {
825 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
826 uint8_t *cdb = cmd->cdb;
888 #if GFAPI_VERSION766
889 static int tcmu_glfs_to_sts(int rc)
890 {
891 switch (rc) {
892 case 0:
893 return TCMU_STS_OK;
894 case -ENOTCONN:
895 return TCMU_STS_FENCED;
896 default:
897 return TCMU_STS_HW_ERR;
898 }
899 }
900
901 static int tcmu_glfs_lock(struct tcmu_device *dev, uint16_t tag)
902 {
903 struct glfs_state *state = tcmur_dev_get_private(dev);
904 struct flock lock;
827905 int ret;
828906
829 switch(cdb[0]) {
830 case WRITE_SAME:
831 case WRITE_SAME_16:
832 ret = tcmur_handle_writesame(dev, tcmur_cmd,
833 tcmu_glfs_writesame);
834 break;
835 default:
836 ret = TCMU_STS_NOT_HANDLED;
837 }
838
839 return ret;
907 if (state->no_fencing)
908 return 0;
909
910 lock.l_type = F_WRLCK | F_RDLCK;
911 lock.l_whence = SEEK_SET;
912 lock.l_start = 0;
913 lock.l_len = 0;
914
915 ret = glfs_file_lock(state->gfd, F_SETLK, &lock, GLFS_LK_MANDATORY);
916 if (ret)
917 tcmu_dev_err(dev, "glfs_file_lock failed: %m\n");
918
919 return tcmu_glfs_to_sts(ret);
920 }
921
922 static int tcmu_glfs_unlock(struct tcmu_device *dev)
923 {
924 struct glfs_state *state = tcmur_dev_get_private(dev);
925 struct flock lock;
926 int ret;
927
928 if (state->no_fencing)
929 return 0;
930
931 lock.l_type = F_UNLCK;
932 lock.l_whence = SEEK_SET;
933 lock.l_start = 0;
934 lock.l_len = 0;
935
936 ret = glfs_file_lock(state->gfd, F_SETLK, &lock, GLFS_LK_MANDATORY);
937 if (ret)
938 tcmu_dev_err(dev, "glfs_file_lock failed: %m\n");
939
940 return tcmu_glfs_to_sts(ret);
941 }
942 #endif
943
944 static int tcmu_glfs_init(void)
945 {
946 darray_init(glfs_cache);
947 return 0;
948 }
949
950 static void tcmu_glfs_destroy(void)
951 {
952 darray_free(glfs_cache);
840953 }
841954
842955 /*
871984 .reconfig = tcmu_glfs_reconfig,
872985 .flush = tcmu_glfs_flush,
873986 .unmap = tcmu_glfs_discard,
874 .handle_cmd = tcmu_glfs_handle_cmd,
987 .writesame = tcmu_glfs_writesame,
875988
876989 .update_logdir = tcmu_glfs_update_logdir,
990
991 #if GFAPI_VERSION766
992 .lock = tcmu_glfs_lock,
993 .unlock = tcmu_glfs_unlock,
994 #endif
995 .init = tcmu_glfs_init,
996 .destroy = tcmu_glfs_destroy,
877997 };
878998
879999 /* Entry point must be named "handler_init". */
4242 [TCMU_ATTR_SUPP_KERN_CMD_REPLY] = { .type = NLA_U8 },
4343 };
4444
45 static int add_device(struct tcmulib_context *ctx, char *dev_name,
45 static int device_add(struct tcmulib_context *ctx, char *dev_name,
4646 char *cfgstring, bool reopen);
47 static void remove_device(struct tcmulib_context *ctx, char *dev_name,
47 static void device_remove(struct tcmulib_context *ctx, char *dev_name,
4848 bool should_block);
4949 static int handle_netlink(struct nl_cache_ops *unused, struct genl_cmd *cmd,
5050 struct genl_info *info, void *arg);
216216 switch (cmd->c_id) {
217217 case TCMU_CMD_ADDED_DEVICE:
218218 reply_cmd = TCMU_CMD_ADDED_DEVICE_DONE;
219 ret = add_device(ctx, buf,
219 ret = device_add(ctx, buf,
220220 nla_get_string(info->attrs[TCMU_ATTR_DEVICE]),
221221 false);
222222 break;
223223 case TCMU_CMD_REMOVED_DEVICE:
224224 reply_cmd = TCMU_CMD_REMOVED_DEVICE_DONE;
225 remove_device(ctx, buf, false);
225 device_remove(ctx, buf, false);
226226 ret = 0;
227227 break;
228228 case TCMU_CMD_RECONFIG_DEVICE:
392392 return dev->map->flags & TCMU_MAILBOX_FLAG_CAP_OOOC;
393393 }
394394
395 static int add_device(struct tcmulib_context *ctx, char *dev_name,
396 char *cfgstring, bool reopen)
397 {
398 struct tcmu_device *dev;
399 struct tcmu_mailbox *mb;
400 char str_buf[256];
401 bool reset_supp = true;
395 /* Read a size_t from a file. Returns -1 on error. */
396 static ssize_t read_size(const char *filename)
397 {
402398 int fd;
403 int ret;
404 char *ptr, *oldptr;
405 char *reason = NULL;
399 int len, rc;
400 char buf[256], *endbuf;
401 ssize_t ret;
402
403 fd = open(filename, O_RDONLY);
404 if (fd == -1)
405 goto err;
406
407 len = read(fd, buf, sizeof(buf)-1);
408 rc = close(fd);
409 if (len <= 0 || rc == -1)
410 goto err;
411
412 buf[len] = '\0'; /* null-terminate */
413 ret = strtoull(buf, &endbuf, 0);
414 if (buf == endbuf || ret == ULLONG_MAX)
415 goto err;
416
417 return ret;
418
419 err:
420 tcmu_warn("cannot read size from %s\n", filename);
421 return -1;
422 }
423
424 /* Extract configuration parameters into dev. */
425 static bool device_parse_cfg(struct tcmu_device *dev,
426 const char *dev_name, const char *cfgstring)
427 {
406428 int len;
407
408 dev = calloc(1, sizeof(*dev));
409 if (!dev) {
410 tcmu_err("calloc failed in add_device\n");
411 return -ENOMEM;
412 }
413
414 snprintf(dev->dev_name, sizeof(dev->dev_name), "%s", dev_name);
415
429 const char *ptr, *oldptr;
430
431 len = snprintf(dev->dev_name, sizeof(dev->dev_name), "%s", dev_name);
432 if (len >= sizeof(dev->dev_name)) {
433 tcmu_err("device name too long for tcmu_device\n");
434 goto err_recompile;
435 }
436
437 /* Check valid cfgstring */
416438 oldptr = cfgstring;
417439 ptr = strchr(oldptr, '/');
418 if (!ptr) {
419 tcmu_err("invalid cfgstring\n");
420 goto err_free;
421 }
422
423 if (strncmp(cfgstring, "tcm-user", ptr-oldptr)) {
424 tcmu_err("invalid cfgstring\n");
425 goto err_free;
426 }
440 if (!ptr)
441 goto err_badcfg;
442 if (strncmp(cfgstring, "tcm-user", ptr-oldptr))
443 goto err_badcfg;
427444
428445 /* Get HBA name */
429446 oldptr = ptr+1;
430447 ptr = strchr(oldptr, '/');
431 if (!ptr) {
432 tcmu_err("invalid cfgstring\n");
433 goto err_free;
434 }
448 if (!ptr)
449 goto err_badcfg;
435450 len = ptr-oldptr;
436 snprintf(dev->tcm_hba_name, sizeof(dev->tcm_hba_name), "user_%.*s", len, oldptr);
451 len = snprintf(dev->tcm_hba_name, sizeof(dev->tcm_hba_name), "user_%.*s", len, oldptr);
452 if (len >= sizeof(dev->tcm_hba_name)) {
453 tcmu_err("hba name too long for tcmu_device\n");
454 goto err_recompile;
455 }
437456
438457 /* Get device name */
439458 oldptr = ptr+1;
440459 ptr = strchr(oldptr, '/');
441 if (!ptr) {
442 tcmu_err("invalid cfgstring\n");
443 goto err_free;
444 }
460 if (!ptr)
461 goto err_badcfg;
445462 len = ptr-oldptr;
446 snprintf(dev->tcm_dev_name, sizeof(dev->tcm_dev_name), "%.*s", len, oldptr);
463 len = snprintf(dev->tcm_dev_name, sizeof(dev->tcm_dev_name), "%.*s", len, oldptr);
464 if (len >= sizeof(dev->tcm_dev_name)) {
465 tcmu_err("tcm device name too long for tcmu_device\n");
466 goto err_recompile;
467 }
447468
448469 /* The rest is the handler-specific cfgstring */
449470 oldptr = ptr+1;
450 ptr = strchr(oldptr, '/');
451 snprintf(dev->cfgstring, sizeof(dev->cfgstring), "%s", oldptr);
471 len = snprintf(dev->cfgstring, sizeof(dev->cfgstring), "%s", oldptr);
472 if (len >= sizeof(dev->cfgstring)) {
473 tcmu_warn("additional handler cfgstring was truncated\n");
474 /* not a terminal error. snprintf() will null-terminate */
475 }
476 return true;
477
478 err_badcfg:
479 tcmu_err("invalid cfgstring: expecting \"tcm-user/<hba_name>/<tcm_device_name>/<handler_name_config>\"\n");
480 err_recompile: /* consider expanding string lengths in dev */
481 return false;
482 }
483
484 static void device_close_shm(struct tcmu_device *dev)
485 {
486 int ret;
487
488 ret = close(dev->fd);
489 if (ret != 0) {
490 tcmu_err("could not close device fd for %s: %d\n", dev->dev_name, errno);
491 }
492 ret = munmap(dev->map, dev->map_len);
493 if (ret != 0) {
494 tcmu_err("could not unmap device %s: %d\n", dev->dev_name, errno);
495 }
496 }
497
498 static bool device_open_shm(struct tcmu_device *dev)
499 {
500 size_t mmap_size;
501 char *mmap_name;
502 off_t mmap_offset;
503
504 /* get filename, size and offset */
505 mmap_name = tcmu_dev_get_memory_info(dev, NULL, &mmap_size, &mmap_offset);
506 if (!mmap_name)
507 goto err_fail;
508
509 /* cache the map size */
510 dev->map_len = mmap_size;
511
512 /* open the map */
513 dev->fd = open(mmap_name, O_RDWR | O_NONBLOCK | O_CLOEXEC);
514 if (dev->fd == -1) {
515 tcmu_err("could not open %s\n", mmap_name);
516 goto err_mmap_name;
517 }
518
519 /* bring the map into memory */
520 dev->map = mmap(NULL, dev->map_len, PROT_READ|PROT_WRITE, MAP_SHARED, dev->fd, mmap_offset);
521 if (dev->map == MAP_FAILED) {
522 tcmu_err("could not mmap %s\n", mmap_name);
523 goto err_fd_close;
524 }
525
526 if (dev->map->version != KERN_IFACE_VER) {
527 tcmu_err("Kernel interface version mismatch: wanted %d got %d\n",
528 KERN_IFACE_VER, dev->map->version);
529 goto err_munmap;
530 }
531
532 free(mmap_name);
533 return true;
534
535 err_munmap:
536 munmap(dev->map, dev->map_len);
537 err_fd_close:
538 close(dev->fd);
539 err_mmap_name:
540 free(mmap_name);
541 err_fail:
542 return false;
543 }
544
545 static int device_add(struct tcmulib_context *ctx, char *dev_name,
546 char *cfgstring, bool reopen)
547 {
548 struct tcmu_device *dev;
549 char *reason = NULL;
550 int rc;
551 bool reset_supp = true;
552
553 dev = calloc(1, sizeof(*dev));
554 if (!dev) {
555 tcmu_err("calloc failed for device_add()\n");
556 return -ENOMEM;
557 }
558
559 if (!device_parse_cfg(dev, dev_name, cfgstring))
560 goto err_free;
452561
453562 dev->handler = find_handler(ctx, dev->cfgstring);
454563 if (!dev->handler) {
472581 * from a fresh slate. We will unblock below when we are
473582 * completely setup.
474583 */
475 ret = tcmu_cfgfs_dev_exec_action(dev, "block_dev", 1);
584 rc = tcmu_cfgfs_dev_exec_action(dev, "block_dev", 1);
476585 /*
477586 * As long as the block_dev file existed, try to reset
478587 * just in case the kernel was in a invald state.
479588 */
480 if (ret == -ENOENT) {
589 if (rc == -ENOENT) {
481590 reset_supp = false;
482591 } else {
483592 /*
484593 * Force a retry of the outstanding commands.
485594 */
486 ret = tcmu_cfgfs_dev_exec_action(dev, "reset_ring", 1);
487 if (ret)
488 tcmu_dev_err(dev, "Could not reset ring %d.\n", ret);
595 rc = tcmu_cfgfs_dev_exec_action(dev, "reset_ring", 1);
596 if (rc)
597 tcmu_dev_err(dev, "Could not reset ring %d.\n", rc);
489598 }
490599 }
491600
492 snprintf(str_buf, sizeof(str_buf), "/dev/%s", dev_name);
493
494 dev->fd = open(str_buf, O_RDWR | O_NONBLOCK | O_CLOEXEC);
495 if (dev->fd == -1) {
496 tcmu_err("could not open %s\n", str_buf);
601 if (!device_open_shm(dev))
497602 goto err_unblock;
498 }
499
500 snprintf(str_buf, sizeof(str_buf), "/sys/class/uio/%s/maps/map0/size", dev->dev_name);
501 fd = open(str_buf, O_RDONLY);
502 if (fd == -1) {
503 tcmu_err("could not open %s\n", str_buf);
504 goto err_fd_close;
505 }
506
507 ret = read(fd, str_buf, sizeof(str_buf));
508 close(fd);
509 if (ret <= 0) {
510 tcmu_err("could not read size of map0\n");
511 goto err_fd_close;
512 }
513 str_buf[ret-1] = '\0'; /* null-terminate and chop off the \n */
514
515 dev->map_len = strtoull(str_buf, NULL, 0);
516 if (dev->map_len == ULLONG_MAX) {
517 tcmu_err("could not get map length\n");
518 goto err_fd_close;
519 }
520
521 dev->map = mmap(NULL, dev->map_len, PROT_READ|PROT_WRITE, MAP_SHARED, dev->fd, 0);
522 if (dev->map == MAP_FAILED) {
523 tcmu_err("could not mmap: %m\n");
524 goto err_fd_close;
525 }
526
527 mb = dev->map;
528 if (mb->version != KERN_IFACE_VER) {
529 tcmu_err("Kernel interface version mismatch: wanted %d got %d\n",
530 KERN_IFACE_VER, mb->version);
531 goto err_munmap;
532 }
533
534 dev->cmd_tail = mb->cmd_tail;
603
604 dev->cmd_tail = dev->map->cmd_tail;
535605 dev->ctx = ctx;
536606
537 ret = dev->handler->added(dev);
538 if (ret != 0) {
607 rc = dev->handler->added(dev);
608 if (rc != 0) {
539609 tcmu_err("handler open failed for %s\n", dev->dev_name);
540 goto err_munmap;
610 goto err_closeshm;
541611 }
542612
543613 darray_append(ctx->devices, dev);
547617
548618 return 0;
549619
550 err_munmap:
551 munmap(dev->map, dev->map_len);
552 err_fd_close:
553 close(dev->fd);
620 err_closeshm:
621 device_close_shm(dev);
554622 err_unblock:
555623 if (reopen && reset_supp)
556624 tcmu_cfgfs_dev_exec_action(dev, "block_dev", 0);
557625 err_free:
558626 free(dev);
559
560627 return -ENOENT;
561628 }
562629
567634
568635 darray_foreach_reverse(dev_ptr, ctx->devices) {
569636 dev = *dev_ptr;
570 remove_device(ctx, dev->dev_name, true);
571 }
572 }
573
574 static void remove_device(struct tcmulib_context *ctx, char *dev_name,
637 device_remove(ctx, dev->dev_name, true);
638 }
639 }
640
641 static void device_remove(struct tcmulib_context *ctx, char *dev_name,
575642 bool should_block)
576643 {
577644 struct tcmu_device *dev;
578 int i, ret;
645 int i;
579646
580647 dev = lookup_dev_by_name(ctx, dev_name, &i);
581648 if (!dev) {
597664
598665 dev->handler->removed(dev);
599666
600 ret = close(dev->fd);
601 if (ret != 0) {
602 tcmu_err("could not close device fd %s: %d\n", dev_name, errno);
603 }
604 ret = munmap(dev->map, dev->map_len);
605 if (ret != 0) {
606 tcmu_err("could not unmap device %s: %d\n", dev_name, errno);
607 }
667 device_close_shm(dev);
608668
609669 if (should_block)
610670 tcmu_cfgfs_dev_exec_action(dev, "block_dev", 0);
688748 if (read_uio_name(dirent_list[i]->d_name, &dev_name))
689749 continue;
690750
691 if (add_device(ctx, dirent_list[i]->d_name, dev_name, true) < 0) {
751 if (device_add(ctx, dirent_list[i]->d_name, dev_name, true) < 0) {
692752 free (dev_name);
693753 continue;
694754 }
772832 void tcmu_dev_set_private(struct tcmu_device *dev, void *private)
773833 {
774834 dev->hm_private = private;
835 }
836
837 const char *tcmu_dev_get_uio_name(struct tcmu_device *dev)
838 {
839 return dev->dev_name;
840 }
841
842 void tcmu_set_thread_name(const char *prefix, struct tcmu_device *dev)
843 {
844 const char *uio = dev ? tcmu_dev_get_uio_name(dev) : NULL;
845 char cname[TCMU_THREAD_NAME_LEN];
846 char *pname;
847
848 if (pthread_getname_np(pthread_self(), cname, TCMU_THREAD_NAME_LEN))
849 return;
850
851 /*
852 * If we are trying to set the pthread name in the
853 * event work thread, we must ignore it.
854 */
855 if (!strcmp(cname, "ework-thread")) {
856 tcmu_dev_warn(dev, "Do not set name for event work thread in the callback fn\n");
857 return;
858 }
859
860 if (!prefix) {
861 tcmu_dev_err(dev, "Failed to set name for thread %lu\n",
862 pthread_self());
863 return;
864 }
865
866 if (asprintf(&pname, "%s%s%s", prefix, uio ? "-" : "", uio ? uio : "") == -1) {
867 tcmu_dev_err(dev, "Could not allocate thread name.\n");
868 return;
869 }
870
871 if (strlen(pname) >= TCMU_THREAD_NAME_LEN) {
872 tcmu_dev_warn(dev, "Cannot set thread name to %s. Name must be less than %d chars. ",
873 pname, TCMU_THREAD_NAME_LEN);
874 pname[TCMU_THREAD_NAME_LEN - 1] = '\0';
875 tcmu_dev_warn(dev, "Truncating to %s.\n", pname);
876 }
877
878 if (pthread_setname_np(pthread_self(), pname))
879 tcmu_dev_err(dev, "Could not set thread name to %s\n", pname);
880 free(pname);
775881 }
776882
777883 void tcmu_dev_set_num_lbas(struct tcmu_device *dev, uint64_t num_lbas)
9211027 int tcmu_dev_get_fd(struct tcmu_device *dev)
9221028 {
9231029 return dev->fd;
1030 }
1031
1032 /**
1033 * tcmu_dev_get_memory_info - retrieve information about tcmu's shared
1034 * memory block. If the memory is mapped to another address (e.g., in
1035 * another process) then the information in struct iovec can be converted
1036 * using these values. Returns the filename of the mmap() that fd uses, or
1037 * NULL if information is not available. The caller must free() the
1038 * returned filename.
1039 * @dev: tcmu device
1040 * @base: receives the base address of the shared memory region
1041 * @len: receives the size of the shared memory region
1042 * @offset: receives the offset within fd for mmap() (conventionally 0).
1043 */
1044 char *
1045 tcmu_dev_get_memory_info(struct tcmu_device *dev, void **base,
1046 size_t *len, off_t *offset)
1047 {
1048 char *mmap_name;
1049 const char *namefmt = "/dev/%s";
1050 const char *sizefmt = "/sys/class/uio/%s/maps/map0/size";
1051
1052 if (asprintf(&mmap_name, namefmt, dev->dev_name) == -1) {
1053 tcmu_err("cannot construct device map filename\n");
1054 goto err_fail;
1055 }
1056 if (base)
1057 *base = dev->map;
1058 if (len) {
1059 if (dev->map_len != 0) {
1060 /* cached */
1061 *len = dev->map_len;
1062 } else {
1063 /* get length of map from file */
1064 ssize_t size;
1065 char *size_name;
1066
1067 if (asprintf(&size_name, sizefmt, dev->dev_name) == -1) {
1068 tcmu_err("cannot construct device map size filename\n");
1069 goto err_free;
1070 }
1071 size = read_size(size_name);
1072 free(size_name);
1073 if (size == -1) {
1074 tcmu_err("unable to read device map0 size\n");
1075 goto err_free;
1076 }
1077 *len = size;
1078 }
1079 }
1080 if (offset)
1081 *offset = 0;
1082 return mmap_name;
1083
1084 err_free:
1085 free(mmap_name);
1086 err_fail:
1087 return NULL;
9241088 }
9251089
9261090 char *tcmu_dev_get_cfgstring(struct tcmu_device *dev)
6161 TCMU_STS_TOO_MANY_TGT_DESC,
6262 };
6363
64 #define TCMU_THREAD_NAME_LEN 16
65
6466 #define SENSE_BUFFERSIZE 96
6567
6668 #define CFGFS_ROOT "/sys/kernel/config/target"
105107 /* Set/Get methods for the opaque tcmu_device */
106108 void *tcmu_dev_get_private(struct tcmu_device *dev);
107109 void tcmu_dev_set_private(struct tcmu_device *dev, void *priv);
108 void *tcmu_get_daemon_dev_private(struct tcmu_device *dev);
109 void tcmu_set_daemon_dev_private(struct tcmu_device *dev, void *priv);
110 const char *tcmu_dev_get_uio_name(struct tcmu_device *dev);
111 void tcmu_set_thread_name(const char *prefix, struct tcmu_device *dev);
110112 int tcmu_dev_get_fd(struct tcmu_device *dev);
113 char *tcmu_dev_get_memory_info(struct tcmu_device *dev, void **base,
114 size_t *len, off_t *offset);
111115 char *tcmu_dev_get_cfgstring(struct tcmu_device *dev);
112116 void tcmu_dev_set_num_lbas(struct tcmu_device *dev, uint64_t num_lbas);
113117 uint64_t tcmu_dev_get_num_lbas(struct tcmu_device *dev);
400400 char buf[BUF_LEN];
401401 char *p;
402402
403 tcmu_set_thread_name("dyn-config", NULL);
404
403405 monitor = inotify_init();
404406 if (monitor == -1) {
405407 tcmu_err("Failed to init inotify %m\n");
182182 {
183183 char timestamp[TCMU_TIME_STRING_BUFLEN] = {0, };
184184
185 if (!output)
186 return;
187
185188 if (time_string_now(timestamp) < 0)
186189 return;
187190
399402 int fd = (intptr_t) data;
400403 char *buf, *msg;
401404 int count, ret, written = 0, r, pid = 0;
405 char pname[TCMU_THREAD_NAME_LEN];
402406
403407 if (fd == -1)
404408 return -1;
407411 if (pid <= 0)
408412 return -1;
409413
414 if (pthread_getname_np(pthread_self(), pname, TCMU_THREAD_NAME_LEN))
415 return -1;
416
410417 /*
411418 * format: timestamp pid [loglevel] msg
412419 */
413 ret = asprintf(&msg, "%s %d [%s] %s", timestamp, pid, loglevel_string(pri), str);
420 ret = asprintf(&msg, "%s %d:%s [%s] %s", timestamp, pid, pname,
421 loglevel_string(pri), str);
414422 if (ret < 0)
415423 return -1;
416424
515523
516524 static void *log_thread_start(void *arg)
517525 {
518 tcmu_logbuf = arg;
526 tcmu_set_thread_name("logger", NULL);
519527
520528 pthread_cleanup_push(log_cleanup, arg);
521529
538546 return false;
539547
540548 if (strlen(path) >= PATH_MAX - TCMU_LOG_FILENAME_MAX) {
541 tcmu_err("--tcmu-log-dir='%s' cannot exceed %d characters\n",
549 tcmu_err("The length of log dir path '%s' exceeds %d characters\n",
542550 path, PATH_MAX - TCMU_LOG_FILENAME_MAX - 1);
543551 return false;
544552 }
686694 if (ret < 0)
687695 tcmu_err("create file output error \n");
688696
697 tcmu_logbuf = logbuf;
689698 ret = pthread_create(&logbuf->thread_id, NULL, log_thread_start,
690699 logbuf);
691700 if (ret) {
701 tcmu_logbuf = NULL;
692702 log_cleanup(logbuf);
693703 return ret;
694704 }
33 tcmur_handle_writesame;
44 tcmu_notify_lock_lost;
55 tcmu_notify_conn_lost;
6 tcmu_notify_cmd_timed_out;
7 tcmu_event_name;
68 tcmur_dev_update_size;
79 tcmur_dev_set_private;
810 tcmur_dev_get_private;
4747 #include "version.h"
4848 #include "libtcmu_config.h"
4949 #include "libtcmu_log.h"
50 #include "tcmur_work.h"
5051
5152 #define TCMU_LOCK_FILE "/run/tcmu.lock"
5253
6667 int tcmur_register_handler(struct tcmur_handler *handler)
6768 {
6869 struct tcmur_handler *h;
70 int ret;
6971 int i;
7072
7173 for (i = 0; i < darray_size(g_runner_handlers); i++) {
7779 }
7880 }
7981
82 if (handler->init) {
83 ret = handler->init();
84 if (ret) {
85 tcmu_err("Failed to init handler %s, ret = %d\n",
86 handler->subtype, ret);
87 return ret;
88 }
89 }
90
91 tcmu_info("Handler %s is registered\n", handler->subtype);
8092 darray_append(g_runner_handlers, handler);
8193 return 0;
8294 }
104116 g_free((char*)handler->opaque);
105117 g_free((char*)handler->subtype);
106118 g_free((char*)handler->cfg_desc);
119 if (handler->destroy)
120 handler->destroy();
107121 g_free(handler);
108122 }
109123
119133 }
120134
121135 return ret;
136 }
137
138 static void tcmur_unregister_all_dbus_handlers(void)
139 {
140 struct tcmur_handler *handler;
141 int i;
142 for (i = 0; i < darray_size(g_runner_handlers); i++) {
143 handler = darray_item(g_runner_handlers, i);
144 if (handler->_is_dbus_handler == true) {
145 if (tcmur_unregister_handler(handler))
146 free_dbus_handler(handler);
147 }
148 }
149 darray_free(g_runner_handlers);
122150 }
123151
124152 static int is_handler(const struct dirent *dirent)
599627 * The lock thread can fire off the recovery thread, so make sure
600628 * it is done first.
601629 */
602 tcmu_cancel_lock_thread(dev);
630 tcmur_flush_work(rdev->event_work);
603631 tcmu_cancel_recovery(dev);
604632
605633 tcmu_release_dev_lock(dev);
722750 }
723751
724752 tcmur_cmd->timed_out = true;
753 /*
754 * These time outs are only currently used for diagnostic
755 * purposes right now, so we do not want to escalate the
756 * error handler and just return true here.
757 */
758 tcmu_notify_cmd_timed_out(dev);
725759 }
726760 pthread_spin_unlock(&rdev->lock);
727761 }
754788 struct pollfd pfd;
755789 int ret;
756790 bool dev_stopping = false;
791
792 tcmu_set_thread_name("cmdproc", dev);
757793
758794 pthread_cleanup_push(tcmur_stop_device, dev);
759795
10281064
10291065 rdev->flags |= TCMUR_DEV_FLAG_IS_OPEN;
10301066
1031 ret = pthread_cond_init(&rdev->lock_cond, NULL);
1032 if (ret) {
1033 ret = -ret;
1067 rdev->event_work = tcmur_create_work();
1068 if (!rdev->event_work) {
1069 ret = -ENOMEM;
10341070 goto close_dev;
10351071 }
10361072
10381074 dev);
10391075 if (ret) {
10401076 ret = -ret;
1041 goto cleanup_lock_cond;
1077 goto cleanup_event_work;
10421078 }
10431079
10441080 return 0;
10451081
1046 cleanup_lock_cond:
1047 pthread_cond_destroy(&rdev->lock_cond);
1082 cleanup_event_work:
1083 tcmur_destroy_work(rdev->event_work);
10481084 close_dev:
10491085 rhandler->close(dev);
10501086 cleanup_aio_tracking:
10911127 cleanup_io_work_queue(dev, false);
10921128 cleanup_aio_tracking(rdev);
10931129
1094 ret = pthread_cond_destroy(&rdev->lock_cond);
1095 if (ret != 0)
1096 tcmu_err("could not cleanup lock cond %d\n", ret);
1130 tcmur_destroy_work(rdev->event_work);
10971131
10981132 ret = pthread_mutex_destroy(&rdev->state_lock);
10991133 if (ret != 0)
11891223 {
11901224 darray(struct tcmulib_handler) handlers = darray_new();
11911225 struct tcmulib_context *tcmulib_context;
1192 struct tcmur_handler **tmp_r_handler;
1226 struct tcmur_handler **tmp_r_handler, *r_handler;
1227 struct tcmulib_handler *handler;
11931228 GMainLoop *loop;
11941229 GIOChannel *libtcmu_gio;
11951230 guint reg_id;
14011436 tcmu_unwatch_config(tcmu_cfg);
14021437 tcmulib_close(tcmulib_context);
14031438 err_free_handlers:
1439 tcmur_unregister_all_dbus_handlers();
1440
1441 darray_foreach(handler, handlers) {
1442 r_handler = handler->hm_private;
1443 if (r_handler && r_handler->destroy)
1444 r_handler->destroy();
1445 }
14041446 darray_free(handlers);
14051447 close_fd:
14061448 if (reset_nl_supp)
+283
-52
rbd.c less more
2424
2525 #include <scsi/scsi.h>
2626
27 #include "darray.h"
2728 #include "tcmu-runner.h"
2829 #include "tcmur_cmd_handler.h"
2930 #include "libtcmu.h"
7980 char *osd_op_timeout;
8081 char *conf_path;
8182 char *id;
83 char *addrs;
8284 };
8385
8486 enum rbd_aio_type {
106108 size_t iov_cnt;
107109 };
108110
111 static pthread_mutex_t blacklist_caches_lock = PTHREAD_MUTEX_INITIALIZER;
112 static darray(char *) blacklist_caches;
113
109114 #ifdef LIBRADOS_SUPPORTS_SERVICES
110115
111116 #ifdef RBD_LOCK_ACQUIRE_SUPPORT
112 static void tcmu_rbd_service_status_update(struct tcmu_device *dev,
113 bool has_lock)
114 {
115 struct tcmu_rbd_state *state = tcmur_dev_get_private(dev);
117 static int tcmu_rbd_service_status_update(struct tcmu_device *dev,
118 bool has_lock)
119 {
120 struct tcmu_rbd_state *state = tcmur_dev_get_private(dev);
121 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
116122 char *status_buf = NULL;
117123 int ret;
118124
119 ret = asprintf(&status_buf, "%s%c%s%c", "lock_owner", '\0',
120 has_lock ? "true" : "false", '\0');
125 ret = asprintf(&status_buf,
126 "%s%c%s%c%s%c%"PRIu64"%c%s%c%"PRIu64"%c%s%c%"PRIu64"%c",
127 "lock_owner", '\0', has_lock ? "true" : "false", '\0',
128 "lock_lost_cnt", '\0', rdev->lock_lost_cnt, '\0',
129 "conn_lost_cnt", '\0', rdev->conn_lost_cnt, '\0',
130 "cmd_timed_out_cnt", '\0', rdev->cmd_timed_out_cnt, '\0');
121131 if (ret < 0) {
122132 tcmu_dev_err(dev, "Could not allocate status buf. Service will not be updated.\n");
123 return;
133 return ret;
124134 }
125135
126136 ret = rados_service_update_status(state->cluster, status_buf);
130140 }
131141
132142 free(status_buf);
133 }
143 return ret;
144 }
145
134146 #endif /* RBD_LOCK_ACQUIRE_SUPPORT */
147
148 static int tcmu_rbd_report_event(struct tcmu_device *dev)
149 {
150 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
151
152 /*
153 * We ignore the specific event and report all the current counter
154 * values, because tools like gwcli/dashboard may not see every
155 * update, and we do not want one event to overwrite the info.
156 */
157 return tcmu_rbd_service_status_update(dev,
158 rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED ? true : false);
159 }
135160
136161 static int tcmu_rbd_service_register(struct tcmu_device *dev)
137162 {
169194 goto free_image_id_buf;
170195 }
171196
172 ret = asprintf(&metadata_buf, "%s%c%s%c%s%c%s%c%s%c%s%c",
197 ret = asprintf(&metadata_buf, "%s%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c",
173198 "pool_name", '\0', state->pool_name, '\0',
174199 "image_name", '\0', state->image_name, '\0',
175 "image_id", '\0', image_id_buf, '\0');
200 "image_id", '\0', image_id_buf, '\0',
201 "daemon_type", '\0', "portal", '\0',
202 "daemon_prefix", '\0', u.nodename, '\0');
176203 if (ret < 0) {
177204 tcmu_dev_err(dev, "Could not allocate metadata buf.\n");
178205 ret = -ENOMEM;
184211 if (ret < 0) {
185212 tcmu_dev_err(dev, "Could not register service to cluster. (Err %d)\n",
186213 ret);
187 }
188
214 goto free_meta_buf;
215 }
216
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
221 free_meta_buf:
189222 free(metadata_buf);
190223 free_daemon_buf:
191224 free(daemon_buf);
211244 #endif /* RBD_LOCK_ACQUIRE_SUPPORT */
212245
213246 #endif /* LIBRADOS_SUPPORTS_SERVICES */
247
248 #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);
252 const char *p, *q, *end;
253 char *cmd, *addr;
254 int ret;
255
256 /*
257 * Just skip extra chars before '[' if there has
258 */
259 p = strchr(addrs, '[');
260 if (!p)
261 p = addrs;
262
263 /*
264 * The addrs will a string like:
265 * "[192.168.195.172:0/2203456141,192.168.195.172:0/4908756432]"
266 * Or
267 * "192.168.195.172:0/2203456141"
268 */
269 while (1) {
270 if (p == NULL || *p == ']') {
271 return; /* we are done here */
272 } else if (*p == '[' || *p == ',') {
273 /* Skip "[" and white spaces */
274 while (*p != '\0' && !isalnum(*p)) p++;
275 if (*p == '\0') {
276 tcmu_dev_warn(dev, "Get an invalid address '%s'!\n", addrs);
277 return;
278 }
279
280 end = strchr(p, ',');
281 if (!end)
282 end = strchr(p, ']');
283
284 if (!end) {
285 tcmu_dev_warn(dev, "Get an invalid address '%s'!\n", addrs);
286 return;
287 }
288
289 q = end; /* The *end should be ',' or ']' */
290
291 while (*q != '\0' && !isalnum(*q)) q--;
292 if (*q == '\0') {
293 tcmu_dev_warn(dev, "Get an invalid address '%s'!\n", addrs);
294 return;
295 }
296
297 addr = strndup(p, q - p + 1);
298 p = end;
299 } else {
300 /* In case of "192.168.195.172:0/2203456141" */
301 addr = strdup(p);
302 p = NULL;
303 }
304
305 ret = asprintf(&cmd,
306 "{\"prefix\": \"osd blacklist\","
307 "\"blacklistop\": \"rm\","
308 "\"addr\": \"%s\"}",
309 addr);
310 free(addr);
311 if (ret < 0) {
312 tcmu_dev_warn(dev, "Could not allocate command. (Err %d)\n",
313 ret);
314 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)
328 {
329 char **entry, *tmp_entry;
330 int ret = 0;
331 int i;
332
333 pthread_mutex_lock(&blacklist_caches_lock);
334 if (darray_empty(blacklist_caches))
335 goto unlock;
336
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);
341 }
342
343 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);
347 free(tmp_entry);
348 }
349
350 pthread_mutex_unlock(&blacklist_caches_lock);
351 return ret;
352 }
353 #endif // LIBRADOS_SUPPORTS_GETADDRS || RBD_LOCK_ACQUIRE_SUPPORT
214354
215355 static char *tcmu_rbd_find_quote(char *string)
216356 {
511651
512652 ret = rbd_is_exclusive_lock_owner(state->image, &is_owner);
513653 if (ret < 0) {
514 tcmu_dev_err(dev, "Could not check lock ownership. Error: %s.\n",
515 strerror(-ret));
654 if (ret == -ESHUTDOWN) {
655 tcmu_dev_dbg(dev, "Client is blacklisted. Could not check lock ownership.\n");
656 } else {
657 tcmu_dev_err(dev, "Could not check lock ownership. Error: %s.\n",
658 strerror(-ret));
659 }
660
516661 if (ret == -ESHUTDOWN || ret == -ETIMEDOUT)
517662 return ret;
518663
533678
534679 ret = tcmu_rbd_has_lock(dev);
535680 if (ret == 1)
536 return TCMUR_DEV_LOCK_LOCKED;
681 return TCMUR_DEV_LOCK_WRITE_LOCKED;
537682 else if (ret == 0 || ret == -ESHUTDOWN)
538683 return TCMUR_DEV_LOCK_UNLOCKED;
539684 else
736881 static int tcmu_rbd_lock(struct tcmu_device *dev, uint16_t tag)
737882 {
738883 struct tcmu_rbd_state *state = tcmur_dev_get_private(dev);
884 #if !defined LIBRADOS_SUPPORTS_GETADDRS && defined RBD_LOCK_ACQUIRE_SUPPORT
885 rbd_lock_mode_t lock_mode;
886 char *owners1[1], *owners2[1];
887 size_t num_owners1 = 1, num_owners2 = 1;
888 #endif
739889 int ret;
740890
741891 ret = tcmu_rbd_has_lock(dev);
757907 if (ret)
758908 goto done;
759909
910 #if !defined LIBRADOS_SUPPORTS_GETADDRS && defined RBD_LOCK_ACQUIRE_SUPPORT
911 ret = rbd_lock_get_owners(state->image, &lock_mode, owners1,
912 &num_owners1);
913 if ((!ret && !num_owners1) || ret < 0) {
914 tcmu_dev_warn(dev, "Could not get lock owners to store blacklist entry %d!\n",
915 ret);
916 } else {
917 int is_owner;
918
919 /* To check whether we are still the lock owner */
920 ret = rbd_is_exclusive_lock_owner(state->image, &is_owner);
921 if (ret) {
922 rbd_lock_get_owners_cleanup(owners1, num_owners1);
923 tcmu_dev_warn(dev, "Could not check lock owners to store blacklist entry %d!\n",
924 ret);
925 goto no_owner;
926 }
927
928 /* To get the lock owner again */
929 ret = rbd_lock_get_owners(state->image, &lock_mode, owners2,
930 &num_owners2);
931 if ((!ret && !num_owners2) || ret < 0) {
932 tcmu_dev_warn(dev, "Could not get lock owners to store blacklist entry %d!\n",
933 ret);
934 /* Only we didn't lose the lock during the above check will we store the blacklist list */
935 } else if (!strcmp(owners1[0], owners2[0]) && is_owner) {
936 state->addrs = strdup(owners1[0]); // ignore the errors
937 }
938
939 rbd_lock_get_owners_cleanup(owners1, num_owners1);
940 rbd_lock_get_owners_cleanup(owners2, num_owners2);
941 }
942 no_owner:
943 #endif
944
760945 set_lock_tag:
761946 tcmu_dev_warn(dev, "Acquired exclusive lock.\n");
762947 if (tag != TCMU_INVALID_LOCK_TAG)
805990 free(state->pool_name);
806991 if (state->id)
807992 free(state->id);
993 if (state->addrs)
994 free(state->addrs);
808995 free(state);
809996 }
810997
8361023 char *pool, *name, *next_opt;
8371024 char *config, *dev_cfg_dup;
8381025 struct tcmu_rbd_state *state;
839 uint32_t max_blocks;
1026 uint32_t max_blocks, unmap_gran;
8401027 int ret;
1028 char buf[128];
8411029
8421030 state = calloc(1, sizeof(*state));
8431031 if (!state)
9471135 max_blocks = (image_info.obj_size * 4) / tcmu_dev_get_block_size(dev);
9481136 tcmu_dev_set_opt_xcopy_rw_len(dev, max_blocks);
9491137 tcmu_dev_set_max_unmap_len(dev, max_blocks);
950 tcmu_dev_set_opt_unmap_gran(dev, image_info.obj_size /
951 tcmu_dev_get_block_size(dev), false);
1138 ret = rados_conf_get(state->cluster, "rbd_discard_granularity_bytes", buf,
1139 sizeof(buf));
1140 if (!ret) {
1141 tcmu_dev_dbg(dev, "rbd_discard_granularity_bytes: %s\n", buf);
1142 unmap_gran = atoi(buf) / tcmu_dev_get_block_size(dev);
1143 } else {
1144 tcmu_dev_warn(dev,
1145 "Failed to get 'rbd_discard_granularity_bytes', %d\n",
1146 ret);
1147 unmap_gran = image_info.obj_size / tcmu_dev_get_block_size(dev);
1148 }
1149 tcmu_dev_dbg(dev, "unmap_gran: %d\n", unmap_gran);
1150 tcmu_dev_set_opt_unmap_gran(dev, unmap_gran, false);
1151 tcmu_dev_set_unmap_gran_align(dev, unmap_gran);
9521152 tcmu_dev_set_write_cache_enabled(dev, 0);
1153
1154 #if defined LIBRADOS_SUPPORTS_GETADDRS || defined RBD_LOCK_ACQUIRE_SUPPORT
1155 tcmu_rbd_rm_stale_entries_from_blacklist(dev);
1156 #endif
1157
1158 #ifdef LIBRADOS_SUPPORTS_GETADDRS
1159 /* Get current entry address for the image */
1160 ret = rados_getaddrs(state->cluster, &state->addrs);
1161 tcmu_dev_info(dev, "address: {%s}\n", state->addrs);
1162 if (ret < 0)
1163 return ret;
1164 #endif
9531165
9541166 free(dev_cfg_dup);
9551167 return 0;
9681180 struct tcmu_rbd_state *state = tcmur_dev_get_private(dev);
9691181
9701182 tcmu_rbd_image_close(dev);
1183
1184 /*
1185 * 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
1188 * other new device help remove it.
1189 */
1190 if (state->addrs) {
1191 pthread_mutex_lock(&blacklist_caches_lock);
1192 darray_append(blacklist_caches, state->addrs);
1193 pthread_mutex_unlock(&blacklist_caches_lock);
1194 state->addrs = NULL;
1195 }
1196
9711197 tcmu_rbd_state_free(state);
9721198 }
9731199
9741200 static int tcmu_rbd_handle_blacklisted_cmd(struct tcmu_device *dev)
975 {
1201 {
9761202 tcmu_notify_lock_lost(dev);
9771203 /*
9781204 * This will happen during failback normally, because
9901216 * to try a different OSD.
9911217 */
9921218 static int tcmu_rbd_handle_timedout_cmd(struct tcmu_device *dev)
993 {
1219 {
9941220 tcmu_dev_err(dev, "Timing out cmd.\n");
995 tcmu_notify_conn_lost(dev);
1221 tcmu_notify_cmd_timed_out(dev);
9961222
9971223 /*
9981224 * TODO: For AA, we will want to kill the ceph tcp connections
14041630 }
14051631 #endif /* RBD_COMPARE_AND_WRITE_SUPPORT */
14061632
1407 /*
1408 * Return scsi status or TCMU_STS_NOT_HANDLED
1409 */
1410 static int tcmu_rbd_handle_cmd(struct tcmu_device *dev,
1411 struct tcmur_cmd *tcmur_cmd)
1412 {
1413 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
1414 uint8_t *cdb = cmd->cdb;
1415 int ret;
1416
1417 switch(cdb[0]) {
1418 #ifdef RBD_WRITE_SAME_SUPPORT
1419 case WRITE_SAME:
1420 case WRITE_SAME_16:
1421 ret = tcmur_handle_writesame(dev, tcmur_cmd,
1422 tcmu_rbd_aio_writesame);
1423 break;
1424 #endif
1425 #ifdef RBD_COMPARE_AND_WRITE_SUPPORT
1426 case COMPARE_AND_WRITE:
1427 ret = tcmur_handle_caw(dev, tcmur_cmd, tcmu_rbd_aio_caw);
1428 break;
1429 #endif
1430 default:
1431 ret = TCMU_STS_NOT_HANDLED;
1432 }
1433
1434 return ret;
1435 }
1436
14371633 static int tcmu_rbd_reconfig(struct tcmu_device *dev,
14381634 struct tcmulib_cfg_info *cfg)
14391635 {
14501646 default:
14511647 return -EOPNOTSUPP;
14521648 }
1649 }
1650
1651 static int tcmu_rbd_init(void)
1652 {
1653 darray_init(blacklist_caches);
1654 return 0;
1655 }
1656
1657 static void tcmu_rbd_destroy(void)
1658 {
1659 char **entry;
1660
1661 tcmu_info("destroying the rbd handler\n");
1662 pthread_mutex_lock(&blacklist_caches_lock);
1663 if (darray_empty(blacklist_caches))
1664 goto unlock;
1665
1666 /* Try to remove all the stale blacklist entities */
1667 darray_foreach(entry, blacklist_caches)
1668 free(*entry);
1669
1670 darray_free(blacklist_caches);
1671
1672 unlock:
1673 pthread_mutex_unlock(&blacklist_caches_lock);
14531674 }
14541675
14551676 /*
14821703 .read = tcmu_rbd_read,
14831704 .write = tcmu_rbd_write,
14841705 .reconfig = tcmu_rbd_reconfig,
1706 #ifdef LIBRADOS_SUPPORTS_SERVICES
1707 .report_event = tcmu_rbd_report_event,
1708 #endif
14851709 #ifdef LIBRBD_SUPPORTS_AIO_FLUSH
14861710 .flush = tcmu_rbd_flush,
14871711 #endif
14881712 #ifdef RBD_DISCARD_SUPPORT
14891713 .unmap = tcmu_rbd_unmap,
14901714 #endif
1491 .handle_cmd = tcmu_rbd_handle_cmd,
1715 #ifdef RBD_WRITE_SAME_SUPPORT
1716 .writesame = tcmu_rbd_aio_writesame,
1717 #endif
1718 #ifdef RBD_COMPARE_AND_WRITE_SUPPORT
1719 .caw = tcmu_rbd_aio_caw,
1720 #endif
14921721 #ifdef RBD_LOCK_ACQUIRE_SUPPORT
14931722 .lock = tcmu_rbd_lock,
14941723 .unlock = tcmu_rbd_unlock,
14951724 .get_lock_tag = tcmu_rbd_get_lock_tag,
14961725 .get_lock_state = tcmu_rbd_get_lock_state,
14971726 #endif
1727 .init = tcmu_rbd_init,
1728 .destroy = tcmu_rbd_destroy,
14981729 };
14991730
15001731 int handler_init(void)
480480 size_t iov_cnt)
481481 {
482482 if (!(cdb[1] & 0x01)) {
483 if (!cdb[2])
484 return tcmu_emulate_std_inquiry(port, cdb, iovec,
485 iov_cnt);
486 else
483 if (cdb[2])
487484 return TCMU_STS_INVALID_CDB;
488 } else {
489 return tcmu_emulate_evpd_inquiry(dev, port, cdb, iovec, iov_cnt);
490 }
485 return tcmu_emulate_std_inquiry(port, cdb, iovec, iov_cnt);
486 }
487 return tcmu_emulate_evpd_inquiry(dev, port, cdb, iovec, iov_cnt);
491488 }
492489
493490 int tcmu_emulate_test_unit_ready(
2121 #include "libtcmu_log.h"
2222 #include "libtcmu_common.h"
2323 #include "tcmur_device.h"
24 #include "tcmur_work.h"
2425 #include "target.h"
2526 #include "alua.h"
2627
211212 * then sends IO only for it to fail due to the handler not
212213 * being able to reach its backend).
213214 */
214 static void *tgt_port_grp_recovery_thread_fn(void *arg)
215 static void tgt_port_grp_recovery_work_fn(void *arg)
215216 {
216217 struct tgt_port_grp *tpg = arg;
217218 struct tcmur_device *rdev, *tmp_rdev;
272273 }
273274
274275 free_tgt_port_grp(tpg);
275 return NULL;
276276 }
277277
278278 int tcmu_add_dev_to_recovery_list(struct tcmu_device *dev)
326326 ret = -ENOMEM;
327327 goto done;
328328 }
329 ret = pthread_create(&tpg->recovery_thread, NULL,
330 tgt_port_grp_recovery_thread_fn, tpg);
329
330 ret = tcmur_run_work(rdev->event_work, tpg, tgt_port_grp_recovery_work_fn);
331331 if (ret) {
332332 tcmu_dev_err(dev, "Could not start recovery thread. Err %d\n",
333333 ret);
5555
5656 /* callback to finish/continue command processing */
5757 void (*done)(struct tcmu_device *dev, struct tcmur_cmd *cmd, int ret);
58 };
59
60 enum tcmur_event {
61 TCMUR_EVT_LOCK_LOST,
62 TCMUR_EVT_CONN_LOST,
63 TCMUR_EVT_CMD_TIMED_OUT,
5864 };
5965
6066 struct tcmulib_cfg_info;
144150 int (*flush)(struct tcmu_device *dev, struct tcmur_cmd *cmd);
145151 int (*unmap)(struct tcmu_device *dev, struct tcmur_cmd *cmd,
146152 uint64_t off, uint64_t len);
153 int (*writesame)(struct tcmu_device *dev, struct tcmur_cmd *cmd, uint64_t off,
154 uint64_t len, struct iovec *iovec, size_t iov_cnt);
155 int (*caw)(struct tcmu_device *dev, struct tcmur_cmd *cmd, uint64_t off,
156 uint64_t len, struct iovec *iovec, size_t iov_cnt);
157
158 /*
159 * Notify the handler of an event.
160 *
161 * Return 0 on success and a -Exyz error code on error.
162 */
163 int (*report_event)(struct tcmu_device *dev);
147164
148165 /*
149166 * If the lock is acquired and the tag is not TCMU_INVALID_LOCK_TAG,
180197 * Update the logdir called by dynamic config thread.
181198 */
182199 bool (*update_logdir)(void);
200
201 /* To init/destroy some global resrouces if needed */
202 int (*init)(void);
203 void (*destroy)(void);
183204 };
184205
185206 void tcmur_cmd_complete(struct tcmu_device *dev, void *data, int rc);
3434 Summary: A daemon that handles the userspace side of the LIO TCM-User backstore
3535 Group: System Environment/Daemons
3636 License: ASL 2.0 or LGPLv2+
37 Version: 1.5.2
37 Version: 1.5.4
3838 URL: https://github.com/open-iscsi/tcmu-runner
3939
4040 #%define _RC
143143 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
144144 struct tcmu_io_queue *io_wq = &rdev->work_queue;
145145 int ret;
146
147 tcmu_set_thread_name("aio", dev);
146148
147149 while (1) {
148150 struct tcmu_work *work;
364364 pthread_mutex_lock(&state->lock);
365365 state->refcount++;
366366 pthread_mutex_unlock(&state->lock);
367
367
368368 ret = aio_request_schedule(dev, tcmur_ucmd, unmap_work_fn,
369369 tcmur_cmd_complete);
370370 if (ret != TCMU_STS_ASYNC_HANDLED)
372372
373373 nlbas -= lbas;
374374 lba += lbas;
375
376375 lbas = min(opt_unmap_gran, nlbas);
377
378376 }
379377
380378 return ret;
681679 uint8_t *cdb = cmd->cdb;
682680 uint64_t lba = tcmu_cdb_get_lba(cdb);
683681 uint64_t nlbas = tcmu_cdb_get_xfer_length(cdb);
682 uint32_t align = tcmu_dev_get_unmap_gran_align(dev);
684683 struct unmap_state *state;
685684 int ret;
685
686 /* If not aligned then falls back to the writesame without unmap */
687 if (lba % align || nlbas % align) {
688 tcmu_dev_dbg(dev,
689 "Start lba: %"PRIu64" or nlbas: %"PRIu64" not aligned to %"PRIu32"\n",
690 lba, nlbas, align);
691 tcmu_dev_dbg(dev, "Falls back to writesame without unmap!\n");
692 return TCMU_STS_NOT_HANDLED;
693 }
686694
687695 tcmu_dev_dbg(dev, "Do UNMAP in WRITE_SAME cmd!\n");
688696
700708
701709 unmap_put(dev, cmd, ret);
702710 return TCMU_STS_ASYNC_HANDLED;
711 }
712
713 static int tcmur_writesame_work_fn(struct tcmu_device *dev, void *data)
714 {
715 struct tcmur_cmd *tcmur_cmd = data;
716 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
717 tcmur_writesame_fn_t write_same_fn = tcmur_cmd->cmd_state;
718 uint8_t *cdb = cmd->cdb;
719 uint64_t off = tcmu_cdb_to_byte(dev, cdb);
720 uint64_t len = tcmu_lba_to_byte(dev, tcmu_cdb_get_xfer_length(cdb));
721
722 /*
723 * Write contents of the logical block data(from the Data-Out Buffer)
724 * to each LBA in the specified LBA range.
725 */
726 return write_same_fn(dev, tcmur_cmd, off, len, cmd->iovec,
727 cmd->iov_cnt);
703728 }
704729
705730 static int handle_writesame(struct tcmu_device *dev, struct tcmulib_cmd *cmd)
715740 struct write_same *write_same;
716741 int i, ret;
717742
743 if (tcmu_dev_in_recovery(dev))
744 return TCMU_STS_BUSY;
745
746 ret = alua_check_state(dev, cmd, false);
747 if (ret)
748 return ret;
749
718750 ret = handle_writesame_check(dev, cmd);
719751 if (ret)
720752 return ret;
721753
722 if (rhandler->unmap && (cmd->cdb[1] & 0x08))
723 return handle_unmap_in_writesame(dev, cmd);
754 if (rhandler->unmap && (cmd->cdb[1] & 0x08)) {
755 ret = handle_unmap_in_writesame(dev, cmd);
756 if (ret != TCMU_STS_NOT_HANDLED)
757 return ret;
758 }
759
760 if (rhandler->writesame) {
761 tcmur_cmd->cmd_state = rhandler->writesame;
762 tcmur_cmd->done = handle_generic_cbk;
763 return aio_request_schedule(dev, tcmur_cmd,
764 tcmur_writesame_work_fn,
765 tcmur_cmd_complete);
766 }
724767
725768 max_xfer_length = tcmu_dev_get_max_xfer_len(dev) * block_size;
726769 length = round_up(length, max_xfer_length);
745788 start_lba, write_lbas);
746789
747790 return aio_request_schedule(dev, tcmur_cmd, writesame_work_fn,
748 tcmur_cmd_complete);
749 }
750
751 static int tcmur_writesame_work_fn(struct tcmu_device *dev, void *data)
752 {
753 struct tcmur_cmd *tcmur_cmd = data;
754 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
755 tcmur_writesame_fn_t write_same_fn = tcmur_cmd->cmd_state;
756 uint8_t *cdb = cmd->cdb;
757 uint64_t off = tcmu_cdb_to_byte(dev, cdb);
758 uint64_t len = tcmu_lba_to_byte(dev, tcmu_cdb_get_xfer_length(cdb));
759
760 /*
761 * Write contents of the logical block data(from the Data-Out Buffer)
762 * to each LBA in the specified LBA range.
763 */
764 return write_same_fn(dev, tcmur_cmd, off, len, cmd->iovec,
765 cmd->iov_cnt);
766 }
767
768 int tcmur_handle_writesame(struct tcmu_device *dev, struct tcmur_cmd *tcmur_cmd,
769 tcmur_writesame_fn_t write_same_fn)
770 {
771 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
772 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
773 int ret;
774
775 if (tcmu_dev_in_recovery(dev))
776 return TCMU_STS_BUSY;
777
778 ret = alua_check_state(dev, cmd);
779 if (ret)
780 return ret;
781
782 ret = handle_writesame_check(dev, cmd);
783 if (ret)
784 return ret;
785
786 if (rhandler->unmap && (cmd->cdb[1] & 0x08))
787 return handle_unmap_in_writesame(dev, cmd);
788
789 tcmur_cmd->cmd_state = write_same_fn;
790 tcmur_cmd->done = handle_generic_cbk;
791
792 return aio_request_schedule(dev, tcmur_cmd, tcmur_writesame_work_fn,
793791 tcmur_cmd_complete);
794792 }
795793
11601158 {
11611159 int i, ret;
11621160
1161 if (tdll % XCOPY_TARGET_DESC_LEN) {
1162 tcmu_dev_err(udev,
1163 "CSCD descriptor list length %u not a multiple of %u\n",
1164 (unsigned int)tdll, XCOPY_TARGET_DESC_LEN);
1165 return TCMU_STS_NOTSUPP_TGT_DESC_TYPE;
1166 }
11631167 /* From spc4r36q,section 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field
11641168 * If the number of CSCD descriptors exceeds the allowed number, the copy
11651169 * manager shall terminate the command with CHECK CONDITION status, with
11721176 return TCMU_STS_TOO_MANY_TGT_DESC;
11731177 }
11741178
1175 for (i = 0; i < RCR_OP_MAX_TARGET_DESC_COUNT; i++) {
1179 for (i = 0; tdll >= XCOPY_TARGET_DESC_LEN; i++) {
11761180 /*
11771181 * Only Identification Descriptor Target Descriptor support
11781182 * for now.
11831187 return ret;
11841188
11851189 tgt_desc += XCOPY_TARGET_DESC_LEN;
1190 tdll -= XCOPY_TARGET_DESC_LEN;
11861191 } else {
11871192 tcmu_dev_err(udev, "Unsupport target descriptor type code 0x%x\n",
11881193 tgt_desc[0]);
11901195 }
11911196 }
11921197
1198 ret = TCMU_STS_CP_TGT_DEV_NOTCONN;
11931199 if (xcopy->src_dev)
11941200 ret = xcopy_locate_udev(udev->ctx, xcopy->dst_tid_wwn,
11951201 &xcopy->dst_dev);
13071313 * data, after the last segment descriptor.
13081314 * */
13091315 inline_dl = be32toh(*(uint32_t *)&par[12]);
1316 if (inline_dl != 0) {
1317 tcmu_dev_err(dev, "non-zero xcopy inline_dl %u unsupported\n",
1318 inline_dl);
1319 ret = TCMU_STS_INVALID_PARAM_LIST_LEN;
1320 goto err;
1321 }
13101322
13111323 /* From spc4r31, section 6.3.1 EXTENDED COPY command introduction
13121324 *
13481360 if (ret != TCMU_STS_OK)
13491361 goto err;
13501362
1363 /*
1364 * tcmu-runner can't determine whether the device(s) referred to in an
1365 * XCOPY request should be accessible to the initiator via transport
1366 * settings, ACLs, etc. XXX Consequently, we need to fail any
1367 * cross-device requests for safety reasons.
1368 */
1369 if (dev != xcopy->src_dev || dev != xcopy->dst_dev) {
1370 tcmu_dev_err(dev, "Cross-device XCOPY not supported\n");
1371 ret = TCMU_STS_CP_TGT_DEV_NOTCONN;
1372 goto err;
1373 }
1374
13511375 if (tcmu_dev_get_block_size(xcopy->src_dev) !=
13521376 tcmu_dev_get_block_size(xcopy->dst_dev)) {
13531377 tcmu_dev_err(dev, "The block size of src dev %u != dst dev %u\n",
16481672 return TCMU_STS_OK;
16491673 }
16501674
1675 static int tcmur_caw_fn(struct tcmu_device *dev, void *data)
1676 {
1677 struct tcmur_cmd *tcmur_cmd = data;
1678 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
1679 tcmur_caw_fn_t caw_fn = tcmur_cmd->cmd_state;
1680 uint64_t off = tcmu_cdb_to_byte(dev, cmd->cdb);
1681 size_t half = (tcmu_iovec_length(cmd->iovec, cmd->iov_cnt)) / 2;
1682
1683 return caw_fn(dev, tcmur_cmd, off, half, cmd->iovec, cmd->iov_cnt);
1684 }
1685
16511686 static int handle_caw(struct tcmu_device *dev, struct tcmulib_cmd *cmd)
16521687 {
1688 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
16531689 struct tcmur_cmd *tcmur_cmd = cmd->hm_private;
16541690 size_t half = (tcmu_iovec_length(cmd->iovec, cmd->iov_cnt)) / 2;
16551691 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
16561692 uint8_t sectors = cmd->cdb[13];
16571693 int ret;
1694
1695 if (tcmu_dev_in_recovery(dev))
1696 return TCMU_STS_BUSY;
1697
1698 ret = alua_check_state(dev, cmd, false);
1699 if (ret)
1700 return ret;
16581701
16591702 /* From sbc4r12a section 5.3 COMPARE AND WRITE command
16601703 * A NUMBER OF LOGICAL BLOCKS field set to zero specifies that no
16721715 if (ret)
16731716 return ret;
16741717
1718 if (rhandler->caw) {
1719 tcmur_cmd->cmd_state = rhandler->caw;
1720 tcmur_cmd->done = handle_generic_cbk;
1721 return aio_request_schedule(dev, tcmur_cmd, tcmur_caw_fn,
1722 tcmur_cmd_complete);
1723 }
1724
16751725 if (tcmur_cmd_state_init(tcmur_cmd, 0, half))
16761726 return TCMU_STS_NO_RESOURCE;
16771727
16871737 pthread_mutex_unlock(&rdev->caw_lock);
16881738 tcmur_cmd_state_free(tcmur_cmd);
16891739 return ret;
1690 }
1691
1692 static int tcmur_caw_fn(struct tcmu_device *dev, void *data)
1693 {
1694 struct tcmur_cmd *tcmur_cmd = data;
1695 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
1696 tcmur_caw_fn_t caw_fn = tcmur_cmd->cmd_state;
1697 uint64_t off = tcmu_cdb_to_byte(dev, cmd->cdb);
1698 size_t half = (tcmu_iovec_length(cmd->iovec, cmd->iov_cnt)) / 2;
1699
1700 return caw_fn(dev, tcmur_cmd, off, half, cmd->iovec, cmd->iov_cnt);
1701 }
1702
1703 int tcmur_handle_caw(struct tcmu_device *dev, struct tcmur_cmd *tcmur_cmd,
1704 tcmur_caw_fn_t caw_fn)
1705 {
1706 struct tcmulib_cmd *cmd = tcmur_cmd->lib_cmd;
1707 uint8_t sectors = cmd->cdb[13];
1708 int ret;
1709
1710 if (tcmu_dev_in_recovery(dev))
1711 return TCMU_STS_BUSY;
1712
1713 /* From sbc4r12a section 5.3 COMPARE AND WRITE command
1714 * A NUMBER OF LOGICAL BLOCKS field set to zero specifies that no
1715 * read operations shall be performed, no logical block data shall
1716 * be transferred from the Data-Out Buffer, no compare operations
1717 * shall be performed, and no write operations shall be performed.
1718 * This condition shall not be considered an error.
1719 */
1720 if (!sectors) {
1721 tcmu_dev_dbg(dev, "NUMBER OF LOGICAL BLOCKS is zero, just return ok.\n");
1722 return TCMU_STS_OK;
1723 }
1724
1725 ret = alua_check_state(dev, cmd);
1726 if (ret)
1727 return ret;
1728
1729 ret = handle_caw_check(dev, cmd);
1730 if (ret)
1731 return ret;
1732
1733 tcmur_cmd->cmd_state = caw_fn;
1734 tcmur_cmd->done = handle_generic_cbk;
1735
1736 return aio_request_schedule(dev, tcmur_cmd, tcmur_caw_fn,
1737 tcmur_cmd_complete);
17381740 }
17391741
17401742 /* async flush */
21172119 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
21182120 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
21192121 uint8_t *cdb = cmd->cdb;
2122 bool is_read = false;
21202123
21212124 track_aio_request_start(rdev);
21222125
21272130
21282131 /* Don't perform alua implicit transition if command is not supported */
21292132 switch(cdb[0]) {
2133 /* Skip to grab the lock for reads */
21302134 case READ_6:
21312135 case READ_10:
21322136 case READ_12:
21332137 case READ_16:
2138 is_read = true;
21342139 case WRITE_6:
21352140 case WRITE_10:
21362141 case WRITE_12:
21452150 case WRITE_SAME:
21462151 case WRITE_SAME_16:
21472152 case FORMAT_UNIT:
2148 ret = alua_check_state(dev, cmd);
2153 ret = alua_check_state(dev, cmd, is_read);
21492154 if (ret)
21502155 goto untrack;
21512156 break;
2323 bool tcmur_handler_is_passthrough_only(struct tcmur_handler *rhandler);
2424 void tcmur_tcmulib_cmd_complete(struct tcmu_device *dev,
2525 struct tcmulib_cmd *cmd, int ret);
26
2627 typedef int (*tcmur_writesame_fn_t)(struct tcmu_device *dev,
2728 struct tcmur_cmd *tcmur_cmd, uint64_t off,
2829 uint64_t len, struct iovec *iov,
2930 size_t iov_cnt);
30 int tcmur_handle_writesame(struct tcmu_device *dev, struct tcmur_cmd *tcmur_cmd,
31 tcmur_writesame_fn_t write_same_fn);
3231
3332 typedef int (*tcmur_caw_fn_t)(struct tcmu_device *dev,
3433 struct tcmur_cmd *tcmur_cmd, uint64_t off,
3534 uint64_t len, struct iovec *iov, size_t iov_cnt);
36 int tcmur_handle_caw(struct tcmu_device *dev, struct tcmur_cmd *tcmur_cmd,
37 tcmur_caw_fn_t caw_fn);
3835
3936 #endif /* __TCMUR_CMD_HANDLER_H */
1919 #include "tcmu-runner.h"
2020 #include "tcmur_device.h"
2121 #include "tcmur_cmd_handler.h"
22 #include "tcmur_work.h"
2223 #include "tcmu_runner_priv.h"
2324 #include "target.h"
2425
4344 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
4445 int ret, attempt = 0;
4546 bool needs_close = false;
46 bool cancel_lock = false;
4747
4848 pthread_mutex_lock(&rdev->state_lock);
4949 if (rdev->flags & TCMUR_DEV_FLAG_STOPPING) {
5050 ret = 0;
5151 goto done;
5252 }
53
54 if (rdev->lock_state == TCMUR_DEV_LOCK_LOCKING &&
55 pthread_self() != rdev->lock_thread)
56 cancel_lock = true;
5753 pthread_mutex_unlock(&rdev->state_lock);
5854
5955 /*
6157 * async lock requests in progress that might be accessing
6258 * the device.
6359 */
64 if (cancel_lock)
65 tcmu_cancel_lock_thread(dev);
66
67 /*
68 * Force a reacquisition of the lock when we have reopend the
69 * device, so it can update state. If we are being called from
70 * the lock code path then do not change state.
71 */
72 pthread_mutex_lock(&rdev->state_lock);
73 if (rdev->lock_state != TCMUR_DEV_LOCK_LOCKING)
74 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
75
60 tcmur_flush_work(rdev->event_work);
61
62 pthread_mutex_lock(&rdev->state_lock);
7663 if (rdev->flags & TCMUR_DEV_FLAG_IS_OPEN)
7764 needs_close = true;
7865 rdev->flags &= ~TCMUR_DEV_FLAG_IS_OPEN;
164151 }
165152 pthread_mutex_unlock(&rdev->state_lock);
166153 tcmu_dev_dbg(dev, "Recovery thread wait done\n");
154 }
155
156 static void __tcmu_report_event(void *data)
157 {
158 struct tcmu_device *dev = data;
159 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
160 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
161 int ret;
162
163 /*
164 * For cmd timeouts and unbalanced systems we will get a burst so wait
165 * a second to batch up the updates.
166 */
167 sleep(1);
168
169 pthread_mutex_lock(&rdev->state_lock);
170 ret = rhandler->report_event(dev);
171 if (ret)
172 tcmu_dev_err(dev, "Could not report events. Error %d.\n", ret);
173 pthread_mutex_unlock(&rdev->state_lock);
174 }
175
176 static void tcmu_report_event(struct tcmu_device *dev)
177 {
178 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
179 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
180 int ret;
181
182 if (!rhandler->report_event)
183 return;
184
185 ret = tcmur_run_work(rdev->event_work, dev, __tcmu_report_event);
186 if (!ret)
187 return;
188
189 if (ret != -EBUSY)
190 tcmu_dev_err(dev, "Could not execute event work. Error %d", ret);
191 }
192
193 static bool __tcmu_notify_conn_lost(struct tcmu_device *dev)
194 {
195 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
196
197 /*
198 * Although there are 2 checks for STOPPING in __tcmu_reopen_dev
199 * which is called a little later by the recovery thread, STOPPING
200 * checking is still needed here.
201 *
202 * In device removal, tcmu_get_alua_grps will never get access to
203 * configfs dir resource which is holded by kernel in configfs_rmdir,
204 * thus tcmulib_cmd->done() will never get a chance to clear
205 * tracked_aio_ops. This will cause a deadlock in dev_removed
206 * which is polling tracked_aio_ops.
207 */
208 if ((rdev->flags & TCMUR_DEV_FLAG_STOPPING) ||
209 (rdev->flags & TCMUR_DEV_FLAG_IN_RECOVERY))
210 return false;
211
212 tcmu_dev_err(dev, "Handler connection lost (lock state %d)\n",
213 rdev->lock_state);
214
215 if (!tcmu_add_dev_to_recovery_list(dev)) {
216 rdev->flags |= TCMUR_DEV_FLAG_IN_RECOVERY;
217 rdev->conn_lost_cnt++;
218 return true;
219 }
220
221 return false;
167222 }
168223
169224 /**
178233 void tcmu_notify_conn_lost(struct tcmu_device *dev)
179234 {
180235 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
181
182 pthread_mutex_lock(&rdev->state_lock);
183
184 /*
185 * Although there are 2 checks for STOPPING in __tcmu_reopen_dev
186 * which is called a little later by the recovery thread, STOPPING
187 * checking is still needed here.
188 *
189 * In device removal, tcmu_get_alua_grps will never get access to
190 * configfs dir resource which is holded by kernel in configfs_rmdir,
191 * thus tcmulib_cmd->done() will never get a chance to clear
192 * tracked_aio_ops. This will cause a deadlock in dev_removed
193 * which is polling tracked_aio_ops.
194 */
195 if ((rdev->flags & TCMUR_DEV_FLAG_STOPPING) ||
196 (rdev->flags & TCMUR_DEV_FLAG_IN_RECOVERY))
197 goto unlock;
198
199 tcmu_dev_err(dev, "Handler connection lost (lock state %d)\n",
200 rdev->lock_state);
201
202 if (!tcmu_add_dev_to_recovery_list(dev))
203 rdev->flags |= TCMUR_DEV_FLAG_IN_RECOVERY;
204 unlock:
205 pthread_mutex_unlock(&rdev->state_lock);
236 bool report;
237
238 pthread_mutex_lock(&rdev->state_lock);
239 report =__tcmu_notify_conn_lost(dev);
240 pthread_mutex_unlock(&rdev->state_lock);
241
242 if (report)
243 tcmu_report_event(dev);
244 }
245
246 static void __tcmu_notify_lock_lost(struct tcmu_device *dev)
247 {
248 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
249
250 rdev->lock_lost = true;
251 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
252 rdev->lock_lost_cnt++;
253
254 tcmu_report_event(dev);
206255 }
207256
208257 /**
223272 * We could be getting stale IO completions. If we are trying to
224273 * reaquire the lock do not change state.
225274 */
226 if (rdev->lock_state != TCMUR_DEV_LOCK_LOCKING) {
227 rdev->lock_lost = true;
228 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
229 }
230 pthread_mutex_unlock(&rdev->state_lock);
231 }
232
233 int tcmu_cancel_lock_thread(struct tcmu_device *dev)
234 {
275 if (rdev->lock_state != TCMUR_DEV_LOCK_WRITE_LOCKING) {
276 __tcmu_notify_lock_lost(dev);
277 }
278 pthread_mutex_unlock(&rdev->state_lock);
279 }
280
281 void tcmu_release_dev_lock(struct tcmu_device *dev)
282 {
283 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
235284 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
236285 int ret;
237286
238287 pthread_mutex_lock(&rdev->state_lock);
239 if (rdev->lock_state != TCMUR_DEV_LOCK_LOCKING) {
240 pthread_mutex_unlock(&rdev->state_lock);
241 return 0;
242 }
243 /*
244 * It looks like lock calls are not cancelable, so
245 * we wait here to avoid crashes.
246 */
247 tcmu_dev_dbg(rdev->dev, "waiting for lock thread to exit\n");
248 ret = pthread_cond_wait(&rdev->lock_cond, &rdev->state_lock);
249 pthread_mutex_unlock(&rdev->state_lock);
250
251 return ret;
252 }
253
254 void tcmu_release_dev_lock(struct tcmu_device *dev)
255 {
256 struct tcmur_handler *rhandler = tcmu_get_runner_handler(dev);
257 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
258 int ret;
259
260 pthread_mutex_lock(&rdev->state_lock);
261 if (rdev->lock_state != TCMUR_DEV_LOCK_LOCKED) {
288 if (rdev->lock_state != TCMUR_DEV_LOCK_WRITE_LOCKED) {
262289 pthread_mutex_unlock(&rdev->state_lock);
263290 return;
264291 }
375402 goto done;
376403 }
377404
405 /*
406 * Since we are here the lock state must be one of:
407 * for implicit:
408 * TCMUR_DEV_LOCK_READ_LOCKING
409 * TCMUR_DEV_LOCK_WRITE_LOCKING
410 *
411 * for explicit:
412 * TCMUR_DEV_LOCK_UNLOCKED
413 * TCMUR_DEV_LOCK_UNKNOWN
414 */
415
378416 reopen = false;
379417 pthread_mutex_lock(&rdev->state_lock);
380 if (rdev->lock_lost || !(rdev->flags & TCMUR_DEV_FLAG_IS_OPEN)) {
418 if (rdev->lock_lost || !(rdev->flags & TCMUR_DEV_FLAG_IS_OPEN))
381419 reopen = true;
382 }
383420 pthread_mutex_unlock(&rdev->state_lock);
384421
385422 retry:
397434 goto drop_conn;
398435 }
399436 }
437
438 pthread_mutex_lock(&rdev->state_lock);
439 if (rdev->lock_state == TCMUR_DEV_LOCK_READ_LOCKING) {
440 pthread_mutex_unlock(&rdev->state_lock);
441 ret = TCMU_STS_OK;
442 goto done;
443 }
444 pthread_mutex_unlock(&rdev->state_lock);
400445
401446 ret = rhandler->lock(dev, tag);
402447 if (ret == TCMU_STS_FENCED) {
431476
432477 /* TODO: set UA based on bgly's patches */
433478 pthread_mutex_lock(&rdev->state_lock);
434 if (ret == TCMU_STS_OK)
435 rdev->lock_state = TCMUR_DEV_LOCK_LOCKED;
436 else
479 if (ret != TCMU_STS_OK) {
437480 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
438
439 tcmu_dev_dbg(dev, "lock call done. lock state %d\n", rdev->lock_state);
481 tcmu_dev_info(dev, "Lock acquisition unsuccessful\n");
482 } else {
483 if (rdev->lock_state == TCMUR_DEV_LOCK_READ_LOCKING) {
484 rdev->lock_state = TCMUR_DEV_LOCK_READ_LOCKED;
485 tcmu_dev_info(dev, "Read lock acquisition successful\n");
486 } else if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKING) {
487 rdev->lock_state = TCMUR_DEV_LOCK_WRITE_LOCKED;
488 tcmu_dev_info(dev, "Write lock acquisition successful\n");
489 } else {
490 /*
491 * For explicit transition it will always acquire the write lock.
492 */
493 rdev->lock_state = TCMUR_DEV_LOCK_WRITE_LOCKED;
494 tcmu_dev_info(dev, "Write lock acquisition successful\n");
495 }
496 }
497
440498 tcmu_cfgfs_dev_exec_action(dev, "block_dev", 0);
441499
442 pthread_cond_signal(&rdev->lock_cond);
443500 pthread_mutex_unlock(&rdev->state_lock);
444501
445502 return ret;
465522 state = rhandler->get_lock_state(dev);
466523 pthread_mutex_lock(&rdev->state_lock);
467524 check_state:
468 if (rdev->lock_state == TCMUR_DEV_LOCK_LOCKED &&
469 state != TCMUR_DEV_LOCK_LOCKED) {
525 if (rdev->lock_state == TCMUR_DEV_LOCK_WRITE_LOCKED &&
526 state != TCMUR_DEV_LOCK_WRITE_LOCKED) {
470527 tcmu_dev_dbg(dev, "Updated out of sync lock state.\n");
471 rdev->lock_state = TCMUR_DEV_LOCK_UNLOCKED;
472 rdev->lock_lost = true;
528 __tcmu_notify_lock_lost(dev);
473529 }
474530 pthread_mutex_unlock(&rdev->state_lock);
475531 }
487543
488544 return rdev->hm_private;
489545 }
546
547 void tcmu_notify_cmd_timed_out(struct tcmu_device *dev)
548 {
549 struct tcmur_device *rdev = tcmu_dev_get_private(dev);
550
551 pthread_mutex_lock(&rdev->state_lock);
552 rdev->cmd_timed_out_cnt++;
553 __tcmu_notify_conn_lost(dev);
554 pthread_mutex_unlock(&rdev->state_lock);
555
556 tcmu_report_event(dev);
557 }
3131 };
3232
3333 enum {
34 TCMUR_DEV_LOCK_UNKNOWN,
3435 TCMUR_DEV_LOCK_UNLOCKED,
35 TCMUR_DEV_LOCK_LOCKED,
36 TCMUR_DEV_LOCK_LOCKING,
37 TCMUR_DEV_LOCK_UNKNOWN,
36 TCMUR_DEV_LOCK_READ_LOCKING,
37 TCMUR_DEV_LOCK_READ_LOCKED,
38 TCMUR_DEV_LOCK_WRITE_LOCKING,
39 TCMUR_DEV_LOCK_WRITE_LOCKED,
3840 };
41
42 struct tcmur_work;
3943
4044 struct tcmur_device {
4145 struct tcmu_device *dev;
4751 uint32_t flags;
4852 uint8_t failover_type;
4953
50 pthread_t recovery_thread;
5154 struct list_node recovery_entry;
55
56 /* tcmur_event counters */
57 uint64_t lock_lost_cnt;
58 uint64_t conn_lost_cnt;
59 uint64_t cmd_timed_out_cnt;
60 struct tcmur_work *event_work;
5261
5362 bool lock_lost;
5463 uint8_t lock_state;
55 pthread_t lock_thread;
56 pthread_cond_t lock_cond;
5764
5865 /* General lock for lock state, thread, dev state, etc */
5966 pthread_mutex_t state_lock;
7986
8087 bool tcmu_dev_in_recovery(struct tcmu_device *dev);
8188 void tcmu_cancel_recovery(struct tcmu_device *dev);
82 int tcmu_cancel_lock_thread(struct tcmu_device *dev);
8389
8490 void tcmu_notify_conn_lost(struct tcmu_device *dev);
8591 void tcmu_notify_lock_lost(struct tcmu_device *dev);
92 void tcmu_notify_cmd_timed_out(struct tcmu_device *dev);
8693
8794 int __tcmu_reopen_dev(struct tcmu_device *dev, int retries);
8895 int tcmu_reopen_dev(struct tcmu_device *dev, int retries);
0 /*
1 * Copyright (c) 2020 Red Hat, Inc.
2 *
3 * This file is licensed to you under your choice of the GNU Lesser
4 * General Public License, version 2.1 or any later version (LGPLv2.1 or
5 * later), or the Apache License 2.0.
6 */
7 #define _GNU_SOURCE
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <errno.h>
11 #include <pthread.h>
12
13 #include "libtcmu.h"
14 #include "libtcmu_log.h"
15 #include "tcmur_device.h"
16 #include "tcmur_work.h"
17
18 struct tcmur_work *tcmur_create_work(void)
19 {
20 struct tcmur_work *work;
21
22 work = calloc(1, sizeof(*work));
23 if (!work)
24 return NULL;
25
26 if (pthread_mutex_init(&work->lock, NULL))
27 goto free_work;
28
29 if (pthread_cond_init(&work->cond, NULL))
30 goto destroy_mutex;
31
32 return work;
33
34 destroy_mutex:
35 pthread_mutex_destroy(&work->lock);
36 free_work:
37 free(work);
38 return NULL;
39 }
40
41 static void __tcmur_flush_work(struct tcmur_work *work)
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 /*
49 * The event work thread may need to do a handler reopen
50 * call and try to flush itself. Just ignore.
51 */
52 if (!strcmp(pname, "ework-thread"))
53 return;
54
55 /*
56 * Some handlers will crash if we do a cancel so we just wait.
57 */
58 tcmu_dbg("waiting for %d work thread to complete\n", work->refcnt);
59 if (work->refcnt)
60 pthread_cond_wait(&work->cond, &work->lock);
61 }
62
63 void tcmur_flush_work(struct tcmur_work *work)
64 {
65 pthread_mutex_lock(&work->lock);
66 __tcmur_flush_work(work);
67 pthread_mutex_unlock(&work->lock);
68 }
69
70 struct private {
71 void *data;
72 void (*work_fn)(void *);
73 struct tcmur_work *work;
74 };
75
76 static void *tcmur_work_fn(void *data)
77 {
78 struct private *p = data;
79
80 tcmu_set_thread_name("ework-thread", NULL);
81
82 p->work_fn(p->data);
83
84 pthread_mutex_lock(&p->work->lock);
85 if (--p->work->refcnt == 0)
86 pthread_cond_signal(&p->work->cond);
87 pthread_mutex_unlock(&p->work->lock);
88
89 free(p);
90 return NULL;
91 }
92
93 int tcmur_run_work(struct tcmur_work *work, void *data, void (*work_fn)(void *))
94 {
95 pthread_attr_t attr;
96 pthread_t thread;
97 struct private *p;
98 int ret;
99
100 p = malloc(sizeof(struct private));
101 if (!p)
102 return -ENOMEM;
103
104 p->data = data;
105 p->work_fn = work_fn;
106 p->work = work;
107
108 pthread_attr_init(&attr);
109 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
110
111 pthread_mutex_lock(&work->lock);
112 ret = pthread_create(&thread, &attr, tcmur_work_fn, p);
113 if (!ret)
114 work->refcnt++;
115 pthread_mutex_unlock(&work->lock);
116
117 pthread_attr_destroy(&attr);
118
119 if (ret)
120 free(p);
121 return ret;
122 }
123
124 void tcmur_destroy_work(struct tcmur_work *work)
125 {
126 tcmur_flush_work(work);
127 pthread_mutex_destroy(&work->lock);
128 pthread_cond_destroy(&work->cond);
129 free(work);
130 }
0 /*
1 * Copyright (c) 2020 Red Hat, Inc.
2 *
3 * This file is licensed to you under your choice of the GNU Lesser
4 * General Public License, version 2.1 or any later version (LGPLv2.1 or
5 * later), or the Apache License 2.0.
6 */
7
8 #ifndef __TCMU_WORK_H
9 #define __TCMU_WORK_H
10
11 #include <pthread.h>
12
13 #include "ccan/list/list.h"
14
15 struct tcmu_device;
16
17 struct tcmur_work {
18 pthread_mutex_t lock;
19 pthread_cond_t cond;
20 int refcnt;
21 };
22
23 struct tcmur_work *tcmur_create_work(void);
24 void tcmur_destroy_work(struct tcmur_work *work);
25 int tcmur_run_work(struct tcmur_work *work, void *data,
26 void (*work_fn)(void *));
27 void tcmur_flush_work(struct tcmur_work *work);
28
29 #endif
33 #define DEFAULT_HANDLER_PATH "@tcmu-runner_HANDLER_PATH@"
44
55 #define GFAPI_VERSION760 @GFAPI_VERSION760@
6
7 #define GFAPI_VERSION766 @GFAPI_VERSION766@