Skip to content

Commit 47cc240

Browse files
committed
device/block: Implement BLK{GETSIZE64,SSZGET,RRPART}
1 parent fe6fb84 commit 47cc240

2 files changed

Lines changed: 102 additions & 9 deletions

File tree

kernel/src/device/block/mod.rs

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ pub mod ram;
77
use crate::device::Device;
88
use crate::{
99
arch::virt::get_page_size,
10-
memory::{IovecIter, VirtAddr},
10+
memory::{IovecIter, VirtAddr, user::UserPtr},
1111
posix::errno::{EResult, Errno},
1212
process::Identity,
13+
uapi,
14+
util::mutex::spin::SpinMutex,
1315
vfs::{self, File, file::FileOps, fs::devtmpfs, inode::Mode},
1416
};
15-
use alloc::{format, sync::Arc, vec::Vec};
17+
use alloc::{collections::btree_map::BTreeMap, format, string::String, sync::Arc, vec::Vec};
1618

1719
pub use bio::{BioRequest, BlockLimits};
1820
pub use io::{BlockBuffer, BlockOp, BlockSegment};
@@ -256,6 +258,14 @@ pub fn BLOCK_STAGE() {
256258
.expect("Unable to create /dev/block");
257259
}
258260

261+
struct RegisteredDisk {
262+
device: Arc<dyn BlockDevice>,
263+
partition_nodes: Vec<String>,
264+
}
265+
266+
static REGISTERED_DISKS: SpinMutex<BTreeMap<String, RegisteredDisk>> =
267+
SpinMutex::new(BTreeMap::new());
268+
259269
/// Registers a block device by name and scans for partitions.
260270
pub fn register_block_device(name: &str, device: Arc<dyn BlockDevice>) -> EResult<()> {
261271
// Register in devtmpfs as well.
@@ -267,19 +277,63 @@ pub fn register_block_device(name: &str, device: Arc<dyn BlockDevice>) -> EResul
267277

268278
log!("Registered block device: \"{}\"", name);
269279

280+
REGISTERED_DISKS.lock().insert(
281+
String::from(name),
282+
RegisteredDisk {
283+
device: device.clone(),
284+
partition_nodes: Vec::new(),
285+
},
286+
);
287+
270288
// Scan for GPT partitions.
271289
scan_partitions(name, device)?;
272290

273291
Ok(())
274292
}
275293

294+
/// Looks up the registered name of a whole-disk block device.
295+
fn registered_disk_name(device: &dyn BlockDevice) -> Option<String> {
296+
let target = device as *const dyn BlockDevice as *const ();
297+
REGISTERED_DISKS
298+
.lock()
299+
.iter()
300+
.find(|(_, disk)| Arc::as_ptr(&disk.device) as *const () == target)
301+
.map(|(name, _)| name.clone())
302+
}
303+
304+
/// Drops every partition node of a disk and scans its partition table again.
305+
pub fn rescan_partitions(name: &str) -> EResult<()> {
306+
let (device, stale) = {
307+
let mut disks = REGISTERED_DISKS.lock();
308+
let disk = disks.get_mut(name).ok_or(Errno::ENODEV)?;
309+
(
310+
disk.device.clone(),
311+
core::mem::take(&mut disk.partition_nodes),
312+
)
313+
};
314+
315+
for node in stale {
316+
if let Err(e) = crate::device::unregister_node(node.as_bytes()) {
317+
log!(
318+
"Unable to remove stale partition node \"{}\": {:?}",
319+
node,
320+
e
321+
);
322+
}
323+
}
324+
325+
scan_partitions(name, device)
326+
}
327+
276328
/// Scans a block device for GPT partitions and registers each as a sub-device.
277329
fn scan_partitions(parent_name: &str, device: Arc<dyn BlockDevice>) -> EResult<()> {
278330
let partitions = match gpt::scan_gpt(device.clone()) {
279331
Ok(p) => p,
280332
Err(_) => return Ok(()), // No GPT found, that's fine.
281333
};
282334

335+
let mut nodes = Vec::new();
336+
283337
for (i, part) in partitions.iter().enumerate() {
284338
let part_name = format!("{}p{}", parent_name, i + 1);
285339
let part_dev = Arc::new(partition::PartitionDevice::new(
@@ -288,31 +342,45 @@ fn scan_partitions(parent_name: &str, device: Arc<dyn BlockDevice>) -> EResult<(
288342
part.end_lba - part.start_lba + 1,
289343
));
290344

345+
let node = format!("block/{}", part_name);
291346
crate::device::register_block_node(
292-
format!("block/{}", part_name).as_bytes(),
347+
node.as_bytes(),
293348
part_dev,
294349
Mode::from_bits_truncate(0o660),
295350
)?;
351+
nodes.push(node);
296352

297353
let root = devtmpfs::get_root();
298354
let uuid_str = part.unique_guid.to_string();
299355
let type_str = part.type_guid.to_string();
300356

301-
// TODO: This could conflict with other partitions.
302-
vfs::symlink(
357+
let type_link = format!("block/parttype-{}", type_str);
358+
match vfs::symlink(
303359
root.clone(),
304360
root.clone(),
305-
format!("block/parttype-{}", type_str).as_bytes(),
361+
type_link.as_bytes(),
306362
part_name.as_bytes(),
307363
&Identity::get_kernel(),
308-
)?;
364+
) {
365+
Ok(_) => nodes.push(type_link),
366+
Err(Errno::EEXIST) => log!(
367+
"Partition type {} already claimed, no \"{}\" link for \"{}\"",
368+
type_str,
369+
type_link,
370+
part_name
371+
),
372+
Err(e) => return Err(e),
373+
}
374+
375+
let uuid_link = format!("block/partuuid-{}", uuid_str);
309376
vfs::symlink(
310377
root.clone(),
311378
root.clone(),
312-
format!("block/partuuid-{}", uuid_str).as_bytes(),
379+
uuid_link.as_bytes(),
313380
part_name.as_bytes(),
314381
&Identity::get_kernel(),
315382
)?;
383+
nodes.push(uuid_link);
316384

317385
log!(
318386
"Partition {}: \"{}\" Type: {} UUID: {}",
@@ -323,6 +391,10 @@ fn scan_partitions(parent_name: &str, device: Arc<dyn BlockDevice>) -> EResult<(
323391
);
324392
}
325393

394+
if let Some(disk) = REGISTERED_DISKS.lock().get_mut(parent_name) {
395+
disk.partition_nodes = nodes;
396+
}
397+
326398
Ok(())
327399
}
328400

@@ -447,6 +519,23 @@ impl<T: BlockDevice> FileOps for T {
447519
}
448520

449521
fn ioctl(&self, file: &File, request: usize, arg: VirtAddr) -> EResult<usize> {
450-
self.handle_ioctl(file, request, arg)
522+
match request as u32 {
523+
uapi::ioctls::BLKGETSIZE64 => {
524+
let size = self.lba_count() * self.get_lba_size() as u64;
525+
UserPtr::new(arg).write(size).ok_or(Errno::EFAULT)?;
526+
Ok(0)
527+
}
528+
uapi::ioctls::BLKSSZGET => {
529+
let lba_size = self.get_lba_size() as u32;
530+
UserPtr::new(arg).write(lba_size).ok_or(Errno::EFAULT)?;
531+
Ok(0)
532+
}
533+
uapi::ioctls::BLKRRPART => {
534+
let name = registered_disk_name(self).ok_or(Errno::ENOTTY)?;
535+
rescan_partitions(&name)?;
536+
Ok(0)
537+
}
538+
_ => self.handle_ioctl(file, request, arg),
539+
}
451540
}
452541
}

kernel/src/uapi/ioctls.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,7 @@ pub const K_XLATE: u32 = 0x01;
157157
pub const K_MEDIUMRAW: u32 = 0x02;
158158
pub const K_UNICODE: u32 = 0x03;
159159
pub const K_OFF: u32 = 0x04;
160+
161+
pub const BLKGETSIZE64: u32 = ior::<u64>(b'B', 0x00);
162+
pub const BLKSSZGET: u32 = ior::<u32>(b'B', 0x01);
163+
pub const BLKRRPART: u32 = io(b'B', 0x02);

0 commit comments

Comments
 (0)