On 21/05/18 10:54, Sakari Ailus wrote: > Add a new request state (UPDATING) as well as a count for updating the > request objects. This way, several updates may take place simultaneously > without affecting each other. The drivers (as well as frameworks) still > must serialise access to their own data structures; what is guaranteed by > the new state is simply correct and optimal handling of requests. > > Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx> > --- > drivers/media/media-request.c | 3 ++- > include/media/media-request.h | 53 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 55 insertions(+), 1 deletion(-) > > diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c > index a1576cf528605..03e74d72241a0 100644 > --- a/drivers/media/media-request.c > +++ b/drivers/media/media-request.c > @@ -22,6 +22,7 @@ static const char * const request_state[] = { > [MEDIA_REQUEST_STATE_QUEUED] = "queued", > [MEDIA_REQUEST_STATE_COMPLETE] = "complete", > [MEDIA_REQUEST_STATE_CLEANING] = "cleaning", > + [MEDIA_REQUEST_STATE_UPDATING] = "updating", > }; > > static const char * > @@ -385,7 +386,7 @@ int media_request_object_bind(struct media_request *req, > > spin_lock_irqsave(&req->lock, flags); > > - if (WARN_ON(req->state != MEDIA_REQUEST_STATE_IDLE)) > + if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING)) > goto unlock; I think the 'obj->req = req' etc. lines just before the spin_lock_irqsave should be moved to after this 'if'. Otherwise there is an unexpected side-effect of calling this function when it returns EBUSY. > > list_add_tail(&obj->list, &req->objects); > diff --git a/include/media/media-request.h b/include/media/media-request.h > index e175538d3c669..42cc6e7f6e532 100644 > --- a/include/media/media-request.h > +++ b/include/media/media-request.h > @@ -28,6 +28,9 @@ > * @MEDIA_REQUEST_STATE_QUEUED: Queued > * @MEDIA_REQUEST_STATE_COMPLETE: Completed, the request is done > * @MEDIA_REQUEST_STATE_CLEANING: Cleaning, the request is being re-inited > + * @MEDIA_REQUEST_STATE_UPDATING: The request is being updated, i.e. > + * request objects are being added, > + * modified or removed > */ > enum media_request_state { > MEDIA_REQUEST_STATE_IDLE, > @@ -35,6 +38,7 @@ enum media_request_state { > MEDIA_REQUEST_STATE_QUEUED, > MEDIA_REQUEST_STATE_COMPLETE, > MEDIA_REQUEST_STATE_CLEANING, > + MEDIA_REQUEST_STATE_UPDATING, > }; > > struct media_request_object; > @@ -56,6 +60,7 @@ struct media_request { > struct kref kref; > char debug_str[TASK_COMM_LEN + 11]; > enum media_request_state state; > + refcount_t updating_count; > struct list_head objects; > unsigned int num_incomplete_objects; > struct wait_queue_head poll_wait; > @@ -65,6 +70,54 @@ struct media_request { > #ifdef CONFIG_MEDIA_CONTROLLER > > /** > + * media_request_lock_for_update - Lock the request for updating its objects > + * > + * @req: The media request > + * > + * Use before updating a request, i.e. adding, modifying or removing a request > + * object in it. A reference to the request must be held during the update. This > + * usually takes place automatically through a file handle. Use > + * @media_request_unlock_for_update when done. > + */ > +static inline int __must_check > +media_request_lock_for_update(struct media_request *req) > +{ > + unsigned long flags; > + int ret = 0; > + > + spin_lock_irqsave(&req->lock, flags); > + if (req->state == MEDIA_REQUEST_STATE_IDLE || > + req->state == MEDIA_REQUEST_STATE_UPDATING) { > + req->state = MEDIA_REQUEST_STATE_UPDATING; > + refcount_inc(&req->updating_count); > + } else { > + ret = -EBUSY; > + } > + spin_unlock_irqrestore(&req->lock, flags); > + > + return ret; > +} > + > +/** > + * media_request_unlock_for_update - Unlock a request previously locked for > + * update > + * > + * @req: The media request > + * > + * Unlock a request that has previously been locked using > + * @media_request_lock_for_update. > + */ > +static inline void media_request_unlock_for_update(struct media_request *req) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&req->lock, flags); > + if (refcount_dec_and_test(&req->updating_count)) > + req->state = MEDIA_REQUEST_STATE_IDLE; > + spin_unlock_irqrestore(&req->lock, flags); > +} This is a very nice solution. Thank you! Regards, Hans > + > +/** > * media_request_get - Get the media request > * > * @req: The request >