The Usbmon: USB Monitoring Framework: Pete Zaitcev Red Hat, Inc
The Usbmon: USB Monitoring Framework: Pete Zaitcev Red Hat, Inc
Pete Zaitcev
Red Hat, Inc.
zaitcev@redhat.com
Abstract
Origins
Limitations of the this approach became pronounced as more users running preconfigured
kernels appeared. For a developer, it is often
undesirable to make users to rebuild their kernels with CONFIG_USB_STORAGE_DEBUG
enabled. These difficulties could be overcome
by making tracing configurable at runtime, by
a module parameter. Nonetheless, this style of
tracing is still not ideal, for several reasons.
Output to the system console and/or log file
is lossy when a large amount of data is piped
through though the syslog subsystem. Timing variations introduced by formatted printouts skew results, which makes it harder to pinpoint problems when peripherals require delays
in the access pattern. And finally, printk()
calls have to be added all the time to capture
what is important. Often it seems as if the one
key printk() is missing, but once added, it
Introduction
Driver, or HCD. When I/O is done, HCD invokes a specified callback to notify the core and
the requesting driver. The usbmon hooks reside
in the core of USB stack, in the submission and
callback paths. Thus, usbmon relies on HCD to
function properly and is only marginally useful
in debugging of HCDs. Such an arrangement
is accepted for two reasons. First, it allows usbmon to be unobtrusive and significantly less
buggy itself. Second, the vast majority of bugs
occur outside of HCDs, in in upper level drivers
or peripherals.
Architecture
Instead of forcing a choice between text and binary interfaces, usbmon adopts a neutral solution. Its data structures are set up to facilitate
several distinct types of consumers of events
(called "readers"). Various reader classes can
provide text and binary interfaces. At this time,
only text-based interface class is implemented.
Every instance of a reader has its own circular
buffer. When hooks are called, they broadcast
events to readers. Readers replicate events into
all buffers which are active for a given bus. To
be sure, this entails an extra overhead of data
copying. However, the complication of having all aliasing properly tracked and resolved
turned out to be insurmountable in the time
frame desired, and the performance impact was
found manageable.
At the lower level, a couple of interesting decisions were made regarding the placement of
hooks and the formatting of events when presented to user programs.
An I/O request in the USB stack is represented
by so-called "URB". A peripheral-specific
driver, such as usb-storage, initializes and submits URB with a call to the USB stack core.
The core dispatches URB to a Host Controller
2
struct mon_bus {
struct list_head bus_link;
spinlock_t lock;
struct dentry dent_s;
/
struct dentry dent_t;
/
struct usb_bus u_bus;
/ Ref /
int nreaders;
/
struct list_head r_list;
/
struct kref ref;
/
/ Stats /
unsigned int cnt_text_lost;
};
Debugging file /
Text interface file /
struct mon_reader {
/ An instance of a process which opened a file /
struct list_head r_link;
struct mon_bus m_bus;
void r_data;
void (rnf_submit)(void data, struct urb urb);
void (rnf_complete)(void data, struct urb urb);
};
Implementation
source OS. In present, when usbmon is not running, it adds 8 bytes of memory use per bus
(on a 32-bit system) and an additional if()
statement in submit and callback paths. This
was deemed an acceptable price for the lack of
tracking.
The usbmon is implemented as a Linux kernel module, which can be loaded and unloaded
at will. This arrangement is not intrinsic to
the design; it is intended to serve as a convenience to developers only. Hooks and additional data fields remain built into the USB
stack core at all times as long as usbmon is
configured on. In a proprietary OS, usbmon
would have to be implemented in a different
way. It is entirely possible to make the usbmon an add-on that stacks on top of HCDs by
manipulating existing function pointers. Such
an implementation would make usbmon effectively non-existing when not actively monitoring. However, this approach introduces a significant complexity of tracking of active URBs
which had their function pointers replaced, and
brings only a marginal advantage for an open-
The key data structure that keeps usbmon together is struct mon_bus (See Figure 1).
One of them is allocated for every USB bus
present. It holds a list of readers attached to
the bus, pointer to the corresponding bus structure, statistic counters, reference count, and a
spinlock. The manner in which circular buffers
are arranged is encapsulated entirely within a
reader.
The locking model is straightforward. All
hooks execute with the bus spinlock taken, so
readers do not do any extra locking. The only
time instances of struct mon_bus may in3
Interfaces
This format is terse, but it can be read by humans in a pinch. It is also useful for postings to
mailing lists, Bugzilla attachments, and other
similar forms of data exchange.
Tools to ease dealing with usbmon are being
developed. Only one such tool exists today:
the USBMon (written with upper case letters),
originally written by David Harding. It is a tool
with a graphical interface.
Lessons
struct usb_mon_operations {
void (urb_submit)(struct usb_bus bus, struct urb urb);
void (urb_submit_error)(struct usb_bus bus, struct urb urb, int err);
void (urb_complete)(struct usb_bus bus, struct urb urb);
void (bus_add)(struct usb_bus bus);
void (bus_remove)(struct usb_bus bus);
};
extern struct usb_mon_operations mon_ops;
static inline void usbmon_urb_submit(struct usb_bus bus, struct urb urb)
{
if (busmonitored)
(mon_opsurb_submit)(bus, urb);
}
static inline void usbmon_notify_bus_remove(struct usb_bus bus)
{
if (mon_ops)
(mon_opsbus_remove)(bus);
}
int usb_mon_register(struct usb_mon_operations ops);
void usb_mon_deregister(void);
log messages. Having any sort of usable unified tracing is helpful when developers have to
work with an explicitly programmed message
passing bus.
Future Work
References
Van Jacobson et al. tcpdump(8), the manual.
In tcpdump version 3.8.2, 2004.
Greg Kroah-Hartman. kobjects and krefs. In
Proceedings of the Linux Symposium (former
OLS) 2004.