dm-log-userspace-transfer.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Copyright (C) 2006-2009 Red Hat, Inc.
  3. *
  4. * This file is released under the LGPL.
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <net/sock.h>
  9. #include <linux/workqueue.h>
  10. #include <linux/connector.h>
  11. #include <linux/device-mapper.h>
  12. #include <linux/dm-log-userspace.h>
  13. #include "dm-log-userspace-transfer.h"
  14. static uint32_t dm_ulog_seq;
  15. /*
  16. * Netlink/Connector is an unreliable protocol. How long should
  17. * we wait for a response before assuming it was lost and retrying?
  18. * (If we do receive a response after this time, it will be discarded
  19. * and the response to the resent request will be waited for.
  20. */
  21. #define DM_ULOG_RETRY_TIMEOUT (15 * HZ)
  22. /*
  23. * Pre-allocated space for speed
  24. */
  25. #define DM_ULOG_PREALLOCED_SIZE 512
  26. static struct cn_msg *prealloced_cn_msg;
  27. static struct dm_ulog_request *prealloced_ulog_tfr;
  28. static struct cb_id ulog_cn_id = {
  29. .idx = CN_IDX_DM,
  30. .val = CN_VAL_DM_USERSPACE_LOG
  31. };
  32. static DEFINE_MUTEX(dm_ulog_lock);
  33. struct receiving_pkg {
  34. struct list_head list;
  35. struct completion complete;
  36. uint32_t seq;
  37. int error;
  38. size_t *data_size;
  39. char *data;
  40. };
  41. static DEFINE_SPINLOCK(receiving_list_lock);
  42. static struct list_head receiving_list;
  43. static int dm_ulog_sendto_server(struct dm_ulog_request *tfr)
  44. {
  45. int r;
  46. struct cn_msg *msg = prealloced_cn_msg;
  47. memset(msg, 0, sizeof(struct cn_msg));
  48. msg->id.idx = ulog_cn_id.idx;
  49. msg->id.val = ulog_cn_id.val;
  50. msg->ack = 0;
  51. msg->seq = tfr->seq;
  52. msg->len = sizeof(struct dm_ulog_request) + tfr->data_size;
  53. r = cn_netlink_send(msg, 0, gfp_any());
  54. return r;
  55. }
  56. /*
  57. * Parameters for this function can be either msg or tfr, but not
  58. * both. This function fills in the reply for a waiting request.
  59. * If just msg is given, then the reply is simply an ACK from userspace
  60. * that the request was received.
  61. *
  62. * Returns: 0 on success, -ENOENT on failure
  63. */
  64. static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
  65. {
  66. uint32_t rtn_seq = (msg) ? msg->seq : (tfr) ? tfr->seq : 0;
  67. struct receiving_pkg *pkg;
  68. /*
  69. * The 'receiving_pkg' entries in this list are statically
  70. * allocated on the stack in 'dm_consult_userspace'.
  71. * Each process that is waiting for a reply from the user
  72. * space server will have an entry in this list.
  73. *
  74. * We are safe to do it this way because the stack space
  75. * is unique to each process, but still addressable by
  76. * other processes.
  77. */
  78. list_for_each_entry(pkg, &receiving_list, list) {
  79. if (rtn_seq != pkg->seq)
  80. continue;
  81. if (msg) {
  82. pkg->error = -msg->ack;
  83. /*
  84. * If we are trying again, we will need to know our
  85. * storage capacity. Otherwise, along with the
  86. * error code, we make explicit that we have no data.
  87. */
  88. if (pkg->error != -EAGAIN)
  89. *(pkg->data_size) = 0;
  90. } else if (tfr->data_size > *(pkg->data_size)) {
  91. DMERR("Insufficient space to receive package [%u] "
  92. "(%u vs %lu)", tfr->request_type,
  93. tfr->data_size, *(pkg->data_size));
  94. *(pkg->data_size) = 0;
  95. pkg->error = -ENOSPC;
  96. } else {
  97. pkg->error = tfr->error;
  98. memcpy(pkg->data, tfr->data, tfr->data_size);
  99. *(pkg->data_size) = tfr->data_size;
  100. }
  101. complete(&pkg->complete);
  102. return 0;
  103. }
  104. return -ENOENT;
  105. }
  106. /*
  107. * This is the connector callback that delivers data
  108. * that was sent from userspace.
  109. */
  110. static void cn_ulog_callback(void *data)
  111. {
  112. struct cn_msg *msg = (struct cn_msg *)data;
  113. struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
  114. spin_lock(&receiving_list_lock);
  115. if (msg->len == 0)
  116. fill_pkg(msg, NULL);
  117. else if (msg->len < sizeof(*tfr))
  118. DMERR("Incomplete message received (expected %u, got %u): [%u]",
  119. (unsigned)sizeof(*tfr), msg->len, msg->seq);
  120. else
  121. fill_pkg(NULL, tfr);
  122. spin_unlock(&receiving_list_lock);
  123. }
  124. /**
  125. * dm_consult_userspace
  126. * @uuid: log's uuid (must be DM_UUID_LEN in size)
  127. * @request_type: found in include/linux/dm-log-userspace.h
  128. * @data: data to tx to the server
  129. * @data_size: size of data in bytes
  130. * @rdata: place to put return data from server
  131. * @rdata_size: value-result (amount of space given/amount of space used)
  132. *
  133. * rdata_size is undefined on failure.
  134. *
  135. * Memory used to communicate with userspace is zero'ed
  136. * before populating to ensure that no unwanted bits leak
  137. * from kernel space to user-space. All userspace log communications
  138. * between kernel and user space go through this function.
  139. *
  140. * Returns: 0 on success, -EXXX on failure
  141. **/
  142. int dm_consult_userspace(const char *uuid, int request_type,
  143. char *data, size_t data_size,
  144. char *rdata, size_t *rdata_size)
  145. {
  146. int r = 0;
  147. size_t dummy = 0;
  148. int overhead_size =
  149. sizeof(struct dm_ulog_request *) + sizeof(struct cn_msg);
  150. struct dm_ulog_request *tfr = prealloced_ulog_tfr;
  151. struct receiving_pkg pkg;
  152. if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) {
  153. DMINFO("Size of tfr exceeds preallocated size");
  154. return -EINVAL;
  155. }
  156. if (!rdata_size)
  157. rdata_size = &dummy;
  158. resend:
  159. /*
  160. * We serialize the sending of requests so we can
  161. * use the preallocated space.
  162. */
  163. mutex_lock(&dm_ulog_lock);
  164. memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size);
  165. memcpy(tfr->uuid, uuid, DM_UUID_LEN);
  166. tfr->seq = dm_ulog_seq++;
  167. /*
  168. * Must be valid request type (all other bits set to
  169. * zero). This reserves other bits for possible future
  170. * use.
  171. */
  172. tfr->request_type = request_type & DM_ULOG_REQUEST_MASK;
  173. tfr->data_size = data_size;
  174. if (data && data_size)
  175. memcpy(tfr->data, data, data_size);
  176. memset(&pkg, 0, sizeof(pkg));
  177. init_completion(&pkg.complete);
  178. pkg.seq = tfr->seq;
  179. pkg.data_size = rdata_size;
  180. pkg.data = rdata;
  181. spin_lock(&receiving_list_lock);
  182. list_add(&(pkg.list), &receiving_list);
  183. spin_unlock(&receiving_list_lock);
  184. r = dm_ulog_sendto_server(tfr);
  185. mutex_unlock(&dm_ulog_lock);
  186. if (r) {
  187. DMERR("Unable to send log request [%u] to userspace: %d",
  188. request_type, r);
  189. spin_lock(&receiving_list_lock);
  190. list_del_init(&(pkg.list));
  191. spin_unlock(&receiving_list_lock);
  192. goto out;
  193. }
  194. r = wait_for_completion_timeout(&(pkg.complete), DM_ULOG_RETRY_TIMEOUT);
  195. spin_lock(&receiving_list_lock);
  196. list_del_init(&(pkg.list));
  197. spin_unlock(&receiving_list_lock);
  198. if (!r) {
  199. DMWARN("[%s] Request timed out: [%u/%u] - retrying",
  200. (strlen(uuid) > 8) ?
  201. (uuid + (strlen(uuid) - 8)) : (uuid),
  202. request_type, pkg.seq);
  203. goto resend;
  204. }
  205. r = pkg.error;
  206. if (r == -EAGAIN)
  207. goto resend;
  208. out:
  209. return r;
  210. }
  211. int dm_ulog_tfr_init(void)
  212. {
  213. int r;
  214. void *prealloced;
  215. INIT_LIST_HEAD(&receiving_list);
  216. prealloced = kmalloc(DM_ULOG_PREALLOCED_SIZE, GFP_KERNEL);
  217. if (!prealloced)
  218. return -ENOMEM;
  219. prealloced_cn_msg = prealloced;
  220. prealloced_ulog_tfr = prealloced + sizeof(struct cn_msg);
  221. r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback);
  222. if (r) {
  223. cn_del_callback(&ulog_cn_id);
  224. return r;
  225. }
  226. return 0;
  227. }
  228. void dm_ulog_tfr_exit(void)
  229. {
  230. cn_del_callback(&ulog_cn_id);
  231. kfree(prealloced_cn_msg);
  232. }