Paul Lawrence | de12cfe | 2018-10-23 08:56:04 -0700 | [diff] [blame] | 1 | dm_bow (backup on write) |
| 2 | ======================== |
| 3 | |
| 4 | dm_bow is a device mapper driver that uses the free space on a device to back up |
| 5 | data that is overwritten. The changes can then be committed by a simple state |
| 6 | change, or rolled back by removing the dm_bow device and running a command line |
| 7 | utility over the underlying device. |
| 8 | |
| 9 | dm_bow has three states, set by writing ‘1’ or ‘2’ to /sys/block/dm-?/bow/state. |
| 10 | It is only possible to go from state 0 (initial state) to state 1, and then from |
| 11 | state 1 to state 2. |
| 12 | |
| 13 | State 0: dm_bow collects all trims to the device and assumes that these mark |
| 14 | free space on the overlying file system that can be safely used. Typically the |
| 15 | mount code would create the dm_bow device, mount the file system, call the |
| 16 | FITRIM ioctl on the file system then switch to state 1. These trims are not |
| 17 | propagated to the underlying device. |
| 18 | |
| 19 | State 1: All writes to the device cause the underlying data to be backed up to |
| 20 | the free (trimmed) area as needed in such a way as they can be restored. |
| 21 | However, the writes, with one exception, then happen exactly as they would |
| 22 | without dm_bow, so the device is always in a good final state. The exception is |
| 23 | that sector 0 is used to keep a log of the latest changes, both to indicate that |
| 24 | we are in this state and to allow rollback. See below for all details. If there |
| 25 | isn't enough free space, writes are failed with -ENOSPC. |
| 26 | |
| 27 | State 2: The transition to state 2 triggers replacing the special sector 0 with |
| 28 | the normal sector 0, and the freeing of all state information. dm_bow then |
| 29 | becomes a pass-through driver, allowing the device to continue to be used with |
| 30 | minimal performance impact. |
| 31 | |
| 32 | Usage |
| 33 | ===== |
| 34 | dm-bow takes one command line parameter, the name of the underlying device. |
| 35 | |
| 36 | dm-bow will typically be used in the following way. dm-bow will be loaded with a |
| 37 | suitable underlying device and the resultant device will be mounted. A file |
| 38 | system trim will be issued via the FITRIM ioctl, then the device will be |
| 39 | switched to state 1. The file system will now be used as normal. At some point, |
| 40 | the changes can either be committed by switching to state 2, or rolled back by |
| 41 | unmounting the file system, removing the dm-bow device and running the command |
| 42 | line utility. Note that rebooting the device will be equivalent to unmounting |
| 43 | and removing, but the command line utility must still be run |
| 44 | |
| 45 | Details of operation in state 1 |
| 46 | =============================== |
| 47 | |
| 48 | dm_bow maintains a type for all sectors. A sector can be any of: |
| 49 | |
| 50 | SECTOR0 |
| 51 | SECTOR0_CURRENT |
| 52 | UNCHANGED |
| 53 | FREE |
| 54 | CHANGED |
| 55 | BACKUP |
| 56 | |
| 57 | SECTOR0 is the first sector on the device, and is used to hold the log of |
| 58 | changes. This is the one exception. |
| 59 | |
| 60 | SECTOR0_CURRENT is a sector picked from the FREE sectors, and is where reads and |
| 61 | writes from the true sector zero are redirected to. Note that like any backup |
| 62 | sector, if the sector is written to directly, it must be moved again. |
| 63 | |
| 64 | UNCHANGED means that the sector has not been changed since we entered state 1. |
| 65 | Thus if it is written to or trimmed, the contents must first be backed up. |
| 66 | |
| 67 | FREE means that the sector was trimmed in state 0 and has not yet been written |
| 68 | to or used for backup. On being written to, a FREE sector is changed to CHANGED. |
| 69 | |
| 70 | CHANGED means that the sector has been modified, and can be further modified |
| 71 | without further backup. |
| 72 | |
| 73 | BACKUP means that this is a free sector being used as a backup. On being written |
| 74 | to, the contents must first be backed up again. |
| 75 | |
| 76 | All backup operations are logged to the first sector. The log sector has the |
| 77 | format: |
| 78 | -------------------------------------------------------- |
| 79 | | Magic | Count | Sequence | Log entry | Log entry | … |
| 80 | -------------------------------------------------------- |
| 81 | |
| 82 | Magic is a magic number. Count is the number of log entries. Sequence is 0 |
| 83 | initially. A log entry is |
| 84 | |
| 85 | ----------------------------------- |
| 86 | | Source | Dest | Size | Checksum | |
| 87 | ----------------------------------- |
| 88 | |
| 89 | When SECTOR0 is full, the log sector is backed up and another empty log sector |
| 90 | created with sequence number one higher. The first entry in any log entry with |
| 91 | sequence > 0 therefore must be the log of the backing up of the previous log |
| 92 | sector. Note that sequence is not strictly needed, but is a useful sanity check |
| 93 | and potentially limits the time spent trying to restore a corrupted snapshot. |
| 94 | |
| 95 | On entering state 1, dm_bow has a list of free sectors. All other sectors are |
| 96 | unchanged. Sector0_current is selected from the free sectors and the contents of |
| 97 | sector 0 are copied there. The sector 0 is backed up, which triggers the first |
| 98 | log entry to be written. |
| 99 | |