1use crate::mm::{MemoryAccessorExt, PAGE_SIZE, TaskMemoryAccessor};
6use crate::security;
7use crate::signals::{SignalInfo, send_standard_signal};
8use crate::task::{CurrentTask, EventHandler, WaitCallback, WaitCanceler, WaitQueue, Waiter};
9use crate::vfs::buffers::{
10 Buffer, InputBuffer, InputBufferCallback, InputBufferExt, MessageData, MessageQueue,
11 OutputBuffer, OutputBufferCallback, PeekBufferSegmentsCallback, PipeMessageData,
12 UserBuffersOutputBuffer, VecInputBuffer, VecOutputBuffer,
13};
14use crate::vfs::fs_registry::FsRegistry;
15use crate::vfs::{
16 CacheMode, FileHandle, FileObject, FileObjectState, FileOps, FileSystem, FileSystemHandle,
17 FileSystemOps, FileSystemOptions, FsNodeInfo, FsStr, SpecialNode, default_fcntl,
18 fileops_impl_nonseekable, fileops_impl_noop_sync,
19};
20use starnix_sync::{LockDepGuard, LockDepMutex, PipeLock, ordered_lock};
21use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
22use starnix_types::user_buffer::{UserBuffer, UserBuffers};
23use starnix_types::vfs::default_statfs;
24use starnix_uapi::auth::CAP_SYS_RESOURCE;
25use starnix_uapi::errors::{EAGAIN, EPIPE, Errno};
26use starnix_uapi::file_mode::mode;
27use starnix_uapi::fs_type::FileSystemTypeFlags;
28use starnix_uapi::open_flags::OpenFlags;
29use starnix_uapi::resource_limits::Resource;
30use starnix_uapi::signals::{SIGPIPE, SIGXFSZ};
31use starnix_uapi::user_address::{UserAddress, UserRef};
32use starnix_uapi::vfs::FdEvents;
33use starnix_uapi::{
34 F_GETPIPE_SZ, F_SETPIPE_SZ, FIONREAD, PIPEFS_MAGIC, errno, error, statfs, uapi,
35};
36use std::sync::Arc;
37
38const ATOMIC_IO_BYTES: u16 = 4096;
39
40const PIPE_MAX_SIZE: usize = 1 << 31;
42
43const SPLICE_READ_WAIT_KEY: u64 = 0;
45
46const SPLICE_WRITE_WAIT_KEY: u64 = 1;
48
49const PIPE_WRITE_SPACE_WAIT_KEY: u64 = 2;
52
53#[derive(Debug)]
54pub struct Pipe {
55 messages: MessageQueue<PipeMessageData>,
56
57 waiters: WaitQueue,
58
59 reader_count: usize,
61
62 had_reader: bool,
64
65 writer_count: usize,
67
68 had_writer: bool,
70
71 splice_read_in_progress: bool,
73
74 splice_read_reserved_bytes: usize,
76
77 splice_write_in_progress: bool,
79}
80
81pub type PipeHandle = Arc<LockDepMutex<Pipe, PipeLock>>;
82
83impl Pipe {
84 pub fn new(default_pipe_capacity: usize) -> PipeHandle {
85 Arc::new(
86 Pipe {
87 messages: MessageQueue::new(default_pipe_capacity),
88 waiters: WaitQueue::default(),
89 reader_count: 0,
90 had_reader: false,
91 writer_count: 0,
92 had_writer: false,
93 splice_read_in_progress: false,
94 splice_read_reserved_bytes: 0,
95 splice_write_in_progress: false,
96 }
97 .into(),
98 )
99 }
100
101 pub fn open(
102 current_task: &CurrentTask,
103 pipe: &PipeHandle,
104 flags: OpenFlags,
105 ) -> Result<Box<dyn FileOps>, Errno> {
106 let mut events = FdEvents::empty();
107 let mut pipe_locked = pipe.lock();
108 let mut must_wait_events = FdEvents::empty();
109 if flags.can_read() {
110 if !pipe_locked.had_reader {
111 events |= FdEvents::POLLOUT;
112 }
113 pipe_locked.add_reader();
114 if !flags.contains(OpenFlags::NONBLOCK) && !flags.can_write() && !pipe_locked.had_writer
115 {
116 must_wait_events |= FdEvents::POLLIN;
117 }
118 }
119 if flags.can_write() {
120 if flags.contains(OpenFlags::NONBLOCK) && pipe_locked.reader_count == 0 {
125 assert!(!flags.can_read()); return error!(ENXIO);
127 }
128 if !pipe_locked.had_writer {
129 events |= FdEvents::POLLIN;
130 }
131 pipe_locked.add_writer();
132 if !flags.contains(OpenFlags::NONBLOCK) && !pipe_locked.had_reader {
133 must_wait_events |= FdEvents::POLLOUT;
134 }
135 }
136 if events != FdEvents::empty() {
137 pipe_locked.waiters.notify_fd_events(events);
138 }
139 let ops = PipeFileObject { pipe: Arc::clone(pipe) };
140 if must_wait_events == FdEvents::empty() {
141 return Ok(Box::new(ops));
142 }
143
144 let ops = scopeguard::guard(ops, |ops| {
146 ops.on_close(flags);
147 });
148
149 let waiter = Waiter::new();
151 loop {
152 pipe_locked.waiters.wait_async_fd_events(
153 &waiter,
154 must_wait_events,
155 WaitCallback::none(),
156 );
157 std::mem::drop(pipe_locked);
158 match waiter.wait(current_task) {
159 Err(e) => {
160 return Err(e);
161 }
162 _ => {}
163 }
164 pipe_locked = pipe.lock();
165 if pipe_locked.had_writer && pipe_locked.had_reader {
166 return Ok(Box::new(scopeguard::ScopeGuard::into_inner(ops)));
167 }
168 }
169 }
170
171 pub fn add_reader(&mut self) {
173 self.reader_count += 1;
174 self.had_reader = true;
175 }
176
177 pub fn add_writer(&mut self) {
179 self.writer_count += 1;
180 self.had_writer = true;
181 }
182
183 pub fn on_close(&mut self) {
186 if self.reader_count == 0 && self.writer_count == 0 {
187 debug_assert!(!self.splice_read_in_progress);
188 debug_assert!(!self.splice_write_in_progress);
189 debug_assert_eq!(self.splice_read_reserved_bytes, 0);
190 self.had_reader = false;
191 self.had_writer = false;
192 self.messages = MessageQueue::new(self.messages.capacity());
193 self.waiters = WaitQueue::default();
194 }
195 }
196
197 fn is_empty(&self) -> bool {
198 self.readable_len() == 0
199 }
200
201 fn readable_len(&self) -> usize {
202 self.messages.len().saturating_sub(self.splice_read_reserved_bytes)
203 }
204
205 fn capacity(&self) -> usize {
206 self.messages.capacity()
207 }
208
209 fn set_capacity(
210 &mut self,
211 current_task: &CurrentTask,
212 mut requested_capacity: usize,
213 ) -> Result<(), Errno> {
214 if requested_capacity > PIPE_MAX_SIZE {
215 return error!(EINVAL);
216 }
217 let page_size = *PAGE_SIZE as usize;
218 if requested_capacity < page_size {
219 requested_capacity = page_size;
220 }
221 requested_capacity = requested_capacity.next_power_of_two();
222 let old_capacity = self.messages.capacity();
223 if requested_capacity > old_capacity
224 && requested_capacity
225 > current_task
226 .kernel()
227 .system_limits
228 .pipe_max_size
229 .load(std::sync::atomic::Ordering::Relaxed)
230 {
231 security::check_task_capable(current_task, CAP_SYS_RESOURCE)?;
232 }
233 let was_writable = self.is_writable(uapi::PIPE_BUF as usize);
234 self.messages.set_capacity(requested_capacity)?;
235 if requested_capacity > old_capacity {
236 self.notify_write_space(was_writable);
237 }
238 Ok(())
239 }
240
241 fn is_readable(&self) -> bool {
242 !self.is_empty() || (self.writer_count == 0 && self.had_writer)
243 }
244
245 fn is_writable(&self, data_size: usize) -> bool {
247 let available_capacity = self.messages.available_capacity();
248 self.had_reader
251 && (self.reader_count == 0
252 || available_capacity >= data_size
253 || (available_capacity > 0 && data_size > uapi::PIPE_BUF as usize))
254 }
255
256 fn min_splice_write_bytes(&self) -> usize {
261 let page_size = *PAGE_SIZE as usize;
262 if self.messages.capacity() <= page_size { page_size } else { 1 }
263 }
264
265 pub fn read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
266 debug_assert!(!self.splice_read_in_progress);
267 if data.available() == 0 {
268 return Ok(0);
269 }
270
271 if !self.is_readable() {
274 return error!(EAGAIN);
275 }
276
277 self.messages.read_stream(data).map(|(info, _)| info.bytes_read)
278 }
279
280 pub fn write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
281 debug_assert!(!self.splice_write_in_progress);
282 if data.available() == 0 {
283 return Ok(0);
284 }
285
286 if !self.had_reader {
287 return error!(EAGAIN);
288 }
289
290 if self.reader_count == 0 {
291 return error!(EPIPE);
292 }
293
294 let total_requested = data.available().saturating_add(data.bytes_read());
295 if !self.is_writable(total_requested) {
296 return error!(EAGAIN);
297 }
298
299 let page_size = *PAGE_SIZE as usize;
300 let mut total_written = 0;
301 while self.messages.available_capacity() > 0 && data.available() > 0 {
302 let chunk_len = std::cmp::min(
303 self.messages.available_capacity(),
304 std::cmp::min(data.available(), page_size),
305 );
306 let bytes = data.read_to_vec_limited(chunk_len)?;
307 let actual = bytes.len();
308 if actual == 0 {
309 break;
310 }
311 self.messages.write_message(PipeMessageData::from(bytes).into());
312 total_written += actual;
313 }
314 Ok(total_written)
315 }
316
317 fn query_events(&self, flags: OpenFlags) -> FdEvents {
318 let mut events = FdEvents::empty();
319
320 if flags.can_read() && self.is_readable() {
321 let writer_closed = self.writer_count == 0 && self.had_writer;
322 let has_data = !self.is_empty();
323 if writer_closed {
324 events |= FdEvents::POLLHUP;
325 }
326 if has_data {
327 events |= FdEvents::POLLIN;
328 }
329 }
330
331 if flags.can_write() && self.is_writable(uapi::PIPE_BUF as usize) {
332 if self.reader_count == 0 && self.had_reader {
333 events |= FdEvents::POLLERR;
334 }
335
336 events |= FdEvents::POLLOUT;
337 }
338
339 events
340 }
341
342 fn fcntl(
343 &mut self,
344 _file: &FileObject,
345 current_task: &CurrentTask,
346 cmd: u32,
347 arg: u64,
348 ) -> Result<SyscallResult, Errno> {
349 match cmd {
350 F_GETPIPE_SZ => Ok(self.capacity().into()),
351 F_SETPIPE_SZ => {
352 let raw_arg = arg as i32;
353 if raw_arg < 0 {
354 return error!(EINVAL);
355 }
356 self.set_capacity(current_task, raw_arg as usize)?;
357 Ok(self.capacity().into())
358 }
359 _ => default_fcntl(cmd),
360 }
361 }
362
363 fn notify_fd_events(&self, events: FdEvents) {
364 self.waiters.notify_fd_events(events);
365 }
366
367 fn notify_write_space(&self, was_writable: bool) {
368 if !was_writable {
369 if self.is_writable(uapi::PIPE_BUF as usize) {
370 self.notify_fd_events(FdEvents::POLLOUT);
371 } else if self.is_writable(1) {
372 self.waiters.notify_value(PIPE_WRITE_SPACE_WAIT_KEY);
373 }
374 }
375 }
376
377 fn consume(&mut self, bytes_read: usize) {
380 let was_writable = self.is_writable(uapi::PIPE_BUF as usize);
381 let mut consumed = bytes_read;
382 while consumed > 0 {
383 let mut message =
384 self.messages.read_message().expect("pipe messages shrunk during splice read");
385 if let Some(remaining) = MessageData::split_off(&mut message.data, consumed) {
386 self.messages.write_front(remaining.into());
387 break;
388 }
389 consumed -= message.len();
390 }
391 if bytes_read > 0 {
392 self.notify_write_space(was_writable);
393 }
394 }
395}
396
397pub fn new_pipe(current_task: &CurrentTask) -> Result<(FileHandle, FileHandle), Errno> {
403 let fs = pipe_fs(current_task, FileSystemOptions::default())?;
404 let mut info = FsNodeInfo::new(mode!(IFIFO, 0o600), current_task.current_fscred());
405 info.blksize = ATOMIC_IO_BYTES.into();
406 let node = fs.create_node_and_allocate_node_id(SpecialNode, info);
407 let pipe = node.fifo(current_task);
408 {
409 let mut state = pipe.lock();
410 state.add_reader();
411 state.add_writer();
412 }
413
414 let read_ops = PipeFileObject { pipe: Arc::clone(pipe) };
416 let read_file = FileObject::new_anonymous(
417 current_task,
418 Box::new(read_ops),
419 Arc::clone(&node),
420 OpenFlags::RDONLY,
421 );
422
423 let write_ops = PipeFileObject { pipe: Arc::clone(pipe) };
425 let write_file = FileObject::new(
426 current_task,
427 Box::new(write_ops),
428 read_file.name.to_passive(),
429 OpenFlags::WRONLY,
430 )?;
431
432 Ok((read_file, write_file))
433}
434
435pub(crate) fn new_pipe_file(
438 current_task: &CurrentTask,
439 ops: Box<dyn FileOps>,
440 flags: OpenFlags,
441) -> Result<FileHandle, Errno> {
442 let fs = pipe_fs(current_task, FileSystemOptions::default())?;
443 let mut info = FsNodeInfo::new(mode!(IFIFO, 0o600), current_task.current_fscred());
444 info.blksize = ATOMIC_IO_BYTES.into();
445 let node = fs.create_node_and_allocate_node_id(SpecialNode, info);
446 Ok(FileObject::new_anonymous(current_task, ops, node, flags))
447}
448
449struct PipeFs;
450impl FileSystemOps for PipeFs {
451 fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
452 Ok(default_statfs(PIPEFS_MAGIC))
453 }
454 fn name(&self) -> &'static FsStr {
455 "pipefs".into()
456 }
457}
458
459fn pipe_fs(
460 current_task: &CurrentTask,
461 _options: FileSystemOptions,
462) -> Result<FileSystemHandle, Errno> {
463 struct PipeFsHandle(FileSystemHandle);
464
465 let kernel = current_task.kernel();
466 let fs = kernel
467 .expando
468 .get_or_init(|| {
469 PipeFsHandle(
470 FileSystem::new(kernel, CacheMode::Uncached, PipeFs, FileSystemOptions::default())
471 .expect("pipefs constructed with valid options"),
472 )
473 })
474 .0
475 .clone();
476 security::file_system_resolve_security(current_task, &fs)?;
477 Ok(fs)
478}
479
480pub fn register_pipe_fs(fs_registry: &FsRegistry) {
481 fs_registry.register("pipefs".into(), FileSystemTypeFlags::empty(), pipe_fs);
482}
483
484pub struct PipeFileObject {
485 pipe: PipeHandle,
486}
487
488impl FileOps for PipeFileObject {
489 fileops_impl_nonseekable!();
490 fileops_impl_noop_sync!();
491
492 fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
493 self.on_close(file.flags());
494 }
495
496 fn read(
497 &self,
498 file: &FileObject,
499 current_task: &CurrentTask,
500 offset: usize,
501 data: &mut dyn OutputBuffer,
502 ) -> Result<usize, Errno> {
503 debug_assert!(offset == 0);
504 file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
505 let mut pipe = self.lock_pipe_without_splice(current_task)?;
506 let was_writable = pipe.is_writable(uapi::PIPE_BUF as usize);
507 let actual = pipe.read(data)?;
508 if actual > 0 {
509 pipe.notify_write_space(was_writable);
510 }
511 Ok(actual)
512 })
513 }
514
515 fn write(
516 &self,
517 file: &FileObject,
518 current_task: &CurrentTask,
519 offset: usize,
520 data: &mut dyn InputBuffer,
521 ) -> Result<usize, Errno> {
522 debug_assert!(offset == 0);
523 debug_assert!(data.bytes_read() == 0);
524
525 let result =
526 file.blocking_op(current_task, FdEvents::POLLOUT | FdEvents::POLLERR, None, || {
527 let mut pipe = self.lock_pipe_without_splice(current_task)?;
528 let offset_before = data.bytes_read();
529 let bytes_written = match pipe.write(data) {
530 Err(e) => {
531 if data.bytes_read() > offset_before {
532 pipe.notify_fd_events(FdEvents::POLLIN);
533 }
534 if e == EPIPE {
535 std::mem::drop(pipe);
536 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
537 }
538 return Err(e);
539 }
540 Ok(bytes_written) => bytes_written,
541 };
542 debug_assert!(data.bytes_read() - offset_before == bytes_written);
543 if bytes_written > 0 {
544 pipe.notify_fd_events(FdEvents::POLLIN);
545 }
546 if data.available() > 0 {
547 return error!(EAGAIN);
548 }
549 Ok(())
550 });
551
552 let bytes_written = data.bytes_read();
553 if bytes_written == 0 {
554 result?;
556 }
557 Ok(bytes_written)
558 }
559
560 fn wait_async(
561 &self,
562 file: &FileObject,
563 _current_task: &CurrentTask,
564 waiter: &Waiter,
565 mut events: FdEvents,
566 handler: EventHandler,
567 ) -> Option<WaitCanceler> {
568 let flags = file.flags();
569 if !flags.can_read() {
570 events.remove(FdEvents::POLLIN);
571 }
572 if !flags.can_write() {
573 events.remove(FdEvents::POLLOUT);
574 }
575 let subscribe_write_space =
576 matches!(handler, EventHandler::None) && events.contains(FdEvents::POLLOUT);
577 let pipe = self.pipe.lock();
578 let canceler = pipe.waiters.wait_async_fd_events(waiter, events, handler);
579 if subscribe_write_space {
580 let write_space_canceler =
581 pipe.waiters.wait_async_value(waiter, PIPE_WRITE_SPACE_WAIT_KEY);
582 Some(WaitCanceler::merge(canceler, write_space_canceler))
583 } else {
584 Some(canceler)
585 }
586 }
587
588 fn query_events(
589 &self,
590 file: &FileObject,
591 _current_task: &CurrentTask,
592 ) -> Result<FdEvents, Errno> {
593 Ok(self.pipe.lock().query_events(file.flags()))
594 }
595
596 fn can_query_events_without_wait(&self) -> bool {
597 true
599 }
600
601 fn fcntl(
602 &self,
603 file: &FileObject,
604 current_task: &CurrentTask,
605 cmd: u32,
606 arg: u64,
607 ) -> Result<SyscallResult, Errno> {
608 self.lock_pipe_without_splice(current_task)?.fcntl(file, current_task, cmd, arg)
609 }
610
611 fn ioctl(
612 &self,
613 _file: &FileObject,
614 current_task: &CurrentTask,
615 request: u32,
616 arg: SyscallArg,
617 ) -> Result<SyscallResult, Errno> {
618 let user_addr = UserAddress::from(arg);
619 match request {
620 FIONREAD => {
621 let pipe = self.lock_pipe_without_splice(current_task)?;
622 let value: i32 = pipe.readable_len().try_into().map_err(|_| errno!(EINVAL))?;
623 std::mem::drop(pipe);
624 let addr = UserRef::<i32>::new(user_addr);
625 current_task.write_object(addr, &value)?;
626 Ok(SUCCESS)
627 }
628 _ => error!(ENOTTY),
629 }
630 }
631}
632
633struct SpliceReadGuard<'a> {
635 pipe: Option<&'a PipeHandle>,
636}
637
638impl<'a> SpliceReadGuard<'a> {
639 fn new(
641 pipe_handle: &'a PipeHandle,
642 mut pipe: LockDepGuard<'a, Pipe>,
643 reserved_bytes: usize,
644 ) -> Self {
645 assert!(!pipe.splice_read_in_progress);
646 pipe.splice_read_in_progress = true;
647 pipe.splice_read_reserved_bytes = reserved_bytes;
648 Self { pipe: Some(pipe_handle) }
649 }
650
651 fn consume(mut self, bytes_read: usize) {
654 if let Some(pipe_handle) = self.pipe.take() {
655 let mut pipe = pipe_handle.lock();
656 pipe.consume(bytes_read);
657 Self::clear(&mut pipe);
658 }
659 }
660
661 fn clear(pipe: &mut Pipe) {
663 assert!(pipe.splice_read_in_progress);
664 pipe.splice_read_in_progress = false;
665 pipe.splice_read_reserved_bytes = 0;
666 pipe.waiters.notify_value(SPLICE_READ_WAIT_KEY);
667 if !pipe.is_empty() {
668 pipe.notify_fd_events(FdEvents::POLLIN);
669 }
670 }
671}
672
673impl Drop for SpliceReadGuard<'_> {
674 fn drop(&mut self) {
675 if let Some(pipe_handle) = self.pipe.take() {
676 Self::clear(&mut pipe_handle.lock());
677 }
678 }
679}
680
681struct SpliceWriteGuard<'a> {
683 pipe: Option<&'a PipeHandle>,
684}
685
686impl<'a> SpliceWriteGuard<'a> {
687 fn new(pipe_handle: &'a PipeHandle, mut pipe: LockDepGuard<'a, Pipe>) -> Self {
689 assert!(!pipe.splice_write_in_progress);
690 pipe.splice_write_in_progress = true;
691 Self { pipe: Some(pipe_handle) }
692 }
693
694 fn enqueue(mut self, bytes: Vec<u8>) -> Result<(), Errno> {
697 if let Some(pipe_handle) = self.pipe.take() {
698 let mut pipe = pipe_handle.lock();
699 if pipe.reader_count == 0 {
700 Self::clear(&mut pipe);
701 return error!(EPIPE);
702 }
703 if !bytes.is_empty() {
704 for chunk in bytes.chunks(*PAGE_SIZE as usize) {
705 pipe.messages.write_message(PipeMessageData::from(chunk.to_vec()).into());
706 }
707 pipe.notify_fd_events(FdEvents::POLLIN);
708 }
709 Self::clear(&mut pipe);
710 }
711 Ok(())
712 }
713
714 fn clear(pipe: &mut Pipe) {
716 assert!(pipe.splice_write_in_progress);
717 pipe.splice_write_in_progress = false;
718 pipe.waiters.notify_value(SPLICE_WRITE_WAIT_KEY);
719 if pipe.reader_count == 0 {
720 pipe.notify_fd_events(FdEvents::POLLOUT | FdEvents::POLLERR);
721 } else {
722 pipe.notify_write_space(false);
723 }
724 }
725}
726
727impl Drop for SpliceWriteGuard<'_> {
728 fn drop(&mut self) {
729 if let Some(pipe_handle) = self.pipe.take() {
730 Self::clear(&mut pipe_handle.lock());
731 }
732 }
733}
734
735impl std::fmt::Debug for SpliceReadGuard<'_> {
736 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
737 f.debug_struct("SpliceReadGuard").finish_non_exhaustive()
738 }
739}
740
741impl std::fmt::Debug for SpliceWriteGuard<'_> {
742 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
743 f.debug_struct("SpliceWriteGuard").finish_non_exhaustive()
744 }
745}
746
747#[derive(Debug)]
749pub struct SpliceOutputBuffer<'a> {
750 guard: SpliceWriteGuard<'a>,
751 buffer: VecOutputBuffer,
752}
753
754impl<'a> Buffer for SpliceOutputBuffer<'a> {
755 fn segments_count(&self) -> Result<usize, Errno> {
756 self.buffer.segments_count()
757 }
758
759 fn peek_each_segment(
760 &mut self,
761 callback: &mut PeekBufferSegmentsCallback<'_>,
762 ) -> Result<(), Errno> {
763 self.buffer.peek_each_segment(callback)
764 }
765}
766
767impl<'a> OutputBuffer for SpliceOutputBuffer<'a> {
768 fn write_each(&mut self, callback: &mut OutputBufferCallback<'_>) -> Result<usize, Errno> {
769 self.buffer.write_each(callback)
770 }
771
772 fn available(&self) -> usize {
773 self.buffer.available()
774 }
775
776 fn bytes_written(&self) -> usize {
777 self.buffer.bytes_written()
778 }
779
780 fn zero(&mut self) -> Result<usize, Errno> {
781 self.buffer.zero()
782 }
783
784 unsafe fn advance(&mut self, length: usize) -> Result<(), Errno> {
785 unsafe { self.buffer.advance(length) }
788 }
789}
790
791#[derive(Debug)]
793pub struct SpliceInputBuffer<'a> {
794 guard: SpliceReadGuard<'a>,
795 buffer: VecInputBuffer,
796}
797
798impl<'a> Buffer for SpliceInputBuffer<'a> {
799 fn segments_count(&self) -> Result<usize, Errno> {
800 self.buffer.segments_count()
801 }
802
803 fn peek_each_segment(
804 &mut self,
805 callback: &mut PeekBufferSegmentsCallback<'_>,
806 ) -> Result<(), Errno> {
807 self.buffer.peek_each_segment(callback)
808 }
809}
810
811impl<'a> InputBuffer for SpliceInputBuffer<'a> {
812 fn peek_each(&mut self, callback: &mut InputBufferCallback<'_>) -> Result<usize, Errno> {
813 self.buffer.peek_each(callback)
814 }
815
816 fn available(&self) -> usize {
817 self.buffer.available()
818 }
819
820 fn bytes_read(&self) -> usize {
821 self.buffer.bytes_read()
822 }
823
824 fn drain(&mut self) -> usize {
825 self.buffer.drain()
826 }
827
828 fn advance(&mut self, length: usize) -> Result<(), Errno> {
829 self.buffer.advance(length)
830 }
831}
832
833impl PipeFileObject {
834 fn on_close(&self, flags: OpenFlags) {
836 let mut events = FdEvents::empty();
837 let mut pipe = self.pipe.lock();
838 if flags.can_read() {
839 assert!(pipe.reader_count > 0);
840 pipe.reader_count -= 1;
841 if pipe.reader_count == 0 {
842 events |= FdEvents::POLLOUT | FdEvents::POLLERR;
843 }
844 }
845 if flags.can_write() {
846 assert!(pipe.writer_count > 0);
847 pipe.writer_count -= 1;
848 if pipe.writer_count == 0 {
849 if pipe.reader_count > 0 {
850 events |= FdEvents::POLLHUP;
851 }
852 if !pipe.is_empty() {
853 events |= FdEvents::POLLIN;
854 }
855 }
856 }
857 if events != FdEvents::empty() {
858 pipe.waiters.notify_fd_events(events);
859 }
860 pipe.on_close();
861 }
862
863 fn lock_pipe_without_splice<'a>(
865 &'a self,
866 current_task: &CurrentTask,
867 ) -> Result<LockDepGuard<'a, Pipe>, Errno> {
868 loop {
869 let pipe = self.pipe.lock();
870 if !pipe.splice_read_in_progress && !pipe.splice_write_in_progress {
871 return Ok(pipe);
872 }
873 let waiter = Waiter::new();
874 if pipe.splice_read_in_progress {
875 pipe.waiters.wait_async_value(&waiter, SPLICE_READ_WAIT_KEY);
876 }
877 if pipe.splice_write_in_progress {
878 pipe.waiters.wait_async_value(&waiter, SPLICE_WRITE_WAIT_KEY);
879 }
880 std::mem::drop(pipe);
881 waiter.wait(current_task)?;
882 }
883 }
884
885 fn try_lock_pipe_for_reading<'a>(
887 &'a self,
888 current_task: &CurrentTask,
889 _non_blocking: bool,
890 ) -> Result<LockDepGuard<'a, Pipe>, Errno> {
891 let pipe = self.lock_pipe_without_splice(current_task)?;
892 if pipe.is_readable() { Ok(pipe) } else { error!(EAGAIN) }
893 }
894
895 fn try_lock_pipe_for_writing<'a>(
898 &'a self,
899 current_task: &CurrentTask,
900 _non_blocking: bool,
901 len: usize,
902 ) -> Result<LockDepGuard<'a, Pipe>, Errno> {
903 let pipe = self.lock_pipe_without_splice(current_task)?;
904 if pipe.had_reader && pipe.reader_count == 0 {
905 std::mem::drop(pipe);
906 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
907 return error!(EPIPE);
908 }
909 if !pipe.is_writable(std::cmp::max(len, pipe.min_splice_write_bytes())) {
910 return error!(EAGAIN);
911 }
912 Ok(pipe)
913 }
914
915 fn lock_pipe_for_reading<'a>(
916 &'a self,
917 current_task: &CurrentTask,
918 file: &FileHandle,
919 non_blocking: bool,
920 ) -> Result<LockDepGuard<'a, Pipe>, Errno> {
921 if non_blocking {
922 return self.try_lock_pipe_for_reading(current_task, true);
923 }
924 match self.try_lock_pipe_for_reading(current_task, false) {
925 Err(errno) if errno == EAGAIN => {}
926 result => return result,
927 }
928 let waiter = Waiter::new();
929 loop {
930 file.wait_async(
931 current_task,
932 &waiter,
933 FdEvents::POLLIN | FdEvents::POLLHUP,
934 WaitCallback::none(),
935 );
936 match self.try_lock_pipe_for_reading(current_task, false) {
937 Err(e) if e == EAGAIN => {}
938 result => return result,
939 }
940 waiter.wait(current_task)?;
941 }
942 }
943
944 fn lock_pipe_for_writing<'a>(
945 &'a self,
946 current_task: &CurrentTask,
947 file: &FileHandle,
948 non_blocking: bool,
949 len: usize,
950 ) -> Result<LockDepGuard<'a, Pipe>, Errno> {
951 if non_blocking {
952 return self.try_lock_pipe_for_writing(current_task, true, len);
953 }
954 match self.try_lock_pipe_for_writing(current_task, false, len) {
955 Err(errno) if errno == EAGAIN => {}
956 result => return result,
957 }
958 let waiter = Waiter::new();
959 loop {
960 file.wait_async(
961 current_task,
962 &waiter,
963 FdEvents::POLLOUT | FdEvents::POLLERR,
964 WaitCallback::none(),
965 );
966 match self.try_lock_pipe_for_writing(current_task, false, len) {
967 Err(e) if e == EAGAIN => {}
968 result => return result,
969 }
970 waiter.wait(current_task)?;
971 }
972 }
973
974 pub fn splice_from(
978 &self,
979 current_task: &CurrentTask,
980 self_file: &FileHandle,
981 from: &FileHandle,
982 maybe_offset: Option<usize>,
983 len: usize,
984 non_blocking: bool,
985 ) -> Result<usize, Errno> {
986 assert!(from.downcast_file::<PipeFileObject>().is_none());
988
989 let non_blocking = non_blocking || self_file.is_non_blocking();
990 let mut buffer = {
991 let pipe = self.lock_pipe_for_writing(current_task, self_file, non_blocking, 1)?;
992 let len = std::cmp::min(len, pipe.messages.available_capacity());
993 SpliceOutputBuffer {
994 guard: SpliceWriteGuard::new(&self.pipe, pipe),
995 buffer: VecOutputBuffer::new(len),
996 }
997 };
998
999 let bytes_read = from
1000 .splice_read(current_task, maybe_offset, &mut buffer, non_blocking)
1001 .inspect_err(|err| {
1002 if *err == EPIPE {
1003 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
1004 }
1005 })?;
1006 if bytes_read > 0 {
1007 buffer.guard.enqueue(Vec::from(buffer.buffer)).inspect_err(|err| {
1008 if *err == EPIPE {
1009 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
1010 }
1011 })?;
1012 }
1013 Ok(bytes_read)
1014 }
1015
1016 pub fn splice_to(
1020 &self,
1021 current_task: &CurrentTask,
1022 self_file: &FileHandle,
1023 to: &FileHandle,
1024 maybe_offset: Option<usize>,
1025 len: usize,
1026 non_blocking: bool,
1027 ) -> Result<usize, Errno> {
1028 assert!(to.downcast_file::<PipeFileObject>().is_none());
1030
1031 let non_blocking = non_blocking || self_file.is_non_blocking();
1032 let (read_guard, mut data) = {
1033 let pipe = self.lock_pipe_for_reading(current_task, self_file, non_blocking)?;
1034 let limit = std::cmp::min(len, pipe.messages.len());
1035 let mut data = Vec::with_capacity(limit);
1036 for message in pipe.messages.peek_queue() {
1037 let remaining = limit - data.len();
1038 if remaining == 0 {
1039 break;
1040 }
1041 message.data.with_bytes(|bytes| {
1042 let count = std::cmp::min(bytes.len(), remaining);
1043 data.extend_from_slice(&bytes[..count]);
1044 Ok(())
1045 })?;
1046 }
1047 if data.is_empty() {
1048 return Ok(0);
1049 }
1050 let reserved_bytes = data.len();
1051 let guard = SpliceReadGuard::new(&self.pipe, pipe, reserved_bytes);
1052 (guard, data)
1053 };
1054 let mut clamped_by_fsize = false;
1055 if to.node().is_reg() {
1056 let fsize_limit = current_task.thread_group().get_rlimit(Resource::FSIZE);
1057 if fsize_limit != uapi::RLIM_INFINITY as u64 {
1058 let out_offset = match maybe_offset {
1059 Some(off) => off as u64,
1060 None => to.offset.read().max(0) as u64,
1061 };
1062 if out_offset >= fsize_limit {
1063 send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1064 return error!(EFBIG);
1065 }
1066 let allowed = usize::try_from(fsize_limit - out_offset).unwrap_or(usize::MAX);
1067 if data.len() > allowed {
1068 data.truncate(allowed);
1069 clamped_by_fsize = true;
1070 }
1071 }
1072 }
1073 let mut buffer =
1074 SpliceInputBuffer { guard: read_guard, buffer: VecInputBuffer::from(data) };
1075 let bytes_written =
1076 to.splice_write(current_task, maybe_offset, &mut buffer, non_blocking)?;
1077 if bytes_written > 0 {
1078 if clamped_by_fsize {
1079 send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1080 }
1081 buffer.guard.consume(bytes_written);
1082 }
1083 Ok(bytes_written)
1084 }
1085
1086 pub fn vmsplice_from(
1090 &self,
1091 current_task: &CurrentTask,
1092 self_file: &FileHandle,
1093 mut iovec: UserBuffers,
1094 non_blocking: bool,
1095 ) -> Result<usize, Errno> {
1096 let available = UserBuffer::cap_buffers_to_max_rw_count(
1097 current_task.maximum_valid_address().ok_or_else(|| errno!(EINVAL))?,
1098 &mut iovec,
1099 )?;
1100 if available == 0 {
1101 return Ok(0);
1102 }
1103
1104 let mut pipe = self.lock_pipe_for_writing(current_task, self_file, non_blocking, 1)?;
1105 let max_bytes = std::cmp::min(available, pipe.messages.available_capacity());
1106 let mappings = current_task.mm()?.get_mappings_for_vmsplice(&iovec, max_bytes)?;
1107
1108 let mut bytes_transferred = 0;
1109 for mapping in mappings.into_iter() {
1110 let actual = mapping.len();
1111 pipe.messages.write_message(PipeMessageData::Vmspliced(mapping).into());
1112 bytes_transferred += actual;
1113 }
1114 if bytes_transferred > 0 {
1115 pipe.notify_fd_events(FdEvents::POLLIN);
1116 }
1117 Ok(bytes_transferred)
1118 }
1119
1120 pub fn vmsplice_to(
1124 &self,
1125 current_task: &CurrentTask,
1126 self_file: &FileHandle,
1127 iovec: UserBuffers,
1128 non_blocking: bool,
1129 ) -> Result<usize, Errno> {
1130 let mut data = UserBuffersOutputBuffer::unified_new(current_task, iovec)?;
1131 if data.available() == 0 {
1132 return Ok(0);
1133 }
1134 let mut pipe = self.lock_pipe_for_reading(current_task, self_file, non_blocking)?;
1135 let was_writable = pipe.is_writable(uapi::PIPE_BUF as usize);
1136 let actual = pipe.read(&mut data)?;
1137 if actual > 0 {
1138 pipe.notify_write_space(was_writable);
1139 }
1140 Ok(actual)
1141 }
1142
1143 fn copy_pipes(
1146 current_task: &CurrentTask,
1147 file_in: &FileHandle,
1148 pipe_in: &PipeFileObject,
1149 file_out: &FileHandle,
1150 pipe_out: &PipeFileObject,
1151 len: usize,
1152 non_blocking: bool,
1153 consume_source: bool,
1154 ) -> Result<usize, Errno> {
1155 if Arc::ptr_eq(&pipe_in.pipe, &pipe_out.pipe) {
1158 return error!(EINVAL);
1159 }
1160 if len == 0 {
1161 return Ok(0);
1162 }
1163
1164 let non_blocking = non_blocking || file_in.is_non_blocking() || file_out.is_non_blocking();
1165 let mut waiting_on_out = false;
1166
1167 let (mut from, mut to) = loop {
1168 let (pipe_in_guard, pipe_out_guard) = ordered_lock(&*pipe_in.pipe, &*pipe_out.pipe);
1169
1170 if pipe_in_guard.splice_read_in_progress || pipe_in_guard.splice_write_in_progress {
1171 let waiter = Waiter::new();
1172 let key = if pipe_in_guard.splice_read_in_progress {
1173 SPLICE_READ_WAIT_KEY
1174 } else {
1175 SPLICE_WRITE_WAIT_KEY
1176 };
1177 pipe_in_guard.waiters.wait_async_value(&waiter, key);
1178 std::mem::drop(pipe_in_guard);
1179 std::mem::drop(pipe_out_guard);
1180 waiter.wait(current_task)?;
1181 continue;
1182 }
1183
1184 if !waiting_on_out && !pipe_in_guard.is_readable() {
1185 if non_blocking {
1186 return error!(EAGAIN);
1187 }
1188 let waiter = Waiter::new();
1189 pipe_in_guard.waiters.wait_async_fd_events(
1190 &waiter,
1191 FdEvents::POLLIN | FdEvents::POLLHUP,
1192 WaitCallback::none(),
1193 );
1194 std::mem::drop(pipe_in_guard);
1195 std::mem::drop(pipe_out_guard);
1196 waiter.wait(current_task)?;
1197 continue;
1198 }
1199
1200 if pipe_out_guard.splice_read_in_progress || pipe_out_guard.splice_write_in_progress {
1201 let waiter = Waiter::new();
1202 let key = if pipe_out_guard.splice_read_in_progress {
1203 SPLICE_READ_WAIT_KEY
1204 } else {
1205 SPLICE_WRITE_WAIT_KEY
1206 };
1207 pipe_out_guard.waiters.wait_async_value(&waiter, key);
1208 std::mem::drop(pipe_in_guard);
1209 std::mem::drop(pipe_out_guard);
1210 waiter.wait(current_task)?;
1211 continue;
1212 }
1213
1214 if pipe_out_guard.reader_count == 0 {
1215 std::mem::drop(pipe_in_guard);
1216 std::mem::drop(pipe_out_guard);
1217 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
1218 return error!(EPIPE);
1219 }
1220
1221 if !pipe_out_guard.is_writable(pipe_out_guard.min_splice_write_bytes()) {
1222 if non_blocking {
1223 return error!(EAGAIN);
1224 }
1225 waiting_on_out = true;
1226 let waiter = Waiter::new();
1227 pipe_out_guard.waiters.wait_async_fd_events(
1228 &waiter,
1229 FdEvents::POLLOUT | FdEvents::POLLERR,
1230 WaitCallback::none(),
1231 );
1232 pipe_out_guard.waiters.wait_async_value(&waiter, PIPE_WRITE_SPACE_WAIT_KEY);
1233 std::mem::drop(pipe_in_guard);
1234 std::mem::drop(pipe_out_guard);
1235 waiter.wait(current_task)?;
1236 continue;
1237 }
1238
1239 if waiting_on_out && pipe_in_guard.is_empty() {
1240 if pipe_in_guard.is_readable() || !consume_source {
1241 return Ok(0);
1242 }
1243 waiting_on_out = false;
1244 continue;
1245 }
1246
1247 if pipe_in_guard.is_empty() {
1248 return Ok(0);
1249 }
1250
1251 break (pipe_in_guard, pipe_out_guard);
1252 };
1253
1254 let mut bytes_transferred = 0;
1255 if consume_source {
1256 let was_writable = from.is_writable(uapi::PIPE_BUF as usize);
1257 while bytes_transferred < len && to.messages.available_capacity() > 0 {
1258 let Some(mut message) = from.messages.read_message() else {
1259 break;
1260 };
1261 let limit =
1262 std::cmp::min(len - bytes_transferred, to.messages.available_capacity());
1263 if let Some(remaining) = message.split_off(limit) {
1264 from.messages.write_front(remaining);
1265 }
1266 bytes_transferred += message.len();
1267 to.messages.write_message(message);
1268 }
1269 if bytes_transferred > 0 {
1270 from.notify_write_space(was_writable);
1271 to.notify_fd_events(FdEvents::POLLIN);
1272 }
1273 } else {
1274 let mut cloned_messages = Vec::new();
1275 for message in from.messages.peek_queue() {
1276 let limit = std::cmp::min(
1277 len - bytes_transferred,
1278 to.messages.available_capacity() - bytes_transferred,
1279 );
1280 if limit == 0 {
1281 break;
1282 }
1283 let cloned = message.clone_at_most(limit);
1284 bytes_transferred += cloned.len();
1285 cloned_messages.push(cloned);
1286 }
1287 for message in cloned_messages {
1288 to.messages.write_message(message);
1289 }
1290 if bytes_transferred > 0 {
1291 to.notify_fd_events(FdEvents::POLLIN);
1292 }
1293 }
1294
1295 Ok(bytes_transferred)
1296 }
1297
1298 pub fn splice_pipes(
1300 current_task: &CurrentTask,
1301 file_in: &FileHandle,
1302 pipe_in: &PipeFileObject,
1303 file_out: &FileHandle,
1304 pipe_out: &PipeFileObject,
1305 len: usize,
1306 non_blocking: bool,
1307 ) -> Result<usize, Errno> {
1308 Self::copy_pipes(
1309 current_task,
1310 file_in,
1311 pipe_in,
1312 file_out,
1313 pipe_out,
1314 len,
1315 non_blocking,
1316 true,
1317 )
1318 }
1319
1320 pub fn tee(
1322 current_task: &CurrentTask,
1323 file_in: &FileHandle,
1324 file_out: &FileHandle,
1325 len: usize,
1326 non_blocking: bool,
1327 ) -> Result<usize, Errno> {
1328 let pipe_in = file_in.downcast_file::<PipeFileObject>().ok_or_else(|| errno!(EINVAL))?;
1329 let pipe_out = file_out.downcast_file::<PipeFileObject>().ok_or_else(|| errno!(EINVAL))?;
1330 Self::copy_pipes(
1331 current_task,
1332 file_in,
1333 &pipe_in,
1334 file_out,
1335 &pipe_out,
1336 len,
1337 non_blocking,
1338 false,
1339 )
1340 }
1341}
1342
1343#[cfg(test)]
1344mod tests {
1345 use super::*;
1346 use crate::mm::memory::MemoryObject;
1347 use crate::mm::{ProtectionFlags, VmsplicePayload, VmsplicePayloadSegment};
1348 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
1349 use crate::testing::{anon_test_file, fill_page, map_memory, spawn_kernel_and_run};
1350 use crate::vfs::buffers::UserBuffersInputBuffer;
1351 use crate::vfs::new_memfd;
1352 use smallvec::smallvec;
1353 use starnix_sync::Mutex;
1354 use starnix_uapi::seal_flags::SealFlags;
1355 use std::sync::mpsc;
1356
1357 struct BoundedSinkFile {
1358 max_write: usize,
1359 written: Arc<Mutex<Vec<u8>>>,
1360 }
1361
1362 impl FileOps for BoundedSinkFile {
1363 fileops_impl_nonseekable!();
1364 fileops_impl_noop_sync!();
1365
1366 fn read(
1367 &self,
1368 _file: &FileObject,
1369 _current_task: &CurrentTask,
1370 _offset: usize,
1371 _data: &mut dyn OutputBuffer,
1372 ) -> Result<usize, Errno> {
1373 error!(ENOTSUP)
1374 }
1375
1376 fn write(
1377 &self,
1378 _file: &FileObject,
1379 _current_task: &CurrentTask,
1380 _offset: usize,
1381 data: &mut dyn InputBuffer,
1382 ) -> Result<usize, Errno> {
1383 let mut remaining = self.max_write;
1384 data.read_each(&mut |slice| {
1385 let count = std::cmp::min(slice.len(), remaining);
1386 self.written.lock().extend_from_slice(&slice[..count]);
1387 remaining -= count;
1388 Ok(count)
1389 })
1390 }
1391 }
1392
1393 struct BarrierSinkFile {
1394 entered_tx: Mutex<Option<mpsc::Sender<()>>>,
1395 resume_rx: Mutex<Option<mpsc::Receiver<()>>>,
1396 max_write: usize,
1397 written: Mutex<Vec<u8>>,
1398 }
1399
1400 impl FileOps for BarrierSinkFile {
1401 fileops_impl_nonseekable!();
1402 fileops_impl_noop_sync!();
1403
1404 fn read(
1405 &self,
1406 _file: &FileObject,
1407 _current_task: &CurrentTask,
1408 _offset: usize,
1409 _data: &mut dyn OutputBuffer,
1410 ) -> Result<usize, Errno> {
1411 error!(ENOTSUP)
1412 }
1413
1414 fn write(
1415 &self,
1416 _file: &FileObject,
1417 _current_task: &CurrentTask,
1418 _offset: usize,
1419 data: &mut dyn InputBuffer,
1420 ) -> Result<usize, Errno> {
1421 if let Some(tx) = self.entered_tx.lock().take() {
1422 tx.send(()).expect("notify entered write");
1423 }
1424 if let Some(rx) = self.resume_rx.lock().take() {
1425 rx.recv().expect("wait to resume write");
1426 }
1427 let mut remaining = self.max_write;
1428 data.read_each(&mut |slice| {
1429 let count = std::cmp::min(slice.len(), remaining);
1430 self.written.lock().extend_from_slice(&slice[..count]);
1431 remaining -= count;
1432 Ok(count)
1433 })
1434 }
1435 }
1436
1437 struct StaticSourceFile {
1438 payload: &'static [u8],
1439 }
1440
1441 impl FileOps for StaticSourceFile {
1442 fileops_impl_nonseekable!();
1443 fileops_impl_noop_sync!();
1444
1445 fn read(
1446 &self,
1447 _file: &FileObject,
1448 _current_task: &CurrentTask,
1449 _offset: usize,
1450 data: &mut dyn OutputBuffer,
1451 ) -> Result<usize, Errno> {
1452 data.write(self.payload)
1453 }
1454
1455 fn write(
1456 &self,
1457 _file: &FileObject,
1458 _current_task: &CurrentTask,
1459 _offset: usize,
1460 _data: &mut dyn InputBuffer,
1461 ) -> Result<usize, Errno> {
1462 error!(ENOTSUP)
1463 }
1464 }
1465
1466 struct BarrierSourceFile {
1467 entered_tx: Mutex<Option<mpsc::Sender<()>>>,
1468 resume_rx: Mutex<Option<mpsc::Receiver<()>>>,
1469 payload: &'static [u8],
1470 }
1471
1472 impl FileOps for BarrierSourceFile {
1473 fileops_impl_nonseekable!();
1474 fileops_impl_noop_sync!();
1475
1476 fn read(
1477 &self,
1478 _file: &FileObject,
1479 _current_task: &CurrentTask,
1480 _offset: usize,
1481 data: &mut dyn OutputBuffer,
1482 ) -> Result<usize, Errno> {
1483 if let Some(tx) = self.entered_tx.lock().take() {
1484 tx.send(()).expect("notify entered read");
1485 }
1486 if let Some(rx) = self.resume_rx.lock().take() {
1487 rx.recv().expect("wait to resume read");
1488 }
1489 data.write(self.payload)
1490 }
1491
1492 fn write(
1493 &self,
1494 _file: &FileObject,
1495 _current_task: &CurrentTask,
1496 _offset: usize,
1497 _data: &mut dyn InputBuffer,
1498 ) -> Result<usize, Errno> {
1499 error!(ENOTSUP)
1500 }
1501 }
1502
1503 #[::fuchsia::test]
1504 async fn test_splice_to_partial_write_preserves_fifo_order() {
1505 spawn_kernel_and_run(async |current_task| {
1506 let kernel = current_task.kernel();
1507 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1508
1509 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1511 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAA")).unwrap(), 4);
1512 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"BBBB")).unwrap(), 4);
1513
1514 let sink_written = Arc::new(Mutex::new(Vec::new()));
1515 let sink_file = anon_test_file(
1516 ¤t_task,
1517 Box::new(BoundedSinkFile { max_write: 2, written: Arc::clone(&sink_written) }),
1518 OpenFlags::WRONLY,
1519 );
1520 let spliced = pipe_out
1521 .downcast_file::<PipeFileObject>()
1522 .unwrap()
1523 .splice_to(¤t_task, &pipe_out, &sink_file, None, 6, true)
1524 .unwrap();
1525 assert_eq!(spliced, 2);
1526 assert_eq!(*sink_written.lock(), b"AA");
1527
1528 let mut remaining = Vec::new();
1529 loop {
1530 let mut out = VecOutputBuffer::new(16);
1531 match pipe_out.read(¤t_task, &mut out) {
1532 Ok(n) if n > 0 => {
1533 remaining.extend_from_slice(&out.data()[..n]);
1534 if remaining.len() == 6 {
1535 break;
1536 }
1537 }
1538 _ => break,
1539 }
1540 }
1541 assert_eq!(remaining, b"AABBBB");
1542
1543 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1545 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAA")).unwrap(), 4);
1546 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"BBBB")).unwrap(), 4);
1547
1548 let (entered_tx, entered_rx) = mpsc::channel();
1549 let (resume_tx, resume_rx) = mpsc::channel();
1550 let barrier_sink = anon_test_file(
1551 ¤t_task,
1552 Box::new(BarrierSinkFile {
1553 entered_tx: Mutex::new(Some(entered_tx)),
1554 resume_rx: Mutex::new(Some(resume_rx)),
1555 max_write: 2,
1556 written: Mutex::new(Vec::new()),
1557 }),
1558 OpenFlags::WRONLY,
1559 );
1560
1561 let (reader_ready_tx, reader_ready_rx) = mpsc::channel();
1562 let pipe_out_unblock = pipe_out.clone();
1563 let (unblock_join, unblock_req) = SpawnRequestBuilder::new()
1564 .with_sync_closure(move |_worker_task: &CurrentTask| {
1565 reader_ready_rx.recv().expect("wait until non-blocking reader starts");
1566 while pipe_out_unblock
1567 .downcast_file::<PipeFileObject>()
1568 .unwrap()
1569 .pipe
1570 .lock()
1571 .waiters
1572 .is_empty()
1573 {
1574 std::thread::yield_now();
1575 }
1576 resume_tx.send(()).expect("allow splice_to write to complete");
1577 })
1578 .build_with_sync_result();
1579 kernel.kthreads.spawner().spawn_from_request(unblock_req);
1580
1581 let pipe_out_clone = pipe_out.clone();
1582 let (reader_join, req) = SpawnRequestBuilder::new()
1583 .with_sync_closure(move |worker_task: &CurrentTask| {
1584 entered_rx.recv().expect("wait until splice_to enters write");
1585 {
1586 let pipe =
1587 pipe_out_clone.downcast_file::<PipeFileObject>().unwrap().pipe.lock();
1588 assert!(pipe.splice_read_in_progress);
1589 assert_eq!(pipe.messages.len(), 8);
1590 }
1591 reader_ready_tx.send(()).expect("signal unblocker");
1592 let mut pipe = pipe_out_clone
1595 .downcast_file::<PipeFileObject>()
1596 .unwrap()
1597 .lock_pipe_for_reading(worker_task, &pipe_out_clone, true)
1598 .expect("non-blocking read lock succeeds once splice_to finishes");
1599 let mut buf = VecOutputBuffer::new(4);
1600 let n = pipe.read(&mut buf).unwrap();
1601 buf.data()[..n].to_vec()
1602 })
1603 .build_with_sync_result();
1604 kernel.kthreads.spawner().spawn_from_request(req);
1605
1606 let spliced = pipe_out
1607 .downcast_file::<PipeFileObject>()
1608 .unwrap()
1609 .splice_to(¤t_task, &pipe_out, &barrier_sink, None, 8, true)
1610 .unwrap();
1611 assert_eq!(spliced, 2);
1612 unblock_join().unwrap();
1613
1614 let concurrent_bytes = reader_join().unwrap();
1616 assert_eq!(concurrent_bytes, b"AABB");
1617
1618 let mut tail_buf = VecOutputBuffer::new(4);
1620 let tail_len = pipe_out.read(¤t_task, &mut tail_buf).unwrap();
1621 assert_eq!(&tail_buf.data()[..tail_len], b"BB");
1622 })
1623 .await;
1624 }
1625
1626 #[::fuchsia::test]
1627 async fn test_splice_from_serializes_concurrent_writers() {
1628 spawn_kernel_and_run(async |current_task| {
1629 let kernel = current_task.kernel();
1630 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1631
1632 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1633 let capacity =
1634 pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
1635 let prefix = vec![b'P'; capacity - 8];
1636 assert_eq!(
1637 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&prefix)).unwrap(),
1638 capacity - 8
1639 );
1640
1641 let (entered_tx, entered_rx) = mpsc::channel();
1642 let (resume_tx, resume_rx) = mpsc::channel();
1643 let barrier_source = anon_test_file(
1644 ¤t_task,
1645 Box::new(BarrierSourceFile {
1646 entered_tx: Mutex::new(Some(entered_tx)),
1647 resume_rx: Mutex::new(Some(resume_rx)),
1648 payload: b"SSSS",
1649 }),
1650 OpenFlags::RDONLY,
1651 );
1652
1653 let (writer_ready_tx, writer_ready_rx) = mpsc::channel();
1654 let pipe_in_unblock = pipe_in.clone();
1655 let (unblock_join, unblock_req) = SpawnRequestBuilder::new()
1656 .with_sync_closure(move |_worker_task: &CurrentTask| {
1657 writer_ready_rx.recv().expect("wait until non-blocking writer starts");
1658 while pipe_in_unblock
1659 .downcast_file::<PipeFileObject>()
1660 .unwrap()
1661 .pipe
1662 .lock()
1663 .waiters
1664 .is_empty()
1665 {
1666 std::thread::yield_now();
1667 }
1668 resume_tx.send(()).expect("allow splice_from read to complete");
1669 })
1670 .build_with_sync_result();
1671 kernel.kthreads.spawner().spawn_from_request(unblock_req);
1672
1673 let pipe_in_clone = pipe_in.clone();
1674 let (writer_join, req) = SpawnRequestBuilder::new()
1675 .with_sync_closure(move |worker_task: &CurrentTask| {
1676 entered_rx.recv().expect("wait until splice_from enters read");
1677 {
1678 let pipe =
1679 pipe_in_clone.downcast_file::<PipeFileObject>().unwrap().pipe.lock();
1680 assert!(pipe.splice_write_in_progress);
1681 assert_eq!(pipe.messages.available_capacity(), 8);
1682 }
1683 writer_ready_tx.send(()).expect("signal unblocker");
1684 let mut pipe = pipe_in_clone
1687 .downcast_file::<PipeFileObject>()
1688 .unwrap()
1689 .lock_pipe_for_writing(worker_task, &pipe_in_clone, true, 4)
1690 .expect("non-blocking write lock succeeds once splice_from finishes");
1691 assert_eq!(pipe.write(&mut VecInputBuffer::new(b"WWWW")).unwrap(), 4);
1692 std::mem::drop(pipe);
1693
1694 std::mem::drop(
1695 pipe_in_clone
1696 .downcast_file::<PipeFileObject>()
1697 .unwrap()
1698 .lock_pipe_without_splice(worker_task)
1699 .unwrap(),
1700 );
1701 pipe_in_clone
1703 .downcast_file::<PipeFileObject>()
1704 .unwrap()
1705 .lock_pipe_for_writing(worker_task, &pipe_in_clone, true, 4)
1706 .err()
1707 .expect("pipe should be full once splice_from and concurrent write finish")
1708 })
1709 .build_with_sync_result();
1710 kernel.kthreads.spawner().spawn_from_request(req);
1711
1712 let spliced = pipe_in
1713 .downcast_file::<PipeFileObject>()
1714 .unwrap()
1715 .splice_from(¤t_task, &pipe_in, &barrier_source, None, 4, true)
1716 .unwrap();
1717 assert_eq!(spliced, 4);
1718 unblock_join().unwrap();
1719 assert_eq!(writer_join().unwrap(), errno!(EAGAIN));
1720
1721 let mut pre_buf = VecOutputBuffer::new(capacity - 8);
1722 assert_eq!(pipe_out.read(¤t_task, &mut pre_buf).unwrap(), capacity - 8);
1723 let mut spliced_buf = VecOutputBuffer::new(8);
1724 assert_eq!(pipe_out.read(¤t_task, &mut spliced_buf).unwrap(), 8);
1725 assert_eq!(spliced_buf.data(), b"SSSSWWWW");
1726 })
1727 .await;
1728 }
1729
1730 #[::fuchsia::test]
1731 async fn test_splice_from_closed_reader_returns_epipe_and_queues_sigpipe() {
1732 spawn_kernel_and_run(async |current_task| {
1733 let kernel = current_task.kernel();
1734 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1735
1736 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1737 std::mem::drop(pipe_out);
1738 current_task.trigger_delayed_releaser();
1739
1740 let source_file = anon_test_file(
1741 ¤t_task,
1742 Box::new(StaticSourceFile { payload: b"DATA" }),
1743 OpenFlags::RDONLY,
1744 );
1745 let err = pipe_in
1746 .downcast_file::<PipeFileObject>()
1747 .unwrap()
1748 .splice_from(¤t_task, &pipe_in, &source_file, None, 4, true)
1749 .unwrap_err();
1750 assert_eq!(err, errno!(EPIPE));
1751 assert!(current_task.write().signals_mut().has_queued(SIGPIPE));
1752 })
1753 .await;
1754 }
1755
1756 #[::fuchsia::test]
1757 async fn test_copy_pipes_with_vmspliced_payload() {
1758 spawn_kernel_and_run(async |current_task| {
1759 let kernel = current_task.kernel();
1760 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1761
1762 let (pipe_a_out, pipe_a_in) = new_pipe(¤t_task).unwrap();
1763 let (pipe_b_out, pipe_b_in) = new_pipe(¤t_task).unwrap();
1764
1765 let mm = current_task.mm().unwrap();
1766 let page_size = *PAGE_SIZE as usize;
1767 let memory = Arc::new(MemoryObject::from(zx::Vmo::create(page_size as u64).unwrap()));
1768 memory.write(b"VMSPLICED_DATA", 0).unwrap();
1769 let payload = VmsplicePayload::new(
1770 Arc::downgrade(&mm),
1771 VmsplicePayloadSegment {
1772 addr_offset: UserAddress::NULL,
1773 length: 14,
1774 memory,
1775 memory_offset: 0,
1776 should_snapshot_on_unmap: true,
1777 },
1778 );
1779 pipe_a_in
1780 .downcast_file::<PipeFileObject>()
1781 .unwrap()
1782 .pipe
1783 .lock()
1784 .messages
1785 .write_message(PipeMessageData::Vmspliced(payload).into());
1786
1787 let copied = PipeFileObject::copy_pipes(
1788 ¤t_task,
1789 &pipe_a_out,
1790 &pipe_a_out.downcast_file::<PipeFileObject>().unwrap(),
1791 &pipe_b_in,
1792 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
1793 10,
1794 false,
1795 false,
1796 )
1797 .unwrap();
1798 assert_eq!(copied, 10);
1799
1800 let mut buf_b = VecOutputBuffer::new(10);
1801 assert_eq!(pipe_b_out.read(¤t_task, &mut buf_b).unwrap(), 10);
1802 assert_eq!(buf_b.data(), b"VMSPLICED_");
1803
1804 let mut buf_a = VecOutputBuffer::new(14);
1805 assert_eq!(pipe_a_out.read(¤t_task, &mut buf_a).unwrap(), 14);
1806 assert_eq!(buf_a.data(), b"VMSPLICED_DATA");
1807 })
1808 .await;
1809 }
1810 #[::fuchsia::test]
1811 async fn test_splice_from_reader_closes_during_read_returns_epipe() {
1812 spawn_kernel_and_run(async |current_task| {
1813 let kernel = current_task.kernel();
1814 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1815
1816 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1817 let (entered_tx, entered_rx) = mpsc::channel();
1818 let (resume_tx, resume_rx) = mpsc::channel();
1819 let barrier_source = anon_test_file(
1820 ¤t_task,
1821 Box::new(BarrierSourceFile {
1822 entered_tx: Mutex::new(Some(entered_tx)),
1823 resume_rx: Mutex::new(Some(resume_rx)),
1824 payload: b"DATA",
1825 }),
1826 OpenFlags::RDONLY,
1827 );
1828
1829 let (closer_join, req) = SpawnRequestBuilder::new()
1830 .with_sync_closure(move |worker_task: &CurrentTask| {
1831 entered_rx.recv().expect("wait until splice_from enters read");
1832 std::mem::drop(pipe_out);
1833 worker_task.trigger_delayed_releaser();
1834 resume_tx.send(()).expect("allow splice_from read to complete");
1835 })
1836 .build_with_sync_result();
1837 kernel.kthreads.spawner().spawn_from_request(req);
1838
1839 let err = pipe_in
1840 .downcast_file::<PipeFileObject>()
1841 .unwrap()
1842 .splice_from(¤t_task, &pipe_in, &barrier_source, None, 4, true)
1843 .unwrap_err();
1844 closer_join().unwrap();
1845 assert_eq!(err, errno!(EPIPE));
1846 assert!(current_task.write().signals_mut().has_queued(SIGPIPE));
1847 assert_eq!(
1848 pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().messages.len(),
1849 0
1850 );
1851 })
1852 .await;
1853 }
1854
1855 #[::fuchsia::test]
1856 async fn test_partial_read_wakes_blocked_writer() {
1857 spawn_kernel_and_run(async |current_task| {
1858 let kernel = current_task.kernel();
1859 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1860
1861 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1862 let capacity =
1863 pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
1864 let fill = vec![b'A'; capacity];
1865 assert_eq!(
1866 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
1867 capacity
1868 );
1869
1870 let pipe_in_clone = pipe_in.clone();
1871 let (writer_join, req) = SpawnRequestBuilder::new()
1872 .with_sync_closure(move |worker_task: &CurrentTask| {
1873 pipe_in_clone
1874 .write(worker_task, &mut VecInputBuffer::new(b"BBBB"))
1875 .expect("blocked write should succeed after partial read")
1876 })
1877 .build_with_sync_result();
1878 kernel.kthreads.spawner().spawn_from_request(req);
1879
1880 while pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().waiters.is_empty()
1881 {
1882 std::thread::yield_now();
1883 }
1884
1885 let page_size = *PAGE_SIZE as usize;
1887 let mut partial = VecOutputBuffer::new(page_size);
1888 assert_eq!(pipe_out.read(¤t_task, &mut partial).unwrap(), page_size);
1889 assert_eq!(partial.data(), &fill[..page_size]);
1890
1891 assert_eq!(writer_join().unwrap(), 4);
1892 })
1893 .await;
1894 }
1895
1896 struct WouldBlockEndpointFile;
1897
1898 impl FileOps for WouldBlockEndpointFile {
1899 fileops_impl_nonseekable!();
1900 fileops_impl_noop_sync!();
1901
1902 fn read(
1903 &self,
1904 file: &FileObject,
1905 current_task: &CurrentTask,
1906 _offset: usize,
1907 _data: &mut dyn OutputBuffer,
1908 ) -> Result<usize, Errno> {
1909 file.blocking_op(current_task, FdEvents::POLLIN, None, || error!(EAGAIN))
1910 }
1911
1912 fn write(
1913 &self,
1914 file: &FileObject,
1915 current_task: &CurrentTask,
1916 _offset: usize,
1917 _data: &mut dyn InputBuffer,
1918 ) -> Result<usize, Errno> {
1919 file.blocking_op(current_task, FdEvents::POLLOUT, None, || error!(EAGAIN))
1920 }
1921
1922 fn wait_async(
1923 &self,
1924 _file: &FileObject,
1925 _current_task: &CurrentTask,
1926 _waiter: &Waiter,
1927 _events: FdEvents,
1928 _handler: EventHandler,
1929 ) -> Option<WaitCanceler> {
1930 Some(WaitCanceler::new_noop())
1931 }
1932 }
1933
1934 #[::fuchsia::test]
1935 async fn test_splice_non_blocking_unix_stream_and_pipe_flags() {
1936 spawn_kernel_and_run(async |current_task| {
1937 let kernel = current_task.kernel();
1938 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1939
1940 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1941 let (unix_sock, unix_peer) = crate::vfs::socket::UnixSocket::new_pair(
1942 ¤t_task,
1943 crate::vfs::socket::SocketDomain::Unix,
1944 crate::vfs::socket::SocketType::Stream,
1945 OpenFlags::RDWR,
1946 )
1947 .unwrap();
1948 let blocking_sink =
1949 anon_test_file(¤t_task, Box::new(WouldBlockEndpointFile), OpenFlags::WRONLY);
1950
1951 assert_eq!(
1954 pipe_in
1955 .downcast_file::<PipeFileObject>()
1956 .unwrap()
1957 .splice_from(¤t_task, &pipe_in, &unix_sock, None, 4, true)
1958 .unwrap_err(),
1959 errno!(EAGAIN)
1960 );
1961 assert!(!unix_sock.is_non_blocking());
1962
1963 pipe_in.update_file_flags(OpenFlags::NONBLOCK, OpenFlags::NONBLOCK);
1966 assert_eq!(
1967 pipe_in
1968 .downcast_file::<PipeFileObject>()
1969 .unwrap()
1970 .splice_from(¤t_task, &pipe_in, &unix_sock, None, 4, false)
1971 .unwrap_err(),
1972 errno!(EAGAIN)
1973 );
1974 assert!(!unix_sock.is_non_blocking());
1975
1976 assert_eq!(
1979 unix_peer.write(¤t_task, &mut VecInputBuffer::new(b"ABCD")).unwrap(),
1980 4
1981 );
1982 assert_eq!(
1983 pipe_in
1984 .downcast_file::<PipeFileObject>()
1985 .unwrap()
1986 .splice_from(¤t_task, &pipe_in, &unix_sock, None, 4, false)
1987 .unwrap(),
1988 4
1989 );
1990 let mut read_buf = VecOutputBuffer::new(4);
1991 assert_eq!(pipe_out.read(¤t_task, &mut read_buf).unwrap(), 4);
1992 assert_eq!(read_buf.data(), b"ABCD");
1993 assert!(!unix_sock.is_non_blocking());
1994
1995 pipe_out.update_file_flags(OpenFlags::NONBLOCK, OpenFlags::NONBLOCK);
1998 assert_eq!(
1999 pipe_out
2000 .downcast_file::<PipeFileObject>()
2001 .unwrap()
2002 .splice_to(¤t_task, &pipe_out, &blocking_sink, None, 4, false)
2003 .unwrap_err(),
2004 errno!(EAGAIN)
2005 );
2006 })
2007 .await;
2008 }
2009
2010 #[::fuchsia::test]
2011 async fn test_fcntl_getpipe_sz_and_setpipe_sz_during_active_splice() {
2012 spawn_kernel_and_run(async |current_task| {
2013 let kernel = current_task.kernel();
2014 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2015
2016 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2017 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"DATA")).unwrap(), 4);
2018 let initial_capacity =
2019 pipe_out.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
2020
2021 let (entered_tx, entered_rx) = mpsc::channel();
2023 let (resume_tx, resume_rx) = mpsc::channel();
2024 let barrier_sink = anon_test_file(
2025 ¤t_task,
2026 Box::new(BarrierSinkFile {
2027 entered_tx: Mutex::new(Some(entered_tx)),
2028 resume_rx: Mutex::new(Some(resume_rx)),
2029 max_write: 4,
2030 written: Mutex::new(Vec::new()),
2031 }),
2032 OpenFlags::WRONLY,
2033 );
2034
2035 let (ready_tx, ready_rx) = mpsc::channel();
2036 let pipe_out_unblock = pipe_out.clone();
2037 let (unblock_join, unblock_req) = SpawnRequestBuilder::new()
2038 .with_sync_closure(move |_worker_task: &CurrentTask| {
2039 ready_rx.recv().expect("wait until F_GETPIPE_SZ starts");
2040 while pipe_out_unblock
2041 .downcast_file::<PipeFileObject>()
2042 .unwrap()
2043 .pipe
2044 .lock()
2045 .waiters
2046 .is_empty()
2047 {
2048 std::thread::yield_now();
2049 }
2050 resume_tx.send(()).expect("allow splice_to write to complete");
2051 })
2052 .build_with_sync_result();
2053 kernel.kthreads.spawner().spawn_from_request(unblock_req);
2054
2055 let pipe_out_clone = pipe_out.clone();
2056 let (fcntl_join, req) = SpawnRequestBuilder::new()
2057 .with_sync_closure(move |worker_task: &CurrentTask| {
2058 entered_rx.recv().expect("wait until splice_to enters write");
2059 ready_tx.send(()).expect("signal unblocker");
2060 let got_sz =
2062 pipe_out_clone.fcntl(worker_task, F_GETPIPE_SZ, 0).expect("F_GETPIPE_SZ");
2063 assert_eq!(got_sz, initial_capacity.into());
2064
2065 let new_sz = (*PAGE_SIZE as u64) * 2;
2066 pipe_out_clone
2067 .fcntl(worker_task, F_SETPIPE_SZ, new_sz)
2068 .expect("F_SETPIPE_SZ after splice_to")
2069 })
2070 .build_with_sync_result();
2071 kernel.kthreads.spawner().spawn_from_request(req);
2072
2073 let spliced = pipe_out
2074 .downcast_file::<PipeFileObject>()
2075 .unwrap()
2076 .splice_to(¤t_task, &pipe_out, &barrier_sink, None, 4, true)
2077 .unwrap();
2078 assert_eq!(spliced, 4);
2079 unblock_join().unwrap();
2080 assert_eq!(fcntl_join().unwrap(), ((*PAGE_SIZE as usize) * 2).into());
2081
2082 let (entered_tx2, entered_rx2) = mpsc::channel();
2084 let (resume_tx2, resume_rx2) = mpsc::channel();
2085 let barrier_source = anon_test_file(
2086 ¤t_task,
2087 Box::new(BarrierSourceFile {
2088 entered_tx: Mutex::new(Some(entered_tx2)),
2089 resume_rx: Mutex::new(Some(resume_rx2)),
2090 payload: b"DATA",
2091 }),
2092 OpenFlags::RDONLY,
2093 );
2094
2095 let (ready_tx2, ready_rx2) = mpsc::channel();
2096 let pipe_in_unblock = pipe_in.clone();
2097 let (unblock_join2, unblock_req2) = SpawnRequestBuilder::new()
2098 .with_sync_closure(move |_worker_task: &CurrentTask| {
2099 ready_rx2.recv().expect("wait until F_SETPIPE_SZ starts");
2100 while pipe_in_unblock
2101 .downcast_file::<PipeFileObject>()
2102 .unwrap()
2103 .pipe
2104 .lock()
2105 .waiters
2106 .is_empty()
2107 {
2108 std::thread::yield_now();
2109 }
2110 resume_tx2.send(()).expect("allow splice_from read to complete");
2111 })
2112 .build_with_sync_result();
2113 kernel.kthreads.spawner().spawn_from_request(unblock_req2);
2114
2115 let pipe_in_clone = pipe_in.clone();
2116 let (fcntl_join2, req2) = SpawnRequestBuilder::new()
2117 .with_sync_closure(move |worker_task: &CurrentTask| {
2118 entered_rx2.recv().expect("wait until splice_from enters read");
2119 ready_tx2.send(()).expect("signal unblocker");
2120 let new_sz = (*PAGE_SIZE as u64) * 4;
2121 let set_sz = pipe_in_clone
2122 .fcntl(worker_task, F_SETPIPE_SZ, new_sz)
2123 .expect("F_SETPIPE_SZ after splice_from");
2124 assert_eq!(set_sz, ((*PAGE_SIZE as usize) * 4).into());
2125 pipe_in_clone.fcntl(worker_task, F_GETPIPE_SZ, 0).expect("F_GETPIPE_SZ")
2126 })
2127 .build_with_sync_result();
2128 kernel.kthreads.spawner().spawn_from_request(req2);
2129
2130 let spliced2 = pipe_in
2131 .downcast_file::<PipeFileObject>()
2132 .unwrap()
2133 .splice_from(¤t_task, &pipe_in, &barrier_source, None, 4, true)
2134 .unwrap();
2135 assert_eq!(spliced2, 4);
2136 unblock_join2().unwrap();
2137 assert_eq!(fcntl_join2().unwrap(), ((*PAGE_SIZE as usize) * 4).into());
2138 })
2139 .await;
2140 }
2141
2142 #[::fuchsia::test]
2143 async fn test_splice_short_transfer_when_available_capacity_below_pipe_buf() {
2144 spawn_kernel_and_run(async |current_task| {
2145 let kernel = current_task.kernel();
2146 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2147
2148 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2149 let capacity =
2150 pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
2151 let fill = vec![b'P'; capacity - 4];
2152 assert_eq!(
2153 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
2154 capacity - 4
2155 );
2156
2157 let source_file = anon_test_file(
2160 ¤t_task,
2161 Box::new(StaticSourceFile { payload: b"12345678" }),
2162 OpenFlags::RDONLY,
2163 );
2164 let spliced = pipe_in
2165 .downcast_file::<PipeFileObject>()
2166 .unwrap()
2167 .splice_from(¤t_task, &pipe_in, &source_file, None, 8, true)
2168 .unwrap();
2169 assert_eq!(spliced, 4);
2170
2171 let (pipe_b_out, pipe_b_in) = new_pipe(¤t_task).unwrap();
2173 assert_eq!(
2174 pipe_b_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
2175 capacity - 4
2176 );
2177 let copied = PipeFileObject::copy_pipes(
2178 ¤t_task,
2179 &pipe_out,
2180 &pipe_out.downcast_file::<PipeFileObject>().unwrap(),
2181 &pipe_b_in,
2182 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
2183 8,
2184 true,
2185 true,
2186 )
2187 .unwrap();
2188 assert_eq!(copied, 4);
2189 let _ = pipe_b_out;
2190 })
2191 .await;
2192 }
2193
2194 #[::fuchsia::test]
2195 async fn test_copy_pipes_honors_nonblock_and_eof_and_epipe() {
2196 spawn_kernel_and_run(async |current_task| {
2197 let kernel = current_task.kernel();
2198 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2199
2200 let (pipe_a_out, pipe_a_in) = new_pipe(¤t_task).unwrap();
2202 let (pipe_b_out, pipe_b_in) = new_pipe(¤t_task).unwrap();
2203 pipe_b_in.update_file_flags(OpenFlags::NONBLOCK, OpenFlags::NONBLOCK);
2204 assert_eq!(
2205 PipeFileObject::copy_pipes(
2206 ¤t_task,
2207 &pipe_a_out,
2208 &pipe_a_out.downcast_file::<PipeFileObject>().unwrap(),
2209 &pipe_b_in,
2210 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
2211 4,
2212 false,
2213 false,
2214 )
2215 .unwrap_err(),
2216 errno!(EAGAIN)
2217 );
2218
2219 std::mem::drop(pipe_a_in);
2223 current_task.trigger_delayed_releaser();
2224 assert_eq!(
2225 PipeFileObject::copy_pipes(
2226 ¤t_task,
2227 &pipe_a_out,
2228 &pipe_a_out.downcast_file::<PipeFileObject>().unwrap(),
2229 &pipe_b_in,
2230 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
2231 4,
2232 true,
2233 false,
2234 )
2235 .unwrap(),
2236 0
2237 );
2238 let capacity =
2239 pipe_b_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
2240 let fill = vec![b'F'; capacity];
2241 assert_eq!(
2242 pipe_b_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
2243 capacity
2244 );
2245 assert_eq!(
2246 PipeFileObject::copy_pipes(
2247 ¤t_task,
2248 &pipe_a_out,
2249 &pipe_a_out.downcast_file::<PipeFileObject>().unwrap(),
2250 &pipe_b_in,
2251 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
2252 4,
2253 true,
2254 false,
2255 )
2256 .unwrap_err(),
2257 errno!(EAGAIN)
2258 );
2259
2260 std::mem::drop(pipe_b_out);
2262 current_task.trigger_delayed_releaser();
2263 assert_eq!(
2264 PipeFileObject::copy_pipes(
2265 ¤t_task,
2266 &pipe_a_out,
2267 &pipe_a_out.downcast_file::<PipeFileObject>().unwrap(),
2268 &pipe_b_in,
2269 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
2270 4,
2271 true,
2272 false,
2273 )
2274 .unwrap_err(),
2275 errno!(EPIPE)
2276 );
2277 assert!(current_task.write().signals_mut().has_queued(SIGPIPE));
2278 })
2279 .await;
2280 }
2281
2282 #[::fuchsia::test]
2283 async fn test_copy_pipes_wakes_with_epipe_when_destination_reader_closes() {
2284 spawn_kernel_and_run(async |current_task| {
2285 let kernel = current_task.kernel();
2286 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2287
2288 let (pipe_a_out, pipe_a_in) = new_pipe(¤t_task).unwrap();
2289 let (pipe_b_out, pipe_b_in) = new_pipe(¤t_task).unwrap();
2290 assert_eq!(
2291 pipe_a_in.write(¤t_task, &mut VecInputBuffer::new(b"DATA")).unwrap(),
2292 4
2293 );
2294 let capacity =
2295 pipe_b_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
2296 let fill = vec![b'F'; capacity];
2297 assert_eq!(
2298 pipe_b_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
2299 capacity
2300 );
2301
2302 let pipe_b_in_clone = pipe_b_in.clone();
2303 let (closer_join, req) = SpawnRequestBuilder::new()
2304 .with_sync_closure(move |worker_task: &CurrentTask| {
2305 while pipe_b_in_clone
2306 .downcast_file::<PipeFileObject>()
2307 .unwrap()
2308 .pipe
2309 .lock()
2310 .waiters
2311 .is_empty()
2312 {
2313 std::thread::yield_now();
2314 }
2315 std::mem::drop(pipe_b_out);
2316 worker_task.trigger_delayed_releaser();
2317 })
2318 .build_with_sync_result();
2319 kernel.kthreads.spawner().spawn_from_request(req);
2320
2321 let err = PipeFileObject::copy_pipes(
2322 ¤t_task,
2323 &pipe_a_out,
2324 &pipe_a_out.downcast_file::<PipeFileObject>().unwrap(),
2325 &pipe_b_in,
2326 &pipe_b_in.downcast_file::<PipeFileObject>().unwrap(),
2327 4,
2328 false,
2329 true,
2330 )
2331 .unwrap_err();
2332 closer_join().unwrap();
2333 assert_eq!(err, errno!(EPIPE));
2334 assert!(current_task.write().signals_mut().has_queued(SIGPIPE));
2335 })
2336 .await;
2337 }
2338
2339 #[::fuchsia::test]
2340 async fn test_splice_to_eof_pipe_does_not_invoke_destination_write() {
2341 spawn_kernel_and_run(async |current_task| {
2342 let kernel = current_task.kernel();
2343 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2344
2345 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2346 std::mem::drop(pipe_in);
2347 current_task.trigger_delayed_releaser();
2348
2349 let endpoint =
2350 anon_test_file(¤t_task, Box::new(WouldBlockEndpointFile), OpenFlags::WRONLY);
2351 let pipe_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
2352
2353 assert_eq!(
2356 pipe_ops.splice_to(¤t_task, &pipe_out, &endpoint, None, 16, true).unwrap(),
2357 0
2358 );
2359 })
2360 .await;
2361 }
2362
2363 #[::fuchsia::test]
2364 async fn test_pipe_readiness_and_fionread_during_eof_and_active_splice() {
2365 spawn_kernel_and_run(async |current_task| {
2366 let kernel = current_task.kernel();
2367 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2368
2369 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2370 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AB")).unwrap(), 2);
2371
2372 let waiter = Waiter::new();
2375 pipe_out.wait_async(¤t_task, &waiter, FdEvents::POLLIN, WaitCallback::none());
2376 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"CD")).unwrap(), 2);
2377 waiter.wait(¤t_task).expect("write to non-empty pipe must notify POLLIN");
2378
2379 let pipe_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
2381 let guard = SpliceReadGuard::new(&pipe_ops.pipe, pipe_ops.pipe.lock(), 4);
2382 assert_eq!(pipe_out.query_events(¤t_task).unwrap(), FdEvents::empty());
2383 assert_eq!(pipe_ops.pipe.lock().readable_len(), 0);
2384 assert!(!pipe_ops.pipe.lock().is_readable());
2385
2386 let pipe_in_clone = pipe_in.clone();
2389 let (writer_join, req) = SpawnRequestBuilder::new()
2390 .with_sync_closure(move |worker_task: &CurrentTask| {
2391 pipe_in_clone
2392 .write(worker_task, &mut VecInputBuffer::new(b"EF"))
2393 .expect("write after active splice read")
2394 })
2395 .build_with_sync_result();
2396 kernel.kthreads.spawner().spawn_from_request(req);
2397 while pipe_ops.pipe.lock().waiters.is_empty() {
2398 std::thread::yield_now();
2399 }
2400
2401 let waiter2 = Waiter::new();
2402 pipe_out.wait_async(¤t_task, &waiter2, FdEvents::POLLIN, WaitCallback::none());
2403 guard.consume(4);
2404 assert_eq!(writer_join().unwrap(), 2);
2405 assert_eq!(
2406 pipe_out.query_events(¤t_task).unwrap(),
2407 FdEvents::POLLIN | FdEvents::POLLRDNORM
2408 );
2409 assert_eq!(pipe_ops.pipe.lock().readable_len(), 2);
2410 waiter2.wait(¤t_task).expect("write after splice read must notify POLLIN");
2411
2412 let mut remaining = VecOutputBuffer::new(2);
2413 assert_eq!(pipe_out.read(¤t_task, &mut remaining).unwrap(), 2);
2414 assert_eq!(remaining.data(), b"EF");
2415
2416 std::mem::drop(pipe_in);
2418 current_task.trigger_delayed_releaser();
2419 assert_eq!(pipe_out.query_events(¤t_task).unwrap(), FdEvents::POLLHUP);
2420 })
2421 .await;
2422 }
2423
2424 #[::fuchsia::test]
2425 async fn test_zero_length_pipe_io_and_no_empty_message_enqueued() {
2426 spawn_kernel_and_run(async |current_task| {
2427 let kernel = current_task.kernel();
2428 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2429
2430 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2431 let pipe_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
2432
2433 assert_eq!(pipe_ops.pipe.lock().read(&mut VecOutputBuffer::new(0)).unwrap(), 0);
2435 assert_eq!(pipe_out.read(¤t_task, &mut VecOutputBuffer::new(0)).unwrap(), 0);
2436 assert_eq!(
2437 pipe_ops
2438 .vmsplice_to(¤t_task, &pipe_out, UserBuffers::default(), true)
2439 .unwrap(),
2440 0
2441 );
2442
2443 assert_eq!(pipe_ops.pipe.lock().write(&mut VecInputBuffer::new(b"")).unwrap(), 0);
2445 assert_eq!(pipe_ops.pipe.lock().messages.peek_queue().len(), 0);
2446
2447 std::mem::drop(pipe_out);
2450 current_task.trigger_delayed_releaser();
2451 let pipe_in_ops = pipe_in.downcast_file::<PipeFileObject>().unwrap();
2452 assert_eq!(pipe_in_ops.pipe.lock().write(&mut VecInputBuffer::new(b"")).unwrap(), 0);
2453 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"")).unwrap(), 0);
2454 assert_eq!(
2455 pipe_in_ops
2456 .vmsplice_from(¤t_task, &pipe_in, UserBuffers::default(), true)
2457 .unwrap(),
2458 0
2459 );
2460 assert!(!current_task.write().signals_mut().has_queued(SIGPIPE));
2461 })
2462 .await;
2463 }
2464
2465 #[::fuchsia::test]
2466 async fn test_readv_writev_vmsplice_partial_efault_short_counts_and_rollback() {
2467 spawn_kernel_and_run(async |current_task| {
2468 let kernel = current_task.kernel();
2469 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2470
2471 let page_size = *PAGE_SIZE as usize;
2472 let two_pages = map_memory(¤t_task, UserAddress::default(), (*PAGE_SIZE) * 2);
2473 let bad_page = (two_pages + *PAGE_SIZE).unwrap();
2474 fill_page(¤t_task, two_pages, 'M');
2475 current_task
2476 .mm()
2477 .unwrap()
2478 .protect(¤t_task, bad_page, page_size, ProtectionFlags::empty())
2479 .unwrap();
2480
2481 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2484 let mut writev_buf = UserBuffersInputBuffer::unified_new(
2485 ¤t_task,
2486 smallvec![
2487 UserBuffer { address: two_pages, length: page_size },
2488 UserBuffer { address: bad_page, length: page_size },
2489 ],
2490 )
2491 .unwrap();
2492 assert_eq!(pipe_in.write(¤t_task, &mut writev_buf).unwrap(), page_size);
2493 assert_eq!(
2494 pipe_out.downcast_file::<PipeFileObject>().unwrap().pipe.lock().readable_len(),
2495 page_size
2496 );
2497 std::mem::drop((pipe_out, pipe_in));
2498
2499 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2502 let mut sub_pipe_buf = UserBuffersInputBuffer::unified_new(
2503 ¤t_task,
2504 smallvec![
2505 UserBuffer { address: two_pages, length: 100 },
2506 UserBuffer { address: bad_page, length: 100 },
2507 ],
2508 )
2509 .unwrap();
2510 assert_eq!(pipe_in.write(¤t_task, &mut sub_pipe_buf), error!(EFAULT));
2511 assert_eq!(
2512 pipe_out.downcast_file::<PipeFileObject>().unwrap().pipe.lock().readable_len(),
2513 0
2514 );
2515 std::mem::drop((pipe_out, pipe_in));
2516
2517 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2520 let pipe_in_ops = pipe_in.downcast_file::<PipeFileObject>().unwrap();
2521 assert_eq!(
2522 pipe_in_ops.vmsplice_from(
2523 ¤t_task,
2524 &pipe_in,
2525 smallvec![UserBuffer { address: bad_page, length: page_size }],
2526 true,
2527 ),
2528 error!(EFAULT)
2529 );
2530 assert_eq!(
2531 pipe_in_ops
2532 .vmsplice_from(
2533 ¤t_task,
2534 &pipe_in,
2535 smallvec![
2536 UserBuffer { address: two_pages, length: page_size },
2537 UserBuffer { address: bad_page, length: page_size },
2538 ],
2539 true,
2540 )
2541 .unwrap(),
2542 page_size
2543 );
2544 assert_eq!(
2545 pipe_out.downcast_file::<PipeFileObject>().unwrap().pipe.lock().readable_len(),
2546 page_size
2547 );
2548 std::mem::drop((pipe_out, pipe_in));
2549
2550 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2553 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAA")).unwrap(), 4);
2554 let mut bad_out =
2555 UserBuffersOutputBuffer::unified_new_at(¤t_task, bad_page, 4).unwrap();
2556 assert_eq!(pipe_out.read(¤t_task, &mut bad_out), error!(EFAULT));
2557 assert_eq!(
2558 pipe_out.downcast_file::<PipeFileObject>().unwrap().pipe.lock().readable_len(),
2559 4
2560 );
2561 std::mem::drop((pipe_out, pipe_in));
2562
2563 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2566 let pipe_out_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
2567 assert_eq!(
2568 pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAABBBB")).unwrap(),
2569 8
2570 );
2571 let fault_iov = smallvec![
2572 UserBuffer { address: two_pages, length: 4 },
2573 UserBuffer { address: bad_page, length: 4 },
2574 ];
2575 assert_eq!(
2576 pipe_out_ops.vmsplice_to(¤t_task, &pipe_out, fault_iov.clone(), true),
2577 error!(EFAULT)
2578 );
2579 assert_eq!(pipe_out_ops.pipe.lock().readable_len(), 8);
2580
2581 let mut readv_out =
2582 UserBuffersOutputBuffer::unified_new(¤t_task, fault_iov.clone()).unwrap();
2583 assert_eq!(pipe_out.read(¤t_task, &mut readv_out), error!(EFAULT));
2584 assert_eq!(readv_out.bytes_written(), 0);
2585 assert_eq!(pipe_out_ops.pipe.lock().readable_len(), 8);
2586 std::mem::drop((pipe_out, pipe_in));
2587
2588 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2592 let pipe_out_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
2593 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAA")).unwrap(), 4);
2594 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"BBBB")).unwrap(), 4);
2595 assert_eq!(
2596 pipe_out_ops
2597 .vmsplice_to(¤t_task, &pipe_out, fault_iov.clone(), true)
2598 .unwrap(),
2599 4
2600 );
2601 assert_eq!(pipe_out_ops.pipe.lock().readable_len(), 4);
2602 let mut rem_buf = VecOutputBuffer::new(4);
2603 assert_eq!(pipe_out.read(¤t_task, &mut rem_buf).unwrap(), 4);
2604 assert_eq!(rem_buf.data(), b"BBBB");
2605
2606 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"CCCC")).unwrap(), 4);
2607 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"DDDD")).unwrap(), 4);
2608 let mut readv_out2 =
2609 UserBuffersOutputBuffer::unified_new(¤t_task, fault_iov).unwrap();
2610 assert_eq!(pipe_out.read(¤t_task, &mut readv_out2).unwrap(), 4);
2611 assert_eq!(pipe_out_ops.pipe.lock().readable_len(), 4);
2612 let mut rem_buf2 = VecOutputBuffer::new(4);
2613 assert_eq!(pipe_out.read(¤t_task, &mut rem_buf2).unwrap(), 4);
2614 assert_eq!(rem_buf2.data(), b"DDDD");
2615 })
2616 .await;
2617 }
2618
2619 #[::fuchsia::test]
2620 async fn test_blocking_write_wakes_when_reader_frees_less_than_pipe_buf() {
2621 spawn_kernel_and_run(async |current_task| {
2622 let kernel = current_task.kernel();
2623 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2624
2625 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2626 let capacity =
2627 pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
2628 let fill = vec![b'A'; capacity];
2629 assert_eq!(
2630 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
2631 capacity
2632 );
2633
2634 let pipe_in_clone = pipe_in.clone();
2635 let (writer_join, req) = SpawnRequestBuilder::new()
2636 .with_sync_closure(move |worker_task: &CurrentTask| {
2637 pipe_in_clone
2638 .write(worker_task, &mut VecInputBuffer::new(b"BBBB"))
2639 .expect("blocked 4-byte write wakes when < PIPE_BUF bytes are freed")
2640 })
2641 .build_with_sync_result();
2642 kernel.kthreads.spawner().spawn_from_request(req);
2643
2644 while pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().waiters.is_empty()
2645 {
2646 std::thread::yield_now();
2647 }
2648
2649 let poll_waiter = Waiter::new();
2652 let poll_ready_items = Arc::default();
2653 pipe_in.wait_async(
2654 ¤t_task,
2655 &poll_waiter,
2656 FdEvents::POLLOUT,
2657 EventHandler::Enqueue {
2658 key: crate::task::ReadyItemKey::Usize(1),
2659 queue: Arc::clone(&poll_ready_items),
2660 sought_events: FdEvents::POLLOUT | FdEvents::POLLERR | FdEvents::POLLHUP,
2661 },
2662 );
2663 let epoll_file = crate::vfs::epoll::EpollFileObject::new_file(¤t_task);
2664 let epoll_ops =
2665 epoll_file.downcast_file::<crate::vfs::epoll::EpollFileObject>().unwrap();
2666 epoll_ops
2667 .add(
2668 ¤t_task,
2669 &pipe_in,
2670 &epoll_file,
2671 starnix_uapi::vfs::EpollEvent::new(FdEvents::POLLOUT | FdEvents::EPOLLET, 1),
2672 )
2673 .unwrap();
2674
2675 let mut small_buf = VecOutputBuffer::new(100);
2676 assert_eq!(pipe_out.read(¤t_task, &mut small_buf).unwrap(), 100);
2677
2678 assert_eq!(writer_join().unwrap(), 4);
2679 assert!(poll_ready_items.lock().is_empty());
2682 assert!(
2683 epoll_ops.wait(¤t_task, 1, zx::MonotonicInstant::ZERO).unwrap().is_empty()
2684 );
2685
2686 let mut page_buf = VecOutputBuffer::new(uapi::PIPE_BUF as usize);
2689 assert_eq!(
2690 pipe_out.read(¤t_task, &mut page_buf).unwrap(),
2691 uapi::PIPE_BUF as usize
2692 );
2693 assert!(!poll_ready_items.lock().is_empty());
2694 let epoll_events =
2695 epoll_ops.wait(¤t_task, 1, zx::MonotonicInstant::ZERO).unwrap();
2696 assert_eq!(epoll_events.len(), 1);
2697 assert!(epoll_events[0].events().contains(FdEvents::POLLOUT));
2698 })
2699 .await;
2700 }
2701 #[::fuchsia::test]
2702 async fn test_splice_to_rlimit_fsize_truncation_and_sigxfsz() {
2703 spawn_kernel_and_run(async |current_task| {
2704 let kernel = current_task.kernel();
2705 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2706
2707 let reg_file = new_memfd(
2708 ¤t_task,
2709 b"rlimit_fsize".into(),
2710 SealFlags::empty(),
2711 OpenFlags::RDWR,
2712 )
2713 .unwrap();
2714 assert!(reg_file.node().is_reg());
2715 current_task
2716 .thread_group()
2717 .limits
2718 .lock()
2719 .set(Resource::FSIZE, uapi::rlimit { rlim_cur: 4, rlim_max: 4 });
2720
2721 let take_sigxfsz = |task: &CurrentTask| -> bool {
2722 task.write().signals_mut().take_next_where(|sig| sig.signal == SIGXFSZ).is_some()
2723 };
2724
2725 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2728 let pipe_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
2729 assert_eq!(
2730 pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAABBBB")).unwrap(),
2731 8
2732 );
2733 assert_eq!(
2734 pipe_ops.splice_to(¤t_task, &pipe_out, ®_file, Some(0), 8, true).unwrap(),
2735 4
2736 );
2737 assert!(take_sigxfsz(¤t_task));
2738 let mut rem = VecOutputBuffer::new(8);
2739 assert_eq!(pipe_out.read(¤t_task, &mut rem).unwrap(), 4);
2740 assert_eq!(rem.data(), b"BBBB");
2741
2742 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAA")).unwrap(), 4);
2745 assert_eq!(
2746 pipe_ops.splice_to(¤t_task, &pipe_out, ®_file, Some(0), 8, true).unwrap(),
2747 4
2748 );
2749 assert!(!take_sigxfsz(¤t_task));
2750
2751 let (eof_out, eof_in) = new_pipe(¤t_task).unwrap();
2753 std::mem::drop(eof_in);
2754 current_task.trigger_delayed_releaser();
2755 let eof_ops = eof_out.downcast_file::<PipeFileObject>().unwrap();
2756 assert_eq!(
2757 eof_ops.splice_to(¤t_task, &eof_out, ®_file, Some(0), 8, false).unwrap(),
2758 0
2759 );
2760 assert!(!take_sigxfsz(¤t_task));
2761
2762 assert_eq!(
2765 pipe_ops.splice_to(¤t_task, &pipe_out, ®_file, Some(0), 8, true),
2766 error!(EAGAIN)
2767 );
2768 assert!(!take_sigxfsz(¤t_task));
2769
2770 assert_eq!(
2772 eof_ops.splice_to(¤t_task, &eof_out, ®_file, Some(4), 4, false).unwrap(),
2773 0
2774 );
2775 assert!(!take_sigxfsz(¤t_task));
2776
2777 assert_eq!(
2780 pipe_ops.splice_to(¤t_task, &pipe_out, ®_file, Some(4), 4, true),
2781 error!(EAGAIN)
2782 );
2783 assert!(!take_sigxfsz(¤t_task));
2784
2785 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAA")).unwrap(), 4);
2788 assert_eq!(
2789 pipe_ops.splice_to(¤t_task, &pipe_out, ®_file, Some(4), 4, true),
2790 error!(EFBIG)
2791 );
2792 assert!(take_sigxfsz(¤t_task));
2793 let mut rem2 = VecOutputBuffer::new(8);
2794 assert_eq!(pipe_out.read(¤t_task, &mut rem2).unwrap(), 4);
2795 assert_eq!(rem2.data(), b"AAAA");
2796 })
2797 .await;
2798 }
2799 #[::fuchsia::test]
2800 async fn test_poll_and_nonblocking_read_during_inflight_splice_to() {
2801 spawn_kernel_and_run(async |current_task| {
2802 let kernel = current_task.kernel();
2803 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2804
2805 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2806 assert_eq!(
2807 pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"AAAABBBB")).unwrap(),
2808 8
2809 );
2810 pipe_out.update_file_flags(OpenFlags::NONBLOCK, OpenFlags::NONBLOCK);
2811
2812 let (entered_tx, entered_rx) = mpsc::channel();
2813 let (resume_tx, resume_rx) = mpsc::channel();
2814 let barrier_sink = anon_test_file(
2815 ¤t_task,
2816 Box::new(BarrierSinkFile {
2817 entered_tx: Mutex::new(Some(entered_tx)),
2818 resume_rx: Mutex::new(Some(resume_rx)),
2819 max_write: 4,
2820 written: Mutex::new(Vec::new()),
2821 }),
2822 OpenFlags::WRONLY,
2823 );
2824
2825 let (ready_tx, ready_rx) = mpsc::channel();
2826 let pipe_out_unblock = pipe_out.clone();
2827 let (unblock_join, unblock_req) = SpawnRequestBuilder::new()
2828 .with_sync_closure(move |_worker_task: &CurrentTask| {
2829 ready_rx.recv().expect("wait until non-blocking read starts");
2830 while pipe_out_unblock
2831 .downcast_file::<PipeFileObject>()
2832 .unwrap()
2833 .pipe
2834 .lock()
2835 .waiters
2836 .is_empty()
2837 {
2838 std::thread::yield_now();
2839 }
2840 resume_tx.send(()).expect("allow splice_to write to complete");
2841 })
2842 .build_with_sync_result();
2843 kernel.kthreads.spawner().spawn_from_request(unblock_req);
2844
2845 let pipe_out_clone = pipe_out.clone();
2846 let (reader_join, req) = SpawnRequestBuilder::new()
2847 .with_sync_closure(move |worker_task: &CurrentTask| {
2848 entered_rx.recv().expect("wait until splice_to enters write");
2849 assert_eq!(
2851 pipe_out_clone.query_events(worker_task).unwrap(),
2852 FdEvents::POLLIN | FdEvents::POLLRDNORM
2853 );
2854 ready_tx.send(()).expect("signal unblocker");
2855 let mut out = VecOutputBuffer::new(4);
2856 let n = pipe_out_clone
2857 .read(worker_task, &mut out)
2858 .expect("O_NONBLOCK read waits for in-flight splice_to and succeeds");
2859 out.data()[..n].to_vec()
2860 })
2861 .build_with_sync_result();
2862 kernel.kthreads.spawner().spawn_from_request(req);
2863
2864 let spliced = pipe_out
2865 .downcast_file::<PipeFileObject>()
2866 .unwrap()
2867 .splice_to(¤t_task, &pipe_out, &barrier_sink, None, 4, true)
2868 .unwrap();
2869 assert_eq!(spliced, 4);
2870 unblock_join().unwrap();
2871 assert_eq!(reader_join().unwrap(), b"BBBB");
2872 })
2873 .await;
2874 }
2875
2876 #[::fuchsia::test]
2877 async fn test_nonblocking_write_to_readerless_pipe_during_inflight_splice_returns_epipe() {
2878 spawn_kernel_and_run(async |current_task| {
2879 let kernel = current_task.kernel();
2880 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2881
2882 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
2883 pipe_in.update_file_flags(OpenFlags::NONBLOCK, OpenFlags::NONBLOCK);
2884
2885 let (entered_tx, entered_rx) = mpsc::channel();
2886 let (resume_tx, resume_rx) = mpsc::channel();
2887 let barrier_source = anon_test_file(
2888 ¤t_task,
2889 Box::new(BarrierSourceFile {
2890 entered_tx: Mutex::new(Some(entered_tx)),
2891 resume_rx: Mutex::new(Some(resume_rx)),
2892 payload: b"AAAA",
2893 }),
2894 OpenFlags::RDONLY,
2895 );
2896
2897 let (ready_tx, ready_rx) = mpsc::channel();
2898 let pipe_in_unblock = pipe_in.clone();
2899 let (unblock_join, unblock_req) = SpawnRequestBuilder::new()
2900 .with_sync_closure(move |_worker_task: &CurrentTask| {
2901 ready_rx.recv().expect("wait until non-blocking write starts");
2902 while pipe_in_unblock
2903 .downcast_file::<PipeFileObject>()
2904 .unwrap()
2905 .pipe
2906 .lock()
2907 .waiters
2908 .is_empty()
2909 {
2910 std::thread::yield_now();
2911 }
2912 resume_tx.send(()).expect("allow splice_from read to complete");
2913 })
2914 .build_with_sync_result();
2915 kernel.kthreads.spawner().spawn_from_request(unblock_req);
2916
2917 let pipe_in_clone = pipe_in.clone();
2918 let (writer_join, req) = SpawnRequestBuilder::new()
2919 .with_sync_closure(move |worker_task: &CurrentTask| {
2920 entered_rx.recv().expect("wait until splice_from enters read");
2921 std::mem::drop(pipe_out);
2922 worker_task.trigger_delayed_releaser();
2923 ready_tx.send(()).expect("signal unblocker");
2924 let err = pipe_in_clone
2925 .write(worker_task, &mut VecInputBuffer::new(b"BBBB"))
2926 .unwrap_err();
2927 let has_sigpipe = worker_task.write().signals_mut().has_queued(SIGPIPE);
2928 (err, has_sigpipe)
2929 })
2930 .build_with_sync_result();
2931 kernel.kthreads.spawner().spawn_from_request(req);
2932
2933 let splice_err = pipe_in
2934 .downcast_file::<PipeFileObject>()
2935 .unwrap()
2936 .splice_from(¤t_task, &pipe_in, &barrier_source, None, 4, true)
2937 .unwrap_err();
2938 assert_eq!(splice_err, errno!(EPIPE));
2939 unblock_join().unwrap();
2940 let (write_err, has_sigpipe) = writer_join().unwrap();
2941 assert_eq!(write_err, errno!(EPIPE));
2942 assert!(has_sigpipe);
2943 })
2944 .await;
2945 }
2946
2947 #[::fuchsia::test]
2948 async fn test_tee_concurrent_with_reader_preserves_fifo_without_duplicates() {
2949 spawn_kernel_and_run(async |current_task| {
2950 let kernel = current_task.kernel();
2951 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
2952
2953 let (pipe_a_out, pipe_a_in) = new_pipe(¤t_task).unwrap();
2956 let (pipe_b_out, pipe_b_in) = new_pipe(¤t_task).unwrap();
2957 const NUM_MSGS: usize = 64;
2958 for i in 0..NUM_MSGS {
2959 let msg = format!("M{:03}", i);
2960 assert_eq!(
2961 pipe_a_in
2962 .write(¤t_task, &mut VecInputBuffer::new(msg.as_bytes()))
2963 .unwrap(),
2964 4
2965 );
2966 }
2967 std::mem::drop(pipe_a_in);
2968 current_task.trigger_delayed_releaser();
2969
2970 let pipe_a_out_clone = pipe_a_out.clone();
2971 let pipe_b_in_clone = pipe_b_in.clone();
2972 let (splicer_join, req) = SpawnRequestBuilder::new()
2973 .with_sync_closure(move |worker_task: &CurrentTask| {
2974 let pipe_a_ops = pipe_a_out_clone.downcast_file::<PipeFileObject>().unwrap();
2975 let pipe_b_ops = pipe_b_in_clone.downcast_file::<PipeFileObject>().unwrap();
2976 loop {
2977 let n = PipeFileObject::splice_pipes(
2978 worker_task,
2979 &pipe_a_out_clone,
2980 &pipe_a_ops,
2981 &pipe_b_in_clone,
2982 &pipe_b_ops,
2983 4,
2984 false,
2985 )
2986 .unwrap();
2987 if n == 0 {
2988 break;
2989 }
2990 }
2991 })
2992 .build_with_sync_result();
2993 kernel.kthreads.spawner().spawn_from_request(req);
2994
2995 let mut read_msgs = Vec::new();
2996 loop {
2997 let mut buf = VecOutputBuffer::new(4);
2998 let n = pipe_a_out.read(¤t_task, &mut buf).unwrap();
2999 if n == 0 {
3000 break;
3001 }
3002 assert_eq!(n, 4);
3003 read_msgs.push(String::from_utf8(buf.data().to_vec()).unwrap());
3004 }
3005 splicer_join().unwrap();
3006 std::mem::drop(pipe_b_in);
3007 current_task.trigger_delayed_releaser();
3008
3009 let mut spliced_msgs = Vec::new();
3010 loop {
3011 let mut buf = VecOutputBuffer::new(4);
3012 let n = pipe_b_out.read(¤t_task, &mut buf).unwrap();
3013 if n == 0 {
3014 break;
3015 }
3016 assert_eq!(n, 4);
3017 spliced_msgs.push(String::from_utf8(buf.data().to_vec()).unwrap());
3018 }
3019
3020 assert!(read_msgs.windows(2).all(|w| w[0] < w[1]));
3022 assert!(spliced_msgs.windows(2).all(|w| w[0] < w[1]));
3023 let mut combined = [read_msgs, spliced_msgs].concat();
3024 combined.sort();
3025 let expected: Vec<String> = (0..NUM_MSGS).map(|i| format!("M{:03}", i)).collect();
3026 assert_eq!(combined, expected);
3027
3028 let (pipe_c_out, pipe_c_in) = new_pipe(¤t_task).unwrap();
3031 let (pipe_d_out, pipe_d_in) = new_pipe(¤t_task).unwrap();
3032 for i in 0..NUM_MSGS {
3033 let msg = format!("T{:03}", i);
3034 assert_eq!(
3035 pipe_c_in
3036 .write(¤t_task, &mut VecInputBuffer::new(msg.as_bytes()))
3037 .unwrap(),
3038 4
3039 );
3040 }
3041 std::mem::drop(pipe_c_in);
3042 current_task.trigger_delayed_releaser();
3043
3044 let pipe_c_out_clone = pipe_c_out.clone();
3045 let pipe_d_in_clone = pipe_d_in.clone();
3046 let (tee_join, tee_req) = SpawnRequestBuilder::new()
3047 .with_sync_closure(move |worker_task: &CurrentTask| {
3048 loop {
3049 let n = PipeFileObject::tee(
3050 worker_task,
3051 &pipe_c_out_clone,
3052 &pipe_d_in_clone,
3053 4,
3054 false,
3055 )
3056 .unwrap();
3057 if n == 0 {
3058 break;
3059 }
3060 }
3061 })
3062 .build_with_sync_result();
3063 kernel.kthreads.spawner().spawn_from_request(tee_req);
3064
3065 loop {
3066 let mut buf = VecOutputBuffer::new(4);
3067 if pipe_c_out.read(¤t_task, &mut buf).unwrap() == 0 {
3068 break;
3069 }
3070 }
3071 tee_join().unwrap();
3072 std::mem::drop(pipe_d_in);
3073 current_task.trigger_delayed_releaser();
3074
3075 let mut teed_msgs = Vec::new();
3076 loop {
3077 let mut buf = VecOutputBuffer::new(4);
3078 let n = pipe_d_out.read(¤t_task, &mut buf).unwrap();
3079 if n == 0 {
3080 break;
3081 }
3082 assert_eq!(n, 4);
3083 teed_msgs.push(String::from_utf8(buf.data().to_vec()).unwrap());
3084 }
3085 assert!(teed_msgs.windows(2).all(|w| w[0] <= w[1]));
3086 })
3087 .await;
3088 }
3089
3090 #[::fuchsia::test]
3091 async fn test_copy_pipes_empty_input_and_readerless_output_matches_linux_ipipe_prep_order() {
3092 spawn_kernel_and_run(async |current_task| {
3093 let kernel = current_task.kernel();
3094 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
3095
3096 let (pipe_a_out, pipe_a_in) = new_pipe(¤t_task).unwrap();
3099 let (pipe_b_out, pipe_b_in) = new_pipe(¤t_task).unwrap();
3100 std::mem::drop(pipe_b_out);
3101 current_task.trigger_delayed_releaser();
3102
3103 let pipe_a_ops = pipe_a_out.downcast_file::<PipeFileObject>().unwrap();
3104 let pipe_b_ops = pipe_b_in.downcast_file::<PipeFileObject>().unwrap();
3105 assert_eq!(
3106 PipeFileObject::splice_pipes(
3107 ¤t_task,
3108 &pipe_a_out,
3109 &pipe_a_ops,
3110 &pipe_b_in,
3111 &pipe_b_ops,
3112 4,
3113 true,
3114 )
3115 .unwrap_err(),
3116 errno!(EAGAIN)
3117 );
3118 assert!(!current_task.write().signals_mut().has_queued(SIGPIPE));
3119 assert_eq!(
3120 PipeFileObject::tee(¤t_task, &pipe_a_out, &pipe_b_in, 4, true).unwrap_err(),
3121 errno!(EAGAIN)
3122 );
3123 assert!(!current_task.write().signals_mut().has_queued(SIGPIPE));
3124
3125 let pipe_a_out_clone = pipe_a_out.clone();
3128 let pipe_b_in_clone = pipe_b_in.clone();
3129 let (splice_join, req) = SpawnRequestBuilder::new()
3130 .with_sync_closure(move |worker_task: &CurrentTask| {
3131 let a_ops = pipe_a_out_clone.downcast_file::<PipeFileObject>().unwrap();
3132 let b_ops = pipe_b_in_clone.downcast_file::<PipeFileObject>().unwrap();
3133 let err = PipeFileObject::splice_pipes(
3134 worker_task,
3135 &pipe_a_out_clone,
3136 &a_ops,
3137 &pipe_b_in_clone,
3138 &b_ops,
3139 4,
3140 false,
3141 )
3142 .unwrap_err();
3143 let has_sigpipe = worker_task.write().signals_mut().has_queued(SIGPIPE);
3144 (err, has_sigpipe)
3145 })
3146 .build_with_sync_result();
3147 kernel.kthreads.spawner().spawn_from_request(req);
3148
3149 while pipe_a_ops.pipe.lock().waiters.is_empty() {
3150 std::thread::yield_now();
3151 }
3152 assert_eq!(
3153 pipe_a_in.write(¤t_task, &mut VecInputBuffer::new(b"DATA")).unwrap(),
3154 4
3155 );
3156 let (err, has_sigpipe) = splice_join().unwrap();
3157 assert_eq!(err, errno!(EPIPE));
3158 assert!(has_sigpipe);
3159 std::mem::drop(pipe_a_in);
3160
3161 let (same_out, same_in) = new_pipe(¤t_task).unwrap();
3163 let same_out_ops = same_out.downcast_file::<PipeFileObject>().unwrap();
3164 let same_in_ops = same_in.downcast_file::<PipeFileObject>().unwrap();
3165 assert_eq!(
3166 PipeFileObject::splice_pipes(
3167 ¤t_task,
3168 &same_out,
3169 &same_out_ops,
3170 &same_in,
3171 &same_in_ops,
3172 4,
3173 true,
3174 )
3175 .unwrap_err(),
3176 errno!(EINVAL)
3177 );
3178 })
3179 .await;
3180 }
3181
3182 #[test]
3183 #[cfg(debug_assertions)]
3184 #[should_panic(expected = "LockDep: Self-deadlock detected")]
3185 fn test_unordered_nested_pipe_lock_panics_in_lockdep() {
3186 let pipe1 = Pipe::new(*PAGE_SIZE as usize);
3187 let pipe2 = Pipe::new(*PAGE_SIZE as usize);
3188 let _guard1 = pipe1.lock();
3189 let _guard2 = pipe2.lock();
3191 }
3192
3193 #[::fuchsia::test]
3194 async fn test_f_setpipe_sz_power_of_two_rounding_and_grow_wakes_blocked_writer() {
3195 spawn_kernel_and_run(async |current_task| {
3196 let kernel = current_task.kernel();
3197 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
3198
3199 let (_pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
3200 let page_size = *PAGE_SIZE as usize;
3201
3202 assert_eq!(
3204 pipe_in.fcntl(¤t_task, F_SETPIPE_SZ, (-1i32 as u32) as u64).unwrap_err(),
3205 errno!(EINVAL)
3206 );
3207
3208 let rounded = pipe_in
3210 .fcntl(¤t_task, F_SETPIPE_SZ, (page_size * 3) as u64)
3211 .expect("F_SETPIPE_SZ rounds to power of two");
3212 assert_eq!(rounded, (page_size * 4).into());
3213 assert_eq!(
3214 pipe_in.fcntl(¤t_task, F_GETPIPE_SZ, 0).unwrap(),
3215 (page_size * 4).into()
3216 );
3217
3218 let fill = vec![b'F'; page_size * 4];
3220 assert_eq!(
3221 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
3222 page_size * 4
3223 );
3224
3225 let pipe_in_clone = pipe_in.clone();
3226 let (writer_join, req) = SpawnRequestBuilder::new()
3227 .with_sync_closure(move |worker_task: &CurrentTask| {
3228 pipe_in_clone
3229 .write(worker_task, &mut VecInputBuffer::new(b"GROW"))
3230 .expect("blocked writer wakes when F_SETPIPE_SZ grows pipe")
3231 })
3232 .build_with_sync_result();
3233 kernel.kthreads.spawner().spawn_from_request(req);
3234
3235 while pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().waiters.is_empty()
3236 {
3237 std::thread::yield_now();
3238 }
3239
3240 let grown = pipe_in
3241 .fcntl(¤t_task, F_SETPIPE_SZ, (page_size * 8) as u64)
3242 .expect("F_SETPIPE_SZ grows capacity");
3243 assert_eq!(grown, (page_size * 8).into());
3244 assert_eq!(writer_join().unwrap(), 4);
3245 })
3246 .await;
3247 }
3248}