@@ -422,6 +422,8 @@ static int config_usb_cfg_link(
struct usb_function *f;
int ret;
+ trace_usb_configfs_link_group(usb_cfg_ci, usb_func_ci);
+
mutex_lock(&gi->lock);
/*
* Make sure this function is from within our _this_ gadget and not
@@ -471,6 +473,8 @@ static void config_usb_cfg_unlink(
to_usb_function_instance(usb_func_ci);
struct usb_function *f;
+ trace_usb_configfs_unlink_group(usb_cfg_ci, usb_func_ci);
+
/*
* ideally I would like to forbid to unlink functions while a gadget is
* bound to an UDC. Since this isn't possible at the moment, we simply
@@ -893,6 +897,8 @@ static int os_desc_link(struct config_item *os_desc_ci,
struct usb_configuration *c = NULL, *iter;
int ret;
+ trace_usb_configfs_link_group(os_desc_ci, usb_cfg_ci);
+
mutex_lock(&gi->lock);
list_for_each_entry(iter, &cdev->configs, list) {
if (iter != &c_target->c)
@@ -924,6 +930,8 @@ static void os_desc_unlink(struct config_item *os_desc_ci,
struct gadget_info *gi = os_desc_item_to_gadget_info(os_desc_ci);
struct usb_composite_dev *cdev = &gi->cdev;
+ trace_usb_configfs_unlink_group(os_desc_ci, usb_cfg_ci);
+
mutex_lock(&gi->lock);
if (gi->composite.gadget_driver.udc_name)
unregister_gadget(gi);
@@ -598,6 +598,8 @@ static int uvcg_control_class_allow_link(struct config_item *src,
struct uvcg_control_header *target_hdr;
int ret = -EINVAL;
+ trace_usb_configfs_link_group(src, target);
+
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
control = src->ci_parent->ci_parent;
@@ -639,6 +641,8 @@ static void uvcg_control_class_drop_link(struct config_item *src,
struct uvc_descriptor_header **class_array;
struct uvcg_control_header *target_hdr;
+ trace_usb_configfs_unlink_group(src, target);
+
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
control = src->ci_parent->ci_parent;
@@ -883,6 +887,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
struct uvcg_format_ptr *format_ptr;
int i, ret = -EINVAL;
+ trace_usb_configfs_link_group(src, target);
+
src_hdr = to_uvcg_streaming_header(src);
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
@@ -946,6 +952,8 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
struct uvcg_format *target_fmt = NULL;
struct uvcg_format_ptr *format_ptr, *tmp;
+ trace_usb_configfs_unlink_group(src, target);
+
src_hdr = to_uvcg_streaming_header(src);
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
@@ -2171,6 +2179,8 @@ static int uvcg_streaming_class_allow_link(struct config_item *src,
size_t size = 0, count = 0;
int ret = -EINVAL;
+ trace_usb_configfs_link_group(src, target);
+
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
streaming = src->ci_parent->ci_parent;
@@ -2242,6 +2252,8 @@ static void uvcg_streaming_class_drop_link(struct config_item *src,
struct uvc_descriptor_header ***class_array;
struct uvcg_streaming_header *target_hdr;
+ trace_usb_configfs_unlink_group(src, target);
+
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
streaming = src->ci_parent->ci_parent;
@@ -88,4 +88,50 @@ void trace_usb_configfs_drop_group(struct config_item *parent,
trace_usb_configfs_make_drop_group(parent, item, "rmdir");
}
EXPORT_SYMBOL(trace_usb_configfs_drop_group);
+
+static void trace_usb_configfs_link_unlink_group(struct config_item *dest,
+ struct config_item *src, char *link_unlink)
+{
+ char *group, *dest_group, *src_group;
+ int ret;
+
+ group = kzalloc(4 * GROUP_LEN, GFP_KERNEL);
+ if (!group)
+ return;
+
+ dest_group = group + 2 * GROUP_LEN;
+ ret = gadget_configfs_group(dest_group, dest);
+ if (ret) {
+ kfree(group);
+ return;
+ }
+
+ src_group = group + 3 * GROUP_LEN;
+ ret = gadget_configfs_group(src_group, src);
+ if (ret) {
+ kfree(group);
+ return;
+ }
+
+ snprintf(group, 2 * GROUP_LEN, "%s %s %s",
+ link_unlink, dest_group, src_group);
+
+ trace_gadget_configfs(group);
+
+ kfree(group);
+}
+
+void trace_usb_configfs_link_group(struct config_item *dest,
+ struct config_item *src)
+{
+ trace_usb_configfs_link_unlink_group(dest, src, "link");
+}
+EXPORT_SYMBOL(trace_usb_configfs_link_group);
+
+void trace_usb_configfs_unlink_group(struct config_item *dest,
+ struct config_item *src)
+{
+ trace_usb_configfs_link_unlink_group(dest, src, "unlink");
+}
+EXPORT_SYMBOL(trace_usb_configfs_unlink_group);
#endif
@@ -608,9 +608,15 @@ void trace_usb_configfs_make_group(struct config_item *parent,
struct config_item *item);
void trace_usb_configfs_drop_group(struct config_item *parent,
struct config_item *item);
+void trace_usb_configfs_link_group(struct config_item *dest,
+ struct config_item *src);
+void trace_usb_configfs_unlink_group(struct config_item *dest,
+ struct config_item *src);
#else
#define trace_usb_configfs_make_group(parent, item) do {} while(0)
#define trace_usb_configfs_drop_group(parent, item) do {} while(0)
+#define trace_usb_configfs_link_group(dest, src) do {} while(0)
+#define trace_usb_configfs_unlink_group(dest, src) do {} while(0)
#endif
struct usb_configuration *usb_get_config(struct usb_composite_dev *cdev,
Add API trace_usb_configfs_link_group() and trace_usb_configfs_unlink_group() to trace user link/unlink a group like add function to configuration or remove function from configuration. If a specific function need link/unlink, it also can be used. Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com> --- v2: no change v3: add API in trace.c v4: fix memory leak drivers/usb/gadget/configfs.c | 8 ++++++ drivers/usb/gadget/function/uvc_configfs.c | 12 ++++++++ drivers/usb/gadget/trace.c | 46 ++++++++++++++++++++++++++++++ include/linux/usb/composite.h | 6 ++++ 4 files changed, 72 insertions(+)