dm-log-userspace-transfer.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 %zu)", 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(struct cn_msg *msg, struct netlink_skb_parms *nsp)
  111. {
  112. struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
  113. if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN))
  114. return;
  115. spin_lock(&receiving_list_lock);
  116. if (msg->len == 0)
  117. fill_pkg(msg, NULL);
  118. else if (msg->len < sizeof(*tfr))
  119. DMERR("Incomplete message received (expected %u, got %u): [%u]",
  120. (unsigned)sizeof(*tfr), msg->len, msg->seq);
  121. else
  122. fill_pkg(NULL, tfr);
  123. spin_unlock(&receiving_list_lock);
  124. }
  125. /**
  126. * dm_consult_userspace
  127. * @uuid: log's universal unique identifier (must be DM_UUID_LEN in size)
  128. * @luid: log's local unique identifier
  129. * @request_type: found in include/linux/dm-log-userspace.h
  130. * @data: data to tx to the server
  131. * @data_size: size of data in bytes
  132. * @rdata: place to put return data from server
  133. * @rdata_size: value-result (amount of space given/amount of space used)
  134. *
  135. * rdata_size is undefined on failure.
  136. *
  137. * Memory used to communicate with userspace is zero'ed
  138. * before populating to ensure that no unwanted bits leak
  139. * from kernel space to user-space. All userspace log communications
  140. * between kernel and user space go through this function.
  141. *
  142. * Returns: 0 on success, -EXXX on failure
  143. **/
  144. int dm_consult_userspace(const char *uuid, uint64_t luid, int request_type,
  145. char *data, size_t data_size,
  146. char *rdata, size_t *rdata_size)
  147. {
  148. int r = 0;
  149. size_t dummy = 0;
  150. int overhead_size =
  151. sizeof(struct dm_ulog_request *) + sizeof(struct cn_msg);
  152. struct dm_ulog_request *tfr = prealloced_ulog_tfr;
  153. struct receiving_pkg pkg;
  154. if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) {
  155. DMINFO("Size of tfr exceeds preallocated size");
  156. return -EINVAL;
  157. }
  158. if (!rdata_size)
  159. rdata_size = &dummy;
  160. resend:
  161. /*
  162. * We serialize the sending of requests so we can
  163. * use the preallocated space.
  164. */
  165. mutex_lock(&dm_ulog_lock);
  166. memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size);
  167. memcpy(tfr->uuid, uuid, DM_UUID_LEN);
  168. tfr->luid = luid;
  169. tfr->seq = dm_ulog_seq++;
  170. /*
  171. * Must be valid request type (all other bits set to
  172. * zero). This reserves other bits for possible future
  173. * use.
  174. */
  175. tfr->request_type = request_type & DM_ULOG_REQUEST_MASK;
  176. tfr->data_size = data_size;
  177. if (data && data_size)
  178. memcpy(tfr->data, data, data_size);
  179. memset(&pkg, 0, sizeof(pkg));
  180. init_completion(&pkg.complete);
  181. pkg.seq = tfr->seq;
  182. pkg.data_size = rdata_size;
  183. pkg.data = rdata;
  184. spin_lock(&receiving_list_lock);
  185. list_add(&(pkg.list), &receiving_list);
  186. spin_unlock(&receiving_list_lock);
  187. r = dm_ulog_sendto_server(tfr);
  188. mutex_unlock(&dm_ulog_lock);
  189. if (r) {
  190. DMERR("Unable to send log request [%u] to userspace: %d",
  191. request_type, r);
  192. spin_lock(&receiving_list_lock);
  193. list_del_init(&(pkg.list));
  194. spin_unlock(&receiving_list_lock);
  195. goto out;
  196. }
  197. r = wait_for_completion_timeout(&(pkg.complete), DM_ULOG_RETRY_TIMEOUT);
  198. spin_lock(&receiving_list_lock);
  199. list_del_init(&(pkg.list));
  200. spin_unlock(&receiving_list_lock);
  201. if (!r) {
  202. DMWARN("[%s] Request timed out: [%u/%u] - retrying",
  203. (strlen(uuid) > 8) ?
  204. (uuid + (strlen(uuid) - 8)) : (uuid),
  205. request_type, pkg.seq);
  206. goto resend;
  207. }
  208. r = pkg.error;
  209. if (r == -EAGAIN)
  210. goto resend;
  211. out:
  212. return r;
  213. }
  214. int dm_ulog_tfr_init(void)
  215. {
  216. int r;
  217. void *prealloced;
  218. INIT_LIST_HEAD(&receiving_list);
  219. prealloced = kmalloc(DM_ULOG_PREALLOCED_SIZE, GFP_KERNEL);
  220. if (!prealloced)
  221. return -ENOMEM;
  222. prealloced_cn_msg = prealloced;
  223. prealloced_ulog_tfr = prealloced + sizeof(struct cn_msg);
  224. r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback);
  225. if (r) {
  226. cn_del_callback(&ulog_cn_id);
  227. return r;
  228. }
  229. return 0;
  230. }
  231. void dm_ulog_tfr_exit(void)
  232. {
  233. cn_del_callback(&ulog_cn_id);
  234. kfree(prealloced_cn_msg);
  235. }