pr-manager-helper.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Persistent reservation manager that talks to qemu-pr-helper
  3. *
  4. * Copyright (c) 2017 Red Hat, Inc.
  5. *
  6. * Author: Paolo Bonzini <pbonzini@redhat.com>
  7. *
  8. * This code is licensed under the LGPL v2.1 or later.
  9. *
  10. */
  11. #include "qemu/osdep.h"
  12. #include "qapi/error.h"
  13. #include "scsi/constants.h"
  14. #include "scsi/pr-manager.h"
  15. #include "scsi/utils.h"
  16. #include "io/channel.h"
  17. #include "io/channel-socket.h"
  18. #include "pr-helper.h"
  19. #include "qapi/qapi-events-block.h"
  20. #include "qemu/module.h"
  21. #include <scsi/sg.h>
  22. #include "qom/object.h"
  23. #define PR_MAX_RECONNECT_ATTEMPTS 5
  24. #define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
  25. OBJECT_DECLARE_SIMPLE_TYPE(PRManagerHelper, PR_MANAGER_HELPER)
  26. struct PRManagerHelper {
  27. /* <private> */
  28. PRManager parent;
  29. char *path;
  30. QemuMutex lock;
  31. QIOChannel *ioc;
  32. };
  33. static void pr_manager_send_status_changed_event(PRManagerHelper *pr_mgr)
  34. {
  35. const char *id = object_get_canonical_path_component(OBJECT(pr_mgr));
  36. if (id) {
  37. qapi_event_send_pr_manager_status_changed(id, !!pr_mgr->ioc);
  38. }
  39. }
  40. /* Called with lock held. */
  41. static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
  42. void *buf, int sz, Error **errp)
  43. {
  44. ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
  45. if (r < 0) {
  46. object_unref(OBJECT(pr_mgr->ioc));
  47. pr_mgr->ioc = NULL;
  48. pr_manager_send_status_changed_event(pr_mgr);
  49. return -EINVAL;
  50. }
  51. return 0;
  52. }
  53. /* Called with lock held. */
  54. static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
  55. int fd,
  56. const void *buf, int sz, Error **errp)
  57. {
  58. size_t nfds = (fd != -1);
  59. while (sz > 0) {
  60. struct iovec iov;
  61. ssize_t n_written;
  62. iov.iov_base = (void *)buf;
  63. iov.iov_len = sz;
  64. n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
  65. nfds ? &fd : NULL, nfds, 0, errp);
  66. if (n_written <= 0) {
  67. assert(n_written != QIO_CHANNEL_ERR_BLOCK);
  68. object_unref(OBJECT(pr_mgr->ioc));
  69. pr_mgr->ioc = NULL;
  70. pr_manager_send_status_changed_event(pr_mgr);
  71. return n_written < 0 ? -EINVAL : 0;
  72. }
  73. nfds = 0;
  74. buf += n_written;
  75. sz -= n_written;
  76. }
  77. return 0;
  78. }
  79. /* Called with lock held. */
  80. static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
  81. Error **errp)
  82. {
  83. char *path = g_strdup(pr_mgr->path);
  84. SocketAddress saddr = {
  85. .type = SOCKET_ADDRESS_TYPE_UNIX,
  86. .u.q_unix.path = path
  87. };
  88. QIOChannelSocket *sioc = qio_channel_socket_new();
  89. Error *local_err = NULL;
  90. uint32_t flags;
  91. int r;
  92. assert(!pr_mgr->ioc);
  93. qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
  94. qio_channel_socket_connect_sync(sioc,
  95. &saddr,
  96. &local_err);
  97. g_free(path);
  98. if (local_err) {
  99. object_unref(OBJECT(sioc));
  100. error_propagate(errp, local_err);
  101. return -ENOTCONN;
  102. }
  103. qio_channel_set_delay(QIO_CHANNEL(sioc), false);
  104. pr_mgr->ioc = QIO_CHANNEL(sioc);
  105. /* A simple feature negotiation protocol, even though there is
  106. * no optional feature right now.
  107. */
  108. r = pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp);
  109. if (r < 0) {
  110. goto out_close;
  111. }
  112. flags = 0;
  113. r = pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp);
  114. if (r < 0) {
  115. goto out_close;
  116. }
  117. pr_manager_send_status_changed_event(pr_mgr);
  118. return 0;
  119. out_close:
  120. object_unref(OBJECT(pr_mgr->ioc));
  121. pr_mgr->ioc = NULL;
  122. return r;
  123. }
  124. static int pr_manager_helper_run(PRManager *p,
  125. int fd, struct sg_io_hdr *io_hdr)
  126. {
  127. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
  128. uint32_t len;
  129. PRHelperResponse resp;
  130. int ret;
  131. int expected_dir;
  132. int attempts;
  133. uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
  134. if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
  135. return -EINVAL;
  136. }
  137. memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
  138. assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
  139. expected_dir =
  140. (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
  141. if (io_hdr->dxfer_direction != expected_dir) {
  142. return -EINVAL;
  143. }
  144. len = scsi_cdb_xfer(cdb);
  145. if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
  146. return -EINVAL;
  147. }
  148. qemu_mutex_lock(&pr_mgr->lock);
  149. /* Try to reconnect while sending the CDB. */
  150. for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
  151. if (!pr_mgr->ioc) {
  152. ret = pr_manager_helper_initialize(pr_mgr, NULL);
  153. if (ret < 0) {
  154. qemu_mutex_unlock(&pr_mgr->lock);
  155. g_usleep(G_USEC_PER_SEC);
  156. qemu_mutex_lock(&pr_mgr->lock);
  157. continue;
  158. }
  159. }
  160. ret = pr_manager_helper_write(pr_mgr, fd, cdb, ARRAY_SIZE(cdb), NULL);
  161. if (ret >= 0) {
  162. break;
  163. }
  164. }
  165. if (ret < 0) {
  166. goto out;
  167. }
  168. /* After sending the CDB, any communications failure causes the
  169. * command to fail. The failure is transient, retrying the command
  170. * will invoke pr_manager_helper_initialize again.
  171. */
  172. if (expected_dir == SG_DXFER_TO_DEV) {
  173. io_hdr->resid = io_hdr->dxfer_len - len;
  174. ret = pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp, len, NULL);
  175. if (ret < 0) {
  176. goto out;
  177. }
  178. }
  179. ret = pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL);
  180. if (ret < 0) {
  181. goto out;
  182. }
  183. resp.result = be32_to_cpu(resp.result);
  184. resp.sz = be32_to_cpu(resp.sz);
  185. if (io_hdr->dxfer_direction == SG_DXFER_FROM_DEV) {
  186. assert(resp.sz <= io_hdr->dxfer_len);
  187. ret = pr_manager_helper_read(pr_mgr, io_hdr->dxferp, resp.sz, NULL);
  188. if (ret < 0) {
  189. goto out;
  190. }
  191. io_hdr->resid = io_hdr->dxfer_len - resp.sz;
  192. } else {
  193. assert(resp.sz == 0);
  194. }
  195. io_hdr->status = resp.result;
  196. if (resp.result == CHECK_CONDITION) {
  197. io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
  198. io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
  199. memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
  200. }
  201. out:
  202. if (ret < 0) {
  203. int sense_len = scsi_build_sense(io_hdr->sbp,
  204. SENSE_CODE(LUN_COMM_FAILURE));
  205. io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
  206. io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
  207. io_hdr->status = CHECK_CONDITION;
  208. }
  209. qemu_mutex_unlock(&pr_mgr->lock);
  210. return ret;
  211. }
  212. static bool pr_manager_helper_is_connected(PRManager *p)
  213. {
  214. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
  215. bool result;
  216. qemu_mutex_lock(&pr_mgr->lock);
  217. result = (pr_mgr->ioc != NULL);
  218. qemu_mutex_unlock(&pr_mgr->lock);
  219. return result;
  220. }
  221. static void pr_manager_helper_complete(UserCreatable *uc, Error **errp)
  222. {
  223. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc);
  224. qemu_mutex_lock(&pr_mgr->lock);
  225. pr_manager_helper_initialize(pr_mgr, errp);
  226. qemu_mutex_unlock(&pr_mgr->lock);
  227. }
  228. static char *get_path(Object *obj, Error **errp)
  229. {
  230. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
  231. return g_strdup(pr_mgr->path);
  232. }
  233. static void set_path(Object *obj, const char *str, Error **errp)
  234. {
  235. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
  236. g_free(pr_mgr->path);
  237. pr_mgr->path = g_strdup(str);
  238. }
  239. static void pr_manager_helper_instance_finalize(Object *obj)
  240. {
  241. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
  242. object_unref(OBJECT(pr_mgr->ioc));
  243. qemu_mutex_destroy(&pr_mgr->lock);
  244. }
  245. static void pr_manager_helper_instance_init(Object *obj)
  246. {
  247. PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
  248. qemu_mutex_init(&pr_mgr->lock);
  249. }
  250. static void pr_manager_helper_class_init(ObjectClass *klass,
  251. void *class_data G_GNUC_UNUSED)
  252. {
  253. PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass);
  254. UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
  255. object_class_property_add_str(klass, "path", get_path, set_path);
  256. uc_klass->complete = pr_manager_helper_complete;
  257. prmgr_klass->run = pr_manager_helper_run;
  258. prmgr_klass->is_connected = pr_manager_helper_is_connected;
  259. }
  260. static const TypeInfo pr_manager_helper_info = {
  261. .parent = TYPE_PR_MANAGER,
  262. .name = TYPE_PR_MANAGER_HELPER,
  263. .instance_size = sizeof(PRManagerHelper),
  264. .instance_init = pr_manager_helper_instance_init,
  265. .instance_finalize = pr_manager_helper_instance_finalize,
  266. .class_init = pr_manager_helper_class_init,
  267. };
  268. static void pr_manager_helper_register_types(void)
  269. {
  270. type_register_static(&pr_manager_helper_info);
  271. }
  272. type_init(pr_manager_helper_register_types);