lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1614accb-dee5-1c0e-ece3-ecdd56f45253@ideasonboard.com>
Date:   Wed, 2 Sep 2020 11:13:09 +0100
From:   Kieran Bingham <kieran.bingham@...asonboard.com>
To:     Kaaira Gupta <kgupta@...iitr.ac.in>,
        Helen Koike <helen.koike@...labora.com>,
        Shuah Khan <skhan@...uxfoundation.org>,
        Mauro Carvalho Chehab <mchehab@...nel.org>,
        linux-media@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v3 5/9] media: vimc: Separate closing of stream and thread

Hi Kaaira,

On 19/08/2020 19:04, Kaaira Gupta wrote:
> Make separate functions for stopping streaming of entities in path of a
> particular stream and stopping thread. This is needed to ensure that
> thread doesn't stop when one device stops streaming in case of multiple
> streams.
> 
> Signed-off-by: Kaaira Gupta <kgupta@...iitr.ac.in>
> ---
>  .../media/test-drivers/vimc/vimc-streamer.c   | 82 ++++++++++++-------
>  1 file changed, 52 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c
> index cc40ecabe95a..6b5ea1537952 100644
> --- a/drivers/media/test-drivers/vimc/vimc-streamer.c
> +++ b/drivers/media/test-drivers/vimc/vimc-streamer.c
> @@ -13,29 +13,59 @@
>  #include "vimc-streamer.h"
>  
>  /**
> - * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream
> + * vimc_streamer_pipeline_terminate - Terminate the thread
>   *
> - * @stream: the pointer to the stream structure with the pipeline to be
> - *	    disabled.
> + * @stream: the pointer to the stream structure
>   *
> - * Calls s_stream to disable the stream in each entity of the pipeline
> + * Erases values of stream struct and terminates the thread

It would help if the function brief described it's purpose rather than
'what it does'. "Erases values of stream struct" is not helpful here, as
that's just a direct read of what happens in the code.

I'm guessing here, but how about:

"Tear down all resources belonging to the pipeline when there are no
longer any active streams being used. This includes stopping the active
processing thread"


But reading my text makes me worry about the ordering that might take
place. The thread should be stopped as soon as the last stream using it
is stopped. Presumably as the 'first thing' that happens to make sure
there is no concurrent processing while the stream is being disabled.

Hopefully there's no race condition ...


>   *
>   */
>  static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
>  {
>  	struct vimc_ent_device *ved;
> -	struct v4l2_subdev *sd;
>  
>  	while (stream->pipe_size) {
>  		stream->pipe_size--;
>  		ved = stream->ved_pipeline[stream->pipe_size];
>  		stream->ved_pipeline[stream->pipe_size] = NULL;
> +	}
>  
> -		if (!is_media_entity_v4l2_subdev(ved->ent))
> -			continue;
> +	kthread_stop(stream->kthread);
> +	stream->kthread = NULL;
> +}
>  
> -		sd = media_entity_to_v4l2_subdev(ved->ent);
> -		v4l2_subdev_call(sd, video, s_stream, 0);
> +/**
> + * vimc_streamer_stream_terminate - Disable stream in all ved in stream
> + *
> + * @ved: pointer to the ved for which stream needs to be disabled
> + *
> + * Calls s_stream to disable the stream in each entity of the stream
> + *
> + */
> +static void vimc_streamer_stream_terminate(struct vimc_ent_device *ved)

I would call this vimc_streamer_stream_stop to match
vimc_streamer_stream_start() rather than terminate...

> +{
> +	struct media_entity *entity = ved->ent;
> +	struct video_device *vdev;
> +	struct v4l2_subdev *sd;
> +
> +	while (entity) {
> +		if (is_media_entity_v4l2_subdev(ved->ent)) {
> +			sd = media_entity_to_v4l2_subdev(ved->ent);
> +			v4l2_subdev_call(sd, video, s_stream, 0);
> +		}
> +		entity = vimc_get_source_entity(ved->ent);
> +		if (!entity)
> +			break;
> +
> +		if (is_media_entity_v4l2_subdev(entity)) {
> +			sd = media_entity_to_v4l2_subdev(entity);
> +			ved = v4l2_get_subdevdata(sd);
> +		} else {
> +			vdev = container_of(entity,
> +					    struct video_device,
> +					    entity);
> +			ved = video_get_drvdata(vdev);
> +		}

It looks like this is walking back through the linked graph, calling
s_stream(0) right?

I wonder if struct vimc_ent_device should have a pointer to the entity
it's connected to, to simplify this. ... presumably this is done
elsewhere too?

Although then that's still walking 'backwards' rather than forwards...




>  	}
>  }
>  
> @@ -43,25 +73,25 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
>   * vimc_streamer_stream_start - Starts streaming for all entities
>   * in a stream
>   *
> - * @ved:    the pointer to the vimc entity initializing the stream
> + * @cved:    the pointer to the vimc entity initializing the stream
>   *
>   * Walks through the entity graph to call vimc_streamer_s_stream()
>   * to enable stream in all entities in path of a stream.
>   *
>   * Return: 0 if success, error code otherwise.
>   */
> -static int vimc_streamer_stream_start(struct vimc_stream *stream,
> -				      struct vimc_ent_device *ved)
> +static int vimc_streamer_stream_start(struct vimc_ent_device *cved)
>  {
>  	struct media_entity *entity;
>  	struct video_device *vdev;
>  	struct v4l2_subdev *sd;
> +	struct vimc_ent_device *ved = cved;
>  	int stream_size = 0;
>  	int ret = 0;
>  
>  	while (stream_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) {
>  		if (!ved) {
> -			vimc_streamer_pipeline_terminate(stream);
> +			vimc_streamer_stream_terminate(cved);
>  			return -EINVAL;
>  		}
>  
> @@ -71,7 +101,7 @@ static int vimc_streamer_stream_start(struct vimc_stream *stream,
>  			if (ret && ret != -ENOIOCTLCMD) {
>  				dev_err(ved->dev, "subdev_call error %s\n",
>  					ved->ent->name);
> -				vimc_streamer_pipeline_terminate(stream);
> +				vimc_streamer_stream_terminate(cved);
>  				return ret;
>  			}
>  		}
> @@ -84,7 +114,7 @@ static int vimc_streamer_stream_start(struct vimc_stream *stream,
>  				dev_err(ved->dev,
>  					"first entity in the pipe '%s' is not a source\n",
>  					ved->ent->name);
> -				vimc_streamer_pipeline_terminate(stream);
> +				vimc_streamer_stream_terminate(cved);
>  				pr_info ("first entry not source");
>  				return -EPIPE;
>  			}
> @@ -104,7 +134,7 @@ static int vimc_streamer_stream_start(struct vimc_stream *stream,
>  		stream_size++;
>  	}
>  
> -	vimc_streamer_pipeline_terminate(stream);
> +	vimc_streamer_stream_terminate(cved);
>  	return -EINVAL;
>  }
>  
> @@ -120,13 +150,14 @@ static int vimc_streamer_stream_start(struct vimc_stream *stream,
>   * Return: 0 if success, error code otherwise.
>   */
>  static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
> -				       struct vimc_ent_device *ved)
> +				       struct vimc_ent_device *cved)
>  {
>  	struct media_entity *entity;
>  	struct media_device *mdev;
>  	struct media_graph graph;
>  	struct video_device *vdev;
>  	struct v4l2_subdev *sd;
> +	struct vimc_ent_device *ved = cved;
>  	int ret;
>  
>  	entity = ved->ent;
> @@ -170,6 +201,7 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
>  		}
>  	}
>  
> +	vimc_streamer_stream_terminate(cved);
>  	vimc_streamer_pipeline_terminate(stream);
>  	return -EINVAL;
>  }
> @@ -246,7 +278,7 @@ int vimc_streamer_s_stream(struct vimc_stream *stream,
>  		if (stream->kthread)
>  			return 0;
>  
> -		ret = vimc_streamer_stream_start(stream, ved);
> +		ret = vimc_streamer_stream_start(ved);
>  		if (ret)
>  			return ret;
>  
> @@ -260,6 +292,7 @@ int vimc_streamer_s_stream(struct vimc_stream *stream,
>  		if (IS_ERR(stream->kthread)) {
>  			ret = PTR_ERR(stream->kthread);
>  			dev_err(ved->dev, "kthread_run failed with %d\n", ret);
> +			vimc_streamer_stream_terminate(ved);
>  			vimc_streamer_pipeline_terminate(stream);
>  			stream->kthread = NULL;

If vimc_streamer_pipeline_terminate() sets stream->kthread = NULL, it
doesn't need to be done again here.


>  			return ret;
> @@ -269,18 +302,7 @@ int vimc_streamer_s_stream(struct vimc_stream *stream,
>  		if (!stream->kthread)
>  			return 0;
>  
> -		ret = kthread_stop(stream->kthread);
> -		/*
> -		 * kthread_stop returns -EINTR in cases when streamon was
> -		 * immediately followed by streamoff, and the thread didn't had
> -		 * a chance to run. Ignore errors to stop the stream in the
> -		 * pipeline.
> -		 */

Do we need to retain that comment when stopping the thread?

> -		if (ret)
> -			dev_dbg(ved->dev, "kthread_stop returned '%d'\n", ret);
> -
> -		stream->kthread = NULL;
> -
> +		vimc_streamer_stream_terminate(ved);
>  		vimc_streamer_pipeline_terminate(stream);
>  	}
>  
> 

-- 
Regards
--
Kieran

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ