Skip to content

Define a file descriptor reservation/commit/rollback abstraction. #311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 28, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions rust/kernel/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,49 @@ impl Deref for FileRef {
self.0.deref()
}
}

/// A file descriptor reservation.
///
/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
/// out of available slots), but commit and drop never fail (and are mutually exclusive).
pub struct FileDescriptorReservation {
fd: u32,
}

impl FileDescriptorReservation {
/// Creates a new file descriptor reservation.
pub fn new(flags: u32) -> Result<Self> {
let fd = unsafe { bindings::get_unused_fd_flags(flags) };
if fd < 0 {
return Err(Error::from_kernel_errno(fd));
}
Ok(Self { fd: fd as _ })
}

/// Returns the file descriptor number that was reserved.
pub fn reserved_fd(&self) -> u32 {
self.fd
}

/// Commits the reservation.
///
/// The previously reserved file descriptor is bound to `file`.
pub fn commit(self, file: File) {
// SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
// guaranteed to have an owned ref count by its type invariants.
unsafe { bindings::fd_install(self.fd, file.ptr) };

// `fd_install` consumes both the file descriptor and the file reference, so we cannot run
// the destructors.
core::mem::forget(self);
core::mem::forget(file);
}
}

impl Drop for FileDescriptorReservation {
fn drop(&mut self) {
// SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
unsafe { bindings::put_unused_fd(self.fd) };
}
}