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

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
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -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,14 +1199,22 @@ 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);

	mutex_lock(&opts->lock);
	if (!--opts->refcnt) {
		free = true;
	}
	mutex_unlock(&opts->lock);

	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)