@@ -215,15 +215,41 @@ static ssize_t name_show(struct device *dev,
215215 struct device_attribute * attr , char * buf )
216216{
217217 struct uio_device * idev = dev_get_drvdata (dev );
218- return sprintf (buf , "%s\n" , idev -> info -> name );
218+ int ret ;
219+
220+ mutex_lock (& idev -> info_lock );
221+ if (!idev -> info ) {
222+ ret = - EINVAL ;
223+ dev_err (dev , "the device has been unregistered\n" );
224+ goto out ;
225+ }
226+
227+ ret = sprintf (buf , "%s\n" , idev -> info -> name );
228+
229+ out :
230+ mutex_unlock (& idev -> info_lock );
231+ return ret ;
219232}
220233static DEVICE_ATTR_RO (name );
221234
222235static ssize_t version_show (struct device * dev ,
223236 struct device_attribute * attr , char * buf )
224237{
225238 struct uio_device * idev = dev_get_drvdata (dev );
226- return sprintf (buf , "%s\n" , idev -> info -> version );
239+ int ret ;
240+
241+ mutex_lock (& idev -> info_lock );
242+ if (!idev -> info ) {
243+ ret = - EINVAL ;
244+ dev_err (dev , "the device has been unregistered\n" );
245+ goto out ;
246+ }
247+
248+ ret = sprintf (buf , "%s\n" , idev -> info -> version );
249+
250+ out :
251+ mutex_unlock (& idev -> info_lock );
252+ return ret ;
227253}
228254static DEVICE_ATTR_RO (version );
229255
@@ -415,11 +441,15 @@ EXPORT_SYMBOL_GPL(uio_event_notify);
415441static irqreturn_t uio_interrupt (int irq , void * dev_id )
416442{
417443 struct uio_device * idev = (struct uio_device * )dev_id ;
418- irqreturn_t ret = idev -> info -> handler (irq , idev -> info );
444+ irqreturn_t ret ;
445+
446+ mutex_lock (& idev -> info_lock );
419447
448+ ret = idev -> info -> handler (irq , idev -> info );
420449 if (ret == IRQ_HANDLED )
421450 uio_event_notify (idev -> info );
422451
452+ mutex_unlock (& idev -> info_lock );
423453 return ret ;
424454}
425455
@@ -460,6 +490,12 @@ static int uio_open(struct inode *inode, struct file *filep)
460490 filep -> private_data = listener ;
461491
462492 mutex_lock (& idev -> info_lock );
493+ if (!idev -> info ) {
494+ mutex_unlock (& idev -> info_lock );
495+ ret = - EINVAL ;
496+ goto err_alloc_listener ;
497+ }
498+
463499 if (idev -> info && idev -> info -> open )
464500 ret = idev -> info -> open (idev -> info , inode );
465501 mutex_unlock (& idev -> info_lock );
@@ -590,6 +626,11 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
590626 s32 irq_on ;
591627
592628 mutex_lock (& idev -> info_lock );
629+ if (!idev -> info ) {
630+ retval = - EINVAL ;
631+ goto out ;
632+ }
633+
593634 if (!idev -> info || !idev -> info -> irq ) {
594635 retval = - EIO ;
595636 goto out ;
@@ -635,10 +676,20 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
635676 struct page * page ;
636677 unsigned long offset ;
637678 void * addr ;
679+ int ret = 0 ;
680+ int mi ;
638681
639- int mi = uio_find_mem_index (vmf -> vma );
640- if (mi < 0 )
641- return VM_FAULT_SIGBUS ;
682+ mutex_lock (& idev -> info_lock );
683+ if (!idev -> info ) {
684+ ret = VM_FAULT_SIGBUS ;
685+ goto out ;
686+ }
687+
688+ mi = uio_find_mem_index (vmf -> vma );
689+ if (mi < 0 ) {
690+ ret = VM_FAULT_SIGBUS ;
691+ goto out ;
692+ }
642693
643694 /*
644695 * We need to subtract mi because userspace uses offset = N*PAGE_SIZE
@@ -653,7 +704,11 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
653704 page = vmalloc_to_page (addr );
654705 get_page (page );
655706 vmf -> page = page ;
656- return 0 ;
707+
708+ out :
709+ mutex_unlock (& idev -> info_lock );
710+
711+ return ret ;
657712}
658713
659714static const struct vm_operations_struct uio_logical_vm_ops = {
@@ -678,6 +733,7 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
678733 struct uio_device * idev = vma -> vm_private_data ;
679734 int mi = uio_find_mem_index (vma );
680735 struct uio_mem * mem ;
736+
681737 if (mi < 0 )
682738 return - EINVAL ;
683739 mem = idev -> info -> mem + mi ;
@@ -719,30 +775,46 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
719775
720776 vma -> vm_private_data = idev ;
721777
778+ mutex_lock (& idev -> info_lock );
779+ if (!idev -> info ) {
780+ ret = - EINVAL ;
781+ goto out ;
782+ }
783+
722784 mi = uio_find_mem_index (vma );
723- if (mi < 0 )
724- return - EINVAL ;
785+ if (mi < 0 ) {
786+ ret = - EINVAL ;
787+ goto out ;
788+ }
725789
726790 requested_pages = vma_pages (vma );
727791 actual_pages = ((idev -> info -> mem [mi ].addr & ~PAGE_MASK )
728792 + idev -> info -> mem [mi ].size + PAGE_SIZE - 1 ) >> PAGE_SHIFT ;
729- if (requested_pages > actual_pages )
730- return - EINVAL ;
793+ if (requested_pages > actual_pages ) {
794+ ret = - EINVAL ;
795+ goto out ;
796+ }
731797
732798 if (idev -> info -> mmap ) {
733799 ret = idev -> info -> mmap (idev -> info , vma );
734- return ret ;
800+ goto out ;
735801 }
736802
737803 switch (idev -> info -> mem [mi ].memtype ) {
738804 case UIO_MEM_PHYS :
739- return uio_mmap_physical (vma );
805+ ret = uio_mmap_physical (vma );
806+ break ;
740807 case UIO_MEM_LOGICAL :
741808 case UIO_MEM_VIRTUAL :
742- return uio_mmap_logical (vma );
809+ ret = uio_mmap_logical (vma );
810+ break ;
743811 default :
744- return - EINVAL ;
812+ ret = - EINVAL ;
745813 }
814+
815+ out :
816+ mutex_unlock (& idev -> info_lock );
817+ return 0 ;
746818}
747819
748820static const struct file_operations uio_fops = {
@@ -932,12 +1004,12 @@ void uio_unregister_device(struct uio_info *info)
9321004
9331005 uio_free_minor (idev );
9341006
1007+ mutex_lock (& idev -> info_lock );
9351008 uio_dev_del_attributes (idev );
9361009
9371010 if (info -> irq && info -> irq != UIO_IRQ_CUSTOM )
9381011 free_irq (info -> irq , idev );
9391012
940- mutex_lock (& idev -> info_lock );
9411013 idev -> info = NULL ;
9421014 mutex_unlock (& idev -> info_lock );
9431015
0 commit comments