Skip to content
Permalink
Browse files

Add ATA trim support, trim sectors which are no longer used.

  • Loading branch information...
ticki committed Jun 14, 2017
1 parent 37af41b commit bce6ea1e608094197ee8a41004d358d26bf92004
Showing with 54 additions and 25 deletions.
  1. +6 −11 core/src/alloc/mod.rs
  2. +13 −6 core/src/disk/cache.rs
  3. +7 −0 core/src/disk/mod.rs
  4. +28 −8 core/src/disk/vdev.rs
@@ -348,13 +348,6 @@ impl<D: Disk> Allocator<D> {
})
}

/// Drop a sector from the cache.
pub fn forget(&self, page: page::Pointer) {
// TODO: This potentially forgets more than one pages (the whole cluster). Someone should
// do something about it.
self.cache.forget(page.cluster)
}

/// Calculate the checksum of some buffer, based on the user choice.
fn checksum(&self, buf: &disk::SectorBuf) -> u64 {
trace!(self, "calculating checksum");
@@ -506,10 +499,8 @@ impl<D: Disk> Allocator<D> {
// Finally we push the old head to the vector, as it is free now.
free.push(old_head);

// Drop the old metacluster from the cache.
self.cache.forget(old_head)?;

free
// Trim the old metacluster.
self.cache.trim(old_head).map(|_| free)
})
}).and_then(|free| {
// Finally, we must flush the state block before we can add the found clutters
@@ -537,10 +528,14 @@ impl<D: Disk> Allocator<D> {
fn freelist_push(&mut self, cluster: cluster::Pointer) {
trace!(self, "pushing to freelist"; "cluster" => cluster);

// Push the cluster to the freelist.
self.free.push(cluster);
}

pub fn flush_free(&self) {
// TODO: Important!! Remember to trim the sectors which gets dealloc'd. This can be done
// through `self.cache.trim`

/* TODO (buggy and incomplete)
let state = self.state.lock();
let mut (cluster, cksum) = state.freelist_head.map_or(|x| (x.cluster, x.checksum), (0, 0));
@@ -50,14 +50,21 @@ impl<D: Disk> Cached<D> {
self.disk.write(sector, &buf)
}

/// Drop a sector from the cache.
fn forget(&self, sector: disk::Sector) {
debug!(self, "removing sector from cache"; "sector" => sector);
/// Drop a sector from the cache and trim it.
///
/// After this has been completed, the data of the sector shall not be read, until some other
/// data has been written to the sector.
///
/// Note that it doesn't necessarily "wipe" the data.
fn trim(&self, sector: disk::Sector) -> future!(()) {
debug!(self, "wiping sector"; "sector" => sector);

// Update the cache tracker.
self.tracker.remove(sector);
// Update the sector map.
self.sectors.remove(sector);
// Finally, trim the sector.
self.disk.trim(sector)
}

/// Read a sector.
@@ -95,11 +102,11 @@ impl<D: Disk> Cached<D> {
}
}

/// Trim the cache.
/// Reduce the cache.
///
/// This reduces the cache to exactly `to` blocks.
fn trim(&self, to: usize) {
info!(self, "trimming cache"; "to" => to);
fn reduce(&self, to: usize) {
info!(self, "reducing cache"; "to" => to);

// Lock the cache tracker.
let tracker = self.tracker.lock();
@@ -46,6 +46,8 @@ pub trait Disk: slog::Drain {
type ReadFuture: Future<Item = Box<SectorBuf>, Error = Error>;
/// The future returned from write operations.
type WriteFuture: Future<Item = (), Error = Error>;
/// The future returned from the trim operations.
type TrimFuture: Future<Item = (), Error = Error>;

/// The number of sectors on this disk.
fn number_of_sectors(&self) -> Sector;
@@ -59,6 +61,11 @@ pub trait Disk: slog::Drain {
/// This returns a future, which carries the operation writing `buf` into sector `sector`.
/// First when the future has completed, the operation has been executed.
fn write(&self, sector: Sector, buf: &SectorBuf) -> Self::WriteFuture;
/// Inform the disk that a sector is no longer in use.
///
/// This returns a future, which carries the operation trimming sector `sector`. First when the
/// future has completed, the operation has been executed.
fn trim(&self, sector: Sector) -> Self::TrimFuture;

/// Create a cached version of the disk.
fn cached(self) -> cache::Cached<Self> {
@@ -134,6 +134,7 @@ delegate_log!(Driver.disk);
impl<D: Disk> Disk for Driver<D> {
type ReadFuture = D::ReadFuture;
type WriteFuture = D::WriteFuture;
type TrimFuture = D::TrimFuture;

fn number_of_sectors(&self) -> disk::Sector {
// Start out with the raw number of sectors. We subtract one to cut of the disk header.
@@ -174,14 +175,10 @@ impl<D: Disk> Disk for Driver<D> {
// Go over the vdev stack.
for vdev in self.header.vdev_stack {
match vdev {
header::Vdev::Mirror => {
let prev_writes = mem::replace(writes, Vec::with_capacity(writes.len() * 2));
for (sector, buf) in prev_writes {
// Write the lower half.
writes.push((sector, buf));
// Write the upper half.
writes.push((2 * sector, buf));
}
// Mirror the higher and lower half.
header::Vdev::Mirror => for i in 0..writes.len() {
// Write the higher half.
writes.push((writes[i].0 * 2, writes[i].1));
},
// TODO
header::Vdev::Speck => unimplemented!(),
@@ -193,4 +190,27 @@ impl<D: Disk> Disk for Driver<D> {
self.disk.write(sector, buf)
}))
}

fn trim(&self, sector: disk::Sector) -> D::TrimFuture {
// Start a vector to track what sectors to trim.
let mut trims = vec![sector];

// Go over the vdev stack.
for vdev in self.header.vdev_stack {
match vdev {
// Mirror the higher and lower half.
header::Vdev::Mirror => for i in 0..writes.len() {
// Trim the higher half's sector.
trims.push(trims[i]);
},
// Encryption doesn't matter for trimming.
header::Vdev::Speck => (),
}
}

// Execute all the trims, we've buffered.
future::join_all(trims.into_iter().map(|sector| {
self.disk.trim(sector)
}))
}
}

0 comments on commit bce6ea1

Please sign in to comment.
You can’t perform that action at this time.