Commit 9286e24b authored by Jerry Zhang's avatar Jerry Zhang Committed by Felipe Balbi

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: default avatarJerry Zhang <zhangjerry@google.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 7ecca2a4
...@@ -109,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f) ...@@ -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_transmit(struct f_midi *midi);
static void f_midi_rmidi_free(struct snd_rawmidi *rmidi); 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_UAC_AC_HEADER_DESCRIPTOR(1);
DECLARE_USB_MIDI_OUT_JACK_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, \ ...@@ -1102,7 +1103,7 @@ static ssize_t f_midi_opts_##name##_store(struct config_item *item, \
u32 num; \ u32 num; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
if (opts->refcnt) { \ if (opts->refcnt > 1) { \
ret = -EBUSY; \ ret = -EBUSY; \
goto end; \ goto end; \
} \ } \
...@@ -1157,7 +1158,7 @@ static ssize_t f_midi_opts_id_store(struct config_item *item, ...@@ -1157,7 +1158,7 @@ static ssize_t f_midi_opts_id_store(struct config_item *item,
char *c; char *c;
mutex_lock(&opts->lock); mutex_lock(&opts->lock);
if (opts->refcnt) { if (opts->refcnt > 1) {
ret = -EBUSY; ret = -EBUSY;
goto end; goto end;
} }
...@@ -1198,13 +1199,21 @@ static const struct config_item_type midi_func_type = { ...@@ -1198,13 +1199,21 @@ static const struct config_item_type midi_func_type = {
static void f_midi_free_inst(struct usb_function_instance *f) static void f_midi_free_inst(struct usb_function_instance *f)
{ {
struct f_midi_opts *opts; struct f_midi_opts *opts;
bool free = false;
opts = container_of(f, struct f_midi_opts, func_inst); opts = container_of(f, struct f_midi_opts, func_inst);
mutex_lock(&opts->lock);
if (!--opts->refcnt) {
free = true;
}
mutex_unlock(&opts->lock);
if (free) {
if (opts->id_allocated) if (opts->id_allocated)
kfree(opts->id); kfree(opts->id);
kfree(opts); kfree(opts);
}
} }
static struct usb_function_instance *f_midi_alloc_inst(void) static struct usb_function_instance *f_midi_alloc_inst(void)
...@@ -1223,6 +1232,7 @@ 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->qlen = 32;
opts->in_ports = 1; opts->in_ports = 1;
opts->out_ports = 1; opts->out_ports = 1;
opts->refcnt = 1;
config_group_init_type_name(&opts->func_inst.group, "", config_group_init_type_name(&opts->func_inst.group, "",
&midi_func_type); &midi_func_type);
...@@ -1234,6 +1244,7 @@ static void f_midi_free(struct usb_function *f) ...@@ -1234,6 +1244,7 @@ static void f_midi_free(struct usb_function *f)
{ {
struct f_midi *midi; struct f_midi *midi;
struct f_midi_opts *opts; struct f_midi_opts *opts;
bool free = false;
midi = func_to_midi(f); midi = func_to_midi(f);
opts = container_of(f->fi, struct f_midi_opts, func_inst); opts = container_of(f->fi, struct f_midi_opts, func_inst);
...@@ -1242,9 +1253,12 @@ static void f_midi_free(struct usb_function *f) ...@@ -1242,9 +1253,12 @@ static void f_midi_free(struct usb_function *f)
kfree(midi->id); kfree(midi->id);
kfifo_free(&midi->in_req_fifo); kfifo_free(&midi->in_req_fifo);
kfree(midi); kfree(midi);
--opts->refcnt; free = true;
} }
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
if (free)
f_midi_free_inst(&opts->func_inst);
} }
static void f_midi_rmidi_free(struct snd_rawmidi *rmidi) static void f_midi_rmidi_free(struct snd_rawmidi *rmidi)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment