Skip to main content

btrfs_uapi/
blkdev.rs

1//! # Block device ioctls: BLKGETSIZE64, BLKDISCARD
2//!
3//! Standard Linux block device ioctls that are not btrfs-specific but are
4//! needed for device preparation (e.g. querying device size, issuing TRIM).
5
6use std::os::{fd::AsRawFd, unix::io::BorrowedFd};
7
8// From linux/fs.h:
9// #define BLKGETSIZE64 _IOR(0x12, 114, size_t)
10// #define BLKDISCARD   _IO(0x12, 119)
11nix::ioctl_read!(blk_getsize64, 0x12, 114, u64);
12nix::ioctl_write_ptr!(blk_discard, 0x12, 119, [u64; 2]);
13
14/// Get the size of a block device in bytes.
15pub fn device_size(fd: BorrowedFd) -> nix::Result<u64> {
16    let mut size: u64 = 0;
17    unsafe { blk_getsize64(fd.as_raw_fd(), &mut size) }?;
18    Ok(size)
19}
20
21/// Issue a BLKDISCARD (TRIM) on the given byte range of a block device.
22///
23/// Tells the device that the specified range is no longer in use and its
24/// contents can be discarded. This is typically done before repurposing a
25/// device (e.g. as a replace target).
26pub fn discard_range(
27    fd: BorrowedFd,
28    offset: u64,
29    length: u64,
30) -> nix::Result<()> {
31    let range: [u64; 2] = [offset, length];
32    unsafe { blk_discard(fd.as_raw_fd(), &range) }?;
33    Ok(())
34}
35
36/// Issue a BLKDISCARD on the entire block device.
37///
38/// Returns the number of bytes discarded (the device size), or an error.
39/// Silently ignores EOPNOTSUPP (device does not support discard).
40pub fn discard_whole_device(fd: BorrowedFd) -> nix::Result<u64> {
41    let size = device_size(fd)?;
42    if size == 0 {
43        return Ok(0);
44    }
45    match discard_range(fd, 0, size) {
46        Ok(()) => Ok(size),
47        Err(nix::errno::Errno::EOPNOTSUPP) => Ok(0),
48        Err(e) => Err(e),
49    }
50}