channel_mgmt.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /*
  2. * Copyright (c) 2009, Microsoft Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along with
  14. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  15. * Place - Suite 330, Boston, MA 02111-1307 USA.
  16. *
  17. * Authors:
  18. * Haiyang Zhang <haiyangz@microsoft.com>
  19. * Hank Janssen <hjanssen@microsoft.com>
  20. */
  21. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  22. #include <linux/kernel.h>
  23. #include <linux/sched.h>
  24. #include <linux/wait.h>
  25. #include <linux/mm.h>
  26. #include <linux/slab.h>
  27. #include <linux/list.h>
  28. #include <linux/module.h>
  29. #include <linux/completion.h>
  30. #include <linux/hyperv.h>
  31. #include "hyperv_vmbus.h"
  32. struct vmbus_channel_message_table_entry {
  33. enum vmbus_channel_message_type message_type;
  34. void (*message_handler)(struct vmbus_channel_message_header *msg);
  35. };
  36. /**
  37. * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
  38. * @icmsghdrp: Pointer to msg header structure
  39. * @icmsg_negotiate: Pointer to negotiate message structure
  40. * @buf: Raw buffer channel data
  41. *
  42. * @icmsghdrp is of type &struct icmsg_hdr.
  43. * @negop is of type &struct icmsg_negotiate.
  44. * Set up and fill in default negotiate response message. This response can
  45. * come from both the vmbus driver and the hv_utils driver. The current api
  46. * will respond properly to both Windows 2008 and Windows 2008-R2 operating
  47. * systems.
  48. *
  49. * Mainly used by Hyper-V drivers.
  50. */
  51. void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
  52. struct icmsg_negotiate *negop, u8 *buf)
  53. {
  54. if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
  55. icmsghdrp->icmsgsize = 0x10;
  56. negop = (struct icmsg_negotiate *)&buf[
  57. sizeof(struct vmbuspipe_hdr) +
  58. sizeof(struct icmsg_hdr)];
  59. if (negop->icframe_vercnt == 2 &&
  60. negop->icversion_data[1].major == 3) {
  61. negop->icversion_data[0].major = 3;
  62. negop->icversion_data[0].minor = 0;
  63. negop->icversion_data[1].major = 3;
  64. negop->icversion_data[1].minor = 0;
  65. } else {
  66. negop->icversion_data[0].major = 1;
  67. negop->icversion_data[0].minor = 0;
  68. negop->icversion_data[1].major = 1;
  69. negop->icversion_data[1].minor = 0;
  70. }
  71. negop->icframe_vercnt = 1;
  72. negop->icmsg_vercnt = 1;
  73. }
  74. }
  75. EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
  76. /*
  77. * alloc_channel - Allocate and initialize a vmbus channel object
  78. */
  79. static struct vmbus_channel *alloc_channel(void)
  80. {
  81. struct vmbus_channel *channel;
  82. channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
  83. if (!channel)
  84. return NULL;
  85. spin_lock_init(&channel->inbound_lock);
  86. channel->controlwq = create_workqueue("hv_vmbus_ctl");
  87. if (!channel->controlwq) {
  88. kfree(channel);
  89. return NULL;
  90. }
  91. return channel;
  92. }
  93. /*
  94. * release_hannel - Release the vmbus channel object itself
  95. */
  96. static void release_channel(struct work_struct *work)
  97. {
  98. struct vmbus_channel *channel = container_of(work,
  99. struct vmbus_channel,
  100. work);
  101. destroy_workqueue(channel->controlwq);
  102. kfree(channel);
  103. }
  104. /*
  105. * free_channel - Release the resources used by the vmbus channel object
  106. */
  107. static void free_channel(struct vmbus_channel *channel)
  108. {
  109. /*
  110. * We have to release the channel's workqueue/thread in the vmbus's
  111. * workqueue/thread context
  112. * ie we can't destroy ourselves.
  113. */
  114. INIT_WORK(&channel->work, release_channel);
  115. queue_work(vmbus_connection.work_queue, &channel->work);
  116. }
  117. /*
  118. * vmbus_process_rescind_offer -
  119. * Rescind the offer by initiating a device removal
  120. */
  121. static void vmbus_process_rescind_offer(struct work_struct *work)
  122. {
  123. struct vmbus_channel *channel = container_of(work,
  124. struct vmbus_channel,
  125. work);
  126. vmbus_device_unregister(channel->device_obj);
  127. }
  128. void vmbus_free_channels(void)
  129. {
  130. struct vmbus_channel *channel;
  131. list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
  132. vmbus_device_unregister(channel->device_obj);
  133. kfree(channel->device_obj);
  134. free_channel(channel);
  135. }
  136. }
  137. /*
  138. * vmbus_process_offer - Process the offer by creating a channel/device
  139. * associated with this offer
  140. */
  141. static void vmbus_process_offer(struct work_struct *work)
  142. {
  143. struct vmbus_channel *newchannel = container_of(work,
  144. struct vmbus_channel,
  145. work);
  146. struct vmbus_channel *channel;
  147. bool fnew = true;
  148. int ret;
  149. unsigned long flags;
  150. /* The next possible work is rescind handling */
  151. INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
  152. /* Make sure this is a new offer */
  153. spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
  154. list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
  155. if (!uuid_le_cmp(channel->offermsg.offer.if_type,
  156. newchannel->offermsg.offer.if_type) &&
  157. !uuid_le_cmp(channel->offermsg.offer.if_instance,
  158. newchannel->offermsg.offer.if_instance)) {
  159. fnew = false;
  160. break;
  161. }
  162. }
  163. if (fnew)
  164. list_add_tail(&newchannel->listentry,
  165. &vmbus_connection.chn_list);
  166. spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
  167. if (!fnew) {
  168. free_channel(newchannel);
  169. return;
  170. }
  171. /*
  172. * Start the process of binding this offer to the driver
  173. * We need to set the DeviceObject field before calling
  174. * vmbus_child_dev_add()
  175. */
  176. newchannel->device_obj = vmbus_device_create(
  177. &newchannel->offermsg.offer.if_type,
  178. &newchannel->offermsg.offer.if_instance,
  179. newchannel);
  180. /*
  181. * Add the new device to the bus. This will kick off device-driver
  182. * binding which eventually invokes the device driver's AddDevice()
  183. * method.
  184. */
  185. ret = vmbus_device_register(newchannel->device_obj);
  186. if (ret != 0) {
  187. pr_err("unable to add child device object (relid %d)\n",
  188. newchannel->offermsg.child_relid);
  189. spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
  190. list_del(&newchannel->listentry);
  191. spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
  192. kfree(newchannel->device_obj);
  193. free_channel(newchannel);
  194. } else {
  195. /*
  196. * This state is used to indicate a successful open
  197. * so that when we do close the channel normally, we
  198. * can cleanup properly
  199. */
  200. newchannel->state = CHANNEL_OPEN_STATE;
  201. }
  202. }
  203. /*
  204. * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
  205. *
  206. */
  207. static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
  208. {
  209. struct vmbus_channel_offer_channel *offer;
  210. struct vmbus_channel *newchannel;
  211. uuid_le *guidtype;
  212. uuid_le *guidinstance;
  213. offer = (struct vmbus_channel_offer_channel *)hdr;
  214. guidtype = &offer->offer.if_type;
  215. guidinstance = &offer->offer.if_instance;
  216. /* Allocate the channel object and save this offer. */
  217. newchannel = alloc_channel();
  218. if (!newchannel) {
  219. pr_err("Unable to allocate channel object\n");
  220. return;
  221. }
  222. memcpy(&newchannel->offermsg, offer,
  223. sizeof(struct vmbus_channel_offer_channel));
  224. newchannel->monitor_grp = (u8)offer->monitorid / 32;
  225. newchannel->monitor_bit = (u8)offer->monitorid % 32;
  226. INIT_WORK(&newchannel->work, vmbus_process_offer);
  227. queue_work(newchannel->controlwq, &newchannel->work);
  228. }
  229. /*
  230. * vmbus_onoffer_rescind - Rescind offer handler.
  231. *
  232. * We queue a work item to process this offer synchronously
  233. */
  234. static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
  235. {
  236. struct vmbus_channel_rescind_offer *rescind;
  237. struct vmbus_channel *channel;
  238. rescind = (struct vmbus_channel_rescind_offer *)hdr;
  239. channel = relid2channel(rescind->child_relid);
  240. if (channel == NULL)
  241. /* Just return here, no channel found */
  242. return;
  243. /* work is initialized for vmbus_process_rescind_offer() from
  244. * vmbus_process_offer() where the channel got created */
  245. queue_work(channel->controlwq, &channel->work);
  246. }
  247. /*
  248. * vmbus_onoffers_delivered -
  249. * This is invoked when all offers have been delivered.
  250. *
  251. * Nothing to do here.
  252. */
  253. static void vmbus_onoffers_delivered(
  254. struct vmbus_channel_message_header *hdr)
  255. {
  256. }
  257. /*
  258. * vmbus_onopen_result - Open result handler.
  259. *
  260. * This is invoked when we received a response to our channel open request.
  261. * Find the matching request, copy the response and signal the requesting
  262. * thread.
  263. */
  264. static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
  265. {
  266. struct vmbus_channel_open_result *result;
  267. struct vmbus_channel_msginfo *msginfo;
  268. struct vmbus_channel_message_header *requestheader;
  269. struct vmbus_channel_open_channel *openmsg;
  270. unsigned long flags;
  271. result = (struct vmbus_channel_open_result *)hdr;
  272. /*
  273. * Find the open msg, copy the result and signal/unblock the wait event
  274. */
  275. spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
  276. list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
  277. msglistentry) {
  278. requestheader =
  279. (struct vmbus_channel_message_header *)msginfo->msg;
  280. if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
  281. openmsg =
  282. (struct vmbus_channel_open_channel *)msginfo->msg;
  283. if (openmsg->child_relid == result->child_relid &&
  284. openmsg->openid == result->openid) {
  285. memcpy(&msginfo->response.open_result,
  286. result,
  287. sizeof(
  288. struct vmbus_channel_open_result));
  289. complete(&msginfo->waitevent);
  290. break;
  291. }
  292. }
  293. }
  294. spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
  295. }
  296. /*
  297. * vmbus_ongpadl_created - GPADL created handler.
  298. *
  299. * This is invoked when we received a response to our gpadl create request.
  300. * Find the matching request, copy the response and signal the requesting
  301. * thread.
  302. */
  303. static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
  304. {
  305. struct vmbus_channel_gpadl_created *gpadlcreated;
  306. struct vmbus_channel_msginfo *msginfo;
  307. struct vmbus_channel_message_header *requestheader;
  308. struct vmbus_channel_gpadl_header *gpadlheader;
  309. unsigned long flags;
  310. gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
  311. /*
  312. * Find the establish msg, copy the result and signal/unblock the wait
  313. * event
  314. */
  315. spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
  316. list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
  317. msglistentry) {
  318. requestheader =
  319. (struct vmbus_channel_message_header *)msginfo->msg;
  320. if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
  321. gpadlheader =
  322. (struct vmbus_channel_gpadl_header *)requestheader;
  323. if ((gpadlcreated->child_relid ==
  324. gpadlheader->child_relid) &&
  325. (gpadlcreated->gpadl == gpadlheader->gpadl)) {
  326. memcpy(&msginfo->response.gpadl_created,
  327. gpadlcreated,
  328. sizeof(
  329. struct vmbus_channel_gpadl_created));
  330. complete(&msginfo->waitevent);
  331. break;
  332. }
  333. }
  334. }
  335. spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
  336. }
  337. /*
  338. * vmbus_ongpadl_torndown - GPADL torndown handler.
  339. *
  340. * This is invoked when we received a response to our gpadl teardown request.
  341. * Find the matching request, copy the response and signal the requesting
  342. * thread.
  343. */
  344. static void vmbus_ongpadl_torndown(
  345. struct vmbus_channel_message_header *hdr)
  346. {
  347. struct vmbus_channel_gpadl_torndown *gpadl_torndown;
  348. struct vmbus_channel_msginfo *msginfo;
  349. struct vmbus_channel_message_header *requestheader;
  350. struct vmbus_channel_gpadl_teardown *gpadl_teardown;
  351. unsigned long flags;
  352. gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
  353. /*
  354. * Find the open msg, copy the result and signal/unblock the wait event
  355. */
  356. spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
  357. list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
  358. msglistentry) {
  359. requestheader =
  360. (struct vmbus_channel_message_header *)msginfo->msg;
  361. if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
  362. gpadl_teardown =
  363. (struct vmbus_channel_gpadl_teardown *)requestheader;
  364. if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
  365. memcpy(&msginfo->response.gpadl_torndown,
  366. gpadl_torndown,
  367. sizeof(
  368. struct vmbus_channel_gpadl_torndown));
  369. complete(&msginfo->waitevent);
  370. break;
  371. }
  372. }
  373. }
  374. spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
  375. }
  376. /*
  377. * vmbus_onversion_response - Version response handler
  378. *
  379. * This is invoked when we received a response to our initiate contact request.
  380. * Find the matching request, copy the response and signal the requesting
  381. * thread.
  382. */
  383. static void vmbus_onversion_response(
  384. struct vmbus_channel_message_header *hdr)
  385. {
  386. struct vmbus_channel_msginfo *msginfo;
  387. struct vmbus_channel_message_header *requestheader;
  388. struct vmbus_channel_initiate_contact *initiate;
  389. struct vmbus_channel_version_response *version_response;
  390. unsigned long flags;
  391. version_response = (struct vmbus_channel_version_response *)hdr;
  392. spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
  393. list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
  394. msglistentry) {
  395. requestheader =
  396. (struct vmbus_channel_message_header *)msginfo->msg;
  397. if (requestheader->msgtype ==
  398. CHANNELMSG_INITIATE_CONTACT) {
  399. initiate =
  400. (struct vmbus_channel_initiate_contact *)requestheader;
  401. memcpy(&msginfo->response.version_response,
  402. version_response,
  403. sizeof(struct vmbus_channel_version_response));
  404. complete(&msginfo->waitevent);
  405. }
  406. }
  407. spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
  408. }
  409. /* Channel message dispatch table */
  410. static struct vmbus_channel_message_table_entry
  411. channel_message_table[CHANNELMSG_COUNT] = {
  412. {CHANNELMSG_INVALID, NULL},
  413. {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer},
  414. {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind},
  415. {CHANNELMSG_REQUESTOFFERS, NULL},
  416. {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered},
  417. {CHANNELMSG_OPENCHANNEL, NULL},
  418. {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
  419. {CHANNELMSG_CLOSECHANNEL, NULL},
  420. {CHANNELMSG_GPADL_HEADER, NULL},
  421. {CHANNELMSG_GPADL_BODY, NULL},
  422. {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created},
  423. {CHANNELMSG_GPADL_TEARDOWN, NULL},
  424. {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown},
  425. {CHANNELMSG_RELID_RELEASED, NULL},
  426. {CHANNELMSG_INITIATE_CONTACT, NULL},
  427. {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response},
  428. {CHANNELMSG_UNLOAD, NULL},
  429. };
  430. /*
  431. * vmbus_onmessage - Handler for channel protocol messages.
  432. *
  433. * This is invoked in the vmbus worker thread context.
  434. */
  435. void vmbus_onmessage(void *context)
  436. {
  437. struct hv_message *msg = context;
  438. struct vmbus_channel_message_header *hdr;
  439. int size;
  440. hdr = (struct vmbus_channel_message_header *)msg->u.payload;
  441. size = msg->header.payload_size;
  442. if (hdr->msgtype >= CHANNELMSG_COUNT) {
  443. pr_err("Received invalid channel message type %d size %d\n",
  444. hdr->msgtype, size);
  445. print_hex_dump_bytes("", DUMP_PREFIX_NONE,
  446. (unsigned char *)msg->u.payload, size);
  447. return;
  448. }
  449. if (channel_message_table[hdr->msgtype].message_handler)
  450. channel_message_table[hdr->msgtype].message_handler(hdr);
  451. else
  452. pr_err("Unhandled channel message type %d\n", hdr->msgtype);
  453. }
  454. /*
  455. * vmbus_request_offers - Send a request to get all our pending offers.
  456. */
  457. int vmbus_request_offers(void)
  458. {
  459. struct vmbus_channel_message_header *msg;
  460. struct vmbus_channel_msginfo *msginfo;
  461. int ret;
  462. msginfo = kmalloc(sizeof(*msginfo) +
  463. sizeof(struct vmbus_channel_message_header),
  464. GFP_KERNEL);
  465. if (!msginfo)
  466. return -ENOMEM;
  467. msg = (struct vmbus_channel_message_header *)msginfo->msg;
  468. msg->msgtype = CHANNELMSG_REQUESTOFFERS;
  469. ret = vmbus_post_msg(msg,
  470. sizeof(struct vmbus_channel_message_header));
  471. if (ret != 0) {
  472. pr_err("Unable to request offers - %d\n", ret);
  473. goto cleanup;
  474. }
  475. cleanup:
  476. kfree(msginfo);
  477. return ret;
  478. }
  479. /* eof */