shim_msgget.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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 = DkStreamMap(file, NULL, PAL_PROT_READ|PAL_PROT_WRITE,
  637. 0, ALIGN_UP(expected_size));
  638. if (!mem) {
  639. ret = -EFAULT;
  640. goto err_file;
  641. }
  642. struct msg_handle_backup * mback = mem;
  643. mem += sizeof(struct msg_handle_backup);
  644. mback->perm = msgq->perm;
  645. mback->nmsgs = msgq->nmsgs;
  646. mback->currentsize = msgq->currentsize;
  647. struct msg_type * mtype;
  648. for (mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ;
  649. mtype++) {
  650. while (mtype->msgs) {
  651. struct msg_backup * msg = mem;
  652. mem += sizeof(struct msg_backup) + mtype->msgs->size;
  653. msg->type = mtype->type;
  654. msg->size = mtype->msgs->size;
  655. __load_msg_qobjs(msgq, mtype, mtype->msgs, msg->data);
  656. }
  657. mtype->msgs = mtype->msg_tail = NULL;
  658. }
  659. DkStreamUnmap(mem, ALIGN_UP(expected_size));
  660. if (msgq->owned)
  661. for (mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ;
  662. mtype++) {
  663. struct msg_req * req = mtype->reqs;
  664. mtype->reqs = mtype->req_tail = NULL;
  665. while (req) {
  666. struct sysv_client * c = &req->dest;
  667. struct msg_req * next = req->next;
  668. __response_ipc_message(c->port, c->vmid, -EIDRM, c->seq);
  669. put_ipc_port(c->port);
  670. __free_msg_qobj(msgq, req);
  671. req = next;
  672. }
  673. }
  674. msgq->owned = false;
  675. ret = 0;
  676. goto out;
  677. err_file:
  678. DkStreamDelete(file, 0);
  679. DkObjectClose(file);
  680. out:
  681. // To wake up any receiver waiting on local message which must
  682. // now be requested from new owner.
  683. DkEventSet(msgq->event);
  684. return ret;
  685. }
  686. static int __load_msg_persist (struct shim_msg_handle * msgq, bool readmsg)
  687. {
  688. int ret = 0;
  689. char fileuri[20];
  690. snprintf(fileuri, 20, "file:msgq.%08x", msgq->msqid);
  691. PAL_HANDLE file = DkStreamOpen(fileuri, PAL_ACCESS_RDONLY, 0, 0, 0);
  692. if (!file)
  693. return -EIDRM;
  694. struct msg_handle_backup mback;
  695. int bytes = DkStreamRead(file, 0, sizeof(struct msg_handle_backup),
  696. &mback, NULL, 0);
  697. if (bytes < sizeof(struct msg_handle_backup)) {
  698. ret = bytes ? -EFAULT : -PAL_ERRNO;
  699. goto out;
  700. }
  701. msgq->perm = mback.perm;
  702. if (!readmsg || !mback.nmsgs)
  703. goto done;
  704. int expected_size = sizeof(struct msg_handle_backup) +
  705. sizeof(struct msg_backup) * mback.nmsgs +
  706. mback.currentsize;
  707. void * mem = DkStreamMap(file, NULL, PAL_PROT_READ,
  708. 0, ALIGN_UP(expected_size));
  709. if (!mem) {
  710. ret = -PAL_ERRNO;
  711. goto out;
  712. }
  713. mem += sizeof(struct msg_handle_backup);
  714. struct msg_type * mtype = NULL;
  715. for (int i = 0 ; i < mback.nmsgs ; i++) {
  716. struct msg_backup * m = mem;
  717. mem += sizeof(struct msg_backup) + m->size;
  718. debug("load msg: type=%d, size=%d\n", m->type, m->size);
  719. if (!mtype || mtype->type != m->type)
  720. mtype = __add_msg_type(m->type, &msgq->types, &msgq->ntypes,
  721. &msgq->maxtypes);
  722. if ((ret = __store_msg_qobjs(msgq, mtype, m->size, m->data)) < 0)
  723. goto out;
  724. };
  725. DkStreamUnmap(mem, ALIGN_UP(expected_size));
  726. done:
  727. DkStreamDelete(file, 0);
  728. ret = 0;
  729. goto out;
  730. out:
  731. DkObjectClose(file);
  732. return ret;
  733. }
  734. int store_all_msg_persist (void)
  735. {
  736. struct shim_msg_handle * msgq, *n;
  737. lock(msgq_list_lock);
  738. list_for_each_entry_safe(msgq, n, &msgq_list, list)
  739. if (msgq->owned) {
  740. struct shim_handle * hdl = container_of(msgq, struct shim_handle,
  741. info.msg);
  742. lock(hdl->lock);
  743. __store_msg_persist(msgq);
  744. unlock(hdl->lock);
  745. }
  746. unlock(msgq_list_lock);
  747. return 0;
  748. }
  749. int shim_do_msgpersist (int msqid, int cmd)
  750. {
  751. struct shim_msg_handle * msgq;
  752. struct shim_handle * hdl;
  753. int ret = -EINVAL;
  754. switch (cmd) {
  755. case MSGPERSIST_STORE:
  756. msgq = get_msg_handle_by_id(msqid);
  757. if (!msgq)
  758. return -EINVAL;
  759. hdl = container_of(msgq, struct shim_handle, info.msg);
  760. lock(hdl->lock);
  761. ret = __store_msg_persist(msgq);
  762. unlock(hdl->lock);
  763. put_msg_handle(msgq);
  764. break;
  765. case MSGPERSIST_LOAD:
  766. lock(msgq_list_lock);
  767. ret = __add_msg_handle(0, msqid, false, &msgq);
  768. if (!ret)
  769. ret = __load_msg_persist(msgq, true);
  770. unlock(msgq_list_lock);
  771. put_msg_handle(msgq);
  772. break;
  773. }
  774. return ret;
  775. }
  776. static int msg_balance_migrate (struct shim_handle * hdl,
  777. struct sysv_client * src)
  778. {
  779. struct shim_msg_handle * msgq = &hdl->info.msg;
  780. int ret = 0;
  781. debug("trigger msg queue balancing, migrate to process %u\n", src->vmid);
  782. if ((ret = __store_msg_persist(msgq)) < 0)
  783. return 0;
  784. struct shim_ipc_info * info = discover_client(src->port, src->vmid);
  785. if (!info)
  786. goto failed;
  787. ipc_sysv_sublease_send(src->vmid, msgq->msqid,
  788. qstrgetstr(&info->uri),
  789. &msgq->lease);
  790. ret = ipc_sysv_msgmov_send(src->port, src->vmid, msgq->msqid, msgq->lease,
  791. msgq->scores, MAX_SYSV_CLIENTS);
  792. if (ret < 0)
  793. goto failed_info;
  794. msgq->owner = info;
  795. for (struct msg_type * mtype = msgq->types ;
  796. mtype < &msgq->types[msgq->ntypes] ; mtype++) {
  797. struct msg_req * req = mtype->reqs;
  798. mtype->reqs = mtype->req_tail = NULL;
  799. while (req) {
  800. struct msg_req * next = req->next;
  801. ipc_sysv_movres_send(&req->dest, info->vmid, qstrgetstr(&info->uri),
  802. msgq->lease, msgq->msqid, SYSV_MSGQ);
  803. put_ipc_port(req->dest.port);
  804. __free_msg_qobj(msgq, req);
  805. req = next;
  806. }
  807. }
  808. ret = 0;
  809. DkEventSet(msgq->event);
  810. goto out;
  811. failed_info:
  812. put_ipc_info(info);
  813. failed:
  814. ret = __load_msg_persist(msgq, true);
  815. out:
  816. return ret;
  817. }