fix block devices getting reported as 0 size

This commit is contained in:
Robin Appelman 2023-06-10 00:11:35 +02:00
commit 7d7c252eea
5 changed files with 94 additions and 43 deletions

8
flake.lock generated
View file

@ -17,16 +17,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1685043448,
"narHash": "sha256-U3BwyDc2OzBcZ8tD09qXibyivgOtOQFTFCVgFyJ+6MM=",
"lastModified": 1686237827,
"narHash": "sha256-fAZB+Zkcmc+qlauiFnIH9+2qgwM0NO/ru5pWEw3tDow=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9886352ec9ab3945896ee8a4185e961fe29df209",
"rev": "81ed90058a851eb73be835c770e062c6938c8a9e",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-22.11",
"ref": "nixos-23.05",
"type": "indirect"
}
},

View file

@ -1,41 +1,33 @@
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "nixpkgs/nixos-22.11";
nixpkgs.url = "nixpkgs/nixos-23.05";
};
outputs = { self, nixpkgs, flake-utils }: let
buildCube = pkgs: pkgs.rustPlatform.buildRustPackage rec {
version = "0.1.0";
pname = "cube";
src = ./.;
cargoSha256 = "sha256-tHcIwMQrGIRC6W0/B476QT5nOUY/5KkzEeJKbg3sFUA=";
meta = with pkgs.lib; {
description = "A basic NBD block server with a single gimmick";
homepage = "https://github.com/icewind1991/cube";
license = licenses.mit;
platforms = platforms.linux;
};
};
in flake-utils.lib.eachDefaultSystem (
outputs = {
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system: let
pkgs = nixpkgs.legacyPackages."${system}";
in
rec {
pkgs = (import nixpkgs) {
inherit system;
};
in rec {
# `nix build`
packages.cube = buildCube pkgs;
defaultPackage = packages.cube;
defaultApp = packages.cube;
packages = rec {
cube = pkgs.callPackage (import ./package.nix) {};
default = cube;
};
# `nix develop`
devShell = pkgs.mkShell {
devShells.default = pkgs.mkShell {
nativeBuildInputs = with pkgs; [rustc cargo bacon cargo-edit cargo-outdated];
};
}
) // {
)
// {
nixosModule = {
config,
lib,
@ -43,16 +35,18 @@
...
}:
with lib; let
cube = buildCube pkgs;
cube = pkgs.callPackage (import ./package.nix) {};
cfg = config.services.cube;
format = pkgs.formats.toml {};
configFile = format.generate "cube.toml" ({
configFile = format.generate "cube.toml" {
inherit (cfg) listen;
exports = mapAttrs (_: export: {
exports =
mapAttrs (_: export: {
inherit (export) path;
read_only = export.readOnly;
}) cfg.exports;
});
})
cfg.exports;
};
pkg = self.defaultPackage.${pkgs.system};
in {
options.services.cube = {

23
package.nix Normal file
View file

@ -0,0 +1,23 @@
{
rustPlatform,
lib,
}: let
src = lib.sources.sourceByRegex (lib.cleanSource ./.) ["Cargo.*" "(src)(/.*)?"];
in
rustPlatform.buildRustPackage rec {
version = "0.1.0";
pname = "cube";
inherit src;
cargoLock = {
lockFile = ./Cargo.lock;
};
meta = with lib; {
description = "A basic NBD block server with a single gimmick";
homepage = "https://github.com/icewind1991/cube";
license = licenses.mit;
platforms = platforms.linux;
};
}

View file

@ -7,6 +7,7 @@ use std::fs::{read_to_string, File, OpenOptions};
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use tracing::{debug, info};
#[derive(Debug, Deserialize)]
pub struct Config {
@ -103,6 +104,19 @@ impl ExportConfig {
err: e,
path: self.path.clone(),
})?;
let size = match meta.len() {
0 => {
let path = self.path.canonicalize().map_err(|e| HandshakeError::Open {
err: e,
path: self.path.clone(),
})?;
if path != self.path {
debug!(path = ?self.path, canonicalized = ?path, "path is configured in non canonicalized form");
}
get_block_size(&path).ok_or_else(|| HandshakeError::UnknownSize(path))?
}
size => size,
};
let readonly = self.readonly || meta.permissions().readonly();
let mut opt = OpenOptions::new();
@ -116,9 +130,11 @@ impl ExportConfig {
path: self.path.clone(),
})?;
info!(readonly, size, "go export meta");
Ok(Export {
readonly,
size: meta.len(),
size,
data: file,
resizeable: false,
rotational: false,
@ -128,6 +144,18 @@ impl ExportConfig {
}
}
#[tracing::instrument]
fn get_block_size(path: &Path) -> Option<u64> {
let device = path.strip_prefix("/dev").ok()?;
let mut sys_path = PathBuf::from("/sys/class/block");
sys_path.push(device);
sys_path.push("size");
debug!(sysfs_path = ?sys_path, "getting block size");
let size_str = read_to_string(sys_path).ok()?;
debug!(block_count = size_str, "got size");
size_str.trim().parse().ok().map(|blocks: u64| blocks * 512)
}
#[derive(Debug, Clone, Deserialize)]
#[serde(from = "HashMap<String, ExportConfig>")]
pub struct Exports {

View file

@ -53,6 +53,8 @@ pub enum HandshakeError {
UnknownExport(String),
#[error("Failed to open {path}")]
Open { path: PathBuf, err: IoError },
#[error("Failed to determine size of source {0:?}")]
UnknownSize(PathBuf),
}
impl From<HandshakeError> for IoError {
@ -62,6 +64,10 @@ impl From<HandshakeError> for IoError {
HandshakeError::UnknownExport(export) => {
IoError::new(ErrorKind::InvalidData, format!("Unknown export: {export}"))
}
HandshakeError::UnknownSize(path) => IoError::new(
ErrorKind::InvalidData,
format!("Failed to get size of: {path:?}"),
),
}
}
}