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 ...@@ -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 */ /* OK, add it to the receive buffer, or copy into external buffer if supplied */
if (ebuf == NULL) { 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 { } else {
memcpy(ebuf, buf, bytes_read); memcpy(ebuf, buf, bytes_read);
} }
......
...@@ -133,8 +133,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in ...@@ -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, ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
size_t len, int usermem)
{ {
size_t todo = len; size_t todo = len;
size_t split; size_t split;
...@@ -142,28 +141,18 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, ...@@ -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; split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
if (split > 0) { if (split > 0) {
if (!usermem)
memcpy(rbuf->data+rbuf->pwrite, buf, split); memcpy(rbuf->data+rbuf->pwrite, buf, split);
else
if (copy_from_user(rbuf->data+rbuf->pwrite,
buf, split))
return -EFAULT;
buf += split; buf += split;
todo -= split; todo -= split;
rbuf->pwrite = 0; rbuf->pwrite = 0;
} }
if (!usermem)
memcpy(rbuf->data+rbuf->pwrite, buf, todo); memcpy(rbuf->data+rbuf->pwrite, buf, todo);
else
if (copy_from_user(rbuf->data+rbuf->pwrite, buf, todo))
return -EFAULT;
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
return len; 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; int status;
ssize_t oldpwrite = rbuf->pwrite; ssize_t oldpwrite = rbuf->pwrite;
...@@ -171,7 +160,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le ...@@ -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 >> 8);
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); 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; if (status < 0) rbuf->pwrite = oldpwrite;
return status; return status;
......
...@@ -53,7 +53,7 @@ struct dvb_ringbuffer { ...@@ -53,7 +53,7 @@ struct dvb_ringbuffer {
** *** write <buflen> bytes *** ** *** write <buflen> bytes ***
** free = dvb_ringbuffer_free(rbuf); ** free = dvb_ringbuffer_free(rbuf);
** if (free >= buflen) ** if (free >= buflen)
** count = dvb_ringbuffer_write(rbuf, buffer, buflen, 0); ** count = dvb_ringbuffer_write(rbuf, buffer, buflen);
** else ** else
** ... ** ...
** **
...@@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, ...@@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
** returns number of bytes transferred or -EFAULT ** returns number of bytes transferred or -EFAULT
*/ */
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, 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, ...@@ -130,11 +130,10 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
* <rbuf> Ringbuffer to write to. * <rbuf> Ringbuffer to write to.
* <buf> Buffer to write. * <buf> Buffer to write.
* <len> Length of buffer (currently limited to 65535 bytes max). * <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. * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
*/ */
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, 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 * 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, ...@@ -393,7 +393,7 @@ static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
free = dvb_ringbuffer_free(rbuf); free = dvb_ringbuffer_free(rbuf);
if (free > todo) if (free > todo)
free = todo; free = todo;
dvb_ringbuffer_write(rbuf, buf, free, 0); dvb_ringbuffer_write(rbuf, buf, free);
todo -= free; todo -= free;
buf += free; buf += free;
} }
...@@ -424,8 +424,8 @@ static void play_audio_cb(u8 *buf, int count, void *priv) ...@@ -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 && \ #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf, static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
unsigned long count, int nonblock, int type, int umem) unsigned long count, int nonblock, int type)
{ {
unsigned long todo = count, n; unsigned long todo = count, n;
DEB_EE(("av7110: %p\n", av7110)); DEB_EE(("av7110: %p\n", av7110));
...@@ -447,15 +447,40 @@ static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf, ...@@ -447,15 +447,40 @@ static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf,
n = todo; n = todo;
if (n > IPACKS * 2) if (n > IPACKS * 2)
n = IPACKS * 2; n = IPACKS * 2;
if (umem) {
if (copy_from_user(av7110->kbuf[type], buf, n)) if (copy_from_user(av7110->kbuf[type], buf, n))
return -EFAULT; return -EFAULT;
av7110_ipack_instant_repack(av7110->kbuf[type], n, av7110_ipack_instant_repack(av7110->kbuf[type], n,
&av7110->ipack[type]); &av7110->ipack[type]);
} else { todo -= n;
av7110_ipack_instant_repack(buf, n, buf += n;
&av7110->ipack[type]); }
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; todo -= n;
buf += n; buf += n;
} }
...@@ -885,7 +910,7 @@ static ssize_t dvb_video_write(struct file *file, const char *buf, ...@@ -885,7 +910,7 @@ static ssize_t dvb_video_write(struct file *file, const char *buf,
if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
return -EPERM; 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) 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 ...@@ -942,10 +967,10 @@ static int play_iframe(struct av7110 *av7110, u8 *buf, unsigned int len, int non
n = MIN_IFRAME / len + 1; n = MIN_IFRAME / len + 1;
/* FIXME: nonblock? */ /* 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++) 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]); av7110_ipack_flush(&av7110->ipack[1]);
return 0; return 0;
......
...@@ -85,7 +85,7 @@ void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len) ...@@ -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 >> 8);
DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); 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); wake_up_interruptible(&cibuf->queue);
} }
...@@ -133,7 +133,7 @@ int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, ...@@ -133,7 +133,7 @@ int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (slots & (1 << i)) { if (slots & (1 << i)) {
msg[2] = i; msg[2] = i;
dvb_ringbuffer_write(cibuf, msg, 8, 0); dvb_ringbuffer_write(cibuf, msg, 8);
slot[i].flags = 0; slot[i].flags = 0;
} }
} }
...@@ -146,22 +146,38 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, ...@@ -146,22 +146,38 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
{ {
int free; int free;
int non_blocking = file->f_flags & O_NONBLOCK; 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) if (count > 2048)
return -EINVAL; goto out;
res = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
free = dvb_ringbuffer_free(cibuf); free = dvb_ringbuffer_free(cibuf);
if (count + 2 > free) { if (count + 2 > free) {
res = -EWOULDBLOCK;
if (non_blocking) if (non_blocking)
return -EWOULDBLOCK; goto out;
res = -ERESTARTSYS;
if (wait_event_interruptible(cibuf->queue, if (wait_event_interruptible(cibuf->queue,
(dvb_ringbuffer_free(cibuf) >= count + 2))) (dvb_ringbuffer_free(cibuf) >= count + 2)))
return -ERESTARTSYS; goto out;
} }
DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8);
DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); 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, 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