diff options
author | Jerry Zhang <zhangjerry@google.com> | 2018-03-31 03:54:24 +0300 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2018-05-15 10:08:44 +0300 |
commit | 9286e24b837151a5a59e7403cea3e4a2c33ba225 (patch) | |
tree | e4707c84aa40d0262f832b34a08d43d471deb479 /drivers/usb/gadget | |
parent | 7ecca2a4080cb6b1fa174adc588fce9e9014c43c (diff) | |
download | linux-9286e24b837151a5a59e7403cea3e4a2c33ba225.tar.xz |
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 <zhangjerry@google.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/function/f_midi.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index e8f35db42394..f80699747ee0 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) |