diff options
author | Jan Kiszka <jan.kiszka@web.de> | 2010-02-08 05:12:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-16 19:01:24 -0500 |
commit | 05b4149433ffae789edaf569da8d998c93eed1aa (patch) | |
tree | 3a62d3e63ab2a7f2c0033cc301ed5f1693ca7270 /drivers/isdn | |
parent | eca39dd830dbc58061aa6cd68853c39055236be3 (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')
-rw-r--r-- | drivers/isdn/capi/capi.c | 181 |
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 | ||
647 | unlock_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 | |
788 | register_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 | ||
954 | static int capi_open(struct inode *inode, struct file *file) | 952 | static 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; |