aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@web.de>2010-02-08 05:12:19 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-16 19:01:24 -0500
commit05b4149433ffae789edaf569da8d998c93eed1aa (patch)
tree3a62d3e63ab2a7f2c0033cc301ed5f1693ca7270 /drivers/isdn/capi
parenteca39dd830dbc58061aa6cd68853c39055236be3 (diff)
CAPI: Rework locking of capidev members
Rename 'ncci_list_mtx' to 'lock', expressing that it now protects a larger set of capidev members: the NCCI list, ap.applid (ie. the registration of the application), and modifications of userflags. We do not need to protect each and every check for ap.applid because, once an application is registered, it will stay for the whole lifetime of the device. Also, there is no need to apply the capidev mutex during release (if there could be concurrent users, we would crash them anyway by freeing the device at the end of capi_release). Signed-off-by: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/capi')
-rw-r--r--drivers/isdn/capi/capi.c181
1 files changed, 88 insertions, 93 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 9d7c3692c7d7..403bf8fcb285 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -141,7 +141,7 @@ struct capidev {
141 141
142 struct capincci *nccis; 142 struct capincci *nccis;
143 143
144 struct mutex ncci_list_mtx; 144 struct mutex lock;
145}; 145};
146 146
147/* -------- global variables ---------------------------------------- */ 147/* -------- global variables ---------------------------------------- */
@@ -574,38 +574,31 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
574 u16 datahandle; 574 u16 datahandle;
575#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 575#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
576 struct capincci *np; 576 struct capincci *np;
577 u32 ncci;
578 unsigned long flags; 577 unsigned long flags;
579 578
579 mutex_lock(&cdev->lock);
580
580 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { 581 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
581 u16 info = CAPIMSG_U16(skb->data, 12); // Info field 582 u16 info = CAPIMSG_U16(skb->data, 12); // Info field
582 if ((info & 0xff00) == 0) { 583 if ((info & 0xff00) == 0)
583 mutex_lock(&cdev->ncci_list_mtx);
584 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); 584 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
585 mutex_unlock(&cdev->ncci_list_mtx);
586 }
587 } 585 }
588 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) { 586 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND)
589 mutex_lock(&cdev->ncci_list_mtx);
590 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); 587 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
591 mutex_unlock(&cdev->ncci_list_mtx); 588
592 }
593 spin_lock_irqsave(&workaround_lock, flags); 589 spin_lock_irqsave(&workaround_lock, flags);
594 if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { 590 if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
595 skb_queue_tail(&cdev->recvqueue, skb); 591 skb_queue_tail(&cdev->recvqueue, skb);
596 wake_up_interruptible(&cdev->recvwait); 592 wake_up_interruptible(&cdev->recvwait);
597 spin_unlock_irqrestore(&workaround_lock, flags); 593 goto unlock_out;
598 return;
599 } 594 }
600 ncci = CAPIMSG_CONTROL(skb->data); 595
601 for (np = cdev->nccis; np && np->ncci != ncci; np = np->next) 596 np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data));
602 ;
603 if (!np) { 597 if (!np) {
604 printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); 598 printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
605 skb_queue_tail(&cdev->recvqueue, skb); 599 skb_queue_tail(&cdev->recvqueue, skb);
606 wake_up_interruptible(&cdev->recvwait); 600 wake_up_interruptible(&cdev->recvwait);
607 spin_unlock_irqrestore(&workaround_lock, flags); 601 goto unlock_out;
608 return;
609 } 602 }
610 603
611#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE 604#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -618,8 +611,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
618 if (!mp) { 611 if (!mp) {
619 skb_queue_tail(&cdev->recvqueue, skb); 612 skb_queue_tail(&cdev->recvqueue, skb);
620 wake_up_interruptible(&cdev->recvwait); 613 wake_up_interruptible(&cdev->recvwait);
621 spin_unlock_irqrestore(&workaround_lock, flags); 614 goto unlock_out;
622 return;
623 } 615 }
624 if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { 616 if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
625 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); 617 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
@@ -652,7 +644,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
652 } 644 }
653#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 645#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
654 646
647unlock_out:
655 spin_unlock_irqrestore(&workaround_lock, flags); 648 spin_unlock_irqrestore(&workaround_lock, flags);
649 mutex_unlock(&cdev->lock);
656} 650}
657 651
658/* -------- file_operations for capidev ----------------------------- */ 652/* -------- file_operations for capidev ----------------------------- */
@@ -730,9 +724,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
730 CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); 724 CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
731 725
732 if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { 726 if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
733 mutex_lock(&cdev->ncci_list_mtx); 727 mutex_lock(&cdev->lock);
734 capincci_free(cdev, CAPIMSG_NCCI(skb->data)); 728 capincci_free(cdev, CAPIMSG_NCCI(skb->data));
735 mutex_unlock(&cdev->ncci_list_mtx); 729 mutex_unlock(&cdev->lock);
736 } 730 }
737 731
738 cdev->errcode = capi20_put_message(&cdev->ap, skb); 732 cdev->errcode = capi20_put_message(&cdev->ap, skb);
@@ -765,30 +759,35 @@ capi_ioctl(struct inode *inode, struct file *file,
765 unsigned int cmd, unsigned long arg) 759 unsigned int cmd, unsigned long arg)
766{ 760{
767 struct capidev *cdev = file->private_data; 761 struct capidev *cdev = file->private_data;
768 struct capi20_appl *ap = &cdev->ap;
769 capi_ioctl_struct data; 762 capi_ioctl_struct data;
770 int retval = -EINVAL; 763 int retval = -EINVAL;
771 void __user *argp = (void __user *)arg; 764 void __user *argp = (void __user *)arg;
772 765
773 switch (cmd) { 766 switch (cmd) {
774 case CAPI_REGISTER: 767 case CAPI_REGISTER:
775 { 768 mutex_lock(&cdev->lock);
776 if (ap->applid)
777 return -EEXIST;
778 769
779 if (copy_from_user(&cdev->ap.rparam, argp, 770 if (cdev->ap.applid) {
780 sizeof(struct capi_register_params))) 771 retval = -EEXIST;
781 return -EFAULT; 772 goto register_out;
782 773 }
783 cdev->ap.private = cdev; 774 if (copy_from_user(&cdev->ap.rparam, argp,
784 cdev->ap.recv_message = capi_recv_message; 775 sizeof(struct capi_register_params))) {
785 cdev->errcode = capi20_register(ap); 776 retval = -EFAULT;
786 if (cdev->errcode) { 777 goto register_out;
787 ap->applid = 0; 778 }
788 return -EIO; 779 cdev->ap.private = cdev;
789 } 780 cdev->ap.recv_message = capi_recv_message;
781 cdev->errcode = capi20_register(&cdev->ap);
782 retval = (int)cdev->ap.applid;
783 if (cdev->errcode) {
784 cdev->ap.applid = 0;
785 retval = -EIO;
790 } 786 }
791 return (int)ap->applid; 787
788register_out:
789 mutex_unlock(&cdev->lock);
790 return retval;
792 791
793 case CAPI_GET_VERSION: 792 case CAPI_GET_VERSION:
794 { 793 {
@@ -887,68 +886,67 @@ capi_ioctl(struct inode *inode, struct file *file,
887 return 0; 886 return 0;
888 887
889 case CAPI_SET_FLAGS: 888 case CAPI_SET_FLAGS:
890 case CAPI_CLR_FLAGS: 889 case CAPI_CLR_FLAGS: {
891 { 890 unsigned userflags;
892 unsigned userflags; 891
893 if (copy_from_user(&userflags, argp, 892 if (copy_from_user(&userflags, argp, sizeof(userflags)))
894 sizeof(userflags))) 893 return -EFAULT;
895 return -EFAULT;
896 if (cmd == CAPI_SET_FLAGS)
897 cdev->userflags |= userflags;
898 else
899 cdev->userflags &= ~userflags;
900 }
901 return 0;
902 894
895 mutex_lock(&cdev->lock);
896 if (cmd == CAPI_SET_FLAGS)
897 cdev->userflags |= userflags;
898 else
899 cdev->userflags &= ~userflags;
900 mutex_unlock(&cdev->lock);
901 return 0;
902 }
903 case CAPI_GET_FLAGS: 903 case CAPI_GET_FLAGS:
904 if (copy_to_user(argp, &cdev->userflags, 904 if (copy_to_user(argp, &cdev->userflags,
905 sizeof(cdev->userflags))) 905 sizeof(cdev->userflags)))
906 return -EFAULT; 906 return -EFAULT;
907 return 0; 907 return 0;
908 908
909 case CAPI_NCCI_OPENCOUNT: 909 case CAPI_NCCI_OPENCOUNT: {
910 { 910 struct capincci *nccip;
911 struct capincci *nccip; 911 unsigned ncci;
912 unsigned ncci; 912 int count = 0;
913 int count = 0;
914 if (copy_from_user(&ncci, argp, sizeof(ncci)))
915 return -EFAULT;
916 913
917 mutex_lock(&cdev->ncci_list_mtx); 914 if (copy_from_user(&ncci, argp, sizeof(ncci)))
918 if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) { 915 return -EFAULT;
919 mutex_unlock(&cdev->ncci_list_mtx); 916
920 return 0; 917 mutex_lock(&cdev->lock);
921 } 918 nccip = capincci_find(cdev, (u32)ncci);
922 count += capincci_minor_opencount(nccip); 919 if (nccip)
923 mutex_unlock(&cdev->ncci_list_mtx); 920 count = capincci_minor_opencount(nccip);
924 return count; 921 mutex_unlock(&cdev->lock);
925 } 922 return count;
926 return 0; 923 }
927 924
928#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE 925#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
929 case CAPI_NCCI_GETUNIT: 926 case CAPI_NCCI_GETUNIT: {
930 { 927 struct capincci *nccip;
931 struct capincci *nccip; 928 struct capiminor *mp;
932 struct capiminor *mp; 929 unsigned ncci;
933 unsigned ncci; 930 int unit = -ESRCH;
934 int unit = 0; 931
935 if (copy_from_user(&ncci, argp, 932 if (copy_from_user(&ncci, argp, sizeof(ncci)))
936 sizeof(ncci))) 933 return -EFAULT;
937 return -EFAULT; 934
938 mutex_lock(&cdev->ncci_list_mtx); 935 mutex_lock(&cdev->lock);
939 nccip = capincci_find(cdev, (u32) ncci); 936 nccip = capincci_find(cdev, (u32)ncci);
940 if (!nccip || (mp = nccip->minorp) == NULL) { 937 if (nccip) {
941 mutex_unlock(&cdev->ncci_list_mtx); 938 mp = nccip->minorp;
942 return -ESRCH; 939 if (mp)
943 } 940 unit = mp->minor;
944 unit = mp->minor;
945 mutex_unlock(&cdev->ncci_list_mtx);
946 return unit;
947 } 941 }
948 return 0; 942 mutex_unlock(&cdev->lock);
943 return unit;
944 }
949#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 945#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
946
947 default:
948 return -EINVAL;
950 } 949 }
951 return -EINVAL;
952} 950}
953 951
954static int capi_open(struct inode *inode, struct file *file) 952static int capi_open(struct inode *inode, struct file *file)
@@ -959,7 +957,7 @@ static int capi_open(struct inode *inode, struct file *file)
959 if (!cdev) 957 if (!cdev)
960 return -ENOMEM; 958 return -ENOMEM;
961 959
962 mutex_init(&cdev->ncci_list_mtx); 960 mutex_init(&cdev->lock);
963 skb_queue_head_init(&cdev->recvqueue); 961 skb_queue_head_init(&cdev->recvqueue);
964 init_waitqueue_head(&cdev->recvwait); 962 init_waitqueue_head(&cdev->recvwait);
965 file->private_data = cdev; 963 file->private_data = cdev;
@@ -979,15 +977,10 @@ static int capi_release(struct inode *inode, struct file *file)
979 list_del(&cdev->list); 977 list_del(&cdev->list);
980 mutex_unlock(&capidev_list_lock); 978 mutex_unlock(&capidev_list_lock);
981 979
982 if (cdev->ap.applid) { 980 if (cdev->ap.applid)
983 capi20_release(&cdev->ap); 981 capi20_release(&cdev->ap);
984 cdev->ap.applid = 0;
985 }
986 skb_queue_purge(&cdev->recvqueue); 982 skb_queue_purge(&cdev->recvqueue);
987
988 mutex_lock(&cdev->ncci_list_mtx);
989 capincci_free(cdev, 0xffffffff); 983 capincci_free(cdev, 0xffffffff);
990 mutex_unlock(&cdev->ncci_list_mtx);
991 984
992 kfree(cdev); 985 kfree(cdev);
993 return 0; 986 return 0;
@@ -1446,11 +1439,13 @@ static int capi20ncci_proc_show(struct seq_file *m, void *v)
1446 mutex_lock(&capidev_list_lock); 1439 mutex_lock(&capidev_list_lock);
1447 list_for_each(l, &capidev_list) { 1440 list_for_each(l, &capidev_list) {
1448 cdev = list_entry(l, struct capidev, list); 1441 cdev = list_entry(l, struct capidev, list);
1442 mutex_lock(&cdev->lock);
1449 for (np=cdev->nccis; np; np = np->next) { 1443 for (np=cdev->nccis; np; np = np->next) {
1450 seq_printf(m, "%d 0x%x\n", 1444 seq_printf(m, "%d 0x%x\n",
1451 cdev->ap.applid, 1445 cdev->ap.applid,
1452 np->ncci); 1446 np->ncci);
1453 } 1447 }
1448 mutex_unlock(&cdev->lock);
1454 } 1449 }
1455 mutex_unlock(&capidev_list_lock); 1450 mutex_unlock(&capidev_list_lock);
1456 return 0; 1451 return 0;