Skip to content

Comments

Refactor and handle mlock failure#33

Merged
ming1 merged 14 commits intomainfrom
refactor-and-handle-mlock-failure
Sep 15, 2025
Merged

Refactor and handle mlock failure#33
ming1 merged 14 commits intomainfrom
refactor-and-handle-mlock-failure

Conversation

@ming1
Copy link
Collaborator

@ming1 ming1 commented Sep 15, 2025

  • refactor io code path

  • improve mlock failure handling

…return types

This commit enhances error handling throughout the codebase by:

1. **Function Signature Changes**: Modified async functions containing
   submit_io_cmd_unified() loops to return Result<(), UblkError> instead
   of () for better error propagation.

2. **Simplified Error Handling**: Replaced verbose match statements with
   the ? operator for cleaner, more idiomatic Rust error handling:
   - Before: match submit_io_cmd_unified() { Ok(f) => f.await, Err(e) => break }
   - After: submit_io_cmd_unified()?.await

3. **Function Extraction**: Extracted anonymous async closures into proper
   named functions with Result return types for better maintainability:
   - examples/ramdisk.rs: Created io_task() -> Result<(), UblkError>
   - examples/loop.rs: Created lo_io_task() -> Result<(), UblkError>
   - examples/null.rs: Created null_io_task() -> Result<(), UblkError>
   - tests/basic.rs: Created test_io_task(), test_auto_reg_io_task(), test_ramdisk_io_task()
   - src/ctrl.rs: Updated io_async_fn() -> Result<(), UblkError>

4. **Import Fixes**: Added missing UblkError imports to fix compilation errors.

Benefits:
- Cleaner, more readable error handling code
- Consistent error propagation patterns across the codebase
- Early return on errors via ? operator
- Better separation of concerns with named functions
- Improved maintainability and debuggability

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
…eturn on failure

This commit enhances error handling for submit_fetch_commands_unified() callsites
by implementing graceful failure handling instead of proceeding to wait_and_handle_io()
after failures.

**Key Changes:**

1. **Replace Panic-Prone Pattern**: Changed from:
   ```rust
   .submit_fetch_commands_unified(...)
   .unwrap()  // <- Would panic on failure
   .wait_and_handle_io(handler);
   ```

   To:
   ```rust
   match .submit_fetch_commands_unified(...) {
       Ok(q) => q.wait_and_handle_io(handler),
       Err(e) => {
           log::error!("submit_fetch_commands_unified failed: {}", e);
           return;  // <- Return instead of proceeding
       }
   }
   ```

2. **Prevent Broken I/O Loops**: Functions now return immediately on
   submit_fetch_commands_unified() failure instead of entering potentially
   broken I/O handling loops.

3. **Improved Error Logging**: All failures are logged with descriptive
   error messages for better debugging.

**Files Modified:**
- examples/null.rs: Fixed sync queue handler
- examples/loop.rs: Fixed sync queue handler
- tests/basic.rs: Fixed 4 test handler instances
- src/ctrl.rs: Fixed test queue handler

**Benefits:**
- Prevents crashes from .unwrap() failures
- Avoids wait_and_handle_io() execution with failed queue setup
- Provides clean shutdown with proper error reporting
- Improves system stability and debuggability

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
- Make submit_io_cmd_unified() private (no longer exported)
- Add submit_io_prep_cmd() for UBLK_U_IO_FETCH_REQ operations
- Add submit_io_commit_cmd() for UBLK_U_IO_COMMIT_AND_FETCH_REQ operations
- Convert all users to use new API functions
- Optimize by moving submit_io_prep_cmd() out of loops for better performance
- Update examples, tests, and documentation to use new API

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
…plify error handling

- Make submit_io_prep_cmd() and submit_io_commit_cmd() async functions returning Result<i32, UblkError>
- Automatically convert UBLK_IO_RES_ABORT to UblkError::QueueIsDown in both functions
- Simplify all users to use ? operator instead of manual UBLK_IO_RES_ABORT checks
- Update examples, tests, and documentation to use simplified error handling pattern
- Suppress QueueIsDown error logging in q_async_fn() as it's expected during shutdown

Benefits:
- Cleaner code with standard Rust error handling patterns
- No more manual UBLK_IO_RES_ABORT checks required
- Consistent error propagation using ? operator
- Reduced boilerplate in user code
- Quieter logs during normal shutdown operations

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
- Add Option<&IoBuf> parameter to submit_io_prep_cmd() for automatic buffer registration
- Move q.register_io_buf() logic into submit_io_prep_cmd() to simplify API usage
- Update all users to pass IoBuf and remove manual register_io_buf calls:
  - Updated examples (null.rs, loop.rs, ramdisk.rs) to use new API pattern
  - Updated tests/basic.rs to handle both IoBuf and AutoReg cases
  - Updated src/ctrl.rs test function
  - Updated README.md example and documentation
- Fix doctests in src/io.rs to use new 4-parameter signature
- Maintain backward compatibility for AutoReg cases by passing None

Benefits:
- Simplified API - users no longer need manual register_io_buf() calls
- Better ergonomics - common registration pattern handled automatically
- Cleaner code - removed repetitive registration calls throughout codebase

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
…ified()

- Move automatic buffer registration into submit_fetch_commands_unified() for BufDescList::Slices
- Remove manual regiser_io_bufs() calls from all users:
  - Updated examples/null.rs sync handler to use simplified API
  - Updated examples/loop.rs to remove redundant registration call
  - Updated src/ctrl.rs test function to use new pattern
- Update documentation to explain automatic buffer registration behavior
- Maintain backward compatibility for AutoReg cases (no buffer registration needed)

Benefits:
- Simplified API - users no longer need manual regiser_io_bufs() calls
- Better ergonomics - common registration pattern handled automatically in unified function
- Single responsibility - submit_fetch_commands_unified() handles complete initialization workflow
- Cleaner code - eliminated repetitive .regiser_io_bufs().submit_fetch_commands_unified() chaining

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
…iptor alignment

- Add comprehensive verification to ensure BufDesc aligns with provided IoBuf:
  - BufDesc::Slice with Some(io_buf): Verify slice points to same memory as IoBuf
  - BufDesc::Slice with None: Ensure slice is empty (user_copy mode)
  - BufDesc::AutoReg with Some(io_buf): Return error (mutually exclusive)
  - BufDesc::AutoReg with None: Valid usage for zero-copy operations
  - ZonedAppendLba/RawAddress: No specific verification needed

- Update documentation to explain verification behavior and error conditions
- Add test_submit_io_prep_cmd_verification() to validate verification logic
- Return -EINVAL error for misaligned buffer descriptors and IoBuf instances

Benefits:
- Prevents user errors by catching mismatched buffer descriptors at runtime
- Better debugging with clear error messages for alignment issues
- Type safety ensuring AutoReg and IoBuf aren't used together
- Early error detection preventing potential memory corruption
- Maintains high performance for correct usage patterns

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
- Add async-lock dependency for Semaphore support
- Add buf_reg_semaphore to UblkQueue for coordination between async tasks
- Add buf_reg_counter for optimized O(1) registration tracking
- Implement wait_for_all_buffer_registrations() using semaphore.acquire()
- Only check all buffers when counter reaches queue depth (optimization)
- Skip synchronization for AutoReg operations (kernel-managed buffers)
- Add permits when all buffers registered or for batch operations
- Fix zero-copy test timeouts by bypassing wait for AutoReg operations
- Update tests to verify counter behavior and semaphore coordination

This approach eliminates circular dependencies between async tasks while
maintaining proper synchronization, ensuring all buffer registrations
complete before prep commands proceed. Performance is maintained with
O(1) registration tracking and selective synchronization.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
…tests

Update error handling patterns in async task spawns to use pattern matching
instead of if-let, filtering out expected QueueIsDown errors during shutdown.

Changes:
- examples/null.rs: Filter QueueIsDown errors in null_io_task logging
- examples/loop.rs: Filter QueueIsDown errors in lo_io_task logging
- examples/ramdisk.rs: Filter QueueIsDown errors in io_task logging
- tests/basic.rs: Filter QueueIsDown errors in test task logging
  - test_ublk_null_async: test_io_task error handling
  - __test_ublk_null_zc: test_auto_reg_io_task error handling
  - __test_ublk_ramdisk: test_ramdisk_io_task error handling

This provides cleaner log output by avoiding noise from expected shutdown
errors while still capturing genuine error conditions.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
…k fails

- Add mlock failure state tracking with UBLK_QUEUE_MLOCK_FAIL flag
- Mark mlock failure in register_io_buf() when IoBuf.mlock() fails
- Add mlock failure check to submit_fetch_commands_unified()
- Add conditional mlock failure check to submit_io_cmd_unified() for FETCH_REQ operations only
- Add mlock failure check to __wait_ios() to fail immediately with -EPERM
- Prevents unsafe operations when memory locking has failed

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
- Add synchronization mechanism using std::sync::Condvar to UblkDev
- UblkCtrl::start_dev() and start_dev_async() now wait for all queue buffer registrations to complete
- Immediate failure on any mlock errors during buffer registration
- Simplified API with mlock_failed parameter in notify_buffer_registration_complete()
- Remove total_queues from BufferRegState, pass nr_hw_queues as parameter
- Make BufferRegState and buf_reg_sync field pub(crate) for proper encapsulation

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
… APIs

Document that UBLK_DEV_F_MLOCK_IO_BUFFER is not supported with deprecated
submit_io_cmd() and submit_fetch_commands() methods. Users should migrate
to the unified APIs (submit_io_prep_cmd, submit_io_commit_cmd, and
submit_fetch_commands_unified) for mlock functionality.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Add buffer address validation to submit_io_commit_cmd() and complete_io_cmd_unified()
when UBLK_DEV_F_MLOCK_IO_BUFFER is enabled:

- Created validate_mlock_buffer_consistency() helper function for code reuse
- Validates that BufDesc::Slice buffer addresses match UblkQueue::bufs[tag]
- Ensures mlock'd buffers are used consistently across operations
- Added comprehensive documentation explaining the validation constraint
- Returns -EINVAL if buffer addresses don't match
- Helper function is marked #[inline(always)] for performance

This prevents potential memory safety issues by ensuring registered mlock'd
buffers are used consistently throughout the I/O lifecycle.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
@ming1 ming1 merged commit 6030adc into main Sep 15, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant