Re: [RFCv11 PATCH 05/29] media-request: add request ioctls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 04/12/2018 12:40 PM, Sakari Ailus wrote:
> Hi Mauro,
> 
> On Tue, Apr 10, 2018 at 07:57:56AM -0300, Mauro Carvalho Chehab wrote:
>> Em Mon,  9 Apr 2018 16:20:02 +0200
>> Hans Verkuil <hverkuil@xxxxxxxxx> escreveu:
>>
>>> From: Hans Verkuil <hans.verkuil@xxxxxxxxx>
>>>
>>> Implement the MEDIA_REQUEST_IOC_QUEUE and MEDIA_REQUEST_IOC_REINIT
>>> ioctls.
>>>
>>> Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>
>>> ---
>>>  drivers/media/media-request.c | 80 +++++++++++++++++++++++++++++++++++++++++--
>>>  1 file changed, 78 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
>>> index dffc290e4ada..27739ff7cb09 100644
>>> --- a/drivers/media/media-request.c
>>> +++ b/drivers/media/media-request.c
>>> @@ -118,10 +118,86 @@ static unsigned int media_request_poll(struct file *filp,
>>>  	return 0;
>>>  }
>>>  
>>> +static long media_request_ioctl_queue(struct media_request *req)
>>> +{
>>> +	struct media_device *mdev = req->mdev;
>>> +	unsigned long flags;
>>> +	int ret = 0;
>>> +
>>> +	dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str);
>>> +
>>> +	spin_lock_irqsave(&req->lock, flags);
>>> +	if (req->state != MEDIA_REQUEST_STATE_IDLE) {
>>> +		dev_dbg(mdev->dev,
>>> +			"request: unable to queue %s, request in state %s\n",
>>> +			req->debug_str, media_request_state_str(req->state));
>>> +		spin_unlock_irqrestore(&req->lock, flags);
>>> +		return -EINVAL;
>>> +	}
>>> +	req->state = MEDIA_REQUEST_STATE_QUEUEING;
>>> +
>>> +	spin_unlock_irqrestore(&req->lock, flags);
>>> +
>>> +	/*
>>> +	 * Ensure the request that is validated will be the one that gets queued
>>> +	 * next by serialising the queueing process.
>>> +	 */
>>> +	mutex_lock(&mdev->req_queue_mutex);
>>
>> The locking here seems really weird. IMHO, it should lock before
>> touching state, as otherwise race conditions may happen.
>>
>> As I suggested before, I would use an atomic type for state, and get rid
>> of the spin lock (as it seems that it is meant to be used just
>> for state).
> 
> The new request state depends on the old state; I don't think you can
> meaningfully do that using the atomic API.
> 
>>
>>> +
>>> +	ret = mdev->ops->req_queue(req);
>>> +	spin_lock_irqsave(&req->lock, flags);
>>> +	req->state = ret ? MEDIA_REQUEST_STATE_IDLE : MEDIA_REQUEST_STATE_QUEUED;
>>> +	spin_unlock_irqrestore(&req->lock, flags);
>>> +	mutex_unlock(&mdev->req_queue_mutex);
>>> +
>>
>> Here, you have both mutex and spin locked. This is a strong indication
>> that locks are not well designed, are you're using two different locks
>> to protect the same data.
> 
> Not the same, it's different data. What is no longer visible in this
> patchset is how request objects are referenced in a request. Effectively
> that part is missing altogether. It will be needed when adding support for
> objects that are not managed through the V4L2 framework such as pixel
> formats or selection rectangles.
> 
> You could move the serialisation of queueing requests to drivers altogether
> but I don't think that'd be a wise choice: the device state at request
> queue head will need to be maintained so that queued requests can be
> validated against it (right now validation is embedded in queueing).
> Failing validation will result into restoring the previous state.

req_queue_mutex doesn't protect data, it serializes the req_queue operation.

You don't want to allow req_queue being called for two different requests
at the same time: that would be a bit of a nightmare in the driver, and anyway,
requests really have to be queued one-by-one.

Actually, just serializing the req_queue ioctl is not enough, it also has to serialize
STREAMON/OFF and releasing (canceling) the vb2_queue. That's not in v11, but
will be in v12. When a queue is cancelled it needs to clean up any associated
requests, and you cannot call req_queue while that is in progress.

Regards,

	Hans

> 
> I had an implementation of that in my previous request set here:
> 
> <URL:https://www.spinics.net/lists/linux-media/msg130994.html>
> 
> We'll implement it but not yet: right now there's just a need for buffers
> and controls. Still, knowing where we're going I'd keep the mutex where it
> is.
> 
>>> +static long media_request_ioctl_reinit(struct media_request *req)
>>> +{
>>> +	struct media_device *mdev = req->mdev;
>>> +	unsigned long flags;
>>> +
>>> +	spin_lock_irqsave(&req->lock, flags);
>>> +	if (req->state != MEDIA_REQUEST_STATE_IDLE &&
>>> +	    req->state != MEDIA_REQUEST_STATE_COMPLETE) {
>>> +		dev_dbg(mdev->dev,
>>> +			"request: %s not in idle or complete state, cannot reinit\n",
>>> +			req->debug_str);
>>> +		spin_unlock_irqrestore(&req->lock, flags);
>>> +		return -EINVAL;
>>> +	}
>>> +	req->state = MEDIA_REQUEST_STATE_CLEANING;
>>> +	spin_unlock_irqrestore(&req->lock, flags);
>>> +
>>> +	media_request_clean(req);
>>> +
>>> +	spin_lock_irqsave(&req->lock, flags);
>>> +	req->state = MEDIA_REQUEST_STATE_IDLE;
>>> +	spin_unlock_irqrestore(&req->lock, flags);
>>
>> This code should be called with the mutex hold.
> 
> That's not necessary. A request which is being re-initialised was in an
> idle or complete state; nothing of that request is bound to the current
> device state in any way. Therefore the objects in that request can be
> simply thrown out.
> 
> The state change to CLEANING is there to prevent the request being e.g.
> queued during the cleaning.
> 




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux