| skipped 874 lines |
875 | 875 | | return parse_file_locks(); |
876 | 876 | | } |
877 | 877 | | |
| 878 | + | static bool task_in_rseq(struct criu_rseq_cs *rseq_cs, uint64_t addr) |
| 879 | + | { |
| 880 | + | return addr >= rseq_cs->start_ip && addr < rseq_cs->start_ip + rseq_cs->post_commit_offset; |
| 881 | + | } |
| 882 | + | |
| 883 | + | static int fixup_thread_rseq(struct pstree_item *item, int i) |
| 884 | + | { |
| 885 | + | CoreEntry *core = item->core[i]; |
| 886 | + | struct criu_rseq_cs *rseq_cs = &dmpi(item)->thread_rseq_cs[i]; |
| 887 | + | pid_t tid = item->threads[i].real; |
| 888 | + | |
| 889 | + | /* equivalent to (struct rseq)->rseq_cs is NULL */ |
| 890 | + | if (!rseq_cs->start_ip) |
| 891 | + | return 0; |
| 892 | + | |
| 893 | + | pr_debug( |
| 894 | + | "fixup_thread_rseq for %d: rseq_cs start_ip = %llx abort_ip = %llx post_commit_offset = %llx flags = %x version = %x; IP = %lx\n", |
| 895 | + | tid, rseq_cs->start_ip, rseq_cs->abort_ip, rseq_cs->post_commit_offset, rseq_cs->flags, |
| 896 | + | rseq_cs->version, (unsigned long)TI_IP(core)); |
| 897 | + | |
| 898 | + | if (rseq_cs->version != 0) { |
| 899 | + | pr_err("unsupported RSEQ ABI version = %d\n", rseq_cs->version); |
| 900 | + | return -1; |
| 901 | + | } |
| 902 | + | |
| 903 | + | if (task_in_rseq(rseq_cs, TI_IP(core))) { |
| 904 | + | struct pid *tid = &item->threads[i]; |
| 905 | + | |
| 906 | + | /* |
| 907 | + | * We need to fixup task instruction pointer from |
| 908 | + | * the original one (which lays inside rseq critical section) |
| 909 | + | * to rseq abort handler address. But we need to look on rseq_cs->flags |
| 910 | + | * (please refer to struct rseq -> flags field description). |
| 911 | + | * Naive idea of flags support may be like... let's change instruction pointer (IP) |
| 912 | + | * to rseq_cs->abort_ip if !(rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL). |
| 913 | + | * But unfortunately, it doesn't work properly, because the kernel does |
| 914 | + | * clean up of rseq_cs field in the struct rseq (modifies userspace memory). |
| 915 | + | * So, we need to preserve original value of (struct rseq)->rseq_cs field in the |
| 916 | + | * image and restore it's value before releasing threads (see restore_rseq_cs()). |
| 917 | + | * |
| 918 | + | * It's worth to mention that we need to fixup IP in CoreEntry |
| 919 | + | * (used when full dump/restore is performed) and also in |
| 920 | + | * the parasite regs storage (used if --leave-running option is used, |
| 921 | + | * or if dump error occurred and process execution is resumed). |
| 922 | + | */ |
| 923 | + | |
| 924 | + | if (!(rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL)) { |
| 925 | + | pr_warn("The %d task is in rseq critical section. IP will be set to rseq abort handler addr\n", |
| 926 | + | tid->real); |
| 927 | + | |
| 928 | + | TI_IP(core) = rseq_cs->abort_ip; |
| 929 | + | |
| 930 | + | if (item->pid->real == tid->real) { |
| 931 | + | compel_set_leader_ip(dmpi(item)->parasite_ctl, rseq_cs->abort_ip); |
| 932 | + | } else { |
| 933 | + | compel_set_thread_ip(dmpi(item)->thread_ctls[i], rseq_cs->abort_ip); |
| 934 | + | } |
| 935 | + | } |
| 936 | + | } |
| 937 | + | |
| 938 | + | return 0; |
| 939 | + | } |
| 940 | + | |
878 | 941 | | static int dump_task_thread(struct parasite_ctl *parasite_ctl, const struct pstree_item *item, int id) |
879 | 942 | | { |
880 | 943 | | struct parasite_thread_ctl *tctl = dmpi(item)->thread_ctls[id]; |
| skipped 301 lines |
1182 | 1245 | | xfree(thread_rseq_cs); |
1183 | 1246 | | dmpi(item)->thread_rseq_cs = NULL; |
1184 | 1247 | | return -1; |
1185 | | - | } |
1186 | | - | |
1187 | | - | static bool task_in_rseq(struct criu_rseq_cs *rseq_cs, uint64_t addr) |
1188 | | - | { |
1189 | | - | return addr >= rseq_cs->start_ip && addr < rseq_cs->start_ip + rseq_cs->post_commit_offset; |
1190 | | - | } |
1191 | | - | |
1192 | | - | static int fixup_thread_rseq(struct pstree_item *item, int i) |
1193 | | - | { |
1194 | | - | CoreEntry *core = item->core[i]; |
1195 | | - | struct criu_rseq_cs *rseq_cs = &dmpi(item)->thread_rseq_cs[i]; |
1196 | | - | pid_t tid = item->threads[i].real; |
1197 | | - | |
1198 | | - | /* equivalent to (struct rseq)->rseq_cs is NULL */ |
1199 | | - | if (!rseq_cs->start_ip) |
1200 | | - | return 0; |
1201 | | - | |
1202 | | - | pr_debug( |
1203 | | - | "fixup_thread_rseq for %d: rseq_cs start_ip = %llx abort_ip = %llx post_commit_offset = %llx flags = %x version = %x; IP = %lx\n", |
1204 | | - | tid, rseq_cs->start_ip, rseq_cs->abort_ip, rseq_cs->post_commit_offset, rseq_cs->flags, |
1205 | | - | rseq_cs->version, (unsigned long)TI_IP(core)); |
1206 | | - | |
1207 | | - | if (rseq_cs->version != 0) { |
1208 | | - | pr_err("unsupported RSEQ ABI version = %d\n", rseq_cs->version); |
1209 | | - | return -1; |
1210 | | - | } |
1211 | | - | |
1212 | | - | if (task_in_rseq(rseq_cs, TI_IP(core))) { |
1213 | | - | struct pid *tid = &item->threads[i]; |
1214 | | - | |
1215 | | - | /* |
1216 | | - | * We need to fixup task instruction pointer from |
1217 | | - | * the original one (which lays inside rseq critical section) |
1218 | | - | * to rseq abort handler address. But we need to look on rseq_cs->flags |
1219 | | - | * (please refer to struct rseq -> flags field description). |
1220 | | - | * Naive idea of flags support may be like... let's change instruction pointer (IP) |
1221 | | - | * to rseq_cs->abort_ip if !(rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL). |
1222 | | - | * But unfortunately, it doesn't work properly, because the kernel does |
1223 | | - | * clean up of rseq_cs field in the struct rseq (modifies userspace memory). |
1224 | | - | * So, we need to preserve original value of (struct rseq)->rseq_cs field in the |
1225 | | - | * image and restore it's value before releasing threads (see restore_rseq_cs()). |
1226 | | - | * |
1227 | | - | * It's worth to mention that we need to fixup IP in CoreEntry |
1228 | | - | * (used when full dump/restore is performed) and also in |
1229 | | - | * the parasite regs storage (used if --leave-running option is used, |
1230 | | - | * or if dump error occurred and process execution is resumed). |
1231 | | - | */ |
1232 | | - | |
1233 | | - | if (!(rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL)) { |
1234 | | - | pr_warn("The %d task is in rseq critical section. IP will be set to rseq abort handler addr\n", |
1235 | | - | tid->real); |
1236 | | - | |
1237 | | - | TI_IP(core) = rseq_cs->abort_ip; |
1238 | | - | |
1239 | | - | if (item->pid->real == tid->real) { |
1240 | | - | compel_set_leader_ip(dmpi(item)->parasite_ctl, rseq_cs->abort_ip); |
1241 | | - | } else { |
1242 | | - | compel_set_thread_ip(dmpi(item)->thread_ctls[i], rseq_cs->abort_ip); |
1243 | | - | } |
1244 | | - | } |
1245 | | - | } |
1246 | | - | |
1247 | | - | return 0; |
1248 | 1248 | | } |
1249 | 1249 | | |
1250 | 1250 | | static int fixup_task_rseq(pid_t pid, struct pstree_item *item) |
| skipped 1048 lines |