Subject: Re: [PATCH net-next v3 2/3] ptp: support multiple timestamp event readers

From: Simon Horman <[email-masked]>
Date: Sun, 1 Oct 2023 17:06:15 +0200

On Thu, Sep 28, 2023 at 03:35:43PM +0200, Xabier Marquiegui wrote:
> Use linked lists to create one event queue per open file. This enables
> simultaneous readers for timestamp event queues.
> 
> Signed-off-by: Xabier Marquiegui <[email-masked]>
> Suggested-by: Richard Cochran <[email-masked]>

Hi Xabier,

some minor feedback from Smatch via myself follows.

> diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
> index 197edf1179f1..65e7acaa40a9 100644
> --- a/drivers/ptp/ptp_chardev.c
> +++ b/drivers/ptp/ptp_chardev.c
> @@ -101,14 +101,74 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
>  	return 0;
>  }
>  
> -int ptp_open(struct posix_clock *pc, fmode_t fmode)
> +int ptp_open(struct posix_clock_user *pcuser, fmode_t fmode)
>  {
> +	struct ptp_clock *ptp =
> +		container_of(pcuser->clk, struct ptp_clock, clock);
> +	struct ida *ida = ptp_get_tsevq_ida(ptp);
> +	struct timestamp_event_queue *queue;
> +
> +	if (!ida)
> +		return -EINVAL;
> +	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
> +	if (!queue)
> +		return -EINVAL;
> +	queue->close_req = false;
> +	queue->reader_pid = task_pid_nr(current);
> +	spin_lock_init(&queue->lock);
> +	queue->ida = ida;
> +	queue->oid = ida_alloc(ida, GFP_KERNEL);
> +	if (queue->oid < 0) {
> +		kfree(queue);

queue is freed on the line above but dereferenced on the line below.

As flagged by Smatch.

> +		return queue->oid;
> +	}
> +	list_add_tail(&queue->qlist, &ptp->tsevqs);
> +	pcuser->private_clkdata = queue;
> +
>  	return 0;
>  }

...

> diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c

...

> @@ -243,15 +275,23 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
>  	ptp->devid = MKDEV(major, index);
>  	ptp->index = index;
>  	INIT_LIST_HEAD(&ptp->tsevqs);
> +	INIT_LIST_HEAD(&ptp->closed_tsevqs);
>  	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
>  	if (!queue)
>  		goto no_memory_queue;
> +	queue->close_req = false;
> +	queue->ida = kzalloc(sizeof(*queue->ida), GFP_KERNEL);
> +	if (!queue->ida)
> +		goto no_memory_queue;

It's not clear to me that queue isn't leaked here.

As flagged by Smatch.

> +	ida_init(queue->ida);
>  	spin_lock_init(&queue->lock);
>  	list_add_tail(&queue->qlist, &ptp->tsevqs);
> -	/* TODO - Transform or delete this mutex */
> -	mutex_init(&ptp->tsevq_mux);
> +	queue->oid = ida_alloc(queue->ida, GFP_KERNEL);
> +	if (queue->oid < 0)
> +		goto ida_err;
>  	mutex_init(&ptp->pincfg_mux);
>  	mutex_init(&ptp->n_vclocks_mux);
> +	mutex_init(&ptp->close_mux);
>  	init_waitqueue_head(&ptp->tsev_wq);
>  
>  	if (ptp->info->getcycles64 || ptp->info->getcyclesx64) {
> @@ -350,9 +390,10 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
>  	if (ptp->kworker)
>  		kthread_destroy_worker(ptp->kworker);
>  kworker_err:
> -	mutex_destroy(&ptp->tsevq_mux);
>  	mutex_destroy(&ptp->pincfg_mux);
>  	mutex_destroy(&ptp->n_vclocks_mux);
> +	mutex_destroy(&ptp->close_mux);
> +ida_err:
>  	ptp_clean_queue_list(ptp);
>  no_memory_queue:
>  	ida_free(&ptp_clocks_map, index);

...