[LinuxPPS] safe pps_register_source()
Fabio Checconi
fchecconi at gmail.com
Thu Aug 9 16:34:47 CEST 2007
On Thu, Aug 09, 2007 at 04:13:59PM +0200, Rodolfo Giometti wrote:
> On Thu, Aug 09, 2007 at 09:40:41AM -0400, Fabio Checconi wrote:
>
> > I think we need something to prevent the deregistration of the
[...]
>
> What do you think about this solution?
>
looks good, a couple of notes below
> diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
> index ccfa123..c35e7d8 100644
> --- a/drivers/pps/kapi.c
> +++ b/drivers/pps/kapi.c
> @@ -120,6 +120,8 @@ int pps_register_source(struct pps_source_info *info, int default_params)
>
> init_waitqueue_head(&pps->queue);
> spin_lock_init(&pps->lock);
> + atomic_set(&pps->usage, 0);
> + init_waitqueue_head(&pps->usage_queue);
>
> /* Create the char device */
> err = pps_register_cdev(pps);
> @@ -178,6 +180,8 @@ void pps_unregister_source(int source)
> idr_remove(&pps_idr, pps->id);
> spin_unlock_irq(&idr_lock);
>
> + wait_event(pps->usage_queue, atomic_read(&pps->usage) == 0);
> +
> pps_sysfs_remove_source_entry(pps);
> pps_unregister_cdev(pps);
> kfree(pps);
> @@ -206,6 +210,12 @@ void pps_event(int source, int event, void *data)
>
> spin_lock_irqsave(&idr_lock, flags);
> pps = idr_find(&pps_idr, source);
> +
> + /* If we find a valid PPS source we lock it before leaving
> + * the lock!
> + */
> + if (!pps)
> + atomic_inc(&pps->usage);
here it seems you're dereferencing a null pointer (!pps)
> spin_unlock_irqrestore(&idr_lock, flags);
>
> if (!pps)
> @@ -251,5 +261,9 @@ void pps_event(int source, int event, void *data)
> kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
>
> spin_unlock_irqrestore(&pps->lock, flags);
> +
> + /* Now we can release the PPS source for (possible) deregistration */
> + atomic_dec(&pps->usage);
> + wake_up_all(&pps->usage_queue);
but a concurrent kfree(pps) on a different processor could be a problem,
I have to think more about that...
> }
> EXPORT_SYMBOL(pps_event);
> diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
> index 41ae2fc..52de2f1 100644
> --- a/drivers/pps/pps.c
> +++ b/drivers/pps/pps.c
> @@ -212,6 +212,9 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
> struct pps_device *pps = container_of(inode->i_cdev,
> struct pps_device, cdev);
>
> + /* Lock the PPS source against (possible) deregistration */
> + atomic_inc(&pps->usage);
> +
> file->private_data = pps;
>
> return 0;
> @@ -219,7 +222,11 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
>
> static int pps_cdev_release(struct inode *inode, struct file *file)
> {
> - /* Nop */
> + struct pps_device *pps = file->private_data;
> +
> + /* Free the PPS source and wake up (possible) deregistration */
> + atomic_dec(&pps->usage);
> + wake_up_all(&pps->usage_queue);
>
> return 0;
> }
> diff --git a/include/linux/pps.h b/include/linux/pps.h
> index a513da9..387b37f 100644
> --- a/include/linux/pps.h
> +++ b/include/linux/pps.h
> @@ -171,6 +171,9 @@ struct pps_device {
> struct fasync_struct *async_queue; /* fasync method */
> spinlock_t lock;
>
> + atomic_t usage; /* usage count */
> + wait_queue_head_t usage_queue;
> +
> struct class_device class_dev;
> };
>
> Rodolfo
>
> --
>
> GNU/Linux Solutions e-mail: giometti at enneenne.com
> Linux Device Driver giometti at gnudd.com
> Embedded Systems giometti at linux.it
> UNIX programming phone: +39 349 2432127
More information about the LinuxPPS
mailing list