Skip to content

Commit 5385df5

Browse files
committed
fmt and follow up
Signed-off-by: Olga Andreeva <[email protected]>
1 parent 67aeefb commit 5385df5

File tree

1 file changed

+103
-37
lines changed
  • lib/llm/src/block_manager/storage

1 file changed

+103
-37
lines changed

lib/llm/src/block_manager/storage/disk.rs

Lines changed: 103 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ impl AlignedBuffer {
5656
let ptr = unsafe { std::alloc::alloc_zeroed(layout) };
5757

5858
if ptr.is_null() {
59-
anyhow::bail!("Failed to allocate aligned buffer of {} bytes", aligned_size);
59+
anyhow::bail!(
60+
"Failed to allocate aligned buffer of {} bytes",
61+
aligned_size
62+
);
6063
}
6164

6265
tracing::trace!(
@@ -130,7 +133,8 @@ fn allocate_file(fd: RawFd, size: u64) -> anyhow::Result<()> {
130133
buf.len()
131134
} else {
132135
// Last partial write - round up to page size for O_DIRECT
133-
let aligned = ((remaining as usize + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
136+
let aligned =
137+
((remaining as usize + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
134138
std::cmp::min(aligned, buf.len())
135139
};
136140

@@ -250,29 +254,88 @@ impl DiskStorage {
250254
let template = CString::new(file_path.to_str().unwrap()).unwrap();
251255
let mut template_bytes = template.into_bytes_with_nul();
252256

257+
// mkostemp only supports flags like O_CLOEXEC, not O_RDWR/O_DIRECT.
258+
// The file is always opened O_RDWR by mkostemp.
259+
// We'll use fcntl to set O_DIRECT after creation.
260+
let raw_fd = unsafe {
261+
nix::libc::mkostemp(
262+
template_bytes.as_mut_ptr() as *mut c_char,
263+
nix::libc::O_CLOEXEC,
264+
)
265+
};
266+
267+
if raw_fd < 0 {
268+
let file_name = CStr::from_bytes_with_nul(template_bytes.as_slice())
269+
.unwrap()
270+
.to_str()
271+
.unwrap_or("<invalid utf8>");
272+
return Err(StorageError::AllocationFailed(format!(
273+
"Failed to create temp file {}: {}",
274+
file_name,
275+
std::io::Error::last_os_error()
276+
)));
277+
}
278+
253279
// Determine whether to use O_DIRECT based on environment variable.
254280
// O_DIRECT is required for GPU DirectStorage but has strict alignment requirements.
255281
// For debugging or when filesystems don't support O_DIRECT alignment, it can be disabled.
256282
let disable_o_direct = std::env::var(DISK_DISABLE_O_DIRECT_KEY).is_ok();
257-
let flags = if disable_o_direct {
258-
tracing::warn!(
259-
"O_DIRECT disabled via {}. GPU DirectStorage performance may be reduced.",
260-
DISK_DISABLE_O_DIRECT_KEY
261-
);
262-
nix::libc::O_RDWR
263-
} else {
283+
284+
if !disable_o_direct {
285+
// Set O_DIRECT via fcntl after file creation.
264286
// For maximum performance, GPU DirectStorage requires O_DIRECT.
265287
// This allows transfers to bypass the kernel page cache.
266288
// It also introduces the restriction that all accesses must be page-aligned.
267-
nix::libc::O_RDWR | nix::libc::O_DIRECT
268-
};
289+
use nix::fcntl::{FcntlArg, OFlag, fcntl};
290+
291+
// Get current flags
292+
let current_flags = match fcntl(raw_fd, FcntlArg::F_GETFL) {
293+
Ok(flags) => OFlag::from_bits_truncate(flags),
294+
Err(e) => {
295+
unsafe { nix::libc::close(raw_fd) };
296+
let file_name = CStr::from_bytes_with_nul(template_bytes.as_slice())
297+
.unwrap()
298+
.to_str()
299+
.unwrap_or("<invalid utf8>");
300+
let _ = unlink(file_name);
301+
return Err(StorageError::AllocationFailed(format!(
302+
"Failed to get file flags for {}: {}",
303+
file_name, e
304+
)));
305+
}
306+
};
269307

270-
let raw_fd = unsafe {
271-
nix::libc::mkostemp(
272-
template_bytes.as_mut_ptr() as *mut c_char,
273-
flags,
274-
)
275-
};
308+
// Add O_DIRECT to existing flags
309+
let new_flags = current_flags | OFlag::O_DIRECT;
310+
311+
if let Err(e) = fcntl(raw_fd, FcntlArg::F_SETFL(new_flags)) {
312+
tracing::error!(
313+
"Failed to set O_DIRECT on file descriptor {}: {}. \
314+
This may indicate filesystem doesn't support O_DIRECT. \
315+
Consider setting {}=true to disable O_DIRECT.",
316+
raw_fd,
317+
e,
318+
DISK_DISABLE_O_DIRECT_KEY
319+
);
320+
unsafe { nix::libc::close(raw_fd) };
321+
let file_name = CStr::from_bytes_with_nul(template_bytes.as_slice())
322+
.unwrap()
323+
.to_str()
324+
.unwrap_or("<invalid utf8>");
325+
let _ = unlink(file_name);
326+
return Err(StorageError::AllocationFailed(format!(
327+
"Failed to set O_DIRECT: {}. Try {}=true",
328+
e, DISK_DISABLE_O_DIRECT_KEY
329+
)));
330+
}
331+
332+
tracing::debug!("O_DIRECT enabled for disk cache (fd={})", raw_fd);
333+
} else {
334+
tracing::warn!(
335+
"O_DIRECT disabled via {}. GPU DirectStorage performance may be reduced.",
336+
DISK_DISABLE_O_DIRECT_KEY
337+
);
338+
}
276339

277340
let file_name = CStr::from_bytes_with_nul(template_bytes.as_slice())
278341
.unwrap()
@@ -442,8 +505,7 @@ mod tests {
442505
];
443506

444507
for requested_size in test_sizes {
445-
let buf = AlignedBuffer::new(requested_size)
446-
.expect("Failed to create aligned buffer");
508+
let buf = AlignedBuffer::new(requested_size).expect("Failed to create aligned buffer");
447509

448510
let mut writer = StrictODirectWriter::new();
449511

@@ -487,24 +549,21 @@ mod tests {
487549
);
488550
eprintln!("✓ Confirmed: vec! buffer failed strict alignment check (as expected)");
489551
} else {
490-
eprintln!(
491-
"⚠ vec! happened to be aligned this time (lucky!), but not guaranteed"
492-
);
552+
eprintln!("⚠ vec! happened to be aligned this time (lucky!), but not guaranteed");
493553
}
494554
}
495555

496556
/// Test that the zero-fill write loop produces properly aligned write operations.
497557
#[test]
498558
fn test_zerofill_write_loop_alignment() {
499559
let test_sizes = vec![
500-
1_000_000, // 1 MB non-aligned
501-
10_000_000, // 10 MB non-aligned
502-
100_000_000, // 100 MB non-aligned
560+
1_000_000, // 1 MB non-aligned
561+
10_000_000, // 10 MB non-aligned
562+
100_000_000, // 100 MB non-aligned
503563
];
504564

505565
for total_size in test_sizes {
506-
let buf = AlignedBuffer::new(ZERO_BUF_SIZE)
507-
.expect("Failed to create buffer");
566+
let buf = AlignedBuffer::new(ZERO_BUF_SIZE).expect("Failed to create buffer");
508567

509568
let mut writer = StrictODirectWriter::new();
510569
let mut written: u64 = 0;
@@ -520,11 +579,14 @@ mod tests {
520579
};
521580

522581
// This should always succeed with our aligned buffer
523-
writer.write(&buf.as_slice()[..to_write])
524-
.unwrap_or_else(|e| panic!(
525-
"Write failed at offset {} for total size {}: {:?}",
526-
written, total_size, e
527-
));
582+
writer
583+
.write(&buf.as_slice()[..to_write])
584+
.unwrap_or_else(|e| {
585+
panic!(
586+
"Write failed at offset {} for total size {}: {:?}",
587+
written, total_size, e
588+
)
589+
});
528590

529591
written += to_write as u64;
530592
}
@@ -567,8 +629,9 @@ mod tests {
567629
for (name, size) in test_cases {
568630
eprintln!("Testing: {} ({} bytes)", name, size);
569631

570-
let storage = DiskStorage::new(size)
571-
.unwrap_or_else(|e| panic!("Failed to allocate {} bytes ({}): {:?}", size, name, e));
632+
let storage = DiskStorage::new(size).unwrap_or_else(|e| {
633+
panic!("Failed to allocate {} bytes ({}): {:?}", size, name, e)
634+
});
572635

573636
// Verify the file is actually the correct size
574637
assert_eq!(storage.size(), size, "Size mismatch for {}", name);
@@ -583,7 +646,11 @@ mod tests {
583646
};
584647

585648
assert!(bytes_read > 0, "No data read back for {}", name);
586-
assert!(buf.iter().all(|&b| b == 0), "File should be zero-filled for {}", name);
649+
assert!(
650+
buf.iter().all(|&b| b == 0),
651+
"File should be zero-filled for {}",
652+
name
653+
);
587654

588655
eprintln!("✓ {} passed", name);
589656
}
@@ -599,8 +666,7 @@ mod tests {
599666
std::env::set_var(DISK_ZEROFILL_FALLBACK_KEY, "1");
600667

601668
let size = 1024 * 1024;
602-
let storage = DiskStorage::new(size)
603-
.expect("Failed to allocate with O_DIRECT disabled");
669+
let storage = DiskStorage::new(size).expect("Failed to allocate with O_DIRECT disabled");
604670

605671
assert_eq!(storage.size(), size);
606672

0 commit comments

Comments
 (0)