# 迁移策略

## 模式
以下模式中会在运行的结尾（写入EPT前）计划分区迁移，只要对应要求都满足，不管用户是否请求迁移（因此，即使用户不想ampart来完成迁移，它们也可以根据ampart在dry-run模式下给出的指示来自己完成迁移）

 - dtoe *(DTB转化为EPT)*
   - 目标非DTB
   - 运行前，目标中存在有效EPT
   - 新旧EPT不同
 - dedit *(DTB编辑)*
   - 目标非DTB
   - 运行前，目标中存在有效EPT
   - 编辑过的DTB可以构建新的EPT
   - 新旧EPT不同
 - eedit *(EPT编辑)*
   - 新旧EPT不同
 - dclone *(DTB编辑)*
   - 目标非DTB
   - 运行前，目标中存在有效EPT
   - 克隆来的DTB可以构建新的EPT
   - 新旧EPT不同
 - eclone *(EPT克隆)*
   - 运行前，目标中存在有效EPT
   - 克隆来的EPT与旧的不同
 - ecreate *(EPT创建)*
   - 运行前，目标中存在有效EPT
   - 创建的EPT与旧的不同

## 技术细节
迁移包括计划和实际迁移

### 前提
新旧两个EPT必须都有效，且包含至少一个分区。对于分区本身的验证工作不在迁移模块中实现，由各模式拉起迁移模块之前的流程负责

### 块
两个EPT中所有分区的偏移和大小的不大于4M的最大公约数会被选择作为迁移块。一般是2M或者4M。如果不能获得迁移块，不会构建迁移计划  

每个块都有一个布尔值的迁移标志，如果需要迁移的话设置为真，并且记录目标块ID。迁移标志默认为假，并且计划前目标块ID默认为0（模块块ID=0并不意味着块没有迁移计划，可能实际上目标块就是0）

## 流程
对于每个需要被迁移的块（标记为待办），执行以下步骤
 - 检查是否为环形迁移（如果目标的目标的...目标是它本身呢）
   - 是环形
     - 读入缓存
     - 如果目标块为待办状态，且其缓存未读取，拉起其迁移流程
       - 如果失败，放弃整个迁移计划
     - 写入目标块
     - 取消待办状态标记
     - 释放缓存，设置为空指针
   - 普通非环形
     - 如果目标块为待办状态，拉起其迁移流程
     - 读入缓存
     - 写入目标块
     - 取消待办状态标记
     - 释放缓存，设置为空指针
   
这里检查了两个重要重要的状态标记（待办，缓存）。对于在计划期间所有需要迁移的分区，待办标记均设置为真。缓存在环形迁移中检查，所以环形迁移不会进入死锁
