Пример #1
0
struct inode* pipe_new(struct inode* inode)
{
    unsigned long page;

    page = __get_free_page(GFP_USER);
    if (!page)
        return NULL;

    inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
    if (!inode->i_pipe)
        goto fail_page;

    init_waitqueue_head(PIPE_WAIT(*inode));
    PIPE_BASE(*inode) = (char*) page;
    PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
    PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
    PIPE_WAITING_WRITERS(*inode) = 0;
    PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1;
    *PIPE_FASYNC_READERS(*inode) = *PIPE_FASYNC_WRITERS(*inode) = NULL;

    return inode;
fail_page:
    free_page(page);
    return NULL;
}
Пример #2
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;
}
Пример #3
0
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)) {
        struct pipe_inode_info *info = inode->i_pipe;
        inode->i_pipe = NULL;
        free_page((unsigned long) info->base);
        kfree(info);
    } 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;
}
Пример #4
0
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;
    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));
    for (;;) {
        int size = PIPE_LEN(*inode);
        if (size) {
            char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode);
            ssize_t chars = PIPE_MAX_RCHUNK(*inode);

            if (chars > total_len)
                chars = total_len;
            if (chars > size)
                chars = size;

            if (pipe_iov_copy_to_user(iov, pipebuf, chars)) {
                if (!ret) ret = -EFAULT;
                break;
            }
            ret += chars;

            PIPE_START(*inode) += chars;
            PIPE_START(*inode) &= (PIPE_SIZE - 1);
            PIPE_LEN(*inode) -= chars;
            total_len -= chars;
            do_wakeup = 1;
            if (!total_len)
                break;	/* common path: read succeeded */
        }
        if (PIPE_LEN(*inode)) /* test for cyclic buffers */
            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);
    }
    /*
     * Hack: we turn off atime updates for -RT kernels.
     * Who uses them on pipes anyway?
     */
#ifndef CONFIG_PREEMPT_RT
    if (ret > 0)
        file_accessed(filp);
#endif
    return ret;
}
Пример #5
0
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;
}