Skip to content

Commit 6a3bdd6

Browse files
authored
Remove local storage parent dataset's reservation (#10126)
If you have a parent dataset that has a reservation, and a child dataset has a bunch of data, you can run into an out-of-space issue when deleting the child dataset if the pool is nearly full: when you delete the child dataset, it moves into a "to be deleted" area in the background, but the space is still used by the child (this amount can be accessed by querying for the `freeing` property of the pool). This, combined with a parent dataset that has a reservation, causes the amount of free space in the pool to go down, so before deleting the volume, remove the reservation set for the parent dataset if one exists. Fixes #10035
1 parent 04dae50 commit 6a3bdd6

2 files changed

Lines changed: 70 additions & 0 deletions

File tree

illumos-utils/src/zfs.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,40 @@ pub struct DatasetVolumeDeleteArgs<'a> {
11291129
pub raw: bool,
11301130
}
11311131

1132+
/// Error returned by [`Zfs::remove_reservation`].
1133+
#[derive(thiserror::Error, Debug)]
1134+
#[error("Failed to remove reservation from '{name}': {err}")]
1135+
pub struct RemoveReservationError {
1136+
name: String,
1137+
#[source]
1138+
err: RemoveReservationErrorInner,
1139+
}
1140+
1141+
impl RemoveReservationError {
1142+
pub fn get_value(name: String, err: GetValueError) -> Self {
1143+
RemoveReservationError {
1144+
name,
1145+
err: RemoveReservationErrorInner::GetValue(err),
1146+
}
1147+
}
1148+
1149+
pub fn set_value(name: String, err: SetValueError) -> Self {
1150+
RemoveReservationError {
1151+
name,
1152+
err: RemoveReservationErrorInner::SetValue(err),
1153+
}
1154+
}
1155+
}
1156+
1157+
#[derive(thiserror::Error, Debug)]
1158+
pub enum RemoveReservationErrorInner {
1159+
#[error(transparent)]
1160+
GetValue(#[from] GetValueError),
1161+
1162+
#[error(transparent)]
1163+
SetValue(#[from] SetValueError),
1164+
}
1165+
11321166
impl Zfs {
11331167
/// Lists all datasets within a pool or existing dataset.
11341168
///
@@ -2128,6 +2162,23 @@ impl Zfs {
21282162
}
21292163
}
21302164
}
2165+
2166+
/// Remove a dataset's reservation, if set
2167+
pub async fn remove_reservation(
2168+
name: &str,
2169+
) -> Result<(), RemoveReservationError> {
2170+
let value = Zfs::get_value(name, "reservation").await.map_err(|e| {
2171+
RemoveReservationError::get_value(name.to_string(), e)
2172+
})?;
2173+
2174+
if value != "none" {
2175+
Zfs::set_value(name, "reservation", "none").await.map_err(|e| {
2176+
RemoveReservationError::set_value(name.to_string(), e)
2177+
})?;
2178+
}
2179+
2180+
Ok(())
2181+
}
21312182
}
21322183

21332184
/// A read-only snapshot of a ZFS filesystem.

sled-agent/src/sled_agent.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,25 @@ impl SledAgent {
15071507
DelegatedZvol::LocalStorageUnencrypted { zpool_id, dataset_id }
15081508
};
15091509

1510+
// If you have a parent dataset that has a reservation, and a child
1511+
// dataset has a bunch of data, you can run into an out-of-space issue
1512+
// when deleting the child dataset if the pool is nearly full: when you
1513+
// delete the child dataset, it moves into a "to be deleted" area in the
1514+
// background, but the space is still used by the child (this amount can
1515+
// be accessed by querying for the `freeing` property of the pool).
1516+
//
1517+
// This, combined with a parent dataset that has a reservation, causes
1518+
// the amount of free space in the pool to go down, so before deleting
1519+
// the volume, remove the reservation set for the parent dataset if one
1520+
// exists.
1521+
1522+
Zfs::remove_reservation(&delegated_zvol.parent_dataset_name())
1523+
.await
1524+
.map_err(|e| HttpError::for_internal_error(e.to_string()))?;
1525+
1526+
// Then proceed with deleting the child volume dataset, then the parent
1527+
// dataset
1528+
15101529
Zfs::delete_dataset_volume(DatasetVolumeDeleteArgs {
15111530
name: &delegated_zvol.volume_name(),
15121531
raw: true,

0 commit comments

Comments
 (0)