infinibad: weird APIs switched to ->write_iter()
Things Not To Do When Writing A Driver, part 1001st: have writev() and write() on the same file doing completely different things. As in, "interpret very different sets of commands". We _can_ handle that, but it's a bloody bad idea. Don't do that in new drivers. Ever. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
9a219bc70b
commit
4961772560
2 changed files with 23 additions and 15 deletions
|
@ -42,6 +42,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/uio.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
|
|
||||||
#include "ipath_kernel.h"
|
#include "ipath_kernel.h"
|
||||||
|
@ -52,15 +53,19 @@ static int ipath_open(struct inode *, struct file *);
|
||||||
static int ipath_close(struct inode *, struct file *);
|
static int ipath_close(struct inode *, struct file *);
|
||||||
static ssize_t ipath_write(struct file *, const char __user *, size_t,
|
static ssize_t ipath_write(struct file *, const char __user *, size_t,
|
||||||
loff_t *);
|
loff_t *);
|
||||||
static ssize_t ipath_writev(struct kiocb *, const struct iovec *,
|
static ssize_t ipath_write_iter(struct kiocb *, struct iov_iter *from);
|
||||||
unsigned long , loff_t);
|
|
||||||
static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
|
static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
|
||||||
static int ipath_mmap(struct file *, struct vm_area_struct *);
|
static int ipath_mmap(struct file *, struct vm_area_struct *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is really, really weird shit - write() and writev() here
|
||||||
|
* have completely unrelated semantics. Sucky userland ABI,
|
||||||
|
* film at 11.
|
||||||
|
*/
|
||||||
static const struct file_operations ipath_file_ops = {
|
static const struct file_operations ipath_file_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.write = ipath_write,
|
.write = ipath_write,
|
||||||
.aio_write = ipath_writev,
|
.write_iter = ipath_write_iter,
|
||||||
.open = ipath_open,
|
.open = ipath_open,
|
||||||
.release = ipath_close,
|
.release = ipath_close,
|
||||||
.poll = ipath_poll,
|
.poll = ipath_poll,
|
||||||
|
@ -2413,18 +2418,17 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ipath_writev(struct kiocb *iocb, const struct iovec *iov,
|
static ssize_t ipath_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
unsigned long dim, loff_t off)
|
|
||||||
{
|
{
|
||||||
struct file *filp = iocb->ki_filp;
|
struct file *filp = iocb->ki_filp;
|
||||||
struct ipath_filedata *fp = filp->private_data;
|
struct ipath_filedata *fp = filp->private_data;
|
||||||
struct ipath_portdata *pd = port_fp(filp);
|
struct ipath_portdata *pd = port_fp(filp);
|
||||||
struct ipath_user_sdma_queue *pq = fp->pq;
|
struct ipath_user_sdma_queue *pq = fp->pq;
|
||||||
|
|
||||||
if (!dim)
|
if (!iter_is_iovec(from) || !from->nr_segs)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return ipath_user_sdma_writev(pd->port_dd, pq, iov, dim);
|
return ipath_user_sdma_writev(pd->port_dd, pq, from->iov, from->nr_segs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct class *ipath_class;
|
static struct class *ipath_class;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/uio.h>
|
||||||
|
|
||||||
#include "qib.h"
|
#include "qib.h"
|
||||||
#include "qib_common.h"
|
#include "qib_common.h"
|
||||||
|
@ -54,15 +55,19 @@
|
||||||
static int qib_open(struct inode *, struct file *);
|
static int qib_open(struct inode *, struct file *);
|
||||||
static int qib_close(struct inode *, struct file *);
|
static int qib_close(struct inode *, struct file *);
|
||||||
static ssize_t qib_write(struct file *, const char __user *, size_t, loff_t *);
|
static ssize_t qib_write(struct file *, const char __user *, size_t, loff_t *);
|
||||||
static ssize_t qib_aio_write(struct kiocb *, const struct iovec *,
|
static ssize_t qib_write_iter(struct kiocb *, struct iov_iter *);
|
||||||
unsigned long, loff_t);
|
|
||||||
static unsigned int qib_poll(struct file *, struct poll_table_struct *);
|
static unsigned int qib_poll(struct file *, struct poll_table_struct *);
|
||||||
static int qib_mmapf(struct file *, struct vm_area_struct *);
|
static int qib_mmapf(struct file *, struct vm_area_struct *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is really, really weird shit - write() and writev() here
|
||||||
|
* have completely unrelated semantics. Sucky userland ABI,
|
||||||
|
* film at 11.
|
||||||
|
*/
|
||||||
static const struct file_operations qib_file_ops = {
|
static const struct file_operations qib_file_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.write = qib_write,
|
.write = qib_write,
|
||||||
.aio_write = qib_aio_write,
|
.write_iter = qib_write_iter,
|
||||||
.open = qib_open,
|
.open = qib_open,
|
||||||
.release = qib_close,
|
.release = qib_close,
|
||||||
.poll = qib_poll,
|
.poll = qib_poll,
|
||||||
|
@ -2248,17 +2253,16 @@ static ssize_t qib_write(struct file *fp, const char __user *data,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t qib_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
unsigned long dim, loff_t off)
|
|
||||||
{
|
{
|
||||||
struct qib_filedata *fp = iocb->ki_filp->private_data;
|
struct qib_filedata *fp = iocb->ki_filp->private_data;
|
||||||
struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
|
struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
|
||||||
struct qib_user_sdma_queue *pq = fp->pq;
|
struct qib_user_sdma_queue *pq = fp->pq;
|
||||||
|
|
||||||
if (!dim || !pq)
|
if (!iter_is_iovec(from) || !from->nr_segs || !pq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return qib_user_sdma_writev(rcd, pq, iov, dim);
|
return qib_user_sdma_writev(rcd, pq, from->iov, from->nr_segs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct class *qib_class;
|
static struct class *qib_class;
|
||||||
|
|
Loading…
Reference in a new issue