Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65a0d43c authored by Mayank Rana's avatar Mayank Rana
Browse files

USB: gadget: f_mass_storage: Fix race condition using proper locking



fsg_common_free_luns() API is called from fsg_unbind() context when
composition switch or adbd is being killed which releases configured
LUNs (i.e. common->luns). common->luns are also being updated from
handle_exception() context when fsg_disable() invokes exception with
FSG_STATE_CONFIG_CHANGE value. In some cases it is observed that
common->luns are being updated from fsg_common_free_luns() when it is
already being used from handle_exception context. Hence fix this issue
by acquiring common->lock before freeing LUNs.

Also set common->nluns to zero after releaseing all LUNs.

CRs-Fixed: 863034
Change-Id: Iad26fe288f382e4d0b0e257aae348f6d80b45035
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent fb120d64
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -2494,6 +2494,7 @@ static void handle_exception(struct fsg_common *common)
	enum fsg_state		old_state;
	struct fsg_lun		*curlun;
	unsigned int		exception_req_tag;
	unsigned long		flags;

	/*
	 * Clear the existing signals.  Anything but SIGUSR1 is converted
@@ -2553,7 +2554,7 @@ static void handle_exception(struct fsg_common *common)
	 * Reset the I/O buffer states and pointers, the SCSI
	 * state, and the exception.  Then invoke the handler.
	 */
	spin_lock_irq(&common->lock);
	spin_lock_irqsave(&common->lock, flags);

	for (i = 0; i < common->fsg_num_buffers; ++i) {
		bh = &common->buffhds[i];
@@ -2579,7 +2580,7 @@ static void handle_exception(struct fsg_common *common)
		}
		common->state = FSG_STATE_IDLE;
	}
	spin_unlock_irq(&common->lock);
	spin_unlock_irqrestore(&common->lock, flags);

	/* Carry out any extra actions required for the exception */
	switch (old_state) {
@@ -2972,9 +2973,14 @@ void fsg_common_remove_luns(struct fsg_common *common)

void fsg_common_free_luns(struct fsg_common *common)
{
	unsigned long flags;

	fsg_common_remove_luns(common);
	spin_lock_irqsave(&common->lock, flags);
	kfree(common->luns);
	common->luns = NULL;
	common->nluns = 0;
	spin_unlock_irqrestore(&common->lock, flags);
}
EXPORT_SYMBOL_GPL(fsg_common_free_luns);