diff options
Diffstat (limited to 'fs/fcntl.c')
| -rw-r--r-- | fs/fcntl.c | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index 452d02f9075e..0a140741b39e 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -614,9 +614,15 @@ int send_sigurg(struct fown_struct *fown) | |||
| 614 | return ret; | 614 | return ret; |
| 615 | } | 615 | } |
| 616 | 616 | ||
| 617 | static DEFINE_RWLOCK(fasync_lock); | 617 | static DEFINE_SPINLOCK(fasync_lock); |
| 618 | static struct kmem_cache *fasync_cache __read_mostly; | 618 | static struct kmem_cache *fasync_cache __read_mostly; |
| 619 | 619 | ||
| 620 | static void fasync_free_rcu(struct rcu_head *head) | ||
| 621 | { | ||
| 622 | kmem_cache_free(fasync_cache, | ||
| 623 | container_of(head, struct fasync_struct, fa_rcu)); | ||
| 624 | } | ||
| 625 | |||
| 620 | /* | 626 | /* |
| 621 | * Remove a fasync entry. If successfully removed, return | 627 | * Remove a fasync entry. If successfully removed, return |
| 622 | * positive and clear the FASYNC flag. If no entry exists, | 628 | * positive and clear the FASYNC flag. If no entry exists, |
| @@ -625,8 +631,6 @@ static struct kmem_cache *fasync_cache __read_mostly; | |||
| 625 | * NOTE! It is very important that the FASYNC flag always | 631 | * NOTE! It is very important that the FASYNC flag always |
| 626 | * match the state "is the filp on a fasync list". | 632 | * match the state "is the filp on a fasync list". |
| 627 | * | 633 | * |
| 628 | * We always take the 'filp->f_lock', in since fasync_lock | ||
| 629 | * needs to be irq-safe. | ||
| 630 | */ | 634 | */ |
| 631 | static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) | 635 | static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) |
| 632 | { | 636 | { |
| @@ -634,17 +638,22 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) | |||
| 634 | int result = 0; | 638 | int result = 0; |
| 635 | 639 | ||
| 636 | spin_lock(&filp->f_lock); | 640 | spin_lock(&filp->f_lock); |
| 637 | write_lock_irq(&fasync_lock); | 641 | spin_lock(&fasync_lock); |
| 638 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { | 642 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { |
| 639 | if (fa->fa_file != filp) | 643 | if (fa->fa_file != filp) |
| 640 | continue; | 644 | continue; |
| 645 | |||
| 646 | spin_lock_irq(&fa->fa_lock); | ||
| 647 | fa->fa_file = NULL; | ||
| 648 | spin_unlock_irq(&fa->fa_lock); | ||
| 649 | |||
| 641 | *fp = fa->fa_next; | 650 | *fp = fa->fa_next; |
| 642 | kmem_cache_free(fasync_cache, fa); | 651 | call_rcu(&fa->fa_rcu, fasync_free_rcu); |
| 643 | filp->f_flags &= ~FASYNC; | 652 | filp->f_flags &= ~FASYNC; |
| 644 | result = 1; | 653 | result = 1; |
| 645 | break; | 654 | break; |
| 646 | } | 655 | } |
| 647 | write_unlock_irq(&fasync_lock); | 656 | spin_unlock(&fasync_lock); |
| 648 | spin_unlock(&filp->f_lock); | 657 | spin_unlock(&filp->f_lock); |
| 649 | return result; | 658 | return result; |
| 650 | } | 659 | } |
| @@ -666,25 +675,30 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa | |||
| 666 | return -ENOMEM; | 675 | return -ENOMEM; |
| 667 | 676 | ||
| 668 | spin_lock(&filp->f_lock); | 677 | spin_lock(&filp->f_lock); |
| 669 | write_lock_irq(&fasync_lock); | 678 | spin_lock(&fasync_lock); |
| 670 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { | 679 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { |
| 671 | if (fa->fa_file != filp) | 680 | if (fa->fa_file != filp) |
| 672 | continue; | 681 | continue; |
| 682 | |||
| 683 | spin_lock_irq(&fa->fa_lock); | ||
| 673 | fa->fa_fd = fd; | 684 | fa->fa_fd = fd; |
| 685 | spin_unlock_irq(&fa->fa_lock); | ||
| 686 | |||
| 674 | kmem_cache_free(fasync_cache, new); | 687 | kmem_cache_free(fasync_cache, new); |
| 675 | goto out; | 688 | goto out; |
| 676 | } | 689 | } |
| 677 | 690 | ||
| 691 | spin_lock_init(&new->fa_lock); | ||
| 678 | new->magic = FASYNC_MAGIC; | 692 | new->magic = FASYNC_MAGIC; |
| 679 | new->fa_file = filp; | 693 | new->fa_file = filp; |
| 680 | new->fa_fd = fd; | 694 | new->fa_fd = fd; |
| 681 | new->fa_next = *fapp; | 695 | new->fa_next = *fapp; |
| 682 | *fapp = new; | 696 | rcu_assign_pointer(*fapp, new); |
| 683 | result = 1; | 697 | result = 1; |
| 684 | filp->f_flags |= FASYNC; | 698 | filp->f_flags |= FASYNC; |
| 685 | 699 | ||
| 686 | out: | 700 | out: |
| 687 | write_unlock_irq(&fasync_lock); | 701 | spin_unlock(&fasync_lock); |
| 688 | spin_unlock(&filp->f_lock); | 702 | spin_unlock(&filp->f_lock); |
| 689 | return result; | 703 | return result; |
| 690 | } | 704 | } |
| @@ -704,37 +718,41 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap | |||
| 704 | 718 | ||
| 705 | EXPORT_SYMBOL(fasync_helper); | 719 | EXPORT_SYMBOL(fasync_helper); |
| 706 | 720 | ||
| 707 | void __kill_fasync(struct fasync_struct *fa, int sig, int band) | 721 | /* |
| 722 | * rcu_read_lock() is held | ||
| 723 | */ | ||
| 724 | static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band) | ||
| 708 | { | 725 | { |
| 709 | while (fa) { | 726 | while (fa) { |
| 710 | struct fown_struct * fown; | 727 | struct fown_struct *fown; |
| 711 | if (fa->magic != FASYNC_MAGIC) { | 728 | if (fa->magic != FASYNC_MAGIC) { |
| 712 | printk(KERN_ERR "kill_fasync: bad magic number in " | 729 | printk(KERN_ERR "kill_fasync: bad magic number in " |
| 713 | "fasync_struct!\n"); | 730 | "fasync_struct!\n"); |
| 714 | return; | 731 | return; |
| 715 | } | 732 | } |
| 716 | fown = &fa->fa_file->f_owner; | 733 | spin_lock(&fa->fa_lock); |
| 717 | /* Don't send SIGURG to processes which have not set a | 734 | if (fa->fa_file) { |
| 718 | queued signum: SIGURG has its own default signalling | 735 | fown = &fa->fa_file->f_owner; |
| 719 | mechanism. */ | 736 | /* Don't send SIGURG to processes which have not set a |
| 720 | if (!(sig == SIGURG && fown->signum == 0)) | 737 | queued signum: SIGURG has its own default signalling |
| 721 | send_sigio(fown, fa->fa_fd, band); | 738 | mechanism. */ |
| 722 | fa = fa->fa_next; | 739 | if (!(sig == SIGURG && fown->signum == 0)) |
| 740 | send_sigio(fown, fa->fa_fd, band); | ||
| 741 | } | ||
| 742 | spin_unlock(&fa->fa_lock); | ||
| 743 | fa = rcu_dereference(fa->fa_next); | ||
| 723 | } | 744 | } |
| 724 | } | 745 | } |
| 725 | 746 | ||
| 726 | EXPORT_SYMBOL(__kill_fasync); | ||
| 727 | |||
| 728 | void kill_fasync(struct fasync_struct **fp, int sig, int band) | 747 | void kill_fasync(struct fasync_struct **fp, int sig, int band) |
| 729 | { | 748 | { |
| 730 | /* First a quick test without locking: usually | 749 | /* First a quick test without locking: usually |
| 731 | * the list is empty. | 750 | * the list is empty. |
| 732 | */ | 751 | */ |
| 733 | if (*fp) { | 752 | if (*fp) { |
| 734 | read_lock(&fasync_lock); | 753 | rcu_read_lock(); |
| 735 | /* reread *fp after obtaining the lock */ | 754 | kill_fasync_rcu(rcu_dereference(*fp), sig, band); |
| 736 | __kill_fasync(*fp, sig, band); | 755 | rcu_read_unlock(); |
| 737 | read_unlock(&fasync_lock); | ||
| 738 | } | 756 | } |
| 739 | } | 757 | } |
| 740 | EXPORT_SYMBOL(kill_fasync); | 758 | EXPORT_SYMBOL(kill_fasync); |
