finish docs

This commit is contained in:
toninov 2025-10-12 20:21:29 +02:00
parent 10d5d294ee
commit fc671f3388
No known key found for this signature in database

View file

@ -61,10 +61,10 @@ Let us start with the FLUSH handler, and its helper functions:
```rust
fn flush() {
RWSEM.down_write();
down_write(RWSEM);
// Populate the FLUSH state, while we are holding the locks
err = prepare_cwbs();
RWSEM.up_write();
up_write(RWSEM);
// After unlocking, WRITEs and DISCARDs are no longer blocked and
// can go through, potentially re-dirtying the PosMap blocks
@ -74,13 +74,13 @@ fn flush() {
// It is important to first wait for all CWB callbacks to finish.
err = DEV.flush();
RWSEM.down_write();
down_write(RWSEM);
// Some blocks might be marked clean, some might not; the overall FLUSH
// operation is successful only if all CWBs were successful
err = mark_blocks_clean();
clear(CWB_ERROR);
clear(FLUSH_PENDING);
RWSEM.up_write();
up_write(RWSEM);
return err;
}
@ -174,10 +174,12 @@ Here, we only describe the critical section, rather than the whole handler.
```rust
fn write(lba) {
lsi = lba / 256; // 256 4-KiB blocks in a slice
block = lsi / 1024; // PosMap block this falls into
lsi = lba / 256; // There are 256 4-KiB blocks in a slice
block = lsi / 1024; // The PosMap block this falls into
RWSEM.down_write();
// Take both locks
RWSEM.down_read();
spin_lock(LOCK);
psi = ENTRIES[LSI];
// If LSI is unmapped, sample a new one and insert in PosMap
if (psi == 0xFFFFFFFF) {
@ -192,10 +194,55 @@ fn write(lba) {
DIRTY[lsi] = true;
SEQNUM[block]++; // Can wrap around
}
RWSEM.up_write();
spin_unlock(LOCK);
up_read(RWSEM);
}
```
We make sure not to increment the sequence number too many times (16384 times) while a FLUSH is executing; this way, the check `SNAP_SEQNUM[block] == SEQNUM[block]` is, as mentioned, sufficient for `mark_blocks_clean()` to conclude that the block was not re-dirtied.
We make sure not to increment the sequence number too many times (16384 times) while a FLUSH is executing; this way, the check `SNAP_SEQNUM[block] == SEQNUM[block]` is, as mentioned, sufficient for `mark_blocks_clean()` to conclude that the block was not re-dirtied. It is anyway overwhelmingly unlikely that the block gets re-dirtied 16384 times before its FLUSH can complete.
#### DISCARD
The DISCARD's critical section is similar to the WRITE's, in that it dirties a position map block, and increments the sequence number. Just, it does not also act on the device, so it does not need to take the per-device `spinlock`.
```rust
fn discard(lsi) {
block = lsi / 1024;
RWSEM.down_read();
spin_lock(LOCK);
psi = ENTRIES[LSI];
// Unmap LSI
if (psi != 0xFFFFFFFF) {
// If there's a FLUSH executing, ensure we don't increment the block's
// sequence number too many times
if (FLUSH_PENDING[block] && (SNAP_SEQNUM[block] + 1 == SEQNUM[block]))
return -EAGAIN; // Just try again later, after the FLUSH finished
ENTRIES[lsi] = 0xFFFFFFFF;
DIRTY[lsi] = true;
SEQNUM[block]++; // Can wrap around
}
spin_unlock(LOCK);
up_read(RWSEM);
}
```
#### READ
The READ handler only takes the `spinlock`, and not the `rwsem`. This allows for concurrency between the READ's and the FLUSH's critical sections: this is fine because READs only *read* the `entries` without writing anything, and because the FLUSH handler does not *write* to `entries`.
```rust
fn read(lba) {
lsi = lba / 256; // There are 256 4-KiB blocks in a slice
block = lsi / 1024; // The PosMap block this falls into
spin_lock(LOCK);
psi = ENTRIES[LSI];
spin_unlock(LOCK);
}
```