Skip to main content

starnix_core/vfs/
pipe.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mm::{
6    MemoryAccessorExt, NumberOfElementsRead, PAGE_SIZE, TaskMemoryAccessor, read_to_vec,
7};
8use crate::security;
9use crate::signals::{SignalInfo, send_standard_signal};
10use crate::task::{CurrentTask, EventHandler, WaitCallback, WaitCanceler, WaitQueue, Waiter};
11use crate::vfs::buffers::{
12    Buffer, InputBuffer, InputBufferCallback, MessageData, MessageQueue, OutputBuffer,
13    OutputBufferCallback, PeekBufferSegmentsCallback, PipeMessageData, UserBuffersOutputBuffer,
14};
15use crate::vfs::fs_registry::FsRegistry;
16use crate::vfs::{
17    CacheMode, FileHandle, FileObject, FileObjectState, FileOps, FileSystem, FileSystemHandle,
18    FileSystemOps, FileSystemOptions, FsNodeInfo, FsStr, SpecialNode, default_fcntl,
19    fileops_impl_nonseekable, fileops_impl_noop_sync,
20};
21use starnix_sync::{Mutex, MutexGuard};
22use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
23use starnix_types::user_buffer::{UserBuffer, UserBuffers};
24use starnix_types::vfs::default_statfs;
25use starnix_uapi::auth::CAP_SYS_RESOURCE;
26use starnix_uapi::errors::{EPIPE, Errno};
27use starnix_uapi::file_mode::mode;
28use starnix_uapi::fs_type::FileSystemTypeFlags;
29use starnix_uapi::open_flags::OpenFlags;
30use starnix_uapi::signals::SIGPIPE;
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::cmp::Ordering;
37use std::sync::Arc;
38
39const ATOMIC_IO_BYTES: u16 = 4096;
40
41/// The maximum size of a pipe, independent of task capabilities and sysctl limits.
42const PIPE_MAX_SIZE: usize = 1 << 31;
43
44fn round_up(value: usize, increment: usize) -> usize {
45    (value + (increment - 1)) & !(increment - 1)
46}
47
48#[derive(Debug)]
49pub struct Pipe {
50    messages: MessageQueue<PipeMessageData>,
51
52    waiters: WaitQueue,
53
54    /// The number of open readers.
55    reader_count: usize,
56
57    /// Whether the pipe has ever had a reader.
58    had_reader: bool,
59
60    /// The number of open writers.
61    writer_count: usize,
62
63    /// Whether the pipe has ever had a writer.
64    had_writer: bool,
65}
66
67pub type PipeHandle = Arc<Mutex<Pipe>>;
68
69impl Pipe {
70    pub fn new(default_pipe_capacity: usize) -> PipeHandle {
71        Arc::new(
72            Pipe {
73                messages: MessageQueue::new(default_pipe_capacity),
74                waiters: WaitQueue::default(),
75                reader_count: 0,
76                had_reader: false,
77                writer_count: 0,
78                had_writer: false,
79            }
80            .into(),
81        )
82    }
83
84    pub fn open(
85        current_task: &CurrentTask,
86        pipe: &PipeHandle,
87        flags: OpenFlags,
88    ) -> Result<Box<dyn FileOps>, Errno> {
89        let mut events = FdEvents::empty();
90        let mut pipe_locked = pipe.lock();
91        let mut must_wait_events = FdEvents::empty();
92        if flags.can_read() {
93            if !pipe_locked.had_reader {
94                events |= FdEvents::POLLOUT;
95            }
96            pipe_locked.add_reader();
97            if !flags.contains(OpenFlags::NONBLOCK) && !flags.can_write() && !pipe_locked.had_writer
98            {
99                must_wait_events |= FdEvents::POLLIN;
100            }
101        }
102        if flags.can_write() {
103            // https://man7.org/linux/man-pages/man2/open.2.html says:
104            //
105            //  ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO,
106            //         and no process has the FIFO open for reading.
107            if flags.contains(OpenFlags::NONBLOCK) && pipe_locked.reader_count == 0 {
108                assert!(!flags.can_read()); // Otherwise add_reader() would have run above.
109                return error!(ENXIO);
110            }
111            if !pipe_locked.had_writer {
112                events |= FdEvents::POLLIN;
113            }
114            pipe_locked.add_writer();
115            if !flags.contains(OpenFlags::NONBLOCK) && !pipe_locked.had_reader {
116                must_wait_events |= FdEvents::POLLOUT;
117            }
118        }
119        if events != FdEvents::empty() {
120            pipe_locked.waiters.notify_fd_events(events);
121        }
122        let ops = PipeFileObject { pipe: Arc::clone(pipe) };
123        if must_wait_events == FdEvents::empty() {
124            return Ok(Box::new(ops));
125        }
126
127        // Ensures that the new PipeFileObject is closed if is it dropped before being returned.
128        let ops = scopeguard::guard(ops, |ops| {
129            ops.on_close(flags);
130        });
131
132        // Wait for the pipe to be connected.
133        let waiter = Waiter::new();
134        loop {
135            pipe_locked.waiters.wait_async_fd_events(
136                &waiter,
137                must_wait_events,
138                WaitCallback::none(),
139            );
140            std::mem::drop(pipe_locked);
141            match waiter.wait(current_task) {
142                Err(e) => {
143                    return Err(e);
144                }
145                _ => {}
146            }
147            pipe_locked = pipe.lock();
148            if pipe_locked.had_writer && pipe_locked.had_reader {
149                return Ok(Box::new(scopeguard::ScopeGuard::into_inner(ops)));
150            }
151        }
152    }
153
154    /// Increments the reader count for this pipe by 1.
155    pub fn add_reader(&mut self) {
156        self.reader_count += 1;
157        self.had_reader = true;
158    }
159
160    /// Increments the writer count for this pipe by 1.
161    pub fn add_writer(&mut self) {
162        self.writer_count += 1;
163        self.had_writer = true;
164    }
165
166    /// Called whenever a fd to the pipe is closed. Reset the pipe state if there is not more
167    /// reader or writer.
168    pub fn on_close(&mut self) {
169        if self.reader_count == 0 && self.writer_count == 0 {
170            self.had_reader = false;
171            self.had_writer = false;
172            self.messages = MessageQueue::new(self.messages.capacity());
173            self.waiters = WaitQueue::default();
174        }
175    }
176
177    fn is_empty(&self) -> bool {
178        self.messages.is_empty()
179    }
180
181    fn capacity(&self) -> usize {
182        self.messages.capacity()
183    }
184
185    fn set_capacity(
186        &mut self,
187        current_task: &CurrentTask,
188        mut requested_capacity: usize,
189    ) -> Result<(), Errno> {
190        if requested_capacity > PIPE_MAX_SIZE {
191            return error!(EINVAL);
192        }
193        if requested_capacity
194            > current_task
195                .kernel()
196                .system_limits
197                .pipe_max_size
198                .load(std::sync::atomic::Ordering::Relaxed)
199        {
200            security::check_task_capable(current_task, CAP_SYS_RESOURCE)?;
201        }
202        let page_size = *PAGE_SIZE as usize;
203        if requested_capacity < page_size {
204            requested_capacity = page_size;
205        }
206        requested_capacity = round_up(requested_capacity, page_size);
207        self.messages.set_capacity(requested_capacity)
208    }
209
210    fn is_readable(&self) -> bool {
211        !self.is_empty() || (self.writer_count == 0 && self.had_writer)
212    }
213
214    /// Returns whether the pipe can accommodate at least part of a message of length `data_size`.
215    fn is_writable(&self, data_size: usize) -> bool {
216        let available_capacity = self.messages.available_capacity();
217        // POSIX requires that a write smaller than PIPE_BUF be atomic, but requires no
218        // atomicity for writes larger than this.
219        self.had_reader
220            && (self.reader_count == 0
221                || available_capacity >= data_size
222                || (available_capacity > 0 && data_size > uapi::PIPE_BUF as usize))
223    }
224
225    pub fn read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
226        // Return EAGAIN if the pipe is empty and still has at least one open writer so the caller
227        // blocks; otherwise fall through and return 0 to indicate EOF.
228
229        if !self.is_readable() {
230            return error!(EAGAIN);
231        }
232
233        self.messages.read_stream(data).map(|(info, _)| info.bytes_read)
234    }
235
236    pub fn write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
237        if !self.had_reader {
238            return error!(EAGAIN);
239        }
240
241        if self.reader_count == 0 {
242            return error!(EPIPE);
243        }
244
245        if !self.is_writable(data.available()) {
246            return error!(EAGAIN);
247        }
248
249        self.messages.write_stream(data, None, &mut vec![])
250    }
251
252    fn query_events(&self, flags: OpenFlags) -> FdEvents {
253        let mut events = FdEvents::empty();
254
255        if flags.can_read() && self.is_readable() {
256            let writer_closed = self.writer_count == 0 && self.had_writer;
257            let has_data = !self.is_empty();
258            if writer_closed {
259                events |= FdEvents::POLLHUP;
260            }
261            if has_data {
262                events |= FdEvents::POLLIN;
263            }
264        }
265
266        if flags.can_write() && self.is_writable(uapi::PIPE_BUF as usize) {
267            if self.reader_count == 0 && self.had_reader {
268                events |= FdEvents::POLLERR;
269            }
270
271            events |= FdEvents::POLLOUT;
272        }
273
274        events
275    }
276
277    fn fcntl(
278        &mut self,
279        _file: &FileObject,
280        current_task: &CurrentTask,
281        cmd: u32,
282        arg: u64,
283    ) -> Result<SyscallResult, Errno> {
284        match cmd {
285            F_GETPIPE_SZ => Ok(self.capacity().into()),
286            F_SETPIPE_SZ => {
287                self.set_capacity(current_task, arg as usize)?;
288                Ok(self.capacity().into())
289            }
290            _ => default_fcntl(cmd),
291        }
292    }
293
294    fn ioctl(
295        &self,
296        _file: &FileObject,
297        current_task: &CurrentTask,
298        request: u32,
299        arg: SyscallArg,
300    ) -> Result<SyscallResult, Errno> {
301        let user_addr = UserAddress::from(arg);
302        match request {
303            FIONREAD => {
304                let addr = UserRef::<i32>::new(user_addr);
305                let value: i32 = self.messages.len().try_into().map_err(|_| errno!(EINVAL))?;
306                current_task.write_object(addr, &value)?;
307                Ok(SUCCESS)
308            }
309            _ => error!(ENOTTY),
310        }
311    }
312
313    fn notify_fd_events(&self, events: FdEvents) {
314        self.waiters.notify_fd_events(events);
315    }
316
317    /// Splice from the `from` pipe to the `to` pipe.
318    pub fn splice(from: &mut Pipe, to: &mut Pipe, len: usize) -> Result<usize, Errno> {
319        if len == 0 {
320            return Ok(0);
321        }
322        let to_was_empty = to.is_empty();
323        let mut bytes_transferred = 0;
324        loop {
325            let limit = std::cmp::min(len - bytes_transferred, to.messages.available_capacity());
326            if limit == 0 {
327                // We no longer want to transfer any bytes.
328                break;
329            }
330            let Some(mut message) = from.messages.read_message() else {
331                // The `from` pipe is empty.
332                break;
333            };
334            if let Some(data) = MessageData::split_off(&mut message.data, limit) {
335                // Some data is left in the message. Push it back.
336                assert!(data.len() > 0);
337                from.messages.write_front(data.into());
338            }
339            bytes_transferred += message.len();
340            to.messages.write_message(message);
341        }
342        if bytes_transferred > 0 {
343            if from.is_empty() {
344                from.notify_fd_events(FdEvents::POLLOUT);
345            }
346            if to_was_empty {
347                to.notify_fd_events(FdEvents::POLLIN);
348            }
349        }
350        return Ok(bytes_transferred);
351    }
352
353    /// Tee from the `from` pipe to the `to` pipe.
354    pub fn tee(from: &mut Pipe, to: &mut Pipe, len: usize) -> Result<usize, Errno> {
355        if len == 0 {
356            return Ok(0);
357        }
358        let to_was_empty = to.is_empty();
359        let mut bytes_transferred = 0;
360        for message in from.messages.peek_queue().iter() {
361            let limit = std::cmp::min(len - bytes_transferred, to.messages.available_capacity());
362            if limit == 0 {
363                break;
364            }
365            let message = message.clone_at_most(limit);
366            bytes_transferred += message.len();
367            to.messages.write_message(message);
368        }
369        if bytes_transferred > 0 && to_was_empty {
370            to.notify_fd_events(FdEvents::POLLIN);
371        }
372        return Ok(bytes_transferred);
373    }
374}
375
376/// Creates a new pipe between the two returned FileObjects.
377///
378/// The first FileObject is the read endpoint of the pipe. The second is the
379/// write endpoint of the pipe. This order matches the order expected by
380/// sys_pipe2().
381pub fn new_pipe(current_task: &CurrentTask) -> Result<(FileHandle, FileHandle), Errno> {
382    let fs = current_task
383        .kernel()
384        .expando
385        .get::<FsRegistry>()
386        .create(current_task, "pipefs".into(), FileSystemOptions::default())
387        .ok_or_else(|| errno!(EINVAL))??;
388    let mut info = FsNodeInfo::new(mode!(IFIFO, 0o600), current_task.current_fscred());
389    info.blksize = ATOMIC_IO_BYTES.into();
390    let node = fs.create_node_and_allocate_node_id(SpecialNode, info);
391    let pipe = node.fifo(current_task);
392    {
393        let mut state = pipe.lock();
394        state.add_reader();
395        state.add_writer();
396    }
397
398    // Creating the readable `FileObject` takes care of initializing the `node` security label.
399    let read_ops = PipeFileObject { pipe: Arc::clone(pipe) };
400    let read_file = FileObject::new_anonymous(
401        current_task,
402        Box::new(read_ops),
403        Arc::clone(&node),
404        OpenFlags::RDONLY,
405    );
406
407    // Create the writable `FileObject` using the readable object's `name` to reduce overhead.
408    let write_ops = PipeFileObject { pipe: Arc::clone(pipe) };
409    let write_file = FileObject::new(
410        current_task,
411        Box::new(write_ops),
412        read_file.name.to_passive(),
413        OpenFlags::WRONLY,
414    )?;
415
416    Ok((read_file, write_file))
417}
418
419struct PipeFs;
420impl FileSystemOps for PipeFs {
421    fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
422        Ok(default_statfs(PIPEFS_MAGIC))
423    }
424    fn name(&self) -> &'static FsStr {
425        "pipefs".into()
426    }
427}
428
429fn pipe_fs(
430    current_task: &CurrentTask,
431    _options: FileSystemOptions,
432) -> Result<FileSystemHandle, Errno> {
433    struct PipeFsHandle(FileSystemHandle);
434
435    let kernel = current_task.kernel();
436    Ok(kernel
437        .expando
438        .get_or_init(|| {
439            PipeFsHandle(
440                FileSystem::new(kernel, CacheMode::Uncached, PipeFs, FileSystemOptions::default())
441                    .expect("pipefs constructed with valid options"),
442            )
443        })
444        .0
445        .clone())
446}
447
448pub fn register_pipe_fs(fs_registry: &FsRegistry) {
449    fs_registry.register("pipefs".into(), FileSystemTypeFlags::empty(), pipe_fs);
450}
451
452pub struct PipeFileObject {
453    pipe: PipeHandle,
454}
455
456impl FileOps for PipeFileObject {
457    fileops_impl_nonseekable!();
458    fileops_impl_noop_sync!();
459
460    fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
461        self.on_close(file.flags());
462    }
463
464    fn read(
465        &self,
466        file: &FileObject,
467        current_task: &CurrentTask,
468        offset: usize,
469        data: &mut dyn OutputBuffer,
470    ) -> Result<usize, Errno> {
471        debug_assert!(offset == 0);
472        if data.available() == 0 {
473            return Ok(0);
474        }
475        file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
476            let mut pipe = self.pipe.lock();
477            let was_writable = pipe.is_writable(uapi::PIPE_BUF as usize);
478            let actual = pipe.read(data)?;
479            if !was_writable && pipe.is_writable(uapi::PIPE_BUF as usize) {
480                pipe.notify_fd_events(FdEvents::POLLOUT);
481            }
482            Ok(actual)
483        })
484    }
485
486    fn write(
487        &self,
488        file: &FileObject,
489        current_task: &CurrentTask,
490        offset: usize,
491        data: &mut dyn InputBuffer,
492    ) -> Result<usize, Errno> {
493        debug_assert!(offset == 0);
494        debug_assert!(data.bytes_read() == 0);
495        if data.available() == 0 {
496            return Ok(0);
497        }
498
499        let result = file.blocking_op(current_task, FdEvents::POLLOUT, None, || {
500            let mut pipe = self.pipe.lock();
501            let offset_before = data.bytes_read();
502            let bytes_written = match pipe.write(data) {
503                Err(e) if e == EPIPE => {
504                    std::mem::drop(pipe);
505                    send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
506                    return Err(e);
507                }
508                result => result?,
509            };
510            debug_assert!(data.bytes_read() - offset_before == bytes_written);
511            if bytes_written > 0 {
512                pipe.notify_fd_events(FdEvents::POLLIN);
513            }
514            if data.available() > 0 {
515                return error!(EAGAIN);
516            }
517            Ok(())
518        });
519
520        let bytes_written = data.bytes_read();
521        if bytes_written == 0 {
522            // Return an error only if no data was sent; return partial progress otherwise.
523            result?;
524        }
525        Ok(bytes_written)
526    }
527
528    fn wait_async(
529        &self,
530        file: &FileObject,
531        _current_task: &CurrentTask,
532        waiter: &Waiter,
533        mut events: FdEvents,
534        handler: EventHandler,
535    ) -> Option<WaitCanceler> {
536        let flags = file.flags();
537        if !flags.can_read() {
538            events.remove(FdEvents::POLLIN);
539        }
540        if !flags.can_write() {
541            events.remove(FdEvents::POLLOUT);
542        }
543        Some(self.pipe.lock().waiters.wait_async_fd_events(waiter, events, handler))
544    }
545
546    fn query_events(
547        &self,
548        file: &FileObject,
549        _current_task: &CurrentTask,
550    ) -> Result<FdEvents, Errno> {
551        Ok(self.pipe.lock().query_events(file.flags()))
552    }
553
554    fn fcntl(
555        &self,
556        file: &FileObject,
557        current_task: &CurrentTask,
558        cmd: u32,
559        arg: u64,
560    ) -> Result<SyscallResult, Errno> {
561        self.pipe.lock().fcntl(file, current_task, cmd, arg)
562    }
563
564    fn ioctl(
565        &self,
566        file: &FileObject,
567        current_task: &CurrentTask,
568        request: u32,
569        arg: SyscallArg,
570    ) -> Result<SyscallResult, Errno> {
571        self.pipe.lock().ioctl(file, current_task, request, arg)
572    }
573}
574
575/// An OutputBuffer that will write the data to `pipe`.
576#[derive(Debug)]
577struct SpliceOutputBuffer<'a> {
578    pipe: &'a mut Pipe,
579    len: usize,
580    available: usize,
581}
582
583impl<'a> Buffer for SpliceOutputBuffer<'a> {
584    fn segments_count(&self) -> Result<usize, Errno> {
585        error!(ENOTSUP)
586    }
587
588    fn peek_each_segment(
589        &mut self,
590        _callback: &mut PeekBufferSegmentsCallback<'_>,
591    ) -> Result<(), Errno> {
592        error!(ENOTSUP)
593    }
594}
595
596impl<'a> OutputBuffer for SpliceOutputBuffer<'a> {
597    fn write_each(&mut self, callback: &mut OutputBufferCallback<'_>) -> Result<usize, Errno> {
598        // SAFETY: `callback` returns the number of bytes read on success.
599        let bytes = unsafe {
600            read_to_vec::<u8, _>(self.available, |buf| callback(buf).map(NumberOfElementsRead))
601        }?;
602        let bytes_len = bytes.len();
603        if bytes_len > 0 {
604            let was_empty = self.pipe.is_empty();
605            self.pipe.messages.write_message(PipeMessageData::from(bytes).into());
606            if was_empty {
607                self.pipe.notify_fd_events(FdEvents::POLLIN);
608            }
609            self.available -= bytes_len;
610        }
611        Ok(bytes_len)
612    }
613
614    fn available(&self) -> usize {
615        self.available
616    }
617
618    fn bytes_written(&self) -> usize {
619        self.len - self.available
620    }
621
622    fn zero(&mut self) -> Result<usize, Errno> {
623        let bytes = vec![0; self.available];
624        let len = bytes.len();
625        if len > 0 {
626            let was_empty = self.pipe.is_empty();
627            self.pipe.messages.write_message(PipeMessageData::from(bytes).into());
628            if was_empty {
629                self.pipe.notify_fd_events(FdEvents::POLLIN);
630            }
631            self.available -= len;
632        }
633        Ok(len)
634    }
635
636    unsafe fn advance(&mut self, _length: usize) -> Result<(), Errno> {
637        error!(ENOTSUP)
638    }
639}
640
641/// An InputBuffer that will read the data from `pipe`.
642#[derive(Debug)]
643struct SpliceInputBuffer<'a> {
644    pipe: &'a mut Pipe,
645    len: usize,
646    available: usize,
647}
648
649impl<'a> Buffer for SpliceInputBuffer<'a> {
650    fn segments_count(&self) -> Result<usize, Errno> {
651        Ok(self.pipe.messages.len())
652    }
653
654    fn peek_each_segment(
655        &mut self,
656        callback: &mut PeekBufferSegmentsCallback<'_>,
657    ) -> Result<(), Errno> {
658        let mut available = self.available;
659        for message in self.pipe.messages.messages() {
660            let to_read = std::cmp::min(available, message.len());
661            callback(&UserBuffer {
662                address: UserAddress::from(message.data.ptr()? as u64),
663                length: to_read,
664            });
665            available -= to_read;
666        }
667        Ok(())
668    }
669}
670
671impl<'a> InputBuffer for SpliceInputBuffer<'a> {
672    fn peek_each(&mut self, callback: &mut InputBufferCallback<'_>) -> Result<usize, Errno> {
673        let mut read = 0;
674        let mut available = self.available;
675        for message in self.pipe.messages.messages() {
676            let to_read = std::cmp::min(available, message.len());
677            let result = message.data.with_bytes(|bytes| callback(&bytes[0..to_read]))?;
678            if result > to_read {
679                return error!(EINVAL);
680            }
681            read += result;
682            available -= result;
683            if result != to_read {
684                break;
685            }
686        }
687        Ok(read)
688    }
689
690    fn available(&self) -> usize {
691        self.available
692    }
693
694    fn bytes_read(&self) -> usize {
695        self.len - self.available
696    }
697
698    fn drain(&mut self) -> usize {
699        let result = self.available;
700        self.available = 0;
701        result
702    }
703
704    fn advance(&mut self, mut length: usize) -> Result<(), Errno> {
705        if length == 0 {
706            return Ok(());
707        }
708        if length > self.available {
709            return error!(EINVAL);
710        }
711        self.available -= length;
712        while let Some(mut message) = self.pipe.messages.read_message() {
713            if let Some(data) = MessageData::split_off(&mut message.data, length) {
714                // Some data is left in the message. Push it back.
715                self.pipe.messages.write_front(data.into());
716            }
717            length -= message.len();
718            if length == 0 {
719                if self.pipe.is_empty() {
720                    self.pipe.notify_fd_events(FdEvents::POLLOUT);
721                }
722                return Ok(());
723            }
724        }
725        panic!();
726    }
727}
728
729impl PipeFileObject {
730    /// Called whenever a fd to a pipe is closed.
731    fn on_close(&self, flags: OpenFlags) {
732        let mut events = FdEvents::empty();
733        let mut pipe = self.pipe.lock();
734        if flags.can_read() {
735            assert!(pipe.reader_count > 0);
736            pipe.reader_count -= 1;
737            if pipe.reader_count == 0 {
738                events |= FdEvents::POLLOUT | FdEvents::POLLERR;
739            }
740        }
741        if flags.can_write() {
742            assert!(pipe.writer_count > 0);
743            pipe.writer_count -= 1;
744            if pipe.writer_count == 0 {
745                if pipe.reader_count > 0 {
746                    events |= FdEvents::POLLHUP;
747                }
748                if !pipe.is_empty() {
749                    events |= FdEvents::POLLIN;
750                }
751            }
752        }
753        if events != FdEvents::empty() {
754            pipe.waiters.notify_fd_events(events);
755        }
756        pipe.on_close();
757    }
758
759    /// Returns the result of `pregen` and a lock on pipe, once `condition` returns true, ensuring
760    /// `pregen` is run before the pipe is locked.
761    ///
762    /// This will wait on `events` if the file is opened in blocking mode. If the file is opened in
763    /// not blocking mode and `condition` is not realized, this will return EAGAIN.
764    fn wait_for_condition<'a, F, G, V>(
765        &'a self,
766        current_task: &CurrentTask,
767        file: &FileHandle,
768        condition: F,
769        pregen: G,
770        events: FdEvents,
771    ) -> Result<(V, MutexGuard<'a, Pipe>), Errno>
772    where
773        F: Fn(&Pipe) -> bool,
774        G: Fn() -> Result<V, Errno>,
775    {
776        file.blocking_op(current_task, events, None, || {
777            let other = pregen()?;
778            let pipe = self.pipe.lock();
779            if condition(&pipe) { Ok((other, pipe)) } else { error!(EAGAIN) }
780        })
781    }
782
783    /// Lock the pipe for reading, after having run `pregen`.
784    fn lock_pipe_for_reading_with<'a, G, V>(
785        &'a self,
786        current_task: &CurrentTask,
787        file: &FileHandle,
788        pregen: G,
789        non_blocking: bool,
790    ) -> Result<(V, MutexGuard<'a, Pipe>), Errno>
791    where
792        G: Fn() -> Result<V, Errno>,
793    {
794        if non_blocking {
795            let other = pregen()?;
796            let pipe = self.pipe.lock();
797            if !pipe.is_readable() {
798                return error!(EAGAIN);
799            }
800            Ok((other, pipe))
801        } else {
802            self.wait_for_condition(
803                current_task,
804                file,
805                |pipe| pipe.is_readable(),
806                pregen,
807                FdEvents::POLLIN | FdEvents::POLLHUP,
808            )
809        }
810    }
811
812    fn lock_pipe_for_reading<'a>(
813        &'a self,
814        current_task: &CurrentTask,
815        file: &FileHandle,
816        non_blocking: bool,
817    ) -> Result<MutexGuard<'a, Pipe>, Errno> {
818        self.lock_pipe_for_reading_with(current_task, file, || Ok(()), non_blocking).map(|(_, l)| l)
819    }
820
821    /// Lock the pipe for writing, after having run `pregen`.
822    fn lock_pipe_for_writing_with<'a, G, V>(
823        &'a self,
824        current_task: &CurrentTask,
825        file: &FileHandle,
826        pregen: G,
827        non_blocking: bool,
828        len: usize,
829    ) -> Result<(V, MutexGuard<'a, Pipe>), Errno>
830    where
831        G: Fn() -> Result<V, Errno>,
832    {
833        let (other, pipe) = if non_blocking {
834            let other = pregen()?;
835            let pipe = self.pipe.lock();
836            if !pipe.is_writable(len) {
837                return error!(EAGAIN);
838            }
839            (other, pipe)
840        } else {
841            self.wait_for_condition(
842                current_task,
843                file,
844                |pipe| pipe.is_writable(len),
845                pregen,
846                FdEvents::POLLOUT,
847            )?
848        };
849        if pipe.reader_count == 0 {
850            std::mem::drop((other, pipe));
851            send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
852            return error!(EPIPE);
853        }
854        Ok((other, pipe))
855    }
856
857    fn lock_pipe_for_writing<'a>(
858        &'a self,
859        current_task: &CurrentTask,
860        file: &FileHandle,
861        non_blocking: bool,
862        len: usize,
863    ) -> Result<MutexGuard<'a, Pipe>, Errno> {
864        self.lock_pipe_for_writing_with(current_task, file, || Ok(()), non_blocking, len)
865            .map(|(_, l)| l)
866    }
867
868    /// Splice from the given file handle to this pipe.
869    ///
870    /// The given file handle must not be a pipe. If you wish to splice between two pipes, use
871    /// `lock_pipes` and `Pipe::splice`.
872    pub fn splice_from(
873        &self,
874        current_task: &CurrentTask,
875        self_file: &FileHandle,
876        from: &FileHandle,
877        maybe_offset: Option<usize>,
878        len: usize,
879        non_blocking: bool,
880    ) -> Result<usize, Errno> {
881        // If both ends are pipes, use `lock_pipes` and `Pipe::splice`.
882        assert!(from.downcast_file::<PipeFileObject>().is_none());
883
884        let mut pipe = self.lock_pipe_for_writing(current_task, self_file, non_blocking, len)?;
885        let len = std::cmp::min(len, pipe.messages.available_capacity());
886        let mut buffer = SpliceOutputBuffer { pipe: &mut pipe, len, available: len };
887        let result = if let Some(offset) = maybe_offset {
888            from.read_at(current_task, offset, &mut buffer)
889        } else {
890            from.read(current_task, &mut buffer)
891        };
892        std::mem::drop(pipe);
893        if let Err(err) = &result
894            && *err == EPIPE
895        {
896            send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
897        }
898        result
899    }
900
901    /// Splice from this pipe to the given file handle.
902    ///
903    /// The given file handle must not be a pipe. If you wish to splice between two pipes, use
904    /// `lock_pipes` and `Pipe::splice`.
905    pub fn splice_to(
906        &self,
907        current_task: &CurrentTask,
908        self_file: &FileHandle,
909        to: &FileHandle,
910        maybe_offset: Option<usize>,
911        len: usize,
912        non_blocking: bool,
913    ) -> Result<usize, Errno> {
914        // If both ends are pipes, use `lock_pipes` and `Pipe::splice`.
915        assert!(to.downcast_file::<PipeFileObject>().is_none());
916
917        let mut pipe = self.lock_pipe_for_reading(current_task, self_file, non_blocking)?;
918        let len = std::cmp::min(len, pipe.messages.len());
919        let mut buffer = SpliceInputBuffer { pipe: &mut pipe, len, available: len };
920        if let Some(offset) = maybe_offset {
921            to.write_at(current_task, offset, &mut buffer)
922        } else {
923            to.write(current_task, &mut buffer)
924        }
925    }
926
927    /// Share the mappings backing the given input buffer into the pipe.
928    ///
929    /// Returns the number of bytes enqueued.
930    pub fn vmsplice_from(
931        &self,
932        current_task: &CurrentTask,
933        self_file: &FileHandle,
934        mut iovec: UserBuffers,
935        non_blocking: bool,
936    ) -> Result<usize, Errno> {
937        let available = UserBuffer::cap_buffers_to_max_rw_count(
938            current_task.maximum_valid_address().ok_or_else(|| errno!(EINVAL))?,
939            &mut iovec,
940        )?;
941        if available == 0 {
942            return Ok(0);
943        }
944        let mappings = current_task.mm()?.get_mappings_for_vmsplice(&iovec)?;
945
946        let mut pipe =
947            self.lock_pipe_for_writing(current_task, self_file, non_blocking, available)?;
948
949        let mut remaining = std::cmp::min(available, pipe.messages.available_capacity());
950
951        let mut bytes_transferred = 0;
952        for mut mapping in mappings.into_iter() {
953            mapping.truncate(remaining);
954            let actual = mapping.len();
955
956            pipe.messages.write_message(PipeMessageData::Vmspliced(mapping).into());
957            remaining -= actual;
958            bytes_transferred += actual;
959
960            if remaining == 0 {
961                break;
962            }
963        }
964        if bytes_transferred > 0 {
965            pipe.notify_fd_events(FdEvents::POLLIN);
966        }
967        Ok(bytes_transferred)
968    }
969
970    /// Copy data from the pipe to the given output buffer.
971    ///
972    /// Returns the number of bytes transferred.
973    pub fn vmsplice_to(
974        &self,
975        current_task: &CurrentTask,
976        self_file: &FileHandle,
977        iovec: UserBuffers,
978        non_blocking: bool,
979    ) -> Result<usize, Errno> {
980        let mut data = UserBuffersOutputBuffer::unified_new(current_task, iovec)?;
981        if data.available() == 0 {
982            return Ok(0);
983        }
984        let mut pipe = self.lock_pipe_for_reading(current_task, self_file, non_blocking)?;
985        let was_writable = pipe.is_writable(uapi::PIPE_BUF as usize);
986        let actual = pipe.read(&mut data)?;
987        if !was_writable && pipe.is_writable(uapi::PIPE_BUF as usize) {
988            pipe.notify_fd_events(FdEvents::POLLOUT);
989        }
990        Ok(actual)
991    }
992
993    /// Obtain the pipe objects from the given file handles, if they are both pipes.
994    ///
995    /// Returns EINVAL if one (or both) of the given file handles is not a pipe.
996    ///
997    /// Obtains the locks on the pipes in the correct order to avoid deadlocks.
998    pub fn lock_pipes<'a, 'b>(
999        current_task: &CurrentTask,
1000        file_in: &'a FileHandle,
1001        file_out: &'b FileHandle,
1002        len: usize,
1003        non_blocking: bool,
1004    ) -> Result<PipeOperands<'a, 'b>, Errno> {
1005        let pipe_in = file_in.downcast_file::<PipeFileObject>().ok_or_else(|| errno!(EINVAL))?;
1006        let pipe_out = file_out.downcast_file::<PipeFileObject>().ok_or_else(|| errno!(EINVAL))?;
1007
1008        let node_cmp =
1009            Arc::as_ptr(&file_in.name.entry.node).cmp(&Arc::as_ptr(&file_out.name.entry.node));
1010
1011        match node_cmp {
1012            Ordering::Equal => error!(EINVAL),
1013            Ordering::Less => {
1014                let (write, read) = pipe_in.lock_pipe_for_reading_with(
1015                    current_task,
1016                    file_in,
1017                    || pipe_out.lock_pipe_for_writing(current_task, file_out, non_blocking, len),
1018                    non_blocking,
1019                )?;
1020                Ok(PipeOperands { read, write })
1021            }
1022            Ordering::Greater => {
1023                let (read, write) = pipe_out.lock_pipe_for_writing_with(
1024                    current_task,
1025                    file_out,
1026                    || pipe_in.lock_pipe_for_reading(current_task, file_in, non_blocking),
1027                    non_blocking,
1028                    len,
1029                )?;
1030                Ok(PipeOperands { read, write })
1031            }
1032        }
1033    }
1034}
1035
1036pub struct PipeOperands<'a, 'b> {
1037    pub read: MutexGuard<'a, Pipe>,
1038    pub write: MutexGuard<'b, Pipe>,
1039}
1040
1041#[cfg(test)]
1042mod tests {
1043    use super::*;
1044    use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
1045    use crate::testing::{anon_test_file, spawn_kernel_and_run};
1046    use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
1047
1048    struct StaticSourceFile {
1049        payload: &'static [u8],
1050    }
1051
1052    impl FileOps for StaticSourceFile {
1053        fileops_impl_nonseekable!();
1054        fileops_impl_noop_sync!();
1055
1056        fn read(
1057            &self,
1058            _file: &FileObject,
1059            _current_task: &CurrentTask,
1060            _offset: usize,
1061            data: &mut dyn OutputBuffer,
1062        ) -> Result<usize, Errno> {
1063            data.write(self.payload)
1064        }
1065
1066        fn write(
1067            &self,
1068            _file: &FileObject,
1069            _current_task: &CurrentTask,
1070            _offset: usize,
1071            _data: &mut dyn InputBuffer,
1072        ) -> Result<usize, Errno> {
1073            error!(ENOTSUP)
1074        }
1075    }
1076
1077    #[::fuchsia::test]
1078    async fn test_splice_from_closed_reader_returns_epipe_and_queues_sigpipe() {
1079        spawn_kernel_and_run(async |current_task| {
1080            let kernel = current_task.kernel();
1081            register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1082
1083            let (pipe_out, pipe_in) = new_pipe(&current_task).unwrap();
1084            std::mem::drop(pipe_out);
1085            current_task.trigger_delayed_releaser();
1086
1087            let source_file = anon_test_file(
1088                &current_task,
1089                Box::new(StaticSourceFile { payload: b"DATA" }),
1090                OpenFlags::RDONLY,
1091            );
1092            let err = pipe_in
1093                .downcast_file::<PipeFileObject>()
1094                .unwrap()
1095                .splice_from(&current_task, &pipe_in, &source_file, None, 4, true)
1096                .unwrap_err();
1097            assert_eq!(err, errno!(EPIPE));
1098            assert!(current_task.write().signals_mut().has_queued(SIGPIPE));
1099        })
1100        .await;
1101    }
1102
1103    #[::fuchsia::test]
1104    async fn test_partial_read_wakes_blocked_writer() {
1105        spawn_kernel_and_run(async |current_task| {
1106            let kernel = current_task.kernel();
1107            register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1108
1109            let (pipe_out, pipe_in) = new_pipe(&current_task).unwrap();
1110            let capacity =
1111                pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
1112            let fill = vec![b'A'; capacity];
1113            assert_eq!(
1114                pipe_in.write(&current_task, &mut VecInputBuffer::new(&fill)).unwrap(),
1115                capacity
1116            );
1117
1118            let pipe_in_clone = pipe_in.clone();
1119            let (writer_join, req) = SpawnRequestBuilder::new()
1120                .with_sync_closure(move |worker_task: &CurrentTask| {
1121                    pipe_in_clone
1122                        .write(worker_task, &mut VecInputBuffer::new(b"BBBB"))
1123                        .expect("blocked write should succeed after partial read")
1124                })
1125                .build_with_sync_result();
1126            kernel.kthreads.spawner().spawn_from_request(req);
1127
1128            while pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().waiters.is_empty()
1129            {
1130                std::thread::yield_now();
1131            }
1132
1133            // Read one page from the full pipe; the pipe is still non-empty, but has space.
1134            let page_size = *PAGE_SIZE as usize;
1135            let mut partial = VecOutputBuffer::new(page_size);
1136            assert_eq!(pipe_out.read(&current_task, &mut partial).unwrap(), page_size);
1137            assert_eq!(partial.data(), &fill[..page_size]);
1138
1139            assert_eq!(writer_join().unwrap(), 4);
1140        })
1141        .await;
1142    }
1143
1144    #[::fuchsia::test]
1145    async fn test_zero_length_pipe_io_and_no_empty_message_enqueued() {
1146        spawn_kernel_and_run(async |current_task| {
1147            let kernel = current_task.kernel();
1148            register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1149
1150            let (pipe_out, pipe_in) = new_pipe(&current_task).unwrap();
1151            let pipe_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
1152
1153            // Zero-length read and vmsplice_to on an empty pipe return 0 without blocking or EAGAIN.
1154            assert_eq!(pipe_out.read(&current_task, &mut VecOutputBuffer::new(0)).unwrap(), 0);
1155            assert_eq!(
1156                pipe_ops
1157                    .vmsplice_to(&current_task, &pipe_out, UserBuffers::default(), true)
1158                    .unwrap(),
1159                0
1160            );
1161
1162            // Zero-length write via `Pipe::write` does not enqueue an empty message in `MessageQueue`.
1163            assert_eq!(pipe_ops.pipe.lock().write(&mut VecInputBuffer::new(b"")).unwrap(), 0);
1164            assert_eq!(pipe_ops.pipe.lock().messages.peek_queue().len(), 0);
1165
1166            // Close the reader: zero-length write and vmsplice_from on a broken pipe return 0
1167            // without EPIPE or SIGPIPE.
1168            std::mem::drop(pipe_out);
1169            current_task.trigger_delayed_releaser();
1170            assert_eq!(pipe_in.write(&current_task, &mut VecInputBuffer::new(b"")).unwrap(), 0);
1171            let pipe_in_ops = pipe_in.downcast_file::<PipeFileObject>().unwrap();
1172            assert_eq!(
1173                pipe_in_ops
1174                    .vmsplice_from(&current_task, &pipe_in, UserBuffers::default(), true)
1175                    .unwrap(),
1176                0
1177            );
1178            assert!(!current_task.write().signals_mut().has_queued(SIGPIPE));
1179        })
1180        .await;
1181    }
1182}