diff options
Diffstat (limited to 'drivers/usb/mon')
| -rw-r--r-- | drivers/usb/mon/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/usb/mon/Makefile | 1 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_bin.c | 116 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_main.c | 50 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_stat.c | 13 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_text.c | 238 | ||||
| -rw-r--r-- | drivers/usb/mon/usb_mon.h | 1 |
7 files changed, 221 insertions, 201 deletions
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 5c6ffa2a612e..ffc7cd422874 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Monitor configuration # @@ -7,6 +8,6 @@ config USB_MON help If you select this option, a component which captures the USB traffic between peripheral-specific drivers and HC drivers will be built. - For more information, see <file:Documentation/usb/usbmon.txt>. + For more information, see <file:Documentation/usb/usbmon.rst>. If unsure, say Y, if allowed, otherwise M. diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index 8ed24ab08698..09f43e89633c 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Makefile for USB monitor # diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 9a62e89d6dc0..e713fc5964b1 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * The USB Monitor, inspired by Dave Harding's USBMon. * @@ -8,6 +9,7 @@ */ #include <linux/kernel.h> +#include <linux/sched/signal.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/cdev.h> @@ -18,8 +20,9 @@ #include <linux/mm.h> #include <linux/scatterlist.h> #include <linux/slab.h> +#include <linux/time64.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "usb_mon.h" @@ -65,18 +68,20 @@ * The magic limit was calculated so that it allows the monitoring * application to pick data once in two ticks. This way, another application, * which presumably drives the bus, gets to hog CPU, yet we collect our data. - * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an - * enormous overhead built into the bus protocol, so we need about 1000 KB. + * + * Originally, for a 480 Mbit/s bus this required a buffer of about 1 MB. For + * modern 20 Gbps buses, this value increases to over 50 MB. The maximum + * buffer size is set to 64 MiB to accommodate this. * * This is still too much for most cases, where we just snoop a few * descriptor fetches for enumeration. So, the default is a "reasonable" - * amount for systems with HZ=250 and incomplete bus saturation. + * amount for typical, low-throughput use cases. * * XXX What about multi-megabyte URBs which take minutes to transfer? */ -#define BUFF_MAX CHUNK_ALIGN(1200*1024) -#define BUFF_DFL CHUNK_ALIGN(300*1024) -#define BUFF_MIN CHUNK_ALIGN(8*1024) +#define BUFF_MAX CHUNK_ALIGN(64*1024*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) /* * The per-event API header (2 per URB). @@ -92,8 +97,8 @@ struct mon_bin_hdr { unsigned short busnum; /* Bus number */ char flag_setup; char flag_data; - s64 ts_sec; /* gettimeofday */ - s32 ts_usec; /* gettimeofday */ + s64 ts_sec; /* ktime_get_real_ts64 */ + s32 ts_usec; /* ktime_get_real_ts64 */ int status; unsigned int len_urb; /* Length of data (submitted or actual) */ unsigned int len_cap; /* Delivered length */ @@ -210,7 +215,10 @@ static unsigned char xfer_to_pipe[4] = { PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT }; -static struct class *mon_bin_class; +static const struct class mon_bin_class = { + .name = "usbmon", +}; + static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -483,7 +491,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, char ev_type, int status) { const struct usb_endpoint_descriptor *epd = &urb->ep->desc; - struct timeval ts; + struct timespec64 ts; unsigned long flags; unsigned int urb_length; unsigned int offset; @@ -494,7 +502,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, struct mon_bin_hdr *ep; char data_tag = 0; - do_gettimeofday(&ts); + ktime_get_real_ts64(&ts); spin_lock_irqsave(&rp->b_lock, flags); @@ -568,7 +576,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; - ep->ts_usec = ts.tv_usec; + ep->ts_usec = ts.tv_nsec / NSEC_PER_USEC; ep->status = status; ep->len_urb = urb_length; ep->len_cap = length + lendesc; @@ -629,12 +637,12 @@ static void mon_bin_complete(void *data, struct urb *urb, int status) static void mon_bin_error(void *data, struct urb *urb, int error) { struct mon_reader_bin *rp = data; - struct timeval ts; + struct timespec64 ts; unsigned long flags; unsigned int offset; struct mon_bin_hdr *ep; - do_gettimeofday(&ts); + ktime_get_real_ts64(&ts); spin_lock_irqsave(&rp->b_lock, flags); @@ -656,7 +664,7 @@ static void mon_bin_error(void *data, struct urb *urb, int error) ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; - ep->ts_usec = ts.tv_usec; + ep->ts_usec = ts.tv_nsec / NSEC_PER_USEC; ep->status = error; ep->flag_setup = '-'; @@ -675,7 +683,8 @@ static int mon_bin_open(struct inode *inode, struct file *file) int rc; mutex_lock(&mon_lock); - if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) { + mbus = mon_bus_lookup(iminor(inode)); + if (mbus == NULL) { mutex_unlock(&mon_lock); return -ENODEV; } @@ -816,7 +825,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, ep = MON_OFF2HDR(rp, rp->b_out); if (rp->b_read < hdrbytes) { - step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read)); + step_len = min_t(size_t, nbytes, hdrbytes - rp->b_read); ptr = ((char *)ep) + rp->b_read; if (step_len && copy_to_user(buf, ptr, step_len)) { mutex_unlock(&rp->fetch_lock); @@ -1000,7 +1009,9 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg break; case MON_IOCQ_RING_SIZE: + mutex_lock(&rp->fetch_lock); ret = rp->b_size; + mutex_unlock(&rp->fetch_lock); break; case MON_IOCT_RING_SIZE: @@ -1018,8 +1029,9 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg return -EINVAL; size = CHUNK_ALIGN(arg); - if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE), - GFP_KERNEL)) == NULL) { + vec = kcalloc(size / CHUNK_SIZE, sizeof(struct mon_pgmap), + GFP_KERNEL); + if (vec == NULL) { ret = -ENOMEM; break; } @@ -1032,12 +1044,18 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg mutex_lock(&rp->fetch_lock); spin_lock_irqsave(&rp->b_lock, flags); - mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); - kfree(rp->b_vec); - rp->b_vec = vec; - rp->b_size = size; - rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; - rp->cnt_lost = 0; + if (rp->mmap_active) { + mon_free_buff(vec, size/CHUNK_SIZE); + kfree(vec); + ret = -EBUSY; + } else { + mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); + kfree(rp->b_vec); + rp->b_vec = vec; + rp->b_size = size; + rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; + rp->cnt_lost = 0; + } spin_unlock_irqrestore(&rp->b_lock, flags); mutex_unlock(&rp->fetch_lock); } @@ -1185,11 +1203,11 @@ static long mon_bin_compat_ioctl(struct file *file, } #endif /* CONFIG_COMPAT */ -static unsigned int +static __poll_t mon_bin_poll(struct file *file, struct poll_table_struct *wait) { struct mon_reader_bin *rp = file->private_data; - unsigned int mask = 0; + __poll_t mask = 0; unsigned long flags; if (file->f_mode & FMODE_READ) @@ -1197,7 +1215,7 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait) spin_lock_irqsave(&rp->b_lock, flags); if (!MON_RING_EMPTY(rp)) - mask |= POLLIN | POLLRDNORM; /* readable */ + mask |= EPOLLIN | EPOLLRDNORM; /* readable */ spin_unlock_irqrestore(&rp->b_lock, flags); return mask; } @@ -1209,31 +1227,44 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait) static void mon_bin_vma_open(struct vm_area_struct *vma) { struct mon_reader_bin *rp = vma->vm_private_data; + unsigned long flags; + + spin_lock_irqsave(&rp->b_lock, flags); rp->mmap_active++; + spin_unlock_irqrestore(&rp->b_lock, flags); } static void mon_bin_vma_close(struct vm_area_struct *vma) { + unsigned long flags; + struct mon_reader_bin *rp = vma->vm_private_data; + spin_lock_irqsave(&rp->b_lock, flags); rp->mmap_active--; + spin_unlock_irqrestore(&rp->b_lock, flags); } /* * Map ring pages to user space. */ -static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +static vm_fault_t mon_bin_vma_fault(struct vm_fault *vmf) { - struct mon_reader_bin *rp = vma->vm_private_data; + struct mon_reader_bin *rp = vmf->vma->vm_private_data; unsigned long offset, chunk_idx; struct page *pageptr; + unsigned long flags; + spin_lock_irqsave(&rp->b_lock, flags); offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= rp->b_size) + if (offset >= rp->b_size) { + spin_unlock_irqrestore(&rp->b_lock, flags); return VM_FAULT_SIGBUS; + } chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); vmf->page = pageptr; + spin_unlock_irqrestore(&rp->b_lock, flags); return 0; } @@ -1247,7 +1278,11 @@ static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) { /* don't do anything here: "fault" will set up page table entries */ vma->vm_ops = &mon_bin_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + + if (vma->vm_flags & VM_WRITE) + return -EPERM; + + vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_MAYWRITE); vma->vm_private_data = filp->private_data; mon_bin_vma_open(vma); return 0; @@ -1256,7 +1291,6 @@ static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) static const struct file_operations mon_fops_binary = { .owner = THIS_MODULE, .open = mon_bin_open, - .llseek = no_llseek, .read = mon_bin_read, /* .write = mon_text_write, */ .poll = mon_bin_poll, @@ -1335,7 +1369,7 @@ int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus) if (minor >= MON_BIN_MAX_MINOR) return 0; - dev = device_create(mon_bin_class, ubus ? ubus->controller : NULL, + dev = device_create(&mon_bin_class, ubus ? ubus->controller : NULL, MKDEV(MAJOR(mon_bin_dev0), minor), NULL, "usbmon%d", minor); if (IS_ERR(dev)) @@ -1347,18 +1381,16 @@ int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus) void mon_bin_del(struct mon_bus *mbus) { - device_destroy(mon_bin_class, mbus->classdev->devt); + device_destroy(&mon_bin_class, mbus->classdev->devt); } int __init mon_bin_init(void) { int rc; - mon_bin_class = class_create(THIS_MODULE, "usbmon"); - if (IS_ERR(mon_bin_class)) { - rc = PTR_ERR(mon_bin_class); + rc = class_register(&mon_bin_class); + if (rc) goto err_class; - } rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon"); if (rc < 0) @@ -1376,7 +1408,7 @@ int __init mon_bin_init(void) err_add: unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); err_dev: - class_destroy(mon_bin_class); + class_unregister(&mon_bin_class); err_class: return rc; } @@ -1385,5 +1417,5 @@ void mon_bin_exit(void) { cdev_del(&mon_bin_cdev); unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); - class_destroy(mon_bin_class); + class_unregister(&mon_bin_class); } diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 10405119985c..af852d53aac6 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * The USB Monitor, inspired by Dave Harding's USBMon. * @@ -80,15 +81,12 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r) static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) { unsigned long flags; - struct list_head *pos; struct mon_reader *r; spin_lock_irqsave(&mbus->lock, flags); mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); + list_for_each_entry(r, &mbus->r_list, r_link) r->rnf_submit(r->r_data, urb); - } spin_unlock_irqrestore(&mbus->lock, flags); } @@ -96,7 +94,8 @@ static void mon_submit(struct usb_bus *ubus, struct urb *urb) { struct mon_bus *mbus; - if ((mbus = ubus->mon_bus) != NULL) + mbus = ubus->mon_bus; + if (mbus != NULL) mon_bus_submit(mbus, urb); mon_bus_submit(&mon_bus0, urb); } @@ -106,15 +105,12 @@ static void mon_submit(struct usb_bus *ubus, struct urb *urb) static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error) { unsigned long flags; - struct list_head *pos; struct mon_reader *r; spin_lock_irqsave(&mbus->lock, flags); mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); + list_for_each_entry(r, &mbus->r_list, r_link) r->rnf_error(r->r_data, urb, error); - } spin_unlock_irqrestore(&mbus->lock, flags); } @@ -122,7 +118,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) { struct mon_bus *mbus; - if ((mbus = ubus->mon_bus) != NULL) + mbus = ubus->mon_bus; + if (mbus != NULL) mon_bus_submit_error(mbus, urb, error); mon_bus_submit_error(&mon_bus0, urb, error); } @@ -132,15 +129,12 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, int status) { unsigned long flags; - struct list_head *pos; struct mon_reader *r; spin_lock_irqsave(&mbus->lock, flags); mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); + list_for_each_entry(r, &mbus->r_list, r_link) r->rnf_complete(r->r_data, urb, status); - } spin_unlock_irqrestore(&mbus->lock, flags); } @@ -148,7 +142,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; - if ((mbus = ubus->mon_bus) != NULL) + mbus = ubus->mon_bus; + if (mbus != NULL) mon_bus_complete(mbus, urb, status); mon_bus_complete(&mon_bus0, urb, status); } @@ -161,11 +156,9 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) static void mon_stop(struct mon_bus *mbus) { struct usb_bus *ubus; - struct list_head *p; if (mbus == &mon_bus0) { - list_for_each (p, &mon_buses) { - mbus = list_entry(p, struct mon_bus, bus_link); + list_for_each_entry(mbus, &mon_buses, bus_link) { /* * We do not change nreaders here, so rely on mon_lock. */ @@ -238,7 +231,7 @@ static struct notifier_block mon_nb = { /* * Ops */ -static struct usb_mon_operations mon_ops_0 = { +static const struct usb_mon_operations mon_ops_0 = { .urb_submit = mon_submit, .urb_submit_error = mon_submit_error, .urb_complete = mon_complete, @@ -280,7 +273,8 @@ static void mon_bus_init(struct usb_bus *ubus) { struct mon_bus *mbus; - if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) + mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL); + if (mbus == NULL) goto err_alloc; kref_init(&mbus->ref); spin_lock_init(&mbus->lock); @@ -327,14 +321,12 @@ static void mon_bus0_init(void) */ struct mon_bus *mon_bus_lookup(unsigned int num) { - struct list_head *p; struct mon_bus *mbus; if (num == 0) { return &mon_bus0; } - list_for_each (p, &mon_buses) { - mbus = list_entry(p, struct mon_bus, bus_link); + list_for_each_entry(mbus, &mon_buses, bus_link) { if (mbus->u_bus->busnum == num) { return mbus; } @@ -345,7 +337,7 @@ struct mon_bus *mon_bus_lookup(unsigned int num) static int __init mon_init(void) { struct usb_bus *ubus; - int rc; + int rc, id; if ((rc = mon_text_init()) != 0) goto err_text; @@ -361,12 +353,11 @@ static int __init mon_init(void) } // MOD_INC_USE_COUNT(which_module?); - mutex_lock(&usb_bus_list_lock); - list_for_each_entry (ubus, &usb_bus_list, bus_list) { + mutex_lock(&usb_bus_idr_lock); + idr_for_each_entry(&usb_bus_idr, ubus, id) mon_bus_init(ubus); - } usb_register_notify(&mon_nb); - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); return 0; err_reg: @@ -406,7 +397,7 @@ static void __exit mon_exit(void) printk(KERN_ERR TAG ": Outstanding opens (%d) on usb%d, leaking...\n", mbus->nreaders, mbus->u_bus->busnum); - atomic_set(&mbus->ref.refcount, 2); /* Force leak */ + kref_get(&mbus->ref); /* Force leak */ } mon_dissolve(mbus, mbus->u_bus); @@ -428,4 +419,5 @@ static void __exit mon_exit(void) module_init(mon_init); module_exit(mon_exit); +MODULE_DESCRIPTION("USB Monitor"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index ebd6189a5014..398e02af6a2b 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * The USB Monitor, inspired by Dave Harding's USBMon. * @@ -12,7 +13,7 @@ #include <linux/export.h> #include <linux/usb.h> #include <linux/fs.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "usb_mon.h" @@ -28,14 +29,15 @@ static int mon_stat_open(struct inode *inode, struct file *file) struct mon_bus *mbus; struct snap *sp; - if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL) + sp = kmalloc(sizeof(struct snap), GFP_KERNEL); + if (sp == NULL) return -ENOMEM; mbus = inode->i_private; - sp->slen = snprintf(sp->str, STAT_BUF_SIZE, - "nreaders %d events %u text_lost %u\n", - mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost); + sp->slen = scnprintf(sp->str, STAT_BUF_SIZE, + "nreaders %d events %u text_lost %u\n", + mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost); file->private_data = sp; return 0; @@ -60,7 +62,6 @@ static int mon_stat_release(struct inode *inode, struct file *file) const struct file_operations mon_fops_stat = { .owner = THIS_MODULE, .open = mon_stat_open, - .llseek = no_llseek, .read = mon_stat_read, /* .write = mon_stat_write, */ /* .poll = mon_stat_poll, */ diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index ad408251d955..68b9b2b41189 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * The USB Monitor, inspired by Dave Harding's USBMon. * @@ -8,12 +9,14 @@ #include <linux/list.h> #include <linux/usb.h> #include <linux/slab.h> +#include <linux/sched/signal.h> #include <linux/time.h> +#include <linux/ktime.h> #include <linux/export.h> #include <linux/mutex.h> #include <linux/debugfs.h> #include <linux/scatterlist.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "usb_mon.h" @@ -82,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; @@ -176,12 +181,12 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, static inline unsigned int mon_get_timestamp(void) { - struct timeval tval; + struct timespec64 now; unsigned int stamp; - do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */ - stamp = stamp * 1000000 + tval.tv_usec; + ktime_get_ts64(&now); + stamp = now.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */ + stamp = stamp * USEC_PER_SEC + now.tv_nsec / NSEC_PER_USEC; return stamp; } @@ -347,7 +352,7 @@ static int mon_text_open(struct inode *inode, struct file *file) rp->r.rnf_error = mon_text_error; rp->r.rnf_complete = mon_text_complete; - snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); + scnprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); rp->e_slab = kmem_cache_create(rp->slab_name, sizeof(struct mon_event_text), sizeof(long), 0, mon_text_ctor); @@ -373,73 +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; - if (IS_ERR(ep = mon_text_read_wait(rp, file))) - 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 += scnprintf(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; - if (IS_ERR(ep = mon_text_read_wait(rp, file))) - 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 += scnprintf(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, @@ -485,7 +520,7 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, utype, udir, ep->devnum, ep->epnum); @@ -503,7 +538,7 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, utype, udir, ep->busnum, ep->devnum, ep->epnum); @@ -514,7 +549,7 @@ static void mon_text_read_statset(struct mon_reader_text *rp, { if (ep->setup_flag == 0) { /* Setup packet is present and captured */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " s %02x %02x %04x %04x %04x", ep->setup[0], ep->setup[1], @@ -522,10 +557,10 @@ static void mon_text_read_statset(struct mon_reader_text *rp, (ep->setup[5] << 8) | ep->setup[4], (ep->setup[7] << 8) | ep->setup[6]); } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %c __ __ ____ ____ ____", ep->setup_flag); } else { /* No setup for this kind of URB */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %d", ep->status); } } @@ -533,7 +568,7 @@ static void mon_text_read_statset(struct mon_reader_text *rp, static void mon_text_read_intstat(struct mon_reader_text *rp, struct mon_text_ptr *p, const struct mon_event_text *ep) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %d:%d", ep->status, ep->interval); } @@ -541,10 +576,10 @@ static void mon_text_read_isostat(struct mon_reader_text *rp, struct mon_text_ptr *p, const struct mon_event_text *ep) { if (ep->type == 'S') { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %d:%d:%d", ep->status, ep->interval, ep->start_frame); } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %d:%d:%d:%d", ep->status, ep->interval, ep->start_frame, ep->error_count); } @@ -557,7 +592,7 @@ static void mon_text_read_isodesc(struct mon_reader_text *rp, int i; const struct mon_iso_desc *dp; - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %d", ep->numdesc); ndesc = ep->numdesc; if (ndesc > ISODESC_MAX) @@ -566,7 +601,7 @@ static void mon_text_read_isodesc(struct mon_reader_text *rp, ndesc = 0; dp = ep->isodesc; for (i = 0; i < ndesc; i++) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %d:%u:%u", dp->status, dp->offset, dp->length); dp++; } @@ -579,28 +614,28 @@ static void mon_text_read_data(struct mon_reader_text *rp, if ((data_len = ep->length) > 0) { if (ep->data_flag == 0) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " ="); if (data_len >= DATA_MAX) data_len = DATA_MAX; for (i = 0; i < data_len; i++) { if (i % 4 == 0) { - p->cnt += snprintf(p->pbuf + p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " "); } - p->cnt += snprintf(p->pbuf + p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%02x", ep->data[i]); } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n"); } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, " %c\n", ep->data_flag); } } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n"); + p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n"); } } @@ -650,7 +685,6 @@ static int mon_text_release(struct inode *inode, struct file *file) static const struct file_operations mon_fops_text_t = { .owner = THIS_MODULE, .open = mon_text_open, - .llseek = no_llseek, .read = mon_text_read_t, .release = mon_text_release, }; @@ -658,71 +692,40 @@ static const struct file_operations mon_fops_text_t = { static const struct file_operations mon_fops_text_u = { .owner = THIS_MODULE, .open = mon_text_open, - .llseek = no_llseek, .read = mon_text_read_u, .release = mon_text_release, }; int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) { - struct dentry *d; - enum { NAMESZ = 10 }; + enum { NAMESZ = 12 }; char name[NAMESZ]; int busnum = ubus? ubus->busnum: 0; - int rc; if (mon_dir == NULL) return 0; if (ubus != NULL) { - rc = snprintf(name, NAMESZ, "%dt", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_t; - d = debugfs_create_file(name, 0600, mon_dir, mbus, + scnprintf(name, NAMESZ, "%dt", busnum); + mbus->dent_t = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t); - if (d == NULL) - goto err_create_t; - mbus->dent_t = d; } - rc = snprintf(name, NAMESZ, "%du", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_u; - d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u); - if (d == NULL) - goto err_create_u; - mbus->dent_u = d; - - rc = snprintf(name, NAMESZ, "%ds", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_s; - d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); - if (d == NULL) - goto err_create_s; - mbus->dent_s = d; + scnprintf(name, NAMESZ, "%du", busnum); + mbus->dent_u = debugfs_create_file(name, 0600, mon_dir, mbus, + &mon_fops_text_u); - return 1; + scnprintf(name, NAMESZ, "%ds", busnum); + mbus->dent_s = debugfs_create_file(name, 0600, mon_dir, mbus, + &mon_fops_stat); -err_create_s: -err_print_s: - debugfs_remove(mbus->dent_u); - mbus->dent_u = NULL; -err_create_u: -err_print_u: - if (ubus != NULL) { - debugfs_remove(mbus->dent_t); - mbus->dent_t = NULL; - } -err_create_t: -err_print_t: - return 0; + return 1; } void mon_text_del(struct mon_bus *mbus) { debugfs_remove(mbus->dent_u); - if (mbus->dent_t != NULL) - debugfs_remove(mbus->dent_t); + debugfs_remove(mbus->dent_t); debugfs_remove(mbus->dent_s); } @@ -740,18 +743,7 @@ static void mon_text_ctor(void *mem) int __init mon_text_init(void) { - struct dentry *mondir; - - mondir = debugfs_create_dir("usbmon", usb_debug_root); - if (IS_ERR(mondir)) { - /* debugfs not available, but we can use usbmon without it */ - return 0; - } - if (mondir == NULL) { - printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); - return -ENOMEM; - } - mon_dir = mondir; + mon_dir = debugfs_create_dir("usbmon", usb_debug_root); return 0; } diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index df9a4df342c7..aa64efaba366 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * The USB Monitor, inspired by Dave Harding's USBMon. * |
