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

Commit 2e873d60 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: storage: Prevent race condition from stalling thread"

parents 11f18d01 0db878a3
Loading
Loading
Loading
Loading
+44 −1
Original line number Diff line number Diff line
@@ -646,12 +646,18 @@ static int sleep_thread(struct fsg_common *common, bool can_freeze)
			rc = -EINTR;
			break;
		}
		if (common->thread_wakeup_needed)
		spin_lock_irq(&common->lock);
		if (common->thread_wakeup_needed) {
			spin_unlock_irq(&common->lock);
			break;
		}
		spin_unlock_irq(&common->lock);
		schedule();
	}
	__set_current_state(TASK_RUNNING);
	spin_lock_irq(&common->lock);
	common->thread_wakeup_needed = 0;
	spin_unlock_irq(&common->lock);
	smp_rmb();	/* ensure the latest bh->state is visible */
	return rc;
}
@@ -712,12 +718,17 @@ static int do_read(struct fsg_common *common)
			     curlun->file_length - file_offset);

		/* Wait for the next buffer to become available */
		spin_lock_irq(&common->lock);
		bh = common->next_buffhd_to_fill;
		while (bh->state != BUF_STATE_EMPTY) {
			spin_unlock_irq(&common->lock);
			rc = sleep_thread(common, false);
			if (rc)
				return rc;

			spin_lock_irq(&common->lock);
		}
		spin_unlock_irq(&common->lock);

		/*
		 * If we were asked to read past the end of file,
@@ -729,8 +740,10 @@ static int do_read(struct fsg_common *common)
			curlun->sense_data_info =
					file_offset >> curlun->blkbits;
			curlun->info_valid = 1;
			spin_lock_irq(&common->lock);
			bh->inreq->length = 0;
			bh->state = BUF_STATE_FULL;
			spin_unlock_irq(&common->lock);
			break;
		}

@@ -768,8 +781,10 @@ static int do_read(struct fsg_common *common)
		 * equal to the buffer size, which is divisible by the
		 * bulk-in maxpacket size.
		 */
		spin_lock_irq(&common->lock);
		bh->inreq->length = nread;
		bh->state = BUF_STATE_FULL;
		spin_unlock_irq(&common->lock);

		/* If an error occurred, report it and its position */
		if (nread < amount) {
@@ -1713,12 +1728,17 @@ static int send_status(struct fsg_common *common)
	u32			sd, sdinfo = 0;

	/* Wait for the next buffer to become available */
	spin_lock_irq(&common->lock);
	bh = common->next_buffhd_to_fill;
	while (bh->state != BUF_STATE_EMPTY) {
		spin_unlock_irq(&common->lock);
		rc = sleep_thread(common, true);
		if (rc)
			return rc;

		spin_lock_irq(&common->lock);
	}
	spin_unlock_irq(&common->lock);

	if (curlun) {
		sd = curlun->sense_data;
@@ -1924,13 +1944,19 @@ static int do_scsi_command(struct fsg_common *common)
	dump_cdb(common);

	/* Wait for the next buffer to become available for data or status */
	spin_lock_irq(&common->lock);
	bh = common->next_buffhd_to_fill;
	common->next_buffhd_to_drain = bh;
	while (bh->state != BUF_STATE_EMPTY) {
		spin_unlock_irq(&common->lock);
		rc = sleep_thread(common, true);
		if (rc)
			return rc;

		spin_lock_irq(&common->lock);
	}
	spin_unlock_irq(&common->lock);

	common->phase_error = 0;
	common->short_packet_received = 0;

@@ -2271,12 +2297,17 @@ static int get_next_command(struct fsg_common *common)
	int			rc = 0;

	/* Wait for the next buffer to become available */
	spin_lock_irq(&common->lock);
	bh = common->next_buffhd_to_fill;
	while (bh->state != BUF_STATE_EMPTY) {
		spin_unlock_irq(&common->lock);
		rc = sleep_thread(common, true);
		if (rc)
			return rc;

		spin_lock_irq(&common->lock);
	}
	spin_unlock_irq(&common->lock);

	/* Queue a request to read a Bulk-only CBW */
	set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
@@ -2291,14 +2322,23 @@ static int get_next_command(struct fsg_common *common)
	 */

	/* Wait for the CBW to arrive */
	spin_lock_irq(&common->lock);
	while (bh->state != BUF_STATE_FULL) {
		spin_unlock_irq(&common->lock);
		rc = sleep_thread(common, true);
		if (rc)
			return rc;

		spin_lock_irq(&common->lock);
	}
	spin_unlock_irq(&common->lock);

	smp_rmb();
	rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;

	spin_lock_irq(&common->lock);
	bh->state = BUF_STATE_EMPTY;
	spin_unlock_irq(&common->lock);

	return rc;
}
@@ -2489,10 +2529,13 @@ static void handle_exception(struct fsg_common *common)
		/* Wait until everything is idle */
		for (;;) {
			int num_active = 0;
			spin_lock_irq(&common->lock);
			for (i = 0; i < common->fsg_num_buffers; ++i) {
				bh = &common->buffhds[i];
				num_active += bh->inreq_busy + bh->outreq_busy;
			}
			spin_unlock_irq(&common->lock);

			if (num_active == 0)
				break;
			if (sleep_thread(common, true))