--- /dev/null
+From e0ccdef92653f8867e2d1667facfd3c23699f540 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Fri, 23 Aug 2019 12:38:07 +0200
+Subject: ALSA: usb-audio: Clean up check_input_term()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit e0ccdef92653f8867e2d1667facfd3c23699f540 upstream.
+
+The primary changes in this patch are cleanups of __check_input_term()
+and move to a non-nested switch-case block by evaluating the pair of
+UAC version and the unit type, as we've done for parse_audio_unit().
+Also each parser is split into the function for readability.
+
+Now, a slight behavior change by this cleanup is the handling of
+processing and extension units. Formerly we've dealt with them
+differently between UAC1/2 and UAC3; the latter returns an error if no
+input sources are available, while the former continues to parse.
+
+In this patch, unify the behavior in all cases: when input sources are
+available, it parses recursively, then override the type and the id,
+as well as channel information if not provided yet.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c | 407 ++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 212 insertions(+), 195 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -773,224 +773,242 @@ static int uac_mixer_unit_get_channels(s
+ }
+
+ /*
+- * parse the source unit recursively until it reaches to a terminal
+- * or a branched unit.
++ * Parse Input Terminal Unit
+ */
+ static int __check_input_term(struct mixer_build *state, int id,
+- struct usb_audio_term *term)
++ struct usb_audio_term *term);
++
++static int parse_term_uac1_iterm_unit(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
++{
++ struct uac_input_terminal_descriptor *d = p1;
++
++ term->type = le16_to_cpu(d->wTerminalType);
++ term->channels = d->bNrChannels;
++ term->chconfig = le16_to_cpu(d->wChannelConfig);
++ term->name = d->iTerminal;
++ return 0;
++}
++
++static int parse_term_uac2_iterm_unit(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
+ {
+- int protocol = state->mixer->protocol;
++ struct uac2_input_terminal_descriptor *d = p1;
+ int err;
+- void *p1;
+- unsigned char *hdr;
+
+- memset(term, 0, sizeof(*term));
+- for (;;) {
+- /* a loop in the terminal chain? */
+- if (test_and_set_bit(id, state->termbitmap))
+- return -EINVAL;
++ /* call recursively to verify the referenced clock entity */
++ err = __check_input_term(state, d->bCSourceID, term);
++ if (err < 0)
++ return err;
+
+- p1 = find_audio_control_unit(state, id);
+- if (!p1)
+- break;
+- if (!snd_usb_validate_audio_desc(p1, protocol))
+- break; /* bad descriptor */
++ /* save input term properties after recursion,
++ * to ensure they are not overriden by the recursion calls
++ */
++ term->id = id;
++ term->type = le16_to_cpu(d->wTerminalType);
++ term->channels = d->bNrChannels;
++ term->chconfig = le32_to_cpu(d->bmChannelConfig);
++ term->name = d->iTerminal;
++ return 0;
++}
+
+- hdr = p1;
+- term->id = id;
++static int parse_term_uac3_iterm_unit(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
++{
++ struct uac3_input_terminal_descriptor *d = p1;
++ int err;
+
+- if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
+- switch (hdr[2]) {
+- case UAC_INPUT_TERMINAL:
+- if (protocol == UAC_VERSION_1) {
+- struct uac_input_terminal_descriptor *d = p1;
+-
+- term->type = le16_to_cpu(d->wTerminalType);
+- term->channels = d->bNrChannels;
+- term->chconfig = le16_to_cpu(d->wChannelConfig);
+- term->name = d->iTerminal;
+- } else { /* UAC_VERSION_2 */
+- struct uac2_input_terminal_descriptor *d = p1;
+-
+- /* call recursively to verify that the
+- * referenced clock entity is valid */
+- err = __check_input_term(state, d->bCSourceID, term);
+- if (err < 0)
+- return err;
+-
+- /* save input term properties after recursion,
+- * to ensure they are not overriden by the
+- * recursion calls */
+- term->id = id;
+- term->type = le16_to_cpu(d->wTerminalType);
+- term->channels = d->bNrChannels;
+- term->chconfig = le32_to_cpu(d->bmChannelConfig);
+- term->name = d->iTerminal;
+- }
+- return 0;
+- case UAC_FEATURE_UNIT: {
+- /* the header is the same for v1 and v2 */
+- struct uac_feature_unit_descriptor *d = p1;
++ /* call recursively to verify the referenced clock entity */
++ err = __check_input_term(state, d->bCSourceID, term);
++ if (err < 0)
++ return err;
+
+- id = d->bSourceID;
+- break; /* continue to parse */
+- }
+- case UAC_MIXER_UNIT: {
+- struct uac_mixer_unit_descriptor *d = p1;
++ /* save input term properties after recursion,
++ * to ensure they are not overriden by the recursion calls
++ */
++ term->id = id;
++ term->type = le16_to_cpu(d->wTerminalType);
+
+- term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
+- term->channels = uac_mixer_unit_bNrChannels(d);
+- term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol);
+- term->name = uac_mixer_unit_iMixer(d);
+- return 0;
+- }
+- case UAC_SELECTOR_UNIT:
+- case UAC2_CLOCK_SELECTOR: {
+- struct uac_selector_unit_descriptor *d = p1;
+- /* call recursively to retrieve the channel info */
+- err = __check_input_term(state, d->baSourceID[0], term);
+- if (err < 0)
+- return err;
+- term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
+- term->id = id;
+- term->name = uac_selector_unit_iSelector(d);
+- return 0;
+- }
+- case UAC1_PROCESSING_UNIT:
+- /* UAC2_EFFECT_UNIT */
+- if (protocol == UAC_VERSION_1)
+- term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
+- else /* UAC_VERSION_2 */
+- term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */
+- /* fall through */
+- case UAC1_EXTENSION_UNIT:
+- /* UAC2_PROCESSING_UNIT_V2 */
+- if (protocol == UAC_VERSION_1 && !term->type)
+- term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */
+- else if (protocol == UAC_VERSION_2 && !term->type)
+- term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
+- /* fall through */
+- case UAC2_EXTENSION_UNIT_V2: {
+- struct uac_processing_unit_descriptor *d = p1;
+-
+- if (protocol == UAC_VERSION_2 &&
+- hdr[2] == UAC2_EFFECT_UNIT) {
+- /* UAC2/UAC1 unit IDs overlap here in an
+- * uncompatible way. Ignore this unit for now.
+- */
+- return 0;
+- }
++ err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID));
++ if (err < 0)
++ return err;
++ term->channels = err;
+
+- if (d->bNrInPins) {
+- id = d->baSourceID[0];
+- break; /* continue to parse */
+- }
+- if (!term->type)
+- term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */
++ /* REVISIT: UAC3 IT doesn't have channels cfg */
++ term->chconfig = 0;
+
+- term->channels = uac_processing_unit_bNrChannels(d);
+- term->chconfig = uac_processing_unit_wChannelConfig(d, protocol);
+- term->name = uac_processing_unit_iProcessing(d, protocol);
+- return 0;
+- }
+- case UAC2_CLOCK_SOURCE: {
+- struct uac_clock_source_descriptor *d = p1;
++ term->name = le16_to_cpu(d->wTerminalDescrStr);
++ return 0;
++}
+
+- term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
+- term->id = id;
+- term->name = d->iClockSource;
+- return 0;
+- }
+- default:
+- return -ENODEV;
+- }
+- } else { /* UAC_VERSION_3 */
+- switch (hdr[2]) {
+- case UAC_INPUT_TERMINAL: {
+- struct uac3_input_terminal_descriptor *d = p1;
+-
+- /* call recursively to verify that the
+- * referenced clock entity is valid */
+- err = __check_input_term(state, d->bCSourceID, term);
+- if (err < 0)
+- return err;
+-
+- /* save input term properties after recursion,
+- * to ensure they are not overriden by the
+- * recursion calls */
+- term->id = id;
+- term->type = le16_to_cpu(d->wTerminalType);
+-
+- err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID));
+- if (err < 0)
+- return err;
+- term->channels = err;
++static int parse_term_mixer_unit(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
++{
++ struct uac_mixer_unit_descriptor *d = p1;
++ int protocol = state->mixer->protocol;
++ int err;
+
+- /* REVISIT: UAC3 IT doesn't have channels cfg */
+- term->chconfig = 0;
++ err = uac_mixer_unit_get_channels(state, d);
++ if (err <= 0)
++ return err;
+
+- term->name = le16_to_cpu(d->wTerminalDescrStr);
+- return 0;
+- }
+- case UAC3_FEATURE_UNIT: {
+- struct uac3_feature_unit_descriptor *d = p1;
++ term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
++ term->channels = err;
++ if (protocol != UAC_VERSION_3) {
++ term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol);
++ term->name = uac_mixer_unit_iMixer(d);
++ }
++ return 0;
++}
+
+- id = d->bSourceID;
+- break; /* continue to parse */
+- }
+- case UAC3_CLOCK_SOURCE: {
+- struct uac3_clock_source_descriptor *d = p1;
++static int parse_term_selector_unit(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
++{
++ struct uac_selector_unit_descriptor *d = p1;
++ int err;
+
+- term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
+- term->id = id;
+- term->name = le16_to_cpu(d->wClockSourceStr);
+- return 0;
+- }
+- case UAC3_MIXER_UNIT: {
+- struct uac_mixer_unit_descriptor *d = p1;
++ /* call recursively to retrieve the channel info */
++ err = __check_input_term(state, d->baSourceID[0], term);
++ if (err < 0)
++ return err;
++ term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
++ term->id = id;
++ if (state->mixer->protocol != UAC_VERSION_3)
++ term->name = uac_selector_unit_iSelector(d);
++ return 0;
++}
+
+- err = uac_mixer_unit_get_channels(state, d);
+- if (err <= 0)
+- return err;
++static int parse_term_proc_unit(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id, int vtype)
++{
++ struct uac_processing_unit_descriptor *d = p1;
++ int protocol = state->mixer->protocol;
++ int err;
+
+- term->channels = err;
+- term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
++ if (d->bNrInPins) {
++ /* call recursively to retrieve the channel info */
++ err = __check_input_term(state, d->baSourceID[0], term);
++ if (err < 0)
++ return err;
++ }
+
+- return 0;
+- }
+- case UAC3_SELECTOR_UNIT:
+- case UAC3_CLOCK_SELECTOR: {
+- struct uac_selector_unit_descriptor *d = p1;
+- /* call recursively to retrieve the channel info */
+- err = __check_input_term(state, d->baSourceID[0], term);
+- if (err < 0)
+- return err;
+- term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
+- term->id = id;
+- term->name = 0; /* TODO: UAC3 Class-specific strings */
++ term->type = vtype << 16; /* virtual type */
++ term->id = id;
+
+- return 0;
+- }
+- case UAC3_PROCESSING_UNIT: {
+- struct uac_processing_unit_descriptor *d = p1;
++ if (protocol == UAC_VERSION_3)
++ return 0;
+
+- if (!d->bNrInPins)
+- return -EINVAL;
++ if (!term->channels) {
++ term->channels = uac_processing_unit_bNrChannels(d);
++ term->chconfig = uac_processing_unit_wChannelConfig(d, protocol);
++ }
++ term->name = uac_processing_unit_iProcessing(d, protocol);
++ return 0;
++}
++
++static int parse_term_uac2_clock_source(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
++{
++ struct uac_clock_source_descriptor *d = p1;
++
++ term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
++ term->id = id;
++ term->name = d->iClockSource;
++ return 0;
++}
+
+- /* call recursively to retrieve the channel info */
+- err = __check_input_term(state, d->baSourceID[0], term);
+- if (err < 0)
+- return err;
+-
+- term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
+- term->id = id;
+- term->name = 0; /* TODO: UAC3 Class-specific strings */
++static int parse_term_uac3_clock_source(struct mixer_build *state,
++ struct usb_audio_term *term,
++ void *p1, int id)
++{
++ struct uac3_clock_source_descriptor *d = p1;
++
++ term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
++ term->id = id;
++ term->name = le16_to_cpu(d->wClockSourceStr);
++ return 0;
++}
+
+- return 0;
+- }
+- default:
+- return -ENODEV;
+- }
++#define PTYPE(a, b) ((a) << 8 | (b))
++
++/*
++ * parse the source unit recursively until it reaches to a terminal
++ * or a branched unit.
++ */
++static int __check_input_term(struct mixer_build *state, int id,
++ struct usb_audio_term *term)
++{
++ int protocol = state->mixer->protocol;
++ void *p1;
++ unsigned char *hdr;
++
++ for (;;) {
++ /* a loop in the terminal chain? */
++ if (test_and_set_bit(id, state->termbitmap))
++ return -EINVAL;
++
++ p1 = find_audio_control_unit(state, id);
++ if (!p1)
++ break;
++ if (!snd_usb_validate_audio_desc(p1, protocol))
++ break; /* bad descriptor */
++
++ hdr = p1;
++ term->id = id;
++
++ switch (PTYPE(protocol, hdr[2])) {
++ case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): {
++ /* the header is the same for all versions */
++ struct uac_feature_unit_descriptor *d = p1;
++
++ id = d->bSourceID;
++ break; /* continue to parse */
++ }
++ case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL):
++ return parse_term_uac1_iterm_unit(state, term, p1, id);
++ case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL):
++ return parse_term_uac2_iterm_unit(state, term, p1, id);
++ case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL):
++ return parse_term_uac3_iterm_unit(state, term, p1, id);
++ case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT):
++ return parse_term_mixer_unit(state, term, p1, id);
++ case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR):
++ case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR):
++ return parse_term_selector_unit(state, term, p1, id);
++ case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2):
++ case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT):
++ return parse_term_proc_unit(state, term, p1, id,
++ UAC3_PROCESSING_UNIT);
++ case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT):
++ return parse_term_proc_unit(state, term, p1, id,
++ UAC3_EFFECT_UNIT);
++ case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2):
++ case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT):
++ return parse_term_proc_unit(state, term, p1, id,
++ UAC3_EXTENSION_UNIT);
++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE):
++ return parse_term_uac2_clock_source(state, term, p1, id);
++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE):
++ return parse_term_uac3_clock_source(state, term, p1, id);
++ default:
++ return -ENODEV;
+ }
+ }
+ return -ENODEV;
+@@ -2731,7 +2749,6 @@ static int parse_audio_unit(struct mixer
+ return 0; /* skip invalid unit */
+ }
+
+-#define PTYPE(a, b) ((a) << 8 | (b))
+ switch (PTYPE(protocol, p1[2])) {
+ case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL):
+ case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL):
--- /dev/null
+From ba8bf0967a154796be15c4983603aad0b05c3138 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 22 Oct 2019 17:45:14 +0200
+Subject: ALSA: usb-audio: Fix copy&paste error in the validator
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit ba8bf0967a154796be15c4983603aad0b05c3138 upstream.
+
+The recently introduced USB-audio descriptor validator had a stupid
+copy&paste error that may lead to an unexpected overlook of too short
+descriptors for processing and extension units. It's likely the cause
+of the report triggered by syzkaller fuzzer. Let's fix it.
+
+Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units")
+Reported-by: syzbot+0620f79a1978b1133fd7@syzkaller.appspotmail.com
+Link: https://lore.kernel.org/r/s5hsgnkdbsl.wl-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/validate.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/usb/validate.c
++++ b/sound/usb/validate.c
+@@ -75,7 +75,7 @@ static bool validate_processing_unit(con
+
+ if (d->bLength < sizeof(*d))
+ return false;
+- len = d->bLength < sizeof(*d) + d->bNrInPins;
++ len = sizeof(*d) + d->bNrInPins;
+ if (d->bLength < len)
+ return false;
+ switch (v->protocol) {
--- /dev/null
+From 60849562a5db4a1eee2160167e4dce4590d3eafe Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 26 Aug 2019 13:55:21 +0200
+Subject: ALSA: usb-audio: Fix possible NULL dereference at create_yamaha_midi_quirk()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 60849562a5db4a1eee2160167e4dce4590d3eafe upstream.
+
+The previous addition of descriptor validation may lead to a NULL
+dereference at create_yamaha_midi_quirk() when either injd or outjd is
+NULL. Add proper non-NULL checks.
+
+Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units")
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/quirks.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -259,8 +259,8 @@ static int create_yamaha_midi_quirk(stru
+ NULL, USB_MS_MIDI_OUT_JACK);
+ if (!injd && !outjd)
+ return -ENODEV;
+- if (!snd_usb_validate_midi_desc(injd) ||
+- !snd_usb_validate_midi_desc(outjd))
++ if (!(injd && snd_usb_validate_midi_desc(injd)) ||
++ !(outjd && snd_usb_validate_midi_desc(outjd)))
+ return -ENODEV;
+ if (injd && (injd->bLength < 5 ||
+ (injd->bJackType != USB_MS_EMBEDDED &&
--- /dev/null
+From 57f8770620e9b51c61089751f0b5ad3dbe376ff2 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 20 Aug 2019 17:17:09 +0200
+Subject: ALSA: usb-audio: More validations of descriptor units
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 57f8770620e9b51c61089751f0b5ad3dbe376ff2 upstream.
+
+Introduce a new helper to validate each audio descriptor unit before
+and check the unit before actually accessing it. This should harden
+against the OOB access cases with malformed descriptors that have been
+recently frequently reported by fuzzers.
+
+The existing descriptor checks are still kept although they become
+superfluous after this patch. They'll be cleaned up eventually
+later.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/Makefile | 3
+ sound/usb/helper.h | 4
+ sound/usb/mixer.c | 10 +
+ sound/usb/power.c | 2
+ sound/usb/quirks.c | 3
+ sound/usb/stream.c | 25 +--
+ sound/usb/validate.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 366 insertions(+), 13 deletions(-)
+
+--- a/sound/usb/Makefile
++++ b/sound/usb/Makefile
+@@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \
+ power.o \
+ proc.o \
+ quirks.o \
+- stream.o
++ stream.o \
++ validate.o
+
+ snd-usbmidi-lib-objs := midi.o
+
+--- a/sound/usb/helper.h
++++ b/sound/usb/helper.h
+@@ -30,4 +30,8 @@ static inline int snd_usb_ctrl_intf(stru
+ return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
+ }
+
++/* in validate.c */
++bool snd_usb_validate_audio_desc(void *p, int protocol);
++bool snd_usb_validate_midi_desc(void *p);
++
+ #endif /* __USBAUDIO_HELPER_H */
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -800,6 +800,8 @@ static int __check_input_term(struct mix
+ p1 = find_audio_control_unit(state, id);
+ if (!p1)
+ break;
++ if (!snd_usb_validate_audio_desc(p1, protocol))
++ break; /* bad descriptor */
+
+ hdr = p1;
+ term->id = id;
+@@ -2794,6 +2796,11 @@ static int parse_audio_unit(struct mixer
+ return -EINVAL;
+ }
+
++ if (!snd_usb_validate_audio_desc(p1, protocol)) {
++ usb_audio_dbg(state->chip, "invalid unit %d\n", unitid);
++ return 0; /* skip invalid unit */
++ }
++
+ if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
+ switch (p1[2]) {
+ case UAC_INPUT_TERMINAL:
+@@ -3164,6 +3171,9 @@ static int snd_usb_mixer_controls(struct
+ while ((p = snd_usb_find_csint_desc(mixer->hostif->extra,
+ mixer->hostif->extralen,
+ p, UAC_OUTPUT_TERMINAL)) != NULL) {
++ if (!snd_usb_validate_audio_desc(p, mixer->protocol))
++ continue; /* skip invalid descriptor */
++
+ if (mixer->protocol == UAC_VERSION_1) {
+ struct uac1_output_terminal_descriptor *desc = p;
+
+--- a/sound/usb/power.c
++++ b/sound/usb/power.c
+@@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_hos
+ struct uac3_power_domain_descriptor *pd_desc = p;
+ int i;
+
++ if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3))
++ continue;
+ for (i = 0; i < pd_desc->bNrEntities; i++) {
+ if (pd_desc->baEntityID[i] == id) {
+ pd->pd_id = pd_desc->bPowerDomainID;
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -259,6 +259,9 @@ static int create_yamaha_midi_quirk(stru
+ NULL, USB_MS_MIDI_OUT_JACK);
+ if (!injd && !outjd)
+ return -ENODEV;
++ if (!snd_usb_validate_midi_desc(injd) ||
++ !snd_usb_validate_midi_desc(outjd))
++ return -ENODEV;
+ if (injd && (injd->bLength < 5 ||
+ (injd->bJackType != USB_MS_EMBEDDED &&
+ injd->bJackType != USB_MS_EXTERNAL)))
+--- a/sound/usb/stream.c
++++ b/sound/usb/stream.c
+@@ -637,16 +637,14 @@ static int parse_uac_endpoint_attributes
+ */
+ static void *
+ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
+- int terminal_id, bool uac23)
++ int terminal_id, int protocol)
+ {
+ struct uac2_input_terminal_descriptor *term = NULL;
+- size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) :
+- sizeof(struct uac_input_terminal_descriptor);
+
+ while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ term, UAC_INPUT_TERMINAL))) {
+- if (term->bLength < minlen)
++ if (!snd_usb_validate_audio_desc(term, protocol))
+ continue;
+ if (term->bTerminalID == terminal_id)
+ return term;
+@@ -657,7 +655,7 @@ snd_usb_find_input_terminal_descriptor(s
+
+ static void *
+ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
+- int terminal_id)
++ int terminal_id, int protocol)
+ {
+ /* OK to use with both UAC2 and UAC3 */
+ struct uac2_output_terminal_descriptor *term = NULL;
+@@ -665,8 +663,9 @@ snd_usb_find_output_terminal_descriptor(
+ while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ term, UAC_OUTPUT_TERMINAL))) {
+- if (term->bLength >= sizeof(*term) &&
+- term->bTerminalID == terminal_id)
++ if (!snd_usb_validate_audio_desc(term, protocol))
++ continue;
++ if (term->bTerminalID == terminal_id)
+ return term;
+ }
+
+@@ -741,7 +740,7 @@ snd_usb_get_audioformat_uac12(struct snd
+
+ iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+ as->bTerminalLink,
+- false);
++ protocol);
+ if (iterm) {
+ num_channels = iterm->bNrChannels;
+ chconfig = le16_to_cpu(iterm->wChannelConfig);
+@@ -777,7 +776,7 @@ snd_usb_get_audioformat_uac12(struct snd
+ */
+ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+ as->bTerminalLink,
+- true);
++ protocol);
+ if (input_term) {
+ clock = input_term->bCSourceID;
+ if (!chconfig && (num_channels == input_term->bNrChannels))
+@@ -786,7 +785,8 @@ snd_usb_get_audioformat_uac12(struct snd
+ }
+
+ output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+- as->bTerminalLink);
++ as->bTerminalLink,
++ protocol);
+ if (output_term) {
+ clock = output_term->bCSourceID;
+ goto found_clock;
+@@ -1012,14 +1012,15 @@ snd_usb_get_audioformat_uac3(struct snd_
+ */
+ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+ as->bTerminalLink,
+- true);
++ UAC_VERSION_3);
+ if (input_term) {
+ clock = input_term->bCSourceID;
+ goto found_clock;
+ }
+
+ output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+- as->bTerminalLink);
++ as->bTerminalLink,
++ UAC_VERSION_3);
+ if (output_term) {
+ clock = output_term->bCSourceID;
+ goto found_clock;
+--- /dev/null
++++ b/sound/usb/validate.c
+@@ -0,0 +1,332 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++//
++// Validation of USB-audio class descriptors
++//
++
++#include <linux/init.h>
++#include <linux/usb.h>
++#include <linux/usb/audio.h>
++#include <linux/usb/audio-v2.h>
++#include <linux/usb/audio-v3.h>
++#include <linux/usb/midi.h>
++#include "usbaudio.h"
++#include "helper.h"
++
++struct usb_desc_validator {
++ unsigned char protocol;
++ unsigned char type;
++ bool (*func)(const void *p, const struct usb_desc_validator *v);
++ size_t size;
++};
++
++#define UAC_VERSION_ALL (unsigned char)(-1)
++
++/* UAC1 only */
++static bool validate_uac1_header(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac1_ac_header_descriptor *d = p;
++
++ return d->bLength >= sizeof(*d) &&
++ d->bLength >= sizeof(*d) + d->bInCollection;
++}
++
++/* for mixer unit; covering all UACs */
++static bool validate_mixer_unit(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac_mixer_unit_descriptor *d = p;
++ size_t len;
++
++ if (d->bLength < sizeof(*d) || !d->bNrInPins)
++ return false;
++ len = sizeof(*d) + d->bNrInPins;
++ /* We can't determine the bitmap size only from this unit descriptor,
++ * so just check with the remaining length.
++ * The actual bitmap is checked at mixer unit parser.
++ */
++ switch (v->protocol) {
++ case UAC_VERSION_1:
++ default:
++ len += 2 + 1; /* wChannelConfig, iChannelNames */
++ /* bmControls[n*m] */
++ len += 1; /* iMixer */
++ break;
++ case UAC_VERSION_2:
++ len += 4 + 1; /* bmChannelConfig, iChannelNames */
++ /* bmMixerControls[n*m] */
++ len += 1 + 1; /* bmControls, iMixer */
++ break;
++ case UAC_VERSION_3:
++ len += 2; /* wClusterDescrID */
++ /* bmMixerControls[n*m] */
++ break;
++ }
++ return d->bLength >= len;
++}
++
++/* both for processing and extension units; covering all UACs */
++static bool validate_processing_unit(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac_processing_unit_descriptor *d = p;
++ const unsigned char *hdr = p;
++ size_t len, m;
++
++ if (d->bLength < sizeof(*d))
++ return false;
++ len = d->bLength < sizeof(*d) + d->bNrInPins;
++ if (d->bLength < len)
++ return false;
++ switch (v->protocol) {
++ case UAC_VERSION_1:
++ default:
++ /* bNrChannels, wChannelConfig, iChannelNames, bControlSize */
++ len += 1 + 2 + 1 + 1;
++ if (d->bLength < len) /* bControlSize */
++ return false;
++ m = hdr[len];
++ len += 1 + m + 1; /* bControlSize, bmControls, iProcessing */
++ break;
++ case UAC_VERSION_2:
++ /* bNrChannels, bmChannelConfig, iChannelNames */
++ len += 1 + 4 + 1;
++ if (v->type == UAC2_PROCESSING_UNIT_V2)
++ len += 2; /* bmControls -- 2 bytes for PU */
++ else
++ len += 1; /* bmControls -- 1 byte for EU */
++ len += 1; /* iProcessing */
++ break;
++ case UAC_VERSION_3:
++ /* wProcessingDescrStr, bmControls */
++ len += 2 + 4;
++ break;
++ }
++ if (d->bLength < len)
++ return false;
++
++ switch (v->protocol) {
++ case UAC_VERSION_1:
++ default:
++ if (v->type == UAC1_EXTENSION_UNIT)
++ return true; /* OK */
++ switch (d->wProcessType) {
++ case UAC_PROCESS_UP_DOWNMIX:
++ case UAC_PROCESS_DOLBY_PROLOGIC:
++ if (d->bLength < len + 1) /* bNrModes */
++ return false;
++ m = hdr[len];
++ len += 1 + m * 2; /* bNrModes, waModes(n) */
++ break;
++ default:
++ break;
++ }
++ break;
++ case UAC_VERSION_2:
++ if (v->type == UAC2_EXTENSION_UNIT_V2)
++ return true; /* OK */
++ switch (d->wProcessType) {
++ case UAC2_PROCESS_UP_DOWNMIX:
++ case UAC2_PROCESS_DOLBY_PROLOCIC: /* SiC! */
++ if (d->bLength < len + 1) /* bNrModes */
++ return false;
++ m = hdr[len];
++ len += 1 + m * 4; /* bNrModes, daModes(n) */
++ break;
++ default:
++ break;
++ }
++ break;
++ case UAC_VERSION_3:
++ if (v->type == UAC3_EXTENSION_UNIT) {
++ len += 2; /* wClusterDescrID */
++ break;
++ }
++ switch (d->wProcessType) {
++ case UAC3_PROCESS_UP_DOWNMIX:
++ if (d->bLength < len + 1) /* bNrModes */
++ return false;
++ m = hdr[len];
++ len += 1 + m * 2; /* bNrModes, waClusterDescrID(n) */
++ break;
++ case UAC3_PROCESS_MULTI_FUNCTION:
++ len += 2 + 4; /* wClusterDescrID, bmAlgorighms */
++ break;
++ default:
++ break;
++ }
++ break;
++ }
++ if (d->bLength < len)
++ return false;
++
++ return true;
++}
++
++/* both for selector and clock selector units; covering all UACs */
++static bool validate_selector_unit(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac_selector_unit_descriptor *d = p;
++ size_t len;
++
++ if (d->bLength < sizeof(*d))
++ return false;
++ len = sizeof(*d) + d->bNrInPins;
++ switch (v->protocol) {
++ case UAC_VERSION_1:
++ default:
++ len += 1; /* iSelector */
++ break;
++ case UAC_VERSION_2:
++ len += 1 + 1; /* bmControls, iSelector */
++ break;
++ case UAC_VERSION_3:
++ len += 4 + 2; /* bmControls, wSelectorDescrStr */
++ break;
++ }
++ return d->bLength >= len;
++}
++
++static bool validate_uac1_feature_unit(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac_feature_unit_descriptor *d = p;
++
++ if (d->bLength < sizeof(*d) || !d->bControlSize)
++ return false;
++ /* at least bmaControls(0) for master channel + iFeature */
++ return d->bLength >= sizeof(*d) + d->bControlSize + 1;
++}
++
++static bool validate_uac2_feature_unit(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac2_feature_unit_descriptor *d = p;
++
++ if (d->bLength < sizeof(*d))
++ return false;
++ /* at least bmaControls(0) for master channel + iFeature */
++ return d->bLength >= sizeof(*d) + 4 + 1;
++}
++
++static bool validate_uac3_feature_unit(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct uac3_feature_unit_descriptor *d = p;
++
++ if (d->bLength < sizeof(*d))
++ return false;
++ /* at least bmaControls(0) for master channel + wFeatureDescrStr */
++ return d->bLength >= sizeof(*d) + 4 + 2;
++}
++
++static bool validate_midi_out_jack(const void *p,
++ const struct usb_desc_validator *v)
++{
++ const struct usb_midi_out_jack_descriptor *d = p;
++
++ return d->bLength >= sizeof(*d) &&
++ d->bLength >= sizeof(*d) + d->bNrInputPins * 2;
++}
++
++#define FIXED(p, t, s) { .protocol = (p), .type = (t), .size = sizeof(s) }
++#define FUNC(p, t, f) { .protocol = (p), .type = (t), .func = (f) }
++
++static struct usb_desc_validator audio_validators[] = {
++ /* UAC1 */
++ FUNC(UAC_VERSION_1, UAC_HEADER, validate_uac1_header),
++ FIXED(UAC_VERSION_1, UAC_INPUT_TERMINAL,
++ struct uac_input_terminal_descriptor),
++ FIXED(UAC_VERSION_1, UAC_OUTPUT_TERMINAL,
++ struct uac1_output_terminal_descriptor),
++ FUNC(UAC_VERSION_1, UAC_MIXER_UNIT, validate_mixer_unit),
++ FUNC(UAC_VERSION_1, UAC_SELECTOR_UNIT, validate_selector_unit),
++ FUNC(UAC_VERSION_1, UAC_FEATURE_UNIT, validate_uac1_feature_unit),
++ FUNC(UAC_VERSION_1, UAC1_PROCESSING_UNIT, validate_processing_unit),
++ FUNC(UAC_VERSION_1, UAC1_EXTENSION_UNIT, validate_processing_unit),
++
++ /* UAC2 */
++ FIXED(UAC_VERSION_2, UAC_HEADER, struct uac2_ac_header_descriptor),
++ FIXED(UAC_VERSION_2, UAC_INPUT_TERMINAL,
++ struct uac2_input_terminal_descriptor),
++ FIXED(UAC_VERSION_2, UAC_OUTPUT_TERMINAL,
++ struct uac2_output_terminal_descriptor),
++ FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit),
++ FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit),
++ FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit),
++ /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */
++ FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit),
++ FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit),
++ FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE,
++ struct uac_clock_source_descriptor),
++ FUNC(UAC_VERSION_2, UAC2_CLOCK_SELECTOR, validate_selector_unit),
++ FIXED(UAC_VERSION_2, UAC2_CLOCK_MULTIPLIER,
++ struct uac_clock_multiplier_descriptor),
++ /* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */
++
++ /* UAC3 */
++ FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor),
++ FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL,
++ struct uac3_input_terminal_descriptor),
++ FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL,
++ struct uac3_output_terminal_descriptor),
++ /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */
++ FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit),
++ FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit),
++ FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit),
++ /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */
++ FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit),
++ FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit),
++ FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE,
++ struct uac3_clock_source_descriptor),
++ FUNC(UAC_VERSION_3, UAC3_CLOCK_SELECTOR, validate_selector_unit),
++ FIXED(UAC_VERSION_3, UAC3_CLOCK_MULTIPLIER,
++ struct uac3_clock_multiplier_descriptor),
++ /* UAC_VERSION_3, UAC3_SAMPLE_RATE_CONVERTER: not implemented yet */
++ /* UAC_VERSION_3, UAC3_CONNECTORS: not implemented yet */
++ { } /* terminator */
++};
++
++static struct usb_desc_validator midi_validators[] = {
++ FIXED(UAC_VERSION_ALL, USB_MS_HEADER,
++ struct usb_ms_header_descriptor),
++ FIXED(UAC_VERSION_ALL, USB_MS_MIDI_IN_JACK,
++ struct usb_midi_in_jack_descriptor),
++ FUNC(UAC_VERSION_ALL, USB_MS_MIDI_OUT_JACK,
++ validate_midi_out_jack),
++ { } /* terminator */
++};
++
++
++/* Validate the given unit descriptor, return true if it's OK */
++static bool validate_desc(unsigned char *hdr, int protocol,
++ const struct usb_desc_validator *v)
++{
++ if (hdr[1] != USB_DT_CS_INTERFACE)
++ return true; /* don't care */
++
++ for (; v->type; v++) {
++ if (v->type == hdr[2] &&
++ (v->protocol == UAC_VERSION_ALL ||
++ v->protocol == protocol)) {
++ if (v->func)
++ return v->func(hdr, v);
++ /* check for the fixed size */
++ return hdr[0] >= v->size;
++ }
++ }
++
++ return true; /* not matching, skip validation */
++}
++
++bool snd_usb_validate_audio_desc(void *p, int protocol)
++{
++ return validate_desc(p, protocol, audio_validators);
++}
++
++bool snd_usb_validate_midi_desc(void *p)
++{
++ return validate_desc(p, UAC_VERSION_1, midi_validators);
++}
++
--- /dev/null
+From b39e077fcb283dd96dd251a3abeba585402c61fe Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Mon, 26 Aug 2019 16:45:50 +0300
+Subject: ALSA: usb-audio: remove some dead code
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit b39e077fcb283dd96dd251a3abeba585402c61fe upstream.
+
+We recently cleaned up the error handling in commit 52c3e317a857 ("ALSA:
+usb-audio: Unify the release of usb_mixer_elem_info objects") but
+accidentally left this stray return.
+
+Fixes: 52c3e317a857 ("ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -2670,7 +2670,6 @@ static int parse_audio_selector_unit(str
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
+ err = -ENOMEM;
+ goto error_name;
+- return -ENOMEM;
+ }
+ kctl->private_value = (unsigned long)namelist;
+ kctl->private_free = usb_mixer_selector_elem_free;
--- /dev/null
+From b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 22 Aug 2019 09:25:27 +0200
+Subject: ALSA: usb-audio: Remove superfluous bLength checks
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a upstream.
+
+Now that we got the more comprehensive validation code for USB-audio
+descriptors, the check of overflow in each descriptor unit parser
+became superfluous. Drop some of the obvious cases.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/clock.c | 14 +++------
+ sound/usb/mixer.c | 84 ------------------------------------------------------
+ 2 files changed, 6 insertions(+), 92 deletions(-)
+
+--- a/sound/usb/clock.c
++++ b/sound/usb/clock.c
+@@ -52,39 +52,37 @@ static void *find_uac_clock_desc(struct
+ static bool validate_clock_source_v2(void *p, int id)
+ {
+ struct uac_clock_source_descriptor *cs = p;
+- return cs->bLength == sizeof(*cs) && cs->bClockID == id;
++ return cs->bClockID == id;
+ }
+
+ static bool validate_clock_source_v3(void *p, int id)
+ {
+ struct uac3_clock_source_descriptor *cs = p;
+- return cs->bLength == sizeof(*cs) && cs->bClockID == id;
++ return cs->bClockID == id;
+ }
+
+ static bool validate_clock_selector_v2(void *p, int id)
+ {
+ struct uac_clock_selector_descriptor *cs = p;
+- return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
+- cs->bLength == 7 + cs->bNrInPins;
++ return cs->bClockID == id;
+ }
+
+ static bool validate_clock_selector_v3(void *p, int id)
+ {
+ struct uac3_clock_selector_descriptor *cs = p;
+- return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
+- cs->bLength == 11 + cs->bNrInPins;
++ return cs->bClockID == id;
+ }
+
+ static bool validate_clock_multiplier_v2(void *p, int id)
+ {
+ struct uac_clock_multiplier_descriptor *cs = p;
+- return cs->bLength == sizeof(*cs) && cs->bClockID == id;
++ return cs->bClockID == id;
+ }
+
+ static bool validate_clock_multiplier_v3(void *p, int id)
+ {
+ struct uac3_clock_multiplier_descriptor *cs = p;
+- return cs->bLength == sizeof(*cs) && cs->bClockID == id;
++ return cs->bClockID == id;
+ }
+
+ #define DEFINE_FIND_HELPER(name, obj, validator, type) \
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -755,13 +755,6 @@ static int uac_mixer_unit_get_channels(s
+ {
+ int mu_channels;
+
+- if (desc->bLength < sizeof(*desc))
+- return -EINVAL;
+- if (!desc->bNrInPins)
+- return -EINVAL;
+- if (desc->bLength < sizeof(*desc) + desc->bNrInPins)
+- return -EINVAL;
+-
+ switch (state->mixer->protocol) {
+ case UAC_VERSION_1:
+ case UAC_VERSION_2:
+@@ -1796,13 +1789,6 @@ static int parse_clock_source_unit(struc
+ if (state->mixer->protocol != UAC_VERSION_2)
+ return -EINVAL;
+
+- if (hdr->bLength != sizeof(*hdr)) {
+- usb_audio_dbg(state->chip,
+- "Bogus clock source descriptor length of %d, ignoring.\n",
+- hdr->bLength);
+- return 0;
+- }
+-
+ /*
+ * The only property of this unit we are interested in is the
+ * clock source validity. If that isn't readable, just bail out.
+@@ -1861,62 +1847,20 @@ static int parse_audio_feature_unit(stru
+ __u8 *bmaControls;
+
+ if (state->mixer->protocol == UAC_VERSION_1) {
+- if (hdr->bLength < 7) {
+- usb_audio_err(state->chip,
+- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+- unitid);
+- return -EINVAL;
+- }
+ csize = hdr->bControlSize;
+- if (!csize) {
+- usb_audio_dbg(state->chip,
+- "unit %u: invalid bControlSize == 0\n",
+- unitid);
+- return -EINVAL;
+- }
+ channels = (hdr->bLength - 7) / csize - 1;
+ bmaControls = hdr->bmaControls;
+- if (hdr->bLength < 7 + csize) {
+- usb_audio_err(state->chip,
+- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+- unitid);
+- return -EINVAL;
+- }
+ } else if (state->mixer->protocol == UAC_VERSION_2) {
+ struct uac2_feature_unit_descriptor *ftr = _ftr;
+- if (hdr->bLength < 6) {
+- usb_audio_err(state->chip,
+- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+- unitid);
+- return -EINVAL;
+- }
+ csize = 4;
+ channels = (hdr->bLength - 6) / 4 - 1;
+ bmaControls = ftr->bmaControls;
+- if (hdr->bLength < 6 + csize) {
+- usb_audio_err(state->chip,
+- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+- unitid);
+- return -EINVAL;
+- }
+ } else { /* UAC_VERSION_3 */
+ struct uac3_feature_unit_descriptor *ftr = _ftr;
+
+- if (hdr->bLength < 7) {
+- usb_audio_err(state->chip,
+- "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n",
+- unitid);
+- return -EINVAL;
+- }
+ csize = 4;
+ channels = (ftr->bLength - 7) / 4 - 1;
+ bmaControls = ftr->bmaControls;
+- if (hdr->bLength < 7 + csize) {
+- usb_audio_err(state->chip,
+- "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n",
+- unitid);
+- return -EINVAL;
+- }
+ }
+
+ /* parse the source unit */
+@@ -2120,15 +2064,11 @@ static int parse_audio_input_terminal(st
+
+ if (state->mixer->protocol == UAC_VERSION_2) {
+ struct uac2_input_terminal_descriptor *d_v2 = raw_desc;
+- if (d_v2->bLength < sizeof(*d_v2))
+- return -EINVAL;
+ control = UAC2_TE_CONNECTOR;
+ term_id = d_v2->bTerminalID;
+ bmctls = le16_to_cpu(d_v2->bmControls);
+ } else if (state->mixer->protocol == UAC_VERSION_3) {
+ struct uac3_input_terminal_descriptor *d_v3 = raw_desc;
+- if (d_v3->bLength < sizeof(*d_v3))
+- return -EINVAL;
+ control = UAC3_TE_INSERTION;
+ term_id = d_v3->bTerminalID;
+ bmctls = le32_to_cpu(d_v3->bmControls);
+@@ -2390,18 +2330,7 @@ static int build_audio_procunit(struct m
+ const char *name = extension_unit ?
+ "Extension Unit" : "Processing Unit";
+
+- if (desc->bLength < 13) {
+- usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
+- return -EINVAL;
+- }
+-
+ num_ins = desc->bNrInPins;
+- if (desc->bLength < 13 + num_ins ||
+- desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {
+- usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
+- return -EINVAL;
+- }
+-
+ for (i = 0; i < num_ins; i++) {
+ err = parse_audio_unit(state, desc->baSourceID[i]);
+ if (err < 0)
+@@ -2656,13 +2585,6 @@ static int parse_audio_selector_unit(str
+ const struct usbmix_name_map *map;
+ char **namelist;
+
+- if (desc->bLength < 5 || !desc->bNrInPins ||
+- desc->bLength < 5 + desc->bNrInPins) {
+- usb_audio_err(state->chip,
+- "invalid SELECTOR UNIT descriptor %d\n", unitid);
+- return -EINVAL;
+- }
+-
+ for (i = 0; i < desc->bNrInPins; i++) {
+ err = parse_audio_unit(state, desc->baSourceID[i]);
+ if (err < 0)
+@@ -3168,8 +3090,6 @@ static int snd_usb_mixer_controls(struct
+ if (mixer->protocol == UAC_VERSION_1) {
+ struct uac1_output_terminal_descriptor *desc = p;
+
+- if (desc->bLength < sizeof(*desc))
+- continue; /* invalid descriptor? */
+ /* mark terminal ID as visited */
+ set_bit(desc->bTerminalID, state.unitbitmap);
+ state.oterm.id = desc->bTerminalID;
+@@ -3181,8 +3101,6 @@ static int snd_usb_mixer_controls(struct
+ } else if (mixer->protocol == UAC_VERSION_2) {
+ struct uac2_output_terminal_descriptor *desc = p;
+
+- if (desc->bLength < sizeof(*desc))
+- continue; /* invalid descriptor? */
+ /* mark terminal ID as visited */
+ set_bit(desc->bTerminalID, state.unitbitmap);
+ state.oterm.id = desc->bTerminalID;
+@@ -3208,8 +3126,6 @@ static int snd_usb_mixer_controls(struct
+ } else { /* UAC_VERSION_3 */
+ struct uac3_output_terminal_descriptor *desc = p;
+
+- if (desc->bLength < sizeof(*desc))
+- continue; /* invalid descriptor? */
+ /* mark terminal ID as visited */
+ set_bit(desc->bTerminalID, state.unitbitmap);
+ state.oterm.id = desc->bTerminalID;
--- /dev/null
+From 68e9fde245591d18200f8a9054cac22339437adb Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 15 Aug 2019 16:30:39 +0200
+Subject: ALSA: usb-audio: Simplify parse_audio_unit()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 68e9fde245591d18200f8a9054cac22339437adb upstream.
+
+Minor code refactoring by combining the UAC version and the type in
+the switch-case flow, so that we reduce the indentation and
+redundancy. One good bonus is that the duplicated definition of the
+same type value (e.g. UAC2_EFFECT_UNIT) can be handled more cleanly.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c | 95 ++++++++++++++++++++++--------------------------------
+ 1 file changed, 39 insertions(+), 56 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -2801,62 +2801,45 @@ static int parse_audio_unit(struct mixer
+ return 0; /* skip invalid unit */
+ }
+
+- if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
+- switch (p1[2]) {
+- case UAC_INPUT_TERMINAL:
+- return parse_audio_input_terminal(state, unitid, p1);
+- case UAC_MIXER_UNIT:
+- return parse_audio_mixer_unit(state, unitid, p1);
+- case UAC2_CLOCK_SOURCE:
+- return parse_clock_source_unit(state, unitid, p1);
+- case UAC_SELECTOR_UNIT:
+- case UAC2_CLOCK_SELECTOR:
+- return parse_audio_selector_unit(state, unitid, p1);
+- case UAC_FEATURE_UNIT:
+- return parse_audio_feature_unit(state, unitid, p1);
+- case UAC1_PROCESSING_UNIT:
+- /* UAC2_EFFECT_UNIT has the same value */
+- if (protocol == UAC_VERSION_1)
+- return parse_audio_processing_unit(state, unitid, p1);
+- else
+- return 0; /* FIXME - effect units not implemented yet */
+- case UAC1_EXTENSION_UNIT:
+- /* UAC2_PROCESSING_UNIT_V2 has the same value */
+- if (protocol == UAC_VERSION_1)
+- return parse_audio_extension_unit(state, unitid, p1);
+- else /* UAC_VERSION_2 */
+- return parse_audio_processing_unit(state, unitid, p1);
+- case UAC2_EXTENSION_UNIT_V2:
+- return parse_audio_extension_unit(state, unitid, p1);
+- default:
+- usb_audio_err(state->chip,
+- "unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+- return -EINVAL;
+- }
+- } else { /* UAC_VERSION_3 */
+- switch (p1[2]) {
+- case UAC_INPUT_TERMINAL:
+- return parse_audio_input_terminal(state, unitid, p1);
+- case UAC3_MIXER_UNIT:
+- return parse_audio_mixer_unit(state, unitid, p1);
+- case UAC3_CLOCK_SOURCE:
+- return parse_clock_source_unit(state, unitid, p1);
+- case UAC3_SELECTOR_UNIT:
+- case UAC3_CLOCK_SELECTOR:
+- return parse_audio_selector_unit(state, unitid, p1);
+- case UAC3_FEATURE_UNIT:
+- return parse_audio_feature_unit(state, unitid, p1);
+- case UAC3_EFFECT_UNIT:
+- return 0; /* FIXME - effect units not implemented yet */
+- case UAC3_PROCESSING_UNIT:
+- return parse_audio_processing_unit(state, unitid, p1);
+- case UAC3_EXTENSION_UNIT:
+- return parse_audio_extension_unit(state, unitid, p1);
+- default:
+- usb_audio_err(state->chip,
+- "unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+- return -EINVAL;
+- }
++#define PTYPE(a, b) ((a) << 8 | (b))
++ switch (PTYPE(protocol, p1[2])) {
++ case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL):
++ case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL):
++ case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL):
++ return parse_audio_input_terminal(state, unitid, p1);
++ case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT):
++ return parse_audio_mixer_unit(state, unitid, p1);
++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE):
++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE):
++ return parse_clock_source_unit(state, unitid, p1);
++ case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR):
++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR):
++ return parse_audio_selector_unit(state, unitid, p1);
++ case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT):
++ return parse_audio_feature_unit(state, unitid, p1);
++ case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2):
++ case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT):
++ return parse_audio_processing_unit(state, unitid, p1);
++ case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT):
++ case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2):
++ case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT):
++ return parse_audio_extension_unit(state, unitid, p1);
++ case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT):
++ case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT):
++ return 0; /* FIXME - effect units not implemented yet */
++ default:
++ usb_audio_err(state->chip,
++ "unit %u: unexpected type 0x%02x\n",
++ unitid, p1[2]);
++ return -EINVAL;
+ }
+ }
+
--- /dev/null
+From 52c3e317a857091fd746e15179a637f32be4d337 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 22 Aug 2019 08:23:10 +0200
+Subject: ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 52c3e317a857091fd746e15179a637f32be4d337 upstream.
+
+Instead of the direct kfree() calls, introduce a new local helper to
+release the usb_mixer_elem_info object. This will be extended to do
+more than a single kfree() in the later patches.
+
+Also, use the standard goto instead of multiple calls in
+parse_audio_selector_unit() error paths.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c | 48 ++++++++++++++++++++++++++++--------------------
+ 1 file changed, 28 insertions(+), 20 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -1041,10 +1041,15 @@ static struct usb_feature_control_info a
+ { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 },
+ };
+
++static void usb_mixer_elem_info_free(struct usb_mixer_elem_info *cval)
++{
++ kfree(cval);
++}
++
+ /* private_free callback */
+ void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl)
+ {
+- kfree(kctl->private_data);
++ usb_mixer_elem_info_free(kctl->private_data);
+ kctl->private_data = NULL;
+ }
+
+@@ -1567,7 +1572,7 @@ static void __build_feature_ctl(struct u
+
+ ctl_info = get_feature_control_info(control);
+ if (!ctl_info) {
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ return;
+ }
+ if (mixer->protocol == UAC_VERSION_1)
+@@ -1600,7 +1605,7 @@ static void __build_feature_ctl(struct u
+
+ if (!kctl) {
+ usb_audio_err(mixer->chip, "cannot malloc kcontrol\n");
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ return;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+@@ -1770,7 +1775,7 @@ static void build_connector_control(stru
+ kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval);
+ if (!kctl) {
+ usb_audio_err(mixer->chip, "cannot malloc kcontrol\n");
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ return;
+ }
+ get_connector_control_name(mixer, term, is_input, kctl->id.name,
+@@ -1823,7 +1828,7 @@ static int parse_clock_source_unit(struc
+ kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval);
+
+ if (!kctl) {
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ return -ENOMEM;
+ }
+
+@@ -2089,7 +2094,7 @@ static void build_mixer_unit_ctl(struct
+ kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
+ if (!kctl) {
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ return;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+@@ -2487,7 +2492,7 @@ static int build_audio_procunit(struct m
+
+ kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
+ if (!kctl) {
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ return -ENOMEM;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+@@ -2625,7 +2630,7 @@ static void usb_mixer_selector_elem_free
+ if (kctl->private_data) {
+ struct usb_mixer_elem_info *cval = kctl->private_data;
+ num_ins = cval->max;
+- kfree(cval);
++ usb_mixer_elem_info_free(cval);
+ kctl->private_data = NULL;
+ }
+ if (kctl->private_value) {
+@@ -2697,10 +2702,10 @@ static int parse_audio_selector_unit(str
+ break;
+ }
+
+- namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL);
++ namelist = kcalloc(desc->bNrInPins, sizeof(char *), GFP_KERNEL);
+ if (!namelist) {
+- kfree(cval);
+- return -ENOMEM;
++ err = -ENOMEM;
++ goto error_cval;
+ }
+ #define MAX_ITEM_NAME_LEN 64
+ for (i = 0; i < desc->bNrInPins; i++) {
+@@ -2708,11 +2713,8 @@ static int parse_audio_selector_unit(str
+ len = 0;
+ namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
+ if (!namelist[i]) {
+- while (i--)
+- kfree(namelist[i]);
+- kfree(namelist);
+- kfree(cval);
+- return -ENOMEM;
++ err = -ENOMEM;
++ goto error_name;
+ }
+ len = check_mapped_selector_name(state, unitid, i, namelist[i],
+ MAX_ITEM_NAME_LEN);
+@@ -2726,10 +2728,8 @@ static int parse_audio_selector_unit(str
+ kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
+ if (! kctl) {
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
+- for (i = 0; i < desc->bNrInPins; i++)
+- kfree(namelist[i]);
+- kfree(namelist);
+- kfree(cval);
++ err = -ENOMEM;
++ goto error_name;
+ return -ENOMEM;
+ }
+ kctl->private_value = (unsigned long)namelist;
+@@ -2776,6 +2776,14 @@ static int parse_audio_selector_unit(str
+ usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
+ cval->head.id, kctl->id.name, desc->bNrInPins);
+ return snd_usb_mixer_add_control(&cval->head, kctl);
++
++ error_name:
++ for (i = 0; i < desc->bNrInPins; i++)
++ kfree(namelist[i]);
++ kfree(namelist);
++ error_cval:
++ usb_mixer_elem_info_free(cval);
++ return err;
+ }
+
+ /*
--- /dev/null
+From de53fd7aedb100f03e5d2231cfce0e4993282425 Mon Sep 17 00:00:00 2001
+From: Dave Chiluk <chiluk+linux@indeed.com>
+Date: Tue, 23 Jul 2019 11:44:26 -0500
+Subject: sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices
+
+From: Dave Chiluk <chiluk+linux@indeed.com>
+
+commit de53fd7aedb100f03e5d2231cfce0e4993282425 upstream.
+
+It has been observed, that highly-threaded, non-cpu-bound applications
+running under cpu.cfs_quota_us constraints can hit a high percentage of
+periods throttled while simultaneously not consuming the allocated
+amount of quota. This use case is typical of user-interactive non-cpu
+bound applications, such as those running in kubernetes or mesos when
+run on multiple cpu cores.
+
+This has been root caused to cpu-local run queue being allocated per cpu
+bandwidth slices, and then not fully using that slice within the period.
+At which point the slice and quota expires. This expiration of unused
+slice results in applications not being able to utilize the quota for
+which they are allocated.
+
+The non-expiration of per-cpu slices was recently fixed by
+'commit 512ac999d275 ("sched/fair: Fix bandwidth timer clock drift
+condition")'. Prior to that it appears that this had been broken since
+at least 'commit 51f2176d74ac ("sched/fair: Fix unlocked reads of some
+cfs_b->quota/period")' which was introduced in v3.16-rc1 in 2014. That
+added the following conditional which resulted in slices never being
+expired.
+
+if (cfs_rq->runtime_expires != cfs_b->runtime_expires) {
+ /* extend local deadline, drift is bounded above by 2 ticks */
+ cfs_rq->runtime_expires += TICK_NSEC;
+
+Because this was broken for nearly 5 years, and has recently been fixed
+and is now being noticed by many users running kubernetes
+(https://github.com/kubernetes/kubernetes/issues/67577) it is my opinion
+that the mechanisms around expiring runtime should be removed
+altogether.
+
+This allows quota already allocated to per-cpu run-queues to live longer
+than the period boundary. This allows threads on runqueues that do not
+use much CPU to continue to use their remaining slice over a longer
+period of time than cpu.cfs_period_us. However, this helps prevent the
+above condition of hitting throttling while also not fully utilizing
+your cpu quota.
+
+This theoretically allows a machine to use slightly more than its
+allotted quota in some periods. This overflow would be bounded by the
+remaining quota left on each per-cpu runqueueu. This is typically no
+more than min_cfs_rq_runtime=1ms per cpu. For CPU bound tasks this will
+change nothing, as they should theoretically fully utilize all of their
+quota in each period. For user-interactive tasks as described above this
+provides a much better user/application experience as their cpu
+utilization will more closely match the amount they requested when they
+hit throttling. This means that cpu limits no longer strictly apply per
+period for non-cpu bound applications, but that they are still accurate
+over longer timeframes.
+
+This greatly improves performance of high-thread-count, non-cpu bound
+applications with low cfs_quota_us allocation on high-core-count
+machines. In the case of an artificial testcase (10ms/100ms of quota on
+80 CPU machine), this commit resulted in almost 30x performance
+improvement, while still maintaining correct cpu quota restrictions.
+That testcase is available at https://github.com/indeedeng/fibtest.
+
+Fixes: 512ac999d275 ("sched/fair: Fix bandwidth timer clock drift condition")
+Signed-off-by: Dave Chiluk <chiluk+linux@indeed.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Phil Auld <pauld@redhat.com>
+Reviewed-by: Ben Segall <bsegall@google.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: John Hammond <jhammond@indeed.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Kyle Anderson <kwa@yelp.com>
+Cc: Gabriel Munos <gmunoz@netflix.com>
+Cc: Peter Oskolkov <posk@posk.io>
+Cc: Cong Wang <xiyou.wangcong@gmail.com>
+Cc: Brendan Gregg <bgregg@netflix.com>
+Link: https://lkml.kernel.org/r/1563900266-19734-2-git-send-email-chiluk+linux@indeed.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ Documentation/scheduler/sched-bwc.txt | 45 +++++++++++++++++++++
+ kernel/sched/fair.c | 72 +++-------------------------------
+ kernel/sched/sched.h | 4 -
+ 3 files changed, 52 insertions(+), 69 deletions(-)
+
+--- a/Documentation/scheduler/sched-bwc.txt
++++ b/Documentation/scheduler/sched-bwc.txt
+@@ -90,6 +90,51 @@ There are two ways in which a group may
+ In case b) above, even though the child may have runtime remaining it will not
+ be allowed to until the parent's runtime is refreshed.
+
++CFS Bandwidth Quota Caveats
++---------------------------
++Once a slice is assigned to a cpu it does not expire. However all but 1ms of
++the slice may be returned to the global pool if all threads on that cpu become
++unrunnable. This is configured at compile time by the min_cfs_rq_runtime
++variable. This is a performance tweak that helps prevent added contention on
++the global lock.
++
++The fact that cpu-local slices do not expire results in some interesting corner
++cases that should be understood.
++
++For cgroup cpu constrained applications that are cpu limited this is a
++relatively moot point because they will naturally consume the entirety of their
++quota as well as the entirety of each cpu-local slice in each period. As a
++result it is expected that nr_periods roughly equal nr_throttled, and that
++cpuacct.usage will increase roughly equal to cfs_quota_us in each period.
++
++For highly-threaded, non-cpu bound applications this non-expiration nuance
++allows applications to briefly burst past their quota limits by the amount of
++unused slice on each cpu that the task group is running on (typically at most
++1ms per cpu or as defined by min_cfs_rq_runtime). This slight burst only
++applies if quota had been assigned to a cpu and then not fully used or returned
++in previous periods. This burst amount will not be transferred between cores.
++As a result, this mechanism still strictly limits the task group to quota
++average usage, albeit over a longer time window than a single period. This
++also limits the burst ability to no more than 1ms per cpu. This provides
++better more predictable user experience for highly threaded applications with
++small quota limits on high core count machines. It also eliminates the
++propensity to throttle these applications while simultanously using less than
++quota amounts of cpu. Another way to say this, is that by allowing the unused
++portion of a slice to remain valid across periods we have decreased the
++possibility of wastefully expiring quota on cpu-local silos that don't need a
++full slice's amount of cpu time.
++
++The interaction between cpu-bound and non-cpu-bound-interactive applications
++should also be considered, especially when single core usage hits 100%. If you
++gave each of these applications half of a cpu-core and they both got scheduled
++on the same CPU it is theoretically possible that the non-cpu bound application
++will use up to 1ms additional quota in some periods, thereby preventing the
++cpu-bound application from fully using its quota by that same amount. In these
++instances it will be up to the CFS algorithm (see sched-design-CFS.rst) to
++decide which application is chosen to run, as they will both be runnable and
++have remaining quota. This runtime discrepancy will be made up in the following
++periods when the interactive application idles.
++
+ Examples
+ --------
+ 1. Limit a group to 1 CPU worth of runtime.
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -4320,8 +4320,6 @@ void __refill_cfs_bandwidth_runtime(stru
+
+ now = sched_clock_cpu(smp_processor_id());
+ cfs_b->runtime = cfs_b->quota;
+- cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period);
+- cfs_b->expires_seq++;
+ }
+
+ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
+@@ -4343,8 +4341,7 @@ static int assign_cfs_rq_runtime(struct
+ {
+ struct task_group *tg = cfs_rq->tg;
+ struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(tg);
+- u64 amount = 0, min_amount, expires;
+- int expires_seq;
++ u64 amount = 0, min_amount;
+
+ /* note: this is a positive sum as runtime_remaining <= 0 */
+ min_amount = sched_cfs_bandwidth_slice() - cfs_rq->runtime_remaining;
+@@ -4361,61 +4358,17 @@ static int assign_cfs_rq_runtime(struct
+ cfs_b->idle = 0;
+ }
+ }
+- expires_seq = cfs_b->expires_seq;
+- expires = cfs_b->runtime_expires;
+ raw_spin_unlock(&cfs_b->lock);
+
+ cfs_rq->runtime_remaining += amount;
+- /*
+- * we may have advanced our local expiration to account for allowed
+- * spread between our sched_clock and the one on which runtime was
+- * issued.
+- */
+- if (cfs_rq->expires_seq != expires_seq) {
+- cfs_rq->expires_seq = expires_seq;
+- cfs_rq->runtime_expires = expires;
+- }
+
+ return cfs_rq->runtime_remaining > 0;
+ }
+
+-/*
+- * Note: This depends on the synchronization provided by sched_clock and the
+- * fact that rq->clock snapshots this value.
+- */
+-static void expire_cfs_rq_runtime(struct cfs_rq *cfs_rq)
+-{
+- struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
+-
+- /* if the deadline is ahead of our clock, nothing to do */
+- if (likely((s64)(rq_clock(rq_of(cfs_rq)) - cfs_rq->runtime_expires) < 0))
+- return;
+-
+- if (cfs_rq->runtime_remaining < 0)
+- return;
+-
+- /*
+- * If the local deadline has passed we have to consider the
+- * possibility that our sched_clock is 'fast' and the global deadline
+- * has not truly expired.
+- *
+- * Fortunately we can check determine whether this the case by checking
+- * whether the global deadline(cfs_b->expires_seq) has advanced.
+- */
+- if (cfs_rq->expires_seq == cfs_b->expires_seq) {
+- /* extend local deadline, drift is bounded above by 2 ticks */
+- cfs_rq->runtime_expires += TICK_NSEC;
+- } else {
+- /* global deadline is ahead, expiration has passed */
+- cfs_rq->runtime_remaining = 0;
+- }
+-}
+-
+ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)
+ {
+ /* dock delta_exec before expiring quota (as it could span periods) */
+ cfs_rq->runtime_remaining -= delta_exec;
+- expire_cfs_rq_runtime(cfs_rq);
+
+ if (likely(cfs_rq->runtime_remaining > 0))
+ return;
+@@ -4600,8 +4553,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cf
+ resched_curr(rq);
+ }
+
+-static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
+- u64 remaining, u64 expires)
++static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, u64 remaining)
+ {
+ struct cfs_rq *cfs_rq;
+ u64 runtime;
+@@ -4626,7 +4578,6 @@ static u64 distribute_cfs_runtime(struct
+ remaining -= runtime;
+
+ cfs_rq->runtime_remaining += runtime;
+- cfs_rq->runtime_expires = expires;
+
+ /* we check whether we're throttled above */
+ if (cfs_rq->runtime_remaining > 0)
+@@ -4651,7 +4602,7 @@ next:
+ */
+ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun)
+ {
+- u64 runtime, runtime_expires;
++ u64 runtime;
+ int throttled;
+
+ /* no need to continue the timer with no bandwidth constraint */
+@@ -4679,8 +4630,6 @@ static int do_sched_cfs_period_timer(str
+ /* account preceding periods in which throttling occurred */
+ cfs_b->nr_throttled += overrun;
+
+- runtime_expires = cfs_b->runtime_expires;
+-
+ /*
+ * This check is repeated as we are holding onto the new bandwidth while
+ * we unthrottle. This can potentially race with an unthrottled group
+@@ -4693,8 +4642,7 @@ static int do_sched_cfs_period_timer(str
+ cfs_b->distribute_running = 1;
+ raw_spin_unlock(&cfs_b->lock);
+ /* we can't nest cfs_b->lock while distributing bandwidth */
+- runtime = distribute_cfs_runtime(cfs_b, runtime,
+- runtime_expires);
++ runtime = distribute_cfs_runtime(cfs_b, runtime);
+ raw_spin_lock(&cfs_b->lock);
+
+ cfs_b->distribute_running = 0;
+@@ -4771,8 +4719,7 @@ static void __return_cfs_rq_runtime(stru
+ return;
+
+ raw_spin_lock(&cfs_b->lock);
+- if (cfs_b->quota != RUNTIME_INF &&
+- cfs_rq->runtime_expires == cfs_b->runtime_expires) {
++ if (cfs_b->quota != RUNTIME_INF) {
+ cfs_b->runtime += slack_runtime;
+
+ /* we are under rq->lock, defer unthrottling using a timer */
+@@ -4804,7 +4751,6 @@ static __always_inline void return_cfs_r
+ static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b)
+ {
+ u64 runtime = 0, slice = sched_cfs_bandwidth_slice();
+- u64 expires;
+
+ /* confirm we're still not at a refresh boundary */
+ raw_spin_lock(&cfs_b->lock);
+@@ -4821,7 +4767,6 @@ static void do_sched_cfs_slack_timer(str
+ if (cfs_b->quota != RUNTIME_INF && cfs_b->runtime > slice)
+ runtime = cfs_b->runtime;
+
+- expires = cfs_b->runtime_expires;
+ if (runtime)
+ cfs_b->distribute_running = 1;
+
+@@ -4830,11 +4775,10 @@ static void do_sched_cfs_slack_timer(str
+ if (!runtime)
+ return;
+
+- runtime = distribute_cfs_runtime(cfs_b, runtime, expires);
++ runtime = distribute_cfs_runtime(cfs_b, runtime);
+
+ raw_spin_lock(&cfs_b->lock);
+- if (expires == cfs_b->runtime_expires)
+- cfs_b->runtime -= min(runtime, cfs_b->runtime);
++ cfs_b->runtime -= min(runtime, cfs_b->runtime);
+ cfs_b->distribute_running = 0;
+ raw_spin_unlock(&cfs_b->lock);
+ }
+@@ -4989,8 +4933,6 @@ void start_cfs_bandwidth(struct cfs_band
+
+ cfs_b->period_active = 1;
+ overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
+- cfs_b->runtime_expires += (overrun + 1) * ktime_to_ns(cfs_b->period);
+- cfs_b->expires_seq++;
+ hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED);
+ }
+
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -334,8 +334,6 @@ struct cfs_bandwidth {
+ u64 quota;
+ u64 runtime;
+ s64 hierarchical_quota;
+- u64 runtime_expires;
+- int expires_seq;
+
+ short idle;
+ short period_active;
+@@ -555,8 +553,6 @@ struct cfs_rq {
+
+ #ifdef CONFIG_CFS_BANDWIDTH
+ int runtime_enabled;
+- int expires_seq;
+- u64 runtime_expires;
+ s64 runtime_remaining;
+
+ u64 throttled_clock;
--- /dev/null
+From 763a9ec06c409dcde2a761aac4bb83ff3938e0b3 Mon Sep 17 00:00:00 2001
+From: Qian Cai <cai@lca.pw>
+Date: Tue, 20 Aug 2019 14:40:55 -0400
+Subject: sched/fair: Fix -Wunused-but-set-variable warnings
+
+From: Qian Cai <cai@lca.pw>
+
+commit 763a9ec06c409dcde2a761aac4bb83ff3938e0b3 upstream.
+
+Commit:
+
+ de53fd7aedb1 ("sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices")
+
+introduced a few compilation warnings:
+
+ kernel/sched/fair.c: In function '__refill_cfs_bandwidth_runtime':
+ kernel/sched/fair.c:4365:6: warning: variable 'now' set but not used [-Wunused-but-set-variable]
+ kernel/sched/fair.c: In function 'start_cfs_bandwidth':
+ kernel/sched/fair.c:4992:6: warning: variable 'overrun' set but not used [-Wunused-but-set-variable]
+
+Also, __refill_cfs_bandwidth_runtime() does no longer update the
+expiration time, so fix the comments accordingly.
+
+Signed-off-by: Qian Cai <cai@lca.pw>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Ben Segall <bsegall@google.com>
+Reviewed-by: Dave Chiluk <chiluk+linux@indeed.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: pauld@redhat.com
+Fixes: de53fd7aedb1 ("sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices")
+Link: https://lkml.kernel.org/r/1566326455-8038-1-git-send-email-cai@lca.pw
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ kernel/sched/fair.c | 19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -4305,21 +4305,16 @@ static inline u64 sched_cfs_bandwidth_sl
+ }
+
+ /*
+- * Replenish runtime according to assigned quota and update expiration time.
+- * We use sched_clock_cpu directly instead of rq->clock to avoid adding
+- * additional synchronization around rq->lock.
++ * Replenish runtime according to assigned quota. We use sched_clock_cpu
++ * directly instead of rq->clock to avoid adding additional synchronization
++ * around rq->lock.
+ *
+ * requires cfs_b->lock
+ */
+ void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
+ {
+- u64 now;
+-
+- if (cfs_b->quota == RUNTIME_INF)
+- return;
+-
+- now = sched_clock_cpu(smp_processor_id());
+- cfs_b->runtime = cfs_b->quota;
++ if (cfs_b->quota != RUNTIME_INF)
++ cfs_b->runtime = cfs_b->quota;
+ }
+
+ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
+@@ -4924,15 +4919,13 @@ static void init_cfs_rq_runtime(struct c
+
+ void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
+ {
+- u64 overrun;
+-
+ lockdep_assert_held(&cfs_b->lock);
+
+ if (cfs_b->period_active)
+ return;
+
+ cfs_b->period_active = 1;
+- overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
++ hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
+ hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED);
+ }
+
configfs-new-object-reprsenting-tree-fragments.patch
configfs-provide-exclusion-between-io-and-removals.patch
configfs-fix-a-deadlock-in-configfs_symlink.patch
+alsa-usb-audio-more-validations-of-descriptor-units.patch
+alsa-usb-audio-simplify-parse_audio_unit.patch
+alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch
+alsa-usb-audio-remove-superfluous-blength-checks.patch
+alsa-usb-audio-clean-up-check_input_term.patch
+alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch
+alsa-usb-audio-remove-some-dead-code.patch
+alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch
+sched-fair-fix-low-cpu-usage-with-high-throttling-by-removing-expiration-of-cpu-local-slices.patch
+sched-fair-fix-wunused-but-set-variable-warnings.patch
+usbip-fix-vhci_urb_enqueue-urb-null-transfer-buffer-error-path.patch
+usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch
--- /dev/null
+From 2c904963b1dd2acd4bc785b6c72e10a6283c2081 Mon Sep 17 00:00:00 2001
+From: Shuah Khan <shuah@kernel.org>
+Date: Thu, 24 Jan 2019 14:46:42 -0700
+Subject: usbip: Fix vhci_urb_enqueue() URB null transfer buffer error path
+
+From: Shuah Khan <shuah@kernel.org>
+
+commit 2c904963b1dd2acd4bc785b6c72e10a6283c2081 upstream.
+
+Fix vhci_urb_enqueue() to print debug msg and return error instead of
+failing with BUG_ON.
+
+Signed-off-by: Shuah Khan <shuah@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/vhci_hcd.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/usbip/vhci_hcd.c
++++ b/drivers/usb/usbip/vhci_hcd.c
+@@ -702,8 +702,10 @@ static int vhci_urb_enqueue(struct usb_h
+ }
+ vdev = &vhci_hcd->vdev[portnum-1];
+
+- /* patch to usb_sg_init() is in 2.5.60 */
+- BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
++ if (!urb->transfer_buffer && urb->transfer_buffer_length) {
++ dev_dbg(dev, "Null URB transfer buffer\n");
++ return -EINVAL;
++ }
+
+ spin_lock_irqsave(&vhci->lock, flags);
+
--- /dev/null
+From ea44d190764b4422af4d1c29eaeb9e69e353b406 Mon Sep 17 00:00:00 2001
+From: Suwan Kim <suwan.kim027@gmail.com>
+Date: Wed, 28 Aug 2019 12:27:41 +0900
+Subject: usbip: Implement SG support to vhci-hcd and stub driver
+
+From: Suwan Kim <suwan.kim027@gmail.com>
+
+commit ea44d190764b4422af4d1c29eaeb9e69e353b406 upstream.
+
+There are bugs on vhci with usb 3.0 storage device. In USB, each SG
+list entry buffer should be divisible by the bulk max packet size.
+But with native SG support, this problem doesn't matter because the
+SG buffer is treated as contiguous buffer. But without native SG
+support, USB storage driver breaks SG list into several URBs and the
+error occurs because of a buffer size of URB that cannot be divided
+by the bulk max packet size. The error situation is as follows.
+
+When USB Storage driver requests 31.5 KB data and has SG list which
+has 3584 bytes buffer followed by 7 4096 bytes buffer for some
+reason. USB Storage driver splits this SG list into several URBs
+because VHCI doesn't support SG and sends them separately. So the
+first URB buffer size is 3584 bytes. When receiving data from device,
+USB 3.0 device sends data packet of 1024 bytes size because the max
+packet size of BULK pipe is 1024 bytes. So device sends 4096 bytes.
+But the first URB buffer has only 3584 bytes buffer size. So host
+controller terminates the transfer even though there is more data to
+receive. So, vhci needs to support SG transfer to prevent this error.
+
+In this patch, vhci supports SG regardless of whether the server's
+host controller supports SG or not, because stub driver splits SG
+list into several URBs if the server's host controller doesn't
+support SG.
+
+To support SG, vhci sets URB_DMA_MAP_SG flag in urb->transfer_flags
+if URB has SG list and this flag will tell stub driver to use SG
+list. After receiving urb from stub driver, vhci clear URB_DMA_MAP_SG
+flag to avoid unnecessary DMA unmapping in HCD.
+
+vhci sends each SG list entry to stub driver. Then, stub driver sees
+the total length of the buffer and allocates SG table and pages
+according to the total buffer length calling sgl_alloc(). After stub
+driver receives completed URB, it again sends each SG list entry to
+vhci.
+
+If the server's host controller doesn't support SG, stub driver
+breaks a single SG request into several URBs and submits them to
+the server's host controller. When all the split URBs are completed,
+stub driver reassembles the URBs into a single return command and
+sends it to vhci.
+
+Moreover, in the situation where vhci supports SG, but stub driver
+does not, or vice versa, usbip works normally. Because there is no
+protocol modification, there is no problem in communication between
+server and client even if the one has a kernel without SG support.
+
+In the case of vhci supports SG and stub driver doesn't, because
+vhci sends only the total length of the buffer to stub driver as
+it did before the patch applied, stub driver only needs to allocate
+the required length of buffers using only kmalloc() regardless of
+whether vhci supports SG or not. But stub driver has to allocate
+buffer with kmalloc() as much as the total length of SG buffer which
+is quite huge when vhci sends SG request, so it has overhead in
+buffer allocation in this situation.
+
+If stub driver needs to send data buffer to vhci because of IN pipe,
+stub driver also sends only total length of buffer as metadata and
+then sends real data as vhci does. Then vhci receive data from stub
+driver and store it to the corresponding buffer of SG list entry.
+
+And for the case of stub driver supports SG and vhci doesn't, since
+the USB storage driver checks that vhci doesn't support SG and sends
+the request to stub driver by splitting the SG list into multiple
+URBs, stub driver allocates a buffer for each URB with kmalloc() as
+it did before this patch.
+
+* Test environment
+
+Test uses two difference machines and two different kernel version
+to make mismatch situation between the client and the server where
+vhci supports SG, but stub driver does not, or vice versa. All tests
+are conducted in both full SG support that both vhci and stub support
+SG and half SG support that is the mismatch situation. Test kernel
+version is 5.3-rc6 with commit "usb: add a HCD_DMA flag instead of
+guestimating DMA capabilities" to avoid unnecessary DMA mapping and
+unmapping.
+
+ - Test kernel version
+ - 5.3-rc6 with SG support
+ - 5.1.20-200.fc29.x86_64 without SG support
+
+* SG support test
+
+ - Test devices
+ - Super-speed storage device - SanDisk Ultra USB 3.0
+ - High-speed storage device - SMI corporation USB 2.0 flash drive
+
+ - Test description
+
+Test read and write operation of mass storage device that uses the
+BULK transfer. In test, the client reads and writes files whose size
+is over 1G and it works normally.
+
+* Regression test
+
+ - Test devices
+ - Super-speed device - Logitech Brio webcam
+ - High-speed device - Logitech C920 HD Pro webcam
+ - Full-speed device - Logitech bluetooth mouse
+ - Britz BR-Orion speaker
+ - Low-speed device - Logitech wired mouse
+
+ - Test description
+
+Moving and click test for mouse. To test the webcam, use gnome-cheese.
+To test the speaker, play music and video on the client. All works
+normally.
+
+* VUDC compatibility test
+
+VUDC also works well with this patch. Tests are done with two USB
+gadget created by CONFIGFS USB gadget. Both use the BULK pipe.
+
+ 1. Serial gadget
+ 2. Mass storage gadget
+
+ - Serial gadget test
+
+Serial gadget on the host sends and receives data using cat command
+on the /dev/ttyGS<N>. The client uses minicom to communicate with
+the serial gadget.
+
+ - Mass storage gadget test
+
+After connecting the gadget with vhci, use "dd" to test read and
+write operation on the client side.
+
+Read - dd if=/dev/sd<N> iflag=direct of=/dev/null bs=1G count=1
+Write - dd if=<my file path> iflag=direct of=/dev/sd<N> bs=1G count=1
+
+Signed-off-by: Suwan Kim <suwan.kim027@gmail.com>
+Acked-by: Shuah khan <skhan@linuxfoundation.org>
+Link: https://lore.kernel.org/r/20190828032741.12234-1-suwan.kim027@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/stub.h | 7 +
+ drivers/usb/usbip/stub_main.c | 57 ++++++++---
+ drivers/usb/usbip/stub_rx.c | 202 +++++++++++++++++++++++++++------------
+ drivers/usb/usbip/stub_tx.c | 99 ++++++++++++++-----
+ drivers/usb/usbip/usbip_common.c | 59 +++++++----
+ drivers/usb/usbip/vhci_hcd.c | 12 ++
+ drivers/usb/usbip/vhci_rx.c | 3
+ drivers/usb/usbip/vhci_tx.c | 66 ++++++++++--
+ 8 files changed, 379 insertions(+), 126 deletions(-)
+
+--- a/drivers/usb/usbip/stub.h
++++ b/drivers/usb/usbip/stub.h
+@@ -52,7 +52,11 @@ struct stub_priv {
+ unsigned long seqnum;
+ struct list_head list;
+ struct stub_device *sdev;
+- struct urb *urb;
++ struct urb **urbs;
++ struct scatterlist *sgl;
++ int num_urbs;
++ int completed_urbs;
++ int urb_status;
+
+ int unlinking;
+ };
+@@ -86,6 +90,7 @@ extern struct usb_device_driver stub_dri
+ struct bus_id_priv *get_busid_priv(const char *busid);
+ void put_busid_priv(struct bus_id_priv *bid);
+ int del_match_busid(char *busid);
++void stub_free_priv_and_urb(struct stub_priv *priv);
+ void stub_device_cleanup_urbs(struct stub_device *sdev);
+
+ /* stub_rx.c */
+--- a/drivers/usb/usbip/stub_main.c
++++ b/drivers/usb/usbip/stub_main.c
+@@ -6,6 +6,7 @@
+ #include <linux/string.h>
+ #include <linux/module.h>
+ #include <linux/device.h>
++#include <linux/scatterlist.h>
+
+ #include "usbip_common.h"
+ #include "stub.h"
+@@ -283,13 +284,49 @@ static struct stub_priv *stub_priv_pop_f
+ struct stub_priv *priv, *tmp;
+
+ list_for_each_entry_safe(priv, tmp, listhead, list) {
+- list_del(&priv->list);
++ list_del_init(&priv->list);
+ return priv;
+ }
+
+ return NULL;
+ }
+
++void stub_free_priv_and_urb(struct stub_priv *priv)
++{
++ struct urb *urb;
++ int i;
++
++ for (i = 0; i < priv->num_urbs; i++) {
++ urb = priv->urbs[i];
++
++ if (!urb)
++ return;
++
++ kfree(urb->setup_packet);
++ urb->setup_packet = NULL;
++
++
++ if (urb->transfer_buffer && !priv->sgl) {
++ kfree(urb->transfer_buffer);
++ urb->transfer_buffer = NULL;
++ }
++
++ if (urb->num_sgs) {
++ sgl_free(urb->sg);
++ urb->sg = NULL;
++ urb->num_sgs = 0;
++ }
++
++ usb_free_urb(urb);
++ }
++ if (!list_empty(&priv->list))
++ list_del(&priv->list);
++ if (priv->sgl)
++ sgl_free(priv->sgl);
++ kfree(priv->urbs);
++ kmem_cache_free(stub_priv_cache, priv);
++}
++
+ static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
+ {
+ unsigned long flags;
+@@ -316,25 +353,15 @@ done:
+ void stub_device_cleanup_urbs(struct stub_device *sdev)
+ {
+ struct stub_priv *priv;
+- struct urb *urb;
++ int i;
+
+ dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n");
+
+ while ((priv = stub_priv_pop(sdev))) {
+- urb = priv->urb;
+- dev_dbg(&sdev->udev->dev, "free urb seqnum %lu\n",
+- priv->seqnum);
+- usb_kill_urb(urb);
+-
+- kmem_cache_free(stub_priv_cache, priv);
++ for (i = 0; i < priv->num_urbs; i++)
++ usb_kill_urb(priv->urbs[i]);
+
+- kfree(urb->transfer_buffer);
+- urb->transfer_buffer = NULL;
+-
+- kfree(urb->setup_packet);
+- urb->setup_packet = NULL;
+-
+- usb_free_urb(urb);
++ stub_free_priv_and_urb(priv);
+ }
+ }
+
+--- a/drivers/usb/usbip/stub_rx.c
++++ b/drivers/usb/usbip/stub_rx.c
+@@ -7,6 +7,7 @@
+ #include <linux/kthread.h>
+ #include <linux/usb.h>
+ #include <linux/usb/hcd.h>
++#include <linux/scatterlist.h>
+
+ #include "usbip_common.h"
+ #include "stub.h"
+@@ -201,7 +202,7 @@ static void tweak_special_requests(struc
+ static int stub_recv_cmd_unlink(struct stub_device *sdev,
+ struct usbip_header *pdu)
+ {
+- int ret;
++ int ret, i;
+ unsigned long flags;
+ struct stub_priv *priv;
+
+@@ -246,12 +247,14 @@ static int stub_recv_cmd_unlink(struct s
+ * so a driver in a client host will know the failure
+ * of the unlink request ?
+ */
+- ret = usb_unlink_urb(priv->urb);
+- if (ret != -EINPROGRESS)
+- dev_err(&priv->urb->dev->dev,
+- "failed to unlink a urb # %lu, ret %d\n",
+- priv->seqnum, ret);
+-
++ for (i = priv->completed_urbs; i < priv->num_urbs; i++) {
++ ret = usb_unlink_urb(priv->urbs[i]);
++ if (ret != -EINPROGRESS)
++ dev_err(&priv->urbs[i]->dev->dev,
++ "failed to unlink %d/%d urb of seqnum %lu, ret %d\n",
++ i + 1, priv->num_urbs,
++ priv->seqnum, ret);
++ }
+ return 0;
+ }
+
+@@ -433,14 +436,36 @@ static void masking_bogus_flags(struct u
+ urb->transfer_flags &= allowed;
+ }
+
++static int stub_recv_xbuff(struct usbip_device *ud, struct stub_priv *priv)
++{
++ int ret;
++ int i;
++
++ for (i = 0; i < priv->num_urbs; i++) {
++ ret = usbip_recv_xbuff(ud, priv->urbs[i]);
++ if (ret < 0)
++ break;
++ }
++
++ return ret;
++}
++
+ static void stub_recv_cmd_submit(struct stub_device *sdev,
+ struct usbip_header *pdu)
+ {
+- int ret;
+ struct stub_priv *priv;
+ struct usbip_device *ud = &sdev->ud;
+ struct usb_device *udev = sdev->udev;
++ struct scatterlist *sgl = NULL, *sg;
++ void *buffer = NULL;
++ unsigned long long buf_len;
++ int nents;
++ int num_urbs = 1;
+ int pipe = get_pipe(sdev, pdu);
++ int use_sg = pdu->u.cmd_submit.transfer_flags & URB_DMA_MAP_SG;
++ int support_sg = 1;
++ int np = 0;
++ int ret, i;
+
+ if (pipe == -1)
+ return;
+@@ -449,76 +474,139 @@ static void stub_recv_cmd_submit(struct
+ if (!priv)
+ return;
+
+- /* setup a urb */
+- if (usb_pipeisoc(pipe))
+- priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
+- GFP_KERNEL);
+- else
+- priv->urb = usb_alloc_urb(0, GFP_KERNEL);
++ buf_len = (unsigned long long)pdu->u.cmd_submit.transfer_buffer_length;
+
+- if (!priv->urb) {
+- usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+- return;
++ /* allocate urb transfer buffer, if needed */
++ if (buf_len) {
++ if (use_sg) {
++ sgl = sgl_alloc(buf_len, GFP_KERNEL, &nents);
++ if (!sgl)
++ goto err_malloc;
++ } else {
++ buffer = kzalloc(buf_len, GFP_KERNEL);
++ if (!buffer)
++ goto err_malloc;
++ }
+ }
+
+- /* allocate urb transfer buffer, if needed */
+- if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
+- priv->urb->transfer_buffer =
+- kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
+- GFP_KERNEL);
+- if (!priv->urb->transfer_buffer) {
++ /* Check if the server's HCD supports SG */
++ if (use_sg && !udev->bus->sg_tablesize) {
++ /*
++ * If the server's HCD doesn't support SG, break a single SG
++ * request into several URBs and map each SG list entry to
++ * corresponding URB buffer. The previously allocated SG
++ * list is stored in priv->sgl (If the server's HCD support SG,
++ * SG list is stored only in urb->sg) and it is used as an
++ * indicator that the server split single SG request into
++ * several URBs. Later, priv->sgl is used by stub_complete() and
++ * stub_send_ret_submit() to reassemble the divied URBs.
++ */
++ support_sg = 0;
++ num_urbs = nents;
++ priv->completed_urbs = 0;
++ pdu->u.cmd_submit.transfer_flags &= ~URB_DMA_MAP_SG;
++ }
++
++ /* allocate urb array */
++ priv->num_urbs = num_urbs;
++ priv->urbs = kmalloc_array(num_urbs, sizeof(*priv->urbs), GFP_KERNEL);
++ if (!priv->urbs)
++ goto err_urbs;
++
++ /* setup a urb */
++ if (support_sg) {
++ if (usb_pipeisoc(pipe))
++ np = pdu->u.cmd_submit.number_of_packets;
++
++ priv->urbs[0] = usb_alloc_urb(np, GFP_KERNEL);
++ if (!priv->urbs[0])
++ goto err_urb;
++
++ if (buf_len) {
++ if (use_sg) {
++ priv->urbs[0]->sg = sgl;
++ priv->urbs[0]->num_sgs = nents;
++ priv->urbs[0]->transfer_buffer = NULL;
++ } else {
++ priv->urbs[0]->transfer_buffer = buffer;
++ }
++ }
++
++ /* copy urb setup packet */
++ priv->urbs[0]->setup_packet = kmemdup(&pdu->u.cmd_submit.setup,
++ 8, GFP_KERNEL);
++ if (!priv->urbs[0]->setup_packet) {
+ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+ return;
+ }
+- }
+
+- /* copy urb setup packet */
+- priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8,
+- GFP_KERNEL);
+- if (!priv->urb->setup_packet) {
+- dev_err(&udev->dev, "allocate setup_packet\n");
+- usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+- return;
++ usbip_pack_pdu(pdu, priv->urbs[0], USBIP_CMD_SUBMIT, 0);
++ } else {
++ for_each_sg(sgl, sg, nents, i) {
++ priv->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
++ /* The URBs which is previously allocated will be freed
++ * in stub_device_cleanup_urbs() if error occurs.
++ */
++ if (!priv->urbs[i])
++ goto err_urb;
++
++ usbip_pack_pdu(pdu, priv->urbs[i], USBIP_CMD_SUBMIT, 0);
++ priv->urbs[i]->transfer_buffer = sg_virt(sg);
++ priv->urbs[i]->transfer_buffer_length = sg->length;
++ }
++ priv->sgl = sgl;
+ }
+
+- /* set other members from the base header of pdu */
+- priv->urb->context = (void *) priv;
+- priv->urb->dev = udev;
+- priv->urb->pipe = pipe;
+- priv->urb->complete = stub_complete;
++ for (i = 0; i < num_urbs; i++) {
++ /* set other members from the base header of pdu */
++ priv->urbs[i]->context = (void *) priv;
++ priv->urbs[i]->dev = udev;
++ priv->urbs[i]->pipe = pipe;
++ priv->urbs[i]->complete = stub_complete;
+
+- usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0);
++ /* no need to submit an intercepted request, but harmless? */
++ tweak_special_requests(priv->urbs[i]);
+
++ masking_bogus_flags(priv->urbs[i]);
++ }
+
+- if (usbip_recv_xbuff(ud, priv->urb) < 0)
++ if (stub_recv_xbuff(ud, priv) < 0)
+ return;
+
+- if (usbip_recv_iso(ud, priv->urb) < 0)
++ if (usbip_recv_iso(ud, priv->urbs[0]) < 0)
+ return;
+
+- /* no need to submit an intercepted request, but harmless? */
+- tweak_special_requests(priv->urb);
+-
+- masking_bogus_flags(priv->urb);
+ /* urb is now ready to submit */
+- ret = usb_submit_urb(priv->urb, GFP_KERNEL);
+-
+- if (ret == 0)
+- usbip_dbg_stub_rx("submit urb ok, seqnum %u\n",
+- pdu->base.seqnum);
+- else {
+- dev_err(&udev->dev, "submit_urb error, %d\n", ret);
+- usbip_dump_header(pdu);
+- usbip_dump_urb(priv->urb);
++ for (i = 0; i < priv->num_urbs; i++) {
++ ret = usb_submit_urb(priv->urbs[i], GFP_KERNEL);
+
+- /*
+- * Pessimistic.
+- * This connection will be discarded.
+- */
+- usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
++ if (ret == 0)
++ usbip_dbg_stub_rx("submit urb ok, seqnum %u\n",
++ pdu->base.seqnum);
++ else {
++ dev_err(&udev->dev, "submit_urb error, %d\n", ret);
++ usbip_dump_header(pdu);
++ usbip_dump_urb(priv->urbs[i]);
++
++ /*
++ * Pessimistic.
++ * This connection will be discarded.
++ */
++ usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
++ break;
++ }
+ }
+
+ usbip_dbg_stub_rx("Leave\n");
++ return;
++
++err_urb:
++ kfree(priv->urbs);
++err_urbs:
++ kfree(buffer);
++ sgl_free(sgl);
++err_malloc:
++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+ }
+
+ /* recv a pdu */
+--- a/drivers/usb/usbip/stub_tx.c
++++ b/drivers/usb/usbip/stub_tx.c
+@@ -5,25 +5,11 @@
+
+ #include <linux/kthread.h>
+ #include <linux/socket.h>
++#include <linux/scatterlist.h>
+
+ #include "usbip_common.h"
+ #include "stub.h"
+
+-static void stub_free_priv_and_urb(struct stub_priv *priv)
+-{
+- struct urb *urb = priv->urb;
+-
+- kfree(urb->setup_packet);
+- urb->setup_packet = NULL;
+-
+- kfree(urb->transfer_buffer);
+- urb->transfer_buffer = NULL;
+-
+- list_del(&priv->list);
+- kmem_cache_free(stub_priv_cache, priv);
+- usb_free_urb(urb);
+-}
+-
+ /* be in spin_lock_irqsave(&sdev->priv_lock, flags) */
+ void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
+ __u32 status)
+@@ -85,6 +71,22 @@ void stub_complete(struct urb *urb)
+ break;
+ }
+
++ /*
++ * If the server breaks single SG request into the several URBs, the
++ * URBs must be reassembled before sending completed URB to the vhci.
++ * Don't wake up the tx thread until all the URBs are completed.
++ */
++ if (priv->sgl) {
++ priv->completed_urbs++;
++
++ /* Only save the first error status */
++ if (urb->status && !priv->urb_status)
++ priv->urb_status = urb->status;
++
++ if (priv->completed_urbs < priv->num_urbs)
++ return;
++ }
++
+ /* link a urb to the queue of tx. */
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+ if (sdev->ud.tcp_socket == NULL) {
+@@ -156,18 +158,22 @@ static int stub_send_ret_submit(struct s
+ size_t total_size = 0;
+
+ while ((priv = dequeue_from_priv_tx(sdev)) != NULL) {
+- int ret;
+- struct urb *urb = priv->urb;
++ struct urb *urb = priv->urbs[0];
+ struct usbip_header pdu_header;
+ struct usbip_iso_packet_descriptor *iso_buffer = NULL;
+ struct kvec *iov = NULL;
++ struct scatterlist *sg;
++ u32 actual_length = 0;
+ int iovnum = 0;
++ int ret;
++ int i;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+ memset(&msg, 0, sizeof(msg));
+
+- if (urb->actual_length > 0 && !urb->transfer_buffer) {
++ if (urb->actual_length > 0 && !urb->transfer_buffer &&
++ !urb->num_sgs) {
+ dev_err(&sdev->udev->dev,
+ "urb: actual_length %d transfer_buffer null\n",
+ urb->actual_length);
+@@ -176,6 +182,11 @@ static int stub_send_ret_submit(struct s
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+ iovnum = 2 + urb->number_of_packets;
++ else if (usb_pipein(urb->pipe) && urb->actual_length > 0 &&
++ urb->num_sgs)
++ iovnum = 1 + urb->num_sgs;
++ else if (usb_pipein(urb->pipe) && priv->sgl)
++ iovnum = 1 + priv->num_urbs;
+ else
+ iovnum = 2;
+
+@@ -192,6 +203,15 @@ static int stub_send_ret_submit(struct s
+ setup_ret_submit_pdu(&pdu_header, urb);
+ usbip_dbg_stub_tx("setup txdata seqnum: %d\n",
+ pdu_header.base.seqnum);
++
++ if (priv->sgl) {
++ for (i = 0; i < priv->num_urbs; i++)
++ actual_length += priv->urbs[i]->actual_length;
++
++ pdu_header.u.ret_submit.status = priv->urb_status;
++ pdu_header.u.ret_submit.actual_length = actual_length;
++ }
++
+ usbip_header_correct_endian(&pdu_header, 1);
+
+ iov[iovnum].iov_base = &pdu_header;
+@@ -200,12 +220,47 @@ static int stub_send_ret_submit(struct s
+ txsize += sizeof(pdu_header);
+
+ /* 2. setup transfer buffer */
+- if (usb_pipein(urb->pipe) &&
++ if (usb_pipein(urb->pipe) && priv->sgl) {
++ /* If the server split a single SG request into several
++ * URBs because the server's HCD doesn't support SG,
++ * reassemble the split URB buffers into a single
++ * return command.
++ */
++ for (i = 0; i < priv->num_urbs; i++) {
++ iov[iovnum].iov_base =
++ priv->urbs[i]->transfer_buffer;
++ iov[iovnum].iov_len =
++ priv->urbs[i]->actual_length;
++ iovnum++;
++ }
++ txsize += actual_length;
++ } else if (usb_pipein(urb->pipe) &&
+ usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
+ urb->actual_length > 0) {
+- iov[iovnum].iov_base = urb->transfer_buffer;
+- iov[iovnum].iov_len = urb->actual_length;
+- iovnum++;
++ if (urb->num_sgs) {
++ unsigned int copy = urb->actual_length;
++ int size;
++
++ for_each_sg(urb->sg, sg, urb->num_sgs, i) {
++ if (copy == 0)
++ break;
++
++ if (copy < sg->length)
++ size = copy;
++ else
++ size = sg->length;
++
++ iov[iovnum].iov_base = sg_virt(sg);
++ iov[iovnum].iov_len = size;
++
++ iovnum++;
++ copy -= size;
++ }
++ } else {
++ iov[iovnum].iov_base = urb->transfer_buffer;
++ iov[iovnum].iov_len = urb->actual_length;
++ iovnum++;
++ }
+ txsize += urb->actual_length;
+ } else if (usb_pipein(urb->pipe) &&
+ usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+--- a/drivers/usb/usbip/usbip_common.c
++++ b/drivers/usb/usbip/usbip_common.c
+@@ -680,8 +680,12 @@ EXPORT_SYMBOL_GPL(usbip_pad_iso);
+ /* some members of urb must be substituted before. */
+ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
+ {
+- int ret;
++ struct scatterlist *sg;
++ int ret = 0;
++ int recv;
+ int size;
++ int copy;
++ int i;
+
+ if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) {
+ /* the direction of urb must be OUT. */
+@@ -701,29 +705,48 @@ int usbip_recv_xbuff(struct usbip_device
+ if (!(size > 0))
+ return 0;
+
+- if (size > urb->transfer_buffer_length) {
++ if (size > urb->transfer_buffer_length)
+ /* should not happen, probably malicious packet */
+- if (ud->side == USBIP_STUB) {
+- usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+- return 0;
+- } else {
+- usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+- return -EPIPE;
+- }
+- }
++ goto error;
++
++ if (urb->num_sgs) {
++ copy = size;
++ for_each_sg(urb->sg, sg, urb->num_sgs, i) {
++ int recv_size;
++
++ if (copy < sg->length)
++ recv_size = copy;
++ else
++ recv_size = sg->length;
++
++ recv = usbip_recv(ud->tcp_socket, sg_virt(sg),
++ recv_size);
+
+- ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
+- if (ret != size) {
+- dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
+- if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) {
+- usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+- } else {
+- usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+- return -EPIPE;
++ if (recv != recv_size)
++ goto error;
++
++ copy -= recv;
++ ret += recv;
+ }
++
++ if (ret != size)
++ goto error;
++ } else {
++ ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
++ if (ret != size)
++ goto error;
+ }
+
+ return ret;
++
++error:
++ dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
++ if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC)
++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
++ else
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++
++ return -EPIPE;
+ }
+ EXPORT_SYMBOL_GPL(usbip_recv_xbuff);
+
+--- a/drivers/usb/usbip/vhci_hcd.c
++++ b/drivers/usb/usbip/vhci_hcd.c
+@@ -702,7 +702,8 @@ static int vhci_urb_enqueue(struct usb_h
+ }
+ vdev = &vhci_hcd->vdev[portnum-1];
+
+- if (!urb->transfer_buffer && urb->transfer_buffer_length) {
++ if (!urb->transfer_buffer && !urb->num_sgs &&
++ urb->transfer_buffer_length) {
+ dev_dbg(dev, "Null URB transfer buffer\n");
+ return -EINVAL;
+ }
+@@ -1148,6 +1149,15 @@ static int vhci_setup(struct usb_hcd *hc
+ hcd->speed = HCD_USB3;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER;
+ }
++
++ /*
++ * Support SG.
++ * sg_tablesize is an arbitrary value to alleviate memory pressure
++ * on the host.
++ */
++ hcd->self.sg_tablesize = 32;
++ hcd->self.no_sg_constraint = 1;
++
+ return 0;
+ }
+
+--- a/drivers/usb/usbip/vhci_rx.c
++++ b/drivers/usb/usbip/vhci_rx.c
+@@ -90,6 +90,9 @@ static void vhci_recv_ret_submit(struct
+ if (usbip_dbg_flag_vhci_rx)
+ usbip_dump_urb(urb);
+
++ if (urb->num_sgs)
++ urb->transfer_flags &= ~URB_DMA_MAP_SG;
++
+ usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum);
+
+ spin_lock_irqsave(&vhci->lock, flags);
+--- a/drivers/usb/usbip/vhci_tx.c
++++ b/drivers/usb/usbip/vhci_tx.c
+@@ -5,6 +5,7 @@
+
+ #include <linux/kthread.h>
+ #include <linux/slab.h>
++#include <linux/scatterlist.h>
+
+ #include "usbip_common.h"
+ #include "vhci.h"
+@@ -50,19 +51,23 @@ static struct vhci_priv *dequeue_from_pr
+
+ static int vhci_send_cmd_submit(struct vhci_device *vdev)
+ {
++ struct usbip_iso_packet_descriptor *iso_buffer = NULL;
+ struct vhci_priv *priv = NULL;
++ struct scatterlist *sg;
+
+ struct msghdr msg;
+- struct kvec iov[3];
++ struct kvec *iov;
+ size_t txsize;
+
+ size_t total_size = 0;
++ int iovnum;
++ int err = -ENOMEM;
++ int i;
+
+ while ((priv = dequeue_from_priv_tx(vdev)) != NULL) {
+ int ret;
+ struct urb *urb = priv->urb;
+ struct usbip_header pdu_header;
+- struct usbip_iso_packet_descriptor *iso_buffer = NULL;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+@@ -72,18 +77,45 @@ static int vhci_send_cmd_submit(struct v
+ usbip_dbg_vhci_tx("setup txdata urb seqnum %lu\n",
+ priv->seqnum);
+
++ if (urb->num_sgs && usb_pipeout(urb->pipe))
++ iovnum = 2 + urb->num_sgs;
++ else
++ iovnum = 3;
++
++ iov = kcalloc(iovnum, sizeof(*iov), GFP_KERNEL);
++ if (!iov) {
++ usbip_event_add(&vdev->ud, SDEV_EVENT_ERROR_MALLOC);
++ return -ENOMEM;
++ }
++
++ if (urb->num_sgs)
++ urb->transfer_flags |= URB_DMA_MAP_SG;
++
+ /* 1. setup usbip_header */
+ setup_cmd_submit_pdu(&pdu_header, urb);
+ usbip_header_correct_endian(&pdu_header, 1);
++ iovnum = 0;
+
+- iov[0].iov_base = &pdu_header;
+- iov[0].iov_len = sizeof(pdu_header);
++ iov[iovnum].iov_base = &pdu_header;
++ iov[iovnum].iov_len = sizeof(pdu_header);
+ txsize += sizeof(pdu_header);
++ iovnum++;
+
+ /* 2. setup transfer buffer */
+ if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) {
+- iov[1].iov_base = urb->transfer_buffer;
+- iov[1].iov_len = urb->transfer_buffer_length;
++ if (urb->num_sgs &&
++ !usb_endpoint_xfer_isoc(&urb->ep->desc)) {
++ for_each_sg(urb->sg, sg, urb->num_sgs, i) {
++ iov[iovnum].iov_base = sg_virt(sg);
++ iov[iovnum].iov_len = sg->length;
++ iovnum++;
++ }
++ } else {
++ iov[iovnum].iov_base = urb->transfer_buffer;
++ iov[iovnum].iov_len =
++ urb->transfer_buffer_length;
++ iovnum++;
++ }
+ txsize += urb->transfer_buffer_length;
+ }
+
+@@ -95,23 +127,26 @@ static int vhci_send_cmd_submit(struct v
+ if (!iso_buffer) {
+ usbip_event_add(&vdev->ud,
+ SDEV_EVENT_ERROR_MALLOC);
+- return -1;
++ goto err_iso_buffer;
+ }
+
+- iov[2].iov_base = iso_buffer;
+- iov[2].iov_len = len;
++ iov[iovnum].iov_base = iso_buffer;
++ iov[iovnum].iov_len = len;
++ iovnum++;
+ txsize += len;
+ }
+
+- ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
++ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, iovnum,
++ txsize);
+ if (ret != txsize) {
+ pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
+ txsize);
+- kfree(iso_buffer);
+ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+- return -1;
++ err = -EPIPE;
++ goto err_tx;
+ }
+
++ kfree(iov);
+ kfree(iso_buffer);
+ usbip_dbg_vhci_tx("send txdata\n");
+
+@@ -119,6 +154,13 @@ static int vhci_send_cmd_submit(struct v
+ }
+
+ return total_size;
++
++err_tx:
++ kfree(iso_buffer);
++err_iso_buffer:
++ kfree(iov);
++
++ return err;
+ }
+
+ static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)