shim_msgget.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. /* Copyright (C) 2014 OSCAR lab, Stony Brook University
  4. This file is part of Graphene Library OS.
  5. Graphene Library OS is free software: you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. Graphene Library OS is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * shim_msgget.c
  17. *
  18. * Implementation of system call "msgget", "msgsnd", "msgrcv" and "msgctl".
  19. */
  20. #include <shim_internal.h>
  21. #include <shim_handle.h>
  22. #include <shim_utils.h>
  23. #include <shim_ipc.h>
  24. #include <shim_sysv.h>
  25. #include <shim_unistd.h>
  26. #include <shim_profile.h>
  27. #include <pal.h>
  28. #include <pal_error.h>
  29. #include <linux_list.h>
  30. #include <errno.h>
  31. #define MSGQ_HASH_LEN 8
  32. #define MSGQ_HASH_NUM (1 << MSGQ_HASH_LEN)
  33. #define MSGQ_HASH_MASK (MSGQ_HASH_NUM - 1)
  34. #define MSGQ_HASH(idx) ((idx) & MSGQ_HASH_MASK)
  35. static LIST_HEAD(msgq_list);
  36. static struct hlist_head msgq_key_hlist [MSGQ_HASH_NUM];
  37. static struct hlist_head msgq_qid_hlist [MSGQ_HASH_NUM];
  38. static LOCKTYPE msgq_list_lock;
  39. static int __load_msg_persist (struct shim_msg_handle * msgq, bool readmsg);
  40. static int __store_msg_persist(struct shim_msg_handle * msgq);
  41. DEFINE_PROFILE_CATAGORY(sysv_msg, );
  42. #define MSG_TO_HANDLE(msghdl) \
  43. container_of((msghdl), struct shim_handle, info.msg)
  44. static int __add_msg_handle (unsigned long key, IDTYPE msqid, bool owned,
  45. struct shim_msg_handle ** msghdl)
  46. {
  47. struct hlist_head * key_head = (key != IPC_PRIVATE) ?
  48. &msgq_key_hlist[MSGQ_HASH(key)] :
  49. NULL;
  50. struct hlist_head * qid_head = msqid ?
  51. &msgq_qid_hlist[MSGQ_HASH(msqid)] :
  52. NULL;
  53. struct shim_msg_handle * tmp;
  54. struct hlist_node * pos;
  55. if (key_head)
  56. hlist_for_each_entry(tmp, pos, key_head, key_hlist)
  57. if (tmp->msqkey == key) {
  58. if (tmp->msqid == msqid) {
  59. if (msghdl)
  60. *msghdl = tmp;
  61. return 0;
  62. }
  63. return -EEXIST;
  64. }
  65. if (qid_head)
  66. hlist_for_each_entry(tmp, pos, qid_head, qid_hlist)
  67. if (tmp->msqid == msqid) {
  68. if (key)
  69. tmp->msqkey = key;
  70. if (msghdl)
  71. *msghdl = tmp;
  72. return 0;
  73. }
  74. struct shim_handle * hdl = get_new_handle();
  75. if (!hdl)
  76. return -ENOMEM;
  77. struct shim_msg_handle * msgq = &hdl->info.msg;
  78. hdl->type = TYPE_MSG;
  79. msgq->msqkey = key;
  80. msgq->msqid = msqid;
  81. msgq->owned = owned;
  82. msgq->deleted = false;
  83. msgq->currentsize = 0;
  84. msgq->event = DkSynchronizationEventCreate(0);
  85. msgq->queue = malloc(MSG_QOBJ_SIZE * DEFAULT_MSG_QUEUE_SIZE);
  86. msgq->queuesize = DEFAULT_MSG_QUEUE_SIZE;
  87. msgq->queueused = 0;
  88. msgq->freed = NULL;
  89. msgq->ntypes = 0;
  90. msgq->maxtypes = INIT_MSG_TYPE_SIZE;
  91. msgq->types = malloc(sizeof(struct msg_type) * INIT_MSG_TYPE_SIZE);
  92. INIT_LIST_HEAD(&msgq->list);
  93. get_handle(hdl);
  94. list_add_tail(&msgq->list, &msgq_list);
  95. INIT_HLIST_NODE(&msgq->key_hlist);
  96. if (key_head) {
  97. get_handle(hdl);
  98. hlist_add_head(&msgq->key_hlist, key_head);
  99. }
  100. INIT_HLIST_NODE(&msgq->qid_hlist);
  101. if (qid_head) {
  102. get_handle(hdl);
  103. hlist_add_head(&msgq->qid_hlist, qid_head);
  104. }
  105. if (!msghdl) {
  106. put_handle(hdl);
  107. return 0;
  108. }
  109. *msghdl = msgq;
  110. return 0;
  111. }
  112. int add_msg_handle (unsigned long key, IDTYPE id, bool owned)
  113. {
  114. lock(msgq_list_lock);
  115. int ret = __add_msg_handle(key, id, owned, NULL);
  116. unlock(msgq_list_lock);
  117. return ret;
  118. }
  119. struct shim_msg_handle * get_msg_handle_by_key (unsigned long key)
  120. {
  121. struct hlist_head * key_head = &msgq_key_hlist[MSGQ_HASH(key)];
  122. struct shim_msg_handle * tmp, * found = NULL;
  123. struct hlist_node * pos;
  124. lock(msgq_list_lock);
  125. hlist_for_each_entry(tmp, pos, key_head, key_hlist)
  126. if (tmp->msqkey == key) {
  127. found = tmp;
  128. break;
  129. }
  130. if (found)
  131. get_handle(MSG_TO_HANDLE(found));
  132. unlock(msgq_list_lock);
  133. return found;
  134. }
  135. struct shim_msg_handle * get_msg_handle_by_id (IDTYPE msqid)
  136. {
  137. struct hlist_head * qid_head = &msgq_qid_hlist[MSGQ_HASH(msqid)];
  138. struct shim_msg_handle * tmp, * found = NULL;
  139. struct hlist_node * pos;
  140. lock(msgq_list_lock);
  141. hlist_for_each_entry(tmp, pos, qid_head, qid_hlist)
  142. if (tmp->msqid == msqid) {
  143. found = tmp;
  144. break;
  145. }
  146. if (found)
  147. get_handle(MSG_TO_HANDLE(found));
  148. unlock(msgq_list_lock);
  149. return found;
  150. }
  151. void put_msg_handle (struct shim_msg_handle * msgq)
  152. {
  153. put_handle(MSG_TO_HANDLE(msgq));
  154. }
  155. static void * __get_msg_qobj (struct shim_msg_handle * msgq)
  156. {
  157. struct msg_qobj * obj = NULL;
  158. if (msgq->freed) {
  159. obj = msgq->freed;
  160. msgq->freed = obj->next;
  161. obj->next = NULL;
  162. return obj;
  163. }
  164. if (msgq->queueused < msgq->queuesize) {
  165. obj = &msgq->queue[msgq->queueused];
  166. msgq->queueused++;
  167. obj->next = NULL;
  168. return obj;
  169. }
  170. return NULL;
  171. }
  172. static void __free_msg_qobj (struct shim_msg_handle * msgq, void * obj)
  173. {
  174. ((struct msg_qobj *) obj)->next = msgq->freed;
  175. msgq->freed = obj;
  176. }
  177. static void __free_msg_linked_qobjs (struct shim_msg_handle * msgq, void * obj)
  178. {
  179. struct msg_qobj * qobj = obj;
  180. while (qobj) {
  181. struct msg_qobj * next = qobj->next;
  182. __free_msg_qobj(msgq, qobj);
  183. qobj = next;
  184. }
  185. }
  186. static int __del_msg_handle (struct shim_msg_handle * msgq)
  187. {
  188. if (msgq->deleted)
  189. return -EIDRM;
  190. msgq->deleted = true;
  191. free(msgq->queue);
  192. msgq->queuesize = 0;
  193. msgq->queueused = 0;
  194. free(msgq->types);
  195. msgq->ntypes = 0;
  196. struct shim_handle * hdl = MSG_TO_HANDLE(msgq);
  197. lock(msgq_list_lock);
  198. list_del_init(&msgq->list);
  199. put_handle(hdl);
  200. if (!hlist_unhashed(&msgq->key_hlist)) {
  201. hlist_del_init(&msgq->key_hlist);
  202. put_handle(hdl);
  203. }
  204. if (!hlist_unhashed(&msgq->qid_hlist)) {
  205. hlist_del_init(&msgq->qid_hlist);
  206. put_handle(hdl);
  207. }
  208. unlock(msgq_list_lock);
  209. return 0;
  210. }
  211. int del_msg_handle (struct shim_msg_handle * msgq)
  212. {
  213. struct shim_handle * hdl = MSG_TO_HANDLE(msgq);
  214. lock(hdl->lock);
  215. int ret = __del_msg_handle(msgq);
  216. unlock(hdl->lock);
  217. return ret;
  218. }
  219. static void __try_create_lock (void)
  220. {
  221. create_lock_runtime(&msgq_list_lock);
  222. }
  223. int shim_do_msgget (key_t key, int msgflg)
  224. {
  225. INC_PROFILE_OCCURENCE(syscall_use_ipc);
  226. IDTYPE msgid = 0;
  227. int ret;
  228. __try_create_lock();
  229. if (key != IPC_PRIVATE) {
  230. struct shim_msg_handle * msgq = get_msg_handle_by_key(key);
  231. if (msgq) {
  232. msgid = msgq->msqid;
  233. put_msg_handle(msgq);
  234. return (msgflg & IPC_EXCL) ? -EEXIST : msgid;
  235. }
  236. }
  237. struct sysv_key k;
  238. k.key = key;
  239. k.type = SYSV_MSGQ;
  240. if (msgflg & IPC_CREAT) {
  241. do {
  242. msgid = allocate_sysv(0, 0);
  243. if (!msgid)
  244. ipc_sysv_lease_send(NULL);
  245. } while (!msgid);
  246. if (key != IPC_PRIVATE) {
  247. if ((ret = ipc_sysv_tellkey_send(NULL, 0, &k, msgid, 0)) < 0) {
  248. release_sysv(msgid);
  249. return ret;
  250. }
  251. }
  252. add_msg_handle(key, msgid, true);
  253. } else {
  254. /* query the manager with the key to find the
  255. corresponding sysvkey */
  256. if ((ret = ipc_sysv_findkey_send(&k)) < 0)
  257. return ret;
  258. msgid = ret;
  259. if ((ret = ipc_sysv_query_send(msgid)) < 0)
  260. return ret;
  261. add_msg_handle(key, msgid, false);
  262. }
  263. return msgid;
  264. }
  265. static int connect_msg_handle (int msqid, struct shim_msg_handle ** msgqp)
  266. {
  267. struct shim_msg_handle * msgq = get_msg_handle_by_id(msqid);
  268. int ret;
  269. if (!msgq) {
  270. if ((ret = ipc_sysv_query_send(msqid)) < 0)
  271. return ret;
  272. if (!msgq) {
  273. lock(msgq_list_lock);
  274. ret = __add_msg_handle(IPC_PRIVATE, msqid, false, &msgq);
  275. unlock(msgq_list_lock);
  276. if (ret < 0)
  277. return ret;
  278. }
  279. }
  280. if (msgq->deleted)
  281. return -EIDRM;
  282. *msgqp = msgq;
  283. return 0;
  284. }
  285. int recover_msg_ownership (struct shim_msg_handle * msgq)
  286. {
  287. struct shim_handle * hdl = MSG_TO_HANDLE(msgq);
  288. lock(hdl->lock);
  289. assert(!msgq->owned);
  290. int ret = __load_msg_persist(msgq, true);
  291. if (ret < 0) {
  292. ret = (ret == -ENOENT) ? -EIDRM : ret;
  293. goto out;
  294. }
  295. msgq->owned = true;
  296. DkEventSet(msgq->event);
  297. out:
  298. unlock(hdl->lock);
  299. return 0;
  300. }
  301. int shim_do_msgsnd (int msqid, const void * msgp, size_t msgsz, int msgflg)
  302. {
  303. INC_PROFILE_OCCURENCE(syscall_use_ipc);
  304. int ret;
  305. if ((msgsz < 0) || (msgsz > MSGMAX))
  306. return -EINVAL;
  307. if (!msgp)
  308. return -EFAULT;
  309. struct __kernel_msgbuf * msgbuf = (struct __kernel_msgbuf *) msgp;
  310. if (msgbuf->mtype < 0)
  311. return -EINVAL;
  312. struct shim_msg_handle * msgq;
  313. __try_create_lock();
  314. if ((ret = connect_msg_handle(msqid, &msgq)) < 0)
  315. return ret;
  316. ret = add_sysv_msg(msgq, msgbuf->mtype, msgsz, msgbuf->mtext, NULL);
  317. put_msg_handle(msgq);
  318. return ret;
  319. }
  320. int shim_do_msgrcv (int msqid, void * msgp, size_t msgsz, long msgtype,
  321. int msgflg)
  322. {
  323. INC_PROFILE_OCCURENCE(syscall_use_ipc);
  324. int ret;
  325. if (msgsz < 0)
  326. return -EINVAL;
  327. if (!msgp)
  328. return -EFAULT;
  329. struct __kernel_msgbuf * msgbuf = (struct __kernel_msgbuf *) msgp;
  330. struct shim_msg_handle * msgq;
  331. __try_create_lock();
  332. if ((ret = connect_msg_handle(msqid, &msgq)) < 0)
  333. return ret;
  334. ret = get_sysv_msg(msgq, msgtype, msgsz, msgbuf->mtext, msgflg, NULL);
  335. put_msg_handle(msgq);
  336. return ret;
  337. }
  338. int shim_do_msgctl (int msqid, int cmd, struct msqid_ds * buf)
  339. {
  340. INC_PROFILE_OCCURENCE(syscall_use_ipc);
  341. struct shim_msg_handle * msgq;
  342. int ret;
  343. __try_create_lock();
  344. if ((ret = connect_msg_handle(msqid, &msgq)) < 0)
  345. return ret;
  346. switch (cmd) {
  347. case IPC_RMID:
  348. if (!msgq->owned) {
  349. ret = ipc_sysv_delres_send(NULL, 0, msgq->msqid, SYSV_MSGQ);
  350. if (ret < 0)
  351. break;
  352. }
  353. __del_msg_handle(msgq);
  354. break;
  355. default:
  356. ret = -ENOSYS;
  357. break;
  358. }
  359. put_msg_handle(msgq);
  360. return ret;
  361. }
  362. static struct msg_type *
  363. __add_msg_type (int type, struct msg_type ** ptypes, int * pntypes,
  364. int * pmaxtypes)
  365. {
  366. struct msg_type * types = *ptypes;
  367. int ntypes = *pntypes;
  368. int maxtypes = *pmaxtypes;
  369. struct msg_type * mtype;
  370. for (mtype = types ;
  371. mtype < &types[ntypes] && mtype->type <= type ; mtype++)
  372. if (mtype->type == type)
  373. return mtype;
  374. int off = mtype - types;
  375. struct msg_type * new_types = types;
  376. if (ntypes == maxtypes)
  377. new_types = malloc(sizeof(struct msg_type) * maxtypes * 2);
  378. if (mtype < &types[ntypes])
  379. memmove(new_types + off + 1, mtype,
  380. sizeof(struct msg_type) * (ntypes - off));
  381. if (new_types != types) {
  382. memcpy(new_types, types, sizeof(struct msg_type) * off);
  383. free(types);
  384. mtype = new_types + off;
  385. *ptypes = new_types;
  386. *pmaxtypes = maxtypes * 2;
  387. }
  388. mtype->type = type;
  389. mtype->msgs = NULL;
  390. mtype->msg_tail = NULL;
  391. mtype->reqs = NULL;
  392. mtype->req_tail = NULL;
  393. (*pntypes)++;
  394. return mtype;
  395. }
  396. static int __load_msg_qobjs (struct shim_msg_handle * msgq,
  397. struct msg_type * mtype,
  398. struct msg_item * msg, void * data)
  399. {
  400. int copysize = MSG_ITEM_DATA_SIZE(msg->size);
  401. memcpy(data, msg->data, copysize);
  402. mtype->msgs = msg->next;
  403. __free_msg_qobj(msgq, msg);
  404. while (copysize < msg->size) {
  405. assert(mtype->msgs);
  406. struct msg_ext_item * ext = (struct msg_ext_item *) mtype->msgs;
  407. int sz = MSG_EXT_ITEM_DATA_SIZE(msg->size - copysize);
  408. memcpy(data + copysize, ext->data, sz);
  409. copysize += sz;
  410. mtype->msgs = ext->next;
  411. __free_msg_qobj(msgq, ext);
  412. }
  413. if (!mtype->msgs)
  414. mtype->msg_tail = NULL;
  415. msgq->nmsgs--;
  416. msgq->currentsize -= msg->size;
  417. return 0;
  418. }
  419. static int __store_msg_qobjs (struct shim_msg_handle * msgq,
  420. struct msg_type * mtype,
  421. int size, const void * data)
  422. {
  423. struct msg_item * newmsg = __get_msg_qobj(msgq);
  424. if (!newmsg)
  425. return -EAGAIN;
  426. struct msg_item * old_tail = mtype->msg_tail;
  427. newmsg->next = NULL;
  428. newmsg->size = size;
  429. int copysize = MSG_ITEM_DATA_SIZE(size);
  430. memcpy(newmsg->data, data, copysize);
  431. if (mtype->msg_tail) {
  432. mtype->msg_tail->next = newmsg;
  433. mtype->msg_tail = newmsg;
  434. } else {
  435. assert(!mtype->msgs);
  436. mtype->msgs = mtype->msg_tail = newmsg;
  437. }
  438. while (copysize < size) {
  439. struct msg_ext_item * ext = __get_msg_qobj(msgq);
  440. if (!ext)
  441. goto eagain;
  442. int sz = MSG_EXT_ITEM_DATA_SIZE(size - copysize);
  443. memcpy(ext->data, data + copysize, sz);
  444. ext->next = NULL;
  445. mtype->msg_tail->next = ext;
  446. mtype->msg_tail = (struct msg_item *) ext;
  447. copysize += sz;
  448. }
  449. msgq->nmsgs++;
  450. msgq->currentsize += size;
  451. return 0;
  452. eagain:
  453. __free_msg_linked_qobjs(msgq, newmsg);
  454. if (mtype->msgs == newmsg)
  455. mtype->msgs = NULL;
  456. mtype->msg_tail = old_tail;
  457. return -EAGAIN;
  458. }
  459. static int msg_balance_migrate (struct shim_handle * hdl,
  460. struct sysv_client * client);
  461. static struct sysv_balance_policy msg_policy = {
  462. .score_decay = MSG_SCORE_DECAY,
  463. .score_max = MSG_SCORE_MAX,
  464. .balance_threshold = MSG_BALANCE_THRESHOLD,
  465. .migrate = &msg_balance_migrate,
  466. };
  467. DEFINE_PROFILE_INTERVAL(add_sysv_msg, sysv_msg);
  468. int add_sysv_msg (struct shim_msg_handle * msgq,
  469. long type, int size, const void * data,
  470. struct sysv_client * src)
  471. {
  472. BEGIN_PROFILE_INTERVAL();
  473. struct shim_handle * hdl = MSG_TO_HANDLE(msgq);
  474. int ret = 0;
  475. lock(hdl->lock);
  476. if (msgq->deleted) {
  477. ret = -EIDRM;
  478. goto out_locked;
  479. }
  480. if (!msgq->owned) {
  481. unlock(hdl->lock);
  482. ret = ipc_sysv_msgsnd_send(src->port, src->vmid, msgq->msqid,
  483. type, data, size, src->seq);
  484. goto out;
  485. }
  486. struct msg_type * mtype = __add_msg_type(type, &msgq->types,
  487. &msgq->ntypes,
  488. &msgq->maxtypes);
  489. if ((ret = __store_msg_qobjs(msgq, mtype, size, data)) < 0)
  490. goto out_locked;
  491. if (msgq->owned)
  492. __balance_sysv_score(&msg_policy, hdl, msgq->scores, MAX_SYSV_CLIENTS,
  493. src, MSG_SND_SCORE);
  494. DkEventSet(msgq->event);
  495. ret = 0;
  496. out_locked:
  497. unlock(hdl->lock);
  498. out:
  499. SAVE_PROFILE_INTERVAL(add_sysv_msg);
  500. return ret;
  501. }
  502. static struct msg_type *
  503. __find_msg_type (int type, struct msg_type * types, int ntypes)
  504. {
  505. for (struct msg_type * mtype = types ;
  506. mtype < &types[ntypes] && mtype->type <= type; mtype++)
  507. if (mtype->type == type)
  508. return mtype;
  509. return NULL;
  510. }
  511. static int __add_msg_req (struct shim_msg_handle * msgq,
  512. struct msg_type * mtype,
  513. int size, int flags, struct sysv_client * src)
  514. {
  515. if (msgq->deleted)
  516. return -EIDRM;
  517. struct msg_req * req = __get_msg_qobj(msgq);
  518. if (!req)
  519. return -ENOMEM;
  520. get_ipc_port(src->port);
  521. req->next = NULL;
  522. req->size = size;
  523. req->flags = flags;
  524. req->dest = *src;
  525. if (mtype->req_tail) {
  526. mtype->req_tail->next = req;
  527. mtype->req_tail = req;
  528. } else {
  529. assert(!mtype->reqs);
  530. mtype->reqs = mtype->req_tail = req;
  531. }
  532. return 0;
  533. }
  534. DEFINE_PROFILE_INTERVAL(get_sysv_msg, sysv_msg);
  535. int get_sysv_msg (struct shim_msg_handle * msgq,
  536. long type, int size, void * data, int flags,
  537. struct sysv_client * src)
  538. {
  539. BEGIN_PROFILE_INTERVAL();
  540. int ret = 0;
  541. struct shim_handle * hdl = MSG_TO_HANDLE(msgq);
  542. struct msg_item * msg = NULL;
  543. struct msg_type * alltypes = NULL, * mtype = NULL;
  544. lock(hdl->lock);
  545. if (msgq->deleted) {
  546. ret = -EIDRM;
  547. goto out_locked;
  548. }
  549. if (msgq->owned) {
  550. __balance_sysv_score(&msg_policy, hdl, msgq->scores, MAX_SYSV_CLIENTS,
  551. src, MSG_RCV_SCORE);
  552. if (!msgq->owned && src) {
  553. struct shim_ipc_info * owner = msgq->owner;
  554. assert(owner);
  555. ret = ipc_sysv_movres_send(src, owner->vmid,
  556. qstrgetstr(&owner->uri), msgq->lease,
  557. msgq->msqid, SYSV_MSGQ);
  558. goto out_locked;
  559. }
  560. }
  561. if (!msgq->owned) {
  562. IDTYPE msqid = msgq->msqid;
  563. if (src) {
  564. struct shim_ipc_info * owner = msgq->owner;
  565. ret = owner ?
  566. ipc_sysv_movres_send(src, owner->vmid,
  567. qstrgetstr(&owner->uri), msgq->lease,
  568. msgq->msqid, SYSV_MSGQ) :
  569. -ECONNREFUSED;
  570. goto out_locked;
  571. }
  572. unowned:
  573. unlock(hdl->lock);
  574. ret = ipc_sysv_msgrcv_send(msqid, type, flags, data, size);
  575. if (ret != -EAGAIN &&
  576. ret != -ECONNREFUSED)
  577. goto out;
  578. lock(hdl->lock);
  579. if (!msgq->owned)
  580. goto out_locked;
  581. }
  582. while (1) {
  583. if (alltypes != msgq->types || !mtype || mtype->type != type) {
  584. alltypes = msgq->types;
  585. mtype = __find_msg_type(type, alltypes, msgq->ntypes);
  586. }
  587. if (mtype && mtype->msgs) {
  588. msg = mtype->msgs;
  589. if (msg->size > size && !(flags & MSG_NOERROR)) {
  590. ret = -E2BIG;
  591. goto out;
  592. }
  593. break;
  594. }
  595. if (flags & IPC_NOWAIT || src)
  596. break;
  597. unlock(hdl->lock);
  598. while (!DkObjectsWaitAny(1, &msgq->event, NO_TIMEOUT));
  599. lock(hdl->lock);
  600. if (!msgq->owned)
  601. goto unowned;
  602. }
  603. if (!msg) {
  604. ret = (!(flags & IPC_NOWAIT) && src) ?
  605. __add_msg_req(msgq, mtype, size, flags, src) : -ENOMSG;
  606. goto out_locked;
  607. }
  608. if ((ret = __load_msg_qobjs(msgq, mtype, msg, data)) < 0)
  609. goto out_locked;;
  610. ret = msg->size;
  611. out_locked:
  612. unlock(hdl->lock);
  613. out:
  614. SAVE_PROFILE_INTERVAL(get_sysv_msg);
  615. return ret;
  616. }
  617. static int __store_msg_persist (struct shim_msg_handle * msgq)
  618. {
  619. int ret = 0;
  620. if (msgq->deleted)
  621. goto out;
  622. debug("store msgq %d to persistent store\n", msgq->msqid);
  623. char fileuri[20];
  624. snprintf(fileuri, 20, "file:msgq.%08x", msgq->msqid);
  625. PAL_HANDLE file = DkStreamOpen(fileuri, PAL_ACCESS_RDWR, 0600,
  626. PAL_CREAT_TRY, 0);
  627. if (!file) {
  628. ret = -PAL_ERRNO;
  629. goto out;
  630. }
  631. int expected_size = sizeof(struct msg_handle_backup) +
  632. sizeof(struct msg_backup) * msgq->nmsgs +
  633. msgq->currentsize;
  634. if (DkStreamSetLength(file, expected_size) != expected_size)
  635. goto err_file;
  636. void * mem = (void *) DkStreamMap(file, NULL,
  637. PAL_PROT_READ|PAL_PROT_WRITE,
  638. 0, ALIGN_UP(expected_size));
  639. if (!mem) {
  640. ret = -EFAULT;
  641. goto err_file;
  642. }
  643. struct msg_handle_backup * mback = mem;
  644. mem += sizeof(struct msg_handle_backup);
  645. mback->perm = msgq->perm;
  646. mback->nmsgs = msgq->nmsgs;
  647. mback->currentsize = msgq->currentsize;
  648. struct msg_type * mtype;
  649. for (mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ;
  650. mtype++) {
  651. while (mtype->msgs) {
  652. struct msg_backup * msg = mem;
  653. mem += sizeof(struct msg_backup) + mtype->msgs->size;
  654. msg->type = mtype->type;
  655. msg->size = mtype->msgs->size;
  656. __load_msg_qobjs(msgq, mtype, mtype->msgs, msg->data);
  657. }
  658. mtype->msgs = mtype->msg_tail = NULL;
  659. }
  660. DkStreamUnmap(mem, ALIGN_UP(expected_size));
  661. if (msgq->owned)
  662. for (mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ;
  663. mtype++) {
  664. struct msg_req * req = mtype->reqs;
  665. mtype->reqs = mtype->req_tail = NULL;
  666. while (req) {
  667. struct sysv_client * c = &req->dest;
  668. struct msg_req * next = req->next;
  669. __response_ipc_message(c->port, c->vmid, -EIDRM, c->seq);
  670. put_ipc_port(c->port);
  671. __free_msg_qobj(msgq, req);
  672. req = next;
  673. }
  674. }
  675. msgq->owned = false;
  676. ret = 0;
  677. goto out;
  678. err_file:
  679. DkStreamDelete(file, 0);
  680. DkObjectClose(file);
  681. out:
  682. // To wake up any receiver waiting on local message which must
  683. // now be requested from new owner.
  684. DkEventSet(msgq->event);
  685. return ret;
  686. }
  687. static int __load_msg_persist (struct shim_msg_handle * msgq, bool readmsg)
  688. {
  689. int ret = 0;
  690. char fileuri[20];
  691. snprintf(fileuri, 20, "file:msgq.%08x", msgq->msqid);
  692. PAL_HANDLE file = DkStreamOpen(fileuri, PAL_ACCESS_RDONLY, 0, 0, 0);
  693. if (!file)
  694. return -EIDRM;
  695. struct msg_handle_backup mback;
  696. int bytes = DkStreamRead(file, 0, sizeof(struct msg_handle_backup),
  697. &mback, NULL, 0);
  698. if (bytes < sizeof(struct msg_handle_backup)) {
  699. ret = bytes ? -EFAULT : -PAL_ERRNO;
  700. goto out;
  701. }
  702. msgq->perm = mback.perm;
  703. if (!readmsg || !mback.nmsgs)
  704. goto done;
  705. int expected_size = sizeof(struct msg_handle_backup) +
  706. sizeof(struct msg_backup) * mback.nmsgs +
  707. mback.currentsize;
  708. void * mem = (void *) DkStreamMap(file, NULL, PAL_PROT_READ, 0,
  709. ALIGN_UP(expected_size));
  710. if (!mem) {
  711. ret = -PAL_ERRNO;
  712. goto out;
  713. }
  714. mem += sizeof(struct msg_handle_backup);
  715. struct msg_type * mtype = NULL;
  716. for (int i = 0 ; i < mback.nmsgs ; i++) {
  717. struct msg_backup * m = mem;
  718. mem += sizeof(struct msg_backup) + m->size;
  719. debug("load msg: type=%d, size=%d\n", m->type, m->size);
  720. if (!mtype || mtype->type != m->type)
  721. mtype = __add_msg_type(m->type, &msgq->types, &msgq->ntypes,
  722. &msgq->maxtypes);
  723. if ((ret = __store_msg_qobjs(msgq, mtype, m->size, m->data)) < 0)
  724. goto out;
  725. };
  726. DkStreamUnmap(mem, ALIGN_UP(expected_size));
  727. done:
  728. DkStreamDelete(file, 0);
  729. ret = 0;
  730. goto out;
  731. out:
  732. DkObjectClose(file);
  733. return ret;
  734. }
  735. int store_all_msg_persist (void)
  736. {
  737. struct shim_msg_handle * msgq, *n;
  738. lock(msgq_list_lock);
  739. list_for_each_entry_safe(msgq, n, &msgq_list, list)
  740. if (msgq->owned) {
  741. struct shim_handle * hdl = container_of(msgq, struct shim_handle,
  742. info.msg);
  743. lock(hdl->lock);
  744. __store_msg_persist(msgq);
  745. unlock(hdl->lock);
  746. }
  747. unlock(msgq_list_lock);
  748. return 0;
  749. }
  750. int shim_do_msgpersist (int msqid, int cmd)
  751. {
  752. struct shim_msg_handle * msgq;
  753. struct shim_handle * hdl;
  754. int ret = -EINVAL;
  755. switch (cmd) {
  756. case MSGPERSIST_STORE:
  757. msgq = get_msg_handle_by_id(msqid);
  758. if (!msgq)
  759. return -EINVAL;
  760. hdl = container_of(msgq, struct shim_handle, info.msg);
  761. lock(hdl->lock);
  762. ret = __store_msg_persist(msgq);
  763. unlock(hdl->lock);
  764. put_msg_handle(msgq);
  765. break;
  766. case MSGPERSIST_LOAD:
  767. lock(msgq_list_lock);
  768. ret = __add_msg_handle(0, msqid, false, &msgq);
  769. if (!ret)
  770. ret = __load_msg_persist(msgq, true);
  771. unlock(msgq_list_lock);
  772. put_msg_handle(msgq);
  773. break;
  774. }
  775. return ret;
  776. }
  777. static int msg_balance_migrate (struct shim_handle * hdl,
  778. struct sysv_client * src)
  779. {
  780. struct shim_msg_handle * msgq = &hdl->info.msg;
  781. int ret = 0;
  782. debug("trigger msg queue balancing, migrate to process %u\n", src->vmid);
  783. if ((ret = __store_msg_persist(msgq)) < 0)
  784. return 0;
  785. struct shim_ipc_info * info = discover_client(src->port, src->vmid);
  786. if (!info)
  787. goto failed;
  788. ipc_sysv_sublease_send(src->vmid, msgq->msqid,
  789. qstrgetstr(&info->uri),
  790. &msgq->lease);
  791. ret = ipc_sysv_msgmov_send(src->port, src->vmid, msgq->msqid, msgq->lease,
  792. msgq->scores, MAX_SYSV_CLIENTS);
  793. if (ret < 0)
  794. goto failed_info;
  795. msgq->owner = info;
  796. for (struct msg_type * mtype = msgq->types ;
  797. mtype < &msgq->types[msgq->ntypes] ; mtype++) {
  798. struct msg_req * req = mtype->reqs;
  799. mtype->reqs = mtype->req_tail = NULL;
  800. while (req) {
  801. struct msg_req * next = req->next;
  802. ipc_sysv_movres_send(&req->dest, info->vmid, qstrgetstr(&info->uri),
  803. msgq->lease, msgq->msqid, SYSV_MSGQ);
  804. put_ipc_port(req->dest.port);
  805. __free_msg_qobj(msgq, req);
  806. req = next;
  807. }
  808. }
  809. ret = 0;
  810. DkEventSet(msgq->event);
  811. goto out;
  812. failed_info:
  813. put_ipc_info(info);
  814. failed:
  815. ret = __load_msg_persist(msgq, true);
  816. out:
  817. return ret;
  818. }