|
@@ -85,6 +85,8 @@ struct mon_reader_text {
|
|
|
|
|
|
wait_queue_head_t wait;
|
|
|
int printf_size;
|
|
|
+ size_t printf_offset;
|
|
|
+ size_t printf_togo;
|
|
|
char *printf_buf;
|
|
|
struct mutex printf_lock;
|
|
|
|
|
@@ -376,75 +378,103 @@ err_alloc:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * For simplicity, we read one record in one system call and throw out
|
|
|
- * what does not fit. This means that the following does not work:
|
|
|
- * dd if=/dbg/usbmon/0t bs=10
|
|
|
- * Also, we do not allow seeks and do not bother advancing the offset.
|
|
|
- */
|
|
|
+static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
|
|
|
+ char __user * const buf, const size_t nbytes)
|
|
|
+{
|
|
|
+ const size_t togo = min(nbytes, rp->printf_togo);
|
|
|
+
|
|
|
+ if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
|
|
|
+ return -EFAULT;
|
|
|
+ rp->printf_togo -= togo;
|
|
|
+ rp->printf_offset += togo;
|
|
|
+ return togo;
|
|
|
+}
|
|
|
+
|
|
|
+/* ppos is not advanced since the llseek operation is not permitted. */
|
|
|
static ssize_t mon_text_read_t(struct file *file, char __user *buf,
|
|
|
- size_t nbytes, loff_t *ppos)
|
|
|
+ size_t nbytes, loff_t *ppos)
|
|
|
{
|
|
|
struct mon_reader_text *rp = file->private_data;
|
|
|
struct mon_event_text *ep;
|
|
|
struct mon_text_ptr ptr;
|
|
|
+ ssize_t ret;
|
|
|
|
|
|
- ep = mon_text_read_wait(rp, file);
|
|
|
- if (IS_ERR(ep))
|
|
|
- return PTR_ERR(ep);
|
|
|
mutex_lock(&rp->printf_lock);
|
|
|
- ptr.cnt = 0;
|
|
|
- ptr.pbuf = rp->printf_buf;
|
|
|
- ptr.limit = rp->printf_size;
|
|
|
-
|
|
|
- mon_text_read_head_t(rp, &ptr, ep);
|
|
|
- mon_text_read_statset(rp, &ptr, ep);
|
|
|
- ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
|
|
- " %d", ep->length);
|
|
|
- mon_text_read_data(rp, &ptr, ep);
|
|
|
-
|
|
|
- if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
|
|
|
- ptr.cnt = -EFAULT;
|
|
|
+
|
|
|
+ if (rp->printf_togo == 0) {
|
|
|
+
|
|
|
+ ep = mon_text_read_wait(rp, file);
|
|
|
+ if (IS_ERR(ep)) {
|
|
|
+ mutex_unlock(&rp->printf_lock);
|
|
|
+ return PTR_ERR(ep);
|
|
|
+ }
|
|
|
+ ptr.cnt = 0;
|
|
|
+ ptr.pbuf = rp->printf_buf;
|
|
|
+ ptr.limit = rp->printf_size;
|
|
|
+
|
|
|
+ mon_text_read_head_t(rp, &ptr, ep);
|
|
|
+ mon_text_read_statset(rp, &ptr, ep);
|
|
|
+ ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
|
|
+ " %d", ep->length);
|
|
|
+ mon_text_read_data(rp, &ptr, ep);
|
|
|
+
|
|
|
+ rp->printf_togo = ptr.cnt;
|
|
|
+ rp->printf_offset = 0;
|
|
|
+
|
|
|
+ kmem_cache_free(rp->e_slab, ep);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = mon_text_copy_to_user(rp, buf, nbytes);
|
|
|
mutex_unlock(&rp->printf_lock);
|
|
|
- kmem_cache_free(rp->e_slab, ep);
|
|
|
- return ptr.cnt;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
+/* ppos is not advanced since the llseek operation is not permitted. */
|
|
|
static ssize_t mon_text_read_u(struct file *file, char __user *buf,
|
|
|
- size_t nbytes, loff_t *ppos)
|
|
|
+ size_t nbytes, loff_t *ppos)
|
|
|
{
|
|
|
struct mon_reader_text *rp = file->private_data;
|
|
|
struct mon_event_text *ep;
|
|
|
struct mon_text_ptr ptr;
|
|
|
+ ssize_t ret;
|
|
|
|
|
|
- ep = mon_text_read_wait(rp, file);
|
|
|
- if (IS_ERR(ep))
|
|
|
- return PTR_ERR(ep);
|
|
|
mutex_lock(&rp->printf_lock);
|
|
|
- ptr.cnt = 0;
|
|
|
- ptr.pbuf = rp->printf_buf;
|
|
|
- ptr.limit = rp->printf_size;
|
|
|
|
|
|
- mon_text_read_head_u(rp, &ptr, ep);
|
|
|
- if (ep->type == 'E') {
|
|
|
- mon_text_read_statset(rp, &ptr, ep);
|
|
|
- } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
|
|
|
- mon_text_read_isostat(rp, &ptr, ep);
|
|
|
- mon_text_read_isodesc(rp, &ptr, ep);
|
|
|
- } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
|
|
|
- mon_text_read_intstat(rp, &ptr, ep);
|
|
|
- } else {
|
|
|
- mon_text_read_statset(rp, &ptr, ep);
|
|
|
+ if (rp->printf_togo == 0) {
|
|
|
+
|
|
|
+ ep = mon_text_read_wait(rp, file);
|
|
|
+ if (IS_ERR(ep)) {
|
|
|
+ mutex_unlock(&rp->printf_lock);
|
|
|
+ return PTR_ERR(ep);
|
|
|
+ }
|
|
|
+ ptr.cnt = 0;
|
|
|
+ ptr.pbuf = rp->printf_buf;
|
|
|
+ ptr.limit = rp->printf_size;
|
|
|
+
|
|
|
+ mon_text_read_head_u(rp, &ptr, ep);
|
|
|
+ if (ep->type == 'E') {
|
|
|
+ mon_text_read_statset(rp, &ptr, ep);
|
|
|
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
|
|
|
+ mon_text_read_isostat(rp, &ptr, ep);
|
|
|
+ mon_text_read_isodesc(rp, &ptr, ep);
|
|
|
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
|
|
|
+ mon_text_read_intstat(rp, &ptr, ep);
|
|
|
+ } else {
|
|
|
+ mon_text_read_statset(rp, &ptr, ep);
|
|
|
+ }
|
|
|
+ ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
|
|
+ " %d", ep->length);
|
|
|
+ mon_text_read_data(rp, &ptr, ep);
|
|
|
+
|
|
|
+ rp->printf_togo = ptr.cnt;
|
|
|
+ rp->printf_offset = 0;
|
|
|
+
|
|
|
+ kmem_cache_free(rp->e_slab, ep);
|
|
|
}
|
|
|
- ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
|
|
- " %d", ep->length);
|
|
|
- mon_text_read_data(rp, &ptr, ep);
|
|
|
|
|
|
- if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
|
|
|
- ptr.cnt = -EFAULT;
|
|
|
+ ret = mon_text_copy_to_user(rp, buf, nbytes);
|
|
|
mutex_unlock(&rp->printf_lock);
|
|
|
- kmem_cache_free(rp->e_slab, ep);
|
|
|
- return ptr.cnt;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
|