From 9286e24b837151a5a59e7403cea3e4a2c33ba225 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Fri, 30 Mar 2018 17:54:24 -0700 Subject: [PATCH] usb: gadget: f_midi: Use refcount when freeing f_midi_opts Currently, the midi function is not freed until it is both removed from the config and released by the user. Since the user could take a long time to release the card, it's possible that the function could be unlinked and thus f_midi_opts would be null when freeing f_midi. Thus, refcount f_midi_opts and only free it when it is unlinked and all f_midis have been freed. Signed-off-by: Jerry Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index e8f35db..f806997 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -109,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f) static void f_midi_transmit(struct f_midi *midi); static void f_midi_rmidi_free(struct snd_rawmidi *rmidi); +static void f_midi_free_inst(struct usb_function_instance *f); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); @@ -1102,7 +1103,7 @@ static ssize_t f_midi_opts_##name##_store(struct config_item *item, \ u32 num; \ \ mutex_lock(&opts->lock); \ - if (opts->refcnt) { \ + if (opts->refcnt > 1) { \ ret = -EBUSY; \ goto end; \ } \ @@ -1157,7 +1158,7 @@ static ssize_t f_midi_opts_id_store(struct config_item *item, char *c; mutex_lock(&opts->lock); - if (opts->refcnt) { + if (opts->refcnt > 1) { ret = -EBUSY; goto end; } @@ -1198,13 +1199,21 @@ static const struct config_item_type midi_func_type = { static void f_midi_free_inst(struct usb_function_instance *f) { struct f_midi_opts *opts; + bool free = false; opts = container_of(f, struct f_midi_opts, func_inst); - if (opts->id_allocated) - kfree(opts->id); + mutex_lock(&opts->lock); + if (!--opts->refcnt) { + free = true; + } + mutex_unlock(&opts->lock); - kfree(opts); + if (free) { + if (opts->id_allocated) + kfree(opts->id); + kfree(opts); + } } static struct usb_function_instance *f_midi_alloc_inst(void) @@ -1223,6 +1232,7 @@ static struct usb_function_instance *f_midi_alloc_inst(void) opts->qlen = 32; opts->in_ports = 1; opts->out_ports = 1; + opts->refcnt = 1; config_group_init_type_name(&opts->func_inst.group, "", &midi_func_type); @@ -1234,6 +1244,7 @@ static void f_midi_free(struct usb_function *f) { struct f_midi *midi; struct f_midi_opts *opts; + bool free = false; midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); @@ -1242,9 +1253,12 @@ static void f_midi_free(struct usb_function *f) kfree(midi->id); kfifo_free(&midi->in_req_fifo); kfree(midi); - --opts->refcnt; + free = true; } mutex_unlock(&opts->lock); + + if (free) + f_midi_free_inst(&opts->func_inst); } static void f_midi_rmidi_free(struct snd_rawmidi *rmidi) -- 2.7.4