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

Commit 6cf11ee6 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] vb2: fix vb2_thread_stop race conditions



The locking scheme inside the vb2 thread is unsafe when stopping the
thread. In particular kthread_stop was called *after* internal data
structures were cleaned up instead of doing that before. In addition,
internal vb2 functions were called after threadio->stop was set to
true and vb2_internal_streamoff was called. This is also not allowed.

All this led to a variety of race conditions and kernel warnings and/or
oopses.

Fixed by moving the kthread_stop call up before the cleanup takes
place, and by checking threadio->stop before calling internal vb2
queuing operations.

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Cc: <stable@vger.kernel.org>      # for v3.16 and up
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 42d74e4f
Loading
Loading
Loading
Loading
+9 −10
Original line number Diff line number Diff line
@@ -3146,27 +3146,26 @@ static int vb2_thread(void *data)
			prequeue--;
		} else {
			call_void_qop(q, wait_finish, q);
			if (!threadio->stop)
				ret = vb2_internal_dqbuf(q, &fileio->b, 0);
			call_void_qop(q, wait_prepare, q);
			dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
		}
		if (threadio->stop)
			break;
		if (ret)
		if (ret || threadio->stop)
			break;
		try_to_freeze();

		vb = q->bufs[fileio->b.index];
		if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR))
			ret = threadio->fnc(vb, threadio->priv);
		if (ret)
			if (threadio->fnc(vb, threadio->priv))
				break;
		call_void_qop(q, wait_finish, q);
		if (set_timestamp)
			v4l2_get_timestamp(&fileio->b.timestamp);
		if (!threadio->stop)
			ret = vb2_internal_qbuf(q, &fileio->b);
		call_void_qop(q, wait_prepare, q);
		if (ret)
		if (ret || threadio->stop)
			break;
	}

@@ -3235,11 +3234,11 @@ int vb2_thread_stop(struct vb2_queue *q)
	threadio->stop = true;
	vb2_internal_streamoff(q, q->type);
	call_void_qop(q, wait_prepare, q);
	err = kthread_stop(threadio->thread);
	q->fileio = NULL;
	fileio->req.count = 0;
	vb2_reqbufs(q, &fileio->req);
	kfree(fileio);
	err = kthread_stop(threadio->thread);
	threadio->thread = NULL;
	kfree(threadio);
	q->fileio = NULL;