/* * linux/fs/pipe.c * * Copyright (C) 1991, 1992, 1999 Linus Torvalds */ #include <linux/mm.h>#include <linux/file.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/mount.h>#include <linux/pipe_fs_i.h>#include <linux/uio.h>#include <linux/highmem.h> #include <asm/uaccess.h>#include <asm/ioctls.h> /* * We use a start+len construction, which provides full use of the * allocated memory. * -- Florian Coosmann (FGC) * * Reads with count = 0 should always return 0. * -- Julian Bradfield 1999-06-07. * * FIFOs and Pipes now generate SIGIO for both readers and writers. * -- Jeremy Elson <jelson@circlemud.org> 2001-08-16 * * pipe_read & write cleanup * -- Manfred Spraul <manfred@colorfullife.com> 2002-05-09 */ /* Drop the inode semaphore and wait for a pipe event, atomically */void pipe_wait(struct inode * inode){ DEFINE_WAIT(wait); prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE); up(PIPE_SEM(*inode)); schedule(); finish_wait(PIPE_WAIT(*inode), &wait); down(PIPE_SEM(*inode));} static inline intpipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len){ unsigned long copy; while (len > 0) { while (!iov->iov_len) iov++; copy = min_t(unsigned long, len, iov->iov_len); if (copy_from_user(to, iov->iov_base, copy)) return -EFAULT; to += copy; len -= copy; iov->iov_base += copy; iov->iov_len -= copy; } return 0;} static inline intpipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len){ unsigned long copy; while (len > 0) { while (!iov->iov_len) iov++; copy = min_t(unsigned long, len, iov->iov_len); if (copy_to_user(iov->iov_base, from, copy)) return -EFAULT; from += copy; len -= copy; iov->iov_base += copy; iov->iov_len -= copy; } return 0;} static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buffer *buf){ struct page *page = buf->page; if (info->tmp_page) { __free_page(page); return; } info->tmp_page = page;} static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf){ return kmap(buf->page);} static void anon_pipe_buf_unmap(struct pipe_inode_info *info, struct pipe_buffer *buf){ kunmap(buf->page);} static struct pipe_buf_operations anon_pipe_buf_ops = { .can_merge = 1, .map = anon_pipe_buf_map, .unmap = anon_pipe_buf_unmap, .release = anon_pipe_buf_release,}; static ssize_tpipe_readv(struct file *filp, const struct iovec *_iov, unsigned long nr_segs, loff_t *ppos){ struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; int do_wakeup; ssize_t ret; struct iovec *iov = (struct iovec *)_iov; size_t total_len; total_len = iov_length(iov, nr_segs); /* Null read succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; down(PIPE_SEM(*inode)); info = inode->i_pipe; for (;;) { int bufs = info->nrbufs; if (bufs) { int curbuf = info->curbuf; struct pipe_buffer *buf = info->bufs + curbuf; struct pipe_buf_operations *ops = buf->ops; void *addr; size_t chars = buf->len; int error; if (chars > total_len) chars = total_len; addr = ops->map(filp, info, buf); error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars); ops->unmap(info, buf); if (unlikely(error)) { if (!ret) ret = -EFAULT; break; } ret += chars; buf->offset += chars; buf->len -= chars; if (!buf->len) { buf->ops = NULL; ops->release(info, buf); curbuf = (curbuf + 1) & (PIPE_BUFFERS-1); info->curbuf = curbuf; info->nrbufs = --bufs; do_wakeup = 1; } total_len -= chars; if (!total_len) break; /* common path: read succeeded */ } if (bufs) /* More to do? */ continue; if (!PIPE_WRITERS(*inode)) break; if (!PIPE_WAITING_WRITERS(*inode)) { /* syscall merging: Usually we must not sleep * if O_NONBLOCK is set, or if we got some data. * But if a writer sleeps in kernel space, then * we can wait for that data without violating POSIX. */ if (ret) break; if (filp->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } pipe_wait(inode); } up(PIPE_SEM(*inode)); /* Signal writers asynchronously that there is more room. */ if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } if (ret > 0) file_accessed(filp); return ret;} static ssize_tpipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ struct iovec iov = { .iov_base = buf, .iov_len = count }; return pipe_readv(filp, &iov, 1, ppos);} static ssize_tpipe_writev(struct file *filp, const struct iovec *_iov, unsigned long nr_segs, loff_t *ppos){ struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; ssize_t ret; int do_wakeup; struct iovec *iov = (struct iovec *)_iov; size_t total_len; ssize_t chars; total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; down(PIPE_SEM(*inode)); info = inode->i_pipe; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); ret = -EPIPE; goto out; } /* We try to merge small writes */ chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ if (info->nrbufs && chars != 0) { int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = info->bufs + lastbuf; struct pipe_buf_operations *ops = buf->ops; int offset = buf->offset + buf->len; if (ops->can_merge && offset + chars <= PAGE_SIZE) { void *addr = ops->map(filp, info, buf); int error = pipe_iov_copy_from_user(offset + addr, iov, chars); ops->unmap(info, buf); ret = error; do_wakeup = 1; if (error) goto out; buf->len += chars; total_len -= chars; ret = chars; if (!total_len) goto out; } } for (;;) { int bufs; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; break; } bufs = info->nrbufs; if (bufs < PIPE_BUFFERS) { int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = info->bufs + newbuf; struct page *page = info->tmp_page; int error; if (!page) { page = alloc_page(GFP_HIGHUSER); if (unlikely(!page)) { ret = ret ? : -ENOMEM; break; } info->tmp_page = page; } /* Always wakeup, even if the copy fails. Otherwise * we lock up (O_NONBLOCK-)readers that sleep due to * syscall merging. * FIXME! Is this really true? */ do_wakeup = 1; chars = PAGE_SIZE; if (chars > total_len) chars = total_len; error = pipe_iov_copy_from_user(kmap(page), iov, chars); kunmap(page); if (unlikely(error)) { if (!ret) ret = -EFAULT; break; } ret += chars; /* Insert it into the buffer array */ buf->page = page; buf->ops = &anon_pipe_buf_ops; buf->offset = 0; buf->len = chars; info->nrbufs = ++bufs; info->tmp_page = NULL; total_len -= chars; if (!total_len) break; } if (bufs < PIPE_BUFFERS) continue; if (filp->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); do_wakeup = 0; } PIPE_WAITING_WRITERS(*inode)++; pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; }out: up(PIPE_SEM(*inode)); if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); } if (ret > 0) inode_update_time(inode, 1); /* mtime and ctime */ return ret;} static ssize_tpipe_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){ struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; return pipe_writev(filp, &iov, 1, ppos);} static ssize_tbad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ return -EBADF;} static ssize_tbad_pipe_w(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){ return -EBADF;} static intpipe_ioctl(struct inode *pino, struct file *filp, unsigned int cmd, unsigned long arg){ struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; int count, buf, nrbufs; switch (cmd) { case FIONREAD: down(PIPE_SEM(*inode)); info = inode->i_pipe; count = 0; buf = info->curbuf; nrbufs = info->nrbufs; while (--nrbufs >= 0) { count += info->bufs[buf].len; buf = (buf+1) & (PIPE_BUFFERS-1); } up(PIPE_SEM(*inode)); return put_user(count, (int __user *)arg); default: return -EINVAL; }} /* No kernel lock held - fine */static unsigned intpipe_poll(struct file *filp, poll_table *wait){ unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info = inode->i_pipe; int nrbufs; poll_wait(filp, PIPE_WAIT(*inode), wait); /* Reading only -- no need for acquiring the semaphore. */ nrbufs = info->nrbufs; mask = 0; if (filp->f_mode & FMODE_READ) { mask = (nrbufs > 0) ? POLLIN | POLLRDNORM : 0; if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode)) mask |= POLLHUP; } if (filp->f_mode & FMODE_WRITE) { mask |= (nrbufs < PIPE_BUFFERS) ? POLLOUT | POLLWRNORM : 0; if (!PIPE_READERS(*inode)) mask |= POLLERR; } return mask;} /* FIXME: most Unices do not set POLLERR for fifos */#define fifo_poll pipe_poll static intpipe_release(struct inode *inode, int decr, int decw){ down(PIPE_SEM(*inode)); PIPE_READERS(*inode) -= decr; PIPE_WRITERS(*inode) -= decw; if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { free_pipe_info(inode); } else { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } up(PIPE_SEM(*inode)); return 0;} static intpipe_read_fasync(int fd, struct file *filp, int on){ struct inode *inode = filp->f_dentry->d_inode; int retval; down(PIPE_SEM(*inode)); retval = fasync_helper(fd, filp, on, PIPE_FASYNC_READERS(*inode)); up(PIPE_SEM(*inode)); if (retval < 0) return retval; return 0;} static intpipe_write_fasync(int fd, struct file *filp, int on){ struct inode *inode = filp->f_dentry->d_inode; int retval; down(PIPE_SEM(*inode)); retval = fasync_helper(fd, filp, on, PIPE_FASYNC_WRITERS(*inode)); up(PIPE_SEM(*inode)); if (retval < 0) return retval; return 0;} static intpipe_rdwr_fasync(int fd, struct file *filp, int on){ struct inode *inode = filp->f_dentry->d_inode; int retval; down(PIPE_SEM(*inode)); retval = fasync_helper(fd, filp, on, PIPE_FASYNC_READERS(*inode)); if (retval >= 0) retval = fasync_helper(fd, filp, on, PIPE_FASYNC_WRITERS(*inode)); up(PIPE_SEM(*inode)); if (retval < 0) return retval; return 0;} Lines 1–500 of 835. Load more
/* * linux/fs/pipe.c * * Copyright (C) 1991, 1992, 1999 Linus Torvalds */ #include <linux/mm.h> #include <linux/file.h> #include <linux/poll.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/mount.h> #include <linux/pipe_fs_i.h> #include <linux/uio.h> #include <linux/highmem.h> #include <asm/uaccess.h> #include <asm/ioctls.h> /* * We use a start+len construction, which provides full use of the * allocated memory. * -- Florian Coosmann (FGC) * * Reads with count = 0 should always return 0. * -- Julian Bradfield 1999-06-07. * * FIFOs and Pipes now generate SIGIO for both readers and writers. * -- Jeremy Elson <jelson@circlemud.org> 2001-08-16 * * pipe_read & write cleanup * -- Manfred Spraul <manfred@colorfullife.com> 2002-05-09 */ /* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct inode * inode) { DEFINE_WAIT(wait); prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE); up(PIPE_SEM(*inode)); schedule(); finish_wait(PIPE_WAIT(*inode), &wait); down(PIPE_SEM(*inode)); } static inline int pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len) { unsigned long copy; while (len > 0) { while (!iov->iov_len) iov++; copy = min_t(unsigned long, len, iov->iov_len); if (copy_from_user(to, iov->iov_base, copy)) return -EFAULT; to += copy; len -= copy; iov->iov_base += copy; iov->iov_len -= copy; } return 0; } static inline int pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len) { unsigned long copy; while (len > 0) { while (!iov->iov_len) iov++; copy = min_t(unsigned long, len, iov->iov_len); if (copy_to_user(iov->iov_base, from, copy)) return -EFAULT; from += copy; len -= copy; iov->iov_base += copy; iov->iov_len -= copy; } return 0; } static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buffer *buf) { struct page *page = buf->page; if (info->tmp_page) { __free_page(page); return; } info->tmp_page = page; } static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf) { return kmap(buf->page); } static void anon_pipe_buf_unmap(struct pipe_inode_info *info, struct pipe_buffer *buf) { kunmap(buf->page); } static struct pipe_buf_operations anon_pipe_buf_ops = { .can_merge = 1, .map = anon_pipe_buf_map, .unmap = anon_pipe_buf_unmap, .release = anon_pipe_buf_release, }; static ssize_t pipe_readv(struct file *filp, const struct iovec *_iov, unsigned long nr_segs, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; int do_wakeup; ssize_t ret; struct iovec *iov = (struct iovec *)_iov; size_t total_len; total_len = iov_length(iov, nr_segs); /* Null read succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; down(PIPE_SEM(*inode)); info = inode->i_pipe; for (;;) { int bufs = info->nrbufs; if (bufs) { int curbuf = info->curbuf; struct pipe_buffer *buf = info->bufs + curbuf; struct pipe_buf_operations *ops = buf->ops; void *addr; size_t chars = buf->len; int error; if (chars > total_len) chars = total_len; addr = ops->map(filp, info, buf); error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars); ops->unmap(info, buf); if (unlikely(error)) { if (!ret) ret = -EFAULT; break; } ret += chars; buf->offset += chars; buf->len -= chars; if (!buf->len) { buf->ops = NULL; ops->release(info, buf); curbuf = (curbuf + 1) & (PIPE_BUFFERS-1); info->curbuf = curbuf; info->nrbufs = --bufs; do_wakeup = 1; } total_len -= chars; if (!total_len) break; /* common path: read succeeded */ } if (bufs) /* More to do? */ continue; if (!PIPE_WRITERS(*inode)) break; if (!PIPE_WAITING_WRITERS(*inode)) { /* syscall merging: Usually we must not sleep * if O_NONBLOCK is set, or if we got some data. * But if a writer sleeps in kernel space, then * we can wait for that data without violating POSIX. */ if (ret) break; if (filp->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } pipe_wait(inode); } up(PIPE_SEM(*inode)); /* Signal writers asynchronously that there is more room. */ if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } if (ret > 0) file_accessed(filp); return ret; } static ssize_t pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct iovec iov = { .iov_base = buf, .iov_len = count }; return pipe_readv(filp, &iov, 1, ppos); } static ssize_t pipe_writev(struct file *filp, const struct iovec *_iov, unsigned long nr_segs, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; ssize_t ret; int do_wakeup; struct iovec *iov = (struct iovec *)_iov; size_t total_len; ssize_t chars; total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; down(PIPE_SEM(*inode)); info = inode->i_pipe; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); ret = -EPIPE; goto out; } /* We try to merge small writes */ chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ if (info->nrbufs && chars != 0) { int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = info->bufs + lastbuf; struct pipe_buf_operations *ops = buf->ops; int offset = buf->offset + buf->len; if (ops->can_merge && offset + chars <= PAGE_SIZE) { void *addr = ops->map(filp, info, buf); int error = pipe_iov_copy_from_user(offset + addr, iov, chars); ops->unmap(info, buf); ret = error; do_wakeup = 1; if (error) goto out; buf->len += chars; total_len -= chars; ret = chars; if (!total_len) goto out; } } for (;;) { int bufs; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; break; } bufs = info->nrbufs; if (bufs < PIPE_BUFFERS) { int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = info->bufs + newbuf; struct page *page = info->tmp_page; int error; if (!page) { page = alloc_page(GFP_HIGHUSER); if (unlikely(!page)) { ret = ret ? : -ENOMEM; break; } info->tmp_page = page; } /* Always wakeup, even if the copy fails. Otherwise * we lock up (O_NONBLOCK-)readers that sleep due to * syscall merging. * FIXME! Is this really true? */ do_wakeup = 1; chars = PAGE_SIZE; if (chars > total_len) chars = total_len; error = pipe_iov_copy_from_user(kmap(page), iov, chars); kunmap(page); if (unlikely(error)) { if (!ret) ret = -EFAULT; break; } ret += chars; /* Insert it into the buffer array */ buf->page = page; buf->ops = &anon_pipe_buf_ops; buf->offset = 0; buf->len = chars; info->nrbufs = ++bufs; info->tmp_page = NULL; total_len -= chars; if (!total_len) break; } if (bufs < PIPE_BUFFERS) continue; if (filp->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); do_wakeup = 0; } PIPE_WAITING_WRITERS(*inode)++; pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; } out: up(PIPE_SEM(*inode)); if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); } if (ret > 0) inode_update_time(inode, 1); /* mtime and ctime */ return ret; } static ssize_t pipe_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; return pipe_writev(filp, &iov, 1, ppos); } static ssize_t bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { return -EBADF; } static ssize_t bad_pipe_w(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { return -EBADF; } static int pipe_ioctl(struct inode *pino, struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; int count, buf, nrbufs; switch (cmd) { case FIONREAD: down(PIPE_SEM(*inode)); info = inode->i_pipe; count = 0; buf = info->curbuf; nrbufs = info->nrbufs; while (--nrbufs >= 0) { count += info->bufs[buf].len; buf = (buf+1) & (PIPE_BUFFERS-1); } up(PIPE_SEM(*inode)); return put_user(count, (int __user *)arg); default: return -EINVAL; } } /* No kernel lock held - fine */ static unsigned int pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info = inode->i_pipe; int nrbufs; poll_wait(filp, PIPE_WAIT(*inode), wait); /* Reading only -- no need for acquiring the semaphore. */ nrbufs = info->nrbufs; mask = 0; if (filp->f_mode & FMODE_READ) { mask = (nrbufs > 0) ? POLLIN | POLLRDNORM : 0; if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode)) mask |= POLLHUP; } if (filp->f_mode & FMODE_WRITE) { mask |= (nrbufs < PIPE_BUFFERS) ? POLLOUT | POLLWRNORM : 0; if (!PIPE_READERS(*inode)) mask |= POLLERR; } return mask; } /* FIXME: most Unices do not set POLLERR for fifos */ #define fifo_poll pipe_poll static int pipe_release(struct inode *inode, int decr, int decw) { down(PIPE_SEM(*inode)); PIPE_READERS(*inode) -= decr; PIPE_WRITERS(*inode) -= decw; if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { free_pipe_info(inode); } else { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } up(PIPE_SEM(*inode)); return 0; } static int pipe_read_fasync(int fd, struct file *filp, int on) { struct inode *inode = filp->f_dentry->d_inode; int retval; down(PIPE_SEM(*inode)); retval = fasync_helper(fd, filp, on, PIPE_FASYNC_READERS(*inode)); up(PIPE_SEM(*inode)); if (retval < 0) return retval; return 0; } static int pipe_write_fasync(int fd, struct file *filp, int on) { struct inode *inode = filp->f_dentry->d_inode; int retval; down(PIPE_SEM(*inode)); retval = fasync_helper(fd, filp, on, PIPE_FASYNC_WRITERS(*inode)); up(PIPE_SEM(*inode)); if (retval < 0) return retval; return 0; } static int pipe_rdwr_fasync(int fd, struct file *filp, int on) { struct inode *inode = filp->f_dentry->d_inode; int retval; down(PIPE_SEM(*inode)); retval = fasync_helper(fd, filp, on, PIPE_FASYNC_READERS(*inode)); if (retval >= 0) retval = fasync_helper(fd, filp, on, PIPE_FASYNC_WRITERS(*inode)); up(PIPE_SEM(*inode)); if (retval < 0) return retval; return 0; }