/* wait on the pipes writers queue */ static inline int pipe_wait_write(struct my_pipe_t *pipe) { #ifdef DO_WAITQUEUE pipe_unlock(pipe); return wait_event_interruptible(pipe->write_queue, pipe_writer_should_i_wake_up(pipe)); #endif /* DO_WAITQUEUE */ #ifdef DO_WAITQUEUE_RISQUE int ret; pipe_unlock(pipe); ret = wait_event_interruptible(pipe->write_queue, pipe_room(pipe) > 0); pipe_lock(pipe); return ret; #endif /* DO_WAITQUEUE_RISQUE */ #ifdef DO_SCHEDULE int ret; DEFINE_WAIT(wait); prepare_to_wait(&pipe->write_queue, &wait, TASK_INTERRUPTIBLE); pipe_unlock(pipe); schedule(); if (signal_pending(current)) ret = -ERESTARTSYS; else ret = 0; finish_wait(&pipe->write_queue, &wait); pipe_lock(pipe); return ret; #endif /* DO_SHCEDULE */ #ifdef DO_NOTHING return 0; #endif /* DO_NOTHING */ }
/* * If called with *pipep = NULL, pipe_new will call pipe_alloc to allocate a * pipe control structure and set *pipep to its address. * pipe is locked, when pipe_new returns with no error. */ static int pipe_new( pipe_control_t **pipep ) { pipe_control_t *pipe; int err = 0; err = pipe_lock(); if (err) return err; pipe = *pipep; if (pipe == NULL) { err = pipe_alloc(&pipe); if (err) goto out; } if (! PIPE_LOCK(pipe)) err = -EINTR; if (*pipep == NULL) { if (err) pipe_free(pipe); else *pipep = pipe; } out: pipe_unlock(); return err; }
static ssize_t pipe_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct my_pipe_t *pipe; size_t data, work_size, first_chunk, second_chunk, ret; pr_debug("pipe_read: start with buf %p\n", buf); if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; pipe = (struct my_pipe_t *)(file->private_data); /* lets sleep while there is no data in the pipe * why do we not just use the waitqueue condition? * because we want to get the pipe LOCKED with data */ pipe_lock(pipe); data = pipe_data(pipe); while (data == 0 && pipe->writers > 0) { ret = pipe_wait_read(pipe); if (ret) { pipe_unlock(pipe); return ret; } data = pipe_data(pipe); } pr_debug("data is %zd\n", data); /* EOF handling */ if (data == 0 && pipe->writers == 0) { pr_debug("signaling EOF\n"); pipe_unlock(pipe); return 0; } /* now data > 0 */ work_size = min(data, count); pr_debug("work_size is %zd\n", work_size); /* copy_to_user data from the pipe */ if (pipe->read_pos <= pipe->write_pos) { ret = pipe_copy_to_user(pipe, work_size, &buf); if (ret) { pipe_unlock(pipe); return ret; } } else { first_chunk = min(work_size, pipe->size-pipe->read_pos); ret = pipe_copy_to_user(pipe, first_chunk, &buf); if (ret) { pipe_unlock(pipe); return ret; } if (first_chunk < work_size) { second_chunk = work_size-first_chunk; ret = pipe_copy_to_user(pipe, second_chunk, &buf); if (ret) { pipe_unlock(pipe); return ret; } } } pipe_unlock(pipe); *ppos += work_size; /* wake up the writers */ pipe_wake_writers(pipe); return work_size; }
static inline int pipe_writer_should_i_wake_up(struct my_pipe_t *pipe) { int ret; pipe_lock(pipe); ret = pipe_room(pipe) > 0; if (!ret) pipe_unlock(pipe); return ret; }
static inline int pipe_reader_should_i_wake_up(struct my_pipe_t *pipe) { int ret; pipe_lock(pipe); ret = pipe_data(pipe) > 0 || pipe->writers == 0; if (!ret) pipe_unlock(pipe); return ret; }
/* * Interface to file system close. * * *pipep points to pipe control structure. When the last user releases pipe, * it will be set to NULL. */ void pipe_release( pipe_control_t **pipep, rtems_libio_t *iop ) { pipe_control_t *pipe = *pipep; uint32_t mode; #if defined(RTEMS_DEBUG) /* WARN pipe not freed and pipep not set to NULL! */ if (pipe_lock()) rtems_fatal_error_occurred(0xdeadbeef); /* WARN pipe not released! */ if (!PIPE_LOCK(pipe)) rtems_fatal_error_occurred(0xdeadbeef); #endif mode = LIBIO_ACCMODE(iop); if (mode & LIBIO_FLAGS_READ) pipe->Readers --; if (mode & LIBIO_FLAGS_WRITE) pipe->Writers --; PIPE_UNLOCK(pipe); if (pipe->Readers == 0 && pipe->Writers == 0) { #if 0 /* To delete an anonymous pipe file when all users closed it */ if (pipe->Anonymous) delfile = TRUE; #endif pipe_free(pipe); *pipep = NULL; } else if (pipe->Readers == 0 && mode != LIBIO_FLAGS_WRITE) /* Notify waiting Writers that all their partners left */ PIPE_WAKEUPWRITERS(pipe); else if (pipe->Writers == 0 && mode != LIBIO_FLAGS_READ) PIPE_WAKEUPREADERS(pipe); pipe_unlock(); #if 0 if (! delfile) return; if (iop->pathinfo.ops->unlink_h == NULL) return; /* This is safe for IMFS, but how about other FSes? */ iop->flags &= ~LIBIO_FLAGS_OPEN; if(iop->pathinfo.ops->unlink_h(&iop->pathinfo)) return; #endif }
static ssize_t pipe_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct my_pipe_t *pipe; size_t work_size, room, first_chunk, second_chunk, ret; pr_debug("pipe_write: start\n"); if (!access_ok(VERIFY_READ, buf, count)) return -EFAULT; pipe = (struct my_pipe_t *)(file->private_data); /* lets check if we have room in the pipe * why do we not just use the waitqueue condition? * because we want to get the pipe LOCKED with data */ pipe_lock(pipe); room = pipe_room(pipe); while (room == 0) { ret = pipe_wait_write(pipe); if (ret) { pipe_unlock(pipe); return ret; } room = pipe_room(pipe); } pr_debug("room is %zd\n", room); /* now room > 0 */ work_size = min(room, count); pr_debug("work_size is %zd\n", work_size); /* copy_from_user data from the pipe */ if (pipe->read_pos <= pipe->write_pos) { first_chunk = min(work_size, pipe->size-pipe->write_pos); ret = pipe_copy_from_user(pipe, first_chunk, &buf); if (ret) { pipe_unlock(pipe); return ret; } if (first_chunk < work_size) { second_chunk = work_size-first_chunk; ret = pipe_copy_from_user(pipe, second_chunk, &buf); if (ret) { pipe_unlock(pipe); return ret; } } } else { ret = pipe_copy_from_user(pipe, work_size, &buf); if (ret) { pipe_unlock(pipe); return ret; } } pipe_unlock(pipe); *ppos += work_size; /* wake up the readers */ pipe_wake_readers(pipe); return work_size; }
static void post_write_request(OutputBuffer * bf) { ChannelPIPE * c = obuf2pipe(bf->queue); c->out_req.client_data = c; c->out_req.done = done_write_request; c->out_req.type = AsyncReqWrite; c->out_req.u.fio.fd = c->fd_out; c->out_req.u.fio.bufp = bf->buf + bf->buf_pos; c->out_req.u.fio.bufsz = bf->buf_len - bf->buf_pos; async_req_post(&c->out_req); pipe_lock(c->chan); }
static void wait_for_dump_helpers(struct file *file) { struct pipe_inode_info *pipe; pipe = file_inode(file)->i_pipe; pipe_lock(pipe); pipe->readers++; pipe->writers--; wake_up_interruptible_sync(&pipe->wait); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); pipe_unlock(pipe); wait_event_freezable(pipe->wait, pipe->readers == 1); pipe_lock(pipe); pipe->readers--; pipe->writers++; pipe_unlock(pipe); }
static void wait_for_dump_helpers(struct file *file) { struct pipe_inode_info *pipe = file->private_data; pipe_lock(pipe); pipe->readers++; pipe->writers--; wake_up_interruptible_sync(&pipe->wait); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); pipe_unlock(pipe); /* * We actually want wait_event_freezable() but then we need * to clear TIF_SIGPENDING and improve dump_interrupted(). */ wait_event_interruptible(pipe->wait, pipe->readers == 1); pipe_lock(pipe); pipe->readers--; pipe->writers++; pipe_unlock(pipe); }
/* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct pipe_inode_info *pipe) { DEFINE_WAIT(wait); /* * Pipes are system-local resources, so sleeping on them * is considered a noninteractive wait: */ prepare_to_wait(&pipe->wait, &wait, TASK_INTERRUPTIBLE); pipe_unlock(pipe); schedule(); finish_wait(&pipe->wait, &wait); pipe_lock(pipe); }
static int pipe_open(struct inode *inode, struct file *filp) { /* hide the pipe in the private_data of the struct file... */ int the_pipe_number = iminor(inode)-MINOR(first_dev); struct my_pipe_t *pipe = pipes+the_pipe_number; #ifdef DO_MUTEX pipe->inode = inode; #endif /* DO_MUTEX */ filp->private_data = pipe; pipe_lock(pipe); if (filp->f_mode & FMODE_READ) pipe->readers++; if (filp->f_mode & FMODE_WRITE) pipe->writers++; pipe_unlock(pipe); return 0; }
static void wait_for_dump_helpers(struct file *file) { struct pipe_inode_info *pipe; pipe = file_inode(file)->i_pipe; pipe_lock(pipe); pipe->readers++; pipe->writers--; while ((pipe->readers > 1) && (!signal_pending(current))) { wake_up_interruptible_sync(&pipe->wait); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); pipe_wait(pipe); } pipe->readers--; pipe->writers++; pipe_unlock(pipe); }
static int pipe_release(struct inode *inode, struct file *filp) { struct my_pipe_t *pipe; pipe = (struct my_pipe_t *)(filp->private_data); pipe_lock(pipe); if (filp->f_mode & FMODE_READ) pipe->readers--; if (filp->f_mode & FMODE_WRITE) pipe->writers--; /* wake up readers since they may want to end if there are no more writers... */ if (filp->f_mode & FMODE_WRITE) { if (pipe->writers == 0) { pr_debug("pipe_release: no more writers, waking up readers...\n"); pipe_wake_readers(pipe); } } pipe_unlock(pipe); return 0; }
static void pipe_write_stream(OutputStream * out, int byte) { ChannelPIPE * c = channel2pipe(out2channel(out)); assert(c->magic == CHANNEL_MAGIC); if (c->chan->state == ChannelStateDisconnected) return; if (c->chan->out.cur == c->chan->out.end) pipe_flush(c); if (byte < 0 || byte == ESC) { char esc = 0; *c->chan->out.cur++ = ESC; if (byte == ESC) esc = 0; else if (byte == MARKER_EOM) esc = 1; else if (byte == MARKER_EOS) esc = 2; else assert(0); if (c->chan->state == ChannelStateDisconnected) return; if (c->chan->out.cur == c->chan->out.end) pipe_flush(c); *c->chan->out.cur++ = esc; if (byte == MARKER_EOM && c->out_flush_cnt < 2) { if (c->out_flush_cnt++ == 0) pipe_lock(c->chan); post_event_with_delay(pipe_flush_event, c, 0); } return; } *c->chan->out.cur++ = (char)byte; }
/* * Almost copy of generic_file_splice_write() (added changed_begin/end, * tux3_iattrdirty()). */ static ssize_t tux3_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { if(DEBUG_MODE_K==1) { printk(KERN_INFO"%25s %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct address_space *mapping = out->f_mapping; struct inode *inode = mapping->host; struct sb *sb = tux_sb(inode->i_sb); struct splice_desc sd = { .total_len = len, .flags = flags, .pos = *ppos, .u.file = out, }; ssize_t ret; sb_start_write(inode->i_sb); pipe_lock(pipe); splice_from_pipe_begin(&sd); do { ret = splice_from_pipe_next(pipe, &sd); if (ret <= 0) break; mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); /* For each ->write_end() calls change_end(). */ change_begin(sb); /* For timestamp. FIXME: convert this to ->update_time * handler? */ tux3_iattrdirty(inode); ret = file_remove_suid(out); if (!ret) { ret = file_update_time(out); if (!ret) ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); } change_end_if_needed(sb); mutex_unlock(&inode->i_mutex); } while (ret > 0); splice_from_pipe_end(pipe, &sd); pipe_unlock(pipe); if (sd.num_spliced) ret = sd.num_spliced; if (ret > 0) { int err; err = generic_write_sync(out, *ppos, ret); if (err) ret = err; else *ppos += ret; balance_dirty_pages_ratelimited(mapping); } sb_end_write(inode->i_sb); return ret; }
static ssize_t svfs_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { struct address_space *mapping; struct inode *inode; struct file *llfs_filp; struct svfs_inode *si; struct splice_desc sd = {0,}; ssize_t ret; svfs_entry(mdc, "pos %lu, len %ld, flags 0x%x\n", (unsigned long)*ppos, (long)len, flags); si = SVFS_I(out->f_dentry->d_inode); if (si->state & SVFS_STATE_DA) { /* create it now */ ASSERT(!(si->state & SVFS_STATE_CONN)); ret = llfs_create(out->f_dentry); if (ret) goto out; } if (!(si->state & SVFS_STATE_CONN)) { /* open it ? */ ret = llfs_lookup(out->f_dentry->d_inode); if (ret) goto out; } llfs_filp = si->llfs_md.llfs_filp; ASSERT(llfs_filp); mapping = llfs_filp->f_mapping; inode = mapping->host; sd.total_len = len; sd.flags = flags; sd.pos = *ppos; sd.u.file = llfs_filp; pipe_lock(pipe); splice_from_pipe_begin(&sd); do { ret = splice_from_pipe_next(pipe, &sd); if (ret <= 0) break; mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); ret = file_remove_suid(out); if (!ret) ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); mutex_unlock(&inode->i_mutex); } while (ret > 0); splice_from_pipe_end(pipe, &sd); pipe_unlock(pipe); if (sd.num_spliced) ret = sd.num_spliced; if (ret > 0) { unsigned long nr_pages; *ppos += ret; nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; /* * If file or inode is SYNC and we actually wrote some data, * sync it. */ if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { int err; mutex_lock(&inode->i_mutex); err = generic_osync_inode(inode, mapping, OSYNC_METADATA|OSYNC_DATA); mutex_unlock(&inode->i_mutex); if (err) ret = err; } balance_dirty_pages_ratelimited_nr(mapping, nr_pages); }