Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce1d4d3e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David S. Miller
Browse files

[NET]: restructure sock_aio_{read,write} / sock_{readv,writev}



Mid-term I plan to restructure the file_operations so that we don't need
to have all these duplicate aio and vectored versions.  This patch is
a small step in that direction but also a worthwile cleanup on it's own:

(1) introduce a alloc_sock_iocb helper that encapsulates allocating a
    proper sock_iocb
(2) add do_sock_read and do_sock_write helpers for common read/write
    code

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cbeb321a
Loading
Loading
Loading
Loading
+110 −114
Original line number Diff line number Diff line
@@ -640,154 +640,150 @@ static void sock_aio_dtor(struct kiocb *iocb)
	kfree(iocb->private);
}

/*
 *	Read data from a socket. ubuf is a user mode pointer. We make sure the user
 *	area ubuf...ubuf+size-1 is writable before asking the protocol.
 */

static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
			 size_t size, loff_t pos)
static ssize_t sock_sendpage(struct file *file, struct page *page,
			     int offset, size_t size, loff_t *ppos, int more)
{
	struct sock_iocb *x, siocb;
	struct socket *sock;
	int flags;

	if (pos != 0)
		return -ESPIPE;
	if (size==0)		/* Match SYS5 behaviour */
		return 0;
	sock = file->private_data;

	if (is_sync_kiocb(iocb))
		x = &siocb;
	else {
		x = kmalloc(sizeof(struct sock_iocb), GFP_KERNEL);
		if (!x)
			return -ENOMEM;
	flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
	if (more)
		flags |= MSG_MORE;

	return sock->ops->sendpage(sock, page, offset, size, flags);
}

static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
		char __user *ubuf, size_t size, struct sock_iocb *siocb)
{
	if (!is_sync_kiocb(iocb)) {
		siocb = kmalloc(sizeof(*siocb), GFP_KERNEL);
		if (!siocb)
			return NULL;
		iocb->ki_dtor = sock_aio_dtor;
	}
	iocb->private = x;
	x->kiocb = iocb;
	sock = iocb->ki_filp->private_data; 

	x->async_msg.msg_name = NULL;
	x->async_msg.msg_namelen = 0;
	x->async_msg.msg_iov = &x->async_iov;
	x->async_msg.msg_iovlen = 1;
	x->async_msg.msg_control = NULL;
	x->async_msg.msg_controllen = 0;
	x->async_iov.iov_base = ubuf;
	x->async_iov.iov_len = size;
	flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
	siocb->kiocb = iocb;
	siocb->async_iov.iov_base = ubuf;
	siocb->async_iov.iov_len = size;

	return __sock_recvmsg(iocb, sock, &x->async_msg, size, flags);
	iocb->private = siocb;
	return siocb;
}

static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
		struct file *file, struct iovec *iov, unsigned long nr_segs)
{
	struct socket *sock = file->private_data;
	size_t size = 0;
	int i;

/*
 *	Write data to a socket. We verify that the user area ubuf..ubuf+size-1
 *	is readable by the user process.
 */
        for (i = 0 ; i < nr_segs ; i++)
                size += iov[i].iov_len;

static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
			  size_t size, loff_t pos)
	msg->msg_name = NULL;
	msg->msg_namelen = 0;
	msg->msg_control = NULL;
	msg->msg_controllen = 0;
	msg->msg_iov = (struct iovec *) iov;
	msg->msg_iovlen = nr_segs;
	msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;

	return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
}

static ssize_t sock_readv(struct file *file, const struct iovec *iov,
			  unsigned long nr_segs, loff_t *ppos)
{
	struct sock_iocb *x, siocb;
	struct socket *sock;
	struct kiocb iocb;
	struct sock_iocb siocb;
	struct msghdr msg;
	int ret;

        init_sync_kiocb(&iocb, NULL);
	iocb.private = &siocb;

	ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
	if (-EIOCBQUEUED == ret)
		ret = wait_on_sync_kiocb(&iocb);
	return ret;
}

static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
			 size_t count, loff_t pos)
{
	struct sock_iocb siocb, *x;

	if (pos != 0)
		return -ESPIPE;
	if(size==0)		/* Match SYS5 behaviour */
	if (count == 0)		/* Match SYS5 behaviour */
		return 0;

	if (is_sync_kiocb(iocb))
		x = &siocb;
	else {
		x = kmalloc(sizeof(struct sock_iocb), GFP_KERNEL);
	x = alloc_sock_iocb(iocb, ubuf, count, &siocb);
	if (!x)
		return -ENOMEM;
		iocb->ki_dtor = sock_aio_dtor;
	}
	iocb->private = x;
	x->kiocb = iocb;
	sock = iocb->ki_filp->private_data; 

	x->async_msg.msg_name = NULL;
	x->async_msg.msg_namelen = 0;
	x->async_msg.msg_iov = &x->async_iov;
	x->async_msg.msg_iovlen = 1;
	x->async_msg.msg_control = NULL;
	x->async_msg.msg_controllen = 0;
	x->async_msg.msg_flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
	if (sock->type == SOCK_SEQPACKET)
		x->async_msg.msg_flags |= MSG_EOR;
	x->async_iov.iov_base = (void __user *)ubuf;
	x->async_iov.iov_len = size;
	
	return __sock_sendmsg(iocb, sock, &x->async_msg, size);
	return do_sock_read(&x->async_msg, iocb, iocb->ki_filp,
			&x->async_iov, 1);
}

static ssize_t sock_sendpage(struct file *file, struct page *page,
			     int offset, size_t size, loff_t *ppos, int more)
static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
		struct file *file, struct iovec *iov, unsigned long nr_segs)
{
	struct socket *sock;
	int flags;
	struct socket *sock = file->private_data;
	size_t size = 0;
	int i;

	sock = file->private_data;
        for (i = 0 ; i < nr_segs ; i++)
                size += iov[i].iov_len;

	flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
	if (more)
		flags |= MSG_MORE;
	msg->msg_name = NULL;
	msg->msg_namelen = 0;
	msg->msg_control = NULL;
	msg->msg_controllen = 0;
	msg->msg_iov = (struct iovec *) iov;
	msg->msg_iovlen = nr_segs;
	msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
	if (sock->type == SOCK_SEQPACKET)
		msg->msg_flags |= MSG_EOR;

	return sock->ops->sendpage(sock, page, offset, size, flags);
	return __sock_sendmsg(iocb, sock, msg, size);
}

static int sock_readv_writev(int type,
			     struct file * file, const struct iovec * iov,
			     long count, size_t size)
static ssize_t sock_writev(struct file *file, const struct iovec *iov,
			   unsigned long nr_segs, loff_t *ppos)
{
	struct msghdr msg;
	struct socket *sock;

	sock = file->private_data;

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_iov = (struct iovec *) iov;
	msg.msg_iovlen = count;
	msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;

	/* read() does a VERIFY_WRITE */
	if (type == VERIFY_WRITE)
		return sock_recvmsg(sock, &msg, size, msg.msg_flags);
	struct kiocb iocb;
	struct sock_iocb siocb;
	int ret;

	if (sock->type == SOCK_SEQPACKET)
		msg.msg_flags |= MSG_EOR;
	init_sync_kiocb(&iocb, NULL);
	iocb.private = &siocb;

	return sock_sendmsg(sock, &msg, size);
	ret = do_sock_write(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
	if (-EIOCBQUEUED == ret)
		ret = wait_on_sync_kiocb(&iocb);
	return ret;
}

static ssize_t sock_readv(struct file *file, const struct iovec *vector,
			  unsigned long count, loff_t *ppos)
static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
			  size_t count, loff_t pos)
{
	size_t tot_len = 0;
	int i;
        for (i = 0 ; i < count ; i++)
                tot_len += vector[i].iov_len;
	return sock_readv_writev(VERIFY_WRITE,
				 file, vector, count, tot_len);
}
	struct sock_iocb siocb, *x;

static ssize_t sock_writev(struct file *file, const struct iovec *vector,
			   unsigned long count, loff_t *ppos)
{
	size_t tot_len = 0;
	int i;
        for (i = 0 ; i < count ; i++)
                tot_len += vector[i].iov_len;
	return sock_readv_writev(VERIFY_READ,
				 file, vector, count, tot_len);
	if (pos != 0)
		return -ESPIPE;
	if (count == 0)		/* Match SYS5 behaviour */
		return 0;

	x = alloc_sock_iocb(iocb, (void __user *)ubuf, count, &siocb);
	if (!x)
		return -ENOMEM;

	return do_sock_write(&x->async_msg, iocb, iocb->ki_filp,
			&x->async_iov, 1);
}