get device info with libc using major/minor
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
203cf57fdf
commit
2bbb28bb88
5 changed files with 64 additions and 103 deletions
75
Cargo.lock
generated
75
Cargo.lock
generated
|
@ -726,6 +726,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"ipaddress",
|
"ipaddress",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
|
"libc",
|
||||||
"libloading",
|
"libloading",
|
||||||
"log",
|
"log",
|
||||||
"nix",
|
"nix",
|
||||||
|
@ -739,7 +740,6 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_regex",
|
"serde_regex",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sysinfo",
|
|
||||||
"thiserror 2.0.7",
|
"thiserror 2.0.7",
|
||||||
"tikv-jemalloc-ctl",
|
"tikv-jemalloc-ctl",
|
||||||
"tikv-jemalloc-sys",
|
"tikv-jemalloc-sys",
|
||||||
|
@ -1674,7 +1674,7 @@ checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"windows 0.52.0",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4076,18 +4076,6 @@ dependencies = [
|
||||||
"syn 2.0.90",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sysinfo"
|
|
||||||
version = "0.33.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
"serde",
|
|
||||||
"windows 0.57.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tendril"
|
name = "tendril"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -4945,17 +4933,7 @@ version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core 0.52.0",
|
"windows-core",
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.57.0",
|
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4968,60 +4946,17 @@ dependencies = [
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-implement",
|
|
||||||
"windows-interface",
|
|
||||||
"windows-result 0.1.2",
|
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-implement"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-interface"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-registry"
|
name = "windows-registry"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
|
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-result 0.2.0",
|
"windows-result",
|
||||||
"windows-strings",
|
"windows-strings",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-result"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -5037,7 +4972,7 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-result 0.2.0",
|
"windows-result",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -498,10 +498,8 @@ version = "1.3.0"
|
||||||
[workspace.dependencies.core_affinity]
|
[workspace.dependencies.core_affinity]
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
|
||||||
[workspace.dependencies.sysinfo]
|
[workspace.dependencies.libc]
|
||||||
version = "0.33.0"
|
version = "0.2"
|
||||||
default-features = false
|
|
||||||
features = ["disk", "serde"]
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Patches
|
# Patches
|
||||||
|
|
|
@ -75,6 +75,7 @@ http.workspace = true
|
||||||
image.workspace = true
|
image.workspace = true
|
||||||
ipaddress.workspace = true
|
ipaddress.workspace = true
|
||||||
itertools.workspace = true
|
itertools.workspace = true
|
||||||
|
libc.workspace = true
|
||||||
libloading.workspace = true
|
libloading.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
|
@ -87,7 +88,6 @@ serde_json.workspace = true
|
||||||
serde_regex.workspace = true
|
serde_regex.workspace = true
|
||||||
serde_yaml.workspace = true
|
serde_yaml.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
sysinfo.workspace = true
|
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tikv-jemallocator.optional = true
|
tikv-jemallocator.optional = true
|
||||||
tikv-jemallocator.workspace = true
|
tikv-jemallocator.workspace = true
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
//! System utilities related to devices/peripherals
|
//! System utilities related to devices/peripherals
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::OsStr,
|
||||||
fs,
|
fs,
|
||||||
fs::{read_to_string, FileType},
|
fs::{read_to_string, FileType},
|
||||||
iter::IntoIterator,
|
iter::IntoIterator,
|
||||||
path::Path,
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{result::FlatOk, Result};
|
use libc::dev_t;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
result::FlatOk,
|
||||||
|
utils::{result::LogDebugErr, string::SplitInfallible},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
|
|
||||||
/// Device characteristics useful for random access throughput
|
/// Device characteristics useful for random access throughput
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
|
@ -35,16 +41,12 @@ pub struct Queue {
|
||||||
|
|
||||||
/// Get device characteristics useful for random access throughput by name.
|
/// Get device characteristics useful for random access throughput by name.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn parallelism(name: &OsStr) -> Parallelism {
|
pub fn parallelism(path: &Path) -> Parallelism {
|
||||||
let name = name
|
let dev_id = dev_from_path(path).log_debug_err().unwrap_or_default();
|
||||||
.to_str()
|
|
||||||
.expect("device name expected to be utf-8 representable");
|
|
||||||
|
|
||||||
let block_path = Path::new("/").join("sys/").join("block/");
|
let mq_path = block_path(dev_id).join("mq/");
|
||||||
|
|
||||||
let mq_path = Path::new(&block_path).join(format!("{name}/mq/"));
|
let nr_requests_path = block_path(dev_id).join("queue/nr_requests");
|
||||||
|
|
||||||
let nr_requests_path = Path::new(&block_path).join(format!("{name}/queue/nr_requests"));
|
|
||||||
|
|
||||||
Parallelism {
|
Parallelism {
|
||||||
nr_requests: read_to_string(&nr_requests_path)
|
nr_requests: read_to_string(&nr_requests_path)
|
||||||
|
@ -96,17 +98,39 @@ fn queue_parallelism(dir: &Path) -> Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the name of the device on which Path is mounted.
|
/// Get the name of the block device on which Path is mounted.
|
||||||
#[must_use]
|
pub fn name_from_path(path: &Path) -> Result<String> {
|
||||||
pub fn name_from_path(path: &Path) -> Option<OsString> {
|
use std::io::{Error, ErrorKind::NotFound};
|
||||||
sysinfo::Disks::new_with_refreshed_list()
|
|
||||||
.into_iter()
|
let (major, minor) = dev_from_path(path)?;
|
||||||
.filter(|disk| path.starts_with(disk.mount_point()))
|
let path = block_path((major, minor)).join("uevent");
|
||||||
.max_by(|a, b| {
|
read_to_string(path)
|
||||||
let a = a.mount_point().ancestors().count();
|
.iter()
|
||||||
let b = b.mount_point().ancestors().count();
|
.map(String::as_str)
|
||||||
a.cmp(&b)
|
.flat_map(str::lines)
|
||||||
})
|
.map(|line| line.split_once_infallible("="))
|
||||||
.map(|disk| Path::new(disk.name()))
|
.find_map(|(key, val)| (key == "DEVNAME").then_some(val))
|
||||||
.and_then(|path| path.file_name().map(ToOwned::to_owned))
|
.ok_or_else(|| Error::new(NotFound, "DEVNAME not found."))
|
||||||
|
.map_err(Into::into)
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the (major, minor) of the block device on which Path is mounted.
|
||||||
|
#[allow(clippy::useless_conversion, clippy::unnecessary_fallible_conversions)]
|
||||||
|
pub fn dev_from_path(path: &Path) -> Result<(dev_t, dev_t)> {
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
let stat = fs::metadata(path)?;
|
||||||
|
let dev_id = stat.dev().try_into()?;
|
||||||
|
|
||||||
|
// SAFETY: These functions may not need to be marked as unsafe.
|
||||||
|
// see: https://github.com/rust-lang/libc/issues/3759
|
||||||
|
let (major, minor) = unsafe { (libc::major(dev_id), libc::minor(dev_id)) };
|
||||||
|
|
||||||
|
Ok((major.try_into()?, minor.try_into()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_path((major, minor): (dev_t, dev_t)) -> PathBuf {
|
||||||
|
format!("/sys/dev/block/{major}:{minor}/").into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use std::{ffi::OsStr, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
debug, debug_info, expected,
|
debug, debug_info, expected,
|
||||||
utils::{
|
utils::{
|
||||||
math::usize_from_f64,
|
math::usize_from_f64,
|
||||||
|
result::LogDebugErr,
|
||||||
stream,
|
stream,
|
||||||
stream::WIDTH_LIMIT,
|
stream::WIDTH_LIMIT,
|
||||||
sys::{compute::is_core_available, storage},
|
sys::{compute::is_core_available, storage},
|
||||||
|
@ -20,8 +21,12 @@ pub(super) fn configure(server: &Arc<Server>) -> (usize, Vec<usize>, Vec<usize>)
|
||||||
// This finds the block device and gathers all the properties we need.
|
// This finds the block device and gathers all the properties we need.
|
||||||
let (device_name, device_prop) = config
|
let (device_name, device_prop) = config
|
||||||
.db_pool_affinity
|
.db_pool_affinity
|
||||||
.and_then(|| storage::name_from_path(&config.database_path))
|
.and_then(|| {
|
||||||
.map(|device_name| (device_name.clone(), storage::parallelism(&device_name)))
|
let path: PathBuf = config.database_path.clone();
|
||||||
|
let name = storage::name_from_path(&path).log_debug_err().ok();
|
||||||
|
let prop = storage::parallelism(&path);
|
||||||
|
name.map(|name| (name, prop))
|
||||||
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
// The default worker count is masked-on if we didn't find better information.
|
// The default worker count is masked-on if we didn't find better information.
|
||||||
|
@ -104,7 +109,6 @@ pub(super) fn configure(server: &Arc<Server>) -> (usize, Vec<usize>, Vec<usize>)
|
||||||
debug_info!(
|
debug_info!(
|
||||||
device_name = ?device_name
|
device_name = ?device_name
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.and_then(OsStr::to_str)
|
|
||||||
.unwrap_or("None"),
|
.unwrap_or("None"),
|
||||||
?worker_counts,
|
?worker_counts,
|
||||||
?queue_sizes,
|
?queue_sizes,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue