Commit 1455f82d authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] sparse: dvb_ringbuffer_pkt_write()/dvb_ringbuffer_write() annotation

copy_from_user() moved from dvb_ringbuffer_{write,pkt_write}() to callers;
these functions are always getting kernel pointer now.  "usermem" argument
killed, code annotated.
parent dd3fb8a8
......@@ -621,7 +621,7 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
/* OK, add it to the receive buffer, or copy into external buffer if supplied */
if (ebuf == NULL) {
dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read, 0);
dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
} else {
memcpy(ebuf, buf, bytes_read);
}
......
......@@ -133,8 +133,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len, int usermem)
ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
{
size_t todo = len;
size_t split;
......@@ -142,28 +141,18 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
if (split > 0) {
if (!usermem)
memcpy(rbuf->data+rbuf->pwrite, buf, split);
else
if (copy_from_user(rbuf->data+rbuf->pwrite,
buf, split))
return -EFAULT;
memcpy(rbuf->data+rbuf->pwrite, buf, split);
buf += split;
todo -= split;
rbuf->pwrite = 0;
}
if (!usermem)
memcpy(rbuf->data+rbuf->pwrite, buf, todo);
else
if (copy_from_user(rbuf->data+rbuf->pwrite, buf, todo))
return -EFAULT;
memcpy(rbuf->data+rbuf->pwrite, buf, todo);
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
return len;
}
ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len, int usermem)
ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
{
int status;
ssize_t oldpwrite = rbuf->pwrite;
......@@ -171,7 +160,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
status = dvb_ringbuffer_write(rbuf, buf, len, usermem);
status = dvb_ringbuffer_write(rbuf, buf, len);
if (status < 0) rbuf->pwrite = oldpwrite;
return status;
......
......@@ -53,7 +53,7 @@ struct dvb_ringbuffer {
** *** write <buflen> bytes ***
** free = dvb_ringbuffer_free(rbuf);
** if (free >= buflen)
** count = dvb_ringbuffer_write(rbuf, buffer, buflen, 0);
** count = dvb_ringbuffer_write(rbuf, buffer, buflen);
** else
** ...
**
......@@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
** returns number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len, int usermem);
size_t len);
/**
......@@ -130,11 +130,10 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
* <rbuf> Ringbuffer to write to.
* <buf> Buffer to write.
* <len> Length of buffer (currently limited to 65535 bytes max).
* <usermem> Set to 1 if <buf> is in userspace.
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
*/
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
size_t len, int usermem);
size_t len);
/**
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
......
......@@ -393,7 +393,7 @@ static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
free = dvb_ringbuffer_free(rbuf);
if (free > todo)
free = todo;
dvb_ringbuffer_write(rbuf, buf, free, 0);
dvb_ringbuffer_write(rbuf, buf, free);
todo -= free;
buf += free;
}
......@@ -424,8 +424,8 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf,
unsigned long count, int nonblock, int type, int umem)
static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
DEB_EE(("av7110: %p\n", av7110));
......@@ -447,15 +447,40 @@ static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf,
n = todo;
if (n > IPACKS * 2)
n = IPACKS * 2;
if (umem) {
if (copy_from_user(av7110->kbuf[type], buf, n))
return -EFAULT;
av7110_ipack_instant_repack(av7110->kbuf[type], n,
&av7110->ipack[type]);
} else {
av7110_ipack_instant_repack(buf, n,
&av7110->ipack[type]);
if (copy_from_user(av7110->kbuf[type], buf, n))
return -EFAULT;
av7110_ipack_instant_repack(av7110->kbuf[type], n,
&av7110->ipack[type]);
todo -= n;
buf += n;
}
return count - todo;
}
static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
DEB_EE(("av7110: %p\n", av7110));
if (!av7110->kbuf[type])
return -ENOBUFS;
if (nonblock && !FREE_COND)
return -EWOULDBLOCK;
while (todo > 0) {
if (!FREE_COND) {
if (nonblock)
return count - todo;
if (wait_event_interruptible(av7110->avout.queue,
FREE_COND))
return count - todo;
}
n = todo;
if (n > IPACKS * 2)
n = IPACKS * 2;
av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]);
todo -= n;
buf += n;
}
......@@ -885,7 +910,7 @@ static ssize_t dvb_video_write(struct file *file, const char *buf,
if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
return -EPERM;
return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1, 1);
return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
}
static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
......@@ -942,10 +967,10 @@ static int play_iframe(struct av7110 *av7110, u8 *buf, unsigned int len, int non
n = MIN_IFRAME / len + 1;
/* FIXME: nonblock? */
dvb_play(av7110, iframe_header, sizeof(iframe_header), 0, 1, 0);
dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1);
for (i = 0; i < n; i++)
dvb_play(av7110, buf, len, 0, 1, 1);
dvb_play(av7110, buf, len, 0, 1);
av7110_ipack_flush(&av7110->ipack[1]);
return 0;
......
......@@ -85,7 +85,7 @@ void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8);
DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff);
dvb_ringbuffer_write(cibuf, data, len, 0);
dvb_ringbuffer_write(cibuf, data, len);
wake_up_interruptible(&cibuf->queue);
}
......@@ -133,7 +133,7 @@ int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
for (i = 0; i < 2; i++) {
if (slots & (1 << i)) {
msg[2] = i;
dvb_ringbuffer_write(cibuf, msg, 8, 0);
dvb_ringbuffer_write(cibuf, msg, 8);
slot[i].flags = 0;
}
}
......@@ -146,22 +146,38 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
{
int free;
int non_blocking = file->f_flags & O_NONBLOCK;
char *page = (char *)__get_free_page(GFP_USER);
int res;
if (!page)
return -ENOMEM;
res = -EINVAL;
if (count > 2048)
return -EINVAL;
goto out;
res = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
free = dvb_ringbuffer_free(cibuf);
if (count + 2 > free) {
res = -EWOULDBLOCK;
if (non_blocking)
return -EWOULDBLOCK;
goto out;
res = -ERESTARTSYS;
if (wait_event_interruptible(cibuf->queue,
(dvb_ringbuffer_free(cibuf) >= count + 2)))
return -ERESTARTSYS;
goto out;
}
DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8);
DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff);
return dvb_ringbuffer_write(cibuf, buf, count, 1);
res = dvb_ringbuffer_write(cibuf, page, count);
out:
free_page((unsigned long)page);
return res;
}
static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment