shim_checkpoint.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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 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 Lesser 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 Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * shim_checkpoints.c
  17. *
  18. * This file contains definitions and macros for checkpointing method.
  19. */
  20. #ifndef _SHIM_CHECKPOINT_H_
  21. #define _SHIM_CHECKPOINT_H_
  22. #include <shim_defs.h>
  23. #include <shim_ipc.h>
  24. #include <shim_profile.h>
  25. #include <pal.h>
  26. #include <stdarg.h>
  27. #ifdef __i386__
  28. typedef uint32_t ptr_t;
  29. # define hashfunc hash32
  30. #else
  31. typedef uint64_t ptr_t;
  32. # define hashfunc hash64
  33. #endif
  34. #define __attribute_migratable __attribute__((section(".migratable")))
  35. extern char __migratable;
  36. extern char __migratable_end;
  37. /* TSAI 7/11/2012:
  38. The checkpoint scheme we are expecting is to support an easy syntax to
  39. implement migration procedure. A migration procedure can be written
  40. in the following syntax:
  41. BEGIN_CP_DEFINITION(exec)
  42. {
  43. DEFINE_CP(thread, ...);
  44. DEFINE_CP(handle_map, ...);
  45. }
  46. void * checkpoint = DO_CHECKPOINT(exec);
  47. The structure of checkpoint data will be a counting-down stack-like
  48. memory segment, with enough space reserved below for 1. in case the
  49. dry run miscalculate the checkpoint size or 2. stack use for the new
  50. thread.
  51. Below is the figure for our checkpoint structure:
  52. Low Bytes -------------------------------------------------
  53. checkpoint_entry[0]
  54. data section for checkpoint 0
  55. checkpoint_entry[1]
  56. data section for checkpoint 1
  57. checkpoint_entry[2]
  58. ...
  59. checkpoint_entry[n] CP_NULL
  60. High Bytes ------------------------------------------------
  61. */
  62. struct shim_cp_entry
  63. {
  64. ptr_t cp_type; /* entry type */
  65. union
  66. {
  67. ptr_t cp_val; /* interger value */
  68. /* originally there is a pointer, now we don't need them */
  69. } cp_un;
  70. };
  71. struct shim_mem_entry {
  72. struct shim_mem_entry * prev;
  73. void * addr;
  74. size_t size;
  75. void ** paddr;
  76. int prot;
  77. void * data;
  78. };
  79. struct shim_gipc_entry {
  80. struct shim_mem_entry mem;
  81. #if HASH_GIPC == 1
  82. unsigned long first_hash;
  83. #endif
  84. };
  85. struct shim_palhdl_entry {
  86. struct shim_palhdl_entry * prev;
  87. PAL_HANDLE handle;
  88. struct shim_qstr * uri;
  89. PAL_HANDLE * phandle;
  90. };
  91. struct shim_cp_store {
  92. /* checkpoint data mapping */
  93. void * cp_map;
  94. struct shim_handle * cp_file;
  95. /* allocation method for check point area */
  96. void * (*alloc) (struct shim_cp_store *, void *, size_t);
  97. /* check point area */
  98. ptr_t base, offset, bound;
  99. /* entries of gipc records */
  100. bool use_gipc;
  101. struct shim_gipc_entry * last_gipc_entry;
  102. int gipc_nentries;
  103. /* entries of out-of-band data */
  104. struct shim_mem_entry * last_mem_entry;
  105. int mem_nentries;
  106. int mem_size;
  107. /* entries of pal handles to send */
  108. struct shim_palhdl_entry * last_palhdl_entry;
  109. int palhdl_nentries;
  110. };
  111. #define CP_FUNC_ARGS \
  112. struct shim_cp_store * store, void * obj, int size, void ** objp
  113. #define RS_FUNC_ARGS \
  114. struct shim_cp_entry * entry, ptr_t base, ptr_t * offset, long rebase
  115. #define DEFINE_CP_FUNC(name) int cp_##name (CP_FUNC_ARGS)
  116. #define DEFINE_RS_FUNC(name) int rs_##name (RS_FUNC_ARGS)
  117. typedef int (*cp_func) (CP_FUNC_ARGS);
  118. typedef int (*rs_func) (RS_FUNC_ARGS);
  119. extern const char * __cp_name;
  120. extern const cp_func __cp_func;
  121. extern const rs_func __rs_func;
  122. enum {
  123. CP_NULL = 0,
  124. CP_IGNORE,
  125. CP_OOB,
  126. CP_ADDR,
  127. CP_SIZE,
  128. CP_FUNC_BASE,
  129. };
  130. #define CP_FUNC_INDEX(name) \
  131. ({ extern const cp_func cp_func_##name; &cp_func_##name - &__cp_func; })
  132. #define CP_FUNC(name) CP_FUNC_BASE + CP_FUNC_INDEX(name)
  133. #define CP_FUNC_NAME(type) (&__cp_name)[(type) - CP_FUNC_BASE]
  134. #define __ADD_CP_OFFSET(size) \
  135. ({ \
  136. ptr_t _off = store->offset; \
  137. if (store->offset + (size) > store->bound) { \
  138. int new_bound = store->bound * 2; \
  139. \
  140. while (store->offset + (size) > new_bound) \
  141. new_bound *= 2; \
  142. \
  143. void * buf = store->alloc(store, \
  144. (void *) store->base + store->bound, \
  145. new_bound - store->bound); \
  146. if (!buf) \
  147. return -ENOMEM; \
  148. \
  149. store->bound = new_bound; \
  150. } \
  151. store->offset += size; \
  152. _off; })
  153. #define ADD_CP_ENTRY(type, value) \
  154. ({ \
  155. struct shim_cp_entry * tmp = \
  156. (void *) base + \
  157. __ADD_CP_OFFSET(sizeof(struct shim_cp_entry)); \
  158. tmp->cp_type = CP_##type; \
  159. tmp->cp_un.cp_val = (ptr_t) (value); \
  160. if (DEBUG_CHECKPOINT) \
  161. debug("ADD CP_" #type "(%p) >%d\n", tmp->cp_un.cp_val, \
  162. store->offset); \
  163. tmp; })
  164. #define ADD_CP_OFFSET(size) \
  165. ({ \
  166. int _size = ((size) + sizeof(void *) - 1) & \
  167. ~(sizeof(void *) - 1); \
  168. struct shim_cp_entry * oob = \
  169. (void *) base + \
  170. __ADD_CP_OFFSET(sizeof(struct shim_cp_entry)); \
  171. oob->cp_type = CP_OOB; \
  172. oob->cp_un.cp_val = (ptr_t) _size; \
  173. ptr_t _off = (ptr_t) __ADD_CP_OFFSET(_size); \
  174. if (DEBUG_CHECKPOINT) \
  175. debug("ADD OFFSET(%d) >%d\n", (size), store->offset); \
  176. _off; })
  177. #define ADD_CP_FUNC_ENTRY(value) \
  178. ({ \
  179. struct shim_cp_entry * tmp = \
  180. (void *) base + \
  181. __ADD_CP_OFFSET(sizeof(struct shim_cp_entry)); \
  182. tmp->cp_type = CP_FUNC_TYPE; \
  183. tmp->cp_un.cp_val = (ptr_t) (value); \
  184. if (DEBUG_CHECKPOINT) \
  185. debug("ADD %s(%p) >%d\n", CP_FUNC_NAME, (value), \
  186. store->offset); \
  187. tmp; })
  188. #define NEXT_CP_ENTRY() \
  189. ({ struct shim_cp_entry * tmp; \
  190. while (1) { \
  191. tmp = (void *) base + *offset; \
  192. if (tmp->cp_type == CP_NULL) { \
  193. tmp = NULL; \
  194. break; \
  195. } \
  196. *offset += sizeof(struct shim_cp_entry); \
  197. if (tmp->cp_type == CP_OOB) \
  198. *offset += tmp->cp_un.cp_val; \
  199. else \
  200. break; \
  201. } \
  202. tmp; })
  203. #define GET_CP_ENTRY(type) \
  204. ({ struct shim_cp_entry * tmp = NEXT_CP_ENTRY(); \
  205. \
  206. while (tmp->cp_type != CP_##type) \
  207. tmp = NEXT_CP_ENTRY(); \
  208. \
  209. /* debug("GET CP_" #type "(%p)\n",tmp->cp_un.cp_val); */ \
  210. tmp->cp_un.cp_val; })
  211. #define GET_CP_FUNC_ENTRY() \
  212. ({ /* debug("GET CP_FUNC_%s(%p) :%d\n", CP_FUNC_NAME, \
  213. entry->cp_un.cp_val); */ \
  214. entry->cp_un.cp_val; })
  215. #define BEGIN_CP_FUNC(name) \
  216. const char * cp_name_##name \
  217. __attribute__((section(".cp_name." #name))) = #name; \
  218. extern DEFINE_CP_FUNC(name); \
  219. extern DEFINE_RS_FUNC(name); \
  220. const cp_func cp_func_##name \
  221. __attribute__((section(".cp_func." #name))) = &cp_##name; \
  222. const rs_func rs_func_##name \
  223. __attribute__((section(".rs_func." #name))) = &rs_##name; \
  224. \
  225. DEFINE_PROFILE_INTERVAL(cp_##name, checkpoint_func); \
  226. DEFINE_PROFILE_INTERVAL(rs_##name, resume_func); \
  227. \
  228. DEFINE_CP_FUNC(name) \
  229. { \
  230. int CP_FUNC_TYPE __attribute__((unused)) = CP_FUNC(name); \
  231. const char * CP_FUNC_NAME __attribute__((unused)) = #name; \
  232. ptr_t base __attribute__((unused)) = store->base; \
  233. BEGIN_PROFILE_INTERVAL(); \
  234. ASSIGN_PROFILE_INTERVAL(cp_##name);
  235. #define END_CP_FUNC(name) \
  236. SAVE_PROFILE_INTERVAL_ASSIGNED(); \
  237. return 0; \
  238. }
  239. #define END_CP_FUNC_NO_RS(name) \
  240. END_CP_FUNC(name) \
  241. BEGIN_RS_FUNC(name) {} END_RS_FUNC(name)
  242. #define BEGIN_RS_FUNC(name) \
  243. DEFINE_RS_FUNC(name) \
  244. { \
  245. int CP_FUNC_TYPE __attribute__((unused)) = CP_FUNC(name); \
  246. const char * CP_FUNC_NAME __attribute__((unused)) = #name; \
  247. BEGIN_PROFILE_INTERVAL(); \
  248. ASSIGN_PROFILE_INTERVAL(rs_##name);
  249. #define END_RS_FUNC(name) \
  250. SAVE_PROFILE_INTERVAL_ASSIGNED(); \
  251. return 0; \
  252. }
  253. #define CP_REBASE(obj) \
  254. do { \
  255. void * _ptr = &(obj); \
  256. size_t _size = sizeof(obj); \
  257. void ** _p; \
  258. for (_p = _ptr ; _p < (void **)(_ptr + _size) ; _p++) \
  259. if (*_p) \
  260. *_p += rebase; \
  261. } while (0)
  262. #define DO_CP_SIZE(name, obj, size, objp) \
  263. do { \
  264. extern DEFINE_CP_FUNC(name); \
  265. int ret = cp_##name(store, obj, size, (void **) objp); \
  266. if (ret < 0) return ret; \
  267. } while (0)
  268. #define DO_CP(name, obj, objp) \
  269. DO_CP_SIZE(name, obj, sizeof(*obj), objp)
  270. #define DO_CP_MEMBER(name, obj, newobj, member) \
  271. DO_CP(name, (obj)->member, &((newobj)->member));
  272. #define DO_CP_IN_MEMBER(name, obj, member) \
  273. DO_CP(name, &((obj)->member), NULL)
  274. struct shim_cp_map_entry { void * addr; ptr_t off; };
  275. void * create_cp_map (void);
  276. void destroy_cp_map (void * map);
  277. struct shim_cp_map_entry *
  278. get_cp_map_entry (void * map, void * addr, bool create);
  279. #define GET_FROM_CP_MAP(obj) \
  280. ({ \
  281. struct shim_cp_map_entry * e = \
  282. get_cp_map_entry(store->cp_map, (obj), false); \
  283. e ? e->off : 0; })
  284. #define ADD_TO_CP_MAP(obj, off) \
  285. do { \
  286. struct shim_cp_map_entry * e = \
  287. get_cp_map_entry(store->cp_map, (obj), true); \
  288. e->off = off; \
  289. } while (0)
  290. #define BEGIN_MIGRATION_DEF(name, ...) \
  291. int migrate_##name (struct shim_cp_store * store, ##__VA_ARGS__) \
  292. { \
  293. int ret = 0; \
  294. ptr_t base = store->base;
  295. #define END_MIGRATION_DEF(name) \
  296. ADD_CP_ENTRY(NULL, 0); \
  297. return 0; \
  298. }
  299. #define DEFINE_MIGRATE(name, obj, size) \
  300. do { \
  301. extern DEFINE_CP_FUNC(name); \
  302. if ((ret = cp_##name(store, (obj), (size), NULL)) < 0) \
  303. return ret; \
  304. } while (0)
  305. #define DEBUG_RESUME 0
  306. #define DEBUG_CHECKPOINT 0
  307. #if DEBUG_RESUME == 1
  308. # define DEBUG_RS(fmt, ...) \
  309. debug("GET %s(%p): " fmt "\n", CP_FUNC_NAME, entry->cp_un.cp_val, \
  310. ##__VA_ARGS__)
  311. #else
  312. # define DEBUG_RS(...) do {} while (0)
  313. #endif
  314. #include <shim_profile.h>
  315. #define START_MIGRATE(store, name, ...) \
  316. ({ int ret = 0; \
  317. do { \
  318. BEGIN_PROFILE_INTERVAL(); \
  319. \
  320. if (!((store)->cp_map = create_cp_map())) { \
  321. ret = -ENOMEM; \
  322. goto out; \
  323. } \
  324. SAVE_PROFILE_INTERVAL(checkpoint_create_map); \
  325. \
  326. ret = migrate_##name((store), ##__VA_ARGS__); \
  327. if (ret < 0) \
  328. goto out; \
  329. \
  330. SAVE_PROFILE_INTERVAL(checkpoint_copy); \
  331. ADD_PROFILE_OCCURENCE(checkpoint_total_size, (store)->offset); \
  332. INC_PROFILE_OCCURENCE(checkpoint_count); \
  333. \
  334. debug("complete checkpointing data\n"); \
  335. out: \
  336. destroy_cp_map((store)->cp_map); \
  337. SAVE_PROFILE_INTERVAL(checkpoint_destroy_map); \
  338. } while (0); \
  339. ret; })
  340. struct newproc_cp_header {
  341. struct cp_header {
  342. unsigned long size;
  343. void * addr;
  344. unsigned long offset;
  345. } hdr;
  346. struct mem_header {
  347. unsigned long entoffset;
  348. int nentries;
  349. } mem;
  350. struct palhdl_header {
  351. unsigned long entoffset;
  352. int nentries;
  353. } palhdl;
  354. struct gipc_header {
  355. char uri[16];
  356. unsigned long entoffset;
  357. int nentries;
  358. } gipc;
  359. };
  360. struct newproc_header {
  361. struct newproc_cp_header checkpoint;
  362. int failure;
  363. #ifdef PROFILE
  364. unsigned long begin_create_time;
  365. unsigned long create_time;
  366. unsigned long write_proc_time;
  367. #endif
  368. };
  369. struct newproc_response {
  370. IDTYPE child_vmid;
  371. int failure;
  372. };
  373. int do_migration (struct newproc_cp_header * hdr, void ** cpptr);
  374. int restore_checkpoint (struct cp_header * cphdr, struct mem_header * memhdr,
  375. ptr_t base, int type);
  376. int do_migrate_process (int (*migrate) (struct shim_cp_store *,
  377. struct shim_thread *,
  378. struct shim_process *, va_list),
  379. struct shim_handle * exec,
  380. const char ** argv,
  381. struct shim_thread * thread, ...);
  382. int init_from_checkpoint_file (const char * filename,
  383. struct newproc_cp_header * hdr,
  384. void ** cpptr);
  385. int restore_from_file (const char * filename, struct newproc_cp_header * hdr,
  386. void ** cpptr);
  387. void restore_context (struct shim_context * context);
  388. int create_checkpoint (const char * cpdir, IDTYPE * session);
  389. int join_checkpoint (struct shim_thread * cur, ucontext_t * context,
  390. IDTYPE sid);
  391. #endif /* _SHIM_CHECKPOINT_H_ */