Skip to content

Commit bd2cda1

Browse files
committed
Fixed error handling in AioCb::{fsync,read,write}
Previously, the `AioCb`'s `in_progress` field would erroneously be set to `true`, even if the syscall had an error Fixes #714
1 parent 0c94373 commit bd2cda1

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
5656
# Fixed
5757
- Fix compilation and tests for OpenBSD targets
5858
([#688](https://github.com/nix-rust/nix/pull/688))
59+
- Fixed error handling in `AioCb::fsync`, `AioCb::read`, and `AioCb::write`.
60+
It is no longer an error to drop an `AioCb` that failed to enqueue in the OS.
61+
([#715](https://github.com/nix-rust/nix/pull/715))
5962

6063
# Removed
6164
- The syscall module has been removed. This only exposed enough functionality for

src/sys/aio.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -232,16 +232,22 @@ impl<'a> AioCb<'a> {
232232
/// An asynchronous version of `fsync`.
233233
pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> {
234234
let p: *mut libc::aiocb = &mut self.aiocb;
235-
self.in_progress = true;
236-
Errno::result(unsafe { libc::aio_fsync(mode as libc::c_int, p) }).map(drop)
235+
Errno::result(unsafe {
236+
libc::aio_fsync(mode as libc::c_int, p)
237+
}).map(|_| {
238+
self.in_progress = true;
239+
})
237240
}
238241

239242
/// Asynchronously reads from a file descriptor into a buffer
240243
pub fn read(&mut self) -> Result<()> {
241244
assert!(self.mutable, "Can't read into an immutable buffer");
242245
let p: *mut libc::aiocb = &mut self.aiocb;
243-
self.in_progress = true;
244-
Errno::result(unsafe { libc::aio_read(p) }).map(drop)
246+
Errno::result(unsafe {
247+
libc::aio_read(p)
248+
}).map(|_| {
249+
self.in_progress = true;
250+
})
245251
}
246252

247253
/// Retrieve return status of an asynchronous operation. Should only be
@@ -257,8 +263,11 @@ impl<'a> AioCb<'a> {
257263
/// Asynchronously writes from a buffer to a file descriptor
258264
pub fn write(&mut self) -> Result<()> {
259265
let p: *mut libc::aiocb = &mut self.aiocb;
260-
self.in_progress = true;
261-
Errno::result(unsafe { libc::aio_write(p) }).map(drop)
266+
Errno::result(unsafe {
267+
libc::aio_write(p)
268+
}).map(|_| {
269+
self.in_progress = true;
270+
})
262271
}
263272

264273
}

test/sys/test_aio.rs

+57
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ fn test_fsync() {
8888
aiocb.aio_return().unwrap();
8989
}
9090

91+
/// `AioCb::fsync` should not modify the `AioCb` object if libc::aio_fsync returns
92+
/// an error
93+
// Skip on Linux, because Linux's AIO implementation can't detect errors
94+
// synchronously
95+
#[test]
96+
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
97+
fn test_fsync_error() {
98+
use std::mem;
99+
100+
const INITIAL: &'static [u8] = b"abcdef123456";
101+
// Create an invalid AioFsyncMode
102+
let mode = unsafe { mem::transmute(666) };
103+
let mut f = tempfile().unwrap();
104+
f.write(INITIAL).unwrap();
105+
let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
106+
0, //priority
107+
SigevNotify::SigevNone);
108+
let err = aiocb.fsync(mode);
109+
assert!(err.is_err());
110+
}
91111

92112
#[test]
93113
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
@@ -156,6 +176,26 @@ fn test_read() {
156176
assert!(EXPECT == rbuf.deref().deref());
157177
}
158178

179+
/// `AioCb::read` should not modify the `AioCb` object if libc::aio_read returns
180+
/// an error
181+
// Skip on Linux, because Linux's AIO implementation can't detect errors
182+
// synchronously
183+
#[test]
184+
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
185+
fn test_read_error() {
186+
const INITIAL: &'static [u8] = b"abcdef123456";
187+
let rbuf = Rc::new(vec![0; 4].into_boxed_slice());
188+
let mut f = tempfile().unwrap();
189+
f.write(INITIAL).unwrap();
190+
let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
191+
-1, //an invalid offset
192+
rbuf.clone(),
193+
0, //priority
194+
SigevNotify::SigevNone,
195+
LioOpcode::LIO_NOP);
196+
assert!(aiocb.read().is_err());
197+
}
198+
159199
// Tests from_mut_slice
160200
#[test]
161201
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
@@ -230,6 +270,23 @@ fn test_write() {
230270
assert!(rbuf == EXPECT);
231271
}
232272

273+
/// `AioCb::write` should not modify the `AioCb` object if libc::aio_write returns
274+
/// an error
275+
// Skip on Linux, because Linux's AIO implementation can't detect errors
276+
// synchronously
277+
#[test]
278+
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
279+
fn test_write_error() {
280+
let wbuf = "CDEF".to_string().into_bytes();
281+
let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor
282+
0, //offset
283+
&wbuf,
284+
0, //priority
285+
SigevNotify::SigevNone,
286+
LioOpcode::LIO_NOP);
287+
assert!(aiocb.write().is_err());
288+
}
289+
233290
lazy_static! {
234291
pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
235292
}

0 commit comments

Comments
 (0)