io_block/os/
linux.rs

1// ioctl
2//  BLKSSZGET - bdev_logical_block_size() - logical, int
3//  BLKPBSZGET - bdev_physical_block_size() - physical, uint
4
5//  BLKBSZGET - block_size() - ????, int
6//  BLKBSZSET - ??? set block size ???
7
8// align-offset
9// discard-zero
10// rotational
11
12use std::ffi::{c_int, c_uint, c_ushort};
13use std::fs::File;
14use std::io;
15use std::io::Result;
16use std::os::unix::fs::FileTypeExt;
17use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
18
19use nix::{ioctl_none, ioctl_read, ioctl_read_bad, ioctl_write_ptr_bad, request_code_none};
20
21use crate::BlockSize;
22
23ioctl_read_bad! {blksectget, request_code_none!(0x12, 103), c_ushort}
24ioctl_read_bad! {blksszget, request_code_none!(0x12, 104), c_int}
25ioctl_read! {blkbszget, 0x12, 112, c_int}
26ioctl_read! {blkgetsize64, 0x12, 114, u64}
27ioctl_read_bad! {blkiomin, request_code_none!(0x12, 120), c_uint}
28ioctl_read_bad! {blkioopt, request_code_none!(0x12, 121), c_uint}
29ioctl_read_bad! {blkalignoff, request_code_none!(0x12, 122), c_int}
30ioctl_read_bad! {blkpbszget, request_code_none!(0x12, 123), c_uint}
31ioctl_read_bad! {blkdiscardzeroes, request_code_none!(0x12, 124), c_uint}
32ioctl_write_ptr_bad! {blkdiscard, request_code_none!(0x12, 119), [u64; 2]}
33
34ioctl_read_bad! {blkroget, request_code_none!(0x12, 93), c_int}
35ioctl_write_ptr_bad! {blkroset, request_code_none!(0x12, 94), c_int}
36ioctl_none! {blkflsbuf, 0x12, 97}
37
38/*
39#define BLKROSET   _IO(0x12,93)	/* set device read-only (0 = read-write) */
40#define BLKROGET   _IO(0x12,94)	/* get read-only status (0 = read_write) */
41#define BLKRRPART  _IO(0x12,95)	/* re-read partition table */
42#define BLKGETSIZE _IO(0x12,96)	/* return device size /512 (long *arg) */
43#define BLKFLSBUF  _IO(0x12,97)	/* flush buffer cache */
44#define BLKRASET   _IO(0x12,98)	/* set read ahead for block device */
45#define BLKRAGET   _IO(0x12,99)	/* get current read ahead setting */
46#define BLKFRASET  _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
47#define BLKFRAGET  _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
48#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
49#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
50#define BLKSSZGET  _IO(0x12,104)/* get block device sector size */
51
52
53#define BLKBSZGET  _IOR(0x12,112,size_t)
54#define BLKBSZSET  _IOW(0x12,113,size_t)
55#define BLKGETSIZE64 _IOR(0x12,114,size_t)	/* return device size in bytes (u64 *arg) */
56#define BLKTRACESETUP _IOWR(0x12,115,struct blk_user_trace_setup)
57#define BLKTRACESTART _IO(0x12,116)
58#define BLKTRACESTOP _IO(0x12,117)
59#define BLKTRACETEARDOWN _IO(0x12,118)
60#define BLKDISCARD _IO(0x12,119)
61#define BLKIOMIN _IO(0x12,120)
62#define BLKIOOPT _IO(0x12,121)
63#define BLKALIGNOFF _IO(0x12,122)
64#define BLKPBSZGET _IO(0x12,123)
65#define BLKDISCARDZEROES _IO(0x12,124)
66#define BLKSECDISCARD _IO(0x12,125)
67#define BLKROTATIONAL _IO(0x12,126)
68#define BLKZEROOUT _IO(0x12,127)
69#define BLKGETDISKSEQ _IOR(0x12,128,__u64)
70*/
71
72pub struct BlockDev {
73    // TODO: consider generalizing for other AsRawFd types
74    // TODO: consider just storing a RawFd instead of a File
75    inner: File,
76}
77
78impl AsRawFd for BlockDev {
79    fn as_raw_fd(&self) -> RawFd {
80        self.inner.as_raw_fd()
81    }
82}
83
84impl FromRawFd for BlockDev {
85    unsafe fn from_raw_fd(fd: RawFd) -> BlockDev {
86        BlockDev::from_file_raw(File::from_raw_fd(fd))
87    }
88}
89
90impl IntoRawFd for BlockDev {
91    fn into_raw_fd(self) -> RawFd {
92        self.inner.into_raw_fd()
93    }
94}
95
96impl BlockDev {
97    /// Treat a file as a block device without checking
98    ///
99    /// # Safety
100    ///
101    /// `i` must refer to a block device file, otherwise the ioctls used by other functions may
102    /// have undesired effects, including reading and writing memory unexpectedly.
103    pub unsafe fn from_file_raw(i: File) -> BlockDev {
104        BlockDev { inner: i }
105    }
106
107    pub fn from_file(i: File) -> io::Result<BlockDev> {
108        let m = i.metadata()?;
109        if !m.file_type().is_block_device() {
110            return Err(io::Error::new(
111                io::ErrorKind::InvalidInput,
112                "Not a block device",
113            ));
114        }
115
116        Ok(unsafe { BlockDev::from_file_raw(i) })
117    }
118
119    pub fn ro(&self) -> io::Result<bool> {
120        let mut c: c_int = 0;
121        unsafe { blkroget(self.as_raw_fd(), &mut c) }
122            .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
123
124        Ok(c != 0)
125    }
126
127    pub fn block_io_min(&self) -> Result<u32> {
128        let mut c: c_uint = 0;
129        unsafe { blkiomin(self.as_raw_fd(), &mut c) }
130            .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
131
132        Ok(c)
133    }
134}
135
136impl BlockSize for BlockDev {
137    fn block_size_logical(&self) -> Result<u64> {
138        let mut c: c_int = 0;
139        unsafe { blksszget(self.as_raw_fd(), &mut c) }
140            .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
141
142        Ok(c as u64)
143    }
144
145    fn block_count(&self) -> Result<u64> {
146        let mut c: u64 = 0;
147        unsafe { blkgetsize64(self.as_raw_fd(), &mut c) }
148            .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
149
150        Ok(c)
151    }
152
153    fn block_size_physical(&self) -> Result<u64> {
154        let mut c: c_uint = 0;
155        unsafe { blkpbszget(self.as_raw_fd(), &mut c) }
156            .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
157
158        Ok(c as u64)
159    }
160}